From 09a9e8f6e637a24d673ff91125a531f82fb0639c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 24 Apr 2023 11:41:22 -0600 Subject: [PATCH 0001/1206] First stage of tag strings: abc'xxx' == f'xxx' --- Parser/tokenizer.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index a8649b8547e256..ec5edf5abefeb3 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1612,7 +1612,7 @@ static int tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token) { int c; - int blankline, nonascii; + int blankline, nonascii, in_tag_string; const char *p_start = NULL; const char *p_end = NULL; @@ -1877,6 +1877,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t c = tok_nextc(tok); if (c == '"' || c == '\'') { if (saw_f) { + in_tag_string = 0; goto f_string_quote; } goto letter_quote; @@ -1888,6 +1889,10 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t } c = tok_nextc(tok); } + if (c == '"' || c == '\'') { + in_tag_string = 1; + goto f_string_quote; + } tok_backup(tok, c); if (nonascii && !verify_identifier(tok)) { return MAKE_TOKEN(ERRORTOKEN); @@ -2181,8 +2186,11 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t return MAKE_TOKEN(NUMBER); } + // We may fall through here + in_tag_string = 0; + f_string_quote: - if (((tolower(*tok->start) == 'f' || tolower(*tok->start) == 'r') && (c == '\'' || c == '"'))) { + if (((tolower(*tok->start) == 'f' || tolower(*tok->start) == 'r' || in_tag_string) && (c == '\'' || c == '"'))) { int quote = c; int quote_size = 1; /* 1 or 3 */ @@ -2225,17 +2233,22 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t the_current_tok->last_expr_size = 0; the_current_tok->last_expr_end = -1; - switch (*tok->start) { - case 'F': - case 'f': - the_current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r'; - break; - case 'R': - case 'r': - the_current_tok->f_string_raw = 1; - break; - default: - Py_UNREACHABLE(); + if (in_tag_string) { + the_current_tok->f_string_raw = 1; + } + else { + switch (*tok->start) { + case 'F': + case 'f': + the_current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r'; + break; + case 'R': + case 'r': + the_current_tok->f_string_raw = 1; + break; + default: + Py_UNREACHABLE(); + } } the_current_tok->curly_bracket_depth = 0; From dbe59b2dc9e8925fd729b3fd9b05b0d67590e629 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 24 Apr 2023 11:56:56 -0600 Subject: [PATCH 0002/1206] Create new token TAGSTRING_START --- Doc/library/token-list.inc | 2 ++ Grammar/Tokens | 1 + Include/internal/pycore_token.h | 9 +++++---- Lib/token.py | 15 ++++++++------- Parser/token.c | 1 + Parser/tokenizer.c | 2 +- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Doc/library/token-list.inc b/Doc/library/token-list.inc index 3b345099bf54b5..891e695da1eced 100644 --- a/Doc/library/token-list.inc +++ b/Doc/library/token-list.inc @@ -219,6 +219,8 @@ .. data:: FSTRING_START +.. data:: TAGSTRING_START + .. data:: FSTRING_MIDDLE .. data:: FSTRING_END diff --git a/Grammar/Tokens b/Grammar/Tokens index 096876fdd130f8..14548745d53df4 100644 --- a/Grammar/Tokens +++ b/Grammar/Tokens @@ -62,6 +62,7 @@ TYPE_IGNORE TYPE_COMMENT SOFT_KEYWORD FSTRING_START +TAGSTRING_START FSTRING_MIDDLE FSTRING_END ERRORTOKEN diff --git a/Include/internal/pycore_token.h b/Include/internal/pycore_token.h index b9df8766736adf..2df6e0498a233a 100644 --- a/Include/internal/pycore_token.h +++ b/Include/internal/pycore_token.h @@ -75,10 +75,11 @@ extern "C" { #define TYPE_COMMENT 59 #define SOFT_KEYWORD 60 #define FSTRING_START 61 -#define FSTRING_MIDDLE 62 -#define FSTRING_END 63 -#define ERRORTOKEN 64 -#define N_TOKENS 68 +#define TAGSTRING_START 62 +#define FSTRING_MIDDLE 63 +#define FSTRING_END 64 +#define ERRORTOKEN 65 +#define N_TOKENS 69 #define NT_OFFSET 256 /* Special definitions for cooperation with parser */ diff --git a/Lib/token.py b/Lib/token.py index 1459d12b376f82..76881d03f3e3b8 100644 --- a/Lib/token.py +++ b/Lib/token.py @@ -65,14 +65,15 @@ TYPE_COMMENT = 59 SOFT_KEYWORD = 60 FSTRING_START = 61 -FSTRING_MIDDLE = 62 -FSTRING_END = 63 +TAGSTRING_START = 62 +FSTRING_MIDDLE = 63 +FSTRING_END = 64 # These aren't used by the C tokenizer but are needed for tokenize.py -ERRORTOKEN = 64 -COMMENT = 65 -NL = 66 -ENCODING = 67 -N_TOKENS = 68 +ERRORTOKEN = 65 +COMMENT = 66 +NL = 67 +ENCODING = 68 +N_TOKENS = 69 # Special definitions for cooperation with parser NT_OFFSET = 256 diff --git a/Parser/token.c b/Parser/token.c index 82267fbfcd0c54..8df8cfc09d9ba1 100644 --- a/Parser/token.c +++ b/Parser/token.c @@ -68,6 +68,7 @@ const char * const _PyParser_TokenNames[] = { "TYPE_COMMENT", "SOFT_KEYWORD", "FSTRING_START", + "TAGSTRING_START", "FSTRING_MIDDLE", "FSTRING_END", "", diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index ec5edf5abefeb3..bdaa65b100f376 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2253,7 +2253,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t the_current_tok->curly_bracket_depth = 0; the_current_tok->curly_bracket_expr_start_depth = -1; - return MAKE_TOKEN(FSTRING_START); + return in_tag_string ? MAKE_TOKEN(TAGSTRING_START) : MAKE_TOKEN(FSTRING_START); } letter_quote: From 250dfebb3c1d2b308c2296ec6e20f629a28c084e Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 24 Apr 2023 12:11:44 -0600 Subject: [PATCH 0003/1206] TAGSTRING_START is a new token --- Grammar/python.gram | 6 +- Parser/parser.c | 3548 ++++++++++++++++++++++--------------------- 2 files changed, 1858 insertions(+), 1696 deletions(-) diff --git a/Grammar/python.gram b/Grammar/python.gram index 3a356c65a75195..d0ac944d8addd7 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -807,7 +807,7 @@ atom[expr_ty]: | 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) } | 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) } | 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) } - | &(STRING|FSTRING_START) strings + | &(STRING|FSTRING_START|TAGSTRING_START) strings | NUMBER | &'(' (tuple | group | genexp) | &'[' (list | listcomp) @@ -894,9 +894,11 @@ fstring_format_spec[expr_ty]: | fstring_replacement_field fstring[expr_ty]: | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } +tagstring[expr_ty]: + | a=TAGSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) } -strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) } +strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|tagstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) } list[expr_ty]: | '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) } diff --git a/Parser/parser.c b/Parser/parser.c index 771366844fc489..75f6c8492abcd3 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -229,365 +229,367 @@ static char *soft_keywords[] = { #define fstring_conversion_type 1149 #define fstring_full_format_spec_type 1150 #define fstring_format_spec_type 1151 -#define string_type 1152 -#define strings_type 1153 -#define list_type 1154 -#define tuple_type 1155 -#define set_type 1156 -#define dict_type 1157 -#define double_starred_kvpairs_type 1158 -#define double_starred_kvpair_type 1159 -#define kvpair_type 1160 -#define for_if_clauses_type 1161 -#define for_if_clause_type 1162 -#define listcomp_type 1163 -#define setcomp_type 1164 -#define genexp_type 1165 -#define dictcomp_type 1166 -#define arguments_type 1167 -#define args_type 1168 -#define kwargs_type 1169 -#define starred_expression_type 1170 -#define kwarg_or_starred_type 1171 -#define kwarg_or_double_starred_type 1172 -#define star_targets_type 1173 -#define star_targets_list_seq_type 1174 -#define star_targets_tuple_seq_type 1175 -#define star_target_type 1176 -#define target_with_star_atom_type 1177 -#define star_atom_type 1178 -#define single_target_type 1179 -#define single_subscript_attribute_target_type 1180 -#define t_primary_type 1181 // Left-recursive -#define t_lookahead_type 1182 -#define del_targets_type 1183 -#define del_target_type 1184 -#define del_t_atom_type 1185 -#define type_expressions_type 1186 -#define func_type_comment_type 1187 -#define invalid_arguments_type 1188 -#define invalid_kwarg_type 1189 -#define expression_without_invalid_type 1190 -#define invalid_legacy_expression_type 1191 -#define invalid_expression_type 1192 -#define invalid_named_expression_type 1193 -#define invalid_assignment_type 1194 -#define invalid_ann_assign_target_type 1195 -#define invalid_del_stmt_type 1196 -#define invalid_block_type 1197 -#define invalid_comprehension_type 1198 -#define invalid_dict_comprehension_type 1199 -#define invalid_parameters_type 1200 -#define invalid_default_type 1201 -#define invalid_star_etc_type 1202 -#define invalid_kwds_type 1203 -#define invalid_parameters_helper_type 1204 -#define invalid_lambda_parameters_type 1205 -#define invalid_lambda_parameters_helper_type 1206 -#define invalid_lambda_star_etc_type 1207 -#define invalid_lambda_kwds_type 1208 -#define invalid_double_type_comments_type 1209 -#define invalid_with_item_type 1210 -#define invalid_for_target_type 1211 -#define invalid_group_type 1212 -#define invalid_import_type 1213 -#define invalid_import_from_targets_type 1214 -#define invalid_with_stmt_type 1215 -#define invalid_with_stmt_indent_type 1216 -#define invalid_try_stmt_type 1217 -#define invalid_except_stmt_type 1218 -#define invalid_finally_stmt_type 1219 -#define invalid_except_stmt_indent_type 1220 -#define invalid_except_star_stmt_indent_type 1221 -#define invalid_match_stmt_type 1222 -#define invalid_case_block_type 1223 -#define invalid_as_pattern_type 1224 -#define invalid_class_pattern_type 1225 -#define invalid_class_argument_pattern_type 1226 -#define invalid_if_stmt_type 1227 -#define invalid_elif_stmt_type 1228 -#define invalid_else_stmt_type 1229 -#define invalid_while_stmt_type 1230 -#define invalid_for_stmt_type 1231 -#define invalid_def_raw_type 1232 -#define invalid_class_def_raw_type 1233 -#define invalid_double_starred_kvpairs_type 1234 -#define invalid_kvpair_type 1235 -#define invalid_starred_expression_type 1236 -#define invalid_replacement_field_type 1237 -#define invalid_conversion_character_type 1238 -#define _loop0_1_type 1239 -#define _loop0_2_type 1240 -#define _loop0_3_type 1241 -#define _loop1_4_type 1242 -#define _loop0_6_type 1243 -#define _gather_5_type 1244 -#define _tmp_7_type 1245 -#define _tmp_8_type 1246 -#define _tmp_9_type 1247 -#define _tmp_10_type 1248 -#define _tmp_11_type 1249 -#define _tmp_12_type 1250 -#define _tmp_13_type 1251 -#define _tmp_14_type 1252 -#define _loop1_15_type 1253 -#define _tmp_16_type 1254 -#define _tmp_17_type 1255 -#define _tmp_18_type 1256 -#define _loop0_20_type 1257 -#define _gather_19_type 1258 -#define _loop0_22_type 1259 -#define _gather_21_type 1260 -#define _tmp_23_type 1261 -#define _tmp_24_type 1262 -#define _loop0_25_type 1263 -#define _loop1_26_type 1264 -#define _loop0_28_type 1265 -#define _gather_27_type 1266 -#define _tmp_29_type 1267 -#define _loop0_31_type 1268 -#define _gather_30_type 1269 -#define _tmp_32_type 1270 -#define _loop1_33_type 1271 -#define _tmp_34_type 1272 -#define _tmp_35_type 1273 -#define _tmp_36_type 1274 -#define _loop0_37_type 1275 -#define _loop0_38_type 1276 -#define _loop0_39_type 1277 -#define _loop1_40_type 1278 -#define _loop0_41_type 1279 -#define _loop1_42_type 1280 -#define _loop1_43_type 1281 -#define _loop1_44_type 1282 -#define _loop0_45_type 1283 -#define _loop1_46_type 1284 -#define _loop0_47_type 1285 -#define _loop1_48_type 1286 -#define _loop0_49_type 1287 -#define _loop0_50_type 1288 -#define _loop1_51_type 1289 -#define _loop0_53_type 1290 -#define _gather_52_type 1291 -#define _loop0_55_type 1292 -#define _gather_54_type 1293 -#define _loop0_57_type 1294 -#define _gather_56_type 1295 -#define _loop0_59_type 1296 -#define _gather_58_type 1297 -#define _tmp_60_type 1298 -#define _loop1_61_type 1299 -#define _loop1_62_type 1300 -#define _tmp_63_type 1301 -#define _tmp_64_type 1302 -#define _loop1_65_type 1303 -#define _loop0_67_type 1304 -#define _gather_66_type 1305 -#define _tmp_68_type 1306 -#define _tmp_69_type 1307 -#define _tmp_70_type 1308 -#define _tmp_71_type 1309 -#define _loop0_73_type 1310 -#define _gather_72_type 1311 -#define _loop0_75_type 1312 -#define _gather_74_type 1313 -#define _tmp_76_type 1314 -#define _loop0_78_type 1315 -#define _gather_77_type 1316 -#define _loop0_80_type 1317 -#define _gather_79_type 1318 -#define _loop1_81_type 1319 -#define _loop1_82_type 1320 -#define _loop0_84_type 1321 -#define _gather_83_type 1322 -#define _loop1_85_type 1323 -#define _loop1_86_type 1324 -#define _loop1_87_type 1325 -#define _tmp_88_type 1326 -#define _loop0_90_type 1327 -#define _gather_89_type 1328 -#define _tmp_91_type 1329 -#define _tmp_92_type 1330 -#define _tmp_93_type 1331 -#define _tmp_94_type 1332 -#define _tmp_95_type 1333 -#define _tmp_96_type 1334 -#define _loop0_97_type 1335 -#define _loop0_98_type 1336 -#define _loop0_99_type 1337 -#define _loop1_100_type 1338 -#define _loop0_101_type 1339 -#define _loop1_102_type 1340 -#define _loop1_103_type 1341 -#define _loop1_104_type 1342 -#define _loop0_105_type 1343 -#define _loop1_106_type 1344 -#define _loop0_107_type 1345 -#define _loop1_108_type 1346 -#define _loop0_109_type 1347 -#define _loop1_110_type 1348 -#define _tmp_111_type 1349 -#define _loop0_112_type 1350 -#define _loop1_113_type 1351 -#define _tmp_114_type 1352 -#define _loop0_116_type 1353 -#define _gather_115_type 1354 -#define _loop1_117_type 1355 -#define _loop0_118_type 1356 -#define _loop0_119_type 1357 -#define _tmp_120_type 1358 -#define _loop0_122_type 1359 -#define _gather_121_type 1360 -#define _tmp_123_type 1361 -#define _loop0_125_type 1362 -#define _gather_124_type 1363 -#define _loop0_127_type 1364 -#define _gather_126_type 1365 -#define _loop0_129_type 1366 -#define _gather_128_type 1367 -#define _loop0_131_type 1368 -#define _gather_130_type 1369 +#define tagstring_type 1152 +#define string_type 1153 +#define strings_type 1154 +#define list_type 1155 +#define tuple_type 1156 +#define set_type 1157 +#define dict_type 1158 +#define double_starred_kvpairs_type 1159 +#define double_starred_kvpair_type 1160 +#define kvpair_type 1161 +#define for_if_clauses_type 1162 +#define for_if_clause_type 1163 +#define listcomp_type 1164 +#define setcomp_type 1165 +#define genexp_type 1166 +#define dictcomp_type 1167 +#define arguments_type 1168 +#define args_type 1169 +#define kwargs_type 1170 +#define starred_expression_type 1171 +#define kwarg_or_starred_type 1172 +#define kwarg_or_double_starred_type 1173 +#define star_targets_type 1174 +#define star_targets_list_seq_type 1175 +#define star_targets_tuple_seq_type 1176 +#define star_target_type 1177 +#define target_with_star_atom_type 1178 +#define star_atom_type 1179 +#define single_target_type 1180 +#define single_subscript_attribute_target_type 1181 +#define t_primary_type 1182 // Left-recursive +#define t_lookahead_type 1183 +#define del_targets_type 1184 +#define del_target_type 1185 +#define del_t_atom_type 1186 +#define type_expressions_type 1187 +#define func_type_comment_type 1188 +#define invalid_arguments_type 1189 +#define invalid_kwarg_type 1190 +#define expression_without_invalid_type 1191 +#define invalid_legacy_expression_type 1192 +#define invalid_expression_type 1193 +#define invalid_named_expression_type 1194 +#define invalid_assignment_type 1195 +#define invalid_ann_assign_target_type 1196 +#define invalid_del_stmt_type 1197 +#define invalid_block_type 1198 +#define invalid_comprehension_type 1199 +#define invalid_dict_comprehension_type 1200 +#define invalid_parameters_type 1201 +#define invalid_default_type 1202 +#define invalid_star_etc_type 1203 +#define invalid_kwds_type 1204 +#define invalid_parameters_helper_type 1205 +#define invalid_lambda_parameters_type 1206 +#define invalid_lambda_parameters_helper_type 1207 +#define invalid_lambda_star_etc_type 1208 +#define invalid_lambda_kwds_type 1209 +#define invalid_double_type_comments_type 1210 +#define invalid_with_item_type 1211 +#define invalid_for_target_type 1212 +#define invalid_group_type 1213 +#define invalid_import_type 1214 +#define invalid_import_from_targets_type 1215 +#define invalid_with_stmt_type 1216 +#define invalid_with_stmt_indent_type 1217 +#define invalid_try_stmt_type 1218 +#define invalid_except_stmt_type 1219 +#define invalid_finally_stmt_type 1220 +#define invalid_except_stmt_indent_type 1221 +#define invalid_except_star_stmt_indent_type 1222 +#define invalid_match_stmt_type 1223 +#define invalid_case_block_type 1224 +#define invalid_as_pattern_type 1225 +#define invalid_class_pattern_type 1226 +#define invalid_class_argument_pattern_type 1227 +#define invalid_if_stmt_type 1228 +#define invalid_elif_stmt_type 1229 +#define invalid_else_stmt_type 1230 +#define invalid_while_stmt_type 1231 +#define invalid_for_stmt_type 1232 +#define invalid_def_raw_type 1233 +#define invalid_class_def_raw_type 1234 +#define invalid_double_starred_kvpairs_type 1235 +#define invalid_kvpair_type 1236 +#define invalid_starred_expression_type 1237 +#define invalid_replacement_field_type 1238 +#define invalid_conversion_character_type 1239 +#define _loop0_1_type 1240 +#define _loop0_2_type 1241 +#define _loop0_3_type 1242 +#define _loop1_4_type 1243 +#define _loop0_6_type 1244 +#define _gather_5_type 1245 +#define _tmp_7_type 1246 +#define _tmp_8_type 1247 +#define _tmp_9_type 1248 +#define _tmp_10_type 1249 +#define _tmp_11_type 1250 +#define _tmp_12_type 1251 +#define _tmp_13_type 1252 +#define _tmp_14_type 1253 +#define _loop1_15_type 1254 +#define _tmp_16_type 1255 +#define _tmp_17_type 1256 +#define _tmp_18_type 1257 +#define _loop0_20_type 1258 +#define _gather_19_type 1259 +#define _loop0_22_type 1260 +#define _gather_21_type 1261 +#define _tmp_23_type 1262 +#define _tmp_24_type 1263 +#define _loop0_25_type 1264 +#define _loop1_26_type 1265 +#define _loop0_28_type 1266 +#define _gather_27_type 1267 +#define _tmp_29_type 1268 +#define _loop0_31_type 1269 +#define _gather_30_type 1270 +#define _tmp_32_type 1271 +#define _loop1_33_type 1272 +#define _tmp_34_type 1273 +#define _tmp_35_type 1274 +#define _tmp_36_type 1275 +#define _loop0_37_type 1276 +#define _loop0_38_type 1277 +#define _loop0_39_type 1278 +#define _loop1_40_type 1279 +#define _loop0_41_type 1280 +#define _loop1_42_type 1281 +#define _loop1_43_type 1282 +#define _loop1_44_type 1283 +#define _loop0_45_type 1284 +#define _loop1_46_type 1285 +#define _loop0_47_type 1286 +#define _loop1_48_type 1287 +#define _loop0_49_type 1288 +#define _loop0_50_type 1289 +#define _loop1_51_type 1290 +#define _loop0_53_type 1291 +#define _gather_52_type 1292 +#define _loop0_55_type 1293 +#define _gather_54_type 1294 +#define _loop0_57_type 1295 +#define _gather_56_type 1296 +#define _loop0_59_type 1297 +#define _gather_58_type 1298 +#define _tmp_60_type 1299 +#define _loop1_61_type 1300 +#define _loop1_62_type 1301 +#define _tmp_63_type 1302 +#define _tmp_64_type 1303 +#define _loop1_65_type 1304 +#define _loop0_67_type 1305 +#define _gather_66_type 1306 +#define _tmp_68_type 1307 +#define _tmp_69_type 1308 +#define _tmp_70_type 1309 +#define _tmp_71_type 1310 +#define _loop0_73_type 1311 +#define _gather_72_type 1312 +#define _loop0_75_type 1313 +#define _gather_74_type 1314 +#define _tmp_76_type 1315 +#define _loop0_78_type 1316 +#define _gather_77_type 1317 +#define _loop0_80_type 1318 +#define _gather_79_type 1319 +#define _loop1_81_type 1320 +#define _loop1_82_type 1321 +#define _loop0_84_type 1322 +#define _gather_83_type 1323 +#define _loop1_85_type 1324 +#define _loop1_86_type 1325 +#define _loop1_87_type 1326 +#define _tmp_88_type 1327 +#define _loop0_90_type 1328 +#define _gather_89_type 1329 +#define _tmp_91_type 1330 +#define _tmp_92_type 1331 +#define _tmp_93_type 1332 +#define _tmp_94_type 1333 +#define _tmp_95_type 1334 +#define _tmp_96_type 1335 +#define _loop0_97_type 1336 +#define _loop0_98_type 1337 +#define _loop0_99_type 1338 +#define _loop1_100_type 1339 +#define _loop0_101_type 1340 +#define _loop1_102_type 1341 +#define _loop1_103_type 1342 +#define _loop1_104_type 1343 +#define _loop0_105_type 1344 +#define _loop1_106_type 1345 +#define _loop0_107_type 1346 +#define _loop1_108_type 1347 +#define _loop0_109_type 1348 +#define _loop1_110_type 1349 +#define _tmp_111_type 1350 +#define _loop0_112_type 1351 +#define _loop0_113_type 1352 +#define _loop1_114_type 1353 +#define _tmp_115_type 1354 +#define _loop0_117_type 1355 +#define _gather_116_type 1356 +#define _loop1_118_type 1357 +#define _loop0_119_type 1358 +#define _loop0_120_type 1359 +#define _tmp_121_type 1360 +#define _loop0_123_type 1361 +#define _gather_122_type 1362 +#define _tmp_124_type 1363 +#define _loop0_126_type 1364 +#define _gather_125_type 1365 +#define _loop0_128_type 1366 +#define _gather_127_type 1367 +#define _loop0_130_type 1368 +#define _gather_129_type 1369 #define _loop0_132_type 1370 -#define _loop0_134_type 1371 -#define _gather_133_type 1372 -#define _loop1_135_type 1373 -#define _tmp_136_type 1374 -#define _loop0_138_type 1375 -#define _gather_137_type 1376 -#define _loop0_140_type 1377 -#define _gather_139_type 1378 -#define _loop0_142_type 1379 -#define _gather_141_type 1380 -#define _loop0_144_type 1381 -#define _gather_143_type 1382 -#define _loop0_146_type 1383 -#define _gather_145_type 1384 -#define _tmp_147_type 1385 -#define _tmp_148_type 1386 -#define _tmp_149_type 1387 -#define _tmp_150_type 1388 -#define _tmp_151_type 1389 -#define _tmp_152_type 1390 -#define _tmp_153_type 1391 -#define _tmp_154_type 1392 -#define _tmp_155_type 1393 -#define _tmp_156_type 1394 -#define _tmp_157_type 1395 -#define _tmp_158_type 1396 -#define _loop0_159_type 1397 -#define _loop0_160_type 1398 -#define _loop0_161_type 1399 -#define _tmp_162_type 1400 -#define _tmp_163_type 1401 -#define _tmp_164_type 1402 -#define _tmp_165_type 1403 -#define _tmp_166_type 1404 -#define _loop0_167_type 1405 -#define _loop0_168_type 1406 -#define _loop0_169_type 1407 -#define _loop1_170_type 1408 -#define _tmp_171_type 1409 -#define _loop0_172_type 1410 -#define _tmp_173_type 1411 -#define _loop0_174_type 1412 -#define _loop1_175_type 1413 -#define _tmp_176_type 1414 -#define _tmp_177_type 1415 -#define _tmp_178_type 1416 -#define _loop0_179_type 1417 -#define _tmp_180_type 1418 -#define _tmp_181_type 1419 -#define _loop1_182_type 1420 -#define _tmp_183_type 1421 -#define _loop0_184_type 1422 -#define _loop0_185_type 1423 -#define _loop0_186_type 1424 -#define _loop0_188_type 1425 -#define _gather_187_type 1426 -#define _tmp_189_type 1427 -#define _loop0_190_type 1428 -#define _tmp_191_type 1429 -#define _loop0_192_type 1430 -#define _loop1_193_type 1431 -#define _loop1_194_type 1432 -#define _tmp_195_type 1433 -#define _tmp_196_type 1434 -#define _loop0_197_type 1435 -#define _tmp_198_type 1436 -#define _tmp_199_type 1437 -#define _tmp_200_type 1438 -#define _loop0_202_type 1439 -#define _gather_201_type 1440 -#define _loop0_204_type 1441 -#define _gather_203_type 1442 -#define _loop0_206_type 1443 -#define _gather_205_type 1444 -#define _loop0_208_type 1445 -#define _gather_207_type 1446 -#define _tmp_209_type 1447 -#define _loop0_210_type 1448 -#define _loop1_211_type 1449 -#define _tmp_212_type 1450 -#define _loop0_213_type 1451 -#define _loop1_214_type 1452 -#define _tmp_215_type 1453 -#define _tmp_216_type 1454 -#define _tmp_217_type 1455 -#define _tmp_218_type 1456 -#define _tmp_219_type 1457 -#define _tmp_220_type 1458 -#define _tmp_221_type 1459 -#define _tmp_222_type 1460 -#define _tmp_223_type 1461 -#define _tmp_224_type 1462 -#define _loop0_226_type 1463 -#define _gather_225_type 1464 -#define _tmp_227_type 1465 -#define _tmp_228_type 1466 -#define _tmp_229_type 1467 -#define _tmp_230_type 1468 -#define _tmp_231_type 1469 -#define _tmp_232_type 1470 -#define _tmp_233_type 1471 -#define _tmp_234_type 1472 -#define _tmp_235_type 1473 -#define _tmp_236_type 1474 -#define _tmp_237_type 1475 -#define _tmp_238_type 1476 -#define _tmp_239_type 1477 -#define _loop0_240_type 1478 -#define _tmp_241_type 1479 -#define _tmp_242_type 1480 -#define _tmp_243_type 1481 -#define _tmp_244_type 1482 -#define _tmp_245_type 1483 -#define _tmp_246_type 1484 -#define _tmp_247_type 1485 -#define _tmp_248_type 1486 -#define _tmp_249_type 1487 -#define _tmp_250_type 1488 -#define _tmp_251_type 1489 -#define _tmp_252_type 1490 -#define _tmp_253_type 1491 -#define _tmp_254_type 1492 -#define _tmp_255_type 1493 -#define _tmp_256_type 1494 -#define _tmp_257_type 1495 -#define _tmp_258_type 1496 -#define _tmp_259_type 1497 -#define _tmp_260_type 1498 -#define _tmp_261_type 1499 -#define _tmp_262_type 1500 -#define _tmp_263_type 1501 -#define _tmp_264_type 1502 -#define _tmp_265_type 1503 -#define _tmp_266_type 1504 -#define _tmp_267_type 1505 -#define _tmp_268_type 1506 -#define _tmp_269_type 1507 -#define _tmp_270_type 1508 -#define _tmp_271_type 1509 -#define _tmp_272_type 1510 +#define _gather_131_type 1371 +#define _loop0_133_type 1372 +#define _loop0_135_type 1373 +#define _gather_134_type 1374 +#define _loop1_136_type 1375 +#define _tmp_137_type 1376 +#define _loop0_139_type 1377 +#define _gather_138_type 1378 +#define _loop0_141_type 1379 +#define _gather_140_type 1380 +#define _loop0_143_type 1381 +#define _gather_142_type 1382 +#define _loop0_145_type 1383 +#define _gather_144_type 1384 +#define _loop0_147_type 1385 +#define _gather_146_type 1386 +#define _tmp_148_type 1387 +#define _tmp_149_type 1388 +#define _tmp_150_type 1389 +#define _tmp_151_type 1390 +#define _tmp_152_type 1391 +#define _tmp_153_type 1392 +#define _tmp_154_type 1393 +#define _tmp_155_type 1394 +#define _tmp_156_type 1395 +#define _tmp_157_type 1396 +#define _tmp_158_type 1397 +#define _tmp_159_type 1398 +#define _loop0_160_type 1399 +#define _loop0_161_type 1400 +#define _loop0_162_type 1401 +#define _tmp_163_type 1402 +#define _tmp_164_type 1403 +#define _tmp_165_type 1404 +#define _tmp_166_type 1405 +#define _tmp_167_type 1406 +#define _loop0_168_type 1407 +#define _loop0_169_type 1408 +#define _loop0_170_type 1409 +#define _loop1_171_type 1410 +#define _tmp_172_type 1411 +#define _loop0_173_type 1412 +#define _tmp_174_type 1413 +#define _loop0_175_type 1414 +#define _loop1_176_type 1415 +#define _tmp_177_type 1416 +#define _tmp_178_type 1417 +#define _tmp_179_type 1418 +#define _loop0_180_type 1419 +#define _tmp_181_type 1420 +#define _tmp_182_type 1421 +#define _loop1_183_type 1422 +#define _tmp_184_type 1423 +#define _loop0_185_type 1424 +#define _loop0_186_type 1425 +#define _loop0_187_type 1426 +#define _loop0_189_type 1427 +#define _gather_188_type 1428 +#define _tmp_190_type 1429 +#define _loop0_191_type 1430 +#define _tmp_192_type 1431 +#define _loop0_193_type 1432 +#define _loop1_194_type 1433 +#define _loop1_195_type 1434 +#define _tmp_196_type 1435 +#define _tmp_197_type 1436 +#define _loop0_198_type 1437 +#define _tmp_199_type 1438 +#define _tmp_200_type 1439 +#define _tmp_201_type 1440 +#define _loop0_203_type 1441 +#define _gather_202_type 1442 +#define _loop0_205_type 1443 +#define _gather_204_type 1444 +#define _loop0_207_type 1445 +#define _gather_206_type 1446 +#define _loop0_209_type 1447 +#define _gather_208_type 1448 +#define _tmp_210_type 1449 +#define _loop0_211_type 1450 +#define _loop1_212_type 1451 +#define _tmp_213_type 1452 +#define _loop0_214_type 1453 +#define _loop1_215_type 1454 +#define _tmp_216_type 1455 +#define _tmp_217_type 1456 +#define _tmp_218_type 1457 +#define _tmp_219_type 1458 +#define _tmp_220_type 1459 +#define _tmp_221_type 1460 +#define _tmp_222_type 1461 +#define _tmp_223_type 1462 +#define _tmp_224_type 1463 +#define _tmp_225_type 1464 +#define _loop0_227_type 1465 +#define _gather_226_type 1466 +#define _tmp_228_type 1467 +#define _tmp_229_type 1468 +#define _tmp_230_type 1469 +#define _tmp_231_type 1470 +#define _tmp_232_type 1471 +#define _tmp_233_type 1472 +#define _tmp_234_type 1473 +#define _tmp_235_type 1474 +#define _tmp_236_type 1475 +#define _tmp_237_type 1476 +#define _tmp_238_type 1477 +#define _tmp_239_type 1478 +#define _tmp_240_type 1479 +#define _loop0_241_type 1480 +#define _tmp_242_type 1481 +#define _tmp_243_type 1482 +#define _tmp_244_type 1483 +#define _tmp_245_type 1484 +#define _tmp_246_type 1485 +#define _tmp_247_type 1486 +#define _tmp_248_type 1487 +#define _tmp_249_type 1488 +#define _tmp_250_type 1489 +#define _tmp_251_type 1490 +#define _tmp_252_type 1491 +#define _tmp_253_type 1492 +#define _tmp_254_type 1493 +#define _tmp_255_type 1494 +#define _tmp_256_type 1495 +#define _tmp_257_type 1496 +#define _tmp_258_type 1497 +#define _tmp_259_type 1498 +#define _tmp_260_type 1499 +#define _tmp_261_type 1500 +#define _tmp_262_type 1501 +#define _tmp_263_type 1502 +#define _tmp_264_type 1503 +#define _tmp_265_type 1504 +#define _tmp_266_type 1505 +#define _tmp_267_type 1506 +#define _tmp_268_type 1507 +#define _tmp_269_type 1508 +#define _tmp_270_type 1509 +#define _tmp_271_type 1510 +#define _tmp_272_type 1511 +#define _tmp_273_type 1512 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -741,6 +743,7 @@ static expr_ty fstring_replacement_field_rule(Parser *p); static expr_ty fstring_conversion_rule(Parser *p); static expr_ty fstring_full_format_spec_rule(Parser *p); static expr_ty fstring_format_spec_rule(Parser *p); +static expr_ty tagstring_rule(Parser *p); static expr_ty string_rule(Parser *p); static expr_ty strings_rule(Parser *p); static expr_ty list_rule(Parser *p); @@ -940,41 +943,41 @@ static asdl_seq *_loop0_109_rule(Parser *p); static asdl_seq *_loop1_110_rule(Parser *p); static void *_tmp_111_rule(Parser *p); static asdl_seq *_loop0_112_rule(Parser *p); -static asdl_seq *_loop1_113_rule(Parser *p); -static void *_tmp_114_rule(Parser *p); -static asdl_seq *_loop0_116_rule(Parser *p); -static asdl_seq *_gather_115_rule(Parser *p); -static asdl_seq *_loop1_117_rule(Parser *p); -static asdl_seq *_loop0_118_rule(Parser *p); +static asdl_seq *_loop0_113_rule(Parser *p); +static asdl_seq *_loop1_114_rule(Parser *p); +static void *_tmp_115_rule(Parser *p); +static asdl_seq *_loop0_117_rule(Parser *p); +static asdl_seq *_gather_116_rule(Parser *p); +static asdl_seq *_loop1_118_rule(Parser *p); static asdl_seq *_loop0_119_rule(Parser *p); -static void *_tmp_120_rule(Parser *p); -static asdl_seq *_loop0_122_rule(Parser *p); -static asdl_seq *_gather_121_rule(Parser *p); -static void *_tmp_123_rule(Parser *p); -static asdl_seq *_loop0_125_rule(Parser *p); -static asdl_seq *_gather_124_rule(Parser *p); -static asdl_seq *_loop0_127_rule(Parser *p); -static asdl_seq *_gather_126_rule(Parser *p); -static asdl_seq *_loop0_129_rule(Parser *p); -static asdl_seq *_gather_128_rule(Parser *p); -static asdl_seq *_loop0_131_rule(Parser *p); -static asdl_seq *_gather_130_rule(Parser *p); +static asdl_seq *_loop0_120_rule(Parser *p); +static void *_tmp_121_rule(Parser *p); +static asdl_seq *_loop0_123_rule(Parser *p); +static asdl_seq *_gather_122_rule(Parser *p); +static void *_tmp_124_rule(Parser *p); +static asdl_seq *_loop0_126_rule(Parser *p); +static asdl_seq *_gather_125_rule(Parser *p); +static asdl_seq *_loop0_128_rule(Parser *p); +static asdl_seq *_gather_127_rule(Parser *p); +static asdl_seq *_loop0_130_rule(Parser *p); +static asdl_seq *_gather_129_rule(Parser *p); static asdl_seq *_loop0_132_rule(Parser *p); -static asdl_seq *_loop0_134_rule(Parser *p); -static asdl_seq *_gather_133_rule(Parser *p); -static asdl_seq *_loop1_135_rule(Parser *p); -static void *_tmp_136_rule(Parser *p); -static asdl_seq *_loop0_138_rule(Parser *p); -static asdl_seq *_gather_137_rule(Parser *p); -static asdl_seq *_loop0_140_rule(Parser *p); -static asdl_seq *_gather_139_rule(Parser *p); -static asdl_seq *_loop0_142_rule(Parser *p); -static asdl_seq *_gather_141_rule(Parser *p); -static asdl_seq *_loop0_144_rule(Parser *p); -static asdl_seq *_gather_143_rule(Parser *p); -static asdl_seq *_loop0_146_rule(Parser *p); -static asdl_seq *_gather_145_rule(Parser *p); -static void *_tmp_147_rule(Parser *p); +static asdl_seq *_gather_131_rule(Parser *p); +static asdl_seq *_loop0_133_rule(Parser *p); +static asdl_seq *_loop0_135_rule(Parser *p); +static asdl_seq *_gather_134_rule(Parser *p); +static asdl_seq *_loop1_136_rule(Parser *p); +static void *_tmp_137_rule(Parser *p); +static asdl_seq *_loop0_139_rule(Parser *p); +static asdl_seq *_gather_138_rule(Parser *p); +static asdl_seq *_loop0_141_rule(Parser *p); +static asdl_seq *_gather_140_rule(Parser *p); +static asdl_seq *_loop0_143_rule(Parser *p); +static asdl_seq *_gather_142_rule(Parser *p); +static asdl_seq *_loop0_145_rule(Parser *p); +static asdl_seq *_gather_144_rule(Parser *p); +static asdl_seq *_loop0_147_rule(Parser *p); +static asdl_seq *_gather_146_rule(Parser *p); static void *_tmp_148_rule(Parser *p); static void *_tmp_149_rule(Parser *p); static void *_tmp_150_rule(Parser *p); @@ -986,63 +989,63 @@ static void *_tmp_155_rule(Parser *p); static void *_tmp_156_rule(Parser *p); static void *_tmp_157_rule(Parser *p); static void *_tmp_158_rule(Parser *p); -static asdl_seq *_loop0_159_rule(Parser *p); +static void *_tmp_159_rule(Parser *p); static asdl_seq *_loop0_160_rule(Parser *p); static asdl_seq *_loop0_161_rule(Parser *p); -static void *_tmp_162_rule(Parser *p); +static asdl_seq *_loop0_162_rule(Parser *p); static void *_tmp_163_rule(Parser *p); static void *_tmp_164_rule(Parser *p); static void *_tmp_165_rule(Parser *p); static void *_tmp_166_rule(Parser *p); -static asdl_seq *_loop0_167_rule(Parser *p); +static void *_tmp_167_rule(Parser *p); static asdl_seq *_loop0_168_rule(Parser *p); static asdl_seq *_loop0_169_rule(Parser *p); -static asdl_seq *_loop1_170_rule(Parser *p); -static void *_tmp_171_rule(Parser *p); -static asdl_seq *_loop0_172_rule(Parser *p); -static void *_tmp_173_rule(Parser *p); -static asdl_seq *_loop0_174_rule(Parser *p); -static asdl_seq *_loop1_175_rule(Parser *p); -static void *_tmp_176_rule(Parser *p); +static asdl_seq *_loop0_170_rule(Parser *p); +static asdl_seq *_loop1_171_rule(Parser *p); +static void *_tmp_172_rule(Parser *p); +static asdl_seq *_loop0_173_rule(Parser *p); +static void *_tmp_174_rule(Parser *p); +static asdl_seq *_loop0_175_rule(Parser *p); +static asdl_seq *_loop1_176_rule(Parser *p); static void *_tmp_177_rule(Parser *p); static void *_tmp_178_rule(Parser *p); -static asdl_seq *_loop0_179_rule(Parser *p); -static void *_tmp_180_rule(Parser *p); +static void *_tmp_179_rule(Parser *p); +static asdl_seq *_loop0_180_rule(Parser *p); static void *_tmp_181_rule(Parser *p); -static asdl_seq *_loop1_182_rule(Parser *p); -static void *_tmp_183_rule(Parser *p); -static asdl_seq *_loop0_184_rule(Parser *p); +static void *_tmp_182_rule(Parser *p); +static asdl_seq *_loop1_183_rule(Parser *p); +static void *_tmp_184_rule(Parser *p); static asdl_seq *_loop0_185_rule(Parser *p); static asdl_seq *_loop0_186_rule(Parser *p); -static asdl_seq *_loop0_188_rule(Parser *p); -static asdl_seq *_gather_187_rule(Parser *p); -static void *_tmp_189_rule(Parser *p); -static asdl_seq *_loop0_190_rule(Parser *p); -static void *_tmp_191_rule(Parser *p); -static asdl_seq *_loop0_192_rule(Parser *p); -static asdl_seq *_loop1_193_rule(Parser *p); +static asdl_seq *_loop0_187_rule(Parser *p); +static asdl_seq *_loop0_189_rule(Parser *p); +static asdl_seq *_gather_188_rule(Parser *p); +static void *_tmp_190_rule(Parser *p); +static asdl_seq *_loop0_191_rule(Parser *p); +static void *_tmp_192_rule(Parser *p); +static asdl_seq *_loop0_193_rule(Parser *p); static asdl_seq *_loop1_194_rule(Parser *p); -static void *_tmp_195_rule(Parser *p); +static asdl_seq *_loop1_195_rule(Parser *p); static void *_tmp_196_rule(Parser *p); -static asdl_seq *_loop0_197_rule(Parser *p); -static void *_tmp_198_rule(Parser *p); +static void *_tmp_197_rule(Parser *p); +static asdl_seq *_loop0_198_rule(Parser *p); static void *_tmp_199_rule(Parser *p); static void *_tmp_200_rule(Parser *p); -static asdl_seq *_loop0_202_rule(Parser *p); -static asdl_seq *_gather_201_rule(Parser *p); -static asdl_seq *_loop0_204_rule(Parser *p); -static asdl_seq *_gather_203_rule(Parser *p); -static asdl_seq *_loop0_206_rule(Parser *p); -static asdl_seq *_gather_205_rule(Parser *p); -static asdl_seq *_loop0_208_rule(Parser *p); -static asdl_seq *_gather_207_rule(Parser *p); -static void *_tmp_209_rule(Parser *p); -static asdl_seq *_loop0_210_rule(Parser *p); -static asdl_seq *_loop1_211_rule(Parser *p); -static void *_tmp_212_rule(Parser *p); -static asdl_seq *_loop0_213_rule(Parser *p); -static asdl_seq *_loop1_214_rule(Parser *p); -static void *_tmp_215_rule(Parser *p); +static void *_tmp_201_rule(Parser *p); +static asdl_seq *_loop0_203_rule(Parser *p); +static asdl_seq *_gather_202_rule(Parser *p); +static asdl_seq *_loop0_205_rule(Parser *p); +static asdl_seq *_gather_204_rule(Parser *p); +static asdl_seq *_loop0_207_rule(Parser *p); +static asdl_seq *_gather_206_rule(Parser *p); +static asdl_seq *_loop0_209_rule(Parser *p); +static asdl_seq *_gather_208_rule(Parser *p); +static void *_tmp_210_rule(Parser *p); +static asdl_seq *_loop0_211_rule(Parser *p); +static asdl_seq *_loop1_212_rule(Parser *p); +static void *_tmp_213_rule(Parser *p); +static asdl_seq *_loop0_214_rule(Parser *p); +static asdl_seq *_loop1_215_rule(Parser *p); static void *_tmp_216_rule(Parser *p); static void *_tmp_217_rule(Parser *p); static void *_tmp_218_rule(Parser *p); @@ -1052,9 +1055,9 @@ static void *_tmp_221_rule(Parser *p); static void *_tmp_222_rule(Parser *p); static void *_tmp_223_rule(Parser *p); static void *_tmp_224_rule(Parser *p); -static asdl_seq *_loop0_226_rule(Parser *p); -static asdl_seq *_gather_225_rule(Parser *p); -static void *_tmp_227_rule(Parser *p); +static void *_tmp_225_rule(Parser *p); +static asdl_seq *_loop0_227_rule(Parser *p); +static asdl_seq *_gather_226_rule(Parser *p); static void *_tmp_228_rule(Parser *p); static void *_tmp_229_rule(Parser *p); static void *_tmp_230_rule(Parser *p); @@ -1067,8 +1070,8 @@ static void *_tmp_236_rule(Parser *p); static void *_tmp_237_rule(Parser *p); static void *_tmp_238_rule(Parser *p); static void *_tmp_239_rule(Parser *p); -static asdl_seq *_loop0_240_rule(Parser *p); -static void *_tmp_241_rule(Parser *p); +static void *_tmp_240_rule(Parser *p); +static asdl_seq *_loop0_241_rule(Parser *p); static void *_tmp_242_rule(Parser *p); static void *_tmp_243_rule(Parser *p); static void *_tmp_244_rule(Parser *p); @@ -1100,6 +1103,7 @@ static void *_tmp_269_rule(Parser *p); static void *_tmp_270_rule(Parser *p); static void *_tmp_271_rule(Parser *p); static void *_tmp_272_rule(Parser *p); +static void *_tmp_273_rule(Parser *p); // file: statements? $ @@ -14229,7 +14233,7 @@ slice_rule(Parser *p) // | 'True' // | 'False' // | 'None' -// | &(STRING | FSTRING_START) strings +// | &(STRING | FSTRING_START | TAGSTRING_START) strings // | NUMBER // | &'(' (tuple | group | genexp) // | &'[' (list | listcomp) @@ -14375,12 +14379,12 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } - { // &(STRING | FSTRING_START) strings + { // &(STRING | FSTRING_START | TAGSTRING_START) strings if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); + D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START | TAGSTRING_START) strings")); expr_ty strings_var; if ( _PyPegen_lookahead(1, _tmp_92_rule, p) @@ -14388,13 +14392,13 @@ atom_rule(Parser *p) (strings_var = strings_rule(p)) // strings ) { - D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); + D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START | TAGSTRING_START) strings")); _res = strings_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&(STRING | FSTRING_START) strings")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&(STRING | FSTRING_START | TAGSTRING_START) strings")); } { // NUMBER if (p->error_indicator) { @@ -15880,6 +15884,56 @@ fstring_format_spec_rule(Parser *p) return _res; } +// tagstring: TAGSTRING_START fstring_middle* FSTRING_END +static expr_ty +tagstring_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + { // TAGSTRING_START fstring_middle* FSTRING_END + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> tagstring[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "TAGSTRING_START fstring_middle* FSTRING_END")); + Token * a; + asdl_seq * b; + Token * c; + if ( + (a = _PyPegen_expect_token(p, TAGSTRING_START)) // token='TAGSTRING_START' + && + (b = _loop0_113_rule(p)) // fstring_middle* + && + (c = _PyPegen_expect_token(p, FSTRING_END)) // token='FSTRING_END' + ) + { + D(fprintf(stderr, "%*c+ tagstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "TAGSTRING_START fstring_middle* FSTRING_END")); + _res = _PyPegen_joined_str ( p , a , ( asdl_expr_seq* ) b , c ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s tagstring[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "TAGSTRING_START fstring_middle* FSTRING_END")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // string: STRING static expr_ty string_rule(Parser *p) @@ -15924,7 +15978,7 @@ string_rule(Parser *p) return _res; } -// strings: ((fstring | string))+ +// strings: ((fstring | tagstring | string))+ static expr_ty strings_rule(Parser *p) { @@ -15951,18 +16005,18 @@ strings_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // ((fstring | string))+ + { // ((fstring | tagstring | string))+ if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); + D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | tagstring | string))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_113_rule(p)) // ((fstring | string))+ + (a = (asdl_expr_seq*)_loop1_114_rule(p)) // ((fstring | tagstring | string))+ ) { - D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); + D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | tagstring | string))+")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -15982,7 +16036,7 @@ strings_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s strings[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((fstring | string))+")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((fstring | tagstring | string))+")); } _res = NULL; done: @@ -16094,7 +16148,7 @@ tuple_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_114_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] + (a = _tmp_115_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -16312,7 +16366,7 @@ double_starred_kvpairs_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_115_rule(p)) // ','.double_starred_kvpair+ + (a = _gather_116_rule(p)) // ','.double_starred_kvpair+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -16474,7 +16528,7 @@ for_if_clauses_rule(Parser *p) D(fprintf(stderr, "%*c> for_if_clauses[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); asdl_comprehension_seq* a; if ( - (a = (asdl_comprehension_seq*)_loop1_117_rule(p)) // for_if_clause+ + (a = (asdl_comprehension_seq*)_loop1_118_rule(p)) // for_if_clause+ ) { D(fprintf(stderr, "%*c+ for_if_clauses[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); @@ -16539,7 +16593,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_118_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_119_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC 'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -16582,7 +16636,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_119_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_120_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -16845,7 +16899,7 @@ genexp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_120_rule(p)) // assignment_expression | expression !':=' + (a = _tmp_121_rule(p)) // assignment_expression | expression !':=' && (b = for_if_clauses_rule(p)) // for_if_clauses && @@ -17097,9 +17151,9 @@ args_rule(Parser *p) asdl_expr_seq* a; void *b; if ( - (a = (asdl_expr_seq*)_gather_121_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + (a = (asdl_expr_seq*)_gather_122_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ && - (b = _tmp_123_rule(p), !p->error_indicator) // [',' kwargs] + (b = _tmp_124_rule(p), !p->error_indicator) // [',' kwargs] ) { D(fprintf(stderr, "%*c+ args[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ [',' kwargs]")); @@ -17190,11 +17244,11 @@ kwargs_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _gather_124_rule(p)) // ','.kwarg_or_starred+ + (a = _gather_125_rule(p)) // ','.kwarg_or_starred+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _gather_126_rule(p)) // ','.kwarg_or_double_starred+ + (b = _gather_127_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+")); @@ -17216,13 +17270,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - asdl_seq * _gather_128_var; + asdl_seq * _gather_129_var; if ( - (_gather_128_var = _gather_128_rule(p)) // ','.kwarg_or_starred+ + (_gather_129_var = _gather_129_rule(p)) // ','.kwarg_or_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - _res = _gather_128_var; + _res = _gather_129_var; goto done; } p->mark = _mark; @@ -17235,13 +17289,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - asdl_seq * _gather_130_var; + asdl_seq * _gather_131_var; if ( - (_gather_130_var = _gather_130_rule(p)) // ','.kwarg_or_double_starred+ + (_gather_131_var = _gather_131_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - _res = _gather_130_var; + _res = _gather_131_var; goto done; } p->mark = _mark; @@ -17634,7 +17688,7 @@ star_targets_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop0_132_rule(p)) // ((',' star_target))* + (b = _loop0_133_rule(p)) // ((',' star_target))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17691,7 +17745,7 @@ star_targets_list_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_133_rule(p)) // ','.star_target+ + (a = (asdl_expr_seq*)_gather_134_rule(p)) // ','.star_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17742,7 +17796,7 @@ star_targets_tuple_seq_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop1_135_rule(p)) // ((',' star_target))+ + (b = _loop1_136_rule(p)) // ((',' star_target))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17831,7 +17885,7 @@ star_target_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (a = _tmp_136_rule(p)) // !'*' star_target + (a = _tmp_137_rule(p)) // !'*' star_target ) { D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)")); @@ -18762,7 +18816,7 @@ del_targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_137_rule(p)) // ','.del_target+ + (a = (asdl_expr_seq*)_gather_138_rule(p)) // ','.del_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -19123,7 +19177,7 @@ type_expressions_rule(Parser *p) expr_ty b; expr_ty c; if ( - (a = _gather_139_rule(p)) // ','.expression+ + (a = _gather_140_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19162,7 +19216,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_141_rule(p)) // ','.expression+ + (a = _gather_142_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19195,7 +19249,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_143_rule(p)) // ','.expression+ + (a = _gather_144_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19315,7 +19369,7 @@ type_expressions_rule(Parser *p) D(fprintf(stderr, "%*c> type_expressions[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.expression+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_145_rule(p)) // ','.expression+ + (a = (asdl_expr_seq*)_gather_146_rule(p)) // ','.expression+ ) { D(fprintf(stderr, "%*c+ type_expressions[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.expression+")); @@ -19367,7 +19421,7 @@ func_type_comment_rule(Parser *p) && (t = _PyPegen_expect_token(p, TYPE_COMMENT)) // token='TYPE_COMMENT' && - _PyPegen_lookahead(1, _tmp_147_rule, p) + _PyPegen_lookahead(1, _tmp_148_rule, p) ) { D(fprintf(stderr, "%*c+ func_type_comment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE INDENT)")); @@ -19496,7 +19550,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_148_rule(p), !p->error_indicator) // [args | expression for_if_clauses] + (_opt_var = _tmp_149_rule(p), !p->error_indicator) // [args | expression for_if_clauses] ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); @@ -19556,13 +19610,13 @@ invalid_arguments_rule(Parser *p) expr_ty a; Token * b; if ( - (_opt_var = _tmp_149_rule(p), !p->error_indicator) // [(args ',')] + (_opt_var = _tmp_150_rule(p), !p->error_indicator) // [(args ',')] && (a = _PyPegen_name_token(p)) // NAME && (b = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_150_rule, p) + _PyPegen_lookahead(1, _tmp_151_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | ')')")); @@ -19701,7 +19755,7 @@ invalid_kwarg_rule(Parser *p) Token* a; Token * b; if ( - (a = (Token*)_tmp_151_rule(p)) // 'True' | 'False' | 'None' + (a = (Token*)_tmp_152_rule(p)) // 'True' | 'False' | 'None' && (b = _PyPegen_expect_token(p, 22)) // token='=' ) @@ -19761,7 +19815,7 @@ invalid_kwarg_rule(Parser *p) expr_ty a; Token * b; if ( - _PyPegen_lookahead(0, _tmp_152_rule, p) + _PyPegen_lookahead(0, _tmp_153_rule, p) && (a = expression_rule(p)) // expression && @@ -20020,7 +20074,7 @@ invalid_expression_rule(Parser *p) expr_ty a; expr_ty b; if ( - _PyPegen_lookahead(0, _tmp_153_rule, p) + _PyPegen_lookahead(0, _tmp_154_rule, p) && (a = disjunction_rule(p)) // disjunction && @@ -20056,7 +20110,7 @@ invalid_expression_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - _PyPegen_lookahead(0, _tmp_154_rule, p) + _PyPegen_lookahead(0, _tmp_155_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); @@ -20089,7 +20143,7 @@ invalid_expression_rule(Parser *p) && (b = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_155_rule, p) + _PyPegen_lookahead(1, _tmp_156_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)")); @@ -20178,7 +20232,7 @@ invalid_named_expression_rule(Parser *p) && (b = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_156_rule, p) + _PyPegen_lookahead(0, _tmp_157_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | ':=')")); @@ -20204,7 +20258,7 @@ invalid_named_expression_rule(Parser *p) Token * b; expr_ty bitwise_or_var; if ( - _PyPegen_lookahead(0, _tmp_157_rule, p) + _PyPegen_lookahead(0, _tmp_158_rule, p) && (a = bitwise_or_rule(p)) // bitwise_or && @@ -20212,7 +20266,7 @@ invalid_named_expression_rule(Parser *p) && (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_158_rule, p) + _PyPegen_lookahead(0, _tmp_159_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')")); @@ -20293,7 +20347,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_159_var; + asdl_seq * _loop0_160_var; expr_ty a; expr_ty expression_var; if ( @@ -20301,7 +20355,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_159_var = _loop0_159_rule(p)) // star_named_expressions* + (_loop0_160_var = _loop0_160_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -20358,10 +20412,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_160_var; + asdl_seq * _loop0_161_var; expr_ty a; if ( - (_loop0_160_var = _loop0_160_rule(p)) // ((star_targets '='))* + (_loop0_161_var = _loop0_161_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -20388,10 +20442,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_161_var; + asdl_seq * _loop0_162_var; expr_ty a; if ( - (_loop0_161_var = _loop0_161_rule(p)) // ((star_targets '='))* + (_loop0_162_var = _loop0_162_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -20417,7 +20471,7 @@ invalid_assignment_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); - void *_tmp_162_var; + void *_tmp_163_var; expr_ty a; AugOperator* augassign_var; if ( @@ -20425,7 +20479,7 @@ invalid_assignment_rule(Parser *p) && (augassign_var = augassign_rule(p)) // augassign && - (_tmp_162_var = _tmp_162_rule(p)) // yield_expr | star_expressions + (_tmp_163_var = _tmp_163_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); @@ -20651,11 +20705,11 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_163_var; + void *_tmp_164_var; expr_ty a; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_163_var = _tmp_163_rule(p)) // '[' | '(' | '{' + (_tmp_164_var = _tmp_164_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -20682,12 +20736,12 @@ invalid_comprehension_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses")); Token * _literal; - void *_tmp_164_var; + void *_tmp_165_var; expr_ty a; asdl_expr_seq* b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_164_var = _tmp_164_rule(p)) // '[' | '{' + (_tmp_165_var = _tmp_165_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20717,12 +20771,12 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' for_if_clauses")); - void *_tmp_165_var; + void *_tmp_166_var; expr_ty a; Token * b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_165_var = _tmp_165_rule(p)) // '[' | '{' + (_tmp_166_var = _tmp_166_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20859,13 +20913,13 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slash_no_default | slash_with_default) param_maybe_default* '/'")); - asdl_seq * _loop0_167_var; - void *_tmp_166_var; + asdl_seq * _loop0_168_var; + void *_tmp_167_var; Token * a; if ( - (_tmp_166_var = _tmp_166_rule(p)) // slash_no_default | slash_with_default + (_tmp_167_var = _tmp_167_rule(p)) // slash_no_default | slash_with_default && - (_loop0_167_var = _loop0_167_rule(p)) // param_maybe_default* + (_loop0_168_var = _loop0_168_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -20889,7 +20943,7 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default? param_no_default* invalid_parameters_helper param_no_default")); - asdl_seq * _loop0_168_var; + asdl_seq * _loop0_169_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -20897,7 +20951,7 @@ invalid_parameters_rule(Parser *p) if ( (_opt_var = slash_no_default_rule(p), !p->error_indicator) // slash_no_default? && - (_loop0_168_var = _loop0_168_rule(p)) // param_no_default* + (_loop0_169_var = _loop0_169_rule(p)) // param_no_default* && (invalid_parameters_helper_var = invalid_parameters_helper_rule(p)) // invalid_parameters_helper && @@ -20923,18 +20977,18 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* '(' param_no_default+ ','? ')'")); - asdl_seq * _loop0_169_var; - asdl_seq * _loop1_170_var; + asdl_seq * _loop0_170_var; + asdl_seq * _loop1_171_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_169_var = _loop0_169_rule(p)) // param_no_default* + (_loop0_170_var = _loop0_170_rule(p)) // param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_loop1_170_var = _loop1_170_rule(p)) // param_no_default+ + (_loop1_171_var = _loop1_171_rule(p)) // param_no_default+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -20961,22 +21015,22 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(slash_no_default | slash_with_default)] param_maybe_default* '*' (',' | param_no_default) param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_172_var; - asdl_seq * _loop0_174_var; + asdl_seq * _loop0_173_var; + asdl_seq * _loop0_175_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_173_var; + void *_tmp_174_var; Token * a; if ( - (_opt_var = _tmp_171_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] + (_opt_var = _tmp_172_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] && - (_loop0_172_var = _loop0_172_rule(p)) // param_maybe_default* + (_loop0_173_var = _loop0_173_rule(p)) // param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_173_var = _tmp_173_rule(p)) // ',' | param_no_default + (_tmp_174_var = _tmp_174_rule(p)) // ',' | param_no_default && - (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default* + (_loop0_175_var = _loop0_175_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21001,10 +21055,10 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_175_var; + asdl_seq * _loop1_176_var; Token * a; if ( - (_loop1_175_var = _loop1_175_rule(p)) // param_maybe_default+ + (_loop1_176_var = _loop1_176_rule(p)) // param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21054,7 +21108,7 @@ invalid_default_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_176_rule, p) + _PyPegen_lookahead(1, _tmp_177_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')")); @@ -21100,12 +21154,12 @@ invalid_star_etc_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); - void *_tmp_177_var; + void *_tmp_178_var; Token * a; if ( (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_177_var = _tmp_177_rule(p)) // ')' | ',' (')' | '**') + (_tmp_178_var = _tmp_178_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -21188,20 +21242,20 @@ invalid_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_179_var; - void *_tmp_178_var; - void *_tmp_180_var; + asdl_seq * _loop0_180_var; + void *_tmp_179_var; + void *_tmp_181_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_178_var = _tmp_178_rule(p)) // param_no_default | ',' + (_tmp_179_var = _tmp_179_rule(p)) // param_no_default | ',' && - (_loop0_179_var = _loop0_179_rule(p)) // param_maybe_default* + (_loop0_180_var = _loop0_180_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_180_var = _tmp_180_rule(p)) // param_no_default | ',' + (_tmp_181_var = _tmp_181_rule(p)) // param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); @@ -21317,7 +21371,7 @@ invalid_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_181_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_182_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')")); @@ -21383,13 +21437,13 @@ invalid_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - asdl_seq * _loop1_182_var; + asdl_seq * _loop1_183_var; if ( - (_loop1_182_var = _loop1_182_rule(p)) // param_with_default+ + (_loop1_183_var = _loop1_183_rule(p)) // param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - _res = _loop1_182_var; + _res = _loop1_183_var; goto done; } p->mark = _mark; @@ -21455,13 +21509,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/'")); - asdl_seq * _loop0_184_var; - void *_tmp_183_var; + asdl_seq * _loop0_185_var; + void *_tmp_184_var; Token * a; if ( - (_tmp_183_var = _tmp_183_rule(p)) // lambda_slash_no_default | lambda_slash_with_default + (_tmp_184_var = _tmp_184_rule(p)) // lambda_slash_no_default | lambda_slash_with_default && - (_loop0_184_var = _loop0_184_rule(p)) // lambda_param_maybe_default* + (_loop0_185_var = _loop0_185_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21485,7 +21539,7 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default")); - asdl_seq * _loop0_185_var; + asdl_seq * _loop0_186_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21493,7 +21547,7 @@ invalid_lambda_parameters_rule(Parser *p) if ( (_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default? && - (_loop0_185_var = _loop0_185_rule(p)) // lambda_param_no_default* + (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_no_default* && (invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper && @@ -21519,18 +21573,18 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* '(' ','.lambda_param+ ','? ')'")); - asdl_seq * _gather_187_var; - asdl_seq * _loop0_186_var; + asdl_seq * _gather_188_var; + asdl_seq * _loop0_187_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_no_default* + (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_187_var = _gather_187_rule(p)) // ','.lambda_param+ + (_gather_188_var = _gather_188_rule(p)) // ','.lambda_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21557,22 +21611,22 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_190_var; - asdl_seq * _loop0_192_var; + asdl_seq * _loop0_191_var; + asdl_seq * _loop0_193_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_191_var; + void *_tmp_192_var; Token * a; if ( - (_opt_var = _tmp_189_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] + (_opt_var = _tmp_190_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] && - (_loop0_190_var = _loop0_190_rule(p)) // lambda_param_maybe_default* + (_loop0_191_var = _loop0_191_rule(p)) // lambda_param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_191_var = _tmp_191_rule(p)) // ',' | lambda_param_no_default + (_tmp_192_var = _tmp_192_rule(p)) // ',' | lambda_param_no_default && - (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default* + (_loop0_193_var = _loop0_193_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21597,10 +21651,10 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_193_var; + asdl_seq * _loop1_194_var; Token * a; if ( - (_loop1_193_var = _loop1_193_rule(p)) // lambda_param_maybe_default+ + (_loop1_194_var = _loop1_194_rule(p)) // lambda_param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21672,13 +21726,13 @@ invalid_lambda_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_194_var; + asdl_seq * _loop1_195_var; if ( - (_loop1_194_var = _loop1_194_rule(p)) // lambda_param_with_default+ + (_loop1_195_var = _loop1_195_rule(p)) // lambda_param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_lambda_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_194_var; + _res = _loop1_195_var; goto done; } p->mark = _mark; @@ -21715,11 +21769,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_195_var; + void *_tmp_196_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_195_var = _tmp_195_rule(p)) // ':' | ',' (':' | '**') + (_tmp_196_var = _tmp_196_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -21772,20 +21826,20 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_197_var; - void *_tmp_196_var; - void *_tmp_198_var; + asdl_seq * _loop0_198_var; + void *_tmp_197_var; + void *_tmp_199_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_196_var = _tmp_196_rule(p)) // lambda_param_no_default | ',' + (_tmp_197_var = _tmp_197_rule(p)) // lambda_param_no_default | ',' && - (_loop0_197_var = _loop0_197_rule(p)) // lambda_param_maybe_default* + (_loop0_198_var = _loop0_198_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_198_var = _tmp_198_rule(p)) // lambda_param_no_default | ',' + (_tmp_199_var = _tmp_199_rule(p)) // lambda_param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); @@ -21904,7 +21958,7 @@ invalid_lambda_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_199_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_200_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')")); @@ -22012,7 +22066,7 @@ invalid_with_item_rule(Parser *p) && (a = expression_rule(p)) // expression && - _PyPegen_lookahead(1, _tmp_200_rule, p) + _PyPegen_lookahead(1, _tmp_201_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' | ')' | ':')")); @@ -22293,7 +22347,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_201_var; + asdl_seq * _gather_202_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22303,7 +22357,7 @@ invalid_with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_201_var = _gather_201_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_202_var = _gather_202_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22327,7 +22381,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_203_var; + asdl_seq * _gather_204_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -22343,7 +22397,7 @@ invalid_with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_203_var = _gather_203_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_204_var = _gather_204_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22393,7 +22447,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_205_var; + asdl_seq * _gather_206_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22404,7 +22458,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (a = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_205_var = _gather_205_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_206_var = _gather_206_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22432,7 +22486,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_207_var; + asdl_seq * _gather_208_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -22449,7 +22503,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_207_var = _gather_207_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_208_var = _gather_208_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22547,7 +22601,7 @@ invalid_try_stmt_rule(Parser *p) && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_209_rule, p) + _PyPegen_lookahead(0, _tmp_210_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -22572,8 +22626,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_210_var; - asdl_seq * _loop1_211_var; + asdl_seq * _loop0_211_var; + asdl_seq * _loop1_212_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22584,9 +22638,9 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_210_var = _loop0_210_rule(p)) // block* + (_loop0_211_var = _loop0_211_rule(p)) // block* && - (_loop1_211_var = _loop1_211_rule(p)) // except_block+ + (_loop1_212_var = _loop1_212_rule(p)) // except_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && @@ -22594,7 +22648,7 @@ invalid_try_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_212_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_213_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22621,8 +22675,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_213_var; - asdl_seq * _loop1_214_var; + asdl_seq * _loop0_214_var; + asdl_seq * _loop1_215_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22631,13 +22685,13 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_213_var = _loop0_213_rule(p)) // block* + (_loop0_214_var = _loop0_214_rule(p)) // block* && - (_loop1_214_var = _loop1_214_rule(p)) // except_star_block+ + (_loop1_215_var = _loop1_215_rule(p)) // except_star_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && - (_opt_var = _tmp_215_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_216_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22705,7 +22759,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var_1 = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_217_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22743,7 +22797,7 @@ invalid_except_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var_1 = _tmp_217_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_218_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22795,14 +22849,14 @@ invalid_except_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_218_var; + void *_tmp_219_var; Token * a; if ( (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_218_var = _tmp_218_rule(p)) // NEWLINE | ':' + (_tmp_219_var = _tmp_219_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -22909,7 +22963,7 @@ invalid_except_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23004,7 +23058,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23373,7 +23427,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_221_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_222_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -23867,7 +23921,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_222_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_2 = _tmp_223_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23927,7 +23981,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23962,7 +24016,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_225_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24013,11 +24067,11 @@ invalid_double_starred_kvpairs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_225_var; + asdl_seq * _gather_226_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_225_var = _gather_225_rule(p)) // ','.double_starred_kvpair+ + (_gather_226_var = _gather_226_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24025,7 +24079,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_225_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_226_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -24078,7 +24132,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_227_rule, p) + _PyPegen_lookahead(1, _tmp_228_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24189,7 +24243,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_228_rule, p) + _PyPegen_lookahead(1, _tmp_229_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24407,7 +24461,7 @@ invalid_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - _PyPegen_lookahead(0, _tmp_229_rule, p) + _PyPegen_lookahead(0, _tmp_230_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)")); @@ -24430,13 +24484,13 @@ invalid_replacement_field_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); Token * _literal; - void *_tmp_230_var; + void *_tmp_231_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_230_var = _tmp_230_rule(p)) // yield_expr | star_expressions + (_tmp_231_var = _tmp_231_rule(p)) // yield_expr | star_expressions && - _PyPegen_lookahead(0, _tmp_231_rule, p) + _PyPegen_lookahead(0, _tmp_232_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); @@ -24460,15 +24514,15 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); Token * _literal; Token * _literal_1; - void *_tmp_232_var; + void *_tmp_233_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_232_var = _tmp_232_rule(p)) // yield_expr | star_expressions + (_tmp_233_var = _tmp_233_rule(p)) // yield_expr | star_expressions && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_233_rule, p) + _PyPegen_lookahead(0, _tmp_234_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); @@ -24493,12 +24547,12 @@ invalid_replacement_field_rule(Parser *p) Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_234_var; + void *_tmp_235_var; void *invalid_conversion_character_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions + (_tmp_235_var = _tmp_235_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && @@ -24506,7 +24560,7 @@ invalid_replacement_field_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_234_var, _opt_var, invalid_conversion_character_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_235_var, _opt_var, invalid_conversion_character_var); goto done; } p->mark = _mark; @@ -24524,17 +24578,17 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_235_var; + void *_tmp_236_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_235_var = _tmp_235_rule(p)) // yield_expr | star_expressions + (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_236_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_237_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_237_rule, p) + _PyPegen_lookahead(0, _tmp_238_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); @@ -24558,24 +24612,24 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_240_var; + asdl_seq * _loop0_241_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_238_var; + void *_tmp_239_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions + (_tmp_239_var = _tmp_239_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_239_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_240_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_240_var = _loop0_240_rule(p)) // fstring_format_spec* + (_loop0_241_var = _loop0_241_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24604,15 +24658,15 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_241_var; + void *_tmp_242_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_241_var = _tmp_241_rule(p)) // yield_expr | star_expressions + (_tmp_242_var = _tmp_242_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_242_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_243_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24660,7 +24714,7 @@ invalid_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_243_rule, p) + _PyPegen_lookahead(1, _tmp_244_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -25605,12 +25659,12 @@ _loop1_15_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_244_var; + void *_tmp_245_var; while ( - (_tmp_244_var = _tmp_244_rule(p)) // star_targets '=' + (_tmp_245_var = _tmp_245_rule(p)) // star_targets '=' ) { - _res = _tmp_244_var; + _res = _tmp_245_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26184,12 +26238,12 @@ _loop0_25_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_245_var; + void *_tmp_246_var; while ( - (_tmp_245_var = _tmp_245_rule(p)) // '.' | '...' + (_tmp_246_var = _tmp_246_rule(p)) // '.' | '...' ) { - _res = _tmp_245_var; + _res = _tmp_246_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26252,12 +26306,12 @@ _loop1_26_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_246_var; + void *_tmp_247_var; while ( - (_tmp_246_var = _tmp_246_rule(p)) // '.' | '...' + (_tmp_247_var = _tmp_247_rule(p)) // '.' | '...' ) { - _res = _tmp_246_var; + _res = _tmp_247_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26657,12 +26711,12 @@ _loop1_33_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_247_var; + void *_tmp_248_var; while ( - (_tmp_247_var = _tmp_247_rule(p)) // '@' named_expression NEWLINE + (_tmp_248_var = _tmp_248_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_247_var; + _res = _tmp_248_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29718,12 +29772,12 @@ _loop1_81_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_248_var; + void *_tmp_249_var; while ( - (_tmp_248_var = _tmp_248_rule(p)) // ',' expression + (_tmp_249_var = _tmp_249_rule(p)) // ',' expression ) { - _res = _tmp_248_var; + _res = _tmp_249_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29791,12 +29845,12 @@ _loop1_82_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_249_var; + void *_tmp_250_var; while ( - (_tmp_249_var = _tmp_249_rule(p)) // ',' star_expression + (_tmp_250_var = _tmp_250_rule(p)) // ',' star_expression ) { - _res = _tmp_249_var; + _res = _tmp_250_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29983,12 +30037,12 @@ _loop1_85_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_250_var; + void *_tmp_251_var; while ( - (_tmp_250_var = _tmp_250_rule(p)) // 'or' conjunction + (_tmp_251_var = _tmp_251_rule(p)) // 'or' conjunction ) { - _res = _tmp_250_var; + _res = _tmp_251_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30056,12 +30110,12 @@ _loop1_86_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_251_var; + void *_tmp_252_var; while ( - (_tmp_251_var = _tmp_251_rule(p)) // 'and' inversion + (_tmp_252_var = _tmp_252_rule(p)) // 'and' inversion ) { - _res = _tmp_251_var; + _res = _tmp_252_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30251,7 +30305,7 @@ _loop0_90_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_252_rule(p)) // slice | starred_expression + (elem = _tmp_253_rule(p)) // slice | starred_expression ) { _res = elem; @@ -30317,7 +30371,7 @@ _gather_89_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_252_rule(p)) // slice | starred_expression + (elem = _tmp_253_rule(p)) // slice | starred_expression && (seq = _loop0_90_rule(p)) // _loop0_90 ) @@ -30383,7 +30437,7 @@ _tmp_91_rule(Parser *p) return _res; } -// _tmp_92: STRING | FSTRING_START +// _tmp_92: STRING | FSTRING_START | TAGSTRING_START static void * _tmp_92_rule(Parser *p) { @@ -30435,6 +30489,25 @@ _tmp_92_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START")); } + { // TAGSTRING_START + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "TAGSTRING_START")); + Token * tagstring_start_var; + if ( + (tagstring_start_var = _PyPegen_expect_token(p, TAGSTRING_START)) // token='TAGSTRING_START' + ) + { + D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "TAGSTRING_START")); + _res = tagstring_start_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "TAGSTRING_START")); + } _res = NULL; done: p->level--; @@ -31843,9 +31916,77 @@ _loop0_112_rule(Parser *p) return _seq; } -// _loop1_113: (fstring | string) +// _loop0_113: fstring_middle +static asdl_seq * +_loop0_113_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // fstring_middle + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); + expr_ty fstring_middle_var; + while ( + (fstring_middle_var = fstring_middle_rule(p)) // fstring_middle + ) + { + _res = fstring_middle_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_113[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_middle")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop1_114: (fstring | tagstring | string) static asdl_seq * -_loop1_113_rule(Parser *p) +_loop1_114_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31866,18 +32007,18 @@ _loop1_113_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // (fstring | string) + { // (fstring | tagstring | string) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_253_var; + D(fprintf(stderr, "%*c> _loop1_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | tagstring | string)")); + void *_tmp_254_var; while ( - (_tmp_253_var = _tmp_253_rule(p)) // fstring | string + (_tmp_254_var = _tmp_254_rule(p)) // fstring | tagstring | string ) { - _res = _tmp_253_var; + _res = _tmp_254_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31894,8 +32035,8 @@ _loop1_113_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_113[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | string)")); + D(fprintf(stderr, "%*c%s _loop1_114[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | tagstring | string)")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -31916,9 +32057,9 @@ _loop1_113_rule(Parser *p) return _seq; } -// _tmp_114: star_named_expression ',' star_named_expressions? +// _tmp_115: star_named_expression ',' star_named_expressions? static void * -_tmp_114_rule(Parser *p) +_tmp_115_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31935,7 +32076,7 @@ _tmp_114_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); Token * _literal; expr_ty y; void *z; @@ -31947,7 +32088,7 @@ _tmp_114_rule(Parser *p) (z = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions? ) { - D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); _res = _PyPegen_seq_insert_in_front ( p , y , z ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -31957,7 +32098,7 @@ _tmp_114_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?")); } _res = NULL; @@ -31966,9 +32107,9 @@ _tmp_114_rule(Parser *p) return _res; } -// _loop0_116: ',' double_starred_kvpair +// _loop0_117: ',' double_starred_kvpair static asdl_seq * -_loop0_116_rule(Parser *p) +_loop0_117_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31994,7 +32135,7 @@ _loop0_116_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -32026,7 +32167,7 @@ _loop0_116_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_117[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32043,9 +32184,9 @@ _loop0_116_rule(Parser *p) return _seq; } -// _gather_115: double_starred_kvpair _loop0_116 +// _gather_116: double_starred_kvpair _loop0_117 static asdl_seq * -_gather_115_rule(Parser *p) +_gather_116_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32057,27 +32198,27 @@ _gather_115_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_116 + { // double_starred_kvpair _loop0_117 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_116")); + D(fprintf(stderr, "%*c> _gather_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_117")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_116_rule(p)) // _loop0_116 + (seq = _loop0_117_rule(p)) // _loop0_117 ) { - D(fprintf(stderr, "%*c+ _gather_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_116")); + D(fprintf(stderr, "%*c+ _gather_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_117")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_115[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_116")); + D(fprintf(stderr, "%*c%s _gather_116[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_117")); } _res = NULL; done: @@ -32085,9 +32226,9 @@ _gather_115_rule(Parser *p) return _res; } -// _loop1_117: for_if_clause +// _loop1_118: for_if_clause static asdl_seq * -_loop1_117_rule(Parser *p) +_loop1_118_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32113,7 +32254,7 @@ _loop1_117_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); + D(fprintf(stderr, "%*c> _loop1_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); comprehension_ty for_if_clause_var; while ( (for_if_clause_var = for_if_clause_rule(p)) // for_if_clause @@ -32136,7 +32277,7 @@ _loop1_117_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_117[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_118[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause")); } if (_n == 0 || p->error_indicator) { @@ -32158,9 +32299,9 @@ _loop1_117_rule(Parser *p) return _seq; } -// _loop0_118: ('if' disjunction) +// _loop0_119: ('if' disjunction) static asdl_seq * -_loop0_118_rule(Parser *p) +_loop0_119_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32186,13 +32327,13 @@ _loop0_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_254_var; + D(fprintf(stderr, "%*c> _loop0_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_255_var; while ( - (_tmp_254_var = _tmp_254_rule(p)) // 'if' disjunction + (_tmp_255_var = _tmp_255_rule(p)) // 'if' disjunction ) { - _res = _tmp_254_var; + _res = _tmp_255_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32209,7 +32350,7 @@ _loop0_118_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_119[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32226,9 +32367,9 @@ _loop0_118_rule(Parser *p) return _seq; } -// _loop0_119: ('if' disjunction) +// _loop0_120: ('if' disjunction) static asdl_seq * -_loop0_119_rule(Parser *p) +_loop0_120_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32254,13 +32395,13 @@ _loop0_119_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_255_var; + D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_256_var; while ( - (_tmp_255_var = _tmp_255_rule(p)) // 'if' disjunction + (_tmp_256_var = _tmp_256_rule(p)) // 'if' disjunction ) { - _res = _tmp_255_var; + _res = _tmp_256_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32277,7 +32418,7 @@ _loop0_119_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_119[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32294,9 +32435,9 @@ _loop0_119_rule(Parser *p) return _seq; } -// _tmp_120: assignment_expression | expression !':=' +// _tmp_121: assignment_expression | expression !':=' static void * -_tmp_120_rule(Parser *p) +_tmp_121_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32313,18 +32454,18 @@ _tmp_120_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -32332,7 +32473,7 @@ _tmp_120_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -32340,12 +32481,12 @@ _tmp_120_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -32354,9 +32495,9 @@ _tmp_120_rule(Parser *p) return _res; } -// _loop0_122: ',' (starred_expression | (assignment_expression | expression !':=') !'=') +// _loop0_123: ',' (starred_expression | (assignment_expression | expression !':=') !'=') static asdl_seq * -_loop0_122_rule(Parser *p) +_loop0_123_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32382,13 +32523,13 @@ _loop0_122_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + D(fprintf(stderr, "%*c> _loop0_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_256_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_257_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -32414,7 +32555,7 @@ _loop0_122_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_122[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_123[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32431,10 +32572,10 @@ _loop0_122_rule(Parser *p) return _seq; } -// _gather_121: -// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122 +// _gather_122: +// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_123 static asdl_seq * -_gather_121_rule(Parser *p) +_gather_122_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32446,27 +32587,27 @@ _gather_121_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122 + { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_123 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); + D(fprintf(stderr, "%*c> _gather_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_123")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_256_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_257_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && - (seq = _loop0_122_rule(p)) // _loop0_122 + (seq = _loop0_123_rule(p)) // _loop0_123 ) { - D(fprintf(stderr, "%*c+ _gather_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); + D(fprintf(stderr, "%*c+ _gather_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_123")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_121[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); + D(fprintf(stderr, "%*c%s _gather_122[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_123")); } _res = NULL; done: @@ -32474,9 +32615,9 @@ _gather_121_rule(Parser *p) return _res; } -// _tmp_123: ',' kwargs +// _tmp_124: ',' kwargs static void * -_tmp_123_rule(Parser *p) +_tmp_124_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32493,7 +32634,7 @@ _tmp_123_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); Token * _literal; asdl_seq* k; if ( @@ -32502,7 +32643,7 @@ _tmp_123_rule(Parser *p) (k = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); _res = k; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -32512,7 +32653,7 @@ _tmp_123_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs")); } _res = NULL; @@ -32521,9 +32662,9 @@ _tmp_123_rule(Parser *p) return _res; } -// _loop0_125: ',' kwarg_or_starred +// _loop0_126: ',' kwarg_or_starred static asdl_seq * -_loop0_125_rule(Parser *p) +_loop0_126_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32549,7 +32690,7 @@ _loop0_125_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c> _loop0_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -32581,7 +32722,7 @@ _loop0_125_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_125[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_126[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32598,9 +32739,9 @@ _loop0_125_rule(Parser *p) return _seq; } -// _gather_124: kwarg_or_starred _loop0_125 +// _gather_125: kwarg_or_starred _loop0_126 static asdl_seq * -_gather_124_rule(Parser *p) +_gather_125_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32612,27 +32753,27 @@ _gather_124_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_starred _loop0_125 + { // kwarg_or_starred _loop0_126 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_125")); + D(fprintf(stderr, "%*c> _gather_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_126")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred && - (seq = _loop0_125_rule(p)) // _loop0_125 + (seq = _loop0_126_rule(p)) // _loop0_126 ) { - D(fprintf(stderr, "%*c+ _gather_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_125")); + D(fprintf(stderr, "%*c+ _gather_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_126")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_124[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_125")); + D(fprintf(stderr, "%*c%s _gather_125[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_126")); } _res = NULL; done: @@ -32640,9 +32781,9 @@ _gather_124_rule(Parser *p) return _res; } -// _loop0_127: ',' kwarg_or_double_starred +// _loop0_128: ',' kwarg_or_double_starred static asdl_seq * -_loop0_127_rule(Parser *p) +_loop0_128_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32668,7 +32809,7 @@ _loop0_127_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -32700,7 +32841,7 @@ _loop0_127_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32717,9 +32858,9 @@ _loop0_127_rule(Parser *p) return _seq; } -// _gather_126: kwarg_or_double_starred _loop0_127 +// _gather_127: kwarg_or_double_starred _loop0_128 static asdl_seq * -_gather_126_rule(Parser *p) +_gather_127_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32731,27 +32872,27 @@ _gather_126_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_127 + { // kwarg_or_double_starred _loop0_128 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_127")); + D(fprintf(stderr, "%*c> _gather_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_128")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred && - (seq = _loop0_127_rule(p)) // _loop0_127 + (seq = _loop0_128_rule(p)) // _loop0_128 ) { - D(fprintf(stderr, "%*c+ _gather_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_127")); + D(fprintf(stderr, "%*c+ _gather_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_128")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_126[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_127")); + D(fprintf(stderr, "%*c%s _gather_127[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_128")); } _res = NULL; done: @@ -32759,9 +32900,9 @@ _gather_126_rule(Parser *p) return _res; } -// _loop0_129: ',' kwarg_or_starred +// _loop0_130: ',' kwarg_or_starred static asdl_seq * -_loop0_129_rule(Parser *p) +_loop0_130_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32787,7 +32928,7 @@ _loop0_129_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c> _loop0_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -32819,7 +32960,7 @@ _loop0_129_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32836,9 +32977,9 @@ _loop0_129_rule(Parser *p) return _seq; } -// _gather_128: kwarg_or_starred _loop0_129 +// _gather_129: kwarg_or_starred _loop0_130 static asdl_seq * -_gather_128_rule(Parser *p) +_gather_129_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32850,27 +32991,27 @@ _gather_128_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_starred _loop0_129 + { // kwarg_or_starred _loop0_130 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_129")); + D(fprintf(stderr, "%*c> _gather_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_130")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred && - (seq = _loop0_129_rule(p)) // _loop0_129 + (seq = _loop0_130_rule(p)) // _loop0_130 ) { - D(fprintf(stderr, "%*c+ _gather_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_129")); + D(fprintf(stderr, "%*c+ _gather_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_130")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_128[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_129")); + D(fprintf(stderr, "%*c%s _gather_129[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_130")); } _res = NULL; done: @@ -32878,9 +33019,9 @@ _gather_128_rule(Parser *p) return _res; } -// _loop0_131: ',' kwarg_or_double_starred +// _loop0_132: ',' kwarg_or_double_starred static asdl_seq * -_loop0_131_rule(Parser *p) +_loop0_132_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32906,7 +33047,7 @@ _loop0_131_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -32938,7 +33079,7 @@ _loop0_131_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_131[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_132[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32955,9 +33096,9 @@ _loop0_131_rule(Parser *p) return _seq; } -// _gather_130: kwarg_or_double_starred _loop0_131 +// _gather_131: kwarg_or_double_starred _loop0_132 static asdl_seq * -_gather_130_rule(Parser *p) +_gather_131_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32969,27 +33110,27 @@ _gather_130_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_131 + { // kwarg_or_double_starred _loop0_132 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_131")); + D(fprintf(stderr, "%*c> _gather_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_132")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred && - (seq = _loop0_131_rule(p)) // _loop0_131 + (seq = _loop0_132_rule(p)) // _loop0_132 ) { - D(fprintf(stderr, "%*c+ _gather_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_131")); + D(fprintf(stderr, "%*c+ _gather_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_132")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_130[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_131")); + D(fprintf(stderr, "%*c%s _gather_131[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_132")); } _res = NULL; done: @@ -32997,9 +33138,9 @@ _gather_130_rule(Parser *p) return _res; } -// _loop0_132: (',' star_target) +// _loop0_133: (',' star_target) static asdl_seq * -_loop0_132_rule(Parser *p) +_loop0_133_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33025,13 +33166,13 @@ _loop0_132_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_257_var; + D(fprintf(stderr, "%*c> _loop0_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_258_var; while ( - (_tmp_257_var = _tmp_257_rule(p)) // ',' star_target + (_tmp_258_var = _tmp_258_rule(p)) // ',' star_target ) { - _res = _tmp_257_var; + _res = _tmp_258_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33048,7 +33189,7 @@ _loop0_132_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_133[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33065,9 +33206,9 @@ _loop0_132_rule(Parser *p) return _seq; } -// _loop0_134: ',' star_target +// _loop0_135: ',' star_target static asdl_seq * -_loop0_134_rule(Parser *p) +_loop0_135_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33093,7 +33234,7 @@ _loop0_134_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _loop0_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty elem; while ( @@ -33125,7 +33266,7 @@ _loop0_134_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33142,9 +33283,9 @@ _loop0_134_rule(Parser *p) return _seq; } -// _gather_133: star_target _loop0_134 +// _gather_134: star_target _loop0_135 static asdl_seq * -_gather_133_rule(Parser *p) +_gather_134_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33156,27 +33297,27 @@ _gather_133_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_target _loop0_134 + { // star_target _loop0_135 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_134")); + D(fprintf(stderr, "%*c> _gather_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_135")); expr_ty elem; asdl_seq * seq; if ( (elem = star_target_rule(p)) // star_target && - (seq = _loop0_134_rule(p)) // _loop0_134 + (seq = _loop0_135_rule(p)) // _loop0_135 ) { - D(fprintf(stderr, "%*c+ _gather_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_134")); + D(fprintf(stderr, "%*c+ _gather_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_135")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_133[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_134")); + D(fprintf(stderr, "%*c%s _gather_134[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_135")); } _res = NULL; done: @@ -33184,9 +33325,9 @@ _gather_133_rule(Parser *p) return _res; } -// _loop1_135: (',' star_target) +// _loop1_136: (',' star_target) static asdl_seq * -_loop1_135_rule(Parser *p) +_loop1_136_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33212,13 +33353,13 @@ _loop1_135_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_258_var; + D(fprintf(stderr, "%*c> _loop1_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_259_var; while ( - (_tmp_258_var = _tmp_258_rule(p)) // ',' star_target + (_tmp_259_var = _tmp_259_rule(p)) // ',' star_target ) { - _res = _tmp_258_var; + _res = _tmp_259_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33235,7 +33376,7 @@ _loop1_135_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_135[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } if (_n == 0 || p->error_indicator) { @@ -33257,9 +33398,9 @@ _loop1_135_rule(Parser *p) return _seq; } -// _tmp_136: !'*' star_target +// _tmp_137: !'*' star_target static void * -_tmp_136_rule(Parser *p) +_tmp_137_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33276,7 +33417,7 @@ _tmp_136_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); expr_ty star_target_var; if ( _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16) // token='*' @@ -33284,12 +33425,12 @@ _tmp_136_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); _res = star_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target")); } _res = NULL; @@ -33298,9 +33439,9 @@ _tmp_136_rule(Parser *p) return _res; } -// _loop0_138: ',' del_target +// _loop0_139: ',' del_target static asdl_seq * -_loop0_138_rule(Parser *p) +_loop0_139_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33326,7 +33467,7 @@ _loop0_138_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); + D(fprintf(stderr, "%*c> _loop0_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); Token * _literal; expr_ty elem; while ( @@ -33358,7 +33499,7 @@ _loop0_138_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_138[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_139[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33375,9 +33516,9 @@ _loop0_138_rule(Parser *p) return _seq; } -// _gather_137: del_target _loop0_138 +// _gather_138: del_target _loop0_139 static asdl_seq * -_gather_137_rule(Parser *p) +_gather_138_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33389,27 +33530,27 @@ _gather_137_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // del_target _loop0_138 + { // del_target _loop0_139 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_138")); + D(fprintf(stderr, "%*c> _gather_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_139")); expr_ty elem; asdl_seq * seq; if ( (elem = del_target_rule(p)) // del_target && - (seq = _loop0_138_rule(p)) // _loop0_138 + (seq = _loop0_139_rule(p)) // _loop0_139 ) { - D(fprintf(stderr, "%*c+ _gather_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_138")); + D(fprintf(stderr, "%*c+ _gather_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_139")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_137[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_138")); + D(fprintf(stderr, "%*c%s _gather_138[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_139")); } _res = NULL; done: @@ -33417,9 +33558,9 @@ _gather_137_rule(Parser *p) return _res; } -// _loop0_140: ',' expression +// _loop0_141: ',' expression static asdl_seq * -_loop0_140_rule(Parser *p) +_loop0_141_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33445,7 +33586,7 @@ _loop0_140_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -33477,7 +33618,7 @@ _loop0_140_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_140[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_141[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33494,9 +33635,9 @@ _loop0_140_rule(Parser *p) return _seq; } -// _gather_139: expression _loop0_140 +// _gather_140: expression _loop0_141 static asdl_seq * -_gather_139_rule(Parser *p) +_gather_140_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33508,27 +33649,27 @@ _gather_139_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_140 + { // expression _loop0_141 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_140")); + D(fprintf(stderr, "%*c> _gather_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_141")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_140_rule(p)) // _loop0_140 + (seq = _loop0_141_rule(p)) // _loop0_141 ) { - D(fprintf(stderr, "%*c+ _gather_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_140")); + D(fprintf(stderr, "%*c+ _gather_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_141")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_139[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_140")); + D(fprintf(stderr, "%*c%s _gather_140[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_141")); } _res = NULL; done: @@ -33536,9 +33677,9 @@ _gather_139_rule(Parser *p) return _res; } -// _loop0_142: ',' expression +// _loop0_143: ',' expression static asdl_seq * -_loop0_142_rule(Parser *p) +_loop0_143_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33564,7 +33705,7 @@ _loop0_142_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -33596,7 +33737,7 @@ _loop0_142_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_142[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_143[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33613,9 +33754,9 @@ _loop0_142_rule(Parser *p) return _seq; } -// _gather_141: expression _loop0_142 +// _gather_142: expression _loop0_143 static asdl_seq * -_gather_141_rule(Parser *p) +_gather_142_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33627,27 +33768,27 @@ _gather_141_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_142 + { // expression _loop0_143 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_142")); + D(fprintf(stderr, "%*c> _gather_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_143")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_142_rule(p)) // _loop0_142 + (seq = _loop0_143_rule(p)) // _loop0_143 ) { - D(fprintf(stderr, "%*c+ _gather_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_142")); + D(fprintf(stderr, "%*c+ _gather_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_143")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_141[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_142")); + D(fprintf(stderr, "%*c%s _gather_142[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_143")); } _res = NULL; done: @@ -33655,9 +33796,9 @@ _gather_141_rule(Parser *p) return _res; } -// _loop0_144: ',' expression +// _loop0_145: ',' expression static asdl_seq * -_loop0_144_rule(Parser *p) +_loop0_145_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33683,7 +33824,7 @@ _loop0_144_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -33715,7 +33856,7 @@ _loop0_144_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_145[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33732,9 +33873,9 @@ _loop0_144_rule(Parser *p) return _seq; } -// _gather_143: expression _loop0_144 +// _gather_144: expression _loop0_145 static asdl_seq * -_gather_143_rule(Parser *p) +_gather_144_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33746,27 +33887,27 @@ _gather_143_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_144 + { // expression _loop0_145 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_144")); + D(fprintf(stderr, "%*c> _gather_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_145")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_144_rule(p)) // _loop0_144 + (seq = _loop0_145_rule(p)) // _loop0_145 ) { - D(fprintf(stderr, "%*c+ _gather_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_144")); + D(fprintf(stderr, "%*c+ _gather_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_145")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_143[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_144")); + D(fprintf(stderr, "%*c%s _gather_144[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_145")); } _res = NULL; done: @@ -33774,9 +33915,9 @@ _gather_143_rule(Parser *p) return _res; } -// _loop0_146: ',' expression +// _loop0_147: ',' expression static asdl_seq * -_loop0_146_rule(Parser *p) +_loop0_147_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33802,7 +33943,7 @@ _loop0_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -33834,7 +33975,7 @@ _loop0_146_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33851,9 +33992,9 @@ _loop0_146_rule(Parser *p) return _seq; } -// _gather_145: expression _loop0_146 +// _gather_146: expression _loop0_147 static asdl_seq * -_gather_145_rule(Parser *p) +_gather_146_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33865,27 +34006,27 @@ _gather_145_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_146 + { // expression _loop0_147 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_146")); + D(fprintf(stderr, "%*c> _gather_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_147")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_146_rule(p)) // _loop0_146 + (seq = _loop0_147_rule(p)) // _loop0_147 ) { - D(fprintf(stderr, "%*c+ _gather_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_146")); + D(fprintf(stderr, "%*c+ _gather_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_147")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_145[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_146")); + D(fprintf(stderr, "%*c%s _gather_146[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_147")); } _res = NULL; done: @@ -33893,9 +34034,9 @@ _gather_145_rule(Parser *p) return _res; } -// _tmp_147: NEWLINE INDENT +// _tmp_148: NEWLINE INDENT static void * -_tmp_147_rule(Parser *p) +_tmp_148_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33912,7 +34053,7 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); Token * indent_var; Token * newline_var; if ( @@ -33921,12 +34062,12 @@ _tmp_147_rule(Parser *p) (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); _res = _PyPegen_dummy_name(p, newline_var, indent_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE INDENT")); } _res = NULL; @@ -33935,9 +34076,9 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: args | expression for_if_clauses +// _tmp_149: args | expression for_if_clauses static void * -_tmp_148_rule(Parser *p) +_tmp_149_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33954,18 +34095,18 @@ _tmp_148_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); expr_ty args_var; if ( (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); _res = args_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args")); } { // expression for_if_clauses @@ -33973,7 +34114,7 @@ _tmp_148_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); expr_ty expression_var; asdl_comprehension_seq* for_if_clauses_var; if ( @@ -33982,12 +34123,12 @@ _tmp_148_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses")); } _res = NULL; @@ -33996,9 +34137,9 @@ _tmp_148_rule(Parser *p) return _res; } -// _tmp_149: args ',' +// _tmp_150: args ',' static void * -_tmp_149_rule(Parser *p) +_tmp_150_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34015,7 +34156,7 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); Token * _literal; expr_ty args_var; if ( @@ -34024,12 +34165,12 @@ _tmp_149_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); _res = _PyPegen_dummy_name(p, args_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ','")); } _res = NULL; @@ -34038,9 +34179,9 @@ _tmp_149_rule(Parser *p) return _res; } -// _tmp_150: ',' | ')' +// _tmp_151: ',' | ')' static void * -_tmp_150_rule(Parser *p) +_tmp_151_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34057,18 +34198,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -34076,18 +34217,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } _res = NULL; @@ -34096,9 +34237,9 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: 'True' | 'False' | 'None' +// _tmp_152: 'True' | 'False' | 'None' static void * -_tmp_151_rule(Parser *p) +_tmp_152_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34115,18 +34256,18 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'False' @@ -34134,18 +34275,18 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } { // 'None' @@ -34153,18 +34294,18 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } _res = NULL; @@ -34173,9 +34314,9 @@ _tmp_151_rule(Parser *p) return _res; } -// _tmp_152: NAME '=' +// _tmp_153: NAME '=' static void * -_tmp_152_rule(Parser *p) +_tmp_153_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34192,7 +34333,7 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); Token * _literal; expr_ty name_var; if ( @@ -34201,12 +34342,12 @@ _tmp_152_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); _res = _PyPegen_dummy_name(p, name_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME '='")); } _res = NULL; @@ -34215,9 +34356,9 @@ _tmp_152_rule(Parser *p) return _res; } -// _tmp_153: NAME STRING | SOFT_KEYWORD +// _tmp_154: NAME STRING | SOFT_KEYWORD static void * -_tmp_153_rule(Parser *p) +_tmp_154_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34234,7 +34375,7 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); expr_ty name_var; expr_ty string_var; if ( @@ -34243,12 +34384,12 @@ _tmp_153_rule(Parser *p) (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); _res = _PyPegen_dummy_name(p, name_var, string_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME STRING")); } { // SOFT_KEYWORD @@ -34256,18 +34397,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); expr_ty soft_keyword_var; if ( (soft_keyword_var = _PyPegen_soft_keyword_token(p)) // SOFT_KEYWORD ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); _res = soft_keyword_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "SOFT_KEYWORD")); } _res = NULL; @@ -34276,9 +34417,9 @@ _tmp_153_rule(Parser *p) return _res; } -// _tmp_154: 'else' | ':' +// _tmp_155: 'else' | ':' static void * -_tmp_154_rule(Parser *p) +_tmp_155_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34295,18 +34436,18 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 645)) // token='else' ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'else'")); } { // ':' @@ -34314,18 +34455,18 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -34334,9 +34475,9 @@ _tmp_154_rule(Parser *p) return _res; } -// _tmp_155: FSTRING_MIDDLE | fstring_replacement_field +// _tmp_156: FSTRING_MIDDLE | fstring_replacement_field static void * -_tmp_155_rule(Parser *p) +_tmp_156_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34353,18 +34494,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); Token * fstring_middle_var; if ( (fstring_middle_var = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); _res = fstring_middle_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE")); } { // fstring_replacement_field @@ -34372,18 +34513,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); expr_ty fstring_replacement_field_var; if ( (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); _res = fstring_replacement_field_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field")); } _res = NULL; @@ -34392,9 +34533,9 @@ _tmp_155_rule(Parser *p) return _res; } -// _tmp_156: '=' | ':=' +// _tmp_157: '=' | ':=' static void * -_tmp_156_rule(Parser *p) +_tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34411,18 +34552,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34430,18 +34571,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34450,9 +34591,9 @@ _tmp_156_rule(Parser *p) return _res; } -// _tmp_157: list | tuple | genexp | 'True' | 'None' | 'False' +// _tmp_158: list | tuple | genexp | 'True' | 'None' | 'False' static void * -_tmp_157_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34469,18 +34610,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // tuple @@ -34488,18 +34629,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // genexp @@ -34507,18 +34648,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } { // 'True' @@ -34526,18 +34667,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'None' @@ -34545,18 +34686,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } { // 'False' @@ -34564,18 +34705,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } _res = NULL; @@ -34584,9 +34725,9 @@ _tmp_157_rule(Parser *p) return _res; } -// _tmp_158: '=' | ':=' +// _tmp_159: '=' | ':=' static void * -_tmp_158_rule(Parser *p) +_tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34603,18 +34744,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34622,18 +34763,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34642,9 +34783,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _loop0_159: star_named_expressions +// _loop0_160: star_named_expressions static asdl_seq * -_loop0_159_rule(Parser *p) +_loop0_160_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34670,7 +34811,7 @@ _loop0_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_expr_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -34693,7 +34834,7 @@ _loop0_159_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34710,9 +34851,9 @@ _loop0_159_rule(Parser *p) return _seq; } -// _loop0_160: (star_targets '=') +// _loop0_161: (star_targets '=') static asdl_seq * -_loop0_160_rule(Parser *p) +_loop0_161_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34738,13 +34879,13 @@ _loop0_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_259_var; + D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_260_var; while ( - (_tmp_259_var = _tmp_259_rule(p)) // star_targets '=' + (_tmp_260_var = _tmp_260_rule(p)) // star_targets '=' ) { - _res = _tmp_259_var; + _res = _tmp_260_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34761,7 +34902,7 @@ _loop0_160_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34778,9 +34919,9 @@ _loop0_160_rule(Parser *p) return _seq; } -// _loop0_161: (star_targets '=') +// _loop0_162: (star_targets '=') static asdl_seq * -_loop0_161_rule(Parser *p) +_loop0_162_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34806,13 +34947,13 @@ _loop0_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_260_var; + D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_261_var; while ( - (_tmp_260_var = _tmp_260_rule(p)) // star_targets '=' + (_tmp_261_var = _tmp_261_rule(p)) // star_targets '=' ) { - _res = _tmp_260_var; + _res = _tmp_261_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34829,7 +34970,7 @@ _loop0_161_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34846,9 +34987,9 @@ _loop0_161_rule(Parser *p) return _seq; } -// _tmp_162: yield_expr | star_expressions +// _tmp_163: yield_expr | star_expressions static void * -_tmp_162_rule(Parser *p) +_tmp_163_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34865,18 +35006,18 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -34884,18 +35025,18 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -34904,9 +35045,9 @@ _tmp_162_rule(Parser *p) return _res; } -// _tmp_163: '[' | '(' | '{' +// _tmp_164: '[' | '(' | '{' static void * -_tmp_163_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34923,18 +35064,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '(' @@ -34942,18 +35083,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '{' @@ -34961,18 +35102,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -34981,9 +35122,9 @@ _tmp_163_rule(Parser *p) return _res; } -// _tmp_164: '[' | '{' +// _tmp_165: '[' | '{' static void * -_tmp_164_rule(Parser *p) +_tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35000,18 +35141,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -35019,18 +35160,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35039,9 +35180,9 @@ _tmp_164_rule(Parser *p) return _res; } -// _tmp_165: '[' | '{' +// _tmp_166: '[' | '{' static void * -_tmp_165_rule(Parser *p) +_tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35058,18 +35199,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -35077,18 +35218,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35097,9 +35238,9 @@ _tmp_165_rule(Parser *p) return _res; } -// _tmp_166: slash_no_default | slash_with_default +// _tmp_167: slash_no_default | slash_with_default static void * -_tmp_166_rule(Parser *p) +_tmp_167_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35116,18 +35257,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35135,18 +35276,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35155,9 +35296,9 @@ _tmp_166_rule(Parser *p) return _res; } -// _loop0_167: param_maybe_default +// _loop0_168: param_maybe_default static asdl_seq * -_loop0_167_rule(Parser *p) +_loop0_168_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35183,7 +35324,7 @@ _loop0_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35206,7 +35347,7 @@ _loop0_167_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35223,9 +35364,9 @@ _loop0_167_rule(Parser *p) return _seq; } -// _loop0_168: param_no_default +// _loop0_169: param_no_default static asdl_seq * -_loop0_168_rule(Parser *p) +_loop0_169_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35251,7 +35392,7 @@ _loop0_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35274,7 +35415,7 @@ _loop0_168_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35291,9 +35432,9 @@ _loop0_168_rule(Parser *p) return _seq; } -// _loop0_169: param_no_default +// _loop0_170: param_no_default static asdl_seq * -_loop0_169_rule(Parser *p) +_loop0_170_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35319,7 +35460,7 @@ _loop0_169_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35342,7 +35483,7 @@ _loop0_169_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_170[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35359,9 +35500,9 @@ _loop0_169_rule(Parser *p) return _seq; } -// _loop1_170: param_no_default +// _loop1_171: param_no_default static asdl_seq * -_loop1_170_rule(Parser *p) +_loop1_171_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35387,7 +35528,7 @@ _loop1_170_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35410,7 +35551,7 @@ _loop1_170_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_170[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_171[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -35432,9 +35573,9 @@ _loop1_170_rule(Parser *p) return _seq; } -// _tmp_171: slash_no_default | slash_with_default +// _tmp_172: slash_no_default | slash_with_default static void * -_tmp_171_rule(Parser *p) +_tmp_172_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35451,18 +35592,18 @@ _tmp_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35470,18 +35611,18 @@ _tmp_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35490,9 +35631,9 @@ _tmp_171_rule(Parser *p) return _res; } -// _loop0_172: param_maybe_default +// _loop0_173: param_maybe_default static asdl_seq * -_loop0_172_rule(Parser *p) +_loop0_173_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35518,7 +35659,7 @@ _loop0_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35541,7 +35682,7 @@ _loop0_172_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35558,9 +35699,9 @@ _loop0_172_rule(Parser *p) return _seq; } -// _tmp_173: ',' | param_no_default +// _tmp_174: ',' | param_no_default static void * -_tmp_173_rule(Parser *p) +_tmp_174_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35577,18 +35718,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // param_no_default @@ -35596,18 +35737,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } _res = NULL; @@ -35616,9 +35757,9 @@ _tmp_173_rule(Parser *p) return _res; } -// _loop0_174: param_maybe_default +// _loop0_175: param_maybe_default static asdl_seq * -_loop0_174_rule(Parser *p) +_loop0_175_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35644,7 +35785,7 @@ _loop0_174_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35667,7 +35808,7 @@ _loop0_174_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_174[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35684,9 +35825,9 @@ _loop0_174_rule(Parser *p) return _seq; } -// _loop1_175: param_maybe_default +// _loop1_176: param_maybe_default static asdl_seq * -_loop1_175_rule(Parser *p) +_loop1_176_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35712,7 +35853,7 @@ _loop1_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35735,7 +35876,7 @@ _loop1_175_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_176[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -35757,9 +35898,9 @@ _loop1_175_rule(Parser *p) return _seq; } -// _tmp_176: ')' | ',' +// _tmp_177: ')' | ',' static void * -_tmp_176_rule(Parser *p) +_tmp_177_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35776,18 +35917,18 @@ _tmp_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' @@ -35795,18 +35936,18 @@ _tmp_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -35815,9 +35956,9 @@ _tmp_176_rule(Parser *p) return _res; } -// _tmp_177: ')' | ',' (')' | '**') +// _tmp_178: ')' | ',' (')' | '**') static void * -_tmp_177_rule(Parser *p) +_tmp_178_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35834,18 +35975,18 @@ _tmp_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -35853,21 +35994,21 @@ _tmp_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_261_var; + void *_tmp_262_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_261_var = _tmp_261_rule(p)) // ')' | '**' + (_tmp_262_var = _tmp_262_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_261_var); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_262_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -35876,9 +36017,9 @@ _tmp_177_rule(Parser *p) return _res; } -// _tmp_178: param_no_default | ',' +// _tmp_179: param_no_default | ',' static void * -_tmp_178_rule(Parser *p) +_tmp_179_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35895,18 +36036,18 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -35914,18 +36055,18 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -35934,9 +36075,9 @@ _tmp_178_rule(Parser *p) return _res; } -// _loop0_179: param_maybe_default +// _loop0_180: param_maybe_default static asdl_seq * -_loop0_179_rule(Parser *p) +_loop0_180_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35962,7 +36103,7 @@ _loop0_179_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35985,7 +36126,7 @@ _loop0_179_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_179[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_180[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36002,9 +36143,9 @@ _loop0_179_rule(Parser *p) return _seq; } -// _tmp_180: param_no_default | ',' +// _tmp_181: param_no_default | ',' static void * -_tmp_180_rule(Parser *p) +_tmp_181_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36021,18 +36162,18 @@ _tmp_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -36040,18 +36181,18 @@ _tmp_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -36060,9 +36201,9 @@ _tmp_180_rule(Parser *p) return _res; } -// _tmp_181: '*' | '**' | '/' +// _tmp_182: '*' | '**' | '/' static void * -_tmp_181_rule(Parser *p) +_tmp_182_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36079,18 +36220,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -36098,18 +36239,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -36117,18 +36258,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -36137,9 +36278,9 @@ _tmp_181_rule(Parser *p) return _res; } -// _loop1_182: param_with_default +// _loop1_183: param_with_default static asdl_seq * -_loop1_182_rule(Parser *p) +_loop1_183_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36165,7 +36306,7 @@ _loop1_182_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -36188,7 +36329,7 @@ _loop1_182_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_182[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_183[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -36210,9 +36351,9 @@ _loop1_182_rule(Parser *p) return _seq; } -// _tmp_183: lambda_slash_no_default | lambda_slash_with_default +// _tmp_184: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_183_rule(Parser *p) +_tmp_184_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36229,18 +36370,18 @@ _tmp_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -36248,18 +36389,18 @@ _tmp_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -36268,9 +36409,9 @@ _tmp_183_rule(Parser *p) return _res; } -// _loop0_184: lambda_param_maybe_default +// _loop0_185: lambda_param_maybe_default static asdl_seq * -_loop0_184_rule(Parser *p) +_loop0_185_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36296,7 +36437,7 @@ _loop0_184_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36319,7 +36460,7 @@ _loop0_184_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_184[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_185[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36336,9 +36477,9 @@ _loop0_184_rule(Parser *p) return _seq; } -// _loop0_185: lambda_param_no_default +// _loop0_186: lambda_param_no_default static asdl_seq * -_loop0_185_rule(Parser *p) +_loop0_186_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36364,7 +36505,7 @@ _loop0_185_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -36387,7 +36528,7 @@ _loop0_185_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_185[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36404,9 +36545,9 @@ _loop0_185_rule(Parser *p) return _seq; } -// _loop0_186: lambda_param_no_default +// _loop0_187: lambda_param_no_default static asdl_seq * -_loop0_186_rule(Parser *p) +_loop0_187_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36432,7 +36573,7 @@ _loop0_186_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -36455,7 +36596,7 @@ _loop0_186_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36472,9 +36613,9 @@ _loop0_186_rule(Parser *p) return _seq; } -// _loop0_188: ',' lambda_param +// _loop0_189: ',' lambda_param static asdl_seq * -_loop0_188_rule(Parser *p) +_loop0_189_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36500,7 +36641,7 @@ _loop0_188_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); + D(fprintf(stderr, "%*c> _loop0_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); Token * _literal; arg_ty elem; while ( @@ -36532,7 +36673,7 @@ _loop0_188_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_188[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_189[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' lambda_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36549,9 +36690,9 @@ _loop0_188_rule(Parser *p) return _seq; } -// _gather_187: lambda_param _loop0_188 +// _gather_188: lambda_param _loop0_189 static asdl_seq * -_gather_187_rule(Parser *p) +_gather_188_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36563,27 +36704,27 @@ _gather_187_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // lambda_param _loop0_188 + { // lambda_param _loop0_189 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_188")); + D(fprintf(stderr, "%*c> _gather_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_189")); arg_ty elem; asdl_seq * seq; if ( (elem = lambda_param_rule(p)) // lambda_param && - (seq = _loop0_188_rule(p)) // _loop0_188 + (seq = _loop0_189_rule(p)) // _loop0_189 ) { - D(fprintf(stderr, "%*c+ _gather_187[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_188")); + D(fprintf(stderr, "%*c+ _gather_188[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_189")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_187[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_188")); + D(fprintf(stderr, "%*c%s _gather_188[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_189")); } _res = NULL; done: @@ -36591,9 +36732,9 @@ _gather_187_rule(Parser *p) return _res; } -// _tmp_189: lambda_slash_no_default | lambda_slash_with_default +// _tmp_190: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_189_rule(Parser *p) +_tmp_190_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36610,18 +36751,18 @@ _tmp_189_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_189[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -36629,18 +36770,18 @@ _tmp_189_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_189[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -36649,9 +36790,9 @@ _tmp_189_rule(Parser *p) return _res; } -// _loop0_190: lambda_param_maybe_default +// _loop0_191: lambda_param_maybe_default static asdl_seq * -_loop0_190_rule(Parser *p) +_loop0_191_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36677,7 +36818,7 @@ _loop0_190_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36700,7 +36841,7 @@ _loop0_190_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_190[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_191[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36717,9 +36858,9 @@ _loop0_190_rule(Parser *p) return _seq; } -// _tmp_191: ',' | lambda_param_no_default +// _tmp_192: ',' | lambda_param_no_default static void * -_tmp_191_rule(Parser *p) +_tmp_192_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36736,18 +36877,18 @@ _tmp_191_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // lambda_param_no_default @@ -36755,18 +36896,18 @@ _tmp_191_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } _res = NULL; @@ -36775,9 +36916,9 @@ _tmp_191_rule(Parser *p) return _res; } -// _loop0_192: lambda_param_maybe_default +// _loop0_193: lambda_param_maybe_default static asdl_seq * -_loop0_192_rule(Parser *p) +_loop0_193_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36803,7 +36944,7 @@ _loop0_192_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36826,7 +36967,7 @@ _loop0_192_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_192[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_193[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36843,9 +36984,9 @@ _loop0_192_rule(Parser *p) return _seq; } -// _loop1_193: lambda_param_maybe_default +// _loop1_194: lambda_param_maybe_default static asdl_seq * -_loop1_193_rule(Parser *p) +_loop1_194_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36871,7 +37012,7 @@ _loop1_193_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36894,7 +37035,7 @@ _loop1_193_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_193[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_194[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -36916,9 +37057,9 @@ _loop1_193_rule(Parser *p) return _seq; } -// _loop1_194: lambda_param_with_default +// _loop1_195: lambda_param_with_default static asdl_seq * -_loop1_194_rule(Parser *p) +_loop1_195_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36944,7 +37085,7 @@ _loop1_194_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -36967,7 +37108,7 @@ _loop1_194_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_194[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_195[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -36989,9 +37130,9 @@ _loop1_194_rule(Parser *p) return _seq; } -// _tmp_195: ':' | ',' (':' | '**') +// _tmp_196: ':' | ',' (':' | '**') static void * -_tmp_195_rule(Parser *p) +_tmp_196_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37008,18 +37149,18 @@ _tmp_195_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -37027,21 +37168,21 @@ _tmp_195_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_262_var; + void *_tmp_263_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_262_var = _tmp_262_rule(p)) // ':' | '**' + (_tmp_263_var = _tmp_263_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_262_var); + D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_263_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -37050,9 +37191,9 @@ _tmp_195_rule(Parser *p) return _res; } -// _tmp_196: lambda_param_no_default | ',' +// _tmp_197: lambda_param_no_default | ',' static void * -_tmp_196_rule(Parser *p) +_tmp_197_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37069,18 +37210,18 @@ _tmp_196_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -37088,18 +37229,18 @@ _tmp_196_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37108,9 +37249,9 @@ _tmp_196_rule(Parser *p) return _res; } -// _loop0_197: lambda_param_maybe_default +// _loop0_198: lambda_param_maybe_default static asdl_seq * -_loop0_197_rule(Parser *p) +_loop0_198_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37136,7 +37277,7 @@ _loop0_197_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -37159,7 +37300,7 @@ _loop0_197_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_197[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_198[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37176,9 +37317,9 @@ _loop0_197_rule(Parser *p) return _seq; } -// _tmp_198: lambda_param_no_default | ',' +// _tmp_199: lambda_param_no_default | ',' static void * -_tmp_198_rule(Parser *p) +_tmp_199_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37195,18 +37336,18 @@ _tmp_198_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -37214,18 +37355,18 @@ _tmp_198_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37234,9 +37375,9 @@ _tmp_198_rule(Parser *p) return _res; } -// _tmp_199: '*' | '**' | '/' +// _tmp_200: '*' | '**' | '/' static void * -_tmp_199_rule(Parser *p) +_tmp_200_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37253,18 +37394,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -37272,18 +37413,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -37291,18 +37432,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -37311,9 +37452,9 @@ _tmp_199_rule(Parser *p) return _res; } -// _tmp_200: ',' | ')' | ':' +// _tmp_201: ',' | ')' | ':' static void * -_tmp_200_rule(Parser *p) +_tmp_201_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37330,18 +37471,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -37349,18 +37490,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -37368,18 +37509,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -37388,9 +37529,9 @@ _tmp_200_rule(Parser *p) return _res; } -// _loop0_202: ',' (expression ['as' star_target]) +// _loop0_203: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_202_rule(Parser *p) +_loop0_203_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37416,13 +37557,13 @@ _loop0_202_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_263_rule(p)) // expression ['as' star_target] + (elem = _tmp_264_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37448,7 +37589,7 @@ _loop0_202_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_202[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_203[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37465,9 +37606,9 @@ _loop0_202_rule(Parser *p) return _seq; } -// _gather_201: (expression ['as' star_target]) _loop0_202 +// _gather_202: (expression ['as' star_target]) _loop0_203 static asdl_seq * -_gather_201_rule(Parser *p) +_gather_202_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37479,27 +37620,27 @@ _gather_201_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_202 + { // (expression ['as' star_target]) _loop0_203 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); + D(fprintf(stderr, "%*c> _gather_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_203")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_263_rule(p)) // expression ['as' star_target] + (elem = _tmp_264_rule(p)) // expression ['as' star_target] && - (seq = _loop0_202_rule(p)) // _loop0_202 + (seq = _loop0_203_rule(p)) // _loop0_203 ) { - D(fprintf(stderr, "%*c+ _gather_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); + D(fprintf(stderr, "%*c+ _gather_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_203")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_201[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); + D(fprintf(stderr, "%*c%s _gather_202[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_203")); } _res = NULL; done: @@ -37507,9 +37648,9 @@ _gather_201_rule(Parser *p) return _res; } -// _loop0_204: ',' (expressions ['as' star_target]) +// _loop0_205: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_204_rule(Parser *p) +_loop0_205_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37535,13 +37676,13 @@ _loop0_204_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_264_rule(p)) // expressions ['as' star_target] + (elem = _tmp_265_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -37567,7 +37708,7 @@ _loop0_204_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_204[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_205[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37584,9 +37725,9 @@ _loop0_204_rule(Parser *p) return _seq; } -// _gather_203: (expressions ['as' star_target]) _loop0_204 +// _gather_204: (expressions ['as' star_target]) _loop0_205 static asdl_seq * -_gather_203_rule(Parser *p) +_gather_204_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37598,27 +37739,27 @@ _gather_203_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_204 + { // (expressions ['as' star_target]) _loop0_205 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c> _gather_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_205")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_264_rule(p)) // expressions ['as' star_target] + (elem = _tmp_265_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_204_rule(p)) // _loop0_204 + (seq = _loop0_205_rule(p)) // _loop0_205 ) { - D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c+ _gather_204[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_205")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c%s _gather_204[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_205")); } _res = NULL; done: @@ -37626,9 +37767,9 @@ _gather_203_rule(Parser *p) return _res; } -// _loop0_206: ',' (expression ['as' star_target]) +// _loop0_207: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_206_rule(Parser *p) +_loop0_207_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37654,13 +37795,13 @@ _loop0_206_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_265_rule(p)) // expression ['as' star_target] + (elem = _tmp_266_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37686,7 +37827,7 @@ _loop0_206_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_206[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_207[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37703,9 +37844,9 @@ _loop0_206_rule(Parser *p) return _seq; } -// _gather_205: (expression ['as' star_target]) _loop0_206 +// _gather_206: (expression ['as' star_target]) _loop0_207 static asdl_seq * -_gather_205_rule(Parser *p) +_gather_206_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37717,27 +37858,27 @@ _gather_205_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_206 + { // (expression ['as' star_target]) _loop0_207 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c> _gather_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_207")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_265_rule(p)) // expression ['as' star_target] + (elem = _tmp_266_rule(p)) // expression ['as' star_target] && - (seq = _loop0_206_rule(p)) // _loop0_206 + (seq = _loop0_207_rule(p)) // _loop0_207 ) { - D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c+ _gather_206[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_207")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c%s _gather_206[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_207")); } _res = NULL; done: @@ -37745,9 +37886,9 @@ _gather_205_rule(Parser *p) return _res; } -// _loop0_208: ',' (expressions ['as' star_target]) +// _loop0_209: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_208_rule(Parser *p) +_loop0_209_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37773,13 +37914,13 @@ _loop0_208_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -37805,7 +37946,7 @@ _loop0_208_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_209[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37822,9 +37963,9 @@ _loop0_208_rule(Parser *p) return _seq; } -// _gather_207: (expressions ['as' star_target]) _loop0_208 +// _gather_208: (expressions ['as' star_target]) _loop0_209 static asdl_seq * -_gather_207_rule(Parser *p) +_gather_208_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37836,27 +37977,27 @@ _gather_207_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_208 + { // (expressions ['as' star_target]) _loop0_209 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c> _gather_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_209")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_208_rule(p)) // _loop0_208 + (seq = _loop0_209_rule(p)) // _loop0_209 ) { - D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c+ _gather_208[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_209")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c%s _gather_208[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_209")); } _res = NULL; done: @@ -37864,9 +38005,9 @@ _gather_207_rule(Parser *p) return _res; } -// _tmp_209: 'except' | 'finally' +// _tmp_210: 'except' | 'finally' static void * -_tmp_209_rule(Parser *p) +_tmp_210_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37883,18 +38024,18 @@ _tmp_209_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c> _tmp_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 637)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c+ _tmp_210[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_209[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_210[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); } { // 'finally' @@ -37902,18 +38043,18 @@ _tmp_209_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c> _tmp_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' ) { - D(fprintf(stderr, "%*c+ _tmp_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c+ _tmp_210[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_209[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_210[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; @@ -37922,9 +38063,9 @@ _tmp_209_rule(Parser *p) return _res; } -// _loop0_210: block +// _loop0_211: block static asdl_seq * -_loop0_210_rule(Parser *p) +_loop0_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37950,7 +38091,7 @@ _loop0_210_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -37973,7 +38114,7 @@ _loop0_210_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_211[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37990,9 +38131,9 @@ _loop0_210_rule(Parser *p) return _seq; } -// _loop1_211: except_block +// _loop1_212: except_block static asdl_seq * -_loop1_211_rule(Parser *p) +_loop1_212_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38018,7 +38159,7 @@ _loop1_211_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); excepthandler_ty except_block_var; while ( (except_block_var = except_block_rule(p)) // except_block @@ -38041,7 +38182,7 @@ _loop1_211_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_211[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_212[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -38063,9 +38204,9 @@ _loop1_211_rule(Parser *p) return _seq; } -// _tmp_212: 'as' NAME +// _tmp_213: 'as' NAME static void * -_tmp_212_rule(Parser *p) +_tmp_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38082,7 +38223,7 @@ _tmp_212_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38091,12 +38232,12 @@ _tmp_212_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38105,9 +38246,9 @@ _tmp_212_rule(Parser *p) return _res; } -// _loop0_213: block +// _loop0_214: block static asdl_seq * -_loop0_213_rule(Parser *p) +_loop0_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38133,7 +38274,7 @@ _loop0_213_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38156,7 +38297,7 @@ _loop0_213_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_213[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_214[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38173,9 +38314,9 @@ _loop0_213_rule(Parser *p) return _seq; } -// _loop1_214: except_star_block +// _loop1_215: except_star_block static asdl_seq * -_loop1_214_rule(Parser *p) +_loop1_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38201,7 +38342,7 @@ _loop1_214_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); excepthandler_ty except_star_block_var; while ( (except_star_block_var = except_star_block_rule(p)) // except_star_block @@ -38224,7 +38365,7 @@ _loop1_214_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_214[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_215[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -38246,9 +38387,9 @@ _loop1_214_rule(Parser *p) return _seq; } -// _tmp_215: expression ['as' NAME] +// _tmp_216: expression ['as' NAME] static void * -_tmp_215_rule(Parser *p) +_tmp_216_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38265,22 +38406,22 @@ _tmp_215_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_267_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_268_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_215[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -38289,9 +38430,9 @@ _tmp_215_rule(Parser *p) return _res; } -// _tmp_216: 'as' NAME +// _tmp_217: 'as' NAME static void * -_tmp_216_rule(Parser *p) +_tmp_217_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38308,7 +38449,7 @@ _tmp_216_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38317,12 +38458,12 @@ _tmp_216_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38331,9 +38472,9 @@ _tmp_216_rule(Parser *p) return _res; } -// _tmp_217: 'as' NAME +// _tmp_218: 'as' NAME static void * -_tmp_217_rule(Parser *p) +_tmp_218_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38350,7 +38491,7 @@ _tmp_217_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38359,12 +38500,12 @@ _tmp_217_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38373,9 +38514,9 @@ _tmp_217_rule(Parser *p) return _res; } -// _tmp_218: NEWLINE | ':' +// _tmp_219: NEWLINE | ':' static void * -_tmp_218_rule(Parser *p) +_tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38392,18 +38533,18 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -38411,18 +38552,18 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -38431,9 +38572,9 @@ _tmp_218_rule(Parser *p) return _res; } -// _tmp_219: 'as' NAME +// _tmp_220: 'as' NAME static void * -_tmp_219_rule(Parser *p) +_tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38450,7 +38591,7 @@ _tmp_219_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38459,12 +38600,12 @@ _tmp_219_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38473,9 +38614,9 @@ _tmp_219_rule(Parser *p) return _res; } -// _tmp_220: 'as' NAME +// _tmp_221: 'as' NAME static void * -_tmp_220_rule(Parser *p) +_tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38492,7 +38633,7 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38501,12 +38642,12 @@ _tmp_220_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38515,9 +38656,9 @@ _tmp_220_rule(Parser *p) return _res; } -// _tmp_221: positional_patterns ',' +// _tmp_222: positional_patterns ',' static void * -_tmp_221_rule(Parser *p) +_tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38534,7 +38675,7 @@ _tmp_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -38543,12 +38684,12 @@ _tmp_221_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -38557,9 +38698,9 @@ _tmp_221_rule(Parser *p) return _res; } -// _tmp_222: '->' expression +// _tmp_223: '->' expression static void * -_tmp_222_rule(Parser *p) +_tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38576,7 +38717,7 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty expression_var; if ( @@ -38585,12 +38726,12 @@ _tmp_222_rule(Parser *p) (expression_var = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = _PyPegen_dummy_name(p, _literal, expression_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -38599,9 +38740,9 @@ _tmp_222_rule(Parser *p) return _res; } -// _tmp_223: '(' arguments? ')' +// _tmp_224: '(' arguments? ')' static void * -_tmp_223_rule(Parser *p) +_tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38618,7 +38759,7 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38631,12 +38772,12 @@ _tmp_223_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38645,9 +38786,9 @@ _tmp_223_rule(Parser *p) return _res; } -// _tmp_224: '(' arguments? ')' +// _tmp_225: '(' arguments? ')' static void * -_tmp_224_rule(Parser *p) +_tmp_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38664,7 +38805,7 @@ _tmp_224_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38677,12 +38818,12 @@ _tmp_224_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38691,9 +38832,9 @@ _tmp_224_rule(Parser *p) return _res; } -// _loop0_226: ',' double_starred_kvpair +// _loop0_227: ',' double_starred_kvpair static asdl_seq * -_loop0_226_rule(Parser *p) +_loop0_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38719,7 +38860,7 @@ _loop0_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -38751,7 +38892,7 @@ _loop0_226_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_227[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38768,9 +38909,9 @@ _loop0_226_rule(Parser *p) return _seq; } -// _gather_225: double_starred_kvpair _loop0_226 +// _gather_226: double_starred_kvpair _loop0_227 static asdl_seq * -_gather_225_rule(Parser *p) +_gather_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38782,27 +38923,27 @@ _gather_225_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_226 + { // double_starred_kvpair _loop0_227 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_226")); + D(fprintf(stderr, "%*c> _gather_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_227")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_226_rule(p)) // _loop0_226 + (seq = _loop0_227_rule(p)) // _loop0_227 ) { - D(fprintf(stderr, "%*c+ _gather_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_226")); + D(fprintf(stderr, "%*c+ _gather_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_227")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_225[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_226")); + D(fprintf(stderr, "%*c%s _gather_226[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_227")); } _res = NULL; done: @@ -38810,9 +38951,9 @@ _gather_225_rule(Parser *p) return _res; } -// _tmp_227: '}' | ',' +// _tmp_228: '}' | ',' static void * -_tmp_227_rule(Parser *p) +_tmp_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38829,18 +38970,18 @@ _tmp_227_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -38848,18 +38989,18 @@ _tmp_227_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -38868,9 +39009,9 @@ _tmp_227_rule(Parser *p) return _res; } -// _tmp_228: '}' | ',' +// _tmp_229: '}' | ',' static void * -_tmp_228_rule(Parser *p) +_tmp_229_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38887,18 +39028,18 @@ _tmp_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -38906,18 +39047,18 @@ _tmp_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -38926,9 +39067,9 @@ _tmp_228_rule(Parser *p) return _res; } -// _tmp_229: yield_expr | star_expressions +// _tmp_230: yield_expr | star_expressions static void * -_tmp_229_rule(Parser *p) +_tmp_230_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38945,18 +39086,18 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -38964,18 +39105,18 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -38984,9 +39125,9 @@ _tmp_229_rule(Parser *p) return _res; } -// _tmp_230: yield_expr | star_expressions +// _tmp_231: yield_expr | star_expressions static void * -_tmp_230_rule(Parser *p) +_tmp_231_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39003,18 +39144,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39022,18 +39163,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39042,9 +39183,9 @@ _tmp_230_rule(Parser *p) return _res; } -// _tmp_231: '=' | '!' | ':' | '}' +// _tmp_232: '=' | '!' | ':' | '}' static void * -_tmp_231_rule(Parser *p) +_tmp_232_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39061,18 +39202,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // '!' @@ -39080,18 +39221,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39099,18 +39240,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39118,18 +39259,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39138,9 +39279,9 @@ _tmp_231_rule(Parser *p) return _res; } -// _tmp_232: yield_expr | star_expressions +// _tmp_233: yield_expr | star_expressions static void * -_tmp_232_rule(Parser *p) +_tmp_233_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39157,18 +39298,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39176,18 +39317,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39196,9 +39337,9 @@ _tmp_232_rule(Parser *p) return _res; } -// _tmp_233: '!' | ':' | '}' +// _tmp_234: '!' | ':' | '}' static void * -_tmp_233_rule(Parser *p) +_tmp_234_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39215,18 +39356,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39234,18 +39375,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39253,18 +39394,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39273,9 +39414,9 @@ _tmp_233_rule(Parser *p) return _res; } -// _tmp_234: yield_expr | star_expressions +// _tmp_235: yield_expr | star_expressions static void * -_tmp_234_rule(Parser *p) +_tmp_235_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39292,18 +39433,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39311,18 +39452,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39331,9 +39472,9 @@ _tmp_234_rule(Parser *p) return _res; } -// _tmp_235: yield_expr | star_expressions +// _tmp_236: yield_expr | star_expressions static void * -_tmp_235_rule(Parser *p) +_tmp_236_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39350,18 +39491,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39369,18 +39510,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39389,9 +39530,9 @@ _tmp_235_rule(Parser *p) return _res; } -// _tmp_236: '!' NAME +// _tmp_237: '!' NAME static void * -_tmp_236_rule(Parser *p) +_tmp_237_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39408,7 +39549,7 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39417,12 +39558,12 @@ _tmp_236_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39431,9 +39572,9 @@ _tmp_236_rule(Parser *p) return _res; } -// _tmp_237: ':' | '}' +// _tmp_238: ':' | '}' static void * -_tmp_237_rule(Parser *p) +_tmp_238_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39450,18 +39591,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39469,18 +39610,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39489,9 +39630,9 @@ _tmp_237_rule(Parser *p) return _res; } -// _tmp_238: yield_expr | star_expressions +// _tmp_239: yield_expr | star_expressions static void * -_tmp_238_rule(Parser *p) +_tmp_239_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39508,18 +39649,18 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39527,18 +39668,18 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39547,9 +39688,9 @@ _tmp_238_rule(Parser *p) return _res; } -// _tmp_239: '!' NAME +// _tmp_240: '!' NAME static void * -_tmp_239_rule(Parser *p) +_tmp_240_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39566,7 +39707,7 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39575,12 +39716,12 @@ _tmp_239_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39589,9 +39730,9 @@ _tmp_239_rule(Parser *p) return _res; } -// _loop0_240: fstring_format_spec +// _loop0_241: fstring_format_spec static asdl_seq * -_loop0_240_rule(Parser *p) +_loop0_241_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39617,7 +39758,7 @@ _loop0_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -39640,7 +39781,7 @@ _loop0_240_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -39657,9 +39798,9 @@ _loop0_240_rule(Parser *p) return _seq; } -// _tmp_241: yield_expr | star_expressions +// _tmp_242: yield_expr | star_expressions static void * -_tmp_241_rule(Parser *p) +_tmp_242_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39676,18 +39817,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39695,18 +39836,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39715,9 +39856,9 @@ _tmp_241_rule(Parser *p) return _res; } -// _tmp_242: '!' NAME +// _tmp_243: '!' NAME static void * -_tmp_242_rule(Parser *p) +_tmp_243_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39734,7 +39875,7 @@ _tmp_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39743,12 +39884,12 @@ _tmp_242_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39757,9 +39898,9 @@ _tmp_242_rule(Parser *p) return _res; } -// _tmp_243: ':' | '}' +// _tmp_244: ':' | '}' static void * -_tmp_243_rule(Parser *p) +_tmp_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39776,18 +39917,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39795,18 +39936,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39815,9 +39956,9 @@ _tmp_243_rule(Parser *p) return _res; } -// _tmp_244: star_targets '=' +// _tmp_245: star_targets '=' static void * -_tmp_244_rule(Parser *p) +_tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39834,7 +39975,7 @@ _tmp_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -39843,7 +39984,7 @@ _tmp_244_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -39853,7 +39994,7 @@ _tmp_244_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -39862,9 +40003,9 @@ _tmp_244_rule(Parser *p) return _res; } -// _tmp_245: '.' | '...' +// _tmp_246: '.' | '...' static void * -_tmp_245_rule(Parser *p) +_tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39881,18 +40022,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -39900,18 +40041,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -39920,9 +40061,9 @@ _tmp_245_rule(Parser *p) return _res; } -// _tmp_246: '.' | '...' +// _tmp_247: '.' | '...' static void * -_tmp_246_rule(Parser *p) +_tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39939,18 +40080,18 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -39958,18 +40099,18 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -39978,9 +40119,9 @@ _tmp_246_rule(Parser *p) return _res; } -// _tmp_247: '@' named_expression NEWLINE +// _tmp_248: '@' named_expression NEWLINE static void * -_tmp_247_rule(Parser *p) +_tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39997,7 +40138,7 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -40009,7 +40150,7 @@ _tmp_247_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40019,7 +40160,7 @@ _tmp_247_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -40028,9 +40169,9 @@ _tmp_247_rule(Parser *p) return _res; } -// _tmp_248: ',' expression +// _tmp_249: ',' expression static void * -_tmp_248_rule(Parser *p) +_tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40047,7 +40188,7 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -40056,7 +40197,7 @@ _tmp_248_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40066,7 +40207,7 @@ _tmp_248_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -40075,9 +40216,9 @@ _tmp_248_rule(Parser *p) return _res; } -// _tmp_249: ',' star_expression +// _tmp_250: ',' star_expression static void * -_tmp_249_rule(Parser *p) +_tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40094,7 +40235,7 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -40103,7 +40244,7 @@ _tmp_249_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40113,7 +40254,7 @@ _tmp_249_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -40122,9 +40263,9 @@ _tmp_249_rule(Parser *p) return _res; } -// _tmp_250: 'or' conjunction +// _tmp_251: 'or' conjunction static void * -_tmp_250_rule(Parser *p) +_tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40141,7 +40282,7 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -40150,7 +40291,7 @@ _tmp_250_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40160,7 +40301,7 @@ _tmp_250_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -40169,9 +40310,9 @@ _tmp_250_rule(Parser *p) return _res; } -// _tmp_251: 'and' inversion +// _tmp_252: 'and' inversion static void * -_tmp_251_rule(Parser *p) +_tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40188,7 +40329,7 @@ _tmp_251_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -40197,7 +40338,7 @@ _tmp_251_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40207,7 +40348,7 @@ _tmp_251_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -40216,9 +40357,9 @@ _tmp_251_rule(Parser *p) return _res; } -// _tmp_252: slice | starred_expression +// _tmp_253: slice | starred_expression static void * -_tmp_252_rule(Parser *p) +_tmp_253_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40235,18 +40376,18 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -40254,18 +40395,18 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -40274,9 +40415,9 @@ _tmp_252_rule(Parser *p) return _res; } -// _tmp_253: fstring | string +// _tmp_254: fstring | tagstring | string static void * -_tmp_253_rule(Parser *p) +_tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40293,37 +40434,56 @@ _tmp_253_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } + { // tagstring + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tagstring")); + expr_ty tagstring_var; + if ( + (tagstring_var = tagstring_rule(p)) // tagstring + ) + { + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tagstring")); + _res = tagstring_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tagstring")); + } { // string if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -40332,9 +40492,9 @@ _tmp_253_rule(Parser *p) return _res; } -// _tmp_254: 'if' disjunction +// _tmp_255: 'if' disjunction static void * -_tmp_254_rule(Parser *p) +_tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40351,7 +40511,7 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40360,7 +40520,7 @@ _tmp_254_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40370,7 +40530,7 @@ _tmp_254_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40379,9 +40539,9 @@ _tmp_254_rule(Parser *p) return _res; } -// _tmp_255: 'if' disjunction +// _tmp_256: 'if' disjunction static void * -_tmp_255_rule(Parser *p) +_tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40398,7 +40558,7 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40407,7 +40567,7 @@ _tmp_255_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40417,7 +40577,7 @@ _tmp_255_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40426,9 +40586,9 @@ _tmp_255_rule(Parser *p) return _res; } -// _tmp_256: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_257: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_256_rule(Parser *p) +_tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40445,18 +40605,18 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -40464,20 +40624,20 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_268_var; + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_269_var; if ( - (_tmp_268_var = _tmp_268_rule(p)) // assignment_expression | expression !':=' + (_tmp_269_var = _tmp_269_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_268_var; + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_269_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -40486,9 +40646,9 @@ _tmp_256_rule(Parser *p) return _res; } -// _tmp_257: ',' star_target +// _tmp_258: ',' star_target static void * -_tmp_257_rule(Parser *p) +_tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40505,7 +40665,7 @@ _tmp_257_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40514,7 +40674,7 @@ _tmp_257_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40524,7 +40684,7 @@ _tmp_257_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -40533,9 +40693,9 @@ _tmp_257_rule(Parser *p) return _res; } -// _tmp_258: ',' star_target +// _tmp_259: ',' star_target static void * -_tmp_258_rule(Parser *p) +_tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40552,7 +40712,7 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40561,7 +40721,7 @@ _tmp_258_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40571,7 +40731,7 @@ _tmp_258_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -40580,9 +40740,9 @@ _tmp_258_rule(Parser *p) return _res; } -// _tmp_259: star_targets '=' +// _tmp_260: star_targets '=' static void * -_tmp_259_rule(Parser *p) +_tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40599,7 +40759,7 @@ _tmp_259_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40608,12 +40768,12 @@ _tmp_259_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40622,9 +40782,9 @@ _tmp_259_rule(Parser *p) return _res; } -// _tmp_260: star_targets '=' +// _tmp_261: star_targets '=' static void * -_tmp_260_rule(Parser *p) +_tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40641,7 +40801,7 @@ _tmp_260_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40650,12 +40810,12 @@ _tmp_260_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40664,9 +40824,9 @@ _tmp_260_rule(Parser *p) return _res; } -// _tmp_261: ')' | '**' +// _tmp_262: ')' | '**' static void * -_tmp_261_rule(Parser *p) +_tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40683,18 +40843,18 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -40702,18 +40862,18 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -40722,9 +40882,9 @@ _tmp_261_rule(Parser *p) return _res; } -// _tmp_262: ':' | '**' +// _tmp_263: ':' | '**' static void * -_tmp_262_rule(Parser *p) +_tmp_263_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40741,18 +40901,18 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -40760,18 +40920,18 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -40780,9 +40940,9 @@ _tmp_262_rule(Parser *p) return _res; } -// _tmp_263: expression ['as' star_target] +// _tmp_264: expression ['as' star_target] static void * -_tmp_263_rule(Parser *p) +_tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40799,22 +40959,22 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_269_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_270_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -40823,9 +40983,9 @@ _tmp_263_rule(Parser *p) return _res; } -// _tmp_264: expressions ['as' star_target] +// _tmp_265: expressions ['as' star_target] static void * -_tmp_264_rule(Parser *p) +_tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40842,22 +41002,22 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_270_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -40866,9 +41026,9 @@ _tmp_264_rule(Parser *p) return _res; } -// _tmp_265: expression ['as' star_target] +// _tmp_266: expression ['as' star_target] static void * -_tmp_265_rule(Parser *p) +_tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40885,22 +41045,22 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -40909,9 +41069,9 @@ _tmp_265_rule(Parser *p) return _res; } -// _tmp_266: expressions ['as' star_target] +// _tmp_267: expressions ['as' star_target] static void * -_tmp_266_rule(Parser *p) +_tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40928,22 +41088,22 @@ _tmp_266_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -40952,9 +41112,9 @@ _tmp_266_rule(Parser *p) return _res; } -// _tmp_267: 'as' NAME +// _tmp_268: 'as' NAME static void * -_tmp_267_rule(Parser *p) +_tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40971,7 +41131,7 @@ _tmp_267_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -40980,12 +41140,12 @@ _tmp_267_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -40994,9 +41154,9 @@ _tmp_267_rule(Parser *p) return _res; } -// _tmp_268: assignment_expression | expression !':=' +// _tmp_269: assignment_expression | expression !':=' static void * -_tmp_268_rule(Parser *p) +_tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41013,18 +41173,18 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -41032,7 +41192,7 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -41040,12 +41200,12 @@ _tmp_268_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -41054,9 +41214,9 @@ _tmp_268_rule(Parser *p) return _res; } -// _tmp_269: 'as' star_target +// _tmp_270: 'as' star_target static void * -_tmp_269_rule(Parser *p) +_tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41073,7 +41233,7 @@ _tmp_269_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41082,12 +41242,12 @@ _tmp_269_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41096,9 +41256,9 @@ _tmp_269_rule(Parser *p) return _res; } -// _tmp_270: 'as' star_target +// _tmp_271: 'as' star_target static void * -_tmp_270_rule(Parser *p) +_tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41115,7 +41275,7 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41124,12 +41284,12 @@ _tmp_270_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41138,9 +41298,9 @@ _tmp_270_rule(Parser *p) return _res; } -// _tmp_271: 'as' star_target +// _tmp_272: 'as' star_target static void * -_tmp_271_rule(Parser *p) +_tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41157,7 +41317,7 @@ _tmp_271_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41166,12 +41326,12 @@ _tmp_271_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41180,9 +41340,9 @@ _tmp_271_rule(Parser *p) return _res; } -// _tmp_272: 'as' star_target +// _tmp_273: 'as' star_target static void * -_tmp_272_rule(Parser *p) +_tmp_273_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41199,7 +41359,7 @@ _tmp_272_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41208,12 +41368,12 @@ _tmp_272_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; From 688bb68c4e87b8893a951e146e095ed6ce850448 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 24 Apr 2023 12:28:30 -0600 Subject: [PATCH 0004/1206] Add TagString AST node (prelim) --- Include/internal/pycore_ast.h | 14 +++- Include/internal/pycore_ast_state.h | 2 + Parser/Python.asdl | 1 + Python/Python-ast.c | 106 ++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_ast.h b/Include/internal/pycore_ast.h index 36277efe9c5ca5..c36fbc1f13b2a4 100644 --- a/Include/internal/pycore_ast.h +++ b/Include/internal/pycore_ast.h @@ -341,9 +341,10 @@ enum _expr_kind {BoolOp_kind=1, NamedExpr_kind=2, BinOp_kind=3, UnaryOp_kind=4, ListComp_kind=9, SetComp_kind=10, DictComp_kind=11, GeneratorExp_kind=12, Await_kind=13, Yield_kind=14, YieldFrom_kind=15, Compare_kind=16, Call_kind=17, - FormattedValue_kind=18, JoinedStr_kind=19, Constant_kind=20, - Attribute_kind=21, Subscript_kind=22, Starred_kind=23, - Name_kind=24, List_kind=25, Tuple_kind=26, Slice_kind=27}; + FormattedValue_kind=18, JoinedStr_kind=19, TagString_kind=20, + Constant_kind=21, Attribute_kind=22, Subscript_kind=23, + Starred_kind=24, Name_kind=25, List_kind=26, Tuple_kind=27, + Slice_kind=28}; struct _expr { enum _expr_kind kind; union { @@ -443,6 +444,11 @@ struct _expr { asdl_expr_seq *values; } JoinedStr; + struct { + expr_ty tag; + expr_ty str; + } TagString; + struct { constant value; string kind; @@ -771,6 +777,8 @@ expr_ty _PyAST_FormattedValue(expr_ty value, int conversion, expr_ty end_lineno, int end_col_offset, PyArena *arena); expr_ty _PyAST_JoinedStr(asdl_expr_seq * values, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); +expr_ty _PyAST_TagString(expr_ty tag, expr_ty str, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena *arena); expr_ty _PyAST_Constant(constant value, string kind, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); diff --git a/Include/internal/pycore_ast_state.h b/Include/internal/pycore_ast_state.h index f15b4905eed14b..a2d18abf8c6d74 100644 --- a/Include/internal/pycore_ast_state.h +++ b/Include/internal/pycore_ast_state.h @@ -134,6 +134,7 @@ struct ast_state { PyObject *Sub_singleton; PyObject *Sub_type; PyObject *Subscript_type; + PyObject *TagString_type; PyObject *TryStar_type; PyObject *Try_type; PyObject *Tuple_type; @@ -234,6 +235,7 @@ struct ast_state { PyObject *slice; PyObject *step; PyObject *stmt_type; + PyObject *str; PyObject *subject; PyObject *tag; PyObject *target; diff --git a/Parser/Python.asdl b/Parser/Python.asdl index e9423a7c984f21..9136144cc090d4 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -77,6 +77,7 @@ module Python | Call(expr func, expr* args, keyword* keywords) | FormattedValue(expr value, int conversion, expr? format_spec) | JoinedStr(expr* values) + | TagString(expr tag, expr str) | Constant(constant value, string? kind) -- the following expression can appear in assignment context diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 6c878474afb192..f2c7fa5685a82b 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -147,6 +147,7 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->Sub_singleton); Py_CLEAR(state->Sub_type); Py_CLEAR(state->Subscript_type); + Py_CLEAR(state->TagString_type); Py_CLEAR(state->TryStar_type); Py_CLEAR(state->Try_type); Py_CLEAR(state->Tuple_type); @@ -247,6 +248,7 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->slice); Py_CLEAR(state->step); Py_CLEAR(state->stmt_type); + Py_CLEAR(state->str); Py_CLEAR(state->subject); Py_CLEAR(state->tag); Py_CLEAR(state->target); @@ -346,6 +348,7 @@ static int init_identifiers(struct ast_state *state) if ((state->simple = PyUnicode_InternFromString("simple")) == NULL) return 0; if ((state->slice = PyUnicode_InternFromString("slice")) == NULL) return 0; if ((state->step = PyUnicode_InternFromString("step")) == NULL) return 0; + if ((state->str = PyUnicode_InternFromString("str")) == NULL) return 0; if ((state->subject = PyUnicode_InternFromString("subject")) == NULL) return 0; if ((state->tag = PyUnicode_InternFromString("tag")) == NULL) return 0; if ((state->target = PyUnicode_InternFromString("target")) == NULL) return 0; @@ -601,6 +604,10 @@ static const char * const FormattedValue_fields[]={ static const char * const JoinedStr_fields[]={ "values", }; +static const char * const TagString_fields[]={ + "tag", + "str", +}; static const char * const Constant_fields[]={ "value", "kind", @@ -1331,6 +1338,7 @@ init_types(struct ast_state *state) " | Call(expr func, expr* args, keyword* keywords)\n" " | FormattedValue(expr value, int conversion, expr? format_spec)\n" " | JoinedStr(expr* values)\n" + " | TagString(expr tag, expr str)\n" " | Constant(constant value, string? kind)\n" " | Attribute(expr value, identifier attr, expr_context ctx)\n" " | Subscript(expr value, expr slice, expr_context ctx)\n" @@ -1428,6 +1436,10 @@ init_types(struct ast_state *state) JoinedStr_fields, 1, "JoinedStr(expr* values)"); if (!state->JoinedStr_type) return 0; + state->TagString_type = make_type(state, "TagString", state->expr_type, + TagString_fields, 2, + "TagString(expr tag, expr str)"); + if (!state->TagString_type) return 0; state->Constant_type = make_type(state, "Constant", state->expr_type, Constant_fields, 2, "Constant(constant value, string? kind)"); @@ -3046,6 +3058,34 @@ _PyAST_JoinedStr(asdl_expr_seq * values, int lineno, int col_offset, int return p; } +expr_ty +_PyAST_TagString(expr_ty tag, expr_ty str, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena) +{ + expr_ty p; + if (!tag) { + PyErr_SetString(PyExc_ValueError, + "field 'tag' is required for TagString"); + return NULL; + } + if (!str) { + PyErr_SetString(PyExc_ValueError, + "field 'str' is required for TagString"); + return NULL; + } + p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = TagString_kind; + p->v.TagString.tag = tag; + p->v.TagString.str = str; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + expr_ty _PyAST_Constant(constant value, string kind, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) @@ -4568,6 +4608,21 @@ ast2obj_expr(struct ast_state *state, void* _o) goto failed; Py_DECREF(value); break; + case TagString_kind: + tp = (PyTypeObject *)state->TagString_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(state, o->v.TagString.tag); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->tag, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(state, o->v.TagString.str); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->str, value) == -1) + goto failed; + Py_DECREF(value); + break; case Constant_kind: tp = (PyTypeObject *)state->Constant_type; result = PyType_GenericNew(tp, NULL, NULL); @@ -9334,6 +9389,54 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (*out == NULL) goto failed; return 0; } + tp = state->TagString_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty tag; + expr_ty str; + + if (_PyObject_LookupAttr(obj, state->tag, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"tag\" missing from TagString"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'TagString' node")) { + goto failed; + } + res = obj2ast_expr(state, tmp, &tag, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->str, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"str\" missing from TagString"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'TagString' node")) { + goto failed; + } + res = obj2ast_expr(state, tmp, &str, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_TagString(tag, str, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } tp = state->Constant_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { @@ -11986,6 +12089,9 @@ astmodule_exec(PyObject *m) if (PyModule_AddObjectRef(m, "JoinedStr", state->JoinedStr_type) < 0) { return -1; } + if (PyModule_AddObjectRef(m, "TagString", state->TagString_type) < 0) { + return -1; + } if (PyModule_AddObjectRef(m, "Constant", state->Constant_type) < 0) { return -1; } From d4e2ec706e753dbdd0e567fed6ca78a1d5de3196 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 24 Apr 2023 23:11:02 -0600 Subject: [PATCH 0005/1206] Turn tag'xxx' into TagString node (don't run!) --- Grammar/python.gram | 2 +- Parser/action_helpers.c | 50 +++++++++++++++++++++++++++++++++++++++++ Parser/parser.c | 2 +- Parser/pegen.h | 1 + Python/ast.c | 3 +++ 5 files changed, 56 insertions(+), 2 deletions(-) diff --git a/Grammar/python.gram b/Grammar/python.gram index d0ac944d8addd7..d3cf086b67a8a7 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -895,7 +895,7 @@ fstring_format_spec[expr_ty]: fstring[expr_ty]: | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } tagstring[expr_ty]: - | a=TAGSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } + | a=TAGSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_tag_str(p, a, (asdl_expr_seq*)b, c) } string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) } strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|tagstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) } diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 55c0f6fdd620f4..af0bebb85e7139 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1344,6 +1344,47 @@ _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b p->arena); } +static expr_ty +_PyPegen_name_from_f_string_start(Parser *p, Token* t) +{ + if (t == NULL) { + return NULL; + } + const char *s = PyBytes_AsString(t->bytes); + if (!s) { + p->error_indicator = 1; + return NULL; + } + int size = strlen(s); + assert(size == PyBytes_Size(t->bytes)); + while (size > 0 && (s[size-1] == '"' || s[size-1] == '\'')) { + size--; + } + char *snew = _PyArena_Malloc(p->arena, size+1); + if (snew == NULL) { + p->error_indicator = 1; + return NULL; + } + strncpy(snew, s, size); + snew[size] = '\0'; + PyObject *id = _PyPegen_new_identifier(p, snew); + if (id == NULL) { + p->error_indicator = 1; + return NULL; + } + return _PyAST_Name(id, Load, t->lineno, t->col_offset, t->end_lineno, + t->end_col_offset, p->arena); +} + +expr_ty +_PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { + expr_ty tag = _PyPegen_name_from_f_string_start(p, a); + expr_ty joined_str = _PyPegen_joined_str(p, a, raw_expressions, b); + return _PyAST_TagString(tag, joined_str, a->lineno, a->col_offset, + b->end_lineno, b->end_col_offset, + p->arena); +} + expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) { char* bstr = PyBytes_AsString(tok->bytes); if (bstr == NULL) { @@ -1457,6 +1498,7 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, assert(len > 0); int f_string_found = 0; + int tag_string_found = 0; int unicode_string_found = 0; int bytes_found = 0; @@ -1471,7 +1513,10 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, unicode_string_found = 1; } n_flattened_elements++; + } else if (elem->kind == TagString_kind) { + tag_string_found = 1; } else { + assert(elem->kind == JoinedStr_kind); n_flattened_elements += asdl_seq_LEN(elem->v.JoinedStr.values); f_string_found = 1; } @@ -1482,6 +1527,11 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, return NULL; } + if (tag_string_found && len > 1) { + RAISE_SYNTAX_ERROR("tag string cannot be joined"); + return NULL; + } + if (bytes_found) { PyObject* res = PyBytes_FromString(""); diff --git a/Parser/parser.c b/Parser/parser.c index 75f6c8492abcd3..b590f687aa0547 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -15916,7 +15916,7 @@ tagstring_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ tagstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "TAGSTRING_START fstring_middle* FSTRING_END")); - _res = _PyPegen_joined_str ( p , a , ( asdl_expr_seq* ) b , c ); + _res = _PyPegen_tag_str ( p , a , ( asdl_expr_seq* ) b , c ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; diff --git a/Parser/pegen.h b/Parser/pegen.h index 6962013c2d18b4..7f39e545ec4ebb 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -347,6 +347,7 @@ asdl_stmt_seq *_PyPegen_interactive_exit(Parser *); // TODO: move to the correct place in this file expr_ty _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b); +expr_ty _PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b); // Generated function in parse.c - function definition in python.gram void *_PyPegen_parse(Parser *); diff --git a/Python/ast.c b/Python/ast.c index 50fc8e01fb3f69..a191435df73ea8 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -344,6 +344,9 @@ validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) case JoinedStr_kind: ret = validate_exprs(state, exp->v.JoinedStr.values, Load, 0); break; + case TagString_kind: + ret = validate_expr(state, exp->v.TagString.str, Load); + break; case FormattedValue_kind: if (validate_expr(state, exp->v.FormattedValue.value, Load) == 0) return 0; From ac515e577a28f2e8febc6643cf065b05f8441020 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 00:03:48 -0600 Subject: [PATCH 0006/1206] Replace FormattedValue with (lambda, raw, conv, spec) tuple --- Parser/action_helpers.c | 86 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index af0bebb85e7139..b0f9e74bcfe91b 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1376,11 +1376,93 @@ _PyPegen_name_from_f_string_start(Parser *p, Token* t) t->end_col_offset, p->arena); } +static expr_ty +lambdafy(Parser *p, expr_ty arg) +{ + arguments_ty args = _PyPegen_empty_arguments(p); + if (args == NULL) + return NULL; + return _PyAST_Lambda(args, arg, + arg->lineno, arg->col_offset, arg->end_lineno, arg->end_col_offset, + p->arena); +} + expr_ty _PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { expr_ty tag = _PyPegen_name_from_f_string_start(p, a); - expr_ty joined_str = _PyPegen_joined_str(p, a, raw_expressions, b); - return _PyAST_TagString(tag, joined_str, a->lineno, a->col_offset, + if (tag == NULL) { + return NULL; + } + expr_ty str = _PyPegen_joined_str(p, a, raw_expressions, b); + if (str == NULL) { + return NULL; + } + if (str->kind == JoinedStr_kind) { + // Transform FormattedValue items into thunks (for now, tuples) + asdl_expr_seq *values = str->v.JoinedStr.values; + int nvalues = asdl_seq_LEN(values); + expr_ty none = NULL; + for (int i = 0; i < nvalues; i++) { + expr_ty value = asdl_seq_GET(values, i); + if (value->kind == FormattedValue_kind) { + if (none == NULL) { + none = _PyAST_Constant(Py_None, NULL, + str->lineno, str->col_offset, + str->end_lineno, str->end_col_offset, + p->arena); + if (none == NULL) + return NULL; + } + expr_ty expr = value->v.FormattedValue.value; + expr_ty lambda = lambdafy(p, expr); + if (lambda == NULL) + return NULL; + constant rawstr = _PyAST_ExprAsUnicode(expr); + if (rawstr == NULL) + return NULL; + expr_ty raw = _PyAST_Constant(rawstr, NULL, + expr->lineno, expr->col_offset, + expr->end_lineno, expr->end_col_offset, + p->arena); + if (raw == NULL) + return NULL; + expr_ty conv = none; + int conversion = value->v.FormattedValue.conversion; + if (conversion >= 0) { + char buf[1]; + buf[0] = conversion; + constant uconv = _PyUnicode_FromASCII(buf, 1); + if (uconv == NULL) + return NULL; + conv = _PyAST_Constant(uconv, NULL, + expr->lineno, expr->col_offset, + expr->end_lineno, expr->end_col_offset, + p->arena); + if (conv == NULL) + return NULL; + } + expr_ty spec = value->v.FormattedValue.format_spec; + if (spec == NULL) { + spec = none; + } + asdl_expr_seq *elts = _Py_asdl_expr_seq_new(4, p->arena); + if (elts == NULL) + return NULL; + asdl_seq_SET(elts, 0, lambda); + asdl_seq_SET(elts, 1, raw); + asdl_seq_SET(elts, 2, conv); + asdl_seq_SET(elts, 3, spec); + expr_ty tuple = _PyAST_Tuple(elts, Load, + value->lineno, value->col_offset, + value->end_lineno, value->end_col_offset, + p->arena); + if (tuple == NULL) + return NULL; + asdl_seq_SET(values, i, tuple); + } + } + } + return _PyAST_TagString(tag, str, a->lineno, a->col_offset, b->end_lineno, b->end_col_offset, p->arena); } From 69a7b4e17d31a69728022a4e702e0a8280cf2955 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 00:10:23 -0600 Subject: [PATCH 0007/1206] Add TODO --- Parser/action_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index b0f9e74bcfe91b..d62ac6f435f8e7 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1580,7 +1580,7 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, assert(len > 0); int f_string_found = 0; - int tag_string_found = 0; + int tag_string_found = 0; // TODO: Do this in the grammar instead int unicode_string_found = 0; int bytes_found = 0; From 7e2e6f614601a228d3c9f11977b19de46cfe4ccc Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 09:05:38 -0600 Subject: [PATCH 0008/1206] Copy the rest of Python/ast*.c from original branch --- Python/ast.c | 3 +- Python/ast_opt.c | 4 +++ Python/ast_unparse.c | 66 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/Python/ast.c b/Python/ast.c index a191435df73ea8..32e7f2abfa12a7 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -345,7 +345,8 @@ validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) ret = validate_exprs(state, exp->v.JoinedStr.values, Load, 0); break; case TagString_kind: - ret = validate_expr(state, exp->v.TagString.str, Load); + ret = validate_expr(state, exp->v.TagString.tag, Load) && + validate_expr(state, exp->v.TagString.str, Load); break; case FormattedValue_kind: if (validate_expr(state, exp->v.FormattedValue.value, Load) == 0) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 8270fa8e372d93..17b7285ffd72bf 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -788,6 +788,10 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) case JoinedStr_kind: CALL_SEQ(astfold_expr, expr, node_->v.JoinedStr.values); break; + case TagString_kind: + CALL(astfold_expr, expr_ty, node_->v.TagString.tag); + CALL(astfold_expr, expr_ty, node_->v.TagString.str); + break; case Attribute_kind: CALL(astfold_expr, expr_ty, node_->v.Attribute.value); break; diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c index 8aff045101cc72..390a0c52c742e6 100644 --- a/Python/ast_unparse.c +++ b/Python/ast_unparse.c @@ -25,7 +25,7 @@ expr_as_unicode(expr_ty e, int level); static int append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level); static int -append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec); +append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec, bool is_tag_str); static int append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e); static int @@ -602,6 +602,41 @@ append_fstring_unicode(_PyUnicodeWriter *writer, PyObject *unicode) return result; } +static int +append_interpolation(_PyUnicodeWriter *writer, expr_ty e) +{ + APPEND_STR("{"); + if (e->kind == Tuple_kind) { + asdl_expr_seq *elts = e->v.Tuple.elts; + if (asdl_seq_LEN(elts) == 4) { + expr_ty raw = asdl_seq_GET(elts, 1); + if (raw->kind == Constant_kind) { + constant c = raw->v.Constant.value; + if (PyUnicode_CheckExact(c)) { + if (-1 == _PyUnicodeWriter_WriteStr(writer, c)) + return -1; + } + } + expr_ty conv = asdl_seq_GET(elts, 2); + if (conv->kind == Constant_kind) { + constant c = conv->v.Constant.value; + if (PyUnicode_CheckExact(c)) { + APPEND_STR("!"); + if (-1 == _PyUnicodeWriter_WriteStr(writer, c)) + return -1; + } + } + expr_ty spec = asdl_seq_GET(elts, 3); + if (spec->kind == JoinedStr_kind) { + APPEND_STR(":"); + if (-1 == append_joinedstr(writer, spec, true, false)) + return -1; + } + } + } + APPEND_STR_FINISH("}"); +} + static int append_fstring_element(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) { @@ -609,9 +644,11 @@ append_fstring_element(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) case Constant_kind: return append_fstring_unicode(writer, e->v.Constant.value); case JoinedStr_kind: - return append_joinedstr(writer, e, is_format_spec); + return append_joinedstr(writer, e, is_format_spec, false); case FormattedValue_kind: return append_formattedvalue(writer, e); + case Tuple_kind: + return append_interpolation(writer, e); default: PyErr_SetString(PyExc_SystemError, "unknown expression kind inside f-string"); @@ -645,16 +682,19 @@ build_fstring_body(asdl_expr_seq *values, bool is_format_spec) } static int -append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) +append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec, bool is_tag_str) { - int result = -1; PyObject *body = build_fstring_body(e->v.JoinedStr.values, is_format_spec); if (!body) { return -1; } + int result = 0; if (!is_format_spec) { - if (-1 != append_charp(writer, "f") && + if (!is_tag_str) { + result = append_charp(writer, "f"); + } + if (-1 != result && -1 != append_repr(writer, body)) { result = 0; @@ -667,6 +707,18 @@ append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) return result; } +static int +append_tagstring(_PyUnicodeWriter *writer, expr_ty e) +{ + APPEND_EXPR(e->v.TagString.tag, 0); + expr_ty str = e->v.TagString.str; + if (str->kind == JoinedStr_kind) { + if (-1 == append_joinedstr(writer, str, false, true)) + return -1; + } + return 0; +} + static int append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e) { @@ -891,7 +943,9 @@ append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level) } return append_ast_constant(writer, e->v.Constant.value); case JoinedStr_kind: - return append_joinedstr(writer, e, false); + return append_joinedstr(writer, e, false, false); + case TagString_kind: + return append_tagstring(writer, e); case FormattedValue_kind: return append_formattedvalue(writer, e); /* The following exprs can be assignment targets. */ From 0a23d67069028862d393c4309074b40b9f120b61 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 09:10:47 -0600 Subject: [PATCH 0009/1206] Copy symtable.c changes --- Python/symtable.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Python/symtable.c b/Python/symtable.c index df7473943f3fc1..964ba950960f39 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1681,6 +1681,10 @@ symtable_visit_expr(struct symtable *st, expr_ty e) case JoinedStr_kind: VISIT_SEQ(st, expr, e->v.JoinedStr.values); break; + case TagString_kind: + VISIT(st, expr, e->v.TagString.tag); + VISIT(st, expr, e->v.TagString.str); + break; case Constant_kind: /* Nothing to do here. */ break; From e16541a65b0f9062bdfa4eca007fd2d57edc11a0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 09:26:59 -0600 Subject: [PATCH 0010/1206] Adapt compile.c changes --- Python/compile.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Python/compile.c b/Python/compile.c index a0ad3687f586d8..a6df5d6e4c8a7a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4499,6 +4499,30 @@ compiler_joined_str(struct compiler *c, expr_ty e) return SUCCESS; } +/* Used to implement tag strings */ +static int +compiler_tag_string(struct compiler *c, expr_ty e) +{ + location loc = LOC(e); + if (e->kind == TagString_kind) { + expr_ty tag = e->v.TagString.tag; + expr_ty str = e->v.TagString.str; + if (tag->kind == Name_kind) { + if (str->kind == JoinedStr_kind) { + // Generate code for tag(str1, str2, ...) + asdl_keyword_seq *keywords = + _Py_asdl_keyword_seq_new(0, c->c_arena); + if (keywords == NULL) + return 0; + ADDOP(c, loc, PUSH_NULL); + VISIT(c, expr, tag); + return compiler_call_helper(c, loc, 0, str->v.JoinedStr.values, keywords); + } + } + } + return compiler_error(c, loc, "More complicated tag-string not yet supported"); +} + /* Used to implement f-strings. Format a single value. */ static int compiler_formatted_value(struct compiler *c, expr_ty e) @@ -5420,6 +5444,8 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) break; case JoinedStr_kind: return compiler_joined_str(c, e); + case TagString_kind: + return compiler_tag_string(c, e); case FormattedValue_kind: return compiler_formatted_value(c, e); /* The following exprs can be assignment targets. */ From 3a8185ddfbb4b40aec26ef844e82c03f0ca492c6 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 10:50:08 -0600 Subject: [PATCH 0011/1206] Add some basic tests --- Lib/test/test_tag_strings.py | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Lib/test/test_tag_strings.py diff --git a/Lib/test/test_tag_strings.py b/Lib/test/test_tag_strings.py new file mode 100644 index 00000000000000..3d2834c8a42186 --- /dev/null +++ b/Lib/test/test_tag_strings.py @@ -0,0 +1,40 @@ +import unittest + +class TagStringTests(unittest.TestCase): + + def test_basic(self): + def tag(*args): + return "Spam" + self.assertEqual(tag"ham", "Spam") + self.assertEqual(tag"...{ham}...{eggs}...", "Spam") + + def test_tag_call(self): + def tag(*args): + return args + self.assertEqual(tag"ham", ("ham",)) + res = tag"... {ham and eggs} ..." + self.assertEqual(len(res), 3) + self.assertEqual(res[0], "... ") + func, string, conv, spec = res[1] + ham = 42 + eggs = "delicious" + self.assertEqual(func(), "delicious") + self.assertEqual(string, "ham and eggs") + self.assertEqual(conv, None) + self.assertEqual(spec, None) + self.assertEqual(res[2], " ...") + + def test_tag_call_with_conversion(self): + def tag(*args): + return args + res = tag"{ham!r:spec}" + func, string, conv, spec = res[0] + ham = 42 + self.assertEqual(func(), 42) + self.assertEqual(string, "ham") + self.assertEqual(conv, "r") + self.assertEqual(spec, "spec") + + +if __name__ == "__main__": + unittest.main() From ae1127a2a851821a94e5984b929b9ba13f46a6bf Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 11:12:43 -0600 Subject: [PATCH 0012/1206] Move check for joined tagstrings to grammar --- Grammar/python.gram | 5 ++- Parser/action_helpers.c | 8 ---- Parser/parser.c | 96 +++++++++++++++++------------------------ 3 files changed, 43 insertions(+), 66 deletions(-) diff --git a/Grammar/python.gram b/Grammar/python.gram index d3cf086b67a8a7..5337899a7c22ce 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -807,7 +807,8 @@ atom[expr_ty]: | 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) } | 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) } | 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) } - | &(STRING|FSTRING_START|TAGSTRING_START) strings + | &(STRING|FSTRING_START) strings + | &TAGSTRING_START tagstring | NUMBER | &'(' (tuple | group | genexp) | &'[' (list | listcomp) @@ -898,7 +899,7 @@ tagstring[expr_ty]: | a=TAGSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_tag_str(p, a, (asdl_expr_seq*)b, c) } string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) } -strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|tagstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) } +strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) } list[expr_ty]: | '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) } diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index d62ac6f435f8e7..3ec18c8707fb60 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1580,7 +1580,6 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, assert(len > 0); int f_string_found = 0; - int tag_string_found = 0; // TODO: Do this in the grammar instead int unicode_string_found = 0; int bytes_found = 0; @@ -1595,8 +1594,6 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, unicode_string_found = 1; } n_flattened_elements++; - } else if (elem->kind == TagString_kind) { - tag_string_found = 1; } else { assert(elem->kind == JoinedStr_kind); n_flattened_elements += asdl_seq_LEN(elem->v.JoinedStr.values); @@ -1609,11 +1606,6 @@ _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, return NULL; } - if (tag_string_found && len > 1) { - RAISE_SYNTAX_ERROR("tag string cannot be joined"); - return NULL; - } - if (bytes_found) { PyObject* res = PyBytes_FromString(""); diff --git a/Parser/parser.c b/Parser/parser.c index b590f687aa0547..05b6c9a82e113f 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -14233,7 +14233,8 @@ slice_rule(Parser *p) // | 'True' // | 'False' // | 'None' -// | &(STRING | FSTRING_START | TAGSTRING_START) strings +// | &(STRING | FSTRING_START) strings +// | &TAGSTRING_START tagstring // | NUMBER // | &'(' (tuple | group | genexp) // | &'[' (list | listcomp) @@ -14379,12 +14380,12 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } - { // &(STRING | FSTRING_START | TAGSTRING_START) strings + { // &(STRING | FSTRING_START) strings if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START | TAGSTRING_START) strings")); + D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); expr_ty strings_var; if ( _PyPegen_lookahead(1, _tmp_92_rule, p) @@ -14392,13 +14393,34 @@ atom_rule(Parser *p) (strings_var = strings_rule(p)) // strings ) { - D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START | TAGSTRING_START) strings")); + D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); _res = strings_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&(STRING | FSTRING_START | TAGSTRING_START) strings")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&(STRING | FSTRING_START) strings")); + } + { // &TAGSTRING_START tagstring + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&TAGSTRING_START tagstring")); + expr_ty tagstring_var; + if ( + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, TAGSTRING_START) // token=TAGSTRING_START + && + (tagstring_var = tagstring_rule(p)) // tagstring + ) + { + D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&TAGSTRING_START tagstring")); + _res = tagstring_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&TAGSTRING_START tagstring")); } { // NUMBER if (p->error_indicator) { @@ -15978,7 +16000,7 @@ string_rule(Parser *p) return _res; } -// strings: ((fstring | tagstring | string))+ +// strings: ((fstring | string))+ static expr_ty strings_rule(Parser *p) { @@ -16005,18 +16027,18 @@ strings_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // ((fstring | tagstring | string))+ + { // ((fstring | string))+ if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | tagstring | string))+")); + D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_114_rule(p)) // ((fstring | tagstring | string))+ + (a = (asdl_expr_seq*)_loop1_114_rule(p)) // ((fstring | string))+ ) { - D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | tagstring | string))+")); + D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -16036,7 +16058,7 @@ strings_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s strings[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((fstring | tagstring | string))+")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((fstring | string))+")); } _res = NULL; done: @@ -30437,7 +30459,7 @@ _tmp_91_rule(Parser *p) return _res; } -// _tmp_92: STRING | FSTRING_START | TAGSTRING_START +// _tmp_92: STRING | FSTRING_START static void * _tmp_92_rule(Parser *p) { @@ -30489,25 +30511,6 @@ _tmp_92_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START")); } - { // TAGSTRING_START - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "TAGSTRING_START")); - Token * tagstring_start_var; - if ( - (tagstring_start_var = _PyPegen_expect_token(p, TAGSTRING_START)) // token='TAGSTRING_START' - ) - { - D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "TAGSTRING_START")); - _res = tagstring_start_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "TAGSTRING_START")); - } _res = NULL; done: p->level--; @@ -31984,7 +31987,7 @@ _loop0_113_rule(Parser *p) return _seq; } -// _loop1_114: (fstring | tagstring | string) +// _loop1_114: (fstring | string) static asdl_seq * _loop1_114_rule(Parser *p) { @@ -32007,15 +32010,15 @@ _loop1_114_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // (fstring | tagstring | string) + { // (fstring | string) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | tagstring | string)")); + D(fprintf(stderr, "%*c> _loop1_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); void *_tmp_254_var; while ( - (_tmp_254_var = _tmp_254_rule(p)) // fstring | tagstring | string + (_tmp_254_var = _tmp_254_rule(p)) // fstring | string ) { _res = _tmp_254_var; @@ -32036,7 +32039,7 @@ _loop1_114_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop1_114[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | tagstring | string)")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | string)")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -40415,7 +40418,7 @@ _tmp_253_rule(Parser *p) return _res; } -// _tmp_254: fstring | tagstring | string +// _tmp_254: fstring | string static void * _tmp_254_rule(Parser *p) { @@ -40448,25 +40451,6 @@ _tmp_254_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } - { // tagstring - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tagstring")); - expr_ty tagstring_var; - if ( - (tagstring_var = tagstring_rule(p)) // tagstring - ) - { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tagstring")); - _res = tagstring_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tagstring")); - } { // string if (p->error_indicator) { p->level--; From e643734ec0b1b9c0fa4e0126b2ff503243c5c9f1 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 25 Apr 2023 11:19:32 -0600 Subject: [PATCH 0013/1206] Test errors for joined tag strings --- Lib/test/test_tag_strings.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/test/test_tag_strings.py b/Lib/test/test_tag_strings.py index 3d2834c8a42186..8429eec9aede98 100644 --- a/Lib/test/test_tag_strings.py +++ b/Lib/test/test_tag_strings.py @@ -35,6 +35,19 @@ def tag(*args): self.assertEqual(conv, "r") self.assertEqual(spec, "spec") + def test_disallow_joins(self): + examples = [ + "tag'foo' tag'bar'", + "tag'foo' 'bar'", + "tag'foo' f'bar'", + "'foo' tag'bar'", + "b'foo' tag'bar'", + "r'foo' tag'bar' rb'baz'", + ] + for ex in examples: + with self.assertRaises(SyntaxError): + compile(ex, ex, "eval") + if __name__ == "__main__": unittest.main() From c1c75ea0b5e602f60d4eafc7b2f8de40c103bdb0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 26 Apr 2023 14:28:35 -0700 Subject: [PATCH 0014/1206] Fix assert() crash in tag'{foo=}' The fix is weird: I just add the (memo) flag to tagstring. This merely avoids the problem by avoiding it. The root cause seems to be that when the tokenizer is called via the cache, last_expr_buffer isn't initialized properly. --- Grammar/python.gram | 2 +- Lib/test/test_tag_strings.py | 13 +++++++++++++ Parser/parser.c | 5 +++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Grammar/python.gram b/Grammar/python.gram index 5337899a7c22ce..436033763c0401 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -895,7 +895,7 @@ fstring_format_spec[expr_ty]: | fstring_replacement_field fstring[expr_ty]: | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } -tagstring[expr_ty]: +tagstring[expr_ty] (memo): | a=TAGSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_tag_str(p, a, (asdl_expr_seq*)b, c) } string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) } diff --git a/Lib/test/test_tag_strings.py b/Lib/test/test_tag_strings.py index 8429eec9aede98..0d581b8d278ff1 100644 --- a/Lib/test/test_tag_strings.py +++ b/Lib/test/test_tag_strings.py @@ -48,6 +48,19 @@ def test_disallow_joins(self): with self.assertRaises(SyntaxError): compile(ex, ex, "eval") + def test_debug_format(self): + def tag(*args): + return args + res = tag"{ham = }" + self.assertEqual(len(res), 2) + self.assertEqual(res[0], "ham = ") + func, string, conv, spec = res[1] + ham = 42 + self.assertEqual(func(), 42) + self.assertEqual(string, "ham") + self.assertEqual(conv, "r") + self.assertEqual(spec, None) + if __name__ == "__main__": unittest.main() diff --git a/Parser/parser.c b/Parser/parser.c index 05b6c9a82e113f..b46e76e9001c89 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -15919,6 +15919,10 @@ tagstring_rule(Parser *p) return NULL; } expr_ty _res = NULL; + if (_PyPegen_is_memoized(p, tagstring_type, &_res)) { + p->level--; + return _res; + } int _mark = p->mark; { // TAGSTRING_START fstring_middle* FSTRING_END if (p->error_indicator) { @@ -15952,6 +15956,7 @@ tagstring_rule(Parser *p) } _res = NULL; done: + _PyPegen_insert_memo(p, _mark, tagstring_type, _res); p->level--; return _res; } From f93052d4fb55e38d6f4b4cee3d599daef97ed076 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 26 Apr 2023 14:57:52 -0700 Subject: [PATCH 0015/1206] Fix behavior of `tag'\N{BLAH}'` This should treat `{BLAH}` as an interpolation. To fix this we modify `_PyPegen_joined_str()` to take an `is_raw` flag. --- Grammar/python.gram | 2 +- Lib/test/test_tag_strings.py | 13 +++++++++++++ Parser/action_helpers.c | 6 +++--- Parser/parser.c | 2 +- Parser/pegen.h | 2 +- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Grammar/python.gram b/Grammar/python.gram index 436033763c0401..1ab4fef48aac8b 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -894,7 +894,7 @@ fstring_format_spec[expr_ty]: | t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) } | fstring_replacement_field fstring[expr_ty]: - | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } + | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, 0, a, (asdl_expr_seq*)b, c) } tagstring[expr_ty] (memo): | a=TAGSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_tag_str(p, a, (asdl_expr_seq*)b, c) } diff --git a/Lib/test/test_tag_strings.py b/Lib/test/test_tag_strings.py index 0d581b8d278ff1..362cc028b6ce9d 100644 --- a/Lib/test/test_tag_strings.py +++ b/Lib/test/test_tag_strings.py @@ -61,6 +61,19 @@ def tag(*args): self.assertEqual(conv, "r") self.assertEqual(spec, None) + def test_unicode_names(self): + def tag(*args): + return args + res = tag"\N{SPACE}" + self.assertEqual(len(res), 2) + self.assertEqual(res[0], r"\N") + func, string, conv, spec = res[1] + SPACE = 42 + self.assertEqual(func(), 42) + self.assertEqual(string, "SPACE") + self.assertEqual(conv, None) + self.assertEqual(spec, None) + if __name__ == "__main__": unittest.main() diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 3ec18c8707fb60..4fa720f0cc56f6 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1290,7 +1290,7 @@ unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions) } expr_ty -_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { +_PyPegen_joined_str(Parser *p, int is_raw, Token* a, asdl_expr_seq* raw_expressions, Token*b) { asdl_expr_seq *expr = unpack_top_level_joined_strs(p, raw_expressions); Py_ssize_t n_items = asdl_seq_LEN(expr); @@ -1298,7 +1298,7 @@ _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b if (quote_str == NULL) { return NULL; } - int is_raw = strpbrk(quote_str, "rR") != NULL; + is_raw = is_raw || strpbrk(quote_str, "rR") != NULL; asdl_expr_seq *seq = _Py_asdl_expr_seq_new(n_items, p->arena); if (seq == NULL) { @@ -1393,7 +1393,7 @@ _PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { if (tag == NULL) { return NULL; } - expr_ty str = _PyPegen_joined_str(p, a, raw_expressions, b); + expr_ty str = _PyPegen_joined_str(p, 1, a, raw_expressions, b); if (str == NULL) { return NULL; } diff --git a/Parser/parser.c b/Parser/parser.c index b46e76e9001c89..0ae22f10c37a78 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -1341,7 +1341,7 @@ fstring_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ fstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); - _res = _PyPegen_joined_str ( p , a , ( asdl_expr_seq* ) b , c ); + _res = _PyPegen_joined_str ( p , 0 , a , ( asdl_expr_seq* ) b , c ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; diff --git a/Parser/pegen.h b/Parser/pegen.h index 7f39e545ec4ebb..78498d2dbe2b0d 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -346,7 +346,7 @@ mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompiler asdl_stmt_seq *_PyPegen_interactive_exit(Parser *); // TODO: move to the correct place in this file -expr_ty _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b); +expr_ty _PyPegen_joined_str(Parser *p, int is_raw, Token* a, asdl_expr_seq* expr, Token*b); expr_ty _PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b); // Generated function in parse.c - function definition in python.gram From e37d679a7970573052c468931c7e4ea96159b5d2 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 26 Apr 2023 18:26:59 -0700 Subject: [PATCH 0016/1206] Fix 3.5 out of four failing tests There are still errors in test_fstring.py, but these are not so easy to track down. It seems that if there is a syntax error involving mismatched braces in an f-string interpolation, the parser backtracks and the tokenizer produces TAGSTRING_START instead of FSTRING_START, and other state is not initialized properly. I'll have to involve Pablo in debugging that. --- Lib/test/test_exceptions.py | 2 +- Lib/test/test_fstring.py | 2 +- Lib/test/test_string_literals.py | 20 ++++++++++---------- Lib/test/test_tokenize.py | 5 +++-- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 4ef7decfbc263e..1b02c94efb561b 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -272,7 +272,7 @@ def bar(): def baz(): '''quux''' - """, 9, 24) + """, 9, 20) check("pass\npass\npass\n(1+)\npass\npass\npass", 4, 4) check("(1+)", 1, 4) check("[interesting\nfoo()\n", 1, 1) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 9d5e16628f04b6..058a3aac6d895f 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1141,7 +1141,7 @@ def test_invalid_string_prefixes(self): "Bf''", "BF''",] double_quote_cases = [case.replace("'", '"') for case in single_quote_cases] - self.assertAllRaise(SyntaxError, 'invalid syntax', + self.assertAllRaise(NameError, 'is not defined', single_quote_cases + double_quote_cases) def test_leading_trailing_spaces(self): diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py index 9b663c00223d1b..d03e913294ecc2 100644 --- a/Lib/test/test_string_literals.py +++ b/Lib/test/test_string_literals.py @@ -250,21 +250,21 @@ def test_eval_bytes_raw(self): self.assertEqual(eval(r""" rb'\U0001d120' """), b"\\" + b"U0001d120") self.assertRaises(SyntaxError, eval, """ br'\U0001d120' """) self.assertRaises(SyntaxError, eval, """ rb'\U0001d120' """) - self.assertRaises(SyntaxError, eval, """ bb'' """) - self.assertRaises(SyntaxError, eval, """ rr'' """) - self.assertRaises(SyntaxError, eval, """ brr'' """) - self.assertRaises(SyntaxError, eval, """ bbr'' """) - self.assertRaises(SyntaxError, eval, """ rrb'' """) - self.assertRaises(SyntaxError, eval, """ rbb'' """) + self.assertRaises(NameError, eval, """ bb'' """) + self.assertRaises(NameError, eval, """ rr'' """) + self.assertRaises(NameError, eval, """ brr'' """) + self.assertRaises(NameError, eval, """ bbr'' """) + self.assertRaises(NameError, eval, """ rrb'' """) + self.assertRaises(NameError, eval, """ rbb'' """) def test_eval_str_u(self): self.assertEqual(eval(""" u'x' """), 'x') self.assertEqual(eval(""" U'\u00e4' """), 'ä') self.assertEqual(eval(""" u'\N{LATIN SMALL LETTER A WITH DIAERESIS}' """), 'ä') - self.assertRaises(SyntaxError, eval, """ ur'' """) - self.assertRaises(SyntaxError, eval, """ ru'' """) - self.assertRaises(SyntaxError, eval, """ bu'' """) - self.assertRaises(SyntaxError, eval, """ ub'' """) + self.assertRaises(NameError, eval, """ ur'' """) + self.assertRaises(NameError, eval, """ ru'' """) + self.assertRaises(NameError, eval, """ bu'' """) + self.assertRaises(NameError, eval, """ ub'' """) def test_uppercase_prefixes(self): self.assertEqual(eval(""" B'x' """), b'x') diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 283a7c23609e67..e60563de11b558 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1806,8 +1806,9 @@ def test_string(self): NAME 'x' (1, 0) (1, 1) EQUAL '=' (1, 2) (1, 3) STRING '"doesn\\'t "' (1, 4) (1, 14) - NAME 'shrink' (1, 14) (1, 20) - STRING '", does it"' (1, 20) (1, 31) + TAGSTRING_START \'shrink"\' (1, 14) (1, 21) + FSTRING_MIDDLE ', does it' (1, 21) (1, 30) + FSTRING_END \'"\' (1, 30) (1, 31) """) self.check_tokenize("x = 'abc' + 'ABC'", """\ From c2b127ed3ab44d404c502bd2f8f279253fd081e6 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Mon, 22 May 2023 21:11:08 +0200 Subject: [PATCH 0017/1206] Post 3.12.0b1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 3de9ed9296a47b..d71bef922e5b2a 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.12.0b1" +#define PY_VERSION "3.12.0b1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 97f85479131ad34daa3bc50e33c471fb2fe6c056 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 22 May 2023 16:20:05 -0700 Subject: [PATCH 0018/1206] [3.12] Add the 3.12 branch to the github workflows. (GH-104768) (#104769) Add the 3.12 branch to the github workflows. (GH-104768) (cherry picked from commit 4194d8f2c40f478eb0fc9b6fa9b913baaff229da) Co-authored-by: T. Wouters --- .github/workflows/build.yml | 2 ++ .github/workflows/doc.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 41abddffa5d648..b9797192dba054 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,7 @@ on: push: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' @@ -16,6 +17,7 @@ on: pull_request: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 3f7550cc72943b..ec900ce68a1dde 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -5,6 +5,7 @@ on: #push: # branches: # - 'main' + # - '3.12' # - '3.11' # - '3.10' # - '3.9' @@ -15,6 +16,7 @@ on: pull_request: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' From b44beac5e101bb68898aa1bf4ccfc37f6f168050 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 23 May 2023 10:56:14 +0200 Subject: [PATCH 0019/1206] [3.12] gh-87891: Add ABI check to CI (#104793) Backport the workflow change and fix-ups: - GH-92442 (e89c01eac7731d7cb54d43252dbc3d3f3a040c53) - GH-94129 (0dadb2249a8bafa7c5877daa08c9452f2248958a) - GH-98556 (194588decc05fa12f04cd90c3b78cc081151b19e) Co-Authored-By: sterliakov <50529348+sterliakov@users.noreply.github.com> Co-authored-by: Hugo van Kemenade Co-authored-by: Pablo Galindo Salgado --- .github/workflows/build.yml | 30 + .gitignore | 3 - Doc/data/python3.12.abi | 26411 ++++++++++++++++++++++++++++++++++ 3 files changed, 26441 insertions(+), 3 deletions(-) create mode 100644 Doc/data/python3.12.abi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9797192dba054..68bebb6bf61d03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,6 +75,36 @@ jobs: echo "run_hypothesis=true" >> $GITHUB_OUTPUT fi + check_abi: + name: 'Check if the ABI has changed' + runs-on: ubuntu-22.04 + needs: check_source + if: needs.check_source.outputs.run_tests == 'true' + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + - name: Install dependencies + run: | + sudo ./.github/workflows/posix-deps-apt.sh + sudo apt-get install -yq abigail-tools + - name: Build CPython + env: + CFLAGS: -g3 -O0 + run: | + # Build Python with the libpython dynamic library + ./configure --enable-shared + make -j4 + - name: Check for changes in the ABI + run: | + if ! make check-abidump; then + echo "Generated ABI file is not up to date." + echo "Please add the release manager of this branch as a reviewer of this PR." + echo "" + echo "To learn more about this check: https://devguide.python.org/setup/#regenerate-the-abi-dump" + echo "" + exit 1 + fi + check_generated_files: name: 'Check if generated files are up to date' runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index ef7642b09bc5d2..bde596a7a0298b 100644 --- a/.gitignore +++ b/.gitignore @@ -156,6 +156,3 @@ Python/frozen_modules/MANIFEST # Ignore ./python binary on Unix but still look into ./Python/ directory. /python !/Python/ - -# main branch only: ABI files are not checked/maintained -Doc/data/python*.abi diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi new file mode 100644 index 00000000000000..79bf7ea6df829e --- /dev/null +++ b/Doc/data/python3.12.abi @@ -0,0 +1,26411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 25b5ce72c9b1c31d5d23b4dcaacafc07690e73e1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 May 2023 01:57:52 -0700 Subject: [PATCH 0020/1206] [3.12] howto/urllib2: remove link to an outdated french translation (GH-104193) (#104758) We now have our own translation and it's not outdated (cherry picked from commit 151b6bfb5d9a15b6e2682e5a3008a3f9ec3086ae) Co-authored-by: Mathieu Dupuy --- Doc/howto/urllib2.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 61ba6bd7224fcc..86137fb38c9b93 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -6,13 +6,6 @@ :Author: `Michael Foord `_ -.. note:: - - There is a French translation of an earlier revision of this - HOWTO, available at `urllib2 - Le Manuel manquant - `_. - - Introduction ============ From 905d419cac0e2617ee07c8a478e132793878a875 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 May 2023 02:24:28 -0700 Subject: [PATCH 0021/1206] [3.12] GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104760) GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104674) (cherry picked from commit 357bed0bcd3c5d7c4a8caad451754a9a172aca3e) Co-authored-by: Brandt Bucher --- Doc/c-api/veryhigh.rst | 8 +++++ Doc/whatsnew/3.12.rst | 9 ++++++ ...-05-19-10-22-34.gh-issue-104668.MLX1g9.rst | 5 +++ Parser/myreadline.c | 32 +++++++++++++++---- 4 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 513856d8a48d70..000a2d3d8790bb 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -167,6 +167,10 @@ the same library that the Python runtime is using. event loops, as done in the :file:`Modules/_tkinter.c` in the Python source code. + .. versionchanged:: 3.12 + This function is only called from the + :ref:`main interpreter `. + .. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *) @@ -187,6 +191,10 @@ the same library that the Python runtime is using. :c:func:`PyMem_RawRealloc`, instead of being allocated by :c:func:`PyMem_Malloc` or :c:func:`PyMem_Realloc`. + .. versionchanged:: 3.12 + This function is only called from the + :ref:`main interpreter `. + .. c:function:: PyObject* PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) This is a simplified interface to :c:func:`PyRun_StringFlags` below, leaving diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index efbd2ca3de122a..4ff90664bb790b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1476,6 +1476,15 @@ Porting to Python 3.12 Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12) already disallows creating classes whose metaclass overrides ``tp_new``. +* :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no + longer called in :ref:`subinterpreters `. This is + because clients generally rely on process-wide global state (since these + callbacks have no way of recovering extension module state). + + This also avoids situations where extensions may find themselves running in a + subinterpreter that they don't support (or haven't yet been loaded in). See + :gh:`104668` for more info. + Deprecated ---------- diff --git a/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst b/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst new file mode 100644 index 00000000000000..7b882afd7f81a0 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst @@ -0,0 +1,5 @@ +Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer` +in subinterpreters, since it's generally difficult to avoid using global +state in their registered callbacks. This also avoids situations where +extensions may find themselves running in a subinterpreter they don't +support (or haven't yet been loaded in). diff --git a/Parser/myreadline.c b/Parser/myreadline.c index 3f0e29f051a438..7074aba74b728c 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -45,7 +45,10 @@ my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp) #endif while (1) { - if (PyOS_InputHook != NULL) { + if (PyOS_InputHook != NULL && + // GH-104668: See PyOS_ReadlineFunctionPointer's comment below... + _Py_IsMainInterpreter(tstate->interp)) + { (void)(PyOS_InputHook)(); } @@ -131,7 +134,10 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn) wbuf = wbuf_local; wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1; while (1) { - if (PyOS_InputHook != NULL) { + if (PyOS_InputHook != NULL && + // GH-104668: See PyOS_ReadlineFunctionPointer's comment below... + _Py_IsMainInterpreter(tstate->interp)) + { (void)(PyOS_InputHook)(); } if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) { @@ -389,11 +395,23 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) * a tty. This can happen, for example if python is run like * this: python -i < test1.py */ - if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout))) - rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt); - else - rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, - prompt); + if (!isatty(fileno(sys_stdin)) || !isatty(fileno(sys_stdout)) || + // GH-104668: Don't call global callbacks like PyOS_InputHook or + // PyOS_ReadlineFunctionPointer from subinterpreters, since it seems + // like there's no good way for users (like readline and tkinter) to + // avoid using global state to manage them. Plus, we generally don't + // want to cause trouble for libraries that don't know/care about + // subinterpreter support. If libraries really need better APIs that + // work per-interpreter and have ways to access module state, we can + // certainly add them later (but for now we'll cross our fingers and + // hope that nobody actually cares): + !_Py_IsMainInterpreter(tstate->interp)) + { + rv = PyOS_StdioReadline(sys_stdin, sys_stdout, prompt); + } + else { + rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt); + } Py_END_ALLOW_THREADS PyThread_release_lock(_PyOS_ReadlineLock); From e43fbbd92884ad167cdaea296526c671f593b234 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 May 2023 02:28:04 -0700 Subject: [PATCH 0022/1206] [3.12] GH-101291: Avoid using macros with casts in low-level long API. (GH-104742) (#104759) (cherry picked from commit e295d8605699ad3d8ec46c8d55a5e47da05b20c6) Co-authored-by: Mark Shannon --- Include/cpython/longintrepr.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 0f569935fff14a..692c69ba76db2f 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -104,9 +104,10 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits); #define _PyLong_SIGN_MASK 3 #define _PyLong_NON_SIZE_BITS 3 + static inline int _PyLong_IsCompact(const PyLongObject* op) { - assert(PyLong_Check(op)); + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); return op->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS); } @@ -115,7 +116,7 @@ _PyLong_IsCompact(const PyLongObject* op) { static inline Py_ssize_t _PyLong_CompactValue(const PyLongObject *op) { - assert(PyLong_Check(op)); + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); assert(PyUnstable_Long_IsCompact(op)); Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); return sign * (Py_ssize_t)op->long_value.ob_digit[0]; From 9aea1f28e2d22dd8650f6153eb5630ffd250d3c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 May 2023 04:24:02 -0700 Subject: [PATCH 0023/1206] [3.12] gh-99108: Release the GIL around hashlib built-in computation (GH-104675) (#104776) gh-99108: Release the GIL around hashlib built-in computation (GH-104675) This matches the GIL releasing behavior of our existing `_hashopenssl` module, extending it to the HACL* built-ins. Includes adding comments to better describe the ENTER/LEAVE macros purpose and explain the lock strategy in both existing and new code. (cherry picked from commit 2e5d8a90aa633ff0bebc9b2b8e21eea389937b19) Co-authored-by: Gregory P. Smith [Google] --- ...3-05-19-19-46-22.gh-issue-99108.wqCg0t.rst | 3 + Modules/_hashopenssl.c | 6 ++ Modules/hashlib.h | 9 +- Modules/md5module.c | 37 +++++++- Modules/sha1module.c | 37 +++++++- Modules/sha2module.c | 94 +++++++++++++++++-- Modules/sha3module.c | 36 ++++++- 7 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst diff --git a/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst b/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst new file mode 100644 index 00000000000000..b595f1893609cc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst @@ -0,0 +1,3 @@ +We now release the GIL around built-in :mod:`hashlib` computations of +reasonable size for the SHA families and MD5 hash functions, matching +what our OpenSSL backed hash computations already does. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 99d0b72819137e..4b425f4147513e 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -227,12 +227,16 @@ get_hashlib_state(PyObject *module) typedef struct { PyObject_HEAD EVP_MD_CTX *ctx; /* OpenSSL message digest context */ + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. PyThread_type_lock lock; /* OpenSSL context lock */ } EVPobject; typedef struct { PyObject_HEAD HMAC_CTX *ctx; /* OpenSSL hmac context */ + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. PyThread_type_lock lock; /* HMAC context lock */ } HMACobject; @@ -896,6 +900,8 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj, if (view.buf && view.len) { if (view.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ Py_BEGIN_ALLOW_THREADS result = EVP_hash(self, view.buf, view.len); Py_END_ALLOW_THREADS diff --git a/Modules/hashlib.h b/Modules/hashlib.h index 56ae7a5e50bf58..a8bad9dd87a939 100644 --- a/Modules/hashlib.h +++ b/Modules/hashlib.h @@ -37,6 +37,13 @@ * LEAVE_HASHLIB block or explicitly acquire and release the lock inside * a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for * an operation. + * + * These only drop the GIL if the lock acquisition itself is likely to + * block. Thus the non-blocking acquire gating the GIL release for a + * blocking lock acquisition. The intent of these macros is to surround + * the assumed always "fast" operations that you aren't releasing the + * GIL around. Otherwise use code similar to what you see in hash + * function update() methods. */ #include "pythread.h" @@ -53,7 +60,7 @@ PyThread_release_lock((obj)->lock); \ } -/* TODO(gps): We should probably make this a module or EVPobject attribute +/* TODO(gpshead): We should make this a module or class attribute * to allow the user to optimize based on the platform they're using. */ #define HASHLIB_GIL_MINSIZE 2048 diff --git a/Modules/md5module.c b/Modules/md5module.c index 86605771d9643f..2122f8b18baf6e 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -49,7 +49,9 @@ typedef long long MD5_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD - + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_MD5_state *hash_state; } MD5object; @@ -72,6 +74,7 @@ static MD5object * newMD5object(MD5State * st) { MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type); + md5->lock = NULL; PyObject_GC_Track(md5); return md5; } @@ -88,6 +91,9 @@ static void MD5_dealloc(MD5object *ptr) { Hacl_Streaming_MD5_legacy_free(ptr->hash_state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -115,7 +121,9 @@ MD5Type_copy_impl(MD5object *self, PyTypeObject *cls) if ((newobj = newMD5object(st))==NULL) return NULL; + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_MD5_legacy_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -130,7 +138,9 @@ MD5Type_digest_impl(MD5object *self) /*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/ { unsigned char digest[MD5_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE); } @@ -145,7 +155,9 @@ MD5Type_hexdigest_impl(MD5object *self) /*[clinic end generated code: output=17badced1f3ac932 input=b60b19de644798dd]*/ { unsigned char digest[MD5_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char*)digest, MD5_DIGESTSIZE); } @@ -177,7 +189,18 @@ MD5Type_update(MD5object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -279,7 +302,15 @@ _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update(new->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update(new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update(new->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha1module.c b/Modules/sha1module.c index bdb76c56f1a6e8..c66269b5f5cdf3 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -48,7 +48,9 @@ typedef long long SHA1_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD - + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA1_state *hash_state; } SHA1object; @@ -71,6 +73,7 @@ static SHA1object * newSHA1object(SHA1State *st) { SHA1object *sha = (SHA1object *)PyObject_GC_New(SHA1object, st->sha1_type); + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -88,6 +91,9 @@ static void SHA1_dealloc(SHA1object *ptr) { Hacl_Streaming_SHA1_legacy_free(ptr->hash_state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -115,7 +121,9 @@ SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls) if ((newobj = newSHA1object(st)) == NULL) return NULL; + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_SHA1_legacy_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -130,7 +138,9 @@ SHA1Type_digest_impl(SHA1object *self) /*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/ { unsigned char digest[SHA1_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, SHA1_DIGESTSIZE); } @@ -145,7 +155,9 @@ SHA1Type_hexdigest_impl(SHA1object *self) /*[clinic end generated code: output=4161fd71e68c6659 input=97691055c0c74ab0]*/ { unsigned char digest[SHA1_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, SHA1_DIGESTSIZE); } @@ -177,7 +189,18 @@ SHA1Type_update(SHA1object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -279,7 +302,15 @@ _sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update(new->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update(new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update(new->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 37d9b5c538fd0b..6c7c3917198d18 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -52,12 +52,18 @@ class SHA512Type "SHA512object *" "&PyType_Type" typedef struct { PyObject_HEAD int digestsize; + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA2_state_sha2_256 *state; } SHA256object; typedef struct { PyObject_HEAD int digestsize; + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA2_state_sha2_512 *state; } SHA512object; @@ -100,6 +106,7 @@ newSHA224object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -112,6 +119,7 @@ newSHA256object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -124,6 +132,7 @@ newSHA384object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -136,6 +145,7 @@ newSHA512object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -153,6 +163,9 @@ static void SHA256_dealloc(SHA256object *ptr) { Hacl_Streaming_SHA2_free_256(ptr->state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -163,6 +176,9 @@ static void SHA512_dealloc(SHA512object *ptr) { Hacl_Streaming_SHA2_free_512(ptr->state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -229,7 +245,9 @@ SHA256Type_copy_impl(SHA256object *self, PyTypeObject *cls) } } + ENTER_HASHLIB(self); SHA256copy(self, newobj); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -259,7 +277,9 @@ SHA512Type_copy_impl(SHA512object *self, PyTypeObject *cls) } } + ENTER_HASHLIB(self); SHA512copy(self, newobj); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -275,9 +295,11 @@ SHA256Type_digest_impl(SHA256object *self) { uint8_t digest[SHA256_DIGESTSIZE]; assert(self->digestsize <= SHA256_DIGESTSIZE); + ENTER_HASHLIB(self); // HACL* performs copies under the hood so that self->state remains valid // after this call. Hacl_Streaming_SHA2_finish_256(self->state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, self->digestsize); } @@ -293,9 +315,11 @@ SHA512Type_digest_impl(SHA512object *self) { uint8_t digest[SHA512_DIGESTSIZE]; assert(self->digestsize <= SHA512_DIGESTSIZE); + ENTER_HASHLIB(self); // HACL* performs copies under the hood so that self->state remains valid // after this call. Hacl_Streaming_SHA2_finish_512(self->state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, self->digestsize); } @@ -311,7 +335,9 @@ SHA256Type_hexdigest_impl(SHA256object *self) { uint8_t digest[SHA256_DIGESTSIZE]; assert(self->digestsize <= SHA256_DIGESTSIZE); + ENTER_HASHLIB(self); Hacl_Streaming_SHA2_finish_256(self->state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, self->digestsize); } @@ -327,7 +353,9 @@ SHA512Type_hexdigest_impl(SHA512object *self) { uint8_t digest[SHA512_DIGESTSIZE]; assert(self->digestsize <= SHA512_DIGESTSIZE); + ENTER_HASHLIB(self); Hacl_Streaming_SHA2_finish_512(self->state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, self->digestsize); } @@ -348,7 +376,18 @@ SHA256Type_update(SHA256object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update_256(self->state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update_256(self->state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update_256(self->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -371,7 +410,18 @@ SHA512Type_update(SHA512object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update_512(self->state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update_512(self->state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update_512(self->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -560,7 +610,15 @@ _sha2_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_256(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_256(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_256(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -606,7 +664,15 @@ _sha2_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_256(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_256(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_256(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -651,7 +717,15 @@ _sha2_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_512(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_512(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_512(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -696,7 +770,15 @@ _sha2_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_512(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_512(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_512(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha3module.c b/Modules/sha3module.c index f05187498a19b3..558d2005cff617 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -60,6 +60,9 @@ class _sha3.shake_256 "SHA3object *" "&SHAKE256type" typedef struct { PyObject_HEAD + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_Keccak_state *hash_state; } SHA3object; @@ -73,6 +76,7 @@ newSHA3object(PyTypeObject *type) if (newobj == NULL) { return NULL; } + newobj->lock = NULL; return newobj; } @@ -133,7 +137,15 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity) if (data) { GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error); - sha3_update(self->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + sha3_update(self->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + sha3_update(self->hash_state, buf.buf, buf.len); + } } PyBuffer_Release(&buf); @@ -157,6 +169,9 @@ static void SHA3_dealloc(SHA3object *self) { Hacl_Streaming_Keccak_free(self->hash_state); + if (self->lock != NULL) { + PyThread_free_lock(self->lock); + } PyTypeObject *tp = Py_TYPE(self); PyObject_Free(self); Py_DECREF(tp); @@ -181,7 +196,9 @@ _sha3_sha3_224_copy_impl(SHA3object *self) if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) { return NULL; } + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_Keccak_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -199,7 +216,9 @@ _sha3_sha3_224_digest_impl(SHA3object *self) unsigned char digest[SHA3_MAX_DIGESTSIZE]; // This function errors out if the algorithm is Shake. Here, we know this // not to be the case, and therefore do not perform error checking. + ENTER_HASHLIB(self); Hacl_Streaming_Keccak_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -216,7 +235,9 @@ _sha3_sha3_224_hexdigest_impl(SHA3object *self) /*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/ { unsigned char digest[SHA3_MAX_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_Keccak_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -237,7 +258,18 @@ _sha3_sha3_224_update(SHA3object *self, PyObject *data) { Py_buffer buf; GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - sha3_update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + sha3_update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + sha3_update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; } From f4e2049f14d40c1b893c68530eec5e341cf3d929 Mon Sep 17 00:00:00 2001 From: Itamar Ostricher Date: Tue, 23 May 2023 11:11:35 -0700 Subject: [PATCH 0024/1206] [3.12] gh-104271: Fix auto() fallback in case of mixed type Enum (GH-104279) gh-104271: Fix auto() fallback in case of mixed type Enum --- Lib/enum.py | 2 +- Lib/test/test_enum.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py index 6e497f7ef6a7de..bb71c84bd46373 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1185,7 +1185,7 @@ def _generate_next_value_(name, start, count, last_values): DeprecationWarning, stacklevel=3, ) - for v in last_values: + for v in reversed(last_values): try: return v + 1 except TypeError: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index fb7a016c9007f8..98010d18c0adb2 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4254,11 +4254,14 @@ class Color(Enum): red = 'red' blue = 2 green = auto() + yellow = auto() - self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(list(Color), + [Color.red, Color.blue, Color.green, Color.yellow]) self.assertEqual(Color.red.value, 'red') self.assertEqual(Color.blue.value, 2) self.assertEqual(Color.green.value, 3) + self.assertEqual(Color.yellow.value, 4) @unittest.skipIf( python_version < (3, 13), From 5c8418c5cc6737cd40df448eff80d2297f68e1a5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 May 2023 13:04:44 -0700 Subject: [PATCH 0025/1206] [3.12] Remove gh-103207 changelog item as it was never part of any release. (GH-104815) (cherry picked from commit 08b4eb83aadcbdb389b5970b51cac9be95146c2a) Co-authored-by: Ned Deily --- Misc/NEWS.d/3.12.0b1.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index eb42b45726f5ed..a1ea082b3a2119 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -2236,16 +2236,6 @@ update curses textbox to additionally handle backspace using the .. -.. date: 2023-04-04-13-37-28 -.. gh-issue: 103207 -.. nonce: x0vvQp -.. section: macOS - -Add instructions to the macOS installer welcome display on how to workaround -the macOS 13 Ventura “The installer encountered an error†failure. - -.. - .. date: 2023-03-24-11-20-47 .. gh-issue: 102997 .. nonce: ZgQkbq From 22c45c49bbdc480ce221fc11ddf488b41c0d9c60 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 May 2023 15:34:50 -0700 Subject: [PATCH 0026/1206] [3.12] gh-103295: fix stack overwrite on 32-bit in perf map test harness (GH-104811) (#104823) gh-103295: fix stack overwrite on 32-bit in perf map test harness (GH-104811) (cherry picked from commit e0b3078705b271ff278dfbc788c2b061c92a9aa3) Co-authored-by: Carl Meyer --- Modules/_testinternalcapi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b91f7b620fdb4e..8267dbf6779017 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -762,19 +762,24 @@ clear_extension(PyObject *self, PyObject *args) static PyObject * write_perf_map_entry(PyObject *self, PyObject *args) { + PyObject *code_addr_v; const void *code_addr; unsigned int code_size; const char *entry_name; - if (!PyArg_ParseTuple(args, "KIs", &code_addr, &code_size, &entry_name)) + if (!PyArg_ParseTuple(args, "OIs", &code_addr_v, &code_size, &entry_name)) return NULL; + code_addr = PyLong_AsVoidPtr(code_addr_v); + if (code_addr == NULL) { + return NULL; + } int ret = PyUnstable_WritePerfMapEntry(code_addr, code_size, entry_name); - if (ret == -1) { - PyErr_SetString(PyExc_OSError, "Failed to write performance map entry"); + if (ret < 0) { + PyErr_SetFromErrno(PyExc_OSError); return NULL; } - return Py_BuildValue("i", ret); + return PyLong_FromLong(ret); } static PyObject * From b719dd8725a820a1af4b76c30ae87c23d8db68c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 23 May 2023 21:40:21 -0700 Subject: [PATCH 0027/1206] [3.12] gh-104372: use == -1 before PyErr_Occurred (GH-104831) (#104833) gh-104372: use == -1 before PyErr_Occurred (GH-104831) The ideal pattern for this. (already in the 3.11 backport) (cherry picked from commit 7f963bfc79a515dc9822ebddbfb1b5927d2dda09) Co-authored-by: Gregory P. Smith --- Modules/_posixsubprocess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 1b7fe71186a163..63403795569a78 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -200,7 +200,7 @@ convert_fds_to_keep_to_c(PyObject *py_fds_to_keep, int *c_fds_to_keep) for (i = 0; i < len; ++i) { PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i); long fd = PyLong_AsLong(fdobj); - if (PyErr_Occurred()) { + if (fd == -1 && PyErr_Occurred()) { return -1; } if (fd < 0 || fd > INT_MAX) { From d10d1e3b10737a8426f92221e2788e40ad05b4e0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 02:05:34 -0700 Subject: [PATCH 0028/1206] [3.12] gh-104797: Allow Protocols to inherit from collections.abc.Buffer (GH-104827) (#104841) gh-104797: Allow Protocols to inherit from collections.abc.Buffer (GH-104827) (cherry picked from commit c0ab7d401c736c37bf4462eef7c7d69fef8fab93) Co-authored-by: Jelle Zijlstra --- Lib/test/test_typing.py | 16 ++++++++++++++++ Lib/typing.py | 2 +- ...023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 9a3e64289ee877..a3fad6f35e7136 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3546,6 +3546,22 @@ def close(self): self.assertIsSubclass(B, Custom) self.assertNotIsSubclass(A, Custom) + @runtime_checkable + class ReleasableBuffer(collections.abc.Buffer, Protocol): + def __release_buffer__(self, mv: memoryview) -> None: ... + + class C: pass + class D: + def __buffer__(self, flags: int) -> memoryview: + return memoryview(b'') + def __release_buffer__(self, mv: memoryview) -> None: + pass + + self.assertIsSubclass(D, ReleasableBuffer) + self.assertIsInstance(D(), ReleasableBuffer) + self.assertNotIsSubclass(C, ReleasableBuffer) + self.assertNotIsInstance(C(), ReleasableBuffer) + def test_builtin_protocol_allowlist(self): with self.assertRaises(TypeError): class CustomProtocol(TestCase, Protocol): diff --git a/Lib/typing.py b/Lib/typing.py index 96393d6a02815b..88837db4b744ab 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1745,7 +1745,7 @@ def _allow_reckless_class_checks(depth=3): _PROTO_ALLOWLIST = { 'collections.abc': [ 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', ], 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], } diff --git a/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst b/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst new file mode 100644 index 00000000000000..60c9a0601cdc9a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst @@ -0,0 +1,2 @@ +Allow :class:`typing.Protocol` classes to inherit from +:class:`collections.abc.Buffer`. Patch by Jelle Zijlstra. From a5c0ef87a1c7b08d9c7407a705b3751d9e0b3638 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 03:00:34 -0700 Subject: [PATCH 0029/1206] [3.12] gh-102856: Add changes related to PEP 701 in 3.12 What's New docs (GH-104824) (#104847) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-102856: Add changes related to PEP 701 in 3.12 What's New docs (GH-104824) (cherry picked from commit c45701e9ef004a523ebb28f3be902b3cf2cf7a9b) Co-authored-by: Marta Gómez Macías Co-authored-by: Pablo Galindo Salgado Co-authored-by: Jelle Zijlstra --- Doc/whatsnew/3.12.rst | 151 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 135 insertions(+), 16 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4ff90664bb790b..27fbb21c33420a 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -66,6 +66,10 @@ Summary -- Release highlights .. PEP-sized items next. +New grammar features: + +* :pep:`701`: Syntactic formalization of f-strings + New typing features: * :pep:`688`: Making the buffer protocol accessible in Python @@ -136,22 +140,70 @@ Improved Error Messages New Features ============ -* Add :ref:`perf_profiling` through the new - environment variable :envvar:`PYTHONPERFSUPPORT`, - the new command-line option :option:`-X perf <-X>`, - as well as the new :func:`sys.activate_stack_trampoline`, - :func:`sys.deactivate_stack_trampoline`, - and :func:`sys.is_stack_trampoline_active` APIs. - (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes - with contributions from Gregory P. Smith [Google] and Mark Shannon - in :gh:`96123`.) -* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, - have a new a *filter* argument that allows limiting tar features than may be - surprising or dangerous, such as creating files outside the destination - directory. - See :ref:`tarfile-extraction-filter` for details. - In Python 3.14, the default will switch to ``'data'``. - (Contributed by Petr Viktorin in :pep:`706`.) +.. _whatsnew312-pep701: + +PEP 701: Syntactic formalization of f-strings +--------------------------------------------- + +:pep:`701` lifts some restrictions on the usage of f-strings. Expression components +inside f-strings can now be any valid Python expression including backslashes, +unicode escaped sequences, multi-line expressions, comments and strings reusing the +same quote as the containing f-string. Let's cover these in detail: + +* Quote reuse: in Python 3.11, reusing the same quotes as the containing f-string + raises a :exc:`SyntaxError`, forcing the user to either use other available + quotes (like using double quotes or triple quotes if the f-string uses single + quotes). In Python 3.12, you can now do things like this: + + >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism'] + >>> f"This is the playlist: {", ".join(songs)}" + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism + + Note that before this change there was no explicit limit in how f-strings can + be nested, but the fact that string quotes cannot be reused inside the + expression component of f-strings made it impossible to nest f-strings + arbitrarily. In fact, this is the most nested f-string that could be written: + + >>> f"""{f'''{f'{f"{1+1}"}'}'''}""" + '2' + + As now f-strings can contain any valid Python expression inside expression + components, it is now possible to nest f-strings arbitrarily: + + >>> f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" + '2' + +* Multi-line expressions and comments: In Python 3.11, f-strings expressions + must be defined in a single line even if outside f-strings expressions could + span multiple lines (like literal lists being defined over multiple lines), + making them harder to read. In Python 3.12 you can now define expressions + spaning multiple lines and include comments on them: + + >>> f"This is the playlist: {", ".join([ + ... 'Take me back to Eden', # My, my, those eyes like fire + ... 'Alkaline', # Not acid nor alkaline + ... 'Ascensionism' # Take to the broken skies at last + ... ])}" + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism' + +* Backslashes and unicode characters: before Python 3.12 f-string expressions + couldn't contain any ``\`` character. This also affected unicode escaped + sequences (such as ``\N{snowman}``) as these contain the ``\N`` part that + previously could not be part of expression components of f-strings. Now, you + can define expressions like this: + + >>> print(f"This is the playlist: {"\n".join(songs)}") + This is the playlist: Take me back to Eden + Alkaline + Ascensionism + >>> print(f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}") + This is the playlist: Take me back to Eden♥Alkaline♥Ascensionism + +See :pep:`701` for more details. + +(Contributed by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou, Cristián +Maureira-Fredes and Marta Gómez in :gh:`102856`. PEP written by Pablo Galindo, +Batuhan Taskaya, Lysandros Nikolaou and Marta Gómez). .. _whatsnew312-pep709: @@ -223,6 +275,24 @@ See :pep:`692` for more details. Other Language Changes ====================== +* Add :ref:`perf_profiling` through the new + environment variable :envvar:`PYTHONPERFSUPPORT`, + the new command-line option :option:`-X perf <-X>`, + as well as the new :func:`sys.activate_stack_trampoline`, + :func:`sys.deactivate_stack_trampoline`, + and :func:`sys.is_stack_trampoline_active` APIs. + (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes + with contributions from Gregory P. Smith [Google] and Mark Shannon + in :gh:`96123`.) + +* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, + have a new a *filter* argument that allows limiting tar features than may be + surprising or dangerous, such as creating files outside the destination + directory. + See :ref:`tarfile-extraction-filter` for details. + In Python 3.14, the default will switch to ``'data'``. + (Contributed by Petr Viktorin in :pep:`706`.) + * :class:`types.MappingProxyType` instances are now hashable if the underlying mapping is hashable. (Contributed by Serhiy Storchaka in :gh:`87995`.) @@ -543,6 +613,14 @@ tkinter like ``create_*()`` methods. (Contributed by Serhiy Storchaka in :gh:`94473`.) +tokenize +-------- + +* The :mod:`tokenize` module includes the changes introduced in :pep:`701`. ( + Contributed by Marta Gómez Macías and Pablo Galindo in :gh:`102856`.) + See :ref:`whatsnew312-porting-to-python312` for more information on the + changes to the :mod:`tokenize` module. + types ----- @@ -687,6 +765,11 @@ Optimizations * Speed up :class:`asyncio.Task` creation by deferring expensive string formatting. (Contributed by Itamar O in :gh:`103793`.) +* The :func:`tokenize.tokenize` and :func:`tokenize.generate_tokens` functions are + up to 64% faster as a side effect of the changes required to cover :pep:`701` in + the :mod:`tokenize` module. (Contributed by Marta Gómez Macías and Pablo Galindo + in :gh:`102856`.) + CPython bytecode changes ======================== @@ -1130,6 +1213,8 @@ Removed Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). +.. _whatsnew312-porting-to-python312: + Porting to Python 3.12 ====================== @@ -1201,6 +1286,40 @@ Changes in the Python API that may be surprising or dangerous. See :ref:`tarfile-extraction-filter` for details. +* The output of the :func:`tokenize.tokenize` and :func:`tokenize.generate_tokens` + functions is now changed due to the changes introduced in :pep:`701`. This + means that ``STRING`` tokens are not emitted any more for f-strings and the + tokens described in :pep:`701` are now produced instead: ``FSTRING_START``, + ``FSRING_MIDDLE`` and ``FSTRING_END`` are now emitted for f-string "string" + parts in addition to the appropriate tokens for the tokenization in the + expression components. For example for the f-string ``f"start {1+1} end"`` + the old version of the tokenizer emitted:: + + 1,0-1,18: STRING 'f"start {1+1} end"' + + while the new version emits:: + + 1,0-1,2: FSTRING_START 'f"' + 1,2-1,8: FSTRING_MIDDLE 'start ' + 1,8-1,9: OP '{' + 1,9-1,10: NUMBER '1' + 1,10-1,11: OP '+' + 1,11-1,12: NUMBER '1' + 1,12-1,13: OP '}' + 1,13-1,17: FSTRING_MIDDLE ' end' + 1,17-1,18: FSTRING_END '"' + + Aditionally, there may be some minor behavioral changes as a consecuence of the + changes required to support :pep:`701`. Some of these changes include: + + * Some final ``DEDENT`` tokens are now emitted within the bounds of the + input. This means that for a file containing 3 lines, the old version of the + tokenizer returned a ``DEDENT`` token in line 4 whilst the new version returns + the token in line 3. + + * The ``type`` attribute of the tokens emitted when tokenizing some invalid Python + characters such as ``!`` has changed from ``ERRORTOKEN`` to ``OP``. + Build Changes ============= From 2d685eca8a6ef25963609246d18097032358881c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 03:21:59 -0700 Subject: [PATCH 0030/1206] [3.12] gh-102856: Add missing quote to fix doctest (GH-104852) (#104854) Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 27fbb21c33420a..265c9f84e8fcc0 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -157,7 +157,7 @@ same quote as the containing f-string. Let's cover these in detail: >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism'] >>> f"This is the playlist: {", ".join(songs)}" - 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism' Note that before this change there was no explicit limit in how f-strings can be nested, but the fact that string quotes cannot be reused inside the From 3d2ed8991f9f0f4bbefe4c6f5c8bbbb92259bac6 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Wed, 24 May 2023 11:40:51 +0100 Subject: [PATCH 0031/1206] [3.12] gh-104825: Remove implicit newline in the line attribute in tokens emitted in the tokenize module (GH-104846). (#104850) (cherry picked from commit c8cf9b42eb2bfbd4c3e708ec28d32430248a1d7a) --- Lib/test/test_tabnanny.py | 8 ++++---- Lib/test/test_tokenize.py | 4 ++-- .../2023-05-24-09-59-56.gh-issue-104825.mQesie.rst | 2 ++ Python/Python-tokenize.c | 4 ++++ 4 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index aa700118f735d9..cc122cafc7985c 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -222,7 +222,7 @@ def test_when_nannynag_error_verbose(self): """ with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as file_path: out = f"{file_path!r}: *** Line 3: trouble in tab city! ***\n" - out += "offending line: '\\tprint(\"world\")\\n'\n" + out += "offending line: '\\tprint(\"world\")'\n" out += "inconsistent use of tabs and spaces in indentation\n" tabnanny.verbose = 1 @@ -231,7 +231,7 @@ def test_when_nannynag_error_verbose(self): def test_when_nannynag_error(self): """A python source code file eligible for raising `tabnanny.NannyNag`.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as file_path: - out = f"{file_path} 3 '\\tprint(\"world\")\\n'\n" + out = f"{file_path} 3 '\\tprint(\"world\")'\n" self.verify_tabnanny_check(file_path, out=out) def test_when_no_file(self): @@ -341,7 +341,7 @@ def test_verbose_mode(self): """Should display more error information if verbose mode is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" + "offending line: '\\tprint(\"world\")'" ).strip() self.validate_cmd("-v", path, stdout=stdout, partial=True) @@ -349,6 +349,6 @@ def test_double_verbose_mode(self): """Should display detailed error information if double verbose is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" + "offending line: '\\tprint(\"world\")'" ).strip() self.validate_cmd("-vv", path, stdout=stdout, partial=True) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 8e7ab3d4b7b578..fd9c919ce6a0d1 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -103,7 +103,7 @@ def k(x): e.exception.msg, 'unindent does not match any outer indentation level') self.assertEqual(e.exception.offset, 9) - self.assertEqual(e.exception.text, ' x += 5\n') + self.assertEqual(e.exception.text, ' x += 5') def test_int(self): # Ordinary integers and binary operators @@ -1157,7 +1157,7 @@ def readline(): # skip the initial encoding token and the end tokens tokens = list(_tokenize(readline(), encoding='utf-8'))[:-2] - expected_tokens = [TokenInfo(3, '"ЉЊЈÐЂ"', (1, 0), (1, 7), '"ЉЊЈÐЂ"\n')] + expected_tokens = [TokenInfo(3, '"ЉЊЈÐЂ"', (1, 0), (1, 7), '"ЉЊЈÐЂ"')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst new file mode 100644 index 00000000000000..caf5d3527085f3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst @@ -0,0 +1,2 @@ +Tokens emitted by the :mod:`tokenize` module do not include an implicit +``\n`` character in the ``line`` attribute anymore. Patch by Pablo Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index f7e32d3af9a9f7..0023e303b96e83 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -123,6 +123,8 @@ _tokenizer_error(struct tok_state *tok) int result = 0; Py_ssize_t size = tok->inp - tok->buf; + assert(tok->buf[size-1] == '\n'); + size -= 1; // Remove the newline character from the end of the line error_line = PyUnicode_DecodeUTF8(tok->buf, size, "replace"); if (!error_line) { result = -1; @@ -193,6 +195,8 @@ tokenizeriter_next(tokenizeriterobject *it) } Py_ssize_t size = it->tok->inp - it->tok->buf; + assert(it->tok->buf[size-1] == '\n'); + size -= 1; // Remove the newline character from the end of the line PyObject *line = PyUnicode_DecodeUTF8(it->tok->buf, size, "replace"); if (line == NULL) { Py_DECREF(str); From b151660883864392c0e37972efde232b46a36589 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 24 May 2023 19:47:07 +0900 Subject: [PATCH 0032/1206] =?UTF-8?q?[3.12]=20gh-101282:=20Enclose=20BOLT?= =?UTF-8?q?=5FAPPLY=5FFLAGS=20value=20in=20double=20quotes=20(gh=E2=80=A6?= =?UTF-8?q?=20(gh-104853)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [3.12] gh-101282: Enclose BOLT_APPLY_FLAGS value in double quotes (gh-104752) (cherry picked from commit c43785192c97698a0217a680b30baae22106ed3e) --- configure | 3 +-- configure.ac | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 2b863be108be26..21a3af145c1369 100755 --- a/configure +++ b/configure @@ -8398,8 +8398,7 @@ $as_echo "$BOLT_INSTRUMENT_FLAGS" >&6; } $as_echo_n "checking BOLT_APPLY_FLAGS... " >&6; } if test -z "${BOLT_APPLY_FLAGS}" then - BOLT_APPLY_FLAGS=-update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot - + BOLT_APPLY_FLAGS=" -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot " fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 diff --git a/configure.ac b/configure.ac index 786d3414eb0e06..c5a79af1a2e2eb 100644 --- a/configure.ac +++ b/configure.ac @@ -2087,23 +2087,23 @@ if test -z "${BOLT_APPLY_FLAGS}" then AS_VAR_SET( [BOLT_APPLY_FLAGS], - [m4_join([ ], - [-update-debug-sections], - [-reorder-blocks=ext-tsp], - [-reorder-functions=hfsort+], - [-split-functions], - [-icf=1], - [-inline-all], - [-split-eh], - [-reorder-functions-use-hot-size], - [-peepholes=none], - [-jump-tables=aggressive], - [-inline-ap], - [-indirect-call-promotion=all], - [-dyno-stats], - [-use-gnu-stack], - [-frame-opt=hot] - )] + [m4_normalize(" + -update-debug-sections + -reorder-blocks=ext-tsp + -reorder-functions=hfsort+ + -split-functions + -icf=1 + -inline-all + -split-eh + -reorder-functions-use-hot-size + -peepholes=none + -jump-tables=aggressive + -inline-ap + -indirect-call-promotion=all + -dyno-stats + -use-gnu-stack + -frame-opt=hot + ")] ) fi AC_MSG_RESULT([$BOLT_APPLY_FLAGS]) From 5e1799ea2e6ce96dbaba380f41f37b3856e43354 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 05:46:22 -0700 Subject: [PATCH 0033/1206] [3.12] gh-104719: IDLE - test existence of all tokenize references. (GH-104767) (#104844) gh-104719: IDLE - test existence of all tokenize references. (GH-104767) Class editor.IndentSearcher contains all editor references to tokenize module. Module io tokenize reference cover those other modules. (cherry picked from commit e561c09975bf67ad8bb67c56a81e30a9165bcc84) Co-authored-by: Terry Jan Reedy Co-authored-by: Jelle Zijlstra --- Lib/idlelib/NEWS.txt | 3 ++ Lib/idlelib/editor.py | 19 +++++----- Lib/idlelib/idle_test/test_editor.py | 36 +++++++++++++++++-- Lib/idlelib/idle_test/test_iomenu.py | 6 ++++ ...-05-23-17-19-49.gh-issue-104719.rvYXH-.rst | 2 ++ 5 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 553b932aa6b6bc..f258797c6e0fb3 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,9 @@ Released on 2023-10-02 ========================= +gh-104719: Remove IDLE's modification of tokenize.tabsize and test +other uses of tokenize data and methods. + gh-104499: Fix completions for Tk Aqua 8.7 (currently blank). gh-104486: Make About print both tcl and tk versions if different, diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index df36be8766016f..69b27d0683a104 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1571,7 +1571,7 @@ def reindent_to(self, column): # blocks are found). def guess_indent(self): - opener, indented = IndentSearcher(self.text, self.tabwidth).run() + opener, indented = IndentSearcher(self.text).run() if opener and indented: raw, indentsmall = get_line_indent(opener, self.tabwidth) raw, indentlarge = get_line_indent(indented, self.tabwidth) @@ -1609,15 +1609,10 @@ def get_line_indent(line, tabwidth): class IndentSearcher: + "Manage initial indent guess, returned by run method." - # .run() chews over the Text widget, looking for a block opener - # and the stmt following it. Returns a pair, - # (line containing block opener, line containing stmt) - # Either or both may be None. - - def __init__(self, text, tabwidth): + def __init__(self, text): self.text = text - self.tabwidth = tabwidth self.i = self.finished = 0 self.blkopenline = self.indentedline = None @@ -1633,7 +1628,8 @@ def readline(self): def tokeneater(self, type, token, start, end, line, INDENT=tokenize.INDENT, NAME=tokenize.NAME, - OPENERS=('class', 'def', 'for', 'if', 'try', 'while')): + OPENERS=('class', 'def', 'for', 'if', 'match', 'try', + 'while', 'with')): if self.finished: pass elif type == NAME and token in OPENERS: @@ -1643,6 +1639,10 @@ def tokeneater(self, type, token, start, end, line, self.finished = 1 def run(self): + """Return 2 lines containing block opener and and indent. + + Either the indent line or both may be None. + """ try: tokens = tokenize.generate_tokens(self.readline) for token in tokens: @@ -1654,6 +1654,7 @@ def run(self): ### end autoindent code ### + def prepstr(s): """Extract the underscore from a string. diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index fdb47abf43fb77..9296a6d235fbbe 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -1,10 +1,10 @@ -"Test editor, coverage 35%." +"Test editor, coverage 53%." from idlelib import editor import unittest from collections import namedtuple from test.support import requires -from tkinter import Tk +from tkinter import Tk, Text Editor = editor.EditorWindow @@ -31,7 +31,7 @@ def test_init(self): e._close() -class TestGetLineIndent(unittest.TestCase): +class GetLineIndentTest(unittest.TestCase): def test_empty_lines(self): for tabwidth in [1, 2, 4, 6, 8]: for line in ['', '\n']: @@ -181,6 +181,36 @@ def test_indent_and_newline_event(self): eq(get('1.0', 'end'), ' def f1(self, a,\n \n return a + b\n') +class IndentSearcherTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = Tk() + cls.root.withdraw() + cls.text = Text(cls.root) + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + del cls.root + + def test_searcher(self): + text = self.text + searcher = (self.text) + test_info = (# text, (block, indent)) + ("", (None, None)), + ("[1,", (None, None)), # TokenError + ("if 1:\n", ('if 1:\n', None)), + ("if 1:\n 2\n 3\n", ('if 1:\n', ' 2\n')), + ) + for code, expected_pair in test_info: + with self.subTest(code=code): + insert(text, code) + actual_pair = editor.IndentSearcher(text).run() + self.assertEqual(actual_pair, expected_pair) + + class RMenuTest(unittest.TestCase): @classmethod diff --git a/Lib/idlelib/idle_test/test_iomenu.py b/Lib/idlelib/idle_test/test_iomenu.py index 2fb836dba21672..e0642cf0cabef0 100644 --- a/Lib/idlelib/idle_test/test_iomenu.py +++ b/Lib/idlelib/idle_test/test_iomenu.py @@ -8,6 +8,12 @@ from idlelib import util from idlelib.idle_test.mock_idle import Func +# Fail if either tokenize.open and t.detect_encoding does not exist. +# These are used in loadfile and encode. +# Also used in pyshell.MI.execfile and runscript.tabnanny. +from tokenize import open, detect_encoding +# Remove when we have proper tests that use both. + class IOBindingTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst b/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst new file mode 100644 index 00000000000000..3fbe04ba4f6844 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst @@ -0,0 +1,2 @@ +Remove IDLE's modification of tokenize.tabsize and test other uses of +tokenize data and methods. From 25890ebbb8502a19b76da7634d9a85e3c8ddcb54 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 06:40:31 -0700 Subject: [PATCH 0034/1206] [3.12] gh-102856: Update "Formatted string literals" docs section after PEP701 (GH-104861) (#104865) (cherry picked from commit 8e5b3b90c83d9aaca1dc2299da696b994780bcc0) Co-authored-by: Lysandros Nikolaou --- Doc/reference/lexical_analysis.rst | 52 ++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 8adb4b740825d0..757f887caa4029 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -741,16 +741,28 @@ Expressions in formatted string literals are treated like regular Python expressions surrounded by parentheses, with a few exceptions. An empty expression is not allowed, and both :keyword:`lambda` and assignment expressions ``:=`` must be surrounded by explicit parentheses. -Replacement expressions can contain line breaks (e.g. in triple-quoted -strings), but they cannot contain comments. Each expression is evaluated -in the context where the formatted string literal appears, in order from -left to right. +Each expression is evaluated in the context where the formatted string literal +appears, in order from left to right. Replacement expressions can contain +newlines in both single-quoted and triple-quoted f-strings and they can contain +comments. Everything that comes after a ``#`` inside a replacement field +is a comment (even closing braces and quotes). In that case, replacement fields +must be closed in a different line. + +.. code-block:: text + + >>> f"abc{a # This is a comment }" + ... + 3}" + 'abc5' .. versionchanged:: 3.7 Prior to Python 3.7, an :keyword:`await` expression and comprehensions containing an :keyword:`async for` clause were illegal in the expressions in formatted string literals due to a problem with the implementation. +.. versionchanged:: 3.12 + Prior to Python 3.12, comments were not allowed inside f-string replacement + fields. + When the equal sign ``'='`` is provided, the output will have the expression text, the ``'='`` and the evaluated value. Spaces after the opening brace ``'{'``, within the expression and after the ``'='`` are all retained in the @@ -813,24 +825,30 @@ Some examples of formatted string literals:: 'line = "The mill\'s closed" ' -A consequence of sharing the same syntax as regular string literals is -that characters in the replacement fields must not conflict with the -quoting used in the outer formatted string literal:: +Reusing the outer f-string quoting type inside a replacement field is +permitted:: - f"abc {a["x"]} def" # error: outer string literal ended prematurely - f"abc {a['x']} def" # workaround: use different quoting + >>> a = dict(x=2) + >>> f"abc {a["x"]} def" + 'abc 2 def' -Backslashes are not allowed in format expressions and will raise -an error:: +.. versionchanged:: 3.12 + Prior to Python 3.12, reuse of the same quoting type of the outer f-string + inside a replacement field was not possible. - f"newline: {ord('\n')}" # raises SyntaxError +Backslashes are also allowed in replacement fields and are evaluated the same +way as in any other context:: -To include a value in which a backslash escape is required, create -a temporary variable. + >>> a = ["a", "b", "c"] + >>> print(f"List a contains:\n{"\n".join(a)}") + List a contains: + a + b + c - >>> newline = ord('\n') - >>> f"newline: {newline}" - 'newline: 10' +.. versionchanged:: 3.12 + Prior to Python 3.12, backslashes were not permitted inside an f-string + replacement field. Formatted string literals cannot be used as docstrings, even if they do not include expressions. From 2b54ea5ba2f5fbbaea03def966f02b742652104e Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Wed, 24 May 2023 13:41:50 -0400 Subject: [PATCH 0035/1206] [3.12] gh-104825: add omitted idlelib text fix (#104880) Order of events: Terry merged new idlelib test into main. Ms. I. made a 3.12 backport; tests passed. Pablo merged the tokenize change with idlelib test fix into main. Pablo merged a 3.12 backport without the idle test fix as the backport of the latter had not yet been been merged. Terry merged the idlelib test backport. The new test failed on at least 4 3.12 buildbots because of the tokenize change. This PR backports the now needed idlelib test fix. (cherry picked from commit c8cf9b4) --- Lib/idlelib/idle_test/test_editor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 9296a6d235fbbe..ba59c40dc6dde5 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -201,8 +201,8 @@ def test_searcher(self): test_info = (# text, (block, indent)) ("", (None, None)), ("[1,", (None, None)), # TokenError - ("if 1:\n", ('if 1:\n', None)), - ("if 1:\n 2\n 3\n", ('if 1:\n', ' 2\n')), + ("if 1:\n", ('if 1:', None)), + ("if 1:\n 2\n 3\n", ('if 1:', ' 2')), ) for code, expected_pair in test_info: with self.subTest(code=code): From 45b88e0653da265ae5cbbed7785f3970c5d52d08 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Wed, 24 May 2023 14:32:50 -0400 Subject: [PATCH 0036/1206] gh-103207: The macOS 13 Ventura Installer.app permission problem is fixed by Apple in macOS 13.4. (GH-104883) --- Mac/BuildScript/resources/Welcome.rtf | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 83b7aa9d883a16..dfb02a0b314b7a 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -26,6 +26,28 @@ At the end of this install, click on \f0 to install a set of current SSL root certificates.\ \ +\f1\b [UPDATE: fixed in macOS 13.4] macOS 13 Ventura users +\f0\b0 : Due to an issue with the macOS +\f1\b Installer +\f0\b0 app in macOS 13 Ventura updates prior to macOS 13.4, installation of some third-party packages including this Python package may fail with a vague +\f1\b "The installer encountered an error" +\f0\b0 message if the +\f1\b Installer +\f0\b0 app does not have permission to access the folder containing the downloaded installer file, typically in the +\f1\b Downloads +\f0\b0 folder. Go to +\f1\b System Settings +\f0\b0 -> +\f1\b Privacy & Security +\f0\b0 -> +\f1\b Files and Folders +\f0\b0 , then click the mark in front of +\f1\b Installer +\f0\b0 to expand, and enable +\f1\b Downloads Folder +\f0\b0 by moving the toggle to the right. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. This problem has been resolved in macOS 13.4.\ +\ + \f1\b NOTE: \f0\b0 This is a beta test preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ } \ No newline at end of file From ddc29c8fdb59849e7eebd8e72462b14a98994874 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 11:41:58 -0700 Subject: [PATCH 0037/1206] [3.12] gh-104866: Tokenize should emit NEWLINE after exiting block with comment (GH-104870) (#104872) gh-104866: Tokenize should emit NEWLINE after exiting block with comment (GH-104870) (cherry picked from commit c90a862cdcf55dc1753c6466e5fa4a467a13ae24) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_tokenize.py | 17 +++++++++++++++++ Parser/tokenizer.c | 9 ++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index fd9c919ce6a0d1..251ce2b864a9d8 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1057,6 +1057,23 @@ async def bar(): pass DEDENT '' (6, 12) (6, 12) """) + def test_newline_after_parenthesized_block_with_comment(self): + self.check_tokenize('''\ +[ + # A comment here + 1 +] +''', """\ + OP '[' (1, 0) (1, 1) + NL '\\n' (1, 1) (1, 2) + COMMENT '# A comment here' (2, 4) (2, 20) + NL '\\n' (2, 20) (2, 21) + NUMBER '1' (3, 4) (3, 5) + NL '\\n' (3, 5) (3, 6) + OP ']' (4, 0) (4, 1) + NEWLINE '\\n' (4, 1) (4, 2) + """) + class GenerateTokensTest(TokenizeTest): def check_tokenize(self, s, expected): # Format the tokens in s in a table format. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 472d4174726354..1e8f785a331ac5 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2007,6 +2007,9 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t tok->atbol = 1; if (blankline || tok->level > 0) { if (tok->tok_extra_tokens) { + if (tok->comment_newline) { + tok->comment_newline = 0; + } p_start = tok->start; p_end = tok->cur; return MAKE_TOKEN(NL); @@ -2015,9 +2018,9 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t } if (tok->comment_newline && tok->tok_extra_tokens) { tok->comment_newline = 0; - p_start = tok->start; - p_end = tok->cur; - return MAKE_TOKEN(NL); + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(NL); } p_start = tok->start; p_end = tok->cur - 1; /* Leave '\n' out of the string */ From 3d91d034a0d74804a356d773f54230e62c9924ba Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 12:21:28 -0700 Subject: [PATCH 0038/1206] [3.12] Improve test coverage for is_typeddict (GH-104884) (#104889) Improve test coverage for is_typeddict (GH-104884) In particular, it's important to test that is_typeddict(TypedDict) returns False. (cherry picked from commit 1497607a8e99f1103c40368dd5f9057f0146a520) Co-authored-by: Jelle Zijlstra --- Lib/test/test_typing.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a3fad6f35e7136..e68ce6eaf22792 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7223,10 +7223,29 @@ class Wrong(*bases): pass def test_is_typeddict(self): - assert is_typeddict(Point2D) is True - assert is_typeddict(Union[str, int]) is False + self.assertIs(is_typeddict(Point2D), True) + self.assertIs(is_typeddict(Union[str, int]), False) # classes, not instances - assert is_typeddict(Point2D()) is False + self.assertIs(is_typeddict(Point2D()), False) + call_based = TypedDict('call_based', {'a': int}) + self.assertIs(is_typeddict(call_based), True) + self.assertIs(is_typeddict(call_based()), False) + + T = TypeVar("T") + class BarGeneric(TypedDict, Generic[T]): + a: T + self.assertIs(is_typeddict(BarGeneric), True) + self.assertIs(is_typeddict(BarGeneric[int]), False) + self.assertIs(is_typeddict(BarGeneric()), False) + + class NewGeneric[T](TypedDict): + a: T + self.assertIs(is_typeddict(NewGeneric), True) + self.assertIs(is_typeddict(NewGeneric[int]), False) + self.assertIs(is_typeddict(NewGeneric()), False) + + # The TypedDict constructor is not itself a TypedDict + self.assertIs(is_typeddict(TypedDict), False) def test_get_type_hints(self): self.assertEqual( From b67021463687941b5ac650a9c3d0f5a533dbcf5d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 12:30:57 -0700 Subject: [PATCH 0039/1206] [3.12] gh-104879: Fix TypeAliasType.__module__ in exec() (GH-104881) (#104890) (cherry picked from commit fe77a99fc8b549a8bf9ccbc5485fe5ea9bcf47b9) Co-authored-by: Jelle Zijlstra --- Lib/test/test_type_aliases.py | 9 +++++ Lib/test/test_typing.py | 34 +++++++++++++++++++ ...-05-24-10-19-35.gh-issue-104879.v-29NL.rst | 2 ++ Objects/typevarobject.c | 9 +++-- 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index 56d150d67afb6f..c43499609aaa56 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -159,6 +159,15 @@ def test_basic(self): self.assertEqual(TA.__type_params__, ()) self.assertEqual(TA.__module__, __name__) + def test_attributes_with_exec(self): + ns = {} + exec("type TA = int", ns, ns) + TA = ns["TA"] + self.assertEqual(TA.__name__, "TA") + self.assertIs(TA.__value__, int) + self.assertEqual(TA.__type_params__, ()) + self.assertIs(TA.__module__, None) + def test_generic(self): T = TypeVar("T") TA = TypeAliasType("TA", list[T], type_params=(T,)) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index e68ce6eaf22792..7fe137f8d7c526 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -373,6 +373,20 @@ def test_basic_plain(self): self.assertIs(T.__covariant__, False) self.assertIs(T.__contravariant__, False) self.assertIs(T.__infer_variance__, False) + self.assertEqual(T.__module__, __name__) + + def test_basic_with_exec(self): + ns = {} + exec('from typing import TypeVar; T = TypeVar("T", bound=float)', ns, ns) + T = ns['T'] + self.assertIsInstance(T, TypeVar) + self.assertEqual(T.__name__, 'T') + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, float) + self.assertIs(T.__covariant__, False) + self.assertIs(T.__contravariant__, False) + self.assertIs(T.__infer_variance__, False) + self.assertIs(T.__module__, None) def test_attributes(self): T_bound = TypeVar('T_bound', bound=int) @@ -939,6 +953,17 @@ def test_name(self): Ts2 = TypeVarTuple('Ts2') self.assertEqual(Ts2.__name__, 'Ts2') + def test_module(self): + Ts = TypeVarTuple('Ts') + self.assertEqual(Ts.__module__, __name__) + + def test_exec(self): + ns = {} + exec('from typing import TypeVarTuple; Ts = TypeVarTuple("Ts")', ns) + Ts = ns['Ts'] + self.assertEqual(Ts.__name__, 'Ts') + self.assertIs(Ts.__module__, None) + def test_instance_is_equal_to_itself(self): Ts = TypeVarTuple('Ts') self.assertEqual(Ts, Ts) @@ -8006,6 +8031,15 @@ def test_basic_plain(self): self.assertEqual(P, P) self.assertIsInstance(P, ParamSpec) self.assertEqual(P.__name__, 'P') + self.assertEqual(P.__module__, __name__) + + def test_basic_with_exec(self): + ns = {} + exec('from typing import ParamSpec; P = ParamSpec("P")', ns, ns) + P = ns['P'] + self.assertIsInstance(P, ParamSpec) + self.assertEqual(P.__name__, 'P') + self.assertIs(P.__module__, None) def test_valid_uses(self): P = ParamSpec('P') diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst new file mode 100644 index 00000000000000..235f4180642be6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst @@ -0,0 +1,2 @@ +Fix crash when accessing the ``__module__`` attribute of type aliases +defined outside a module. Patch by Jelle Zijlstra. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 6730ebfc064e35..6aa0d8a3bc53be 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1319,8 +1319,13 @@ typealias_module(PyObject *self, void *unused) return Py_NewRef(ta->module); } if (ta->compute_value != NULL) { - // PyFunction_GetModule() returns a borrowed reference - return Py_NewRef(PyFunction_GetModule(ta->compute_value)); + PyObject* mod = PyFunction_GetModule(ta->compute_value); + if (mod != NULL) { + // PyFunction_GetModule() returns a borrowed reference, + // and it may return NULL (e.g., for functions defined + // in an exec()'ed block). + return Py_NewRef(mod); + } } Py_RETURN_NONE; } From c4bc97a0aa0c8793d6995f8e89ff915faaf421a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 13:55:37 -0700 Subject: [PATCH 0040/1206] [3.12] gh-99108: Refresh HACL* (GH-104808) (#104893) gh-99108: Refresh HACL* (GH-104808) Refresh HACL* from upstream to improve SHA2 performance and fix a 32-bit issue in SHA3. (cherry picked from commit 160321e5304b962a162eb023472aa2bc8307ae15) Co-authored-by: Jonathan Protzenko --- Makefile.pre.in | 14 +- ...3-05-24-09-29-08.gh-issue-99108.hwS2cr.rst | 2 + Modules/Setup | 2 +- Modules/Setup.stdlib.in | 2 +- Modules/_hacl/Hacl_Hash_MD5.c | 6 +- Modules/_hacl/Hacl_Hash_MD5.h | 2 +- Modules/_hacl/Hacl_Hash_SHA1.c | 6 +- Modules/_hacl/Hacl_Hash_SHA1.h | 2 +- ...Hacl_Streaming_SHA2.c => Hacl_Hash_SHA2.c} | 189 ++++++++++-------- ...Hacl_Streaming_SHA2.h => Hacl_Hash_SHA2.h} | 22 +- Modules/_hacl/Hacl_Hash_SHA3.c | 28 ++- Modules/_hacl/Hacl_Hash_SHA3.h | 12 +- Modules/_hacl/Hacl_Streaming_Types.h | 7 + .../{Hacl_SHA2_Generic.h => Hacl_Hash_SHA2.h} | 58 +++++- Modules/_hacl/refresh.sh | 16 +- Modules/sha2module.c | 2 +- PCbuild/pythoncore.vcxproj | 2 +- PCbuild/pythoncore.vcxproj.filters | 2 +- 18 files changed, 225 insertions(+), 149 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst rename Modules/_hacl/{Hacl_Streaming_SHA2.c => Hacl_Hash_SHA2.c} (87%) rename Modules/_hacl/{Hacl_Streaming_SHA2.h => Hacl_Hash_SHA2.h} (91%) rename Modules/_hacl/internal/{Hacl_SHA2_Generic.h => Hacl_Hash_SHA2.h} (83%) diff --git a/Makefile.pre.in b/Makefile.pre.in index eb79c9c4ca1801..2482b637739a79 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -208,7 +208,7 @@ ENSUREPIP= @ENSUREPIP@ # Internal static libraries LIBMPDEC_A= Modules/_decimal/libmpdec/libmpdec.a LIBEXPAT_A= Modules/expat/libexpat.a -LIBHACL_SHA2_A= Modules/_hacl/libHacl_Streaming_SHA2.a +LIBHACL_SHA2_A= Modules/_hacl/libHacl_Hash_SHA2.a # Module state, compiler flags and linker flags # Empty CFLAGS and LDFLAGS are omitted. @@ -583,7 +583,7 @@ LIBEXPAT_HEADERS= \ # hashlib's HACL* library LIBHACL_SHA2_OBJS= \ - Modules/_hacl/Hacl_Streaming_SHA2.o + Modules/_hacl/Hacl_Hash_SHA2.o LIBHACL_HEADERS= \ Modules/_hacl/include/krml/FStar_UInt128_Verified.h \ @@ -596,8 +596,8 @@ LIBHACL_HEADERS= \ Modules/_hacl/python_hacl_namespaces.h LIBHACL_SHA2_HEADERS= \ - Modules/_hacl/Hacl_Streaming_SHA2.h \ - Modules/_hacl/internal/Hacl_SHA2_Generic.h \ + Modules/_hacl/Hacl_Hash_SHA2.h \ + Modules/_hacl/internal/Hacl_Hash_SHA2.h \ $(LIBHACL_HEADERS) ######################################################################### @@ -964,11 +964,11 @@ $(LIBEXPAT_A): $(LIBEXPAT_OBJS) $(AR) $(ARFLAGS) $@ $(LIBEXPAT_OBJS) ########################################################################## -# Build HACL* static libraries for hashlib: libHacl_Streaming_SHA2.a +# Build HACL* static libraries for hashlib: libHacl_Hash_SHA2.a LIBHACL_CFLAGS=-I$(srcdir)/Modules/_hacl/include -D_BSD_SOURCE -D_DEFAULT_SOURCE $(PY_STDMODULE_CFLAGS) $(CCSHARED) -Modules/_hacl/Hacl_Streaming_SHA2.o: $(srcdir)/Modules/_hacl/Hacl_Streaming_SHA2.c $(LIBHACL_SHA2_HEADERS) - $(CC) -c $(LIBHACL_CFLAGS) -o $@ $(srcdir)/Modules/_hacl/Hacl_Streaming_SHA2.c +Modules/_hacl/Hacl_Hash_SHA2.o: $(srcdir)/Modules/_hacl/Hacl_Hash_SHA2.c $(LIBHACL_SHA2_HEADERS) + $(CC) -c $(LIBHACL_CFLAGS) -o $@ $(srcdir)/Modules/_hacl/Hacl_Hash_SHA2.c $(LIBHACL_SHA2_A): $(LIBHACL_SHA2_OBJS) -rm -f $@ diff --git a/Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst b/Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst new file mode 100644 index 00000000000000..312ba89454b5b8 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst @@ -0,0 +1,2 @@ +Refresh our new HACL* built-in :mod:`hashlib` code from upstream. Built-in +SHA2 should be faster and an issue with SHA3 on 32-bit platforms is fixed. diff --git a/Modules/Setup b/Modules/Setup index 312e99fea530dc..a8faa1d1028da5 100644 --- a/Modules/Setup +++ b/Modules/Setup @@ -165,7 +165,7 @@ PYTHONPATH=$(COREPYTHONPATH) #_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c #_md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE #_sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE -#_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a +#_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Hash_SHA2.a #_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE # text encodings and unicode diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 6db567d713090d..0fc7955cd9b7c2 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -78,7 +78,7 @@ # hashing builtins, can be disabled with --without-builtin-hashlib-hashes @MODULE__MD5_TRUE@_md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE @MODULE__SHA1_TRUE@_sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE -@MODULE__SHA2_TRUE@_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a +@MODULE__SHA2_TRUE@_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Hash_SHA2.a @MODULE__SHA3_TRUE@_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE @MODULE__BLAKE2_TRUE@_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c diff --git a/Modules/_hacl/Hacl_Hash_MD5.c b/Modules/_hacl/Hacl_Hash_MD5.c index 2c613066d9f682..222ac824f01961 100644 --- a/Modules/_hacl/Hacl_Hash_MD5.c +++ b/Modules/_hacl/Hacl_Hash_MD5.c @@ -1227,14 +1227,14 @@ void Hacl_Streaming_MD5_legacy_init(Hacl_Streaming_MD_state_32 *s) /** 0 = success, 1 = max length exceeded */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_MD5_legacy_update(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) { Hacl_Streaming_MD_state_32 s = *p; uint64_t total_len = s.total_len; if ((uint64_t)len > (uint64_t)2305843009213693951U - total_len) { - return (uint32_t)1U; + return Hacl_Streaming_Types_MaximumLengthExceeded; } uint32_t sz; if (total_len % (uint64_t)(uint32_t)64U == (uint64_t)0U && total_len > (uint64_t)0U) @@ -1399,7 +1399,7 @@ Hacl_Streaming_MD5_legacy_update(Hacl_Streaming_MD_state_32 *p, uint8_t *data, u } ); } - return (uint32_t)0U; + return Hacl_Streaming_Types_Success; } void Hacl_Streaming_MD5_legacy_finish(Hacl_Streaming_MD_state_32 *p, uint8_t *dst) diff --git a/Modules/_hacl/Hacl_Hash_MD5.h b/Modules/_hacl/Hacl_Hash_MD5.h index 015e3668751b75..13c19fd40f4d12 100644 --- a/Modules/_hacl/Hacl_Hash_MD5.h +++ b/Modules/_hacl/Hacl_Hash_MD5.h @@ -46,7 +46,7 @@ void Hacl_Streaming_MD5_legacy_init(Hacl_Streaming_MD_state_32 *s); /** 0 = success, 1 = max length exceeded */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_MD5_legacy_update(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len); void Hacl_Streaming_MD5_legacy_finish(Hacl_Streaming_MD_state_32 *p, uint8_t *dst); diff --git a/Modules/_hacl/Hacl_Hash_SHA1.c b/Modules/_hacl/Hacl_Hash_SHA1.c index e155e338271c56..5ecb3c0b3a56e0 100644 --- a/Modules/_hacl/Hacl_Hash_SHA1.c +++ b/Modules/_hacl/Hacl_Hash_SHA1.c @@ -263,14 +263,14 @@ void Hacl_Streaming_SHA1_legacy_init(Hacl_Streaming_MD_state_32 *s) /** 0 = success, 1 = max length exceeded */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA1_legacy_update(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) { Hacl_Streaming_MD_state_32 s = *p; uint64_t total_len = s.total_len; if ((uint64_t)len > (uint64_t)2305843009213693951U - total_len) { - return (uint32_t)1U; + return Hacl_Streaming_Types_MaximumLengthExceeded; } uint32_t sz; if (total_len % (uint64_t)(uint32_t)64U == (uint64_t)0U && total_len > (uint64_t)0U) @@ -435,7 +435,7 @@ Hacl_Streaming_SHA1_legacy_update(Hacl_Streaming_MD_state_32 *p, uint8_t *data, } ); } - return (uint32_t)0U; + return Hacl_Streaming_Types_Success; } void Hacl_Streaming_SHA1_legacy_finish(Hacl_Streaming_MD_state_32 *p, uint8_t *dst) diff --git a/Modules/_hacl/Hacl_Hash_SHA1.h b/Modules/_hacl/Hacl_Hash_SHA1.h index 5e2ae8e713292d..dc50aa6f6d3902 100644 --- a/Modules/_hacl/Hacl_Hash_SHA1.h +++ b/Modules/_hacl/Hacl_Hash_SHA1.h @@ -46,7 +46,7 @@ void Hacl_Streaming_SHA1_legacy_init(Hacl_Streaming_MD_state_32 *s); /** 0 = success, 1 = max length exceeded */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA1_legacy_update(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len); void Hacl_Streaming_SHA1_legacy_finish(Hacl_Streaming_MD_state_32 *p, uint8_t *dst); diff --git a/Modules/_hacl/Hacl_Streaming_SHA2.c b/Modules/_hacl/Hacl_Hash_SHA2.c similarity index 87% rename from Modules/_hacl/Hacl_Streaming_SHA2.c rename to Modules/_hacl/Hacl_Hash_SHA2.c index 69c3be8cdf7fd1..08e3f7edbf4ede 100644 --- a/Modules/_hacl/Hacl_Streaming_SHA2.c +++ b/Modules/_hacl/Hacl_Hash_SHA2.c @@ -23,12 +23,11 @@ */ -#include "Hacl_Streaming_SHA2.h" +#include "internal/Hacl_Hash_SHA2.h" -#include "internal/Hacl_SHA2_Generic.h" -static inline void sha256_init(uint32_t *hash) +void Hacl_SHA2_Scalar32_sha256_init(uint32_t *hash) { KRML_MAYBE_FOR8(i, (uint32_t)0U, @@ -39,7 +38,7 @@ static inline void sha256_init(uint32_t *hash) os[i] = x;); } -static inline void sha256_update0(uint8_t *b, uint32_t *hash) +static inline void sha256_update(uint8_t *b, uint32_t *hash) { uint32_t hash_old[8U] = { 0U }; uint32_t ws[16U] = { 0U }; @@ -159,19 +158,24 @@ static inline void sha256_update0(uint8_t *b, uint32_t *hash) os[i] = x;); } -static inline void sha256_update_nblocks(uint32_t len, uint8_t *b, uint32_t *st) +void Hacl_SHA2_Scalar32_sha256_update_nblocks(uint32_t len, uint8_t *b, uint32_t *st) { uint32_t blocks = len / (uint32_t)64U; for (uint32_t i = (uint32_t)0U; i < blocks; i++) { uint8_t *b0 = b; uint8_t *mb = b0 + i * (uint32_t)64U; - sha256_update0(mb, st); + sha256_update(mb, st); } } -static inline void -sha256_update_last(uint64_t totlen, uint32_t len, uint8_t *b, uint32_t *hash) +void +Hacl_SHA2_Scalar32_sha256_update_last( + uint64_t totlen, + uint32_t len, + uint8_t *b, + uint32_t *hash +) { uint32_t blocks; if (len + (uint32_t)8U + (uint32_t)1U <= (uint32_t)64U) @@ -199,15 +203,15 @@ sha256_update_last(uint64_t totlen, uint32_t len, uint8_t *b, uint32_t *hash) uint8_t *lb1 = l1; uint8_t *last0 = lb0; uint8_t *last1 = lb1; - sha256_update0(last0, hash); + sha256_update(last0, hash); if (blocks > (uint32_t)1U) { - sha256_update0(last1, hash); + sha256_update(last1, hash); return; } } -static inline void sha256_finish(uint32_t *st, uint8_t *h) +void Hacl_SHA2_Scalar32_sha256_finish(uint32_t *st, uint8_t *h) { uint8_t hbuf[32U] = { 0U }; KRML_MAYBE_FOR8(i, @@ -218,7 +222,7 @@ static inline void sha256_finish(uint32_t *st, uint8_t *h) memcpy(h, hbuf, (uint32_t)32U * sizeof (uint8_t)); } -static inline void sha224_init(uint32_t *hash) +void Hacl_SHA2_Scalar32_sha224_init(uint32_t *hash) { KRML_MAYBE_FOR8(i, (uint32_t)0U, @@ -231,15 +235,16 @@ static inline void sha224_init(uint32_t *hash) static inline void sha224_update_nblocks(uint32_t len, uint8_t *b, uint32_t *st) { - sha256_update_nblocks(len, b, st); + Hacl_SHA2_Scalar32_sha256_update_nblocks(len, b, st); } -static void sha224_update_last(uint64_t totlen, uint32_t len, uint8_t *b, uint32_t *st) +void +Hacl_SHA2_Scalar32_sha224_update_last(uint64_t totlen, uint32_t len, uint8_t *b, uint32_t *st) { - sha256_update_last(totlen, len, b, st); + Hacl_SHA2_Scalar32_sha256_update_last(totlen, len, b, st); } -static inline void sha224_finish(uint32_t *st, uint8_t *h) +void Hacl_SHA2_Scalar32_sha224_finish(uint32_t *st, uint8_t *h) { uint8_t hbuf[32U] = { 0U }; KRML_MAYBE_FOR8(i, @@ -381,7 +386,7 @@ static inline void sha512_update(uint8_t *b, uint64_t *hash) os[i] = x;); } -static inline void sha512_update_nblocks(uint32_t len, uint8_t *b, uint64_t *st) +void Hacl_SHA2_Scalar32_sha512_update_nblocks(uint32_t len, uint8_t *b, uint64_t *st) { uint32_t blocks = len / (uint32_t)128U; for (uint32_t i = (uint32_t)0U; i < blocks; i++) @@ -392,8 +397,13 @@ static inline void sha512_update_nblocks(uint32_t len, uint8_t *b, uint64_t *st) } } -static inline void -sha512_update_last(FStar_UInt128_uint128 totlen, uint32_t len, uint8_t *b, uint64_t *hash) +void +Hacl_SHA2_Scalar32_sha512_update_last( + FStar_UInt128_uint128 totlen, + uint32_t len, + uint8_t *b, + uint64_t *hash +) { uint32_t blocks; if (len + (uint32_t)16U + (uint32_t)1U <= (uint32_t)128U) @@ -429,7 +439,7 @@ sha512_update_last(FStar_UInt128_uint128 totlen, uint32_t len, uint8_t *b, uint6 } } -static inline void sha512_finish(uint64_t *st, uint8_t *h) +void Hacl_SHA2_Scalar32_sha512_finish(uint64_t *st, uint8_t *h) { uint8_t hbuf[64U] = { 0U }; KRML_MAYBE_FOR8(i, @@ -440,7 +450,7 @@ static inline void sha512_finish(uint64_t *st, uint8_t *h) memcpy(h, hbuf, (uint32_t)64U * sizeof (uint8_t)); } -static inline void sha384_init(uint64_t *hash) +void Hacl_SHA2_Scalar32_sha384_init(uint64_t *hash) { KRML_MAYBE_FOR8(i, (uint32_t)0U, @@ -451,18 +461,23 @@ static inline void sha384_init(uint64_t *hash) os[i] = x;); } -static inline void sha384_update_nblocks(uint32_t len, uint8_t *b, uint64_t *st) +void Hacl_SHA2_Scalar32_sha384_update_nblocks(uint32_t len, uint8_t *b, uint64_t *st) { - sha512_update_nblocks(len, b, st); + Hacl_SHA2_Scalar32_sha512_update_nblocks(len, b, st); } -static void -sha384_update_last(FStar_UInt128_uint128 totlen, uint32_t len, uint8_t *b, uint64_t *st) +void +Hacl_SHA2_Scalar32_sha384_update_last( + FStar_UInt128_uint128 totlen, + uint32_t len, + uint8_t *b, + uint64_t *st +) { - sha512_update_last(totlen, len, b, st); + Hacl_SHA2_Scalar32_sha512_update_last(totlen, len, b, st); } -static inline void sha384_finish(uint64_t *st, uint8_t *h) +void Hacl_SHA2_Scalar32_sha384_finish(uint64_t *st, uint8_t *h) { uint8_t hbuf[64U] = { 0U }; KRML_MAYBE_FOR8(i, @@ -486,7 +501,7 @@ Hacl_Streaming_MD_state_32 *Hacl_Streaming_SHA2_create_in_256(void) Hacl_Streaming_MD_state_32 *p = (Hacl_Streaming_MD_state_32 *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_MD_state_32)); p[0U] = s; - sha256_init(block_state); + Hacl_SHA2_Scalar32_sha256_init(block_state); return p; } @@ -522,20 +537,20 @@ void Hacl_Streaming_SHA2_init_256(Hacl_Streaming_MD_state_32 *s) Hacl_Streaming_MD_state_32 scrut = *s; uint8_t *buf = scrut.buf; uint32_t *block_state = scrut.block_state; - sha256_init(block_state); + Hacl_SHA2_Scalar32_sha256_init(block_state); Hacl_Streaming_MD_state_32 tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)(uint32_t)0U }; s[0U] = tmp; } -static inline uint32_t +static inline Hacl_Streaming_Types_error_code update_224_256(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) { Hacl_Streaming_MD_state_32 s = *p; uint64_t total_len = s.total_len; if ((uint64_t)len > (uint64_t)2305843009213693951U - total_len) { - return (uint32_t)1U; + return Hacl_Streaming_Types_MaximumLengthExceeded; } uint32_t sz; if (total_len % (uint64_t)(uint32_t)64U == (uint64_t)0U && total_len > (uint64_t)0U) @@ -591,7 +606,7 @@ update_224_256(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) } if (!(sz1 == (uint32_t)0U)) { - sha256_update_nblocks((uint32_t)64U, buf, block_state1); + Hacl_SHA2_Scalar32_sha256_update_nblocks((uint32_t)64U, buf, block_state1); } uint32_t ite; if ((uint64_t)len % (uint64_t)(uint32_t)64U == (uint64_t)0U && (uint64_t)len > (uint64_t)0U) @@ -607,7 +622,9 @@ update_224_256(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) uint32_t data2_len = len - data1_len; uint8_t *data1 = data; uint8_t *data2 = data + data1_len; - sha256_update_nblocks(data1_len, data1, block_state1); + Hacl_SHA2_Scalar32_sha256_update_nblocks(data1_len / (uint32_t)64U * (uint32_t)64U, + data1, + block_state1); uint8_t *dst = buf; memcpy(dst, data2, data2_len * sizeof (uint8_t)); *p @@ -665,7 +682,7 @@ update_224_256(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) } if (!(sz1 == (uint32_t)0U)) { - sha256_update_nblocks((uint32_t)64U, buf, block_state1); + Hacl_SHA2_Scalar32_sha256_update_nblocks((uint32_t)64U, buf, block_state1); } uint32_t ite; if @@ -687,7 +704,9 @@ update_224_256(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) uint32_t data2_len = len - diff - data1_len; uint8_t *data11 = data2; uint8_t *data21 = data2 + data1_len; - sha256_update_nblocks(data1_len, data11, block_state1); + Hacl_SHA2_Scalar32_sha256_update_nblocks(data1_len / (uint32_t)64U * (uint32_t)64U, + data11, + block_state1); uint8_t *dst = buf; memcpy(dst, data21, data2_len * sizeof (uint8_t)); *p @@ -700,7 +719,7 @@ update_224_256(Hacl_Streaming_MD_state_32 *p, uint8_t *data, uint32_t len) } ); } - return (uint32_t)0U; + return Hacl_Streaming_Types_Success; } /** @@ -710,7 +729,7 @@ success, or 1 if the combined length of all of the data passed to `update_256` This function is identical to the update function for SHA2_224. */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_256( Hacl_Streaming_MD_state_32 *p, uint8_t *input, @@ -755,10 +774,13 @@ void Hacl_Streaming_SHA2_finish_256(Hacl_Streaming_MD_state_32 *p, uint8_t *dst) } uint8_t *buf_last = buf_1 + r - ite; uint8_t *buf_multi = buf_1; - sha256_update_nblocks((uint32_t)0U, buf_multi, tmp_block_state); + Hacl_SHA2_Scalar32_sha256_update_nblocks((uint32_t)0U, buf_multi, tmp_block_state); uint64_t prev_len_last = total_len - (uint64_t)r; - sha256_update_last(prev_len_last + (uint64_t)r, r, buf_last, tmp_block_state); - sha256_finish(tmp_block_state, dst); + Hacl_SHA2_Scalar32_sha256_update_last(prev_len_last + (uint64_t)r, + r, + buf_last, + tmp_block_state); + Hacl_SHA2_Scalar32_sha256_finish(tmp_block_state, dst); } /** @@ -779,20 +801,20 @@ void Hacl_Streaming_SHA2_free_256(Hacl_Streaming_MD_state_32 *s) /** Hash `input`, of len `input_len`, into `dst`, an array of 32 bytes. */ -void Hacl_Streaming_SHA2_sha256(uint8_t *input, uint32_t input_len, uint8_t *dst) +void Hacl_Streaming_SHA2_hash_256(uint8_t *input, uint32_t input_len, uint8_t *dst) { uint8_t *ib = input; uint8_t *rb = dst; uint32_t st[8U] = { 0U }; - sha256_init(st); + Hacl_SHA2_Scalar32_sha256_init(st); uint32_t rem = input_len % (uint32_t)64U; uint64_t len_ = (uint64_t)input_len; - sha256_update_nblocks(input_len, ib, st); + Hacl_SHA2_Scalar32_sha256_update_nblocks(input_len, ib, st); uint32_t rem1 = input_len % (uint32_t)64U; uint8_t *b0 = ib; uint8_t *lb = b0 + input_len - rem1; - sha256_update_last(len_, rem, lb, st); - sha256_finish(st, rb); + Hacl_SHA2_Scalar32_sha256_update_last(len_, rem, lb, st); + Hacl_SHA2_Scalar32_sha256_finish(st, rb); } Hacl_Streaming_MD_state_32 *Hacl_Streaming_SHA2_create_in_224(void) @@ -804,7 +826,7 @@ Hacl_Streaming_MD_state_32 *Hacl_Streaming_SHA2_create_in_224(void) Hacl_Streaming_MD_state_32 *p = (Hacl_Streaming_MD_state_32 *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_MD_state_32)); p[0U] = s; - sha224_init(block_state); + Hacl_SHA2_Scalar32_sha224_init(block_state); return p; } @@ -813,13 +835,13 @@ void Hacl_Streaming_SHA2_init_224(Hacl_Streaming_MD_state_32 *s) Hacl_Streaming_MD_state_32 scrut = *s; uint8_t *buf = scrut.buf; uint32_t *block_state = scrut.block_state; - sha224_init(block_state); + Hacl_SHA2_Scalar32_sha224_init(block_state); Hacl_Streaming_MD_state_32 tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)(uint32_t)0U }; s[0U] = tmp; } -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_224( Hacl_Streaming_MD_state_32 *p, uint8_t *input, @@ -865,8 +887,11 @@ void Hacl_Streaming_SHA2_finish_224(Hacl_Streaming_MD_state_32 *p, uint8_t *dst) uint8_t *buf_multi = buf_1; sha224_update_nblocks((uint32_t)0U, buf_multi, tmp_block_state); uint64_t prev_len_last = total_len - (uint64_t)r; - sha224_update_last(prev_len_last + (uint64_t)r, r, buf_last, tmp_block_state); - sha224_finish(tmp_block_state, dst); + Hacl_SHA2_Scalar32_sha224_update_last(prev_len_last + (uint64_t)r, + r, + buf_last, + tmp_block_state); + Hacl_SHA2_Scalar32_sha224_finish(tmp_block_state, dst); } void Hacl_Streaming_SHA2_free_224(Hacl_Streaming_MD_state_32 *p) @@ -877,20 +902,20 @@ void Hacl_Streaming_SHA2_free_224(Hacl_Streaming_MD_state_32 *p) /** Hash `input`, of len `input_len`, into `dst`, an array of 28 bytes. */ -void Hacl_Streaming_SHA2_sha224(uint8_t *input, uint32_t input_len, uint8_t *dst) +void Hacl_Streaming_SHA2_hash_224(uint8_t *input, uint32_t input_len, uint8_t *dst) { uint8_t *ib = input; uint8_t *rb = dst; uint32_t st[8U] = { 0U }; - sha224_init(st); + Hacl_SHA2_Scalar32_sha224_init(st); uint32_t rem = input_len % (uint32_t)64U; uint64_t len_ = (uint64_t)input_len; sha224_update_nblocks(input_len, ib, st); uint32_t rem1 = input_len % (uint32_t)64U; uint8_t *b0 = ib; uint8_t *lb = b0 + input_len - rem1; - sha224_update_last(len_, rem, lb, st); - sha224_finish(st, rb); + Hacl_SHA2_Scalar32_sha224_update_last(len_, rem, lb, st); + Hacl_SHA2_Scalar32_sha224_finish(st, rb); } Hacl_Streaming_MD_state_64 *Hacl_Streaming_SHA2_create_in_512(void) @@ -941,14 +966,14 @@ void Hacl_Streaming_SHA2_init_512(Hacl_Streaming_MD_state_64 *s) s[0U] = tmp; } -static inline uint32_t +static inline Hacl_Streaming_Types_error_code update_384_512(Hacl_Streaming_MD_state_64 *p, uint8_t *data, uint32_t len) { Hacl_Streaming_MD_state_64 s = *p; uint64_t total_len = s.total_len; if ((uint64_t)len > (uint64_t)18446744073709551615U - total_len) { - return (uint32_t)1U; + return Hacl_Streaming_Types_MaximumLengthExceeded; } uint32_t sz; if (total_len % (uint64_t)(uint32_t)128U == (uint64_t)0U && total_len > (uint64_t)0U) @@ -1004,7 +1029,7 @@ update_384_512(Hacl_Streaming_MD_state_64 *p, uint8_t *data, uint32_t len) } if (!(sz1 == (uint32_t)0U)) { - sha512_update_nblocks((uint32_t)128U, buf, block_state1); + Hacl_SHA2_Scalar32_sha512_update_nblocks((uint32_t)128U, buf, block_state1); } uint32_t ite; if ((uint64_t)len % (uint64_t)(uint32_t)128U == (uint64_t)0U && (uint64_t)len > (uint64_t)0U) @@ -1020,7 +1045,9 @@ update_384_512(Hacl_Streaming_MD_state_64 *p, uint8_t *data, uint32_t len) uint32_t data2_len = len - data1_len; uint8_t *data1 = data; uint8_t *data2 = data + data1_len; - sha512_update_nblocks(data1_len, data1, block_state1); + Hacl_SHA2_Scalar32_sha512_update_nblocks(data1_len / (uint32_t)128U * (uint32_t)128U, + data1, + block_state1); uint8_t *dst = buf; memcpy(dst, data2, data2_len * sizeof (uint8_t)); *p @@ -1078,7 +1105,7 @@ update_384_512(Hacl_Streaming_MD_state_64 *p, uint8_t *data, uint32_t len) } if (!(sz1 == (uint32_t)0U)) { - sha512_update_nblocks((uint32_t)128U, buf, block_state1); + Hacl_SHA2_Scalar32_sha512_update_nblocks((uint32_t)128U, buf, block_state1); } uint32_t ite; if @@ -1100,7 +1127,9 @@ update_384_512(Hacl_Streaming_MD_state_64 *p, uint8_t *data, uint32_t len) uint32_t data2_len = len - diff - data1_len; uint8_t *data11 = data2; uint8_t *data21 = data2 + data1_len; - sha512_update_nblocks(data1_len, data11, block_state1); + Hacl_SHA2_Scalar32_sha512_update_nblocks(data1_len / (uint32_t)128U * (uint32_t)128U, + data11, + block_state1); uint8_t *dst = buf; memcpy(dst, data21, data2_len * sizeof (uint8_t)); *p @@ -1113,7 +1142,7 @@ update_384_512(Hacl_Streaming_MD_state_64 *p, uint8_t *data, uint32_t len) } ); } - return (uint32_t)0U; + return Hacl_Streaming_Types_Success; } /** @@ -1123,7 +1152,7 @@ success, or 1 if the combined length of all of the data passed to `update_512` This function is identical to the update function for SHA2_384. */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_512( Hacl_Streaming_MD_state_64 *p, uint8_t *input, @@ -1168,14 +1197,14 @@ void Hacl_Streaming_SHA2_finish_512(Hacl_Streaming_MD_state_64 *p, uint8_t *dst) } uint8_t *buf_last = buf_1 + r - ite; uint8_t *buf_multi = buf_1; - sha512_update_nblocks((uint32_t)0U, buf_multi, tmp_block_state); + Hacl_SHA2_Scalar32_sha512_update_nblocks((uint32_t)0U, buf_multi, tmp_block_state); uint64_t prev_len_last = total_len - (uint64_t)r; - sha512_update_last(FStar_UInt128_add(FStar_UInt128_uint64_to_uint128(prev_len_last), + Hacl_SHA2_Scalar32_sha512_update_last(FStar_UInt128_add(FStar_UInt128_uint64_to_uint128(prev_len_last), FStar_UInt128_uint64_to_uint128((uint64_t)r)), r, buf_last, tmp_block_state); - sha512_finish(tmp_block_state, dst); + Hacl_SHA2_Scalar32_sha512_finish(tmp_block_state, dst); } /** @@ -1196,7 +1225,7 @@ void Hacl_Streaming_SHA2_free_512(Hacl_Streaming_MD_state_64 *s) /** Hash `input`, of len `input_len`, into `dst`, an array of 64 bytes. */ -void Hacl_Streaming_SHA2_sha512(uint8_t *input, uint32_t input_len, uint8_t *dst) +void Hacl_Streaming_SHA2_hash_512(uint8_t *input, uint32_t input_len, uint8_t *dst) { uint8_t *ib = input; uint8_t *rb = dst; @@ -1204,12 +1233,12 @@ void Hacl_Streaming_SHA2_sha512(uint8_t *input, uint32_t input_len, uint8_t *dst Hacl_SHA2_Scalar32_sha512_init(st); uint32_t rem = input_len % (uint32_t)128U; FStar_UInt128_uint128 len_ = FStar_UInt128_uint64_to_uint128((uint64_t)input_len); - sha512_update_nblocks(input_len, ib, st); + Hacl_SHA2_Scalar32_sha512_update_nblocks(input_len, ib, st); uint32_t rem1 = input_len % (uint32_t)128U; uint8_t *b0 = ib; uint8_t *lb = b0 + input_len - rem1; - sha512_update_last(len_, rem, lb, st); - sha512_finish(st, rb); + Hacl_SHA2_Scalar32_sha512_update_last(len_, rem, lb, st); + Hacl_SHA2_Scalar32_sha512_finish(st, rb); } Hacl_Streaming_MD_state_64 *Hacl_Streaming_SHA2_create_in_384(void) @@ -1221,7 +1250,7 @@ Hacl_Streaming_MD_state_64 *Hacl_Streaming_SHA2_create_in_384(void) Hacl_Streaming_MD_state_64 *p = (Hacl_Streaming_MD_state_64 *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_MD_state_64)); p[0U] = s; - sha384_init(block_state); + Hacl_SHA2_Scalar32_sha384_init(block_state); return p; } @@ -1230,13 +1259,13 @@ void Hacl_Streaming_SHA2_init_384(Hacl_Streaming_MD_state_64 *s) Hacl_Streaming_MD_state_64 scrut = *s; uint8_t *buf = scrut.buf; uint64_t *block_state = scrut.block_state; - sha384_init(block_state); + Hacl_SHA2_Scalar32_sha384_init(block_state); Hacl_Streaming_MD_state_64 tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)(uint32_t)0U }; s[0U] = tmp; } -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_384( Hacl_Streaming_MD_state_64 *p, uint8_t *input, @@ -1280,14 +1309,14 @@ void Hacl_Streaming_SHA2_finish_384(Hacl_Streaming_MD_state_64 *p, uint8_t *dst) } uint8_t *buf_last = buf_1 + r - ite; uint8_t *buf_multi = buf_1; - sha384_update_nblocks((uint32_t)0U, buf_multi, tmp_block_state); + Hacl_SHA2_Scalar32_sha384_update_nblocks((uint32_t)0U, buf_multi, tmp_block_state); uint64_t prev_len_last = total_len - (uint64_t)r; - sha384_update_last(FStar_UInt128_add(FStar_UInt128_uint64_to_uint128(prev_len_last), + Hacl_SHA2_Scalar32_sha384_update_last(FStar_UInt128_add(FStar_UInt128_uint64_to_uint128(prev_len_last), FStar_UInt128_uint64_to_uint128((uint64_t)r)), r, buf_last, tmp_block_state); - sha384_finish(tmp_block_state, dst); + Hacl_SHA2_Scalar32_sha384_finish(tmp_block_state, dst); } void Hacl_Streaming_SHA2_free_384(Hacl_Streaming_MD_state_64 *p) @@ -1298,19 +1327,19 @@ void Hacl_Streaming_SHA2_free_384(Hacl_Streaming_MD_state_64 *p) /** Hash `input`, of len `input_len`, into `dst`, an array of 48 bytes. */ -void Hacl_Streaming_SHA2_sha384(uint8_t *input, uint32_t input_len, uint8_t *dst) +void Hacl_Streaming_SHA2_hash_384(uint8_t *input, uint32_t input_len, uint8_t *dst) { uint8_t *ib = input; uint8_t *rb = dst; uint64_t st[8U] = { 0U }; - sha384_init(st); + Hacl_SHA2_Scalar32_sha384_init(st); uint32_t rem = input_len % (uint32_t)128U; FStar_UInt128_uint128 len_ = FStar_UInt128_uint64_to_uint128((uint64_t)input_len); - sha384_update_nblocks(input_len, ib, st); + Hacl_SHA2_Scalar32_sha384_update_nblocks(input_len, ib, st); uint32_t rem1 = input_len % (uint32_t)128U; uint8_t *b0 = ib; uint8_t *lb = b0 + input_len - rem1; - sha384_update_last(len_, rem, lb, st); - sha384_finish(st, rb); + Hacl_SHA2_Scalar32_sha384_update_last(len_, rem, lb, st); + Hacl_SHA2_Scalar32_sha384_finish(st, rb); } diff --git a/Modules/_hacl/Hacl_Streaming_SHA2.h b/Modules/_hacl/Hacl_Hash_SHA2.h similarity index 91% rename from Modules/_hacl/Hacl_Streaming_SHA2.h rename to Modules/_hacl/Hacl_Hash_SHA2.h index b58df4c4d121c9..a0e731094dfaa5 100644 --- a/Modules/_hacl/Hacl_Streaming_SHA2.h +++ b/Modules/_hacl/Hacl_Hash_SHA2.h @@ -23,8 +23,8 @@ */ -#ifndef __Hacl_Streaming_SHA2_H -#define __Hacl_Streaming_SHA2_H +#ifndef __Hacl_Hash_SHA2_H +#define __Hacl_Hash_SHA2_H #if defined(__cplusplus) extern "C" { @@ -73,7 +73,7 @@ success, or 1 if the combined length of all of the data passed to `update_256` This function is identical to the update function for SHA2_224. */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_256( Hacl_Streaming_MD_state_32 *p, uint8_t *input, @@ -98,13 +98,13 @@ void Hacl_Streaming_SHA2_free_256(Hacl_Streaming_MD_state_32 *s); /** Hash `input`, of len `input_len`, into `dst`, an array of 32 bytes. */ -void Hacl_Streaming_SHA2_sha256(uint8_t *input, uint32_t input_len, uint8_t *dst); +void Hacl_Streaming_SHA2_hash_256(uint8_t *input, uint32_t input_len, uint8_t *dst); Hacl_Streaming_MD_state_32 *Hacl_Streaming_SHA2_create_in_224(void); void Hacl_Streaming_SHA2_init_224(Hacl_Streaming_MD_state_32 *s); -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_224( Hacl_Streaming_MD_state_32 *p, uint8_t *input, @@ -123,7 +123,7 @@ void Hacl_Streaming_SHA2_free_224(Hacl_Streaming_MD_state_32 *p); /** Hash `input`, of len `input_len`, into `dst`, an array of 28 bytes. */ -void Hacl_Streaming_SHA2_sha224(uint8_t *input, uint32_t input_len, uint8_t *dst); +void Hacl_Streaming_SHA2_hash_224(uint8_t *input, uint32_t input_len, uint8_t *dst); Hacl_Streaming_MD_state_64 *Hacl_Streaming_SHA2_create_in_512(void); @@ -144,7 +144,7 @@ success, or 1 if the combined length of all of the data passed to `update_512` This function is identical to the update function for SHA2_384. */ -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_512( Hacl_Streaming_MD_state_64 *p, uint8_t *input, @@ -169,13 +169,13 @@ void Hacl_Streaming_SHA2_free_512(Hacl_Streaming_MD_state_64 *s); /** Hash `input`, of len `input_len`, into `dst`, an array of 64 bytes. */ -void Hacl_Streaming_SHA2_sha512(uint8_t *input, uint32_t input_len, uint8_t *dst); +void Hacl_Streaming_SHA2_hash_512(uint8_t *input, uint32_t input_len, uint8_t *dst); Hacl_Streaming_MD_state_64 *Hacl_Streaming_SHA2_create_in_384(void); void Hacl_Streaming_SHA2_init_384(Hacl_Streaming_MD_state_64 *s); -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_SHA2_update_384( Hacl_Streaming_MD_state_64 *p, uint8_t *input, @@ -194,11 +194,11 @@ void Hacl_Streaming_SHA2_free_384(Hacl_Streaming_MD_state_64 *p); /** Hash `input`, of len `input_len`, into `dst`, an array of 48 bytes. */ -void Hacl_Streaming_SHA2_sha384(uint8_t *input, uint32_t input_len, uint8_t *dst); +void Hacl_Streaming_SHA2_hash_384(uint8_t *input, uint32_t input_len, uint8_t *dst); #if defined(__cplusplus) } #endif -#define __Hacl_Streaming_SHA2_H_DEFINED +#define __Hacl_Hash_SHA2_H_DEFINED #endif diff --git a/Modules/_hacl/Hacl_Hash_SHA3.c b/Modules/_hacl/Hacl_Hash_SHA3.c index 58eb436881d45c..b3febdfeb2b221 100644 --- a/Modules/_hacl/Hacl_Hash_SHA3.c +++ b/Modules/_hacl/Hacl_Hash_SHA3.c @@ -184,8 +184,7 @@ Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_ *p = (Hacl_Streaming_Keccak_state *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_Keccak_state)); p[0U] = s; uint64_t *s1 = block_state.snd; - for (uint32_t _i = 0U; _i < (uint32_t)25U; ++_i) - ((void **)s1)[_i] = (void *)(uint64_t)0U; + memset(s1, 0U, (uint32_t)25U * sizeof (uint64_t)); return p; } @@ -230,23 +229,22 @@ void Hacl_Streaming_Keccak_reset(Hacl_Streaming_Keccak_state *s) uint8_t *buf = scrut.buf; Hacl_Streaming_Keccak_hash_buf block_state = scrut.block_state; uint64_t *s1 = block_state.snd; - for (uint32_t _i = 0U; _i < (uint32_t)25U; ++_i) - ((void **)s1)[_i] = (void *)(uint64_t)0U; + memset(s1, 0U, (uint32_t)25U * sizeof (uint64_t)); Hacl_Streaming_Keccak_state tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)(uint32_t)0U }; s[0U] = tmp; } -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint32_t len) { Hacl_Streaming_Keccak_state s = *p; Hacl_Streaming_Keccak_hash_buf block_state = s.block_state; uint64_t total_len = s.total_len; Spec_Hash_Definitions_hash_alg i = block_state.fst; - if ((uint64_t)len > (uint64_t)0xffffffffffffffffU - total_len) + if ((uint64_t)len > (uint64_t)0xFFFFFFFFFFFFFFFFU - total_len) { - return (uint32_t)1U; + return Hacl_Streaming_Types_MaximumLengthExceeded; } uint32_t sz; if (total_len % (uint64_t)block_len(i) == (uint64_t)0U && total_len > (uint64_t)0U) @@ -419,7 +417,7 @@ Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint } ); } - return (uint32_t)0U; + return Hacl_Streaming_Types_Success; } static void @@ -486,32 +484,32 @@ finish_( Hacl_Impl_SHA3_squeeze(s, block_len(a11), hash_len(a11), dst); } -Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Types_error_code Hacl_Streaming_Keccak_finish(Hacl_Streaming_Keccak_state *s, uint8_t *dst) { Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s); if (a1 == Spec_Hash_Definitions_Shake128 || a1 == Spec_Hash_Definitions_Shake256) { - return Hacl_Streaming_Keccak_InvalidAlgorithm; + return Hacl_Streaming_Types_InvalidAlgorithm; } finish_(a1, s, dst, hash_len(a1)); - return Hacl_Streaming_Keccak_Success; + return Hacl_Streaming_Types_Success; } -Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Types_error_code Hacl_Streaming_Keccak_squeeze(Hacl_Streaming_Keccak_state *s, uint8_t *dst, uint32_t l) { Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s); if (!(a1 == Spec_Hash_Definitions_Shake128 || a1 == Spec_Hash_Definitions_Shake256)) { - return Hacl_Streaming_Keccak_InvalidAlgorithm; + return Hacl_Streaming_Types_InvalidAlgorithm; } if (l == (uint32_t)0U) { - return Hacl_Streaming_Keccak_InvalidLength; + return Hacl_Streaming_Types_InvalidLength; } finish_(a1, s, dst, l); - return Hacl_Streaming_Keccak_Success; + return Hacl_Streaming_Types_Success; } uint32_t Hacl_Streaming_Keccak_block_len(Hacl_Streaming_Keccak_state *s) diff --git a/Modules/_hacl/Hacl_Hash_SHA3.h b/Modules/_hacl/Hacl_Hash_SHA3.h index 2a5cf4b1844b9d..681b6af4a80e77 100644 --- a/Modules/_hacl/Hacl_Hash_SHA3.h +++ b/Modules/_hacl/Hacl_Hash_SHA3.h @@ -62,19 +62,13 @@ Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_copy(Hacl_Streaming_Keccak_st void Hacl_Streaming_Keccak_reset(Hacl_Streaming_Keccak_state *s); -uint32_t +Hacl_Streaming_Types_error_code Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint32_t len); -#define Hacl_Streaming_Keccak_Success 0 -#define Hacl_Streaming_Keccak_InvalidAlgorithm 1 -#define Hacl_Streaming_Keccak_InvalidLength 2 - -typedef uint8_t Hacl_Streaming_Keccak_error_code; - -Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Types_error_code Hacl_Streaming_Keccak_finish(Hacl_Streaming_Keccak_state *s, uint8_t *dst); -Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Types_error_code Hacl_Streaming_Keccak_squeeze(Hacl_Streaming_Keccak_state *s, uint8_t *dst, uint32_t l); uint32_t Hacl_Streaming_Keccak_block_len(Hacl_Streaming_Keccak_state *s); diff --git a/Modules/_hacl/Hacl_Streaming_Types.h b/Modules/_hacl/Hacl_Streaming_Types.h index 8a60b707bc4958..15ef16ba6075a9 100644 --- a/Modules/_hacl/Hacl_Streaming_Types.h +++ b/Modules/_hacl/Hacl_Streaming_Types.h @@ -52,6 +52,13 @@ extern "C" { typedef uint8_t Spec_Hash_Definitions_hash_alg; +#define Hacl_Streaming_Types_Success 0 +#define Hacl_Streaming_Types_InvalidAlgorithm 1 +#define Hacl_Streaming_Types_InvalidLength 2 +#define Hacl_Streaming_Types_MaximumLengthExceeded 3 + +typedef uint8_t Hacl_Streaming_Types_error_code; + typedef struct Hacl_Streaming_MD_state_32_s { uint32_t *block_state; diff --git a/Modules/_hacl/internal/Hacl_SHA2_Generic.h b/Modules/_hacl/internal/Hacl_Hash_SHA2.h similarity index 83% rename from Modules/_hacl/internal/Hacl_SHA2_Generic.h rename to Modules/_hacl/internal/Hacl_Hash_SHA2.h index 6ac47f3cf7ed36..851f7dc60c94c2 100644 --- a/Modules/_hacl/internal/Hacl_SHA2_Generic.h +++ b/Modules/_hacl/internal/Hacl_Hash_SHA2.h @@ -23,8 +23,8 @@ */ -#ifndef __internal_Hacl_SHA2_Generic_H -#define __internal_Hacl_SHA2_Generic_H +#ifndef __internal_Hacl_Hash_SHA2_H +#define __internal_Hacl_Hash_SHA2_H #if defined(__cplusplus) extern "C" { @@ -35,6 +35,9 @@ extern "C" { #include "krml/lowstar_endianness.h" #include "krml/internal/target.h" + +#include "../Hacl_Hash_SHA2.h" + static const uint32_t Hacl_Impl_SHA2_Generic_h224[8U] = @@ -124,9 +127,58 @@ Hacl_Impl_SHA2_Generic_k384_512[80U] = (uint64_t)0x5fcb6fab3ad6faecU, (uint64_t)0x6c44198c4a475817U }; +void Hacl_SHA2_Scalar32_sha256_init(uint32_t *hash); + +void Hacl_SHA2_Scalar32_sha256_update_nblocks(uint32_t len, uint8_t *b, uint32_t *st); + +void +Hacl_SHA2_Scalar32_sha256_update_last( + uint64_t totlen, + uint32_t len, + uint8_t *b, + uint32_t *hash +); + +void Hacl_SHA2_Scalar32_sha256_finish(uint32_t *st, uint8_t *h); + +void Hacl_SHA2_Scalar32_sha224_init(uint32_t *hash); + +void +Hacl_SHA2_Scalar32_sha224_update_last(uint64_t totlen, uint32_t len, uint8_t *b, uint32_t *st); + +void Hacl_SHA2_Scalar32_sha224_finish(uint32_t *st, uint8_t *h); + +void Hacl_SHA2_Scalar32_sha512_init(uint64_t *hash); + +void Hacl_SHA2_Scalar32_sha512_update_nblocks(uint32_t len, uint8_t *b, uint64_t *st); + +void +Hacl_SHA2_Scalar32_sha512_update_last( + FStar_UInt128_uint128 totlen, + uint32_t len, + uint8_t *b, + uint64_t *hash +); + +void Hacl_SHA2_Scalar32_sha512_finish(uint64_t *st, uint8_t *h); + +void Hacl_SHA2_Scalar32_sha384_init(uint64_t *hash); + +void Hacl_SHA2_Scalar32_sha384_update_nblocks(uint32_t len, uint8_t *b, uint64_t *st); + +void +Hacl_SHA2_Scalar32_sha384_update_last( + FStar_UInt128_uint128 totlen, + uint32_t len, + uint8_t *b, + uint64_t *st +); + +void Hacl_SHA2_Scalar32_sha384_finish(uint64_t *st, uint8_t *h); + #if defined(__cplusplus) } #endif -#define __internal_Hacl_SHA2_Generic_H_DEFINED +#define __internal_Hacl_Hash_SHA2_H_DEFINED #endif diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh index d2ba05f30d860f..c1b3e37f3afb9d 100755 --- a/Modules/_hacl/refresh.sh +++ b/Modules/_hacl/refresh.sh @@ -22,7 +22,7 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. -expected_hacl_star_rev=b6903a3e6458000730c3d83174d4b08d6d3e2ece +expected_hacl_star_rev=521af282fdf6d60227335120f18ae9309a4b8e8c hacl_dir="$(realpath "$1")" cd "$(dirname "$0")" @@ -40,7 +40,7 @@ fi declare -a dist_files dist_files=( - Hacl_Streaming_SHA2.h + Hacl_Hash_SHA2.h Hacl_Streaming_Types.h Hacl_Hash_SHA1.h internal/Hacl_Hash_SHA1.h @@ -48,8 +48,8 @@ dist_files=( Hacl_Hash_SHA3.h internal/Hacl_Hash_MD5.h internal/Hacl_Hash_SHA3.h - internal/Hacl_SHA2_Generic.h - Hacl_Streaming_SHA2.c + Hacl_Hash_SHA2.c + internal/Hacl_Hash_SHA2.h Hacl_Hash_SHA1.c Hacl_Hash_MD5.c Hacl_Hash_SHA3.c @@ -126,14 +126,8 @@ $sed -i -z 's!\(extern\|typedef\)[^;]*;\n\n!!g' include/krml/FStar_UInt_8_16_32_ # compilation, but this is not necessary. $sed -i 's!#include.*Hacl_Krmllib.h"!!g' "${all_files[@]}" -# This header is useful for *other* algorithms that refer to SHA2, e.g. Ed25519 -# which needs to compute a digest of a message before signing it. Here, since no -# other algorithm builds upon SHA2, this internal header is useless (and is not -# included in $dist_files). -$sed -i 's!#include.*internal/Hacl_Streaming_SHA2.h"!#include "Hacl_Streaming_SHA2.h"!g' "${all_files[@]}" - # Use globally unique names for the Hacl_ C APIs to avoid linkage conflicts. -$sed -i -z 's!#include \n!#include \n#include "python_hacl_namespaces.h"\n!' Hacl_Streaming_SHA2.h +$sed -i -z 's!#include \n!#include \n#include "python_hacl_namespaces.h"\n!' Hacl_Hash_SHA2.h # Finally, we remove a bunch of ifdefs from target.h that are, again, useful in # the general case, but not exercised by the subset of HACL* that we vendor. diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 6c7c3917198d18..db3774c81e2d92 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -45,7 +45,7 @@ class SHA512Type "SHA512object *" "&PyType_Type" /* Our SHA2 implementations defer to the HACL* verified library. */ -#include "_hacl/Hacl_Streaming_SHA2.h" +#include "_hacl/Hacl_Hash_SHA2.h" // TODO: Get rid of int digestsize in favor of Hacl state info? diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 48cd4418f90fee..43716487f91bd5 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -378,7 +378,7 @@ - + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 5c8c1444e8100e..22eb70a0f2dde4 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -782,7 +782,7 @@ Modules - + Modules From a06423388618424e2c6dab2ab503fdca5a953e38 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 16:33:52 -0700 Subject: [PATCH 0041/1206] [3.12] gh-104874: Document NewType.__supertype__ (GH-104875) (#104906) gh-104874: Document NewType.__supertype__ (GH-104875) (cherry picked from commit 41768a2bd3a8f57e6ce4e4ae9cab083b69817ec1) Co-authored-by: Jelle Zijlstra --- Doc/library/typing.rst | 12 ++++++++++++ .../2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst | 2 ++ 2 files changed, 14 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index c90cb411acde07..cd4df61c5ac3af 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1648,6 +1648,18 @@ These are not used in annotations. They are building blocks for declaring types. UserId = NewType('UserId', int) first_user = UserId(1) + .. attribute:: __module__ + + The module in which the new type is defined. + + .. attribute:: __name__ + + The name of the new type. + + .. attribute:: __supertype__ + + The type that the new type is based on. + .. versionadded:: 3.5.2 .. versionchanged:: 3.10 diff --git a/Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst b/Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst new file mode 100644 index 00000000000000..9d5904bc146421 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst @@ -0,0 +1,2 @@ +Document the ``__name__`` and ``__supertype__`` attributes of +:class:`typing.NewType`. Patch by Jelle Zijlstra. From 51eb009cef155f02c59d05ce1f0d93c50ea9085a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 17:36:13 -0700 Subject: [PATCH 0042/1206] [3.12] Fix test_importlib.test_side_effect_import() (GH-104840) (#104842) Fix test_importlib.test_side_effect_import() (GH-104840) Wait until the thread spawn by the import completes to avoid dangling threads. With this fix, the following command no longer fails: ./python -m test --fail-env-changed test_importlib -m test_side_effect_import -F -j20 (cherry picked from commit 426950993f6a39cdf3f6a3333ac8b518833c7e61) Co-authored-by: Victor Stinner --- Lib/test/test_importlib/test_threaded_import.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_importlib/test_threaded_import.py b/Lib/test/test_importlib/test_threaded_import.py index 85c3032aed53b1..68de4a66f3c703 100644 --- a/Lib/test/test_importlib/test_threaded_import.py +++ b/Lib/test/test_importlib/test_threaded_import.py @@ -238,7 +238,8 @@ def target(): self.addCleanup(forget, TESTFN) self.addCleanup(rmtree, '__pycache__') importlib.invalidate_caches() - __import__(TESTFN) + with threading_helper.wait_threads_exit(): + __import__(TESTFN) del sys.modules[TESTFN] def test_concurrent_futures_circular_import(self): From 4833f621b341a05debb794b896baab9dfe393fcc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 19:14:11 -0700 Subject: [PATCH 0043/1206] [3.12] Misc updates to Whatsnew 3.12 (GH-104912) (GH-104915) --- Doc/library/json.rst | 4 ++-- Doc/whatsnew/3.12.rst | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 00f585124a86b3..a752efd7ef2292 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -552,10 +552,10 @@ Exceptions AttrDict(mapping, **kwargs) AttrDict(iterable, **kwargs) - Subclass of :class:`dict` object that also supports attribute style dotted access. + Subclass of :class:`dict` that also supports attribute style dotted access. This class is intended for use with the :attr:`object_hook` in - :func:`json.load` and :func:`json.loads`:: + :func:`json.load` and :func:`json.loads`: .. doctest:: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 265c9f84e8fcc0..ff86cf7eba4da7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -341,7 +341,11 @@ Other Language Changes (Contributed by Nikita Sobolev in :gh:`100581`.) * :class:`slice` objects are now hashable, allowing them to be used as dict keys and - set items. (Contributed by Will Bradshaw and Furkan Onder in :gh:`101264`.) + set items. (Contributed by Will Bradshaw, Furkan Onder, and Raymond Hettinger in :gh:`101264`.) + +* :func:`sum` now uses Neumaier summation to improve accuracy when summing + floats or mixed ints and floats. + (Contributed by Raymond Hettinger in :gh:`100425`.) * Exceptions raised in a typeobject's ``__set_name__`` method are no longer wrapped by a :exc:`RuntimeError`. Context information is added to the @@ -493,12 +497,24 @@ itertools tuples where the last batch may be shorter than the rest. (Contributed by Raymond Hettinger in :gh:`98363`.) +json +---- + +* Added :class:`json.AttrDict` for use with ``object_hook`` in :func:`json.load` + or :func:`json.loads`. This is a subclass of :class:`dict` that also supports + attribute style dotted access. + (Contributed by Raymond Hettinger in :gh:`96145`.) + math ---- * Added :func:`math.sumprod` for computing a sum of products. (Contributed by Raymond Hettinger in :gh:`100485`.) +* Extended :func:`math.nextafter` to include a *steps* argument + for moving up or down multiple steps at a time. + (By Matthias Goergens, Mark Dickinson, and Raymond Hettinger in :gh:`94906`.) + os -- @@ -541,6 +557,15 @@ pdb value. (Contributed by Tian Gao in :gh:`103693`.) +random +------ + +* Added :func:`random.binomialvariate`. + (Contributed by Raymond Hettinger in :gh:`81620`.) + +* Added a default of ``lamb=1.0`` to :func:`random.expovariate`. + (Contributed by Raymond Hettinger in :gh:`100234`.) + shutil ------ @@ -594,6 +619,13 @@ sqlite3 to make configuration changes to a database connection. (Contributed by Erlend E. Aasland in :gh:`103489`.) +statistics +---------- + +* Extended :func:`statistics.correlation` to include as a ``ranked`` method + for computing the Spearman correlation of ranked data. + (Contributed by Raymond Hettinger in :gh:`95861`.) + threading --------- @@ -915,6 +947,7 @@ APIs: * :func:`!unittest.makeSuite` (:gh:`50096`) * :func:`!unittest.getTestCaseNames` (:gh:`50096`) * :class:`!webbrowser.MacOSX` (:gh:`86421`) +* :class:`classmethod` descriptor chaining (:gh:`89519`) Pending Removal in Python 3.14 ------------------------------ From 1a47d11f35973feb222fc0921b002633595f289c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 24 May 2023 20:39:41 -0700 Subject: [PATCH 0044/1206] [3.12] Misc improvements to the itertools docs (GH-104916) (GH-104917) --- Doc/library/itertools.rst | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index a0d794017e2602..b3decaef9c49d1 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -147,10 +147,10 @@ loops that truncate the stream. >>> list(accumulate(data, max)) # running maximum [3, 4, 6, 6, 6, 9, 9, 9, 9, 9] - # Amortize a 5% loan of 1000 with 4 annual payments of 90 - >>> cashflows = [1000, -90, -90, -90, -90] - >>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt)) - [1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001] + # Amortize a 5% loan of 1000 with 10 annual payments of 90 + >>> account_update = lambda bal, pmt: round(bal * 1.05) + pmt + >>> list(accumulate(repeat(-90, 10), account_update, initial=1_000)) + [1000, 960, 918, 874, 828, 779, 728, 674, 618, 559, 497] See :func:`functools.reduce` for a similar function that returns only the final accumulated value. @@ -951,7 +951,10 @@ which incur interpreter overhead. nexts = cycle(islice(nexts, num_active)) def partition(pred, iterable): - "Use a predicate to partition entries into false entries and true entries" + """Partition entries into false entries and true entries. + + If *pred* is slow, consider wrapping it with functools.lru_cache(). + """ # partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9 t1, t2 = tee(iterable) return filterfalse(pred, t1), filter(pred, t2) @@ -1031,7 +1034,7 @@ The following recipes have a more mathematical flavor: return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) def sieve(n): - "Primes less than n" + "Primes less than n." # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 data = bytearray((0, 1)) * (n // 2) data[:3] = 0, 0, 0 @@ -1068,7 +1071,7 @@ The following recipes have a more mathematical flavor: def matmul(m1, m2): "Multiply two matrices." - # matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]) --> (49, 80), (41, 60) + # matmul([(7, 5), (3, 5)], [(2, 5), (7, 9)]) --> (49, 80), (41, 60) n = len(m2[0]) return batched(starmap(math.sumprod, product(m1, transpose(m2))), n) @@ -1109,6 +1112,17 @@ The following recipes have a more mathematical flavor: powers = map(pow, repeat(x), reversed(range(n))) return math.sumprod(coefficients, powers) + def polynomial_derivative(coefficients): + """Compute the first derivative of a polynomial. + + f(x) = x³ -4x² -17x + 60 + f'(x) = 3x² -8x -17 + """ + # polynomial_derivative([1, -4, -17, 60]) -> [3, -8, -17] + n = len(coefficients) + powers = reversed(range(1, n)) + return list(map(operator.mul, coefficients, powers)) + def nth_combination(iterable, r, index): "Equivalent to list(combinations(iterable, r))[index]" pool = tuple(iterable) @@ -1297,6 +1311,9 @@ The following recipes have a more mathematical flavor: >>> all(factored(x) == expanded(x) for x in range(-10, 11)) True + >>> polynomial_derivative([1, -4, -17, 60]) + [3, -8, -17] + >>> list(iter_index('AABCADEAF', 'A')) [0, 1, 4, 7] >>> list(iter_index('AABCADEAF', 'B')) From b328ba194157ab5191d056608d35ab4353fc61af Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 May 2023 06:16:20 -0700 Subject: [PATCH 0045/1206] [3.12] Fix indentation in `json.AttrDict` REPL example (GH-104930) (#104931) Fix indentation in `json.AttrDict` REPL example (GH-104930) This is causing the docs to be rendered incorrectly. (cherry picked from commit 38539ef1267f26a8b3508fcc8c6199cf46fc300b) Co-authored-by: Alex Waygood --- Doc/library/json.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst index a752efd7ef2292..ef58dd09423640 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -559,14 +559,14 @@ Exceptions .. doctest:: - >>> json_string = '{"mercury": 88, "venus": 225, "earth": 365, "mars": 687}' - >>> orbital_period = json.loads(json_string, object_hook=AttrDict) - >>> orbital_period['earth'] # Dict style lookup - 365 - >>> orbital_period.earth # Attribute style lookup - 365 - >>> orbital_period.keys() # All dict methods are present - dict_keys(['mercury', 'venus', 'earth', 'mars']) + >>> json_string = '{"mercury": 88, "venus": 225, "earth": 365, "mars": 687}' + >>> orbital_period = json.loads(json_string, object_hook=AttrDict) + >>> orbital_period['earth'] # Dict style lookup + 365 + >>> orbital_period.earth # Attribute style lookup + 365 + >>> orbital_period.keys() # All dict methods are present + dict_keys(['mercury', 'venus', 'earth', 'mars']) Attribute style access only works for keys that are valid attribute names. In contrast, dictionary style access works for all keys. For From d176f78ec23116bedaa8c5ad27fe5ca323deebaf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 May 2023 08:49:46 -0700 Subject: [PATCH 0046/1206] Improves the Windows MSI test run on PR (GH-104929) Correctly set the exit code when builds fail Also build docs as part of the test (cherry picked from commit 569b2b8d612354062b8679d2d3f44f7ee03e66c2) Co-authored-by: Steve Dower --- .github/workflows/build_msi.yml | 4 ++- Tools/msi/build.bat | 58 ++++++++++++++------------------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 2bed09014e0ff2..22f613a88aa11e 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -8,12 +8,14 @@ on: - '3.*' paths: - 'Tools/msi/**' + - '.github/workflows/build_msi.yml' pull_request: branches: - 'main' - '3.*' paths: - 'Tools/msi/**' + - '.github/workflows/build_msi.yml' permissions: contents: read @@ -33,4 +35,4 @@ jobs: steps: - uses: actions/checkout@v3 - name: Build CPython installer - run: .\Tools\msi\build.bat -${{ matrix.type }} + run: .\Tools\msi\build.bat --doc -${{ matrix.type }} diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat index 8771d004211ea9..b9aab887c4939b 100644 --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -29,29 +29,23 @@ call "%D%get_externals.bat" call "%PCBUILD%find_msbuild.bat" %MSBUILD% if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable & exit /b 2) -if defined BUILDX86 ( - call "%PCBUILD%build.bat" -p Win32 -d -e %REBUILD% %BUILDTEST% - if errorlevel 1 exit /B %ERRORLEVEL% - call "%PCBUILD%build.bat" -p Win32 -e %REBUILD% %BUILDTEST% - if errorlevel 1 exit /B %ERRORLEVEL% -) -if defined BUILDX64 ( - call "%PCBUILD%build.bat" -p x64 -d -e %REBUILD% %BUILDTEST% - if errorlevel 1 exit /B %ERRORLEVEL% - call "%PCBUILD%build.bat" -p x64 -e %REBUILD% %BUILDTEST% - if errorlevel 1 exit /B %ERRORLEVEL% -) -if defined BUILDARM64 ( - call "%PCBUILD%build.bat" -p ARM64 -d -e %REBUILD% %BUILDTEST% - if errorlevel 1 exit /B %ERRORLEVEL% - call "%PCBUILD%build.bat" -p ARM64 -e %REBUILD% %BUILDTEST% - if errorlevel 1 exit /B %ERRORLEVEL% -) +if defined BUILDX86 call "%PCBUILD%build.bat" -p Win32 -d -e %REBUILD% %BUILDTEST% +if errorlevel 1 exit /B %ERRORLEVEL% +if defined BUILDX86 call "%PCBUILD%build.bat" -p Win32 -e %REBUILD% %BUILDTEST% +if errorlevel 1 exit /B %ERRORLEVEL% -if defined BUILDDOC ( - call "%PCBUILD%..\Doc\make.bat" html - if errorlevel 1 exit /B %ERRORLEVEL% -) +if defined BUILDX64 call "%PCBUILD%build.bat" -p x64 -d -e %REBUILD% %BUILDTEST% +if errorlevel 1 exit /B %ERRORLEVEL% +if defined BUILDX64 call "%PCBUILD%build.bat" -p x64 -e %REBUILD% %BUILDTEST% +if errorlevel 1 exit /B %ERRORLEVEL% + +if defined BUILDARM64 call "%PCBUILD%build.bat" -p ARM64 -d -e %REBUILD% %BUILDTEST% +if errorlevel 1 exit /B %ERRORLEVEL% +if defined BUILDARM64 call "%PCBUILD%build.bat" -p ARM64 -e %REBUILD% %BUILDTEST% +if errorlevel 1 exit /B %ERRORLEVEL% + +if defined BUILDDOC call "%PCBUILD%..\Doc\make.bat" html +if errorlevel 1 exit /B %ERRORLEVEL% rem Build the launcher MSI separately %MSBUILD% "%D%launcher\launcher.wixproj" /p:Platform=x86 @@ -68,18 +62,14 @@ if defined REBUILD ( set BUILD_CMD=%BUILD_CMD% /t:Rebuild ) -if defined BUILDX86 ( - %MSBUILD% /p:Platform=x86 %BUILD_CMD% - if errorlevel 1 exit /B %ERRORLEVEL% -) -if defined BUILDX64 ( - %MSBUILD% /p:Platform=x64 %BUILD_CMD% - if errorlevel 1 exit /B %ERRORLEVEL% -) -if defined BUILDARM64 ( - %MSBUILD% /p:Platform=ARM64 %BUILD_CMD% - if errorlevel 1 exit /B %ERRORLEVEL% -) +if defined BUILDX86 %MSBUILD% /p:Platform=x86 %BUILD_CMD% +if errorlevel 1 exit /B %ERRORLEVEL% + +if defined BUILDX64 %MSBUILD% /p:Platform=x64 %BUILD_CMD% +if errorlevel 1 exit /B %ERRORLEVEL% + +if defined BUILDARM64 %MSBUILD% /p:Platform=ARM64 %BUILD_CMD% +if errorlevel 1 exit /B %ERRORLEVEL% exit /B 0 From 930efde4c72a38cdc98dfafc94f790638639924e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 May 2023 10:15:48 -0700 Subject: [PATCH 0047/1206] [3.12] gh-104935: typing: Fix interactions between `@runtime_checkable` and `Generic` (GH-104939) (#104941) gh-104935: typing: Fix interactions between `@runtime_checkable` and `Generic` (GH-104939) --------- (cherry picked from commit 2b7027d0b2ee2e102a24a0da27d01b8221f9351c) Co-authored-by: Jelle Zijlstra Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 42 +++++++++++++++++++ Lib/typing.py | 6 +-- ...-05-25-08-50-47.gh-issue-104935.-rm1BR.rst | 3 ++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7fe137f8d7c526..c8bf94307c8011 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2472,6 +2472,48 @@ def f(): self.assertNotIsSubclass(types.FunctionType, P) self.assertNotIsInstance(f, P) + def test_runtime_checkable_generic_non_protocol(self): + # Make sure this doesn't raise AttributeError + with self.assertRaisesRegex( + TypeError, + "@runtime_checkable can be only applied to protocol classes", + ): + @runtime_checkable + class Foo[T]: ... + + def test_runtime_checkable_generic(self): + @runtime_checkable + class Foo[T](Protocol): + def meth(self) -> T: ... + + class Impl: + def meth(self) -> int: ... + + self.assertIsSubclass(Impl, Foo) + + class NotImpl: + def method(self) -> int: ... + + self.assertNotIsSubclass(NotImpl, Foo) + + def test_pep695_generics_can_be_runtime_checkable(self): + @runtime_checkable + class HasX(Protocol): + x: int + + class Bar[T]: + x: T + def __init__(self, x): + self.x = x + + class Capybara[T]: + y: str + def __init__(self, y): + self.y = y + + self.assertIsInstance(Bar(1), HasX) + self.assertNotIsInstance(Capybara('a'), HasX) + def test_everything_implements_empty_protocol(self): @runtime_checkable class Empty(Protocol): diff --git a/Lib/typing.py b/Lib/typing.py index 88837db4b744ab..dd172b17639b33 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1899,7 +1899,7 @@ def _proto_hook(other): annotations = getattr(base, '__annotations__', {}) if (isinstance(annotations, collections.abc.Mapping) and attr in annotations and - issubclass(other, Generic) and other._is_protocol): + issubclass(other, Generic) and getattr(other, '_is_protocol', False)): break else: return NotImplemented @@ -1917,7 +1917,7 @@ def _proto_hook(other): if not (base in (object, Generic) or base.__module__ in _PROTO_ALLOWLIST and base.__name__ in _PROTO_ALLOWLIST[base.__module__] or - issubclass(base, Generic) and base._is_protocol): + issubclass(base, Generic) and getattr(base, '_is_protocol', False)): raise TypeError('Protocols can only inherit from other' ' protocols, got %r' % base) if cls.__init__ is Protocol.__init__: @@ -2064,7 +2064,7 @@ def close(self): ... Warning: this will check only the presence of the required methods, not their type signatures! """ - if not issubclass(cls, Generic) or not cls._is_protocol: + if not issubclass(cls, Generic) or not getattr(cls, '_is_protocol', False): raise TypeError('@runtime_checkable can be only applied to protocol classes,' ' got %r' % cls) cls._is_runtime_protocol = True diff --git a/Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst b/Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst new file mode 100644 index 00000000000000..7af52bce2c9185 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst @@ -0,0 +1,3 @@ +Fix bugs with the interaction between :func:`typing.runtime_checkable` and +:class:`typing.Generic` that were introduced by the :pep:`695` +implementation. Patch by Jelle Zijlstra. From 5c2971b78f7e2bdf8ed6073c7470cdfe2a4b7a69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 May 2023 13:44:29 -0700 Subject: [PATCH 0048/1206] [3.12] gh-104372: Drop the GIL around the vfork() call. (GH-104782) (#104942) gh-104372: Drop the GIL around the vfork() call. (GH-104782) On Linux where the `subprocess` module can use the `vfork` syscall for faster spawning, prevent the parent process from blocking other threads by dropping the GIL while it waits for the vfork'ed child process `exec` outcome. This prevents spawning a binary from a slow filesystem from blocking the rest of the application. Fixes GH-104372. (cherry picked from commit d08679212d9af52dd074cd4a6abb440edb944c9c) Co-authored-by: Gregory P. Smith --- Doc/library/subprocess.rst | 13 ++++++++----- ...-05-22-18-39-53.gh-issue-104372.7tDRaK.rst | 5 +++++ Modules/_posixsubprocess.c | 19 ++++++++++++++++++- 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 53dfbf827260c9..738e611c05adbf 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -57,10 +57,13 @@ underlying :class:`Popen` interface can be used directly. and combine both streams into one, use ``stdout=PIPE`` and ``stderr=STDOUT`` instead of *capture_output*. - The *timeout* argument is passed to :meth:`Popen.communicate`. If the timeout - expires, the child process will be killed and waited for. The - :exc:`TimeoutExpired` exception will be re-raised after the child process - has terminated. + A *timeout* may be specified in seconds, it is internally passed on to + :meth:`Popen.communicate`. If the timeout expires, the child process will be + killed and waited for. The :exc:`TimeoutExpired` exception will be + re-raised after the child process has terminated. The initial process + creation itself cannot be interrupted on many platform APIs so you are not + guaranteed to see a timeout exception until at least after however long + process creation takes. The *input* argument is passed to :meth:`Popen.communicate` and thus to the subprocess's stdin. If used it must be a byte sequence, or a string if @@ -734,7 +737,7 @@ arguments. code. All of the functions and methods that accept a *timeout* parameter, such as -:func:`call` and :meth:`Popen.communicate` will raise :exc:`TimeoutExpired` if +:func:`run` and :meth:`Popen.communicate` will raise :exc:`TimeoutExpired` if the timeout expires before the process exits. Exceptions defined in this module all inherit from :exc:`SubprocessError`. diff --git a/Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst b/Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst new file mode 100644 index 00000000000000..ea13ec85543ca2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst @@ -0,0 +1,5 @@ +On Linux where :mod:`subprocess` can use the ``vfork()`` syscall for faster +spawning, prevent the parent process from blocking other threads by dropping +the GIL while it waits for the vfork'ed child process ``exec()`` outcome. +This prevents spawning a binary from a slow filesystem from blocking the +rest of the application. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 63403795569a78..36470804c6a165 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -559,7 +559,7 @@ reset_signal_handlers(const sigset_t *child_sigmask) * required by POSIX but not supported natively on Linux. Another reason to * avoid this family of functions is that sharing an address space between * processes running with different privileges is inherently insecure. - * See bpo-35823 for further discussion and references. + * See https://bugs.python.org/issue35823 for discussion and references. * * In some C libraries, setrlimit() has the same thread list/signalling * behavior since resource limits were per-thread attributes before @@ -798,6 +798,7 @@ do_fork_exec(char *const exec_array[], pid_t pid; #ifdef VFORK_USABLE + PyThreadState *vfork_tstate_save; if (child_sigmask) { /* These are checked by our caller; verify them in debug builds. */ assert(uid == (uid_t)-1); @@ -805,7 +806,22 @@ do_fork_exec(char *const exec_array[], assert(extra_group_size < 0); assert(preexec_fn == Py_None); + /* Drop the GIL so that other threads can continue execution while this + * thread in the parent remains blocked per vfork-semantics on the + * child's exec syscall outcome. Exec does filesystem access which + * can take an arbitrarily long time. This addresses GH-104372. + * + * The vfork'ed child still runs in our address space. Per POSIX it + * must be limited to nothing but exec, but the Linux implementation + * is a little more usable. See the child_exec() comment - The child + * MUST NOT re-acquire the GIL. + */ + vfork_tstate_save = PyEval_SaveThread(); pid = vfork(); + if (pid != 0) { + // Not in the child process, reacquire the GIL. + PyEval_RestoreThread(vfork_tstate_save); + } if (pid == (pid_t)-1) { /* If vfork() fails, fall back to using fork(). When it isn't * allowed in a process by the kernel, vfork can return -1 @@ -819,6 +835,7 @@ do_fork_exec(char *const exec_array[], } if (pid != 0) { + // Parent process. return pid; } From 8010cefc45d6763fea0c5950db9237ce42776516 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 May 2023 23:21:15 -0700 Subject: [PATCH 0049/1206] [3.12] gh-102024: Reduced _idle_semaphore.release calls (GH-102025) (#104959) gh-102024: Reduced _idle_semaphore.release calls (GH-102025) Reduced _idle_semaphore.release calls in concurrent.futures.thread._worker _idle_semaphore.release() is now only called if only work_queue is empty. --------- (cherry picked from commit 0242e9a57aa87ed0b5cac526f65631c654a39054) Co-authored-by: Andrii Kuzmin Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Lib/concurrent/futures/thread.py | 19 +++++++++++-------- ...-02-18-22-55-48.gh-issue-102024.RUmg_D.rst | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py index 51c942f51abd37..3b3a36a5093336 100644 --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -43,7 +43,7 @@ def _python_exit(): after_in_parent=_global_shutdown_lock.release) -class _WorkItem(object): +class _WorkItem: def __init__(self, future, fn, args, kwargs): self.future = future self.fn = fn @@ -78,17 +78,20 @@ def _worker(executor_reference, work_queue, initializer, initargs): return try: while True: - work_item = work_queue.get(block=True) - if work_item is not None: - work_item.run() - # Delete references to object. See issue16284 - del work_item - - # attempt to increment idle count + try: + work_item = work_queue.get_nowait() + except queue.Empty: + # attempt to increment idle count if queue is empty executor = executor_reference() if executor is not None: executor._idle_semaphore.release() del executor + work_item = work_queue.get(block=True) + + if work_item is not None: + work_item.run() + # Delete references to object. See GH-60488 + del work_item continue executor = executor_reference() diff --git a/Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst b/Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst new file mode 100644 index 00000000000000..bb9e28e06c5554 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst @@ -0,0 +1 @@ +Reduce calls of ``_idle_semaphore.release()`` in :func:`concurrent.futures.thread._worker`. From bd2cc41d3832369e78ff96a78a1bf089f7d0594d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 25 May 2023 23:30:12 -0700 Subject: [PATCH 0050/1206] [3.12] gh-104479: Update outdated tutorial floating-point reference (GH-104681) (#104960) (cherry picked from commit 2cf04e455d8f087bd08cd1d43751007b5e41b3c5) Co-authored-by: Mark Dickinson --- Doc/tutorial/floatingpoint.rst | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Doc/tutorial/floatingpoint.rst b/Doc/tutorial/floatingpoint.rst index 306b1eba3c45b8..b88055a41fd1ff 100644 --- a/Doc/tutorial/floatingpoint.rst +++ b/Doc/tutorial/floatingpoint.rst @@ -148,7 +148,7 @@ Binary floating-point arithmetic holds many surprises like this. The problem with "0.1" is explained in precise detail below, in the "Representation Error" section. See `Examples of Floating Point Problems `_ for -a pleasant summary of how binary floating point works and the kinds of +a pleasant summary of how binary floating-point works and the kinds of problems commonly encountered in practice. Also see `The Perils of Floating Point `_ for a more complete account of other common surprises. @@ -174,7 +174,7 @@ Another form of exact arithmetic is supported by the :mod:`fractions` module which implements arithmetic based on rational numbers (so the numbers like 1/3 can be represented exactly). -If you are a heavy user of floating point operations you should take a look +If you are a heavy user of floating-point operations you should take a look at the NumPy package and many other packages for mathematical and statistical operations supplied by the SciPy project. See . @@ -268,12 +268,14 @@ decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, C++, Java, Fortran, and many others) often won't display the exact decimal number you expect. -Why is that? 1/10 is not exactly representable as a binary fraction. Almost all -machines today (November 2000) use IEEE-754 floating point arithmetic, and -almost all platforms map Python floats to IEEE-754 "double precision". 754 -doubles contain 53 bits of precision, so on input the computer strives to -convert 0.1 to the closest fraction it can of the form *J*/2**\ *N* where *J* is -an integer containing exactly 53 bits. Rewriting :: +Why is that? 1/10 is not exactly representable as a binary fraction. Since at +least 2000, almost all machines use IEEE 754 binary floating-point arithmetic, +and almost all platforms map Python floats to IEEE 754 binary64 "double +precision" values. IEEE 754 binary64 values contain 53 bits of precision, so +on input the computer strives to convert 0.1 to the closest fraction it can of +the form *J*/2**\ *N* where *J* is an integer containing exactly 53 bits. +Rewriting +:: 1 / 10 ~= J / (2**N) @@ -308,7 +310,8 @@ by rounding up: >>> q+1 7205759403792794 -Therefore the best possible approximation to 1/10 in 754 double precision is:: +Therefore the best possible approximation to 1/10 in IEEE 754 double precision +is:: 7205759403792794 / 2 ** 56 @@ -321,7 +324,7 @@ if we had not rounded up, the quotient would have been a little bit smaller than 1/10. But in no case can it be *exactly* 1/10! So the computer never "sees" 1/10: what it sees is the exact fraction given -above, the best 754 double approximation it can get: +above, the best IEEE 754 double approximation it can get: .. doctest:: From 6324458bef67c597b4278fff829b7a20cb32b64a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 00:15:56 -0700 Subject: [PATCH 0051/1206] [3.12] gh-104943: Remove mentions of old Python versions (GH-104945) (#104963) (cherry picked from commit 46857d0b2a2ac6aeb6dcce2bf2c92ddf4abe7496) Co-authored-by: Tomas R --- Lib/typing.py | 5 +---- .../2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst diff --git a/Lib/typing.py b/Lib/typing.py index dd172b17639b33..a7b2566b253421 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2715,7 +2715,7 @@ def __new__(cls, typename, bases, ns): def NamedTuple(typename, fields=None, /, **kwargs): """Typed version of namedtuple. - Usage in Python versions >= 3.6:: + Usage:: class Employee(NamedTuple): name: str @@ -2732,9 +2732,6 @@ class Employee(NamedTuple): Employee = NamedTuple('Employee', name=str, id=int) - In Python versions <= 3.5 use:: - - Employee = NamedTuple('Employee', [('name', str), ('id', int)]) """ if fields is None: fields = kwargs.items() diff --git a/Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst b/Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst new file mode 100644 index 00000000000000..bc4d03b8e95f86 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst @@ -0,0 +1 @@ +Remove mentions of old Python versions in :class:`typing.NamedTuple`. From b31cfd276ee48b51220e6dbdc8bb9d66c5c7679d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 03:33:45 -0700 Subject: [PATCH 0052/1206] [3.12] Fix typo in the tokenizer (GH-104950) (#104953) (cherry picked from commit 705e387dd81b971cb1ee5727da54adfb565f61d0) Co-authored-by: Stepfen Shawn --- Parser/tokenizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 3f34763239acda..019f533ef2a260 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -21,7 +21,7 @@ enum decoding_state { }; enum interactive_underflow_t { - /* Normal mode of operation: return a new token when asked in interactie mode */ + /* Normal mode of operation: return a new token when asked in interactive mode */ IUNDERFLOW_NORMAL, /* Forcefully return ENDMARKER when asked for a new token in interactive mode. This * can be used to prevent the tokenizer to prompt the user for new tokens */ From 83bdfa43206f9d04585d1d44ea55e1d93091a905 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 05:08:58 -0700 Subject: [PATCH 0053/1206] [3.12] gh-104924: Fix `read()able` in `http.client` log messages (gh-104926) (gh-104970) gh-104924: Fix `read()able` in `http.client` log messages (gh-104926) (cherry picked from commit 6c81d7572edbe3a5800b1128e55a2dcef03cc13c) Co-authored-by: Oleg Iarygin --- Lib/http/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/http/client.py b/Lib/http/client.py index 59a9fd72b4722f..3d98e4eb54bb45 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -1024,7 +1024,7 @@ def send(self, data): print("send:", repr(data)) if hasattr(data, "read") : if self.debuglevel > 0: - print("sendIng a read()able") + print("sending a readable") encode = self._is_textIO(data) if encode and self.debuglevel > 0: print("encoding file using iso-8859-1") @@ -1054,7 +1054,7 @@ def _output(self, s): def _read_readable(self, readable): if self.debuglevel > 0: - print("sendIng a read()able") + print("reading a readable") encode = self._is_textIO(readable) if encode and self.debuglevel > 0: print("encoding file using iso-8859-1") From 3158b4d2f92299a2d2571405ff6eb920fa9d6b50 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 06:15:08 -0700 Subject: [PATCH 0054/1206] [3.12] gh-104955: Fix __release_buffer__ signature (GH-104956) (#104973) (cherry picked from commit 6e1eccdcce5ea3bf1ef9d326d20ef9df21262c6b) Co-authored-by: Jelle Zijlstra Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Lib/test/test_inspect.py | 5 +++++ .../2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst | 2 ++ Objects/typeobject.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 0590e49d0e1a43..ade32151eaf233 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2766,6 +2766,11 @@ class ThisWorksNow: # Regression test for issue #20586 test_callable(_testcapi.docstring_with_signature_but_no_doc) + # Regression test for gh-104955 + method = bytearray.__release_buffer__ + sig = test_unbound_method(method) + self.assertEqual(list(sig.parameters), ['self', 'buffer']) + @cpython_only @unittest.skipIf(MISSING_C_DOCSTRINGS, "Signature information for builtins requires docstrings") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst new file mode 100644 index 00000000000000..9fccf2a41ffb6f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst @@ -0,0 +1,2 @@ +Fix signature for the new :meth:`~object.__release_buffer__` slot. Patch by Jelle +Zijlstra. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2fbcafe91aadc6..0a2e1b1d3c1f78 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9428,7 +9428,7 @@ static pytype_slotdef slotdefs[] = { "__buffer__($self, flags, /)\n--\n\n" "Return a buffer object that exposes the underlying memory of the object."), BUFSLOT(__release_buffer__, bf_releasebuffer, slot_bf_releasebuffer, wrap_releasebuffer, - "__release_buffer__($self, /)\n--\n\n" + "__release_buffer__($self, buffer, /)\n--\n\n" "Release the buffer object that exposes the underlying memory of the object."), AMSLOT(__await__, am_await, slot_am_await, wrap_unaryfunc, From 01af2b0e516608c831f4c6837087479f45368d21 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 07:35:35 -0700 Subject: [PATCH 0055/1206] [3.12] Remove raw asserts in test_typing.py (GH-104951) (#104978) Remove raw asserts in test_typing.py (GH-104951) (cherry picked from commit 2cb445635e99d4401949cabebd373288cfdd0138) Co-authored-by: Jelle Zijlstra --- Lib/test/test_typing.py | 52 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c8bf94307c8011..ae9878f872fd78 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -6474,7 +6474,7 @@ def __len__(self): return 0 self.assertEqual(len(MMC()), 0) - assert callable(MMC.update) + self.assertTrue(callable(MMC.update)) self.assertIsInstance(MMC(), typing.Mapping) class MMB(typing.MutableMapping[KT, VT]): @@ -6669,8 +6669,8 @@ def foo(a: A) -> Optional[BaseException]: else: return a() - assert isinstance(foo(KeyboardInterrupt), KeyboardInterrupt) - assert foo(None) is None + self.assertIsInstance(foo(KeyboardInterrupt), KeyboardInterrupt) + self.assertIsNone(foo(None)) class TestModules(TestCase): @@ -7017,6 +7017,10 @@ def test_basics_functional_syntax(self): self.assertEqual(Emp.__bases__, (dict,)) self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) self.assertEqual(Emp.__total__, True) + self.assertEqual(Emp.__required_keys__, {'name', 'id'}) + self.assertIsInstance(Emp.__required_keys__, frozenset) + self.assertEqual(Emp.__optional_keys__, set()) + self.assertIsInstance(Emp.__optional_keys__, frozenset) def test_basics_keywords_syntax(self): with self.assertWarns(DeprecationWarning): @@ -7119,7 +7123,9 @@ def test_total(self): self.assertEqual(D(x=1), {'x': 1}) self.assertEqual(D.__total__, False) self.assertEqual(D.__required_keys__, frozenset()) + self.assertIsInstance(D.__required_keys__, frozenset) self.assertEqual(D.__optional_keys__, {'x'}) + self.assertIsInstance(D.__optional_keys__, frozenset) self.assertEqual(Options(), {}) self.assertEqual(Options(log_level=2), {'log_level': 2}) @@ -7131,8 +7137,10 @@ def test_optional_keys(self): class Point2Dor3D(Point2D, total=False): z: int - assert Point2Dor3D.__required_keys__ == frozenset(['x', 'y']) - assert Point2Dor3D.__optional_keys__ == frozenset(['z']) + self.assertEqual(Point2Dor3D.__required_keys__, frozenset(['x', 'y'])) + self.assertIsInstance(Point2Dor3D.__required_keys__, frozenset) + self.assertEqual(Point2Dor3D.__optional_keys__, frozenset(['z'])) + self.assertIsInstance(Point2Dor3D.__optional_keys__, frozenset) def test_keys_inheritance(self): class BaseAnimal(TypedDict): @@ -7145,26 +7153,26 @@ class Animal(BaseAnimal, total=False): class Cat(Animal): fur_color: str - assert BaseAnimal.__required_keys__ == frozenset(['name']) - assert BaseAnimal.__optional_keys__ == frozenset([]) - assert BaseAnimal.__annotations__ == {'name': str} + self.assertEqual(BaseAnimal.__required_keys__, frozenset(['name'])) + self.assertEqual(BaseAnimal.__optional_keys__, frozenset([])) + self.assertEqual(BaseAnimal.__annotations__, {'name': str}) - assert Animal.__required_keys__ == frozenset(['name']) - assert Animal.__optional_keys__ == frozenset(['tail', 'voice']) - assert Animal.__annotations__ == { + self.assertEqual(Animal.__required_keys__, frozenset(['name'])) + self.assertEqual(Animal.__optional_keys__, frozenset(['tail', 'voice'])) + self.assertEqual(Animal.__annotations__, { 'name': str, 'tail': bool, 'voice': str, - } + }) - assert Cat.__required_keys__ == frozenset(['name', 'fur_color']) - assert Cat.__optional_keys__ == frozenset(['tail', 'voice']) - assert Cat.__annotations__ == { + self.assertEqual(Cat.__required_keys__, frozenset(['name', 'fur_color'])) + self.assertEqual(Cat.__optional_keys__, frozenset(['tail', 'voice'])) + self.assertEqual(Cat.__annotations__, { 'fur_color': str, 'name': str, 'tail': bool, 'voice': str, - } + }) def test_required_notrequired_keys(self): self.assertEqual(NontotalMovie.__required_keys__, @@ -7394,11 +7402,11 @@ class C(B[int]): self.assertEqual(C.__total__, True) self.assertEqual(C.__optional_keys__, frozenset(['b'])) self.assertEqual(C.__required_keys__, frozenset(['a', 'c'])) - assert C.__annotations__ == { + self.assertEqual(C.__annotations__, { 'a': T, 'b': KT, 'c': int, - } + }) with self.assertRaises(TypeError): C[str] @@ -7413,11 +7421,11 @@ class Point3D(Point2DGeneric[T], Generic[T, KT]): self.assertEqual(Point3D.__total__, True) self.assertEqual(Point3D.__optional_keys__, frozenset()) self.assertEqual(Point3D.__required_keys__, frozenset(['a', 'b', 'c'])) - assert Point3D.__annotations__ == { + self.assertEqual(Point3D.__annotations__, { 'a': T, 'b': T, 'c': KT, - } + }) self.assertEqual(Point3D[int, str].__origin__, Point3D) with self.assertRaises(TypeError): @@ -7444,11 +7452,11 @@ class WithImplicitAny(B): self.assertEqual(WithImplicitAny.__total__, True) self.assertEqual(WithImplicitAny.__optional_keys__, frozenset(['b'])) self.assertEqual(WithImplicitAny.__required_keys__, frozenset(['a', 'c'])) - assert WithImplicitAny.__annotations__ == { + self.assertEqual(WithImplicitAny.__annotations__, { 'a': T, 'b': KT, 'c': int, - } + }) with self.assertRaises(TypeError): WithImplicitAny[str] From 8ca29573a89f78f87380210d02f48410763f507d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 08:25:46 -0700 Subject: [PATCH 0056/1206] [3.12] gh-104972: Ensure that line attributes in tokens in the tokenize module are correct (GH-104975) (#104982) gh-104972: Ensure that line attributes in tokens in the tokenize module are correct (GH-104975) (cherry picked from commit 3fdb55c48291a459fb1e33edb5140ec0383222df) Co-authored-by: Pablo Galindo Salgado --- Lib/idlelib/idle_test/test_editor.py | 4 ++-- Lib/test/test_tokenize.py | 15 +++++++++++++-- ...2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst | 2 ++ Python/Python-tokenize.c | 9 ++++----- 4 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index ba59c40dc6dde5..9296a6d235fbbe 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -201,8 +201,8 @@ def test_searcher(self): test_info = (# text, (block, indent)) ("", (None, None)), ("[1,", (None, None)), # TokenError - ("if 1:\n", ('if 1:', None)), - ("if 1:\n 2\n 3\n", ('if 1:', ' 2')), + ("if 1:\n", ('if 1:\n', None)), + ("if 1:\n 2\n 3\n", ('if 1:\n', ' 2\n')), ) for code, expected_pair in test_info: with self.subTest(code=code): diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 251ce2b864a9d8..0b7c25838d6782 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1174,7 +1174,7 @@ def readline(): # skip the initial encoding token and the end tokens tokens = list(_tokenize(readline(), encoding='utf-8'))[:-2] - expected_tokens = [TokenInfo(3, '"ЉЊЈÐЂ"', (1, 0), (1, 7), '"ЉЊЈÐЂ"')] + expected_tokens = [TokenInfo(3, '"ЉЊЈÐЂ"', (1, 0), (1, 7), '"ЉЊЈÐЂ"\n')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") @@ -1657,7 +1657,6 @@ def check_roundtrip(self, f): code = f.encode('utf-8') else: code = f.read() - f.close() readline = iter(code.splitlines(keepends=True)).__next__ tokens5 = list(tokenize(readline)) tokens2 = [tok[:2] for tok in tokens5] @@ -1672,6 +1671,17 @@ def check_roundtrip(self, f): tokens2_from5 = [tok[:2] for tok in tokenize(readline5)] self.assertEqual(tokens2_from5, tokens2) + def check_line_extraction(self, f): + if isinstance(f, str): + code = f.encode('utf-8') + else: + code = f.read() + readline = iter(code.splitlines(keepends=True)).__next__ + for tok in tokenize(readline): + if tok.type in {ENCODING, ENDMARKER}: + continue + self.assertEqual(tok.string, tok.line[tok.start[1]: tok.end[1]]) + def test_roundtrip(self): # There are some standard formatting practices that are easy to get right. @@ -1768,6 +1778,7 @@ def test_random_files(self): with open(testfile, 'rb') as f: # with self.subTest(file=testfile): self.check_roundtrip(f) + self.check_line_extraction(f) def roundtrip(self, code): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst new file mode 100644 index 00000000000000..05d50c108c7b77 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst @@ -0,0 +1,2 @@ +Ensure that the ``line`` attribute in :class:`tokenize.TokenInfo` objects in +the :mod:`tokenize` module are always correct. Patch by Pablo Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 0023e303b96e83..88087c12562413 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -194,15 +194,14 @@ tokenizeriter_next(tokenizeriterobject *it) goto exit; } - Py_ssize_t size = it->tok->inp - it->tok->buf; - assert(it->tok->buf[size-1] == '\n'); - size -= 1; // Remove the newline character from the end of the line - PyObject *line = PyUnicode_DecodeUTF8(it->tok->buf, size, "replace"); + const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start; + Py_ssize_t size = it->tok->inp - line_start; + PyObject *line = PyUnicode_DecodeUTF8(line_start, size, "replace"); if (line == NULL) { Py_DECREF(str); goto exit; } - const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start; + Py_ssize_t lineno = ISSTRINGLIT(type) ? it->tok->first_lineno : it->tok->lineno; Py_ssize_t end_lineno = it->tok->lineno; Py_ssize_t col_offset = -1; From 97509ca2bc9f48283ceeb1f1f6acd6b6cfb8c268 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 26 May 2023 19:02:51 +0300 Subject: [PATCH 0057/1206] [3.12] CI: Cache config.cache across runs to speed up build (GH-104800) (#104967) --- .github/workflows/build.yml | 51 ++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68bebb6bf61d03..cfb7f65c0fbad1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -113,6 +113,11 @@ jobs: if: needs.check_source.outputs.run_tests == 'true' steps: - uses: actions/checkout@v3 + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} - uses: actions/setup-python@v3 - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh @@ -129,7 +134,7 @@ jobs: - name: Configure CPython run: | # Build Python with the libpython dynamic library - ./configure --with-pydebug --enable-shared + ./configure --config-cache --with-pydebug --enable-shared - name: Regenerate autoconf files with container image run: make regen-configure - name: Build CPython @@ -210,6 +215,11 @@ jobs: PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v3 + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} - name: Install Homebrew dependencies run: brew install pkg-config openssl@1.1 xz gdbm tcl-tk - name: Configure CPython @@ -218,6 +228,7 @@ jobs: LDFLAGS="-L$(brew --prefix gdbm)/lib -I$(brew --prefix xz)/lib" \ PKG_CONFIG_PATH="$(brew --prefix tcl-tk)/lib/pkgconfig" \ ./configure \ + --config-cache \ --with-pydebug \ --prefix=/opt/python-dev \ --with-openssl="$(brew --prefix openssl@1.1)" @@ -270,9 +281,18 @@ jobs: run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR - name: Bind mount sources read-only run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: ${{ env.CPYTHON_BUILDDIR }}/config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: ../cpython-ro-srcdir/configure --with-pydebug --with-openssl=$OPENSSL_DIR + run: | + ../cpython-ro-srcdir/configure \ + --config-cache \ + --with-pydebug \ + --with-openssl=$OPENSSL_DIR - name: Build CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: make -j4 @@ -303,6 +323,11 @@ jobs: LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib steps: - uses: actions/checkout@v3 + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies @@ -327,7 +352,7 @@ jobs: - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 - name: Configure CPython - run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR + run: ./configure --config-cache --with-pydebug --with-openssl=$OPENSSL_DIR - name: Build CPython run: make -j4 - name: Display build info @@ -336,7 +361,7 @@ jobs: run: ./python Lib/test/ssltests.py test_hypothesis: - name: "Hypothesis Tests on Ubuntu" + name: "Hypothesis tests on Ubuntu" runs-on: ubuntu-20.04 timeout-minutes: 60 needs: check_source @@ -377,9 +402,18 @@ jobs: run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR - name: Bind mount sources read-only run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: ${{ env.CPYTHON_BUILDDIR }}/config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: ../cpython-ro-srcdir/configure --with-pydebug --with-openssl=$OPENSSL_DIR + run: | + ../cpython-ro-srcdir/configure \ + --config-cache \ + --with-pydebug \ + --with-openssl=$OPENSSL_DIR - name: Build CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: make -j4 @@ -447,6 +481,11 @@ jobs: ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: - uses: actions/checkout@v3 + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies @@ -475,7 +514,7 @@ jobs: - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 - name: Configure CPython - run: ./configure --with-address-sanitizer --without-pymalloc + run: ./configure --config-cache --with-address-sanitizer --without-pymalloc - name: Build CPython run: make -j4 - name: Display build info From bb1e57ee40f81af266a8fd7607d773ab1d25c73b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 10:12:41 -0700 Subject: [PATCH 0058/1206] [3.12] gh-104984: remove kwargs and starargs from Call & ClassDef (GH-104986) (#104987) gh-104984: remove kwargs and starargs from Call & ClassDef (GH-104986) These fields are removed in https://github.com/python/cpython/commit/025e9ebd0a0a19f50ca83af6ada0ac65be1fa2a1 (cherry picked from commit 61c1d6760facbc172a58512cad46148f587b4da1) Co-authored-by: Shaygan Hooshyari --- Doc/library/ast.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index b6b1e076c9f08c..c75c4e3bd219b8 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -481,7 +481,7 @@ Expressions Comparison operator tokens. -.. class:: Call(func, args, keywords, starargs, kwargs) +.. class:: Call(func, args, keywords) A function call. ``func`` is the function, which will often be a :class:`Name` or :class:`Attribute` object. Of the arguments: @@ -491,7 +491,7 @@ Expressions arguments passed by keyword. When creating a ``Call`` node, ``args`` and ``keywords`` are required, but - they can be empty lists. ``starargs`` and ``kwargs`` are optional. + they can be empty lists. .. doctest:: @@ -1820,7 +1820,7 @@ Function and class definitions type_ignores=[]) -.. class:: ClassDef(name, bases, keywords, starargs, kwargs, body, decorator_list) +.. class:: ClassDef(name, bases, keywords, body, decorator_list) A class definition. @@ -1829,9 +1829,6 @@ Function and class definitions * ``keywords`` is a list of :class:`keyword` nodes, principally for 'metaclass'. Other keywords will be passed to the metaclass, as per `PEP-3115 `_. - * ``starargs`` and ``kwargs`` are each a single node, as in a function call. - starargs will be expanded to join the list of base classes, and kwargs will - be passed to the metaclass. * ``body`` is a list of nodes representing the code within the class definition. * ``decorator_list`` is a list of nodes, as in :class:`FunctionDef`. From dcee0aa9119243c294df820d6586d539ff039d3d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 11:19:34 -0700 Subject: [PATCH 0059/1206] [3.12] gh-103921: Document PEP 695 (GH-104642) (#104989) (cherry picked from commit 060277d96bf4ba86df8e4d65831a8cbdfeb51fc5) Co-authored-by: Jelle Zijlstra Co-authored-by: Alex Waygood --- Doc/library/ast.rst | 102 ++++- Doc/library/dis.rst | 111 ++++- Doc/library/stdtypes.rst | 8 + Doc/library/typing.rst | 691 ++++++++++++++++++++--------- Doc/reference/compound_stmts.rst | 244 +++++++++- Doc/reference/datamodel.rst | 12 + Doc/reference/executionmodel.rst | 116 ++++- Doc/reference/lexical_analysis.rst | 16 +- Doc/reference/simple_stmts.rst | 46 ++ Doc/whatsnew/3.12.rst | 75 +++- Objects/typevarobject.c | 115 ++--- 11 files changed, 1234 insertions(+), 302 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index c75c4e3bd219b8..8a686354b9f65c 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -917,6 +917,25 @@ Statements type_ignores=[]) +.. class:: TypeAlias(name, type_params, value) + + A :ref:`type alias ` created through the :keyword:`type` + statement. ``name`` is the name of the alias, ``type_params`` is a list of + :ref:`type parameters `, and ``value`` is the value of the + type alias. + + .. doctest:: + + >>> print(ast.dump(ast.parse('type Alias = int'), indent=4)) + Module( + body=[ + TypeAlias( + name=Name(id='Alias', ctx=Store()), + type_params=[], + value=Name(id='int', ctx=Load()))], + type_ignores=[]) + + Other statements which are only applicable inside functions or loops are described in other sections. @@ -1644,15 +1663,93 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) +.. _ast-type-params: + +Type parameters +^^^^^^^^^^^^^^^ + +:ref:`Type parameters ` can exist on classes, functions, and type +aliases. + +.. class:: TypeVar(name, bound) + + A :class:`typing.TypeVar`. ``name`` is the name of the type variable. + ``bound`` is the bound or constraints, if any. If ``bound`` is a :class:`Tuple`, + it represents constraints; otherwise it represents the bound. + + .. doctest:: + + >>> print(ast.dump(ast.parse("type Alias[T: int] = list[T]"), indent=4)) + Module( + body=[ + TypeAlias( + name=Name(id='Alias', ctx=Store()), + type_params=[ + TypeVar( + name='T', + bound=Name(id='int', ctx=Load()))], + value=Subscript( + value=Name(id='list', ctx=Load()), + slice=Name(id='T', ctx=Load()), + ctx=Load()))], + type_ignores=[]) + +.. class:: ParamSpec(name) + + A :class:`typing.ParamSpec`. ``name`` is the name of the parameter specification. + + .. doctest:: + + >>> print(ast.dump(ast.parse("type Alias[**P] = Callable[P, int]"), indent=4)) + Module( + body=[ + TypeAlias( + name=Name(id='Alias', ctx=Store()), + type_params=[ + ParamSpec(name='P')], + value=Subscript( + value=Name(id='Callable', ctx=Load()), + slice=Tuple( + elts=[ + Name(id='P', ctx=Load()), + Name(id='int', ctx=Load())], + ctx=Load()), + ctx=Load()))], + type_ignores=[]) + +.. class:: TypeVarTuple(name) + + A :class:`typing.TypeVarTuple`. ``name`` is the name of the type variable tuple. + + .. doctest:: + + >>> print(ast.dump(ast.parse("type Alias[*Ts] = tuple[*Ts]"), indent=4)) + Module( + body=[ + TypeAlias( + name=Name(id='Alias', ctx=Store()), + type_params=[ + TypeVarTuple(name='Ts')], + value=Subscript( + value=Name(id='tuple', ctx=Load()), + slice=Tuple( + elts=[ + Starred( + value=Name(id='Ts', ctx=Load()), + ctx=Load())], + ctx=Load()), + ctx=Load()))], + type_ignores=[]) Function and class definitions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. class:: FunctionDef(name, args, body, decorator_list, returns, type_comment) +.. class:: FunctionDef(name, type_params, args, body, decorator_list, returns, type_comment) A function definition. * ``name`` is a raw string of the function name. + * ``type_params`` is a list of :ref:`type parameters `. * ``args`` is an :class:`arguments` node. * ``body`` is the list of nodes inside the function. * ``decorator_list`` is the list of decorators to be applied, stored outermost @@ -1820,11 +1917,12 @@ Function and class definitions type_ignores=[]) -.. class:: ClassDef(name, bases, keywords, body, decorator_list) +.. class:: ClassDef(name, type_params, bases, keywords, body, decorator_list) A class definition. * ``name`` is a raw string for the class name + * ``type_params`` is a list of :ref:`type parameters `. * ``bases`` is a list of nodes for explicitly specified base classes. * ``keywords`` is a list of :class:`keyword` nodes, principally for 'metaclass'. Other keywords will be passed to the metaclass, as per `PEP-3115 diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 4762fb50437460..9b90f1ef23d92c 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -188,9 +188,9 @@ operation is being performed, so the intermediate analysis object isn't useful: For a module, it disassembles all functions. For a class, it disassembles all methods (including class and static methods). For a code object or sequence of raw bytecode, it prints one line per bytecode instruction. - It also recursively disassembles nested code objects (the code of - comprehensions, generator expressions and nested functions, and the code - used for building nested classes). + It also recursively disassembles nested code objects. These can include + generator expressions, nested functions, the bodies of nested classes, + and the code objects used for :ref:`annotation scopes `. Strings are first compiled to code objects with the :func:`compile` built-in function before being disassembled. If no object is provided, this function disassembles the last traceback. @@ -926,6 +926,27 @@ iterations of the loop. .. opcode:: LOAD_NAME (namei) Pushes the value associated with ``co_names[namei]`` onto the stack. + The name is looked up within the locals, then the globals, then the builtins. + + +.. opcode:: LOAD_LOCALS + + Pushes a reference to the locals dictionary onto the stack. This is used + to prepare namespace dictionaries for :opcode:`LOAD_FROM_DICT_OR_DEREF` + and :opcode:`LOAD_FROM_DICT_OR_GLOBALS`. + + .. versionadded:: 3.12 + + +.. opcode:: LOAD_FROM_DICT_OR_GLOBALS (i) + + Pops a mapping off the stack and looks up the value for ``co_names[namei]``. + If the name is not found there, looks it up in the globals and then the builtins, + similar to :opcode:`LOAD_GLOBAL`. + This is used for loading global variables in + :ref:`annotation scopes ` within class bodies. + + .. versionadded:: 3.12 .. opcode:: BUILD_TUPLE (count) @@ -1243,16 +1264,17 @@ iterations of the loop. ``i`` is no longer offset by the length of ``co_varnames``. -.. opcode:: LOAD_CLASSDEREF (i) +.. opcode:: LOAD_FROM_DICT_OR_DEREF (i) - Much like :opcode:`LOAD_DEREF` but first checks the locals dictionary before - consulting the cell. This is used for loading free variables in class - bodies. - - .. versionadded:: 3.4 + Pops a mapping off the stack and looks up the name associated with + slot ``i`` of the "fast locals" storage in this mapping. + If the name is not found there, loads it from the cell contained in + slot ``i``, similar to :opcode:`LOAD_DEREF`. This is used for loading + free variables in class bodies (which previously used + :opcode:`!LOAD_CLASSDEREF`) and in + :ref:`annotation scopes ` within class bodies. - .. versionchanged:: 3.11 - ``i`` is no longer offset by the length of ``co_varnames``. + .. versionadded:: 3.12 .. opcode:: STORE_DEREF (i) @@ -1504,13 +1526,45 @@ iterations of the loop. The operand determines which intrinsic function is called: - * ``0`` Not valid - * ``1`` Prints the argument to standard out. Used in the REPL. - * ``2`` Performs ``import *`` for the named module. - * ``3`` Extracts the return value from a ``StopIteration`` exception. - * ``4`` Wraps an aync generator value - * ``5`` Performs the unary ``+`` operation - * ``6`` Converts a list to a tuple + +-----------------------------------+-----------------------------------+ + | Operand | Description | + +===================================+===================================+ + | ``INTRINSIC_1_INVALID`` | Not valid | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_PRINT`` | Prints the argument to standard | + | | out. Used in the REPL. | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_IMPORT_STAR`` | Performs ``import *`` for the | + | | named module. | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_STOPITERATION_ERROR`` | Extracts the return value from a | + | | ``StopIteration`` exception. | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_ASYNC_GEN_WRAP`` | Wraps an aync generator value | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_UNARY_POSITIVE`` | Performs the unary ``+`` | + | | operation | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_LIST_TO_TUPLE`` | Converts a list to a tuple | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_TYPEVAR`` | Creates a :class:`typing.TypeVar` | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_PARAMSPEC`` | Creates a | + | | :class:`typing.ParamSpec` | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_TYPEVARTUPLE`` | Creates a | + | | :class:`typing.TypeVarTuple` | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_SUBSCRIPT_GENERIC`` | Returns :class:`typing.Generic` | + | | subscripted with the argument | + +-----------------------------------+-----------------------------------+ + | ``INTRINSIC_TYPEALIAS`` | Creates a | + | | :class:`typing.TypeAliasType`; | + | | used in the :keyword:`type` | + | | statement. The argument is a tuple| + | | of the type alias's name, | + | | type parameters, and value. | + +-----------------------------------+-----------------------------------+ .. versionadded:: 3.12 @@ -1522,8 +1576,25 @@ iterations of the loop. The operand determines which intrinsic function is called: - * ``0`` Not valid - * ``1`` Calculates the :exc:`ExceptionGroup` to raise from a ``try-except*``. + +----------------------------------------+-----------------------------------+ + | Operand | Description | + +========================================+===================================+ + | ``INTRINSIC_2_INVALID`` | Not valid | + +----------------------------------------+-----------------------------------+ + | ``INTRINSIC_PREP_RERAISE_STAR`` | Calculates the | + | | :exc:`ExceptionGroup` to raise | + | | from a ``try-except*``. | + +----------------------------------------+-----------------------------------+ + | ``INTRINSIC_TYPEVAR_WITH_BOUND`` | Creates a :class:`typing.TypeVar` | + | | with a bound. | + +----------------------------------------+-----------------------------------+ + | ``INTRINSIC_TYPEVAR_WITH_CONSTRAINTS`` | Creates a | + | | :class:`typing.TypeVar` with | + | | constraints. | + +----------------------------------------+-----------------------------------+ + | ``INTRINSIC_SET_FUNCTION_TYPE_PARAMS`` | Sets the ``__type_params__`` | + | | attribute of a function. | + +----------------------------------------+-----------------------------------+ .. versionadded:: 3.12 diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 9203afbf6a4e8a..fdef5314b9a4ef 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5476,6 +5476,14 @@ types, where they are relevant. Some of these are not reported by the .. versionadded:: 3.3 +.. attribute:: definition.__type_params__ + + The :ref:`type parameters ` of generic classes, functions, + and :ref:`type aliases `. + + .. versionadded:: 3.12 + + .. attribute:: class.__mro__ This attribute is a tuple of classes that are considered when looking for diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index cd4df61c5ac3af..a4bba7b5ad630b 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -101,6 +101,8 @@ annotations. These include: * :pep:`692`: Using ``TypedDict`` for more precise ``**kwargs`` typing *Introducing* a new way of typing ``**kwargs`` with :data:`Unpack` and :data:`TypedDict` +* :pep:`695`: Type Parameter Syntax + *Introducing* builtin syntax for creating generic functions, classes, and type aliases. * :pep:`698`: Adding an override decorator to typing *Introducing* the :func:`@override` decorator @@ -109,10 +111,12 @@ annotations. These include: Type aliases ============ -A type alias is defined by assigning the type to the alias. In this example, -``Vector`` and ``list[float]`` will be treated as interchangeable synonyms:: +A type alias is defined using the :keyword:`type` statement, which creates +an instance of :class:`TypeAliasType`. In this example, +``Vector`` and ``list[float]`` will be treated equivalently by static type +checkers:: - Vector = list[float] + type Vector = list[float] def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector] @@ -124,9 +128,9 @@ Type aliases are useful for simplifying complex type signatures. For example:: from collections.abc import Sequence - ConnectionOptions = dict[str, str] - Address = tuple[str, int] - Server = tuple[Address, ConnectionOptions] + type ConnectionOptions = dict[str, str] + type Address = tuple[str, int] + type Server = tuple[Address, ConnectionOptions] def broadcast_message(message: str, servers: Sequence[Server]) -> None: ... @@ -141,6 +145,18 @@ Type aliases are useful for simplifying complex type signatures. For example:: Note that ``None`` as a type hint is a special case and is replaced by ``type(None)``. +The :keyword:`type` statement is new in Python 3.12. For backwards +compatibility, type aliases can also be created through simple assignment:: + + Vector = list[float] + +Or marked with :data:`TypeAlias` to make it explicit that this is a type alias, +not a normal variable assignment:: + + from typing import TypeAlias + + Vector: TypeAlias = list[float] + .. _distinct: NewType @@ -206,7 +222,7 @@ See :pep:`484` for more details. .. note:: Recall that the use of a type alias declares two types to be *equivalent* to - one another. Doing ``Alias = Original`` will make the static type checker + one another. Doing ``type Alias = Original`` will make the static type checker treat ``Alias`` as being *exactly equivalent* to ``Original`` in all cases. This is useful when you want to simplify complex type signatures. @@ -282,19 +298,26 @@ subscription to denote expected types for container elements. def notify_by_email(employees: Sequence[Employee], overrides: Mapping[str, str]) -> None: ... -Generics can be parameterized by using a factory available in typing -called :class:`TypeVar`. +Generics can be parameterized by using :ref:`type parameter syntax `:: -:: + from collections.abc import Sequence + + def first[T](l: Sequence[T]) -> T: # Generic function + return l[0] + +Or by using the :class:`TypeVar` factory directly:: from collections.abc import Sequence from typing import TypeVar - T = TypeVar('T') # Declare type variable + U = TypeVar('U') # Declare type variable - def first(l: Sequence[T]) -> T: # Generic function + def first(l: Sequence[U]) -> U: # Generic function return l[0] +.. versionchanged:: 3.12 + Syntactic support for generics is new in Python 3.12. + .. _user-defined-generics: User-defined generic types @@ -304,12 +327,9 @@ A user-defined class can be defined as a generic class. :: - from typing import TypeVar, Generic from logging import Logger - T = TypeVar('T') - - class LoggedVar(Generic[T]): + class LoggedVar[T]: def __init__(self, value: T, name: str, logger: Logger) -> None: self.name = name self.logger = logger @@ -326,12 +346,23 @@ A user-defined class can be defined as a generic class. def log(self, message: str) -> None: self.logger.info('%s: %s', self.name, message) -``Generic[T]`` as a base class defines that the class ``LoggedVar`` takes a -single type parameter ``T`` . This also makes ``T`` valid as a type within the -class body. +This syntax indicates that the class ``LoggedVar`` is parameterised around a +single :class:`type variable ` ``T`` . This also makes ``T`` valid as +a type within the class body. + +Generic classes implicitly inherit from :class:`Generic`. For compatibility +with Python 3.11 and lower, it is also possible to inherit explicitly from +:class:`Generic` to indicate a generic class:: + + from typing import TypeVar, Generic + + T = TypeVar('T') + + class LoggedVar(Generic[T]): + ... -The :class:`Generic` base class defines :meth:`~object.__class_getitem__` so -that ``LoggedVar[T]`` is valid as a type:: +Generic classes have :meth:`~object.__class_getitem__` methods, meaning they +can be parameterised at runtime (e.g. ``LoggedVar[int]`` below):: from collections.abc import Iterable @@ -344,11 +375,14 @@ A generic type can have any number of type variables. All varieties of from typing import TypeVar, Generic, Sequence - T = TypeVar('T', contravariant=True) - B = TypeVar('B', bound=Sequence[bytes], covariant=True) - S = TypeVar('S', int, str) + class WeirdTrio[T, B: Sequence[bytes], S: (int, str)]: + ... + + OldT = TypeVar('OldT', contravariant=True) + OldB = TypeVar('OldB', bound=Sequence[bytes], covariant=True) + OldS = TypeVar('OldS', int, str) - class WeirdTrio(Generic[T, B, S]): + class OldWeirdTrio(Generic[OldT, OldB, OldS]): ... Each type variable argument to :class:`Generic` must be distinct. @@ -357,29 +391,26 @@ This is thus invalid:: from typing import TypeVar, Generic ... + class Pair[M, M]: # SyntaxError + ... + T = TypeVar('T') class Pair(Generic[T, T]): # INVALID ... -You can use multiple inheritance with :class:`Generic`:: +Generic classes can also inherit from other classes:: from collections.abc import Sized - from typing import TypeVar, Generic - T = TypeVar('T') - - class LinkedList(Sized, Generic[T]): + class LinkedList[T](Sized): ... -When inheriting from generic classes, some type variables could be fixed:: +When inheriting from generic classes, some type parameters could be fixed:: from collections.abc import Mapping - from typing import TypeVar - - T = TypeVar('T') - class MyDict(Mapping[str, T]): + class MyDict[T](Mapping[str, T]): ... In this case ``MyDict`` has a single parameter, ``T``. @@ -392,49 +423,66 @@ not generic but implicitly inherits from ``Iterable[Any]``:: class MyIterable(Iterable): # Same as Iterable[Any] -User defined generic type aliases are also supported. Examples:: +User-defined generic type aliases are also supported. Examples:: from collections.abc import Iterable - from typing import TypeVar - S = TypeVar('S') - Response = Iterable[S] | int + + type Response[S] = Iterable[S] | int # Return type here is same as Iterable[str] | int def response(query: str) -> Response[str]: ... - T = TypeVar('T', int, float, complex) - Vec = Iterable[tuple[T, T]] + type Vec[T] = Iterable[tuple[T, T]] - def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]] + def inproduct[T: (int, float, complex)](v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]] return sum(x*y for x, y in v) +For backward compatibility, generic type aliases can also be created +through a simple assignment:: + + from collections.abc import Iterable + from typing import TypeVar + + S = TypeVar("S") + Response = Iterable[S] | int + .. versionchanged:: 3.7 :class:`Generic` no longer has a custom metaclass. +.. versionchanged:: 3.12 + Syntactic support for generics and type aliases is new in version 3.12. + Previously, generic classes had to explicitly inherit from :class:`Generic` + or contain a type variable in one of their bases. + User-defined generics for parameter expressions are also supported via parameter -specification variables in the form ``Generic[P]``. The behavior is consistent +specification variables in the form ``[**P]``. The behavior is consistent with type variables' described above as parameter specification variables are treated by the typing module as a specialized type variable. The one exception to this is that a list of types can be used to substitute a :class:`ParamSpec`:: - >>> from typing import Generic, ParamSpec, TypeVar - - >>> T = TypeVar('T') - >>> P = ParamSpec('P') - - >>> class Z(Generic[T, P]): ... + >>> class Z[T, **P]: ... # T is a TypeVar; P is a ParamSpec ... >>> Z[int, [dict, float]] __main__.Z[int, [dict, float]] +Classes generic over a :class:`ParamSpec` can also be created using explicit +inheritance from :class:`Generic`. In this case, ``**`` is not used:: -Furthermore, a generic with only one parameter specification variable will accept + from typing import ParamSpec, Generic + + P = ParamSpec('P') + + class Z(Generic[P]): + ... + +Another difference between :class:`TypeVar` and :class:`ParamSpec` is that a +generic with only one parameter specification variable will accept parameter lists in the forms ``X[[Type1, Type2, ...]]`` and also ``X[Type1, Type2, ...]`` for aesthetic reasons. Internally, the latter is converted to the former, so the following are equivalent:: - >>> class X(Generic[P]): ... + >>> class X[**P]: ... ... >>> X[int, str] __main__.X[[int, str]] @@ -670,20 +718,20 @@ These can be used as types in annotations and do not support ``[]``. This can be used to define a function that should never be called, or a function that never returns:: - from typing import Never + from typing import Never - def never_call_me(arg: Never) -> None: - pass + def never_call_me(arg: Never) -> None: + pass - def int_or_str(arg: int | str) -> None: - never_call_me(arg) # type checker error - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _: - never_call_me(arg) # ok, arg is of type Never + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never .. versionadded:: 3.11 @@ -717,9 +765,9 @@ These can be used as types in annotations and do not support ``[]``. from typing import Self class Foo: - def return_self(self) -> Self: - ... - return self + def return_self(self) -> Self: + ... + return self This annotation is semantically equivalent to the following, @@ -730,16 +778,16 @@ These can be used as types in annotations and do not support ``[]``. Self = TypeVar("Self", bound="Foo") class Foo: - def return_self(self: Self) -> Self: - ... - return self + def return_self(self: Self) -> Self: + ... + return self In general if something currently follows the pattern of:: class Foo: - def return_self(self) -> "Foo": - ... - return self + def return_self(self) -> "Foo": + ... + return self You should use :data:`Self` as calls to ``SubclassOfFoo.return_self`` would have ``Foo`` as the return type and not ``SubclassOfFoo``. @@ -767,6 +815,15 @@ These can be used as types in annotations and do not support ``[]``. .. versionadded:: 3.10 + .. deprecated:: 3.12 + :data:`TypeAlias` is deprecated in favor of the :keyword:`type` statement, + which creates instances of :class:`TypeAliasType`. + Note that while :data:`TypeAlias` and :class:`TypeAliasType` serve + similar purposes and have similar names, they are distinct and the + latter is not the type of the former. + Removal of :data:`TypeAlias` is not currently planned, but users + are encouraged to migrate to :keyword:`type` statements. + Special forms """"""""""""" @@ -1255,8 +1312,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn from typing import TypedDict, Unpack class Movie(TypedDict): - name: str - year: int + name: str + year: int # This function expects two keyword arguments - `name` of type `str` # and `year` of type `int`. @@ -1266,213 +1323,327 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.11 -Building generic types -"""""""""""""""""""""" +Building generic types and type aliases +""""""""""""""""""""""""""""""""""""""" + +The following objects are not used directly in annotations. Instead, they are building blocks +for creating generic types and type aliases. -These are not used in annotations. They are building blocks for creating generic types. +These objects can be created through special syntax +(:ref:`type parameter lists ` and the :keyword:`type` statement). +For compatibility with Python 3.11 and earlier, they can also be created +without the dedicated syntax, as documented below. .. class:: Generic Abstract base class for generic types. - A generic type is typically declared by inheriting from an - instantiation of this class with one or more type variables. - For example, a generic mapping type might be defined as:: + A generic type is typically declared by adding a list of type parameters + after the class name:: - class Mapping(Generic[KT, VT]): + class Mapping[KT, VT]: def __getitem__(self, key: KT) -> VT: ... # Etc. - This class can then be used as follows:: + Such a class implicitly inherits from ``Generic``. + The runtime semantics of this syntax are discussed in the + :ref:`Language Reference `. - X = TypeVar('X') - Y = TypeVar('Y') + This class can then be used as follows:: - def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y: + def lookup_name[X, Y](mapping: Mapping[X, Y], key: X, default: Y) -> Y: try: return mapping[key] except KeyError: return default -.. class:: TypeVar + Here the brackets after the function name indicate a + :ref:`generic function `. - Type variable. + For backwards compatibility, generic classes can also be + declared by explicitly inheriting from + ``Generic``. In this case, the type parameters must be declared + separately:: - Usage:: + KT = TypeVar('KT') + VT = TypeVar('VT') + + class Mapping(Generic[KT, VT]): + def __getitem__(self, key: KT) -> VT: + ... + # Etc. + +.. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False) + + Type variable. + + The preferred way to construct a type variable is via the dedicated syntax + for :ref:`generic functions `, + :ref:`generic classes `, and + :ref:`generic type aliases `:: + + class Sequence[T]: # T is a TypeVar + ... + + This syntax can also be used to create bound and constrained type + variables:: + + class StrSequence[S: str]: # S is a TypeVar bound to str + ... + + + class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes + ... + + However, if desired, reusable type variables can also be constructed manually, like so:: T = TypeVar('T') # Can be anything S = TypeVar('S', bound=str) # Can be any subtype of str A = TypeVar('A', str, bytes) # Must be exactly str or bytes - Type variables exist primarily for the benefit of static type - checkers. They serve as the parameters for generic types as well - as for generic function definitions. See :class:`Generic` for more - information on generic types. Generic functions work as follows:: + Type variables exist primarily for the benefit of static type + checkers. They serve as the parameters for generic types as well + as for generic function and type alias definitions. + See :class:`Generic` for more + information on generic types. Generic functions work as follows:: + + def repeat[T](x: T, n: int) -> Sequence[T]: + """Return a list containing n references to x.""" + return [x]*n + + + def print_capitalized[S: str](x: S) -> S: + """Print x capitalized, and return x.""" + print(x.capitalize()) + return x - def repeat(x: T, n: int) -> Sequence[T]: - """Return a list containing n references to x.""" - return [x]*n + def concatenate[A: (str, bytes)](x: A, y: A) -> A: + """Add two strings or bytes objects together.""" + return x + y + + Note that type variables can be *bound*, *constrained*, or neither, but + cannot be both bound *and* constrained. + + The variance of type variables is inferred by type checkers when they are created + through the :ref:`type parameter syntax ` or when + ``infer_variance=True`` is passed. + Manually created type variables may be explicitly marked covariant or contravariant by passing + ``covariant=True`` or ``contravariant=True``. + By default, manually created type variables are invariant. + See :pep:`484` and :pep:`695` for more details. + + Bound type variables and constrained type variables have different + semantics in several important ways. Using a *bound* type variable means + that the ``TypeVar`` will be solved using the most specific type possible:: + + x = print_capitalized('a string') + reveal_type(x) # revealed type is str + + class StringSubclass(str): + pass + + y = print_capitalized(StringSubclass('another string')) + reveal_type(y) # revealed type is StringSubclass + + z = print_capitalized(45) # error: int is not a subtype of str + + Type variables can be bound to concrete types, abstract types (ABCs or + protocols), and even unions of types:: + + # Can be anything with an __abs__ method + def print_abs[T: SupportsAbs](arg: T) -> None: + print("Absolute value:", abs(arg)) + + U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes + V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method + + .. _typing-constrained-typevar: + + Using a *constrained* type variable, however, means that the ``TypeVar`` + can only ever be solved as being exactly one of the constraints given:: + + a = concatenate('one', 'two') + reveal_type(a) # revealed type is str + + b = concatenate(StringSubclass('one'), StringSubclass('two')) + reveal_type(b) # revealed type is str, despite StringSubclass being passed in + + c = concatenate('one', b'two') # error: type variable 'A' can be either str or bytes in a function call, but not both + + At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`. + + .. attribute:: __name__ + + The name of the type variable. - def print_capitalized(x: S) -> S: - """Print x capitalized, and return x.""" - print(x.capitalize()) - return x + .. attribute:: __covariant__ + Whether the type var has been explicitly marked as covariant. - def concatenate(x: A, y: A) -> A: - """Add two strings or bytes objects together.""" - return x + y + .. attribute:: __contravariant__ - Note that type variables can be *bound*, *constrained*, or neither, but - cannot be both bound *and* constrained. + Whether the type var has been explicitly marked as contravariant. - Bound type variables and constrained type variables have different - semantics in several important ways. Using a *bound* type variable means - that the ``TypeVar`` will be solved using the most specific type possible:: + .. attribute:: __infer_variance__ - x = print_capitalized('a string') - reveal_type(x) # revealed type is str + Whether the type variable's variance should be inferred by type checkers. - class StringSubclass(str): - pass + .. versionadded:: 3.12 - y = print_capitalized(StringSubclass('another string')) - reveal_type(y) # revealed type is StringSubclass + .. attribute:: __bound__ - z = print_capitalized(45) # error: int is not a subtype of str + The bound of the type variable, if any. - Type variables can be bound to concrete types, abstract types (ABCs or - protocols), and even unions of types:: + .. versionchanged:: 3.12 - U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes - V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method + For type variables created through :ref:`type parameter syntax `, + the bound is evaluated only when the attribute is accessed, not when + the type variable is created (see :ref:`lazy-evaluation`). -.. _typing-constrained-typevar: + .. attribute:: __constraints__ - Using a *constrained* type variable, however, means that the ``TypeVar`` - can only ever be solved as being exactly one of the constraints given:: + A tuple containing the constraints of the type variable, if any. - a = concatenate('one', 'two') - reveal_type(a) # revealed type is str + .. versionchanged:: 3.12 - b = concatenate(StringSubclass('one'), StringSubclass('two')) - reveal_type(b) # revealed type is str, despite StringSubclass being passed in + For type variables created through :ref:`type parameter syntax `, + the constraints are evaluated only when the attribute is accessed, not when + the type variable is created (see :ref:`lazy-evaluation`). - c = concatenate('one', b'two') # error: type variable 'A' can be either str or bytes in a function call, but not both + .. versionchanged:: 3.12 + + Type variables can now be declared using the + :ref:`type parameter ` syntax introduced by :pep:`695`. + The ``infer_variance`` parameter was added. + +.. class:: TypeVarTuple(name) + + Type variable tuple. A specialized form of :class:`type variable ` + that enables *variadic* generics. + + Type variable tuples can be declared in :ref:`type parameter lists ` + using a single asterisk (``*``) before the name:: - At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`. In general, - :func:`isinstance` and :func:`issubclass` should not be used with types. + def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]: + return (*tup[1:], tup[0]) - Type variables may be marked covariant or contravariant by passing - ``covariant=True`` or ``contravariant=True``. See :pep:`484` for more - details. By default, type variables are invariant. + Or by explicitly invoking the ``TypeVarTuple`` constructor:: -.. class:: TypeVarTuple + T = TypeVar("T") + Ts = TypeVarTuple("Ts") + + def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]: + return (*tup[1:], tup[0]) - Type variable tuple. A specialized form of :class:`type variable ` - that enables *variadic* generics. + A normal type variable enables parameterization with a single type. A type + variable tuple, in contrast, allows parameterization with an + *arbitrary* number of types by acting like an *arbitrary* number of type + variables wrapped in a tuple. For example:: - A normal type variable enables parameterization with a single type. A type - variable tuple, in contrast, allows parameterization with an - *arbitrary* number of types by acting like an *arbitrary* number of type - variables wrapped in a tuple. For example:: + # T is bound to int, Ts is bound to () + # Return value is (1,), which has type tuple[int] + move_first_element_to_last(tup=(1,)) - T = TypeVar('T') - Ts = TypeVarTuple('Ts') + # T is bound to int, Ts is bound to (str,) + # Return value is ('spam', 1), which has type tuple[str, int] + move_first_element_to_last(tup=(1, 'spam')) - def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]: - return (*tup[1:], tup[0]) + # T is bound to int, Ts is bound to (str, float) + # Return value is ('spam', 3.0, 1), which has type tuple[str, float, int] + move_first_element_to_last(tup=(1, 'spam', 3.0)) - # T is bound to int, Ts is bound to () - # Return value is (1,), which has type tuple[int] - move_first_element_to_last(tup=(1,)) + # This fails to type check (and fails at runtime) + # because tuple[()] is not compatible with tuple[T, *Ts] + # (at least one element is required) + move_first_element_to_last(tup=()) - # T is bound to int, Ts is bound to (str,) - # Return value is ('spam', 1), which has type tuple[str, int] - move_first_element_to_last(tup=(1, 'spam')) + Note the use of the unpacking operator ``*`` in ``tuple[T, *Ts]``. + Conceptually, you can think of ``Ts`` as a tuple of type variables + ``(T1, T2, ...)``. ``tuple[T, *Ts]`` would then become + ``tuple[T, *(T1, T2, ...)]``, which is equivalent to + ``tuple[T, T1, T2, ...]``. (Note that in older versions of Python, you might + see this written using :data:`Unpack ` instead, as + ``Unpack[Ts]``.) - # T is bound to int, Ts is bound to (str, float) - # Return value is ('spam', 3.0, 1), which has type tuple[str, float, int] - move_first_element_to_last(tup=(1, 'spam', 3.0)) + Type variable tuples must *always* be unpacked. This helps distinguish type + variable tuples from normal type variables:: - # This fails to type check (and fails at runtime) - # because tuple[()] is not compatible with tuple[T, *Ts] - # (at least one element is required) - move_first_element_to_last(tup=()) + x: Ts # Not valid + x: tuple[Ts] # Not valid + x: tuple[*Ts] # The correct way to do it - Note the use of the unpacking operator ``*`` in ``tuple[T, *Ts]``. - Conceptually, you can think of ``Ts`` as a tuple of type variables - ``(T1, T2, ...)``. ``tuple[T, *Ts]`` would then become - ``tuple[T, *(T1, T2, ...)]``, which is equivalent to - ``tuple[T, T1, T2, ...]``. (Note that in older versions of Python, you might - see this written using :data:`Unpack ` instead, as - ``Unpack[Ts]``.) + Type variable tuples can be used in the same contexts as normal type + variables. For example, in class definitions, arguments, and return types:: - Type variable tuples must *always* be unpacked. This helps distinguish type - variable tuples from normal type variables:: + class Array[*Shape]: + def __getitem__(self, key: tuple[*Shape]) -> float: ... + def __abs__(self) -> "Array[*Shape]": ... + def get_shape(self) -> tuple[*Shape]: ... - x: Ts # Not valid - x: tuple[Ts] # Not valid - x: tuple[*Ts] # The correct way to do it + Type variable tuples can be happily combined with normal type variables:: - Type variable tuples can be used in the same contexts as normal type - variables. For example, in class definitions, arguments, and return types:: + DType = TypeVar('DType') - Shape = TypeVarTuple('Shape') - class Array(Generic[*Shape]): - def __getitem__(self, key: tuple[*Shape]) -> float: ... - def __abs__(self) -> "Array[*Shape]": ... - def get_shape(self) -> tuple[*Shape]: ... + class Array[DType, *Shape]: # This is fine + pass - Type variable tuples can be happily combined with normal type variables:: + class Array2[*Shape, DType]: # This would also be fine + pass - DType = TypeVar('DType') + float_array_1d: Array[float, Height] = Array() # Totally fine + int_array_2d: Array[int, Height, Width] = Array() # Yup, fine too - class Array(Generic[DType, *Shape]): # This is fine - pass + However, note that at most one type variable tuple may appear in a single + list of type arguments or type parameters:: - class Array2(Generic[*Shape, DType]): # This would also be fine - pass + x: tuple[*Ts, *Ts] # Not valid + class Array[*Shape, *Shape]: # Not valid + pass - float_array_1d: Array[float, Height] = Array() # Totally fine - int_array_2d: Array[int, Height, Width] = Array() # Yup, fine too + Finally, an unpacked type variable tuple can be used as the type annotation + of ``*args``:: - However, note that at most one type variable tuple may appear in a single - list of type arguments or type parameters:: + def call_soon[*Ts]( + callback: Callable[[*Ts], None], + *args: *Ts + ) -> None: + ... + callback(*args) - x: tuple[*Ts, *Ts] # Not valid - class Array(Generic[*Shape, *Shape]): # Not valid - pass + In contrast to non-unpacked annotations of ``*args`` - e.g. ``*args: int``, + which would specify that *all* arguments are ``int`` - ``*args: *Ts`` + enables reference to the types of the *individual* arguments in ``*args``. + Here, this allows us to ensure the types of the ``*args`` passed + to ``call_soon`` match the types of the (positional) arguments of + ``callback``. - Finally, an unpacked type variable tuple can be used as the type annotation - of ``*args``:: + See :pep:`646` for more details on type variable tuples. + + .. attribute:: __name__ - def call_soon( - callback: Callable[[*Ts], None], - *args: *Ts - ) -> None: - ... - callback(*args) + The name of the type variable tuple. - In contrast to non-unpacked annotations of ``*args`` - e.g. ``*args: int``, - which would specify that *all* arguments are ``int`` - ``*args: *Ts`` - enables reference to the types of the *individual* arguments in ``*args``. - Here, this allows us to ensure the types of the ``*args`` passed - to ``call_soon`` match the types of the (positional) arguments of - ``callback``. + .. versionadded:: 3.11 - See :pep:`646` for more details on type variable tuples. + .. versionchanged:: 3.12 - .. versionadded:: 3.11 + Type variable tuples can now be declared using the + :ref:`type parameter ` syntax introduced by :pep:`695`. .. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False) Parameter specification variable. A specialized version of :class:`type variables `. - Usage:: + In :ref:`type parameter lists `, parameter specifications + can be declared with two asterisks (``**``):: + + type IntFunc[**P] = Callable[P, int] + + For compatibility with Python 3.11 and earlier, ``ParamSpec`` objects + can also be created as follows:: P = ParamSpec('P') @@ -1489,13 +1660,9 @@ These are not used in annotations. They are building blocks for creating generic new callable returned by it have inter-dependent type parameters:: from collections.abc import Callable - from typing import TypeVar, ParamSpec import logging - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: + def add_logging[T, **P](f: Callable[P, T]) -> Callable[P, T]: '''A type-safe decorator to add logging to a function.''' def inner(*args: P.args, **kwargs: P.kwargs) -> T: logging.info(f'{f.__name__} was called') @@ -1530,6 +1697,10 @@ These are not used in annotations. They are building blocks for creating generic ``P.args`` and ``P.kwargs`` are instances respectively of :class:`ParamSpecArgs` and :class:`ParamSpecKwargs`. + .. attribute:: __name__ + + The name of the parameter specification. + Parameter specification variables created with ``covariant=True`` or ``contravariant=True`` can be used to declare covariant or contravariant generic types. The ``bound`` argument is also accepted, similar to @@ -1538,6 +1709,11 @@ These are not used in annotations. They are building blocks for creating generic .. versionadded:: 3.10 + .. versionchanged:: 3.12 + + Parameter specifications can now be declared using the + :ref:`type parameter ` syntax introduced by :pep:`695`. + .. note:: Only parameter specification variables defined in global scope can be pickled. @@ -1565,6 +1741,67 @@ These are not used in annotations. They are building blocks for creating generic .. versionadded:: 3.10 +.. class:: TypeAliasType(name, value, *, type_params=()) + + The type of type aliases created through the :keyword:`type` statement. + + Example:: + + >>> type Alias = int + >>> type(Alias) + + + .. versionadded:: 3.12 + + .. attribute:: __name__ + + The name of the type alias:: + + >>> type Alias = int + >>> Alias.__name__ + 'Alias' + + .. attribute:: __module__ + + The module in which the type alias was defined:: + + >>> type Alias = int + >>> Alias.__module__ + '__main__' + + .. attribute:: __type_params__ + + The type parameters of the type alias, or an empty tuple if the alias is + not generic: + + .. doctest:: + + >>> type ListOrSet[T] = list[T] | set[T] + >>> ListOrSet.__type_params__ + (T,) + >>> type NotGeneric = int + >>> NotGeneric.__type_params__ + () + + .. attribute:: __value__ + + The type alias's value. This is :ref:`lazily evaluated `, + so names used in the definition of the alias are not resolved until the + ``__value__`` attribute is accessed: + + .. doctest:: + + >>> type Mutually = Recursive + >>> type Recursive = Mutually + >>> Mutually + Mutually + >>> Recursive + Recursive + >>> Mutually.__value__ + Recursive + >>> Recursive.__value__ + Mutually + Other special directives """""""""""""""""""""""" @@ -1613,12 +1850,18 @@ These are not used in annotations. They are building blocks for declaring types. ``NamedTuple`` subclasses can be generic:: - class Group(NamedTuple, Generic[T]): + class Group[T](NamedTuple): key: T group: list[T] Backward-compatible usage:: + # For creating a generic NamedTuple on Python 3.11 or lower + class Group(NamedTuple, Generic[T]): + key: T + group: list[T] + + # A functional syntax is also supported Employee = NamedTuple('Employee', [('name', str), ('id', int)]) .. versionchanged:: 3.6 @@ -1692,6 +1935,15 @@ These are not used in annotations. They are building blocks for declaring types. Protocol classes can be generic, for example:: + class GenProto[T](Protocol): + def meth(self) -> T: + ... + + In code that needs to be compatible with Python 3.11 or older, generic + Protocols can be written as follows:: + + T = TypeVar("T") + class GenProto(Protocol[T]): def meth(self) -> T: ... @@ -1887,6 +2139,13 @@ These are not used in annotations. They are building blocks for declaring types. A ``TypedDict`` can be generic:: + class Group[T](TypedDict): + key: T + group: list[T] + + To create a generic ``TypedDict`` that is compatible with Python 3.11 + or lower, inherit from :class:`Generic` explicitly:: + class Group(TypedDict, Generic[T]): key: T group: list[T] @@ -1985,12 +2244,10 @@ Corresponding to built-in types This type may be used as follows:: - T = TypeVar('T', int, float) - - def vec2(x: T, y: T) -> List[T]: + def vec2[T: (int, float)](x: T, y: T) -> List[T]: return [x, y] - def keep_positives(vector: Sequence[T]) -> List[T]: + def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]: return [item for item in vector if item > 0] .. deprecated:: 3.9 @@ -2189,8 +2446,8 @@ Corresponding to collections in :mod:`collections.abc` A generic version of :class:`collections.abc.Mapping`. This type can be used as follows:: - def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: - return word_list[word] + def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: + return word_list[word] .. deprecated:: 3.9 :class:`collections.abc.Mapping` now supports subscripting (``[]``). @@ -3006,3 +3263,5 @@ convenience. This is subject to change, and not all deprecations are listed. | ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` | | ``typing.Sized`` | | | | +----------------------------------+---------------+-------------------+----------------+ +| ``typing.TypeAlias`` | 3.12 | Undecided | :pep:`695` | ++----------------------------------+---------------+-------------------+----------------+ diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 9d1e5b6c596d9f..6d30eccab1990f 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -1206,7 +1206,7 @@ A function definition defines a user-defined function object (see section :ref:`types`): .. productionlist:: python-grammar - funcdef: [`decorators`] "def" `funcname` "(" [`parameter_list`] ")" + funcdef: [`decorators`] "def" `funcname` [`type_params`] "(" [`parameter_list`] ")" : ["->" `expression`] ":" `suite` decorators: `decorator`+ decorator: "@" `assignment_expression` NEWLINE @@ -1256,6 +1256,15 @@ except that the original function is not temporarily bound to the name ``func``. :token:`~python-grammar:assignment_expression`. Previously, the grammar was much more restrictive; see :pep:`614` for details. +A list of :ref:`type parameters ` may be given in square brackets +between the function's name and the opening parenthesis for its parameter list. +This indicates to static type checkers that the function is generic. At runtime, +the type parameters can be retrieved from the function's ``__type_params__`` +attribute. See :ref:`generic-functions` for more. + +.. versionchanged:: 3.12 + Type parameter lists are new in Python 3.12. + .. index:: triple: default; parameter; value single: argument; function definition @@ -1378,7 +1387,7 @@ Class definitions A class definition defines a class object (see section :ref:`types`): .. productionlist:: python-grammar - classdef: [`decorators`] "class" `classname` [`inheritance`] ":" `suite` + classdef: [`decorators`] "class" `classname` [`type_params`] [`inheritance`] ":" `suite` inheritance: "(" [`argument_list`] ")" classname: `identifier` @@ -1434,6 +1443,15 @@ decorators. The result is then bound to the class name. :token:`~python-grammar:assignment_expression`. Previously, the grammar was much more restrictive; see :pep:`614` for details. +A list of :ref:`type parameters ` may be given in square brackets +immediately after the class's name. +This indicates to static type checkers that the class is generic. At runtime, +the type parameters can be retrieved from the class's ``__type_params__`` +attribute. See :ref:`generic-classes` for more. + +.. versionchanged:: 3.12 + Type parameter lists are new in Python 3.12. + **Programmer's note:** Variables defined in the class definition are class attributes; they are shared by instances. Instance attributes can be set in a method with ``self.name = value``. Both class and instance attributes are @@ -1589,6 +1607,228 @@ body of a coroutine function. The proposal that made coroutines a proper standalone concept in Python, and added supporting syntax. +.. _type-params: + +Type parameter lists +==================== + +.. versionadded:: 3.12 + +.. index:: + single: type parameters + +.. productionlist:: python-grammar + type_params: "[" `type_param` ("," `type_param`)* "]" + type_param: `typevar` | `typevartuple` | `paramspec` + typevar: `identifier` (":" `expression`)? + typevartuple: "*" `identifier` + paramspec: "**" `identifier` + +:ref:`Functions ` (including :ref:`coroutines `), +:ref:`classes ` and :ref:`type aliases ` may +contain a type parameter list:: + + def max[T](args: list[T]) -> T: + ... + + async def amax[T](args: list[T]) -> T: + ... + + class Bag[T]: + def __iter__(self) -> Iterator[T]: + ... + + def add(self, arg: T) -> None: + ... + + type ListOrSet[T] = list[T] | set[T] + +Semantically, this indicates that the function, class, or type alias is +generic over a type variable. This information is primarily used by static +type checkers, and at runtime, generic objects behave much like their +non-generic counterparts. + +Type parameters are declared in square brackets (``[]``) immediately +after the name of the function, class, or type alias. The type parameters +are accessible within the scope of the generic object, but not elsewhere. +Thus, after a declaration ``def func[T](): pass``, the name ``T`` is not available in +the module scope. Below, the semantics of generic objects are described +with more precision. The scope of type parameters is modeled with a special +function (technically, an :ref:`annotation scope `) that +wraps the creation of the generic object. + +Generic functions, classes, and type aliases have a :attr:`!__type_params__` +attribute listing their type parameters. + +Type parameters come in three kinds: + +* :data:`typing.TypeVar`, introduced by a plain name (e.g., ``T``). Semantically, this + represents a single type to a type checker. +* :data:`typing.TypeVarTuple`, introduced by a name prefixed with a single + asterisk (e.g., ``*Ts``). Semantically, this stands for a tuple of any + number of types. +* :data:`typing.ParamSpec`, introduced by a name prefixed with two asterisks + (e.g., ``**P``). Semantically, this stands for the parameters of a callable. + +:data:`typing.TypeVar` declarations can define *bounds* and *constraints* with +a colon (``:``) followed by an expression. A single expression after the colon +indicates a bound (e.g. ``T: int``). Semantically, this means +that the :data:`!typing.TypeVar` can only represent types that are a subtype of +this bound. A parenthesized tuple of expressions after the colon indicates a +set of constraints (e.g. ``T: (str, bytes)``). Each member of the tuple should be a +type (again, this is not enforced at runtime). Constrained type variables can only +take on one of the types in the list of constraints. + +For :data:`!typing.TypeVar`\ s declared using the type parameter list syntax, +the bound and constraints are not evaluated when the generic object is created, +but only when the value is explicitly accessed through the attributes ``__bound__`` +and ``__constraints__``. To accomplish this, the bounds or constraints are +evaluated in a separate :ref:`annotation scope `. + +:data:`typing.TypeVarTuple`\ s and :data:`typing.ParamSpec`\ s cannot have bounds +or constraints. + +The following example indicates the full set of allowed type parameter declarations:: + + def overly_generic[ + SimpleTypeVar, + TypeVarWithBound: int, + TypeVarWithConstraints: (str, bytes), + *SimpleTypeVarTuple, + **SimpleParamSpec, + ]( + a: SimpleTypeVar, + b: TypeVarWithBound, + c: Callable[SimpleParamSpec, TypeVarWithConstraints], + *d: SimpleTypeVarTuple, + ): ... + +.. _generic-functions: + +Generic functions +----------------- + +Generic functions are declared as follows:: + + def func[T](arg: T): ... + +This syntax is equivalent to:: + + annotation-def TYPE_PARAMS_OF_func(): + T = typing.TypeVar("T") + def func(arg: T): ... + func.__type_params__ = (T,) + return func + func = TYPE_PARAMS_OF_func() + +Here ``annotation-def`` indicates an :ref:`annotation scope `, +which is not actually bound to any name at runtime. (One +other liberty is taken in the translation: the syntax does not go through +attribute access on the :mod:`typing` module, but creates an instance of +:data:`typing.TypeVar` directly.) + +The annotations of generic functions are evaluated within the annotation scope +used for declaring the type parameters, but the function's defaults and +decorators are not. + +The following example illustrates the scoping rules for these cases, +as well as for additional flavors of type parameters:: + + @decorator + def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default): + ... + +Except for the :ref:`lazy evaluation ` of the +:class:`~typing.TypeVar` bound, this is equivalent to:: + + DEFAULT_OF_arg = some_default + + annotation-def TYPE_PARAMS_OF_func(): + + annotation-def BOUND_OF_T(): + return int + # In reality, BOUND_OF_T() is evaluated only on demand. + T = typing.TypeVar("T", bound=BOUND_OF_T()) + + Ts = typing.TypeVarTuple("Ts") + P = typing.ParamSpec("P") + + def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg): + ... + + func.__type_params__ = (T, Ts, P) + return func + func = decorator(TYPE_PARAMS_OF_func()) + +The capitalized names like ``DEFAULT_OF_arg`` are not actually +bound at runtime. + +.. _generic-classes: + +Generic classes +--------------- + +Generic classes are declared as follows:: + + class Bag[T]: ... + +This syntax is equivalent to:: + + annotation-def TYPE_PARAMS_OF_Bag(): + T = typing.TypeVar("T") + class Bag(typing.Generic[T]): + __type_params__ = (T,) + ... + return Bag + Bag = TYPE_PARAMS_OF_Bag() + +Here again ``annotation-def`` (not a real keyword) indicates an +:ref:`annotation scope `, and the name +``TYPE_PARAMS_OF_Bag`` is not actually bound at runtime. + +Generic classes implicitly inherit from :data:`typing.Generic`. +The base classes and keyword arguments of generic classes are +evaluated within the type scope for the type parameters, +and decorators are evaluated outside that scope. This is illustrated +by this example:: + + @decorator + class Bag(Base[T], arg=T): ... + +This is equivalent to:: + + annotation-def TYPE_PARAMS_OF_Bag(): + T = typing.TypeVar("T") + class Bag(Base[T], typing.Generic[T], arg=T): + __type_params__ = (T,) + ... + return Bag + Bag = decorator(TYPE_PARAMS_OF_Bag()) + +.. _generic-type-aliases: + +Generic type aliases +-------------------- + +The :keyword:`type` statement can also be used to create a generic type alias:: + + type ListOrSet[T] = list[T] | set[T] + +Except for the :ref:`lazy evaluation ` of the value, +this is equivalent to:: + + annotation-def TYPE_PARAMS_OF_ListOrSet(): + T = typing.TypeVar("T") + + annotation-def VALUE_OF_ListOrSet(): + return list[T] | set[T] + # In reality, the value is lazily evaluated + return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,)) + ListOrSet = TYPE_PARAMS_OF_ListOrSet() + +Here, ``annotation-def`` (not a real keyword) indicates an +:ref:`annotation scope `. The capitalized names +like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime. .. rubric:: Footnotes diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index c0734e49f29192..e8f9775dd33ce1 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -499,6 +499,7 @@ Callable types single: __globals__ (function attribute) single: __annotations__ (function attribute) single: __kwdefaults__ (function attribute) + single: __type_params__ (function attribute) pair: global; namespace +-------------------------+-------------------------------+-----------+ @@ -561,6 +562,12 @@ Callable types | :attr:`__kwdefaults__` | A dict containing defaults | Writable | | | for keyword-only parameters. | | +-------------------------+-------------------------------+-----------+ + | :attr:`__type_params__` | A tuple containing the | Writable | + | | :ref:`type parameters | | + | | ` of a | | + | | :ref:`generic function | | + | | `. | | + +-------------------------+-------------------------------+-----------+ Most of the attributes labelled "Writable" check the type of the assigned value. @@ -837,6 +844,7 @@ Custom classes single: __bases__ (class attribute) single: __doc__ (class attribute) single: __annotations__ (class attribute) + single: __type_params__ (class attribute) Special attributes: @@ -863,6 +871,10 @@ Custom classes working with :attr:`__annotations__`, please see :ref:`annotations-howto`. + :attr:`__type_params__` + A tuple containing the :ref:`type parameters ` of + a :ref:`generic class `. + Class instances .. index:: pair: object; class instance diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index 8917243999d399..cea3a56ba51644 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -71,6 +71,8 @@ The following constructs bind names: + in a capture pattern in structural pattern matching * :keyword:`import` statements. +* :keyword:`type` statements. +* :ref:`type parameter lists `. The :keyword:`!import` statement of the form ``from ... import *`` binds all names defined in the imported module, except those beginning with an underscore. @@ -149,7 +151,8 @@ a global statement, the free variable is treated as a global. The :keyword:`nonlocal` statement causes corresponding names to refer to previously bound variables in the nearest enclosing function scope. :exc:`SyntaxError` is raised at compile time if the given name does not -exist in any enclosing function scope. +exist in any enclosing function scope. :ref:`Type parameters ` +cannot be rebound with the :keyword:`!nonlocal` statement. .. index:: pair: module; __main__ @@ -163,14 +166,119 @@ These references follow the normal rules for name resolution with an exception that unbound local variables are looked up in the global namespace. The namespace of the class definition becomes the attribute dictionary of the class. The scope of names defined in a class block is limited to the -class block; it does not extend to the code blocks of methods -- this includes -comprehensions and generator expressions since they are implemented using a -function scope. This means that the following will fail:: +class block; it does not extend to the code blocks of methods. This includes +comprehensions and generator expressions, but it does not include +:ref:`annotation scopes `, +which have access to their enclosing class scopes. +This means that the following will fail:: class A: a = 42 b = list(a + i for i in range(10)) +However, the following will succeed:: + + class A: + type Alias = Nested + class Nested: pass + + print(A.Alias.__value__) # + +.. _annotation-scopes: + +Annotation scopes +----------------- + +:ref:`Type parameter lists ` and :keyword:`type` statements +introduce *annotation scopes*, which behave mostly like function scopes, +but with some exceptions discussed below. :term:`Annotations ` +currently do not use annotation scopes, but they are expected to use +annotation scopes in Python 3.13 when :pep:`649` is implemented. + +Annotation scopes are used in the following contexts: + +* Type parameter lists for :ref:`generic type aliases `. +* Type parameter lists for :ref:`generic functions `. + A generic function's annotations are + executed within the annotation scope, but its defaults and decorators are not. +* Type parameter lists for :ref:`generic classes `. + A generic class's base classes and + keyword arguments are executed within the annotation scope, but its decorators are not. +* The bounds and constraints for type variables + (:ref:`lazily evaluated `). +* The value of type aliases (:ref:`lazily evaluated `). + +Annotation scopes differ from function scopes in the following ways: + +* Annotation scopes have access to their enclosing class namespace. + If an annotation scope is immediately within a class scope, or within another + annotation scope that is immediately within a class scope, the code in the + annotation scope can use names defined in the class scope as if it were + executed directly within the class body. This contrasts with regular + functions defined within classes, which cannot access names defined in the class scope. +* Expressions in annotation scopes cannot contain :keyword:`yield`, ``yield from``, + :keyword:`await`, or :token:`:= ` + expressions. (These expressions are allowed in other scopes contained within the + annotation scope.) +* Names defined in annotation scopes cannot be rebound with :keyword:`nonlocal` + statements in inner scopes. This includes only type parameters, as no other + syntactic elements that can appear within annotation scopes can introduce new names. +* While annotation scopes have an internal name, that name is not reflected in the + :term:`__qualname__ ` of objects defined within the scope. + Instead, the :attr:`!__qualname__` + of such objects is as if the object were defined in the enclosing scope. + +.. versionadded:: 3.12 + Annotation scopes were introduced in Python 3.12 as part of :pep:`695`. + +.. _lazy-evaluation: + +Lazy evaluation +--------------- + +The values of type aliases created through the :keyword:`type` statement are +*lazily evaluated*. The same applies to the bounds and constraints of type +variables created through the :ref:`type parameter syntax `. +This means that they are not evaluated when the type alias or type variable is +created. Instead, they are only evaluated when doing so is necessary to resolve +an attribute access. + +Example: + +.. doctest:: + + >>> type Alias = 1/0 + >>> Alias.__value__ + Traceback (most recent call last): + ... + ZeroDivisionError: division by zero + >>> def func[T: 1/0](): pass + >>> T = func.__type_params__[0] + >>> T.__bound__ + Traceback (most recent call last): + ... + ZeroDivisionError: division by zero + +Here the exception is raised only when the ``__value__`` attribute +of the type alias or the ``__bound__`` attribute of the type variable +is accessed. + +This behavior is primarily useful for references to types that have not +yet been defined when the type alias or type variable is created. For example, +lazy evaluation enables creation of mutually recursive type aliases:: + + from typing import Literal + + type SimpleExpr = int | Parenthesized + type Parenthesized = tuple[Literal["("], Expr, Literal[")"]] + type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr] + +Lazily evaluated values are evaluated in :ref:`annotation scope `, +which means that names that appear inside the lazily evaluated value are looked up +as if they were used in the immediately enclosing scope. + +.. versionadded:: 3.12 + .. _restrict_exec: Builtins and restricted execution diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 757f887caa4029..47062f86810e91 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -361,15 +361,19 @@ Soft Keywords .. versionadded:: 3.10 Some identifiers are only reserved under specific contexts. These are known as -*soft keywords*. The identifiers ``match``, ``case`` and ``_`` can -syntactically act as keywords in contexts related to the pattern matching -statement, but this distinction is done at the parser level, not when -tokenizing. +*soft keywords*. The identifiers ``match``, ``case``, ``type`` and ``_`` can +syntactically act as keywords in certain contexts, +but this distinction is done at the parser level, not when tokenizing. -As soft keywords, their use with pattern matching is possible while still -preserving compatibility with existing code that uses ``match``, ``case`` and ``_`` as +As soft keywords, their use in the grammar is possible while still +preserving compatibility with existing code that uses these names as identifier names. +``match``, ``case``, and ``_`` are used in the :keyword:`match` statement. +``type`` is used in the :keyword:`type` statement. + +.. versionchanged:: 3.12 + ``type`` is now a soft keyword. .. index:: single: _, identifiers diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index f7a8b44d195417..662a4b643c4378 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -28,6 +28,7 @@ simple statements is: : | `future_stmt` : | `global_stmt` : | `nonlocal_stmt` + : | `type_stmt` .. _exprstmts: @@ -1012,3 +1013,48 @@ pre-existing bindings in the local scope. :pep:`3104` - Access to Names in Outer Scopes The specification for the :keyword:`nonlocal` statement. + +.. _type: + +The :keyword:`!type` statement +============================== + +.. index:: pair: statement; type + +.. productionlist:: python-grammar + type_stmt: 'type' `identifier` [`type_params`] "=" `expression` + +The :keyword:`!type` statement declares a type alias, which is an instance +of :class:`typing.TypeAliasType`. + +For example, the following statement creates a type alias:: + + type Point = tuple[float, float] + +This code is roughly equivalent to:: + + annotation-def VALUE_OF_Point(): + return tuple[float, float] + Point = typing.TypeAliasType("Point", VALUE_OF_Point()) + +``annotation-def`` indicates an :ref:`annotation scope `, which behaves +mostly like a function, but with several small differences. + +The value of the +type alias is evaluated in the annotation scope. It is not evaluated when the +type alias is created, but only when the value is accessed through the type alias's +:attr:`!__value__` attribute (see :ref:`lazy-evaluation`). +This allows the type alias to refer to names that are not yet defined. + +Type aliases may be made generic by adding a :ref:`type parameter list ` +after the name. See :ref:`generic-type-aliases` for more. + +:keyword:`!type` is a :ref:`soft keyword `. + +.. versionadded:: 3.12 + +.. seealso:: + + :pep:`695` - Type Parameter Syntax + Introduced the :keyword:`!type` statement and syntax for + generic classes and functions. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ff86cf7eba4da7..3e924a5da6f534 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -74,6 +74,8 @@ New typing features: * :pep:`688`: Making the buffer protocol accessible in Python +* :ref:`whatsnew312-pep695` + * :ref:`whatsnew312-pep692` * :pep:`698`: Override Decorator for Static Typing @@ -272,6 +274,70 @@ See :pep:`692` for more details. (PEP written by Franek Magiera) +.. _whatsnew312-pep695: + +PEP 695: Type Parameter Syntax +------------------------------ + +Generic classes and functions under :pep:`484` were declared using a verbose syntax +that left the scope of type parameters unclear and required explicit declarations of +variance. + +:pep:`695` introduces a new, more compact and explicit way to create +:ref:`generic classes ` and :ref:`functions `:: + + def max[T](args: Iterable[T]) -> T: + ... + + class list[T]: + def __getitem__(self, index: int, /) -> T: + ... + + def append(self, element: T) -> None: + ... + +In addition, the PEP introduces a new way to declare :ref:`type aliases ` +using the :keyword:`type` statement, which creates an instance of +:class:`~typing.TypeAliasType`:: + + type Point = tuple[float, float] + +Type aliases can also be :ref:`generic `:: + + type Point[T] = tuple[T, T] + +The new syntax allows declaring :class:`~typing.TypeVarTuple` +and :class:`~typing.ParamSpec` parameters, as well as :class:`~typing.TypeVar` +parameters with bounds or constraints:: + + type IntFunc[**P] = Callable[P, int] # ParamSpec + type LabeledTuple[*Ts] = tuple[str, *Ts] # TypeVarTuple + type HashableSequence[T: Hashable] = Sequence[T] # TypeVar with bound + type IntOrStrSequence[T: (int, str)] = Sequence[T] # TypeVar with constraints + +The value of type aliases and the bound and constraints of type variables +created through this syntax are evaluated only on demand (see +:ref:`lazy-evaluation`). This means type aliases are able to refer to other +types defined later in the file. + +Type parameters declared through a type parameter list are visible within the +scope of the declaration and any nested scopes, but not in the outer scope. For +example, they can be used in the type annotations for the methods of a generic +class or in the class body. However, they cannot be used in the module scope after +the class is defined. See :ref:`type-params` for a detailed description of the +runtime semantics of type parameters. + +In order to support these scoping semantics, a new kind of scope is introduced, +the :ref:`annotation scope `. Annotation scopes behave for the +most part like function scopes, but interact differently with enclosing class scopes. +In Python 3.13, :term:`annotations ` will also be evaluated in +annotation scopes. + +See :pep:`695` for more details. + +(PEP written by Eric Traut. Implementation by Jelle Zijlstra, Eric Traut, +and others in :gh:`103764`.) + Other Language Changes ====================== @@ -806,14 +872,19 @@ Optimizations CPython bytecode changes ======================== -* Removed the :opcode:`LOAD_METHOD` instruction. It has been merged into +* Remove the :opcode:`LOAD_METHOD` instruction. It has been merged into :opcode:`LOAD_ATTR`. :opcode:`LOAD_ATTR` will now behave like the old :opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set. (Contributed by Ken Jin in :gh:`93429`.) -* Removed the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` +* Remove the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` instructions. (Contributed by Irit Katriel in :gh:`102859`.) +* Add the :opcode:`LOAD_FROM_DICT_OR_DEREF`, :opcode:`LOAD_FROM_DICT_OR_GLOBALS`, + and :opcode:`LOAD_LOCALS` opcodes as part of the implementation of :pep:`695`. + Remove the :opcode:`!LOAD_CLASSDEREF` opcode, which can be replaced with + :opcode:`LOAD_LOCALS` plus :opcode:`LOAD_FROM_DICT_OR_DEREF`. (Contributed + by Jelle Zijlstra in :gh:`103764`.) Demos and Tools =============== diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 6aa0d8a3bc53be..0b7d84c706d94e 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -443,45 +443,38 @@ static PyMethodDef typevar_methods[] = { PyDoc_STRVAR(typevar_doc, "Type variable.\n\ \n\ -Usage::\n\ +The preferred way to construct a type variable is via the dedicated syntax\n\ +for generic functions, classes, and type aliases:\n\ \n\ - T = TypeVar('T') # Can be anything\n\ - A = TypeVar('A', str, bytes) # Must be str or bytes\n\ + class Sequence[T]: # T is a TypeVar\n\ + ...\n\ \n\ -Type variables exist primarily for the benefit of static type\n\ -checkers. They serve as the parameters for generic types as well\n\ -as for generic function definitions. See class Generic for more\n\ -information on generic types. Generic functions work as follows:\n\ -\n\ - def repeat(x: T, n: int) -> List[T]:\n\ - '''Return a list containing n references to x.'''\n\ - return [x]*n\n\ +This syntax can also be used to create bound and constrained type\n\ +variables:\n\ \n\ - def longest(x: A, y: A) -> A:\n\ - '''Return the longest of two strings.'''\n\ - return x if len(x) >= len(y) else y\n\ + class StrSequence[S: str]: # S is a TypeVar bound to str\n\ + ...\n\ \n\ -The latter example's signature is essentially the overloading\n\ -of (str, str) -> str and (bytes, bytes) -> bytes. Also note\n\ -that if the arguments are instances of some subclass of str,\n\ -the return type is still plain str.\n\ + class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes\n\ + ...\n\ \n\ -At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError.\n\ +However, if desired, reusable type variables can also be constructed\n\ +manually, like so:\n\ \n\ -Type variables defined with covariant=True or contravariant=True\n\ -can be used to declare covariant or contravariant generic types.\n\ -See PEP 484 for more details. By default generic types are invariant\n\ -in all type variables.\n\ + T = TypeVar('T') # Can be anything\n\ + S = TypeVar('S', bound=str) # Can be any subtype of str\n\ + A = TypeVar('A', str, bytes) # Must be exactly str or bytes\n\ \n\ -Type variables can be introspected. e.g.:\n\ -\n\ - T.__name__ == 'T'\n\ - T.__constraints__ == ()\n\ - T.__covariant__ == False\n\ - T.__contravariant__ = False\n\ - A.__constraints__ == (str, bytes)\n\ +Type variables exist primarily for the benefit of static type\n\ +checkers. They serve as the parameters for generic types as well\n\ +as for generic function and type alias definitions.\n\ \n\ -Note that only type variables defined in global scope can be pickled.\n\ +The variance of type variables is inferred by type checkers when they are created\n\ +through the type parameter syntax and when ``infer_variance=True`` is passed.\n\ +Manually created type variables may be explicitly marked covariant or\n\ +contravariant by passing ``covariant=True`` or ``contravariant=True``.\n\ +By default, manually created type variables are invariant. See PEP 484\n\ +and PEP 695 for more details.\n\ "); static PyType_Slot typevar_slots[] = { @@ -942,7 +935,14 @@ static PyMethodDef paramspec_methods[] = { PyDoc_STRVAR(paramspec_doc, "Parameter specification variable.\n\ \n\ -Usage::\n\ +The preferred way to construct a parameter specification is via the dedicated syntax\n\ +for generic functions, classes, and type aliases, where\n\ +the use of '**' creates a parameter specification:\n\ +\n\ + type IntFunc[**P] = Callable[P, int]\n\ +\n\ +For compatibility with Python 3.11 and earlier, ParamSpec objects\n\ +can also be created as follows:\n\ \n\ P = ParamSpec('P')\n\ \n\ @@ -952,12 +952,9 @@ callable to another callable, a pattern commonly found in higher order\n\ functions and decorators. They are only valid when used in ``Concatenate``,\n\ or as the first argument to ``Callable``, or as parameters for user-defined\n\ Generics. See class Generic for more information on generic types. An\n\ -example for annotating a decorator::\n\ -\n\ - T = TypeVar('T')\n\ - P = ParamSpec('P')\n\ +example for annotating a decorator:\n\ \n\ - def add_logging(f: Callable[P, T]) -> Callable[P, T]:\n\ + def add_logging[**P, T](f: Callable[P, T]) -> Callable[P, T]:\n\ '''A type-safe decorator to add logging to a function.'''\n\ def inner(*args: P.args, **kwargs: P.kwargs) -> T:\n\ logging.info(f'{f.__name__} was called')\n\ @@ -969,17 +966,9 @@ example for annotating a decorator::\n\ '''Add two numbers together.'''\n\ return x + y\n\ \n\ -Parameter specification variables defined with covariant=True or\n\ -contravariant=True can be used to declare covariant or contravariant\n\ -generic types. These keyword arguments are valid, but their actual semantics\n\ -are yet to be decided. See PEP 612 for details.\n\ -\n\ Parameter specification variables can be introspected. e.g.:\n\ \n\ P.__name__ == 'P'\n\ - P.__bound__ == None\n\ - P.__covariant__ == False\n\ - P.__contravariant__ == False\n\ \n\ Note that only parameter specification variables defined in global scope can\n\ be pickled.\n\ @@ -1175,9 +1164,18 @@ static PyMethodDef typevartuple_methods[] = { }; PyDoc_STRVAR(typevartuple_doc, -"Type variable tuple.\n\ +"Type variable tuple. A specialized form of type variable that enables\n\ +variadic generics.\n\ +\n\ +The preferred way to construct a type variable tuple is via the dedicated syntax\n\ +for generic functions, classes, and type aliases, where a single\n\ +'*' indicates a type variable tuple:\n\ +\n\ + def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:\n\ + return (*tup[1:], tup[0])\n\ \n\ -Usage:\n\ +For compatibility with Python 3.11 and earlier, TypeVarTuple objects\n\ +can also be created as follows:\n\ \n\ Ts = TypeVarTuple('Ts') # Can be given any name\n\ \n\ @@ -1185,7 +1183,7 @@ Just as a TypeVar (type variable) is a placeholder for a single type,\n\ a TypeVarTuple is a placeholder for an *arbitrary* number of types. For\n\ example, if we define a generic class using a TypeVarTuple:\n\ \n\ - class C(Generic[*Ts]): ...\n\ + class C[*Ts]: ...\n\ \n\ Then we can parameterize that class with an arbitrary number of type\n\ arguments:\n\ @@ -1441,6 +1439,23 @@ PyDoc_STRVAR(typealias_doc, Type aliases are created through the type statement:\n\ \n\ type Alias = int\n\ +\n\ +In this example, Alias and int will be treated equivalently by static\n\ +type checkers.\n\ +\n\ +At runtime, Alias is an instance of TypeAliasType. The __name__ attribute\n\ +holds the name of the type alias. The value of the type\n\ +alias is stored in the __value__ attribute. It is evaluated lazily, so\n\ +the value is computed only if the attribute is accessed.\n\ +\n\ +Type aliases can also be generic:\n\ +\n\ + type ListOrSet[T] = list[T] | set[T]\n\ +\n\ +In this case, the type parameters of the alias are stored in the\n\ +__type_params__ attribute.\n\ +\n\ +See PEP 695 for more information.\n\ "); static PyNumberMethods typealias_as_number = { @@ -1489,14 +1504,14 @@ PyDoc_STRVAR(generic_doc, \n\ A generic type is typically declared by inheriting from\n\ this class parameterized with one or more type variables.\n\ -For example, a generic mapping type might be defined as::\n\ +For example, a generic mapping type might be defined as:\n\ \n\ class Mapping(Generic[KT, VT]):\n\ def __getitem__(self, key: KT) -> VT:\n\ ...\n\ # Etc.\n\ \n\ -This class can then be used as follows::\n\ +This class can then be used as follows:\n\ \n\ def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:\n\ try:\n\ From eca102ddac77a42c6fda62a283fe0802e0ff5549 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 11:33:09 -0700 Subject: [PATCH 0060/1206] [3.12] GH-104947: Make pathlib.PureWindowsPath comparisons consistent across platforms (GH-104948) (GH-104990) Use `str.lower()` rather than `ntpath.normcase()` to normalize case of Windows paths. This restores behaviour from Python 3.11. (cherry picked from commit ad0be361c9922a918c7c3eaf83e1d8f2b019279c) Co-authored-by: Barney Gale Co-authored-by: Gregory P. Smith --- Lib/pathlib.py | 5 ++++- Lib/test/test_pathlib.py | 1 + .../Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 3d68c161603d08..bfe26e1e167953 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -421,7 +421,10 @@ def _str_normcase(self): try: return self._str_normcase_cached except AttributeError: - self._str_normcase_cached = self._flavour.normcase(str(self)) + if _is_case_sensitive(self._flavour): + self._str_normcase_cached = str(self) + else: + self._str_normcase_cached = str(self).lower() return self._str_normcase_cached @property diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index ab2c2b232a0411..bc2947ec95b305 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -904,6 +904,7 @@ def test_eq(self): self.assertEqual(P('a/B'), P('A/b')) self.assertEqual(P('C:a/B'), P('c:A/b')) self.assertEqual(P('//Some/SHARE/a/B'), P('//somE/share/A/b')) + self.assertEqual(P('\u0130'), P('i\u0307')) def test_as_uri(self): P = self.cls diff --git a/Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst b/Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst new file mode 100644 index 00000000000000..4af73d73d2a717 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst @@ -0,0 +1,2 @@ +Make comparisons between :class:`pathlib.PureWindowsPath` objects consistent +across Windows and Posix to match 3.11 behavior. From 305d78b71481e309051b1b88f363805d8c0ad34a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 11:42:36 -0700 Subject: [PATCH 0061/1206] [3.12] GH-103631: Fix `PurePosixPath(PureWindowsPath(...))` separator handling (GH-104949) (GH-104991) For backwards compatibility, accept backslashes as path separators in `PurePosixPath` if an instance of `PureWindowsPath` is supplied. This restores behaviour from Python 3.11. (cherry picked from commit 328422ce6162eb18735a2c0de12f8a696be97d0c) Co-authored-by: Barney Gale Co-authored-by: Gregory P. Smith --- Lib/pathlib.py | 3 +++ Lib/test/test_pathlib.py | 6 ++++++ .../Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst | 2 ++ 3 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index bfe26e1e167953..a42085e3a3f802 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -300,6 +300,9 @@ def __init__(self, *args): for arg in args: if isinstance(arg, PurePath): path = arg._raw_path + if arg._flavour is ntpath and self._flavour is posixpath: + # GH-103631: Convert separators for backwards compatibility. + path = path.replace('\\', '/') else: try: path = os.fspath(arg) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index bc2947ec95b305..bf4decf9f97ae8 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -789,6 +789,12 @@ def test_div(self): pp = P('//a') / '/c' self.assertEqual(pp, P('/c')) + def test_parse_windows_path(self): + P = self.cls + p = P('c:', 'a', 'b') + pp = P(pathlib.PureWindowsPath('c:\\a\\b')) + self.assertEqual(p, pp) + class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase): cls = pathlib.PureWindowsPath diff --git a/Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst b/Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst new file mode 100644 index 00000000000000..d1eb2d3ed6191f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst @@ -0,0 +1,2 @@ +Fix ``pathlib.PurePosixPath(pathlib.PureWindowsPath(...))`` not converting +path separators to restore 3.11 compatible behavior. From 05189f3054e3a831967a1bb53d14d97c97e31598 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 14:02:42 -0700 Subject: [PATCH 0062/1206] [3.12] GH-101588: Deprecate pickle/copy/deepcopy support in itertools (GH-104965) (GH-104997) --- Doc/whatsnew/3.12.rst | 6 +++ Lib/test/test_itertools.py | 49 ++++++++++++++++++- ...-05-26-01-31-30.gh-issue-101588.RaqxFy.rst | 1 + Modules/itertoolsmodule.c | 44 ++++++++++++++++- 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3e924a5da6f534..9f8f7d4ca1e72c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1069,6 +1069,12 @@ Pending Removal in Python 3.14 functions that have been deprecated since Python 2 but only gained a proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. +* :mod:`itertools` had undocumented, inefficient, historically buggy, + and inconsistent support for copy, deepcopy, and pickle operations. + This will be removed in 3.14 for a significant reduction in code + volume and maintenance burden. + (Contributed by Raymond Hettinger in :gh:`101588`.) + * Accessing ``co_lnotab`` was deprecated in :pep:`626` since 3.10 and was planned to be removed in 3.12 but it only got a proper :exc:`DeprecationWarning` in 3.12. diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 9fe559d4b7eed5..4d6ea780e15373 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -15,6 +15,26 @@ import struct import threading import gc +import warnings + +def pickle_deprecated(testfunc): + """ Run the test three times. + First, verify that a Deprecation Warning is raised. + Second, run normally but with DeprecationWarnings temporarily disabled. + Third, run with warnings promoted to errors. + """ + def inner(self): + with self.assertWarns(DeprecationWarning): + testfunc(self) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=DeprecationWarning) + testfunc(self) + with warnings.catch_warnings(): + warnings.simplefilter("error", category=DeprecationWarning) + with self.assertRaises((DeprecationWarning, AssertionError, SystemError)): + testfunc(self) + + return inner maxsize = support.MAX_Py_ssize_t minsize = -maxsize-1 @@ -124,6 +144,7 @@ def expand(it, i=0): c = expand(compare[took:]) self.assertEqual(a, c); + @pickle_deprecated def test_accumulate(self): self.assertEqual(list(accumulate(range(10))), # one positional arg [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]) @@ -220,6 +241,7 @@ def test_chain_from_iterable(self): self.assertRaises(TypeError, list, chain.from_iterable([2, 3])) self.assertEqual(list(islice(chain.from_iterable(repeat(range(5))), 2)), [0, 1]) + @pickle_deprecated def test_chain_reducible(self): for oper in [copy.deepcopy] + picklecopiers: it = chain('abc', 'def') @@ -233,6 +255,7 @@ def test_chain_reducible(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, chain('abc', 'def'), compare=list('abcdef')) + @pickle_deprecated def test_chain_setstate(self): self.assertRaises(TypeError, chain().__setstate__, ()) self.assertRaises(TypeError, chain().__setstate__, []) @@ -246,6 +269,7 @@ def test_chain_setstate(self): it.__setstate__((iter(['abc', 'def']), iter(['ghi']))) self.assertEqual(list(it), ['ghi', 'a', 'b', 'c', 'd', 'e', 'f']) + @pickle_deprecated def test_combinations(self): self.assertRaises(TypeError, combinations, 'abc') # missing r argument self.assertRaises(TypeError, combinations, 'abc', 2, 1) # too many arguments @@ -269,7 +293,6 @@ def test_combinations(self): self.assertEqual(list(op(testIntermediate)), [(0,1,3), (0,2,3), (1,2,3)]) - def combinations1(iterable, r): 'Pure python version shown in the docs' pool = tuple(iterable) @@ -337,6 +360,7 @@ def test_combinations_tuple_reuse(self): self.assertEqual(len(set(map(id, combinations('abcde', 3)))), 1) self.assertNotEqual(len(set(map(id, list(combinations('abcde', 3))))), 1) + @pickle_deprecated def test_combinations_with_replacement(self): cwr = combinations_with_replacement self.assertRaises(TypeError, cwr, 'abc') # missing r argument @@ -425,6 +449,7 @@ def test_combinations_with_replacement_tuple_reuse(self): self.assertEqual(len(set(map(id, cwr('abcde', 3)))), 1) self.assertNotEqual(len(set(map(id, list(cwr('abcde', 3))))), 1) + @pickle_deprecated def test_permutations(self): self.assertRaises(TypeError, permutations) # too few arguments self.assertRaises(TypeError, permutations, 'abc', 2, 1) # too many arguments @@ -531,6 +556,7 @@ def test_combinatorics(self): self.assertEqual(comb, list(filter(set(perm).__contains__, cwr))) # comb: cwr that is a perm self.assertEqual(comb, sorted(set(cwr) & set(perm))) # comb: both a cwr and a perm + @pickle_deprecated def test_compress(self): self.assertEqual(list(compress(data='ABCDEF', selectors=[1,0,1,0,1,1])), list('ACEF')) self.assertEqual(list(compress('ABCDEF', [1,0,1,0,1,1])), list('ACEF')) @@ -564,7 +590,7 @@ def test_compress(self): next(testIntermediate) self.assertEqual(list(op(testIntermediate)), list(result2)) - + @pickle_deprecated def test_count(self): self.assertEqual(lzip('abc',count()), [('a', 0), ('b', 1), ('c', 2)]) self.assertEqual(lzip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)]) @@ -613,6 +639,7 @@ def test_count(self): #check proper internal error handling for large "step' sizes count(1, maxsize+5); sys.exc_info() + @pickle_deprecated def test_count_with_stride(self): self.assertEqual(lzip('abc',count(2,3)), [('a', 2), ('b', 5), ('c', 8)]) self.assertEqual(lzip('abc',count(start=2,step=3)), @@ -675,6 +702,7 @@ def test_cycle(self): self.assertRaises(TypeError, cycle, 5) self.assertEqual(list(islice(cycle(gen3()),10)), [0,1,2,0,1,2,0,1,2,0]) + @pickle_deprecated def test_cycle_copy_pickle(self): # check copy, deepcopy, pickle c = cycle('abc') @@ -711,6 +739,7 @@ def test_cycle_copy_pickle(self): d = pickle.loads(p) # rebuild the cycle object self.assertEqual(take(20, d), list('cdeabcdeabcdeabcdeab')) + @pickle_deprecated def test_cycle_unpickle_compat(self): testcases = [ b'citertools\ncycle\n(c__builtin__\niter\n((lI1\naI2\naI3\natRI1\nbtR((lI1\naI0\ntb.', @@ -742,6 +771,7 @@ def test_cycle_unpickle_compat(self): it = pickle.loads(t) self.assertEqual(take(10, it), [2, 3, 1, 2, 3, 1, 2, 3, 1, 2]) + @pickle_deprecated def test_cycle_setstate(self): # Verify both modes for restoring state @@ -778,6 +808,7 @@ def test_cycle_setstate(self): self.assertRaises(TypeError, cycle('').__setstate__, ()) self.assertRaises(TypeError, cycle('').__setstate__, ([],)) + @pickle_deprecated def test_groupby(self): # Check whether it accepts arguments correctly self.assertEqual([], list(groupby([]))) @@ -935,6 +966,7 @@ def test_filter(self): c = filter(isEven, range(6)) self.pickletest(proto, c) + @pickle_deprecated def test_filterfalse(self): self.assertEqual(list(filterfalse(isEven, range(6))), [1,3,5]) self.assertEqual(list(filterfalse(None, [0,1,0,2,0])), [0,0,0]) @@ -965,6 +997,7 @@ def test_zip(self): lzip('abc', 'def')) @support.impl_detail("tuple reuse is specific to CPython") + @pickle_deprecated def test_zip_tuple_reuse(self): ids = list(map(id, zip('abc', 'def'))) self.assertEqual(min(ids), max(ids)) @@ -1040,6 +1073,7 @@ def test_zip_longest_tuple_reuse(self): ids = list(map(id, list(zip_longest('abc', 'def')))) self.assertEqual(len(dict.fromkeys(ids)), len(ids)) + @pickle_deprecated def test_zip_longest_pickling(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, zip_longest("abc", "def")) @@ -1186,6 +1220,7 @@ def test_product_tuple_reuse(self): self.assertEqual(len(set(map(id, product('abc', 'def')))), 1) self.assertNotEqual(len(set(map(id, list(product('abc', 'def'))))), 1) + @pickle_deprecated def test_product_pickling(self): # check copy, deepcopy, pickle for args, result in [ @@ -1201,6 +1236,7 @@ def test_product_pickling(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, product(*args)) + @pickle_deprecated def test_product_issue_25021(self): # test that indices are properly clamped to the length of the tuples p = product((1, 2),(3,)) @@ -1211,6 +1247,7 @@ def test_product_issue_25021(self): p.__setstate__((0, 0, 0x1000)) # will access tuple element 1 if not clamped self.assertRaises(StopIteration, next, p) + @pickle_deprecated def test_repeat(self): self.assertEqual(list(repeat(object='a', times=3)), ['a', 'a', 'a']) self.assertEqual(lzip(range(3),repeat('a')), @@ -1243,6 +1280,7 @@ def test_repeat_with_negative_times(self): self.assertEqual(repr(repeat('a', times=-1)), "repeat('a', 0)") self.assertEqual(repr(repeat('a', times=-2)), "repeat('a', 0)") + @pickle_deprecated def test_map(self): self.assertEqual(list(map(operator.pow, range(3), range(1,7))), [0**1, 1**2, 2**3]) @@ -1273,6 +1311,7 @@ def test_map(self): c = map(tupleize, 'abc', count()) self.pickletest(proto, c) + @pickle_deprecated def test_starmap(self): self.assertEqual(list(starmap(operator.pow, zip(range(3), range(1,7)))), [0**1, 1**2, 2**3]) @@ -1300,6 +1339,7 @@ def test_starmap(self): c = starmap(operator.pow, zip(range(3), range(1,7))) self.pickletest(proto, c) + @pickle_deprecated def test_islice(self): for args in [ # islice(args) should agree with range(args) (10, 20, 3), @@ -1394,6 +1434,7 @@ def __index__(self): self.assertEqual(list(islice(range(100), IntLike(10), IntLike(50), IntLike(5))), list(range(10,50,5))) + @pickle_deprecated def test_takewhile(self): data = [1, 3, 5, 20, 2, 4, 6, 8] self.assertEqual(list(takewhile(underten, data)), [1, 3, 5]) @@ -1414,6 +1455,7 @@ def test_takewhile(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, takewhile(underten, data)) + @pickle_deprecated def test_dropwhile(self): data = [1, 3, 5, 20, 2, 4, 6, 8] self.assertEqual(list(dropwhile(underten, data)), [20, 2, 4, 6, 8]) @@ -1431,6 +1473,7 @@ def test_dropwhile(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): self.pickletest(proto, dropwhile(underten, data)) + @pickle_deprecated def test_tee(self): n = 200 @@ -1732,6 +1775,7 @@ class TestExamples(unittest.TestCase): def test_accumulate(self): self.assertEqual(list(accumulate([1,2,3,4,5])), [1, 3, 6, 10, 15]) + @pickle_deprecated def test_accumulate_reducible(self): # check copy, deepcopy, pickle data = [1, 2, 3, 4, 5] @@ -1747,6 +1791,7 @@ def test_accumulate_reducible(self): self.assertEqual(list(copy.deepcopy(it)), accumulated[1:]) self.assertEqual(list(copy.copy(it)), accumulated[1:]) + @pickle_deprecated def test_accumulate_reducible_none(self): # Issue #25718: total is None it = accumulate([None, None, None], operator.is_) diff --git a/Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst b/Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst new file mode 100644 index 00000000000000..07e3dc468f7d9a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst @@ -0,0 +1 @@ +Deprecate undocumented copy/deepcopy/pickle support for itertools. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 555eab09935e9e..4a6d1314b3864e 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -93,6 +93,16 @@ class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" #undef clinic_state_by_cls #undef clinic_state +/* Deprecation of pickle support: GH-101588 *********************************/ + +#define ITERTOOL_PICKLE_DEPRECATION \ + if (PyErr_WarnEx( \ + PyExc_DeprecationWarning, \ + "Itertool pickle/copy/deepcopy support " \ + "will be removed in a Python 3.14.", 1) < 0) { \ + return NULL; \ + } + /* batched object ************************************************************/ /* Note: The built-in zip() function includes a "strict" argument @@ -506,6 +516,7 @@ groupby_reduce(groupbyobject *lz, PyObject *Py_UNUSED(ignored)) /* reduce as a 'new' call with an optional 'setstate' if groupby * has started */ + ITERTOOL_PICKLE_DEPRECATION; PyObject *value; if (lz->tgtkey && lz->currkey && lz->currvalue) value = Py_BuildValue("O(OO)(OOO)", Py_TYPE(lz), @@ -522,6 +533,7 @@ PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyObject * groupby_setstate(groupbyobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *currkey, *currvalue, *tgtkey; if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, "state is not a tuple"); @@ -660,6 +672,7 @@ _grouper_next(_grouperobject *igo) static PyObject * _grouper_reduce(_grouperobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (((groupbyobject *)lz->parent)->currgrouper != lz) { return Py_BuildValue("N(())", _PyEval_GetBuiltin(&_Py_ID(iter))); } @@ -828,6 +841,7 @@ teedataobject_dealloc(teedataobject *tdo) static PyObject * teedataobject_reduce(teedataobject *tdo, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; int i; /* create a temporary list of already iterated values */ PyObject *values = PyList_New(tdo->numread); @@ -1041,12 +1055,14 @@ tee_dealloc(teeobject *to) static PyObject * tee_reduce(teeobject *to, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(())(Oi)", Py_TYPE(to), to->dataobj, to->index); } static PyObject * tee_setstate(teeobject *to, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; teedataobject *tdo; int index; if (!PyTuple_Check(state)) { @@ -1275,6 +1291,7 @@ cycle_next(cycleobject *lz) static PyObject * cycle_reduce(cycleobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* Create a new cycle with the iterator tuple, then set the saved state */ if (lz->it == NULL) { PyObject *it = PyObject_GetIter(lz->saved); @@ -1298,6 +1315,7 @@ cycle_reduce(cycleobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * cycle_setstate(cycleobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *saved=NULL; int firstpass; if (!PyTuple_Check(state)) { @@ -1446,12 +1464,14 @@ dropwhile_next(dropwhileobject *lz) static PyObject * dropwhile_reduce(dropwhileobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)l", Py_TYPE(lz), lz->func, lz->it, lz->start); } static PyObject * dropwhile_setstate(dropwhileobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; int start = PyObject_IsTrue(state); if (start < 0) return NULL; @@ -1584,12 +1604,14 @@ takewhile_next(takewhileobject *lz) static PyObject * takewhile_reduce(takewhileobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)l", Py_TYPE(lz), lz->func, lz->it, lz->stop); } static PyObject * takewhile_reduce_setstate(takewhileobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; int stop = PyObject_IsTrue(state); if (stop < 0) @@ -1786,6 +1808,7 @@ islice_next(isliceobject *lz) static PyObject * islice_reduce(isliceobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* When unpickled, generate a new object with the same bounds, * then 'setstate' with the next and count */ @@ -1818,6 +1841,7 @@ islice_reduce(isliceobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * islice_setstate(isliceobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; Py_ssize_t cnt = PyLong_AsSsize_t(state); if (cnt == -1 && PyErr_Occurred()) @@ -1953,6 +1977,7 @@ starmap_next(starmapobject *lz) static PyObject * starmap_reduce(starmapobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* Just pickle the iterator */ return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it); } @@ -2109,6 +2134,7 @@ chain_next(chainobject *lz) static PyObject * chain_reduce(chainobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->source) { /* we can't pickle function objects (itertools.from_iterable) so * we must use setstate to replace the iterable. One day we @@ -2128,6 +2154,7 @@ chain_reduce(chainobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * chain_setstate(chainobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *source, *active=NULL; if (!PyTuple_Check(state)) { @@ -2403,6 +2430,7 @@ product_next(productobject *lz) static PyObject * product_reduce(productobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->stopped) { return Py_BuildValue("O(())", Py_TYPE(lz)); } else if (lz->result == NULL) { @@ -2433,6 +2461,7 @@ product_reduce(productobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * product_setstate(productobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *result; Py_ssize_t n, i; @@ -2711,6 +2740,7 @@ combinations_next(combinationsobject *co) static PyObject * combinations_reduce(combinationsobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->result == NULL) { return Py_BuildValue("O(On)", Py_TYPE(lz), lz->pool, lz->r); } else if (lz->stopped) { @@ -2740,6 +2770,7 @@ combinations_reduce(combinationsobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * combinations_setstate(combinationsobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *result; Py_ssize_t i; Py_ssize_t n = PyTuple_GET_SIZE(lz->pool); @@ -3019,6 +3050,7 @@ cwr_next(cwrobject *co) static PyObject * cwr_reduce(cwrobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->result == NULL) { return Py_BuildValue("O(On)", Py_TYPE(lz), lz->pool, lz->r); } else if (lz->stopped) { @@ -3047,6 +3079,7 @@ cwr_reduce(cwrobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * cwr_setstate(cwrobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *result; Py_ssize_t n, i; @@ -3354,6 +3387,7 @@ permutations_next(permutationsobject *po) static PyObject * permutations_reduce(permutationsobject *po, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (po->result == NULL) { return Py_BuildValue("O(On)", Py_TYPE(po), po->pool, po->r); } else if (po->stopped) { @@ -3396,6 +3430,7 @@ permutations_reduce(permutationsobject *po, PyObject *Py_UNUSED(ignored)) static PyObject * permutations_setstate(permutationsobject *po, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *indices, *cycles, *result; Py_ssize_t n, i; @@ -3593,6 +3628,7 @@ accumulate_next(accumulateobject *lz) static PyObject * accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; itertools_state *state = lz->state; if (lz->initial != Py_None) { @@ -3628,6 +3664,7 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * accumulate_setstate(accumulateobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; Py_INCREF(state); Py_XSETREF(lz->total, state); Py_RETURN_NONE; @@ -3776,6 +3813,7 @@ compress_next(compressobject *lz) static PyObject * compress_reduce(compressobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->data, lz->selectors); } @@ -3908,6 +3946,7 @@ filterfalse_next(filterfalseobject *lz) static PyObject * filterfalse_reduce(filterfalseobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it); } @@ -4135,6 +4174,7 @@ count_repr(countobject *lz) static PyObject * count_reduce(countobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->cnt == PY_SSIZE_T_MAX) return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->long_cnt, lz->long_step); return Py_BuildValue("O(n)", Py_TYPE(lz), lz->cnt); @@ -4258,6 +4298,7 @@ PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list( static PyObject * repeat_reduce(repeatobject *ro, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* unpickle this so that a new repeat iterator is constructed with an * object, then call __setstate__ on it to set cnt */ @@ -4478,7 +4519,7 @@ zip_longest_next(ziplongestobject *lz) static PyObject * zip_longest_reduce(ziplongestobject *lz, PyObject *Py_UNUSED(ignored)) { - + ITERTOOL_PICKLE_DEPRECATION; /* Create a new tuple with empty sequences where appropriate to pickle. * Then use setstate to set the fillvalue */ @@ -4505,6 +4546,7 @@ zip_longest_reduce(ziplongestobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * zip_longest_setstate(ziplongestobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; Py_INCREF(state); Py_XSETREF(lz->fillvalue, state); Py_RETURN_NONE; From 2c02c6886739f0ed420d900b2a29933bc1c5df37 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 15:14:45 -0700 Subject: [PATCH 0063/1206] [3.12] gh-104976: Ensure trailing dedent tokens are emitted as the previous tokenizer (GH-104980) (#105000) --- Lib/test/test_tokenize.py | 15 ++++++----- Lib/tokenize.py | 5 ---- ...-05-26-15-16-11.gh-issue-104976.6dLitD.rst | 3 +++ Python/Python-tokenize.c | 26 ++++++++++++++++--- 4 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 0b7c25838d6782..abb68859be944c 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -82,7 +82,7 @@ def test_basic(self): NAME 'False' (4, 11) (4, 16) COMMENT '# NEWLINE' (4, 17) (4, 26) NEWLINE '\\n' (4, 26) (4, 27) - DEDENT '' (4, 27) (4, 27) + DEDENT '' (5, 0) (5, 0) """) indent_error_file = b"""\ def k(x): @@ -755,8 +755,8 @@ def test_tabs(self): NEWLINE '\\n' (2, 5) (2, 6) INDENT ' \\t' (3, 0) (3, 9) NAME 'pass' (3, 9) (3, 13) - DEDENT '' (3, 14) (3, 14) - DEDENT '' (3, 14) (3, 14) + DEDENT '' (4, 0) (4, 0) + DEDENT '' (4, 0) (4, 0) """) def test_non_ascii_identifiers(self): @@ -968,7 +968,7 @@ async def foo(): NUMBER '1' (2, 17) (2, 18) OP ':' (2, 18) (2, 19) NAME 'pass' (2, 20) (2, 24) - DEDENT '' (2, 25) (2, 25) + DEDENT '' (3, 0) (3, 0) """) self.check_tokenize('''async def foo(async): await''', """\ @@ -1016,7 +1016,7 @@ async def bar(): pass NAME 'await' (6, 2) (6, 7) OP '=' (6, 8) (6, 9) NUMBER '2' (6, 10) (6, 11) - DEDENT '' (6, 12) (6, 12) + DEDENT '' (7, 0) (7, 0) """) self.check_tokenize('''\ @@ -1054,7 +1054,7 @@ async def bar(): pass NAME 'await' (6, 2) (6, 7) OP '=' (6, 8) (6, 9) NUMBER '2' (6, 10) (6, 11) - DEDENT '' (6, 12) (6, 12) + DEDENT '' (7, 0) (7, 0) """) def test_newline_after_parenthesized_block_with_comment(self): @@ -2680,7 +2680,8 @@ def generate_source(indents): valid = generate_source(MAXINDENT - 1) tokens = list(_generate_tokens_from_c_tokenizer(valid)) - self.assertEqual(tokens[-1].type, DEDENT) + self.assertEqual(tokens[-2].type, DEDENT) + self.assertEqual(tokens[-1].type, ENDMARKER) compile(valid, "", "exec") invalid = generate_source(MAXINDENT) diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 911f0f12f9bb7e..4895e94d1dfda7 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -447,13 +447,8 @@ def tokenize(readline): def _tokenize(rl_gen, encoding): source = b"".join(rl_gen).decode(encoding) - token = None for token in _generate_tokens_from_c_tokenizer(source, extra_tokens=True): yield token - if token is not None: - last_line, _ = token.start - yield TokenInfo(ENDMARKER, '', (last_line + 1, 0), (last_line + 1, 0), '') - def generate_tokens(readline): """Tokenize a source reading Python code as unicode strings. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst new file mode 100644 index 00000000000000..377e8e76362687 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst @@ -0,0 +1,3 @@ +Ensure that trailing ``DEDENT`` :class:`tokenize.TokenInfo` objects emitted +by the :mod:`tokenize` module are reported as in Python 3.11. Patch by Pablo +Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 88087c12562413..01c2215366a736 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -30,6 +30,7 @@ class _tokenizer.tokenizeriter "tokenizeriterobject *" "_tokenize_get_state_by_t typedef struct { PyObject_HEAD struct tok_state *tok; + int done; } tokenizeriterobject; /*[clinic input] @@ -63,6 +64,7 @@ tokenizeriter_new_impl(PyTypeObject *type, const char *source, if (extra_tokens) { self->tok->tok_extra_tokens = 1; } + self->done = 0; return (PyObject *)self; } @@ -179,8 +181,9 @@ tokenizeriter_next(tokenizeriterobject *it) } goto exit; } - if (type == ERRORTOKEN || type == ENDMARKER) { + if (it->done || type == ERRORTOKEN) { PyErr_SetString(PyExc_StopIteration, "EOF"); + it->done = 1; goto exit; } PyObject *str = NULL; @@ -194,9 +197,19 @@ tokenizeriter_next(tokenizeriterobject *it) goto exit; } + int is_trailing_token = 0; + if (type == ENDMARKER || (type == DEDENT && it->tok->done == E_EOF)) { + is_trailing_token = 1; + } + const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start; - Py_ssize_t size = it->tok->inp - line_start; - PyObject *line = PyUnicode_DecodeUTF8(line_start, size, "replace"); + PyObject* line = NULL; + if (it->tok->tok_extra_tokens && is_trailing_token) { + line = PyUnicode_FromString(""); + } else { + Py_ssize_t size = it->tok->inp - line_start; + line = PyUnicode_DecodeUTF8(line_start, size, "replace"); + } if (line == NULL) { Py_DECREF(str); goto exit; @@ -214,6 +227,10 @@ tokenizeriter_next(tokenizeriterobject *it) } if (it->tok->tok_extra_tokens) { + if (is_trailing_token) { + lineno = end_lineno = lineno + 1; + col_offset = end_col_offset = 0; + } // Necessary adjustments to match the original Python tokenize // implementation if (type > DEDENT && type < OP) { @@ -231,6 +248,9 @@ tokenizeriter_next(tokenizeriterobject *it) result = Py_BuildValue("(iN(nn)(nn)N)", type, str, lineno, col_offset, end_lineno, end_col_offset, line); exit: _PyToken_Free(&token); + if (type == ENDMARKER) { + it->done = 1; + } return result; } From f625ec360324842d7123db7dfe05ca2e221eecfd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 18:41:21 -0700 Subject: [PATCH 0064/1206] [3.12] gh-104839: Prevent test_venv AddressSanitizer spam (GH-105005) (#105006) gh-104839: Prevent test_venv AddressSanitizer spam (GH-105005) Pass any ASAN_OPTIONS environment variable through to the child process so that leak sanitizer being disabled on our CI and buildbots stays true in the children. (cherry picked from commit a17f160376955d369c8d332e1b1a90a6e18c852a) Co-authored-by: Gregory P. Smith [Google] --- Lib/test/test_venv.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 95944c7c711620..5205604c2c7185 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -600,15 +600,14 @@ def test_zippath_from_non_installed_posix(self): ld_library_path_env = "DYLD_LIBRARY_PATH" else: ld_library_path_env = "LD_LIBRARY_PATH" - # Note that in address sanitizer mode, the current runtime - # implementation leaks memory due to not being able to correctly - # clean all unicode objects during runtime shutdown. Therefore, - # this uses subprocess.run instead of subprocess.check_call to - # maintain the core of the test while not failing due to the refleaks. - # This should be able to use check_call once all refleaks are fixed. - subprocess.run(cmd, - env={"PYTHONPATH": pythonpath, - ld_library_path_env: ld_library_path}) + child_env = { + "PYTHONPATH": pythonpath, + ld_library_path_env: ld_library_path, + } + if asan_options := os.environ.get("ASAN_OPTIONS"): + # prevent https://github.com/python/cpython/issues/104839 + child_env["ASAN_OPTIONS"] = asan_options + subprocess.check_call(cmd, env=child_env) envpy = os.path.join(self.env_dir, self.bindir, self.exe) # Now check the venv created from the non-installed python has # correct zip path in pythonpath. From 368d177da5bec2a71ab1af6e6f8e07ba6b2b1222 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 26 May 2023 19:17:09 -0700 Subject: [PATCH 0065/1206] [3.12] gh-104992: [What's New in 3.11] Document unittest.TestProgram.usageExit's deprecation (GH-104994) (#105009) gh-104992: [What's New in 3.11] Document unittest.TestProgram.usageExit's deprecation (GH-104994) Document unittest.TestProgram.usageExit's pending removal in 3.13 (cherry picked from commit 7df861c23cd61e7c55943d4036ea5c6b1df5cb49) Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.11.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 7a479c6e56a9f0..48606f3be42e3c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1856,6 +1856,10 @@ Standard Library (Contributed by Erlend E. Aasland in :issue:`5846`.) +* :meth:`~!unittest.TestProgram.usageExit` is marked deprecated, to be removed + in 3.13. + (Contributed by Carlos Damázio in :gh:`67048`.) + .. _whatsnew311-pending-removal: .. _whatsnew311-python-api-pending-removal: From edd0cb8e77d7b65f5a9c2c69dc81f9c4514878d5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 May 2023 03:10:03 -0700 Subject: [PATCH 0066/1206] [3.12] CI: Precompute hash for config cache key in check_source job (GH-105008) (#105014) Co-authored-by: Itamar Ostricher --- .github/workflows/build.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfb7f65c0fbad1..3ada845c4cbbc3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,6 +39,7 @@ jobs: outputs: run_tests: ${{ steps.check.outputs.run_tests }} run_hypothesis: ${{ steps.check.outputs.run_hypothesis }} + config_hash: ${{ steps.config_hash.outputs.hash }} steps: - uses: actions/checkout@v3 - name: Check for source changes @@ -74,6 +75,10 @@ jobs: echo "Run hypothesis tests" echo "run_hypothesis=true" >> $GITHUB_OUTPUT fi + - name: Compute hash for config cache key + id: config_hash + run: | + echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> $GITHUB_OUTPUT check_abi: name: 'Check if the ABI has changed' @@ -117,7 +122,7 @@ jobs: uses: actions/cache@v3 with: path: config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} + key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - uses: actions/setup-python@v3 - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh @@ -219,7 +224,7 @@ jobs: uses: actions/cache@v3 with: path: config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} + key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Install Homebrew dependencies run: brew install pkg-config openssl@1.1 xz gdbm tcl-tk - name: Configure CPython @@ -285,7 +290,7 @@ jobs: uses: actions/cache@v3 with: path: ${{ env.CPYTHON_BUILDDIR }}/config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} + key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | @@ -327,7 +332,7 @@ jobs: uses: actions/cache@v3 with: path: config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} + key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies @@ -406,7 +411,7 @@ jobs: uses: actions/cache@v3 with: path: ${{ env.CPYTHON_BUILDDIR }}/config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} + key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Configure CPython out-of-tree working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | @@ -485,7 +490,7 @@ jobs: uses: actions/cache@v3 with: path: config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }} + key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies From 2b176bc90269b400226d0219a05e9b4c49604c51 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 May 2023 10:24:30 -0700 Subject: [PATCH 0067/1206] [3.12] gh-105017: Fix including additional NL token when using CRLF (GH-105022) (#105023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marta Gómez Macías Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_tokenize.py | 8 ++++++++ .../2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst | 1 + Parser/tokenizer.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index abb68859be944c..293592b3fd13db 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -84,6 +84,14 @@ def test_basic(self): NEWLINE '\\n' (4, 26) (4, 27) DEDENT '' (5, 0) (5, 0) """) + + self.check_tokenize("foo='bar'\r\n", """\ + NAME 'foo' (1, 0) (1, 3) + OP '=' (1, 3) (1, 4) + STRING "'bar'" (1, 4) (1, 9) + NEWLINE '\\n' (1, 9) (1, 10) + """) + indent_error_file = b"""\ def k(x): x += 2 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst new file mode 100644 index 00000000000000..d41a2169ccb3de --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst @@ -0,0 +1 @@ +Do not include an additional final ``NL`` token when parsing files having CRLF lines. Patch by Marta Gómez. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 1e8f785a331ac5..b8c1c110b546fd 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -800,7 +800,7 @@ translate_newlines(const char *s, int exec_input, struct tok_state *tok) { } /* If this is exec input, add a newline to the end of the string if there isn't one already. */ - if (exec_input && c != '\n') { + if (exec_input && c != '\n' && c != '\0') { *current = '\n'; current++; } From 5426ff14765bda6c1bf5a74f8223edc144bc8b1f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 27 May 2023 14:51:05 -0700 Subject: [PATCH 0068/1206] [3.12] gh-104497: Make tkinter test pass with tk 8.7 (GH-104789) (#105028) For test_widgets.MenuTest.test_configure_type, the options in the error message change to alphabetical order. --------- (cherry picked from commit 897e716d03d559a10dd5015ecb501ceb98955f3a) Co-authored-by: Terry Jan Reedy Co-authored-by: Serhiy Storchaka --- Lib/test/test_tkinter/test_widgets.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 76cc16e5b977de..34e67c0cbc44a3 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1408,10 +1408,13 @@ def test_configure_title(self): def test_configure_type(self): widget = self.create() + opts = ('normal, tearoff, or menubar' + if widget.info_patchlevel() < (8, 7) else + 'menubar, normal, or tearoff') self.checkEnumParam( widget, 'type', 'normal', 'tearoff', 'menubar', - errmsg='bad type "{}": must be normal, tearoff, or menubar', + errmsg='bad type "{}": must be ' + opts, ) def test_entryconfigure(self): From 36a4227859fe4cb5a3ad79ea6da99b4d8b405a8d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 May 2023 01:12:30 -0700 Subject: [PATCH 0069/1206] [3.12] gh-104992: [What's New in 3.12] Document unittest.TestProgram.usageExit's deprecation (GH-104995) (#105036) Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 9f8f7d4ca1e72c..7b266b2e94b240 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1015,8 +1015,9 @@ APIs: * :func:`locale.getdefaultlocale` (:gh:`90817`) * :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`) * :func:`!unittest.findTestCases` (:gh:`50096`) -* :func:`!unittest.makeSuite` (:gh:`50096`) * :func:`!unittest.getTestCaseNames` (:gh:`50096`) +* :func:`!unittest.makeSuite` (:gh:`50096`) +* :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`) * :class:`!webbrowser.MacOSX` (:gh:`86421`) * :class:`classmethod` descriptor chaining (:gh:`89519`) From 41b622b1e8736bd86c8dc2e1471121d5f6a88937 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 May 2023 04:18:43 -0700 Subject: [PATCH 0070/1206] [3.12] gh-105013: Fix inspect.getsource with parenthesized multiline lambdas (GH-105021) (#105032) gh-105013: Fix inspect.getsource with parenthesized multiline lambdas (GH-105021) (cherry picked from commit 3a5be878be6f89ee98d0ef9a1274e6a9d9ccbc37) Co-authored-by: Pablo Galindo Salgado --- Lib/inspect.py | 8 ++++++++ Lib/test/inspect_fodder2.py | 17 +++++++++++++++++ Lib/test/test_inspect.py | 16 ++++++++++++++++ ...23-05-27-16-57-11.gh-issue-105013.IsDgDY.rst | 2 ++ 4 files changed, 43 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index 7709a95003efbd..55530fc780b35c 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1242,6 +1242,14 @@ def getblock(lines): blockfinder.tokeneater(*_token) except (EndOfBlock, IndentationError): pass + except SyntaxError as e: + if "unmatched" not in e.msg: + raise e from None + _, *_token_info = _token + try: + blockfinder.tokeneater(tokenize.NEWLINE, *_token_info) + except (EndOfBlock, IndentationError): + pass return lines[:blockfinder.last] def getsourcelines(object): diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/inspect_fodder2.py index 2dc49817087c44..03464613694605 100644 --- a/Lib/test/inspect_fodder2.py +++ b/Lib/test/inspect_fodder2.py @@ -273,3 +273,20 @@ def wrapper(*a, **kwd): @deco_factory(foo=(1 + 2), bar=lambda: 1) def complex_decorated(foo=0, bar=lambda: 0): return foo + bar() + +# line 276 +parenthesized_lambda = ( + lambda: ()) +parenthesized_lambda2 = [ + lambda: ()][0] +parenthesized_lambda3 = {0: + lambda: ()}[0] + +# line 285 +post_line_parenthesized_lambda1 = (lambda: () +) + +# line 289 +nested_lambda = ( + lambda right: [].map( + lambda length: ())) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index ade32151eaf233..a7bd680d0f5bcc 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -776,6 +776,22 @@ def test_twoline_indented_lambda(self): # where the second line _is_ indented. self.assertSourceEqual(mod2.tlli, 33, 34) + def test_parenthesized_multiline_lambda(self): + # Test inspect.getsource with a parenthesized multi-line lambda + # function. + self.assertSourceEqual(mod2.parenthesized_lambda, 279, 279) + self.assertSourceEqual(mod2.parenthesized_lambda2, 281, 281) + self.assertSourceEqual(mod2.parenthesized_lambda3, 283, 283) + + def test_post_line_parenthesized_lambda(self): + # Test inspect.getsource with a parenthesized multi-line lambda + # function. + self.assertSourceEqual(mod2.post_line_parenthesized_lambda1, 286, 287) + + def test_nested_lambda(self): + # Test inspect.getsource with a nested lambda function. + self.assertSourceEqual(mod2.nested_lambda, 291, 292) + def test_onelinefunc(self): # Test inspect.getsource with a regular one-line function. self.assertSourceEqual(mod2.onelinefunc, 37, 37) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst new file mode 100644 index 00000000000000..a9917c2849982a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst @@ -0,0 +1,2 @@ +Fix handling of multiline parenthesized lambdas in +:func:`inspect.getsource`. Patch by Pablo Galindo From 3f8d5d9ed60ae0f70c92dc29587cc6367eda80c3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 May 2023 07:16:43 -0700 Subject: [PATCH 0071/1206] [3.12] gh-105017: Include CRLF lines in strings and column numbers (GH-105030) (#105041) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-105017: Include CRLF lines in strings and column numbers (GH-105030) (cherry picked from commit 96fff35325e519cc76ffacf22e57e4c393d4446f) Co-authored-by: Marta Gómez Macías Co-authored-by: Pablo Galindo --- Lib/test/test_tokenize.py | 44 +++++++++++++++---- ...-05-27-21-50-48.gh-issue-105017.4sDyDV.rst | 1 + Parser/pegen.c | 4 +- Parser/tokenizer.c | 38 +++++++++++----- Parser/tokenizer.h | 4 +- Python/Python-tokenize.c | 9 +++- 6 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 293592b3fd13db..cd11dddd0fe51a 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -85,11 +85,29 @@ def test_basic(self): DEDENT '' (5, 0) (5, 0) """) - self.check_tokenize("foo='bar'\r\n", """\ - NAME 'foo' (1, 0) (1, 3) - OP '=' (1, 3) (1, 4) - STRING "'bar'" (1, 4) (1, 9) - NEWLINE '\\n' (1, 9) (1, 10) + self.check_tokenize("if True:\r\n # NL\r\n foo='bar'\r\n\r\n", """\ + NAME 'if' (1, 0) (1, 2) + NAME 'True' (1, 3) (1, 7) + OP ':' (1, 7) (1, 8) + NEWLINE '\\r\\n' (1, 8) (1, 10) + COMMENT '# NL' (2, 4) (2, 8) + NL '\\r\\n' (2, 8) (2, 10) + INDENT ' ' (3, 0) (3, 4) + NAME 'foo' (3, 4) (3, 7) + OP '=' (3, 7) (3, 8) + STRING "\'bar\'" (3, 8) (3, 13) + NEWLINE '\\r\\n' (3, 13) (3, 15) + NL '\\r\\n' (4, 0) (4, 2) + DEDENT '' (5, 0) (5, 0) + """) + + self.check_tokenize("x = 1 + \\\r\n1\r\n", """\ + NAME 'x' (1, 0) (1, 1) + OP '=' (1, 2) (1, 3) + NUMBER '1' (1, 4) (1, 5) + OP '+' (1, 6) (1, 7) + NUMBER '1' (2, 0) (2, 1) + NEWLINE '\\r\\n' (2, 1) (2, 3) """) indent_error_file = b"""\ @@ -1784,9 +1802,9 @@ def test_random_files(self): if support.verbose >= 2: print('tokenize', testfile) with open(testfile, 'rb') as f: - # with self.subTest(file=testfile): - self.check_roundtrip(f) - self.check_line_extraction(f) + with self.subTest(file=testfile): + self.check_roundtrip(f) + self.check_line_extraction(f) def roundtrip(self, code): @@ -2084,6 +2102,10 @@ def test_string(self): b\ c"""', """\ STRING 'rb"\""a\\\\\\nb\\\\\\nc"\""' (1, 0) (3, 4) + """) + + self.check_tokenize(r'"hola\\\r\ndfgf"', """\ + STRING \'"hola\\\\\\\\\\\\r\\\\ndfgf"\' (1, 0) (1, 16) """) self.check_tokenize('f"abc"', """\ @@ -2120,6 +2142,12 @@ def test_string(self): FSTRING_START 'Rf"' (1, 0) (1, 3) FSTRING_MIDDLE 'abc\\\\\\ndef' (1, 3) (2, 3) FSTRING_END '"' (2, 3) (2, 4) + """) + + self.check_tokenize(r'f"hola\\\r\ndfgf"', """\ + FSTRING_START \'f"\' (1, 0) (1, 2) + FSTRING_MIDDLE 'hola\\\\\\\\\\\\r\\\\ndfgf' (1, 2) (1, 16) + FSTRING_END \'"\' (1, 16) (1, 17) """) def test_function(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst new file mode 100644 index 00000000000000..02d653c2d658eb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst @@ -0,0 +1 @@ +Show CRLF lines in the tokenize string attribute in both NL and NEWLINE tokens. Patch by Marta Gómez. diff --git a/Parser/pegen.c b/Parser/pegen.c index b031a6f5d440e8..b9894dd0acc546 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -924,9 +924,9 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen struct tok_state *tok; if (flags != NULL && flags->cf_flags & PyCF_IGNORE_COOKIE) { - tok = _PyTokenizer_FromUTF8(str, exec_input); + tok = _PyTokenizer_FromUTF8(str, exec_input, 0); } else { - tok = _PyTokenizer_FromString(str, exec_input); + tok = _PyTokenizer_FromString(str, exec_input, 0); } if (tok == NULL) { if (PyErr_Occurred()) { diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index b8c1c110b546fd..9058c67ada6486 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -772,7 +772,8 @@ translate_into_utf8(const char* str, const char* enc) { static char * -translate_newlines(const char *s, int exec_input, struct tok_state *tok) { +translate_newlines(const char *s, int exec_input, int preserve_crlf, + struct tok_state *tok) { int skip_next_lf = 0; size_t needed_length = strlen(s) + 2, final_length; char *buf, *current; @@ -792,7 +793,7 @@ translate_newlines(const char *s, int exec_input, struct tok_state *tok) { break; } } - if (c == '\r') { + if (!preserve_crlf && c == '\r') { skip_next_lf = 1; c = '\n'; } @@ -822,14 +823,14 @@ translate_newlines(const char *s, int exec_input, struct tok_state *tok) { inside TOK. */ static char * -decode_str(const char *input, int single, struct tok_state *tok) +decode_str(const char *input, int single, struct tok_state *tok, int preserve_crlf) { PyObject* utf8 = NULL; char *str; const char *s; const char *newl[2] = {NULL, NULL}; int lineno = 0; - tok->input = str = translate_newlines(input, single, tok); + tok->input = str = translate_newlines(input, single, preserve_crlf, tok); if (str == NULL) return NULL; tok->enc = NULL; @@ -881,14 +882,14 @@ decode_str(const char *input, int single, struct tok_state *tok) /* Set up tokenizer for string */ struct tok_state * -_PyTokenizer_FromString(const char *str, int exec_input) +_PyTokenizer_FromString(const char *str, int exec_input, int preserve_crlf) { struct tok_state *tok = tok_new(); char *decoded; if (tok == NULL) return NULL; - decoded = decode_str(str, exec_input, tok); + decoded = decode_str(str, exec_input, tok, preserve_crlf); if (decoded == NULL) { _PyTokenizer_Free(tok); return NULL; @@ -902,13 +903,13 @@ _PyTokenizer_FromString(const char *str, int exec_input) /* Set up tokenizer for UTF-8 string */ struct tok_state * -_PyTokenizer_FromUTF8(const char *str, int exec_input) +_PyTokenizer_FromUTF8(const char *str, int exec_input, int preserve_crlf) { struct tok_state *tok = tok_new(); char *translated; if (tok == NULL) return NULL; - tok->input = translated = translate_newlines(str, exec_input, tok); + tok->input = translated = translate_newlines(str, exec_input, preserve_crlf, tok); if (translated == NULL) { _PyTokenizer_Free(tok); return NULL; @@ -1050,7 +1051,7 @@ tok_underflow_interactive(struct tok_state *tok) { } char *newtok = PyOS_Readline(tok->fp ? tok->fp : stdin, stdout, tok->prompt); if (newtok != NULL) { - char *translated = translate_newlines(newtok, 0, tok); + char *translated = translate_newlines(newtok, 0, 0, tok); PyMem_Free(newtok); if (translated == NULL) { return 0; @@ -1594,6 +1595,9 @@ tok_decimal_tail(struct tok_state *tok) static inline int tok_continuation_line(struct tok_state *tok) { int c = tok_nextc(tok); + if (c == '\r') { + c = tok_nextc(tok); + } if (c != '\n') { tok->done = E_LINECONT; return -1; @@ -1693,7 +1697,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t } } tok_backup(tok, c); - if (c == '#' || c == '\n') { + if (c == '#' || c == '\n' || c == '\r') { /* Lines with only whitespace and/or comments shouldn't affect the indentation and are not passed to the parser as NEWLINE tokens, @@ -1822,7 +1826,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t const char *prefix, *type_start; int current_starting_col_offset; - while (c != EOF && c != '\n') { + while (c != EOF && c != '\n' && c != '\r') { c = tok_nextc(tok); } @@ -2002,6 +2006,10 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t return MAKE_TOKEN(NAME); } + if (c == '\r') { + c = tok_nextc(tok); + } + /* Newline */ if (c == '\n') { tok->atbol = 1; @@ -2405,7 +2413,10 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t else { end_quote_size = 0; if (c == '\\') { - tok_nextc(tok); /* skip escaped char */ + c = tok_nextc(tok); /* skip escaped char */ + if (c == '\r') { + c = tok_nextc(tok); + } } } } @@ -2696,6 +2707,9 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct return MAKE_TOKEN(FSTRING_MIDDLE); } else if (c == '\\') { int peek = tok_nextc(tok); + if (peek == '\r') { + peek = tok_nextc(tok); + } // Special case when the backslash is right before a curly // brace. We have to restore and return the control back // to the loop for the next iteration. diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 019f533ef2a260..02749e355da812 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -135,8 +135,8 @@ struct tok_state { #endif }; -extern struct tok_state *_PyTokenizer_FromString(const char *, int); -extern struct tok_state *_PyTokenizer_FromUTF8(const char *, int); +extern struct tok_state *_PyTokenizer_FromString(const char *, int, int); +extern struct tok_state *_PyTokenizer_FromUTF8(const char *, int, int); extern struct tok_state *_PyTokenizer_FromFile(FILE *, const char*, const char *, const char *); extern void _PyTokenizer_Free(struct tok_state *); diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 01c2215366a736..4eced66b617708 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -55,7 +55,7 @@ tokenizeriter_new_impl(PyTypeObject *type, const char *source, if (filename == NULL) { return NULL; } - self->tok = _PyTokenizer_FromUTF8(source, 1); + self->tok = _PyTokenizer_FromUTF8(source, 1, 1); if (self->tok == NULL) { Py_DECREF(filename); return NULL; @@ -240,7 +240,12 @@ tokenizeriter_next(tokenizeriterobject *it) type = NAME; } else if (type == NEWLINE) { - str = PyUnicode_FromString("\n"); + Py_DECREF(str); + if (it->tok->start[0] == '\r') { + str = PyUnicode_FromString("\r\n"); + } else { + str = PyUnicode_FromString("\n"); + } end_col_offset++; } } From 74bbc603e42d3b191358023811695d9fa4766076 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 28 May 2023 12:15:36 -0700 Subject: [PATCH 0072/1206] [3.12] Document PEP 698 and other new typing features in What's New (GH-104957) (#105045) Co-authored-by: Jelle Zijlstra --- Doc/whatsnew/3.12.rst | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 7b266b2e94b240..ef9e4012437f7d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -272,7 +272,36 @@ typed dictionaries:: See :pep:`692` for more details. -(PEP written by Franek Magiera) +(Contributed by Franek Magiera in :gh:`103629`.) + +PEP 698: Override Decorator for Static Typing +--------------------------------------------- + +A new decorator :func:`typing.override` has been added to the :mod:`typing` +module. It indicates to type checkers that the method is intended to override +a method in a superclass. This allows type checkers to catch mistakes where +a method that is intended to override something in a base class +does not in fact do so. + +Example:: + + from typing import override + + class Base: + def get_color(self) -> str: + return "blue" + + class GoodChild(Base): + @override # ok: overrides Base.get_color + def get_color(self) -> str: + return "yellow" + + class BadChild(Base): + @override # type checker error: does not override Base.get_color + def get_colour(self) -> str: + return "red" + +(Contributed by Steven Troxler in :gh:`101561`.) .. _whatsnew312-pep695: @@ -772,11 +801,6 @@ tempfile typing ------ -* Add :func:`typing.override`, an override decorator telling to static type - checkers to verify that a method overrides some method or attribute of the - same name on a base class, as per :pep:`698`. (Contributed by Steven Troxler in - :gh:`101564`.) - * :func:`isinstance` checks against :func:`runtime-checkable protocols ` now use :func:`inspect.getattr_static` rather than :func:`hasattr` to lookup whether @@ -821,6 +845,13 @@ typing or more members may be slower than in Python 3.11. (Contributed by Alex Waygood in :gh:`74690` and :gh:`103193`.) +* All :data:`typing.TypedDict` and :data:`typing.NamedTuple` classes now have the + ``__orig_bases__`` attribute. (Contributed by Adrian Garcia Badaracco in + :gh:`103699`.) + +* Add ``frozen_default`` parameter to :func:`typing.dataclass_transform`. + (Contributed by Erik De Bonte in :gh:`99957`.) + sys --- From 5dc6b18cb0c83faab556b46bdcf96ce21880fa91 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 May 2023 02:05:42 -0700 Subject: [PATCH 0073/1206] Fix compiler warning in unicodeobject.c (GH-105050) Fix compiler warning in unicodeobject.c (GH-105050) (cherry picked from commit e92ac0a741b125f1cffe8c07b054d1dea7b0a05a) Co-authored-by: Inada Naoki --- Objects/unicodeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index ec5684b1d09502..6f25f91c0ff28d 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -236,7 +236,7 @@ static inline PyObject *get_interned_dict(PyInterpreterState *interp) } Py_ssize_t -_PyUnicode_InternedSize() +_PyUnicode_InternedSize(void) { return PyObject_Length(get_interned_dict(_PyInterpreterState_GET())); } From 635ce29257a7f7272af009d3c08379522317d89b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 May 2023 05:36:08 -0700 Subject: [PATCH 0074/1206] gh-104803: Implement ntpath.isdevdrive for checking whether a path is on a Windows Dev Drive (GH-104805) (cherry picked from commit bfd20d257e4ad16a25f4bac0ea4dbb719cdf6bc7) Co-authored-by: Steve Dower --- Doc/library/os.path.rst | 18 ++++ Lib/ntpath.py | 16 ++++ Lib/test/test_ntpath.py | 20 +++++ ...-05-23-19-26-28.gh-issue-104803.gqxYml.rst | 3 + Modules/clinic/posixmodule.c.h | 70 ++++++++++++++- Modules/posixmodule.c | 90 +++++++++++++++++++ 6 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index 7881c52db87090..3a668e28f2e268 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -304,6 +304,24 @@ the :mod:`glob` module.) Accepts a :term:`path-like object`. +.. function:: isdevdrive(path) + + Return ``True`` if pathname *path* is located on a Windows Dev Drive. + A Dev Drive is optimized for developer scenarios, and offers faster + performance for reading and writing files. It is recommended for use for + source code, temporary build directories, package caches, and other + IO-intensive operations. + + May raise an error for an invalid path, for example, one without a + recognizable drive, but returns ``False`` on platforms that do not support + Dev Drives. See `the Windows documentation `_ + for information on enabling and creating Dev Drives. + + .. availability:: Windows. + + .. versionadded:: 3.12 + + .. function:: join(path, *paths) Join one or more path segments intelligently. The return value is the diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 0f3674fe11eecd..dadcdc0c495da1 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -867,3 +867,19 @@ def commonpath(paths): except ImportError: # Use genericpath.* as imported above pass + + +try: + from nt import _path_isdevdrive +except ImportError: + def isdevdrive(path): + """Determines whether the specified path is on a Windows Dev Drive.""" + # Never a Dev Drive + return False +else: + def isdevdrive(path): + """Determines whether the specified path is on a Windows Dev Drive.""" + try: + return _path_isdevdrive(abspath(path)) + except OSError: + return False diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 0e57c165ca98ea..538d758624c9d6 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -992,6 +992,26 @@ def test_fast_paths_in_use(self): self.assertTrue(os.path.exists is nt._path_exists) self.assertFalse(inspect.isfunction(os.path.exists)) + @unittest.skipIf(os.name != 'nt', "Dev Drives only exist on Win32") + def test_isdevdrive(self): + # Result may be True or False, but shouldn't raise + self.assertIn(ntpath.isdevdrive(os_helper.TESTFN), (True, False)) + # ntpath.isdevdrive can handle relative paths + self.assertIn(ntpath.isdevdrive("."), (True, False)) + self.assertIn(ntpath.isdevdrive(b"."), (True, False)) + # Volume syntax is supported + self.assertIn(ntpath.isdevdrive(os.listvolumes()[0]), (True, False)) + # Invalid volume returns False from os.path method + self.assertFalse(ntpath.isdevdrive(r"\\?\Volume{00000000-0000-0000-0000-000000000000}\\")) + # Invalid volume raises from underlying helper + with self.assertRaises(OSError): + nt._path_isdevdrive(r"\\?\Volume{00000000-0000-0000-0000-000000000000}\\") + + @unittest.skipIf(os.name == 'nt', "isdevdrive fallback only used off Win32") + def test_isdevdrive_fallback(self): + # Fallback always returns False + self.assertFalse(ntpath.isdevdrive(os_helper.TESTFN)) + class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase): pathmodule = ntpath diff --git a/Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst b/Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst new file mode 100644 index 00000000000000..d2242c76189970 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst @@ -0,0 +1,3 @@ +Add :func:`os.path.isdevdrive` to detect whether a path is on a Windows Dev +Drive. Returns ``False`` on platforms that do not support Dev Drive, and is +absent on non-Windows platforms. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 8b0550d832fc0a..3312bd667694dd 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1715,6 +1715,70 @@ os_listmounts(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec #if defined(MS_WINDOWS) +PyDoc_STRVAR(os__path_isdevdrive__doc__, +"_path_isdevdrive($module, /, path)\n" +"--\n" +"\n" +"Determines whether the specified path is on a Windows Dev Drive."); + +#define OS__PATH_ISDEVDRIVE_METHODDEF \ + {"_path_isdevdrive", _PyCFunction_CAST(os__path_isdevdrive), METH_FASTCALL|METH_KEYWORDS, os__path_isdevdrive__doc__}, + +static PyObject * +os__path_isdevdrive_impl(PyObject *module, path_t *path); + +static PyObject * +os__path_isdevdrive(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_path_isdevdrive", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + path_t path = PATH_T_INITIALIZE("_path_isdevdrive", "path", 0, 0); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &path)) { + goto exit; + } + return_value = os__path_isdevdrive_impl(module, &path); + +exit: + /* Cleanup for path */ + path_cleanup(&path); + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + PyDoc_STRVAR(os__getfullpathname__doc__, "_getfullpathname($module, path, /)\n" "--\n" @@ -11379,6 +11443,10 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #define OS_LISTMOUNTS_METHODDEF #endif /* !defined(OS_LISTMOUNTS_METHODDEF) */ +#ifndef OS__PATH_ISDEVDRIVE_METHODDEF + #define OS__PATH_ISDEVDRIVE_METHODDEF +#endif /* !defined(OS__PATH_ISDEVDRIVE_METHODDEF) */ + #ifndef OS__GETFULLPATHNAME_METHODDEF #define OS__GETFULLPATHNAME_METHODDEF #endif /* !defined(OS__GETFULLPATHNAME_METHODDEF) */ @@ -11922,4 +11990,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=47750e0e29c8d707 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9d8b0d6717c9af54 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 531f26ba8bc86f..77df9e7b8a5b7b 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4530,6 +4530,95 @@ os_listmounts_impl(PyObject *module, path_t *volume) } +/*[clinic input] +os._path_isdevdrive + + path: path_t + +Determines whether the specified path is on a Windows Dev Drive. + +[clinic start generated code]*/ + +static PyObject * +os__path_isdevdrive_impl(PyObject *module, path_t *path) +/*[clinic end generated code: output=1f437ea6677433a2 input=ee83e4996a48e23d]*/ +{ +#ifndef PERSISTENT_VOLUME_STATE_DEV_VOLUME + /* This flag will be documented at + https://learn.microsoft.com/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_fs_persistent_volume_information + after release, and will be available in the latest WinSDK. + We include the flag to avoid a specific version dependency + on the latest WinSDK. */ + const int PERSISTENT_VOLUME_STATE_DEV_VOLUME = 0x00002000; +#endif + int err = 0; + PyObject *r = NULL; + wchar_t volume[MAX_PATH]; + + Py_BEGIN_ALLOW_THREADS + if (!GetVolumePathNameW(path->wide, volume, MAX_PATH)) { + /* invalid path of some kind */ + /* Note that this also includes the case where a volume is mounted + in a path longer than 260 characters. This is likely to be rare + and problematic for other reasons, so a (soft) failure in this + check seems okay. */ + err = GetLastError(); + } else if (GetDriveTypeW(volume) != DRIVE_FIXED) { + /* only care about local dev drives */ + r = Py_False; + } else { + HANDLE hVolume = CreateFileW( + volume, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + if (hVolume == INVALID_HANDLE_VALUE) { + err = GetLastError(); + } else { + FILE_FS_PERSISTENT_VOLUME_INFORMATION volumeState = {0}; + volumeState.Version = 1; + volumeState.FlagMask = PERSISTENT_VOLUME_STATE_DEV_VOLUME; + if (!DeviceIoControl( + hVolume, + FSCTL_QUERY_PERSISTENT_VOLUME_STATE, + &volumeState, + sizeof(volumeState), + &volumeState, + sizeof(volumeState), + NULL, + NULL + )) { + err = GetLastError(); + } + CloseHandle(hVolume); + if (err == ERROR_INVALID_PARAMETER) { + /* not supported on this platform */ + r = Py_False; + } else if (!err) { + r = (volumeState.VolumeFlags & PERSISTENT_VOLUME_STATE_DEV_VOLUME) + ? Py_True : Py_False; + } + } + } + Py_END_ALLOW_THREADS + + if (err) { + PyErr_SetFromWindowsErr(err); + return NULL; + } + + if (r) { + return Py_NewRef(r); + } + + return NULL; +} + + int _PyOS_getfullpathname(const wchar_t *path, wchar_t **abspath_p) { @@ -15797,6 +15886,7 @@ static PyMethodDef posix_methods[] = { OS_SETNS_METHODDEF OS_UNSHARE_METHODDEF + OS__PATH_ISDEVDRIVE_METHODDEF OS__PATH_ISDIR_METHODDEF OS__PATH_ISFILE_METHODDEF OS__PATH_ISLINK_METHODDEF From 68bf3fe0e4221bd33823b727af1f70708bdb8f29 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 May 2023 09:57:04 -0700 Subject: [PATCH 0075/1206] gh-104820: Fixes os.stat on Windows to better handle file systems that do not support FileIdInformation (GH-104892) (cherry picked from commit 6031727a37c6003f78e3b0c7414a0a214855dd08) Co-authored-by: Steve Dower --- .../2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst | 2 ++ Modules/posixmodule.c | 12 ++++++++---- Python/fileutils.c | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst diff --git a/Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst b/Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst new file mode 100644 index 00000000000000..5bdfbabfaf28e1 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst @@ -0,0 +1,2 @@ +Fixes :func:`~os.stat` and related functions on file systems that do not +support file ID requests. This includes FAT32 and exFAT. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 77df9e7b8a5b7b..abc50b4d335bd2 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1864,6 +1864,7 @@ win32_xstat_slow_impl(const wchar_t *path, struct _Py_stat_struct *result, BY_HANDLE_FILE_INFORMATION fileInfo; FILE_BASIC_INFO basicInfo; FILE_ID_INFO idInfo; + FILE_ID_INFO *pIdInfo = &idInfo; FILE_ATTRIBUTE_TAG_INFO tagInfo = { 0 }; DWORD fileType, error; BOOL isUnhandledTag = FALSE; @@ -2000,9 +2001,7 @@ win32_xstat_slow_impl(const wchar_t *path, struct _Py_stat_struct *result, if (!GetFileInformationByHandle(hFile, &fileInfo) || !GetFileInformationByHandleEx(hFile, FileBasicInfo, - &basicInfo, sizeof(basicInfo)) || - !GetFileInformationByHandleEx(hFile, FileIdInfo, - &idInfo, sizeof(idInfo))) { + &basicInfo, sizeof(basicInfo))) { switch (GetLastError()) { case ERROR_INVALID_PARAMETER: case ERROR_INVALID_FUNCTION: @@ -2018,7 +2017,12 @@ win32_xstat_slow_impl(const wchar_t *path, struct _Py_stat_struct *result, } } - _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, &basicInfo, &idInfo, result); + if (!GetFileInformationByHandleEx(hFile, FileIdInfo, &idInfo, sizeof(idInfo))) { + /* Failed to get FileIdInfo, so do not pass it along */ + pIdInfo = NULL; + } + + _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, &basicInfo, pIdInfo, result); update_st_mode_from_path(path, fileInfo.dwFileAttributes, result); cleanup: diff --git a/Python/fileutils.c b/Python/fileutils.c index 969b7163b5ac18..f137ee936502c1 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1132,7 +1132,8 @@ _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, file_id.id = id_info->FileId; result->st_ino = file_id.st_ino; result->st_ino_high = file_id.st_ino_high; - } else { + } + if (!result->st_ino && !result->st_ino_high) { /* should only occur for DirEntry_from_find_data, in which case the index is likely to be zero anyway. */ result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; From 56722efe36dd5ef8320f1b3fd0a949d85e62e585 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 May 2023 10:21:03 -0700 Subject: [PATCH 0076/1206] gh-103646: Remove --include-pip-user from default APPX package build (GH-105064) (cherry picked from commit 6da701511e70fb26ad4710153d8d5a82b809919c) Co-authored-by: Steve Dower --- .../Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst | 5 +++++ PC/layout/support/options.py | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst diff --git a/Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst b/Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst new file mode 100644 index 00000000000000..71c1e7c6594cbf --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst @@ -0,0 +1,5 @@ +When installed from the Microsoft Store, ``pip`` no longer defaults to +per-user installs. However, as the install directory is unwritable, it +should automatically decide to do a per-user install anyway. This should +resolve issues when ``pip`` is passed an option that conflicts with +``--user``. diff --git a/PC/layout/support/options.py b/PC/layout/support/options.py index 26d13f5377ad59..60256fb32fe329 100644 --- a/PC/layout/support/options.py +++ b/PC/layout/support/options.py @@ -41,7 +41,6 @@ def public(f): "options": [ "stable", "pip", - "pip-user", "tcltk", "idle", "venv", From 67945261c42d746d0674b4361b2d8efa75e57345 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 May 2023 12:37:02 -0700 Subject: [PATCH 0077/1206] [3.12] GH-89455: Add missing attributes (added in 3.11) to traceback module docs (GH-105044) (#105066) GH-89455: Add missing attributes (added in 3.11) to traceback module docs (GH-105044) (cherry picked from commit 39f6a0489fcc815a578d27dfee2feea003c896f8) Co-authored-by: Jakub Kuczys --- Doc/library/traceback.rst | 19 ++++++++++++++++++- Lib/traceback.py | 2 ++ ...3-05-28-21-01-00.gh-issue-89455.qAKRrA.rst | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 5c0e261b90763c..9a04b56947a1bb 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -218,7 +218,7 @@ The module also defines the following classes: :class:`TracebackException` objects are created from actual exceptions to capture data for later printing in a lightweight fashion. -.. class:: TracebackException(exc_type, exc_value, exc_traceback, *, limit=None, lookup_lines=True, capture_locals=False, compact=False) +.. class:: TracebackException(exc_type, exc_value, exc_traceback, *, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10) Capture an exception for later rendering. *limit*, *lookup_lines* and *capture_locals* are as for the :class:`StackSummary` class. @@ -230,6 +230,12 @@ capture data for later printing in a lightweight fashion. Note that when locals are captured, they are also shown in the traceback. + *max_group_width* and *max_group_depth* control the formatting of exception + groups (see :exc:`BaseExceptionGroup`). The depth refers to the nesting + level of the group, and the width refers to the size of a single exception + group's exceptions array. The formatted output is truncated when either + limit is exceeded. + .. attribute:: __cause__ A :class:`TracebackException` of the original ``__cause__``. @@ -238,6 +244,14 @@ capture data for later printing in a lightweight fashion. A :class:`TracebackException` of the original ``__context__``. + .. attribute:: exceptions + + If ``self`` represents an :exc:`ExceptionGroup`, this field holds a list of + :class:`TracebackException` instances representing the nested exceptions. + Otherwise it is ``None``. + + .. versionadded:: 3.11 + .. attribute:: __suppress_context__ The ``__suppress_context__`` value from the original exception. @@ -323,6 +337,9 @@ capture data for later printing in a lightweight fashion. .. versionchanged:: 3.10 Added the *compact* parameter. + .. versionchanged:: 3.11 + Added the *max_group_width* and *max_group_depth* parameters. + :class:`StackSummary` Objects ----------------------------- diff --git a/Lib/traceback.py b/Lib/traceback.py index 419f6e81b5e1be..0ea77bfb94612e 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -658,6 +658,8 @@ class TracebackException: - :attr:`__cause__` A TracebackException of the original *__cause__*. - :attr:`__context__` A TracebackException of the original *__context__*. + - :attr:`exceptions` For exception groups - a list of TracebackException + instances for the nested *exceptions*. ``None`` for other exceptions. - :attr:`__suppress_context__` The *__suppress_context__* value from the original exception. - :attr:`stack` A `StackSummary` representing the traceback. diff --git a/Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst b/Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst new file mode 100644 index 00000000000000..fdfa4357f001b5 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst @@ -0,0 +1,3 @@ +Add missing documentation for the ``max_group_depth`` and ``max_group_width`` +parameters and the ``exceptions`` attribute of the +:class:`traceback.TracebackException` class. From 7f04a1546f2be67bfa53ddaa5769002d4d1691f2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 29 May 2023 21:25:52 -0700 Subject: [PATCH 0078/1206] [3.12] gh-105077: Fix test_tkinter refleak checking (GH-105078) (GH-105079) Use specific symbols from `test.support` to avoid having `support` overwritten by `test_tkinter`'s own `support` submodule. (cherry picked from commit 5454db4ace66018179f034fbffcea8d791d66a98) --- Lib/test/test_tkinter/__init__.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tkinter/__init__.py b/Lib/test/test_tkinter/__init__.py index edcb44951bde36..b1181bc04b7953 100644 --- a/Lib/test/test_tkinter/__init__.py +++ b/Lib/test/test_tkinter/__init__.py @@ -1,18 +1,23 @@ import os.path import unittest -from test import support -from test.support import import_helper +from test.support import ( + check_sanitizer, + import_helper, + load_package_tests, + requires, + ) -if support.check_sanitizer(address=True, memory=True): + +if check_sanitizer(address=True, memory=True): raise unittest.SkipTest("Tests involving libX11 can SEGFAULT on ASAN/MSAN builds") # Skip test if _tkinter wasn't built. import_helper.import_module('_tkinter') # Skip test if tk cannot be initialized. -support.requires('gui') +requires('gui') def load_tests(*args): - return support.load_package_tests(os.path.dirname(__file__), *args) + return load_package_tests(os.path.dirname(__file__), *args) From fd6b913535d78d3bfec710075ac930474c1057ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 May 2023 02:53:46 -0700 Subject: [PATCH 0079/1206] [3.12] gh-102251: Fix reference leak in _testsinglephase initialization (GH-105082) (#105083) Correctly decref 'initialized' in init_module() (cherry picked from commit d14eb3433cf2a40a202471b815f0a935f2840ead) Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- Modules/_testsinglephase.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c index a16157702ae789..8e6973f0b052cc 100644 --- a/Modules/_testsinglephase.c +++ b/Modules/_testsinglephase.c @@ -140,7 +140,9 @@ init_module(PyObject *module, module_state *state) if (initialized == NULL) { return -1; } - if (PyModule_AddObjectRef(module, "_module_initialized", initialized) != 0) { + int rc = PyModule_AddObjectRef(module, "_module_initialized", initialized); + Py_DECREF(initialized); + if (rc < 0) { return -1; } From 7899fac3c5fba3b8258cdd72562230c51164d778 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 May 2023 07:33:01 -0700 Subject: [PATCH 0080/1206] [3.12] gh-104799: Move location of type_params AST fields (GH-104828) (#104974) gh-104799: Move location of type_params AST fields (GH-104828) (cherry picked from commit ba73473f4c18ba4cf7ab18d84d94a47d2d37a0c5) Co-authored-by: Jelle Zijlstra Co-authored-by: Alex Waygood --- Doc/data/python3.12.abi | 136 ++++---- Doc/library/ast.rst | 12 +- Grammar/python.gram | 12 +- Include/internal/pycore_ast.h | 36 +- Lib/test/test_ast.py | 130 ++++--- ...-05-23-18-31-49.gh-issue-104799.MJYOw6.rst | 4 + Parser/Python.asdl | 12 +- Parser/action_helpers.c | 26 +- Parser/parser.c | 6 +- Python/Python-ast.c | 325 +++++++++--------- 10 files changed, 365 insertions(+), 334 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 79bf7ea6df829e..9802893e69cca7 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -10092,22 +10092,22 @@ - + - + - + - + - + - + @@ -10115,19 +10115,19 @@ - + - + - + - + - + @@ -10143,7 +10143,7 @@ - + @@ -10151,7 +10151,7 @@ - + @@ -10196,7 +10196,7 @@ - + @@ -10218,7 +10218,7 @@ - + @@ -10481,7 +10481,7 @@ - + @@ -10521,7 +10521,7 @@ - + @@ -10529,7 +10529,7 @@ - + @@ -10553,7 +10553,7 @@ - + @@ -10630,10 +10630,10 @@ - + @@ -10645,10 +10645,10 @@ - + @@ -10659,11 +10659,11 @@ - + @@ -10763,12 +10763,12 @@ - + - + @@ -10788,7 +10788,7 @@ - + @@ -10877,10 +10877,10 @@ - + - + @@ -13441,10 +13441,10 @@ - + - + @@ -13473,7 +13473,7 @@ - + @@ -13488,7 +13488,7 @@ - + @@ -13509,13 +13509,13 @@ - + - + - + @@ -13551,7 +13551,7 @@ - + @@ -13652,7 +13652,7 @@ - + @@ -14252,7 +14252,7 @@ - + @@ -14312,7 +14312,7 @@ - + @@ -14366,7 +14366,7 @@ - + @@ -14525,7 +14525,7 @@ - + @@ -14609,7 +14609,7 @@ - + @@ -15089,7 +15089,7 @@ - + @@ -15221,7 +15221,7 @@ - + @@ -15302,7 +15302,7 @@ - + @@ -15374,7 +15374,7 @@ - + @@ -15680,7 +15680,7 @@ - + @@ -15817,7 +15817,7 @@ - + @@ -17440,10 +17440,10 @@ - - - - + + + + @@ -17916,7 +17916,7 @@ - + @@ -17926,7 +17926,7 @@ - + @@ -17963,7 +17963,7 @@ - + @@ -17976,7 +17976,7 @@ - + @@ -18009,7 +18009,7 @@ - + @@ -18020,7 +18020,7 @@ - + @@ -18195,7 +18195,7 @@ - + @@ -18714,11 +18714,11 @@ - + - + @@ -19370,7 +19370,7 @@ - + @@ -19424,7 +19424,7 @@ - + @@ -19645,7 +19645,7 @@ - + @@ -19742,7 +19742,7 @@ - + @@ -19847,7 +19847,7 @@ - + @@ -20608,7 +20608,7 @@ - + @@ -21234,7 +21234,7 @@ - + @@ -21244,7 +21244,7 @@ - + diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 8a686354b9f65c..17d1de9fbb8f11 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1821,7 +1821,6 @@ Function and class definitions body=[ FunctionDef( name='f', - type_params=[], args=arguments( posonlyargs=[], args=[ @@ -1846,7 +1845,8 @@ Function and class definitions decorator_list=[ Name(id='decorator1', ctx=Load()), Name(id='decorator2', ctx=Load())], - returns=Constant(value='return annotation'))], + returns=Constant(value='return annotation'), + type_params=[])], type_ignores=[]) @@ -1943,7 +1943,6 @@ Function and class definitions body=[ ClassDef( name='Foo', - type_params=[], bases=[ Name(id='base1', ctx=Load()), Name(id='base2', ctx=Load())], @@ -1955,7 +1954,8 @@ Function and class definitions Pass()], decorator_list=[ Name(id='decorator1', ctx=Load()), - Name(id='decorator2', ctx=Load())])], + Name(id='decorator2', ctx=Load())], + type_params=[])], type_ignores=[]) Async and await @@ -1982,7 +1982,6 @@ Async and await body=[ AsyncFunctionDef( name='f', - type_params=[], args=arguments( posonlyargs=[], args=[], @@ -1996,7 +1995,8 @@ Async and await func=Name(id='other_func', ctx=Load()), args=[], keywords=[])))], - decorator_list=[])], + decorator_list=[], + type_params=[])], type_ignores=[]) diff --git a/Grammar/python.gram b/Grammar/python.gram index e6a983429e39d8..9131835f7421bc 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -254,10 +254,10 @@ class_def[stmt_ty]: class_def_raw[stmt_ty]: | invalid_class_def_raw | 'class' a=NAME t=[type_params] b=['(' z=[arguments] ')' { z }] ':' c=block { - _PyAST_ClassDef(a->v.Name.id, t, + _PyAST_ClassDef(a->v.Name.id, (b) ? ((expr_ty) b)->v.Call.args : NULL, (b) ? ((expr_ty) b)->v.Call.keywords : NULL, - c, NULL, EXTRA) } + c, NULL, t, EXTRA) } # Function definitions # -------------------- @@ -269,17 +269,17 @@ function_def[stmt_ty]: function_def_raw[stmt_ty]: | invalid_def_raw | 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { - _PyAST_FunctionDef(n->v.Name.id, t, + _PyAST_FunctionDef(n->v.Name.id, (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)), - b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) } + b, NULL, a, NEW_TYPE_COMMENT(p, tc), t, EXTRA) } | ASYNC 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { CHECK_VERSION( stmt_ty, 5, "Async functions are", - _PyAST_AsyncFunctionDef(n->v.Name.id, t, + _PyAST_AsyncFunctionDef(n->v.Name.id, (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)), - b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) + b, NULL, a, NEW_TYPE_COMMENT(p, tc), t, EXTRA) ) } # Function parameters diff --git a/Include/internal/pycore_ast.h b/Include/internal/pycore_ast.h index 06a40239a2473a..b568902bb1e381 100644 --- a/Include/internal/pycore_ast.h +++ b/Include/internal/pycore_ast.h @@ -198,31 +198,31 @@ struct _stmt { union { struct { identifier name; - asdl_type_param_seq *type_params; arguments_ty args; asdl_stmt_seq *body; asdl_expr_seq *decorator_list; expr_ty returns; string type_comment; + asdl_type_param_seq *type_params; } FunctionDef; struct { identifier name; - asdl_type_param_seq *type_params; arguments_ty args; asdl_stmt_seq *body; asdl_expr_seq *decorator_list; expr_ty returns; string type_comment; + asdl_type_param_seq *type_params; } AsyncFunctionDef; struct { identifier name; - asdl_type_param_seq *type_params; asdl_expr_seq *bases; asdl_keyword_seq *keywords; asdl_stmt_seq *body; asdl_expr_seq *decorator_list; + asdl_type_param_seq *type_params; } ClassDef; struct { @@ -682,22 +682,22 @@ mod_ty _PyAST_Interactive(asdl_stmt_seq * body, PyArena *arena); mod_ty _PyAST_Expression(expr_ty body, PyArena *arena); mod_ty _PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena); -stmt_ty _PyAST_FunctionDef(identifier name, asdl_type_param_seq * type_params, - arguments_ty args, asdl_stmt_seq * body, - asdl_expr_seq * decorator_list, expr_ty returns, - string type_comment, int lineno, int col_offset, int +stmt_ty _PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * + body, asdl_expr_seq * decorator_list, expr_ty + returns, string type_comment, asdl_type_param_seq * + type_params, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); -stmt_ty _PyAST_AsyncFunctionDef(identifier name, asdl_type_param_seq * - type_params, arguments_ty args, asdl_stmt_seq * - body, asdl_expr_seq * decorator_list, expr_ty - returns, string type_comment, int lineno, int - col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -stmt_ty _PyAST_ClassDef(identifier name, asdl_type_param_seq * type_params, - asdl_expr_seq * bases, asdl_keyword_seq * keywords, - asdl_stmt_seq * body, asdl_expr_seq * decorator_list, - int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); +stmt_ty _PyAST_AsyncFunctionDef(identifier name, arguments_ty args, + asdl_stmt_seq * body, asdl_expr_seq * + decorator_list, expr_ty returns, string + type_comment, asdl_type_param_seq * + type_params, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); +stmt_ty _PyAST_ClassDef(identifier name, asdl_expr_seq * bases, + asdl_keyword_seq * keywords, asdl_stmt_seq * body, + asdl_expr_seq * decorator_list, asdl_type_param_seq * + type_params, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); stmt_ty _PyAST_Return(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); stmt_ty _PyAST_Delete(asdl_expr_seq * targets, int lineno, int col_offset, int diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index cf128e1e8cd04c..76edbf5121c806 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -4,6 +4,7 @@ import enum import os import sys +import textwrap import types import unittest import warnings @@ -1583,20 +1584,41 @@ def arguments(args=None, posonlyargs=None, vararg=None, def test_funcdef(self): a = ast.arguments([], [], None, [], [], None, []) - f = ast.FunctionDef("x", [], a, [], [], None) + f = ast.FunctionDef("x", a, [], [], None, None, []) self.stmt(f, "empty body on FunctionDef") - f = ast.FunctionDef("x", [], a, [ast.Pass()], [ast.Name("x", ast.Store())], - None) + f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())], None, None, []) self.stmt(f, "must have Load context") - f = ast.FunctionDef("x", [], a, [ast.Pass()], [], - ast.Name("x", ast.Store())) + f = ast.FunctionDef("x", a, [ast.Pass()], [], + ast.Name("x", ast.Store()), None, []) self.stmt(f, "must have Load context") def fac(args): - return ast.FunctionDef("x", [], args, [ast.Pass()], [], None) + return ast.FunctionDef("x", args, [ast.Pass()], [], None, None, []) self._check_arguments(fac, self.stmt) + def test_funcdef_pattern_matching(self): + # gh-104799: New fields on FunctionDef should be added at the end + def matcher(node): + match node: + case ast.FunctionDef("foo", ast.arguments(args=[ast.arg("bar")]), + [ast.Pass()], + [ast.Name("capybara", ast.Load())], + ast.Name("pacarana", ast.Load())): + return True + case _: + return False + + code = """ + @capybara + def foo(bar) -> pacarana: + pass + """ + source = ast.parse(textwrap.dedent(code)) + funcdef = source.body[0] + self.assertIsInstance(funcdef, ast.FunctionDef) + self.assertTrue(matcher(funcdef)) + def test_classdef(self): - def cls(bases=None, keywords=None, body=None, decorator_list=None): + def cls(bases=None, keywords=None, body=None, decorator_list=None, type_params=None): if bases is None: bases = [] if keywords is None: @@ -1605,8 +1627,10 @@ def cls(bases=None, keywords=None, body=None, decorator_list=None): body = [ast.Pass()] if decorator_list is None: decorator_list = [] - return ast.ClassDef("myclass", [], bases, keywords, - body, decorator_list) + if type_params is None: + type_params = [] + return ast.ClassDef("myclass", bases, keywords, + body, decorator_list, type_params) self.stmt(cls(bases=[ast.Name("x", ast.Store())]), "must have Load context") self.stmt(cls(keywords=[ast.keyword("x", ast.Name("x", ast.Store()))]), @@ -2895,23 +2919,23 @@ def main(): exec_results = [ ('Module', [('Expr', (1, 0, 1, 4), ('Constant', (1, 0, 1, 4), None, None))], []), ('Module', [('Expr', (1, 0, 1, 18), ('Constant', (1, 0, 1, 18), 'module docstring', None))], []), -('Module', [('FunctionDef', (1, 0, 1, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 14), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 23), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 21), 'f', [], ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 71), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 27), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('FunctionDef', (1, 0, 1, 45), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [], [('Pass', (1, 8, 1, 12))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 21), 'C', [], [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [])], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 14), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 23), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 21), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 71), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 27), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 45), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None, [])], []), +('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [('Pass', (1, 8, 1, 12))], [], [])], []), +('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [], [])], []), +('Module', [('ClassDef', (1, 0, 1, 21), 'C', [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [], [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None, [])], []), ('Module', [('Delete', (1, 0, 1, 5), [('Name', (1, 4, 1, 5), 'v', ('Del',))])], []), ('Module', [('Assign', (1, 0, 1, 5), [('Name', (1, 0, 1, 1), 'v', ('Store',))], ('Constant', (1, 4, 1, 5), 1, None), None)], []), ('Module', [('Assign', (1, 0, 1, 7), [('Tuple', (1, 0, 1, 3), [('Name', (1, 0, 1, 1), 'a', ('Store',)), ('Name', (1, 2, 1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 6, 1, 7), 'c', ('Load',)), None)], []), @@ -2948,41 +2972,41 @@ def main(): ('Module', [('Expr', (1, 0, 1, 20), ('DictComp', (1, 0, 1, 20), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'v', ('Store',)), ('Name', (1, 13, 1, 14), 'w', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'x', ('Load',)), [], 0)]))], []), ('Module', [('Expr', (1, 0, 1, 19), ('SetComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 12, 1, 13), 'x', ('Load',)), [('Name', (1, 17, 1, 18), 'g', ('Load',))], 0)]))], []), ('Module', [('Expr', (1, 0, 1, 16), ('SetComp', (1, 0, 1, 16), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7, 1, 10), [('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 9, 1, 10), 'm', ('Store',))], ('Store',)), ('Name', (1, 14, 1, 15), 'x', ('Load',)), [], 0)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', [], ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', [], ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None, [])], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None, [])], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None, [])], []), ('Module', [('Expr', (1, 0, 1, 14), ('Dict', (1, 0, 1, 14), [None, ('Constant', (1, 10, 1, 11), 2, None)], [('Dict', (1, 3, 1, 8), [('Constant', (1, 4, 1, 5), 1, None)], [('Constant', (1, 6, 1, 7), 2, None)]), ('Constant', (1, 12, 1, 13), 3, None)]))], []), ('Module', [('Expr', (1, 0, 1, 12), ('Set', (1, 0, 1, 12), [('Starred', (1, 1, 1, 8), ('Set', (1, 2, 1, 8), [('Constant', (1, 3, 1, 4), 1, None), ('Constant', (1, 6, 1, 7), 2, None)]), ('Load',)), ('Constant', (1, 10, 1, 11), 3, None)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None)], []), -('Module', [('FunctionDef', (4, 0, 4, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), -('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), -('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])])], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None)], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None, [])], []), +('Module', [('FunctionDef', (4, 0, 4, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None, [])], []), +('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None, [])], []), +('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], [])], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None, [])], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None, [])], []), ('Module', [('Expr', (1, 0, 1, 8), ('NamedExpr', (1, 1, 1, 7), ('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Constant', (1, 6, 1, 7), 1, None)))], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 26), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 39), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 20), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 30), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 42), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 40), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 39), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 20), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 30), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 42), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None, [])], []), +('Module', [('FunctionDef', (1, 0, 1, 40), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None, [])], []), ('Module', [('TypeAlias', (1, 0, 1, 12), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [], ('Name', (1, 9, 1, 12), 'int', ('Load',)))], []), ('Module', [('TypeAlias', (1, 0, 1, 15), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None)], ('Name', (1, 12, 1, 15), 'int', ('Load',)))], []), ('Module', [('TypeAlias', (1, 0, 1, 32), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None), ('TypeVarTuple', (1, 10, 1, 13), 'Ts'), ('ParamSpec', (1, 15, 1, 18), 'P')], ('Tuple', (1, 22, 1, 32), [('Name', (1, 23, 1, 24), 'T', ('Load',)), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Name', (1, 30, 1, 31), 'P', ('Load',))], ('Load',)))], []), ('Module', [('TypeAlias', (1, 0, 1, 37), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 13), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',))), ('TypeVarTuple', (1, 15, 1, 18), 'Ts'), ('ParamSpec', (1, 20, 1, 23), 'P')], ('Tuple', (1, 27, 1, 37), [('Name', (1, 28, 1, 29), 'T', ('Load',)), ('Name', (1, 31, 1, 33), 'Ts', ('Load',)), ('Name', (1, 35, 1, 36), 'P', ('Load',))], ('Load',)))], []), ('Module', [('TypeAlias', (1, 0, 1, 44), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 20), 'T', ('Tuple', (1, 10, 1, 20), [('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Name', (1, 16, 1, 19), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 22, 1, 25), 'Ts'), ('ParamSpec', (1, 27, 1, 30), 'P')], ('Tuple', (1, 34, 1, 44), [('Name', (1, 35, 1, 36), 'T', ('Load',)), ('Name', (1, 38, 1, 40), 'Ts', ('Load',)), ('Name', (1, 42, 1, 43), 'P', ('Load',))], ('Load',)))], []), -('Module', [('ClassDef', (1, 0, 1, 16), 'X', [('TypeVar', (1, 8, 1, 9), 'T', None)], [], [], [('Pass', (1, 12, 1, 16))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 26), 'X', [('TypeVar', (1, 8, 1, 9), 'T', None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts'), ('ParamSpec', (1, 16, 1, 19), 'P')], [], [], [('Pass', (1, 22, 1, 26))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 31), 'X', [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',))), ('TypeVarTuple', (1, 16, 1, 19), 'Ts'), ('ParamSpec', (1, 21, 1, 24), 'P')], [], [], [('Pass', (1, 27, 1, 31))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 38), 'X', [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 23, 1, 26), 'Ts'), ('ParamSpec', (1, 28, 1, 31), 'P')], [], [], [('Pass', (1, 34, 1, 38))], [])], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [('TypeVar', (1, 6, 1, 7), 'T', None)], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 26), 'f', [('TypeVar', (1, 6, 1, 7), 'T', None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts'), ('ParamSpec', (1, 14, 1, 17), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 31), 'f', [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',))), ('TypeVarTuple', (1, 14, 1, 17), 'Ts'), ('ParamSpec', (1, 19, 1, 22), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 38), 'f', [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 21, 1, 24), 'Ts'), ('ParamSpec', (1, 26, 1, 29), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None)], []), +('Module', [('ClassDef', (1, 0, 1, 16), 'X', [], [], [('Pass', (1, 12, 1, 16))], [], [('TypeVar', (1, 8, 1, 9), 'T', None)])], []), +('Module', [('ClassDef', (1, 0, 1, 26), 'X', [], [], [('Pass', (1, 22, 1, 26))], [], [('TypeVar', (1, 8, 1, 9), 'T', None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts'), ('ParamSpec', (1, 16, 1, 19), 'P')])], []), +('Module', [('ClassDef', (1, 0, 1, 31), 'X', [], [], [('Pass', (1, 27, 1, 31))], [], [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',))), ('TypeVarTuple', (1, 16, 1, 19), 'Ts'), ('ParamSpec', (1, 21, 1, 24), 'P')])], []), +('Module', [('ClassDef', (1, 0, 1, 38), 'X', [], [], [('Pass', (1, 34, 1, 38))], [], [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 23, 1, 26), 'Ts'), ('ParamSpec', (1, 28, 1, 31), 'P')])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None)])], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None, [('TypeVar', (1, 6, 1, 7), 'T', None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts'), ('ParamSpec', (1, 14, 1, 17), 'P')])], []), +('Module', [('FunctionDef', (1, 0, 1, 31), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None, [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',))), ('TypeVarTuple', (1, 14, 1, 17), 'Ts'), ('ParamSpec', (1, 19, 1, 22), 'P')])], []), +('Module', [('FunctionDef', (1, 0, 1, 38), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None, [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 21, 1, 24), 'Ts'), ('ParamSpec', (1, 26, 1, 29), 'P')])], []), ] single_results = [ ('Interactive', [('Expr', (1, 0, 1, 3), ('BinOp', (1, 0, 1, 3), ('Constant', (1, 0, 1, 1), 1, None), ('Add',), ('Constant', (1, 2, 1, 3), 2, None)))]), diff --git a/Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst b/Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst new file mode 100644 index 00000000000000..614918d7572969 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst @@ -0,0 +1,4 @@ +Adjust the location of the (see :pep:`695`) ``type_params`` field on +:class:`ast.ClassDef`, :class:`ast.AsyncFunctionDef`, and +:class:`ast.FunctionDef` to better preserve backward compatibility. Patch by +Jelle Zijlstra diff --git a/Parser/Python.asdl b/Parser/Python.asdl index dc2eb802b0436c..93632a09f0959b 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -8,19 +8,19 @@ module Python | Expression(expr body) | FunctionType(expr* argtypes, expr returns) - stmt = FunctionDef(identifier name, type_param* type_params, arguments args, + stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, - string? type_comment) - | AsyncFunctionDef(identifier name, type_param* type_params, arguments args, + string? type_comment, type_param* type_params) + | AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, - string? type_comment) + string? type_comment, type_param* type_params) | ClassDef(identifier name, - type_param* type_params, expr* bases, keyword* keywords, stmt* body, - expr* decorator_list) + expr* decorator_list, + type_param* type_params) | Return(expr? value) | Delete(expr* targets) diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 06d77b64cacbcc..c4d8f75e542805 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -752,22 +752,25 @@ _PyPegen_function_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty f assert(function_def != NULL); if (function_def->kind == AsyncFunctionDef_kind) { return _PyAST_AsyncFunctionDef( - function_def->v.FunctionDef.name, function_def->v.FunctionDef.type_params, - function_def->v.FunctionDef.args, - function_def->v.FunctionDef.body, decorators, function_def->v.FunctionDef.returns, - function_def->v.FunctionDef.type_comment, function_def->lineno, - function_def->col_offset, function_def->end_lineno, function_def->end_col_offset, - p->arena); + function_def->v.AsyncFunctionDef.name, + function_def->v.AsyncFunctionDef.args, + function_def->v.AsyncFunctionDef.body, decorators, + function_def->v.AsyncFunctionDef.returns, + function_def->v.AsyncFunctionDef.type_comment, + function_def->v.AsyncFunctionDef.type_params, + function_def->lineno, function_def->col_offset, + function_def->end_lineno, function_def->end_col_offset, p->arena); } return _PyAST_FunctionDef( - function_def->v.FunctionDef.name, function_def->v.FunctionDef.type_params, + function_def->v.FunctionDef.name, function_def->v.FunctionDef.args, function_def->v.FunctionDef.body, decorators, function_def->v.FunctionDef.returns, - function_def->v.FunctionDef.type_comment, function_def->lineno, - function_def->col_offset, function_def->end_lineno, - function_def->end_col_offset, p->arena); + function_def->v.FunctionDef.type_comment, + function_def->v.FunctionDef.type_params, + function_def->lineno, function_def->col_offset, + function_def->end_lineno, function_def->end_col_offset, p->arena); } /* Construct a ClassDef equivalent to class_def, but with decorators */ @@ -776,9 +779,10 @@ _PyPegen_class_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty clas { assert(class_def != NULL); return _PyAST_ClassDef( - class_def->v.ClassDef.name, class_def->v.ClassDef.type_params, + class_def->v.ClassDef.name, class_def->v.ClassDef.bases, class_def->v.ClassDef.keywords, class_def->v.ClassDef.body, decorators, + class_def->v.ClassDef.type_params, class_def->lineno, class_def->col_offset, class_def->end_lineno, class_def->end_col_offset, p->arena); } diff --git a/Parser/parser.c b/Parser/parser.c index fc5466fea2b3fc..1705ebd456b5ff 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -4425,7 +4425,7 @@ class_def_raw_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_ClassDef ( a -> v . Name . id , t , ( b ) ? ( ( expr_ty ) b ) -> v . Call . args : NULL , ( b ) ? ( ( expr_ty ) b ) -> v . Call . keywords : NULL , c , NULL , EXTRA ); + _res = _PyAST_ClassDef ( a -> v . Name . id , ( b ) ? ( ( expr_ty ) b ) -> v . Call . args : NULL , ( b ) ? ( ( expr_ty ) b ) -> v . Call . keywords : NULL , c , NULL , t , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -4602,7 +4602,7 @@ function_def_raw_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_FunctionDef ( n -> v . Name . id , t , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , EXTRA ); + _res = _PyAST_FunctionDef ( n -> v . Name . id , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , t , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -4665,7 +4665,7 @@ function_def_raw_rule(Parser *p) UNUSED(_end_lineno); // Only used by EXTRA macro int _end_col_offset = _token->end_col_offset; UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = CHECK_VERSION ( stmt_ty , 5 , "Async functions are" , _PyAST_AsyncFunctionDef ( n -> v . Name . id , t , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , EXTRA ) ); + _res = CHECK_VERSION ( stmt_ty , 5 , "Async functions are" , _PyAST_AsyncFunctionDef ( n -> v . Name . id , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , t , EXTRA ) ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 87906d975d7414..030c082a4a6b14 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -409,29 +409,29 @@ static const char * const stmt_attributes[] = { static PyObject* ast2obj_stmt(struct ast_state *state, void*); static const char * const FunctionDef_fields[]={ "name", - "type_params", "args", "body", "decorator_list", "returns", "type_comment", + "type_params", }; static const char * const AsyncFunctionDef_fields[]={ "name", - "type_params", "args", "body", "decorator_list", "returns", "type_comment", + "type_params", }; static const char * const ClassDef_fields[]={ "name", - "type_params", "bases", "keywords", "body", "decorator_list", + "type_params", }; static const char * const Return_fields[]={ "value", @@ -1169,9 +1169,9 @@ init_types(struct ast_state *state) "FunctionType(expr* argtypes, expr returns)"); if (!state->FunctionType_type) return 0; state->stmt_type = make_type(state, "stmt", state->AST_type, NULL, 0, - "stmt = FunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" - " | AsyncFunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" - " | ClassDef(identifier name, type_param* type_params, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)\n" + "stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)\n" + " | AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)\n" + " | ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list, type_param* type_params)\n" " | Return(expr? value)\n" " | Delete(expr* targets)\n" " | Assign(expr* targets, expr value, string? type_comment)\n" @@ -1206,7 +1206,7 @@ init_types(struct ast_state *state) return 0; state->FunctionDef_type = make_type(state, "FunctionDef", state->stmt_type, FunctionDef_fields, 7, - "FunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); + "FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)"); if (!state->FunctionDef_type) return 0; if (PyObject_SetAttr(state->FunctionDef_type, state->returns, Py_None) == -1) @@ -1217,7 +1217,7 @@ init_types(struct ast_state *state) state->AsyncFunctionDef_type = make_type(state, "AsyncFunctionDef", state->stmt_type, AsyncFunctionDef_fields, 7, - "AsyncFunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); + "AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)"); if (!state->AsyncFunctionDef_type) return 0; if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->returns, Py_None) == -1) @@ -1227,7 +1227,7 @@ init_types(struct ast_state *state) return 0; state->ClassDef_type = make_type(state, "ClassDef", state->stmt_type, ClassDef_fields, 6, - "ClassDef(identifier name, type_param* type_params, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)"); + "ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list, type_param* type_params)"); if (!state->ClassDef_type) return 0; state->Return_type = make_type(state, "Return", state->stmt_type, Return_fields, 1, @@ -2032,11 +2032,11 @@ _PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena) } stmt_ty -_PyAST_FunctionDef(identifier name, asdl_type_param_seq * type_params, - arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * - decorator_list, expr_ty returns, string type_comment, int - lineno, int col_offset, int end_lineno, int end_col_offset, - PyArena *arena) +_PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * body, + asdl_expr_seq * decorator_list, expr_ty returns, string + type_comment, asdl_type_param_seq * type_params, int lineno, + int col_offset, int end_lineno, int end_col_offset, PyArena + *arena) { stmt_ty p; if (!name) { @@ -2054,12 +2054,12 @@ _PyAST_FunctionDef(identifier name, asdl_type_param_seq * type_params, return NULL; p->kind = FunctionDef_kind; p->v.FunctionDef.name = name; - p->v.FunctionDef.type_params = type_params; p->v.FunctionDef.args = args; p->v.FunctionDef.body = body; p->v.FunctionDef.decorator_list = decorator_list; p->v.FunctionDef.returns = returns; p->v.FunctionDef.type_comment = type_comment; + p->v.FunctionDef.type_params = type_params; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; @@ -2068,9 +2068,9 @@ _PyAST_FunctionDef(identifier name, asdl_type_param_seq * type_params, } stmt_ty -_PyAST_AsyncFunctionDef(identifier name, asdl_type_param_seq * type_params, - arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq - * decorator_list, expr_ty returns, string type_comment, +_PyAST_AsyncFunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * + body, asdl_expr_seq * decorator_list, expr_ty returns, + string type_comment, asdl_type_param_seq * type_params, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { @@ -2090,12 +2090,12 @@ _PyAST_AsyncFunctionDef(identifier name, asdl_type_param_seq * type_params, return NULL; p->kind = AsyncFunctionDef_kind; p->v.AsyncFunctionDef.name = name; - p->v.AsyncFunctionDef.type_params = type_params; p->v.AsyncFunctionDef.args = args; p->v.AsyncFunctionDef.body = body; p->v.AsyncFunctionDef.decorator_list = decorator_list; p->v.AsyncFunctionDef.returns = returns; p->v.AsyncFunctionDef.type_comment = type_comment; + p->v.AsyncFunctionDef.type_params = type_params; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; @@ -2104,11 +2104,10 @@ _PyAST_AsyncFunctionDef(identifier name, asdl_type_param_seq * type_params, } stmt_ty -_PyAST_ClassDef(identifier name, asdl_type_param_seq * type_params, - asdl_expr_seq * bases, asdl_keyword_seq * keywords, - asdl_stmt_seq * body, asdl_expr_seq * decorator_list, int - lineno, int col_offset, int end_lineno, int end_col_offset, - PyArena *arena) +_PyAST_ClassDef(identifier name, asdl_expr_seq * bases, asdl_keyword_seq * + keywords, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, + asdl_type_param_seq * type_params, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!name) { @@ -2121,11 +2120,11 @@ _PyAST_ClassDef(identifier name, asdl_type_param_seq * type_params, return NULL; p->kind = ClassDef_kind; p->v.ClassDef.name = name; - p->v.ClassDef.type_params = type_params; p->v.ClassDef.bases = bases; p->v.ClassDef.keywords = keywords; p->v.ClassDef.body = body; p->v.ClassDef.decorator_list = decorator_list; + p->v.ClassDef.type_params = type_params; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; @@ -3883,12 +3882,6 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.type_params, - ast2obj_type_param); - if (!value) goto failed; - if (PyObject_SetAttr(result, state->type_params, value) == -1) - goto failed; - Py_DECREF(value); value = ast2obj_arguments(state, o->v.FunctionDef.args); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) @@ -3916,6 +3909,12 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.type_params, + ast2obj_type_param); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->type_params, value) == -1) + goto failed; + Py_DECREF(value); break; case AsyncFunctionDef_kind: tp = (PyTypeObject *)state->AsyncFunctionDef_type; @@ -3926,13 +3925,6 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_list(state, - (asdl_seq*)o->v.AsyncFunctionDef.type_params, - ast2obj_type_param); - if (!value) goto failed; - if (PyObject_SetAttr(result, state->type_params, value) == -1) - goto failed; - Py_DECREF(value); value = ast2obj_arguments(state, o->v.AsyncFunctionDef.args); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) @@ -3961,6 +3953,13 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(state, + (asdl_seq*)o->v.AsyncFunctionDef.type_params, + ast2obj_type_param); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->type_params, value) == -1) + goto failed; + Py_DECREF(value); break; case ClassDef_kind: tp = (PyTypeObject *)state->ClassDef_type; @@ -3971,12 +3970,6 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.type_params, - ast2obj_type_param); - if (!value) goto failed; - if (PyObject_SetAttr(result, state->type_params, value) == -1) - goto failed; - Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.bases, ast2obj_expr); if (!value) goto failed; @@ -4001,6 +3994,12 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->decorator_list, value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.type_params, + ast2obj_type_param); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->type_params, value) == -1) + goto failed; + Py_DECREF(value); break; case Return_kind: tp = (PyTypeObject *)state->Return_type; @@ -6075,12 +6074,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; - asdl_type_param_seq* type_params; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; expr_ty returns; string type_comment; + asdl_type_param_seq* type_params; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; @@ -6099,42 +6098,6 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { - return 1; - } - if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from FunctionDef"); - return 1; - } - else { - int res; - Py_ssize_t len; - Py_ssize_t i; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "FunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); - goto failed; - } - len = PyList_GET_SIZE(tmp); - type_params = _Py_asdl_type_param_seq_new(len, arena); - if (type_params == NULL) goto failed; - for (i = 0; i < len; i++) { - type_param_ty val; - PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); - if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { - goto failed; - } - res = obj2ast_type_param(state, tmp2, &val, arena); - _Py_LeaveRecursiveCall(); - Py_DECREF(tmp2); - if (res != 0) goto failed; - if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"type_params\" changed size during iteration"); - goto failed; - } - asdl_seq_SET(type_params, i, val); - } - Py_CLEAR(tmp); - } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } @@ -6258,10 +6221,46 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - *out = _PyAST_FunctionDef(name, type_params, args, body, - decorator_list, returns, type_comment, - lineno, col_offset, end_lineno, - end_col_offset, arena); + if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from FunctionDef"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "FunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + type_params = _Py_asdl_type_param_seq_new(len, arena); + if (type_params == NULL) goto failed; + for (i = 0; i < len; i++) { + type_param_ty val; + PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); + if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { + goto failed; + } + res = obj2ast_type_param(state, tmp2, &val, arena); + _Py_LeaveRecursiveCall(); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"type_params\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(type_params, i, val); + } + Py_CLEAR(tmp); + } + *out = _PyAST_FunctionDef(name, args, body, decorator_list, returns, + type_comment, type_params, lineno, + col_offset, end_lineno, end_col_offset, + arena); if (*out == NULL) goto failed; return 0; } @@ -6272,12 +6271,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; - asdl_type_param_seq* type_params; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; expr_ty returns; string type_comment; + asdl_type_param_seq* type_params; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; @@ -6296,42 +6295,6 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { - return 1; - } - if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from AsyncFunctionDef"); - return 1; - } - else { - int res; - Py_ssize_t len; - Py_ssize_t i; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); - goto failed; - } - len = PyList_GET_SIZE(tmp); - type_params = _Py_asdl_type_param_seq_new(len, arena); - if (type_params == NULL) goto failed; - for (i = 0; i < len; i++) { - type_param_ty val; - PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); - if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { - goto failed; - } - res = obj2ast_type_param(state, tmp2, &val, arena); - _Py_LeaveRecursiveCall(); - Py_DECREF(tmp2); - if (res != 0) goto failed; - if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"type_params\" changed size during iteration"); - goto failed; - } - asdl_seq_SET(type_params, i, val); - } - Py_CLEAR(tmp); - } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } @@ -6455,8 +6418,44 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - *out = _PyAST_AsyncFunctionDef(name, type_params, args, body, - decorator_list, returns, type_comment, + if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from AsyncFunctionDef"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + type_params = _Py_asdl_type_param_seq_new(len, arena); + if (type_params == NULL) goto failed; + for (i = 0; i < len; i++) { + type_param_ty val; + PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); + if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { + goto failed; + } + res = obj2ast_type_param(state, tmp2, &val, arena); + _Py_LeaveRecursiveCall(); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"type_params\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(type_params, i, val); + } + Py_CLEAR(tmp); + } + *out = _PyAST_AsyncFunctionDef(name, args, body, decorator_list, + returns, type_comment, type_params, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; @@ -6469,11 +6468,11 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; - asdl_type_param_seq* type_params; asdl_expr_seq* bases; asdl_keyword_seq* keywords; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; + asdl_type_param_seq* type_params; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; @@ -6492,42 +6491,6 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { - return 1; - } - if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from ClassDef"); - return 1; - } - else { - int res; - Py_ssize_t len; - Py_ssize_t i; - if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); - goto failed; - } - len = PyList_GET_SIZE(tmp); - type_params = _Py_asdl_type_param_seq_new(len, arena); - if (type_params == NULL) goto failed; - for (i = 0; i < len; i++) { - type_param_ty val; - PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); - if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { - goto failed; - } - res = obj2ast_type_param(state, tmp2, &val, arena); - _Py_LeaveRecursiveCall(); - Py_DECREF(tmp2); - if (res != 0) goto failed; - if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"type_params\" changed size during iteration"); - goto failed; - } - asdl_seq_SET(type_params, i, val); - } - Py_CLEAR(tmp); - } if (_PyObject_LookupAttr(obj, state->bases, &tmp) < 0) { return 1; } @@ -6672,8 +6635,44 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - *out = _PyAST_ClassDef(name, type_params, bases, keywords, body, - decorator_list, lineno, col_offset, end_lineno, + if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from ClassDef"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + type_params = _Py_asdl_type_param_seq_new(len, arena); + if (type_params == NULL) goto failed; + for (i = 0; i < len; i++) { + type_param_ty val; + PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); + if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { + goto failed; + } + res = obj2ast_type_param(state, tmp2, &val, arena); + _Py_LeaveRecursiveCall(); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"type_params\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(type_params, i, val); + } + Py_CLEAR(tmp); + } + *out = _PyAST_ClassDef(name, bases, keywords, body, decorator_list, + type_params, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; From b45df737d43e809b1c41b9b2056ecb28c3cfb288 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 30 May 2023 16:50:23 +0100 Subject: [PATCH 0081/1206] [3.12] gh-105071: add PyUnstable_Exc_PrepReraiseStar to expose except* implementation in the unstable API (GH-105072) (#105095) (cherry picked from commit b7aadb4583b040ddc8564896b91f4e5e571c82d6) --- Doc/c-api/exceptions.rst | 10 ++ Include/cpython/pyerrors.h | 4 + Lib/test/test_capi/test_exceptions.py | 93 +++++++++++++++++++ ...-05-30-10-15-13.gh-issue-105071.dPtp7c.rst | 1 + Modules/_testcapi/clinic/exceptions.c.h | 33 ++++++- Modules/_testcapi/exceptions.c | 17 ++++ Objects/exceptions.c | 39 ++++++++ 7 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 4ed96f01dbbc3e..22666d70529061 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -772,6 +772,16 @@ Exception Objects Set :attr:`~BaseException.args` of exception *ex* to *args*. +.. c:function:: PyObject* PyUnstable_Exc_PrepReraiseStar(PyObject *orig, PyObject *excs) + + Implement part of the interpreter's implementation of :keyword:`!except*`. + *orig* is the original exception that was caught, and *excs* is the list of + the exceptions that need to be raised. This list contains the the unhandled + part of *orig*, if any, as well as the exceptions that were raised from the + :keyword:`!except*` clauses (so they have a different traceback from *orig*) and + those that were reraised (and have the same traceback as *orig*). + Return the :exc:`ExceptionGroup` that needs to be reraised in the end, or + ``None`` if there is nothing to reraise. .. _unicodeexceptions: diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 758804ade2baa7..156665cbdb1ba4 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -116,6 +116,10 @@ PyAPI_FUNC(int) _PyException_AddNote( PyObject *exc, PyObject *note); +PyAPI_FUNC(PyObject*) PyUnstable_Exc_PrepReraiseStar( + PyObject *orig, + PyObject *excs); + /* In signalmodule.c */ int PySignal_SetWakeupFd(int fd); diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index 1081f40b6981af..118b575cba6df7 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -5,6 +5,7 @@ from test import support from test.support import import_helper from test.support.script_helper import assert_python_failure +from test.support.testcase import ExceptionIsLikeMixin from .test_misc import decode_stderr @@ -189,5 +190,97 @@ def __repr__(self): 'Normalization failed: type=Broken args=') +class Test_PyUnstable_Exc_PrepReraiseStar(ExceptionIsLikeMixin, unittest.TestCase): + + def setUp(self): + super().setUp() + try: + raise ExceptionGroup("eg", [TypeError('bad type'), ValueError(42)]) + except ExceptionGroup as e: + self.orig = e + + def test_invalid_args(self): + with self.assertRaisesRegex(TypeError, "orig must be an exception"): + _testcapi.unstable_exc_prep_reraise_star(42, [None]) + + with self.assertRaisesRegex(TypeError, "excs must be a list"): + _testcapi.unstable_exc_prep_reraise_star(self.orig, 42) + + with self.assertRaisesRegex(TypeError, "not an exception"): + _testcapi.unstable_exc_prep_reraise_star(self.orig, [TypeError(42), 42]) + + with self.assertRaisesRegex(ValueError, "orig must be a raised exception"): + _testcapi.unstable_exc_prep_reraise_star(ValueError(42), [TypeError(42)]) + + with self.assertRaisesRegex(ValueError, "orig must be a raised exception"): + _testcapi.unstable_exc_prep_reraise_star(ExceptionGroup("eg", [ValueError(42)]), + [TypeError(42)]) + + + def test_nothing_to_reraise(self): + self.assertEqual( + _testcapi.unstable_exc_prep_reraise_star(self.orig, [None]), None) + + try: + raise ValueError(42) + except ValueError as e: + orig = e + self.assertEqual( + _testcapi.unstable_exc_prep_reraise_star(orig, [None]), None) + + def test_reraise_orig(self): + orig = self.orig + res = _testcapi.unstable_exc_prep_reraise_star(orig, [orig]) + self.assertExceptionIsLike(res, orig) + + def test_raise_orig_parts(self): + orig = self.orig + match, rest = orig.split(TypeError) + + test_cases = [ + ([match, rest], orig), + ([rest, match], orig), + ([match], match), + ([rest], rest), + ([], None), + ] + + for input, expected in test_cases: + with self.subTest(input=input): + res = _testcapi.unstable_exc_prep_reraise_star(orig, input) + self.assertExceptionIsLike(res, expected) + + + def test_raise_with_new_exceptions(self): + orig = self.orig + + match, rest = orig.split(TypeError) + new1 = OSError('bad file') + new2 = RuntimeError('bad runtime') + + test_cases = [ + ([new1, match, rest], ExceptionGroup("", [new1, orig])), + ([match, new1, rest], ExceptionGroup("", [new1, orig])), + ([match, rest, new1], ExceptionGroup("", [new1, orig])), + + ([new1, new2, match, rest], ExceptionGroup("", [new1, new2, orig])), + ([new1, match, new2, rest], ExceptionGroup("", [new1, new2, orig])), + ([new2, rest, match, new1], ExceptionGroup("", [new2, new1, orig])), + ([rest, new2, match, new1], ExceptionGroup("", [new2, new1, orig])), + + + ([new1, new2, rest], ExceptionGroup("", [new1, new2, rest])), + ([new1, match, new2], ExceptionGroup("", [new1, new2, match])), + ([rest, new2, new1], ExceptionGroup("", [new2, new1, rest])), + ([new1, new2], ExceptionGroup("", [new1, new2])), + ([new2, new1], ExceptionGroup("", [new2, new1])), + ] + + for (input, expected) in test_cases: + with self.subTest(input=input): + res = _testcapi.unstable_exc_prep_reraise_star(orig, input) + self.assertExceptionIsLike(res, expected) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst b/Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst new file mode 100644 index 00000000000000..3d916fcb961f62 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst @@ -0,0 +1 @@ +Add ``PyUnstable_Exc_PrepReraiseStar`` to the unstable C api to expose the implementation of :keyword:`except* `. diff --git a/Modules/_testcapi/clinic/exceptions.c.h b/Modules/_testcapi/clinic/exceptions.c.h index 2cc4ef3dc0d497..01730ffa2ed036 100644 --- a/Modules/_testcapi/clinic/exceptions.c.h +++ b/Modules/_testcapi/clinic/exceptions.c.h @@ -395,4 +395,35 @@ _testcapi_traceback_print(PyObject *module, PyObject *const *args, Py_ssize_t na exit: return return_value; } -/*[clinic end generated code: output=ec1b2e62adea9846 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_testcapi_unstable_exc_prep_reraise_star__doc__, +"unstable_exc_prep_reraise_star($module, orig, excs, /)\n" +"--\n" +"\n" +"To test PyUnstable_Exc_PrepReraiseStar."); + +#define _TESTCAPI_UNSTABLE_EXC_PREP_RERAISE_STAR_METHODDEF \ + {"unstable_exc_prep_reraise_star", _PyCFunction_CAST(_testcapi_unstable_exc_prep_reraise_star), METH_FASTCALL, _testcapi_unstable_exc_prep_reraise_star__doc__}, + +static PyObject * +_testcapi_unstable_exc_prep_reraise_star_impl(PyObject *module, + PyObject *orig, PyObject *excs); + +static PyObject * +_testcapi_unstable_exc_prep_reraise_star(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *orig; + PyObject *excs; + + if (!_PyArg_CheckPositional("unstable_exc_prep_reraise_star", nargs, 2, 2)) { + goto exit; + } + orig = args[0]; + excs = args[1]; + return_value = _testcapi_unstable_exc_prep_reraise_star_impl(module, orig, excs); + +exit: + return return_value; +} +/*[clinic end generated code: output=fd6aef54f195c77b input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index 0a9902c135a7e5..a627bf1717fe0c 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -288,6 +288,22 @@ _testcapi_traceback_print_impl(PyObject *module, PyObject *traceback, Py_RETURN_NONE; } +/*[clinic input] +_testcapi.unstable_exc_prep_reraise_star + orig: object + excs: object + / +To test PyUnstable_Exc_PrepReraiseStar. +[clinic start generated code]*/ + +static PyObject * +_testcapi_unstable_exc_prep_reraise_star_impl(PyObject *module, + PyObject *orig, PyObject *excs) +/*[clinic end generated code: output=850cf008e0563c77 input=27fbcda2203eb301]*/ +{ + return PyUnstable_Exc_PrepReraiseStar(orig, excs); +} + /* * Define the PyRecurdingInfinitelyError_Type @@ -328,6 +344,7 @@ static PyMethodDef test_methods[] = { _TESTCAPI_SET_EXCEPTION_METHODDEF _TESTCAPI_TRACEBACK_PRINT_METHODDEF _TESTCAPI_WRITE_UNRAISABLE_EXC_METHODDEF + _TESTCAPI_UNSTABLE_EXC_PREP_RERAISE_STAR_METHODDEF {NULL}, }; diff --git a/Objects/exceptions.c b/Objects/exceptions.c index a8d4e3a696ce8e..7bec7395cc7f0b 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1351,7 +1351,10 @@ is_same_exception_metadata(PyObject *exc1, PyObject *exc2) PyObject * _PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs) { + /* orig must be a raised & caught exception, so it has a traceback */ assert(PyExceptionInstance_Check(orig)); + assert(_PyBaseExceptionObject_cast(orig)->traceback != NULL); + assert(PyList_Check(excs)); Py_ssize_t numexcs = PyList_GET_SIZE(excs); @@ -1438,6 +1441,42 @@ _PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs) return result; } +PyObject * +PyUnstable_Exc_PrepReraiseStar(PyObject *orig, PyObject *excs) +{ + if (orig == NULL || !PyExceptionInstance_Check(orig)) { + PyErr_SetString(PyExc_TypeError, "orig must be an exception instance"); + return NULL; + } + if (excs == NULL || !PyList_Check(excs)) { + PyErr_SetString(PyExc_TypeError, + "excs must be a list of exception instances"); + return NULL; + } + Py_ssize_t numexcs = PyList_GET_SIZE(excs); + for (Py_ssize_t i = 0; i < numexcs; i++) { + PyObject *exc = PyList_GET_ITEM(excs, i); + if (exc == NULL || !(PyExceptionInstance_Check(exc) || Py_IsNone(exc))) { + PyErr_Format(PyExc_TypeError, + "item %d of excs is not an exception", i); + return NULL; + } + } + + /* Make sure that orig has something as traceback, in the interpreter + * it always does becuase it's a raised exception. + */ + PyObject *tb = PyException_GetTraceback(orig); + + if (tb == NULL) { + PyErr_Format(PyExc_ValueError, "orig must be a raised exception"); + return NULL; + } + Py_DECREF(tb); + + return _PyExc_PrepReraiseStar(orig, excs); +} + static PyMemberDef BaseExceptionGroup_members[] = { {"message", T_OBJECT, offsetof(PyBaseExceptionGroupObject, msg), READONLY, PyDoc_STR("exception message")}, From 4e7d41f9867676dc1aacdf0310f500b0191be0fc Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 30 May 2023 17:31:51 +0100 Subject: [PATCH 0082/1206] [3.12] Enable the ABI check job to publish the updated ABI data file (GH-105088) --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3ada845c4cbbc3..046c2aaa55f67b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,15 +100,28 @@ jobs: ./configure --enable-shared make -j4 - name: Check for changes in the ABI + id: check run: | if ! make check-abidump; then echo "Generated ABI file is not up to date." echo "Please add the release manager of this branch as a reviewer of this PR." echo "" + echo "The up to date ABI file should be attached to this build as an artifact." + echo "" echo "To learn more about this check: https://devguide.python.org/setup/#regenerate-the-abi-dump" echo "" exit 1 fi + - name: Generate updated ABI files + if: ${{ failure() && steps.check.conclusion == 'failure' }} + run: | + make regen-abidump + - uses: actions/upload-artifact@v3 + name: Publish updated ABI files + if: ${{ failure() && steps.check.conclusion == 'failure' }} + with: + name: abi-data + path: ./Doc/data/*.abi check_generated_files: name: 'Check if generated files are up to date' From 9fb7abba6d64dd345e09e13675b522aa2006d74f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 May 2023 09:34:57 -0700 Subject: [PATCH 0083/1206] [3.12] gh-103921: Minor PEP-695 fixes to the `ast` module docs (GH-105093) (#105101) (cherry picked from commit c8c1e73d95d5dcd7a2c8d7c10cfafc3fe5a9377e) Co-authored-by: Alex Waygood --- Doc/library/ast.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 17d1de9fbb8f11..f3b0bf0c4f7779 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1744,17 +1744,17 @@ aliases. Function and class definitions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. class:: FunctionDef(name, type_params, args, body, decorator_list, returns, type_comment) +.. class:: FunctionDef(name, args, body, decorator_list, returns, type_comment, type_params) A function definition. * ``name`` is a raw string of the function name. - * ``type_params`` is a list of :ref:`type parameters `. * ``args`` is an :class:`arguments` node. * ``body`` is the list of nodes inside the function. * ``decorator_list`` is the list of decorators to be applied, stored outermost first (i.e. the first in the list will be applied last). * ``returns`` is the return annotation. + * ``type_params`` is a list of :ref:`type parameters `. .. attribute:: type_comment @@ -1917,12 +1917,11 @@ Function and class definitions type_ignores=[]) -.. class:: ClassDef(name, type_params, bases, keywords, body, decorator_list) +.. class:: ClassDef(name, bases, keywords, body, decorator_list, type_params) A class definition. * ``name`` is a raw string for the class name - * ``type_params`` is a list of :ref:`type parameters `. * ``bases`` is a list of nodes for explicitly specified base classes. * ``keywords`` is a list of :class:`keyword` nodes, principally for 'metaclass'. Other keywords will be passed to the metaclass, as per `PEP-3115 @@ -1930,6 +1929,7 @@ Function and class definitions * ``body`` is a list of nodes representing the code within the class definition. * ``decorator_list`` is a list of nodes, as in :class:`FunctionDef`. + * ``type_params`` is a list of :ref:`type parameters `. .. doctest:: @@ -1961,7 +1961,7 @@ Function and class definitions Async and await ^^^^^^^^^^^^^^^ -.. class:: AsyncFunctionDef(name, args, body, decorator_list, returns, type_comment) +.. class:: AsyncFunctionDef(name, args, body, decorator_list, returns, type_comment, type_params) An ``async def`` function definition. Has the same fields as :class:`FunctionDef`. From aeee5a575647a9f2676d0d00c763e1a9454a6102 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 May 2023 10:03:57 -0700 Subject: [PATCH 0084/1206] [3.12] gh-105071: add missing versionadded directive (GH-105097) (#105105) gh-105071: add missing versionadded directive (GH-105097) (cherry picked from commit 4571eedca2f70768ddc4a2fd4fba2ae11b4c8037) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/c-api/exceptions.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 22666d70529061..dc73ad8157961b 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -783,6 +783,8 @@ Exception Objects Return the :exc:`ExceptionGroup` that needs to be reraised in the end, or ``None`` if there is nothing to reraise. + .. versionadded:: 3.12 + .. _unicodeexceptions: Unicode Exception Objects From 9ae49e3f3bdf585473f03522a1b7dd7c9e4baa6a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 May 2023 12:33:17 -0700 Subject: [PATCH 0085/1206] gh-88745: Add _winapi.CopyFile2 and update shutil.copy2 to use it (GH-105055) (cherry picked from commit cda1bd3c9d3b2cecdeeba0c498cd2df83fbdb535) Co-authored-by: Steve Dower --- Doc/data/python3.12.abi | 1935 +++++++++-------- .../pycore_global_objects_fini_generated.h | 3 + Include/internal/pycore_global_strings.h | 3 + .../internal/pycore_runtime_init_generated.h | 3 + .../internal/pycore_unicodeobject_generated.h | 9 + Lib/shutil.py | 25 + ...3-05-29-11-38-53.gh-issue-88745.cldf9G.rst | 3 + Modules/_winapi.c | 93 + Modules/clinic/_winapi.c.h | 72 +- 9 files changed, 1186 insertions(+), 960 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 9802893e69cca7..94b09516b511e1 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -867,6 +867,7 @@ + @@ -1701,7 +1702,7 @@ - + @@ -1719,7 +1720,7 @@ - + @@ -1729,10 +1730,10 @@ - + - + @@ -1820,11 +1821,11 @@ - + - + @@ -1836,14 +1837,14 @@ - + - + @@ -1862,7 +1863,7 @@ - + @@ -1872,7 +1873,7 @@ - + @@ -1914,13 +1915,13 @@ - + - + @@ -1928,7 +1929,7 @@ - + @@ -2008,7 +2009,7 @@ - + @@ -2039,7 +2040,7 @@ - + @@ -2067,7 +2068,7 @@ - + @@ -3364,7 +3365,7 @@ - + @@ -3418,7 +3419,7 @@ - + @@ -3524,7 +3525,7 @@ - + @@ -3533,7 +3534,7 @@ - + @@ -3589,7 +3590,7 @@ - + @@ -3611,12 +3612,12 @@ - + - + @@ -3633,7 +3634,7 @@ - + @@ -3775,7 +3776,7 @@ - + @@ -3846,7 +3847,7 @@ - + @@ -3905,7 +3906,7 @@ - + @@ -3928,7 +3929,7 @@ - + @@ -4657,7 +4658,7 @@ - + @@ -4691,7 +4692,7 @@ - + @@ -5032,7 +5033,7 @@ - + @@ -5129,7 +5130,7 @@ - + @@ -5317,7 +5318,7 @@ - + @@ -5355,7 +5356,7 @@ - + @@ -5571,7 +5572,7 @@ - + @@ -5636,7 +5637,7 @@ - + @@ -5658,7 +5659,7 @@ - + @@ -5714,7 +5715,7 @@ - + @@ -5973,7 +5974,7 @@ - + @@ -6090,7 +6091,7 @@ - + @@ -6227,7 +6228,7 @@ - + @@ -6527,7 +6528,7 @@ - + @@ -6536,7 +6537,7 @@ - + @@ -6760,136 +6761,141 @@ - - + + + - - + + - - + + - - + + - - + + - - - + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - + + - - - + + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - - - + + + + + - - - + + + - + @@ -6978,7 +6984,7 @@ - + @@ -7171,7 +7177,7 @@ - + @@ -7302,7 +7308,7 @@ - + @@ -7397,7 +7403,7 @@ - + @@ -7426,7 +7432,7 @@ - + @@ -7567,7 +7573,7 @@ - + @@ -7623,7 +7629,7 @@ - + @@ -7637,7 +7643,7 @@ - + @@ -7694,7 +7700,7 @@ - + @@ -7849,7 +7855,7 @@ - + @@ -7877,7 +7883,7 @@ - + @@ -7904,7 +7910,7 @@ - + @@ -8086,7 +8092,7 @@ - + @@ -8098,7 +8104,7 @@ - + @@ -8396,7 +8402,7 @@ - + @@ -8531,7 +8537,7 @@ - + @@ -8576,7 +8582,7 @@ - + @@ -8591,7 +8597,7 @@ - + @@ -8604,7 +8610,7 @@ - + @@ -8632,7 +8638,7 @@ - + @@ -8660,7 +8666,7 @@ - + @@ -8731,7 +8737,7 @@ - + @@ -8750,7 +8756,7 @@ - + @@ -8971,7 +8977,7 @@ - + @@ -8987,7 +8993,7 @@ - + @@ -9009,7 +9015,7 @@ - + @@ -9678,7 +9684,7 @@ - + @@ -9692,7 +9698,7 @@ - + @@ -9710,7 +9716,7 @@ - + @@ -10830,7 +10836,7 @@ - + @@ -10877,10 +10883,10 @@ - + - + @@ -11106,7 +11112,7 @@ - + @@ -11907,7 +11913,7 @@ - + @@ -13337,12 +13343,12 @@ - + - + @@ -13355,19 +13361,19 @@ - + - + - + - + - + @@ -13419,7 +13425,7 @@ - + @@ -13433,18 +13439,18 @@ - + - + - - + + - - + + @@ -13473,7 +13479,7 @@ - + @@ -13488,7 +13494,7 @@ - + @@ -13509,13 +13515,13 @@ - + - + - + @@ -13551,7 +13557,7 @@ - + @@ -13623,7 +13629,7 @@ - + @@ -13652,7 +13658,7 @@ - + @@ -14252,7 +14258,7 @@ - + @@ -14312,7 +14318,7 @@ - + @@ -14366,7 +14372,7 @@ - + @@ -14525,7 +14531,7 @@ - + @@ -14609,7 +14615,7 @@ - + @@ -14666,1027 +14672,1036 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -15809,20 +15824,20 @@ - + - + - + - + - + - + @@ -15982,7 +15997,7 @@ - + @@ -15993,7 +16008,7 @@ - + @@ -16526,7 +16541,7 @@ - + @@ -16635,7 +16650,7 @@ - + @@ -17369,8 +17384,8 @@ - + @@ -17601,7 +17616,7 @@ - + @@ -18891,7 +18906,7 @@ - + @@ -18929,7 +18944,7 @@ - + @@ -20794,11 +20809,13 @@ + + @@ -20935,8 +20952,8 @@ - - + + @@ -21003,7 +21020,7 @@ - + @@ -21058,7 +21075,7 @@ - + @@ -21083,7 +21100,7 @@ - + @@ -21121,7 +21138,7 @@ - + @@ -21227,7 +21244,7 @@ - + @@ -21238,17 +21255,17 @@ - + - + - + @@ -21316,7 +21333,7 @@ - + @@ -21336,7 +21353,7 @@ - + @@ -21349,7 +21366,7 @@ - + @@ -21456,7 +21473,7 @@ - + @@ -21505,7 +21522,7 @@ - + @@ -21522,12 +21539,12 @@ - + - + @@ -21897,7 +21914,7 @@ - + @@ -22063,7 +22080,7 @@ - + @@ -22154,7 +22171,7 @@ - + @@ -22553,7 +22570,7 @@ - + @@ -22720,7 +22737,7 @@ - + @@ -22809,7 +22826,7 @@ - + @@ -22820,7 +22837,7 @@ - + @@ -22978,7 +22995,7 @@ - + @@ -23070,53 +23087,53 @@ - - - + + + - - + + - - - - + + + + - - - - + + + + - - - + + + - - - + + + - - + + - - - + + + - - - + + + - + @@ -23126,7 +23143,7 @@ - + @@ -23212,7 +23229,7 @@ - + @@ -23226,7 +23243,7 @@ - + @@ -23331,7 +23348,7 @@ - + @@ -23403,7 +23420,7 @@ - + @@ -23508,21 +23525,21 @@ - + - + - + - + @@ -23531,7 +23548,7 @@ - + @@ -23605,7 +23622,7 @@ - + @@ -23821,7 +23838,7 @@ - + @@ -24162,11 +24179,11 @@ - + - + @@ -24241,7 +24258,7 @@ - + @@ -24260,7 +24277,7 @@ - + @@ -24367,7 +24384,7 @@ - + @@ -24396,7 +24413,7 @@ - + @@ -24412,7 +24429,7 @@ - + @@ -24484,7 +24501,7 @@ - + @@ -24493,7 +24510,7 @@ - + @@ -24529,7 +24546,7 @@ - + @@ -24541,7 +24558,7 @@ - + @@ -24626,7 +24643,7 @@ - + @@ -25346,7 +25363,7 @@ - + @@ -25553,14 +25570,14 @@ - + - + @@ -25579,7 +25596,7 @@ - + @@ -25816,7 +25833,7 @@ - + @@ -26073,7 +26090,7 @@ - + @@ -26104,7 +26121,7 @@ - + @@ -26116,10 +26133,10 @@ - + - + @@ -26333,7 +26350,7 @@ - + @@ -26359,7 +26376,7 @@ - + diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 5a1993eac23a8a..d5819fcd1c5038 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -916,6 +916,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_value)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(excepthook)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exception)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(existing_file_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(extend)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(extra_tokens)); @@ -1068,6 +1069,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(namespaces)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(narg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ndigits)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(new_file_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(new_limit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(newline)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(newlines)); @@ -1122,6 +1124,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(priority)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(progress)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(progress_handler)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(progress_routine)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(proto)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(protocol)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ps1)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 61967877ab4ac8..0c84999cbf8127 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -404,6 +404,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(exc_value) STRUCT_FOR_ID(excepthook) STRUCT_FOR_ID(exception) + STRUCT_FOR_ID(existing_file_name) STRUCT_FOR_ID(exp) STRUCT_FOR_ID(extend) STRUCT_FOR_ID(extra_tokens) @@ -556,6 +557,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(namespaces) STRUCT_FOR_ID(narg) STRUCT_FOR_ID(ndigits) + STRUCT_FOR_ID(new_file_name) STRUCT_FOR_ID(new_limit) STRUCT_FOR_ID(newline) STRUCT_FOR_ID(newlines) @@ -610,6 +612,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(priority) STRUCT_FOR_ID(progress) STRUCT_FOR_ID(progress_handler) + STRUCT_FOR_ID(progress_routine) STRUCT_FOR_ID(proto) STRUCT_FOR_ID(protocol) STRUCT_FOR_ID(ps1) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 59ec49af358f2e..07f237b2905864 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -910,6 +910,7 @@ extern "C" { INIT_ID(exc_value), \ INIT_ID(excepthook), \ INIT_ID(exception), \ + INIT_ID(existing_file_name), \ INIT_ID(exp), \ INIT_ID(extend), \ INIT_ID(extra_tokens), \ @@ -1062,6 +1063,7 @@ extern "C" { INIT_ID(namespaces), \ INIT_ID(narg), \ INIT_ID(ndigits), \ + INIT_ID(new_file_name), \ INIT_ID(new_limit), \ INIT_ID(newline), \ INIT_ID(newlines), \ @@ -1116,6 +1118,7 @@ extern "C" { INIT_ID(priority), \ INIT_ID(progress), \ INIT_ID(progress_handler), \ + INIT_ID(progress_routine), \ INIT_ID(proto), \ INIT_ID(protocol), \ INIT_ID(ps1), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 8f8a067e4c1808..9b470094b7afe2 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1053,6 +1053,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(exception); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(existing_file_name); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(exp); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1509,6 +1512,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(ndigits); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(new_file_name); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(new_limit); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1671,6 +1677,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(progress_handler); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(progress_routine); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(proto); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Lib/shutil.py b/Lib/shutil.py index 7d1a3d00011f37..3f2864af517e7d 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -42,6 +42,8 @@ if sys.platform == 'win32': import _winapi +else: + _winapi = None COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024 # This should never be removed, see rationale in: @@ -435,6 +437,29 @@ def copy2(src, dst, *, follow_symlinks=True): """ if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) + + if hasattr(_winapi, "CopyFile2"): + src_ = os.fsdecode(src) + dst_ = os.fsdecode(dst) + flags = _winapi.COPY_FILE_ALLOW_DECRYPTED_DESTINATION # for compat + if not follow_symlinks: + flags |= _winapi.COPY_FILE_COPY_SYMLINK + try: + _winapi.CopyFile2(src_, dst_, flags) + return dst + except OSError as exc: + if (exc.winerror == _winapi.ERROR_PRIVILEGE_NOT_HELD + and not follow_symlinks): + # Likely encountered a symlink we aren't allowed to create. + # Fall back on the old code + pass + elif exc.winerror == _winapi.ERROR_ACCESS_DENIED: + # Possibly encountered a hidden or readonly file we can't + # overwrite. Fall back on old code + pass + else: + raise + copyfile(src, dst, follow_symlinks=follow_symlinks) copystat(src, dst, follow_symlinks=follow_symlinks) return dst diff --git a/Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst b/Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst new file mode 100644 index 00000000000000..258eb89d50d9f5 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst @@ -0,0 +1,3 @@ +Improve performance of :func:`shutil.copy2` by using the operating system's +``CopyFile2`` function. This may result in subtle changes to metadata copied +along with some files, bringing them in line with normal OS behavior. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 1e02dbc1a4bfd1..bbc9facd227c9e 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1947,6 +1947,7 @@ _winapi_GetFileType_impl(PyObject *module, HANDLE handle) return result; } + /*[clinic input] _winapi._mimetypes_read_windows_registry @@ -2075,6 +2076,67 @@ _winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module, return result; } + +/*[clinic input] +_winapi.CopyFile2 + + existing_file_name: LPCWSTR + new_file_name: LPCWSTR + flags: DWORD + progress_routine: object = None + +Copies a file from one name to a new name. + +This is implemented using the CopyFile2 API, which preserves all stat +and metadata information apart from security attributes. + +progress_routine is reserved for future use, but is currently not +implemented. Its value is ignored. +[clinic start generated code]*/ + +static PyObject * +_winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name, + LPCWSTR new_file_name, DWORD flags, + PyObject *progress_routine) +/*[clinic end generated code: output=43d960d9df73d984 input=fb976b8d1492d130]*/ +{ + HRESULT hr; + COPYFILE2_EXTENDED_PARAMETERS params = { sizeof(COPYFILE2_EXTENDED_PARAMETERS) }; + + if (PySys_Audit("_winapi.CopyFile2", "uuI", + existing_file_name, new_file_name, flags) < 0) { + return NULL; + } + + params.dwCopyFlags = flags; + /* For future implementation. We ignore the value for now so that + users only have to test for 'CopyFile2' existing and not whether + the additional parameter exists. + if (progress_routine != Py_None) { + params.pProgressRoutine = _winapi_CopyFile2ProgressRoutine; + params.pvCallbackContext = Py_NewRef(progress_routine); + } + */ + Py_BEGIN_ALLOW_THREADS; + hr = CopyFile2(existing_file_name, new_file_name, ¶ms); + Py_END_ALLOW_THREADS; + /* For future implementation. + if (progress_routine != Py_None) { + Py_DECREF(progress_routine); + } + */ + if (FAILED(hr)) { + if ((hr & 0xFFFF0000) == 0x80070000) { + PyErr_SetFromWindowsErr(hr & 0xFFFF); + } else { + PyErr_SetFromWindowsErr(hr); + } + return NULL; + } + Py_RETURN_NONE; +} + + static PyMethodDef winapi_functions[] = { _WINAPI_CLOSEHANDLE_METHODDEF _WINAPI_CONNECTNAMEDPIPE_METHODDEF @@ -2110,6 +2172,7 @@ static PyMethodDef winapi_functions[] = { _WINAPI_GETFILETYPE_METHODDEF _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF _WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF + _WINAPI_COPYFILE2_METHODDEF {NULL, NULL} }; @@ -2146,6 +2209,7 @@ static int winapi_exec(PyObject *m) WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP); WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS); WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE); + WINAPI_CONSTANT(F_DWORD, ERROR_ACCESS_DENIED); WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING); @@ -2159,6 +2223,7 @@ static int winapi_exec(PyObject *m) WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED); WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); + WINAPI_CONSTANT(F_DWORD, ERROR_PRIVILEGE_NOT_HELD); WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE); WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); @@ -2252,6 +2317,34 @@ static int winapi_exec(PyObject *m) WINAPI_CONSTANT(F_DWORD, LCMAP_TRADITIONAL_CHINESE); WINAPI_CONSTANT(F_DWORD, LCMAP_UPPERCASE); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_ALLOW_DECRYPTED_DESTINATION); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_COPY_SYMLINK); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_FAIL_IF_EXISTS); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_BUFFERING); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_OFFLOAD); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_OPEN_SOURCE_FOR_WRITE); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESTARTABLE); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_SECURITY_PRIVILEGES); + WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESUME_FROM_PAUSE); +#ifndef COPY_FILE_REQUEST_COMPRESSED_TRAFFIC + // Only defined in newer WinSDKs + #define COPY_FILE_REQUEST_COMPRESSED_TRAFFIC 0x10000000 +#endif + WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_COMPRESSED_TRAFFIC); + + WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_STARTED); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_FINISHED); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_STARTED); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_FINISHED); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_POLL_CONTINUE); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_ERROR); + + WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CONTINUE); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CANCEL); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_STOP); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_QUIET); + WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_PAUSE); + WINAPI_CONSTANT("i", NULL); return 0; diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 7bc63e612be348..3767b19d76db05 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -1411,4 +1411,74 @@ _winapi_NeedCurrentDirectoryForExePath(PyObject *module, PyObject *arg) return return_value; } -/*[clinic end generated code: output=96ea65ece7912d0a input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_winapi_CopyFile2__doc__, +"CopyFile2($module, /, existing_file_name, new_file_name, flags,\n" +" progress_routine=None)\n" +"--\n" +"\n" +"Copies a file from one name to a new name.\n" +"\n" +"This is implemented using the CopyFile2 API, which preserves all stat\n" +"and metadata information apart from security attributes.\n" +"\n" +"progress_routine is reserved for future use, but is currently not\n" +"implemented. Its value is ignored."); + +#define _WINAPI_COPYFILE2_METHODDEF \ + {"CopyFile2", _PyCFunction_CAST(_winapi_CopyFile2), METH_FASTCALL|METH_KEYWORDS, _winapi_CopyFile2__doc__}, + +static PyObject * +_winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name, + LPCWSTR new_file_name, DWORD flags, + PyObject *progress_routine); + +static PyObject * +_winapi_CopyFile2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(existing_file_name), &_Py_ID(new_file_name), &_Py_ID(flags), &_Py_ID(progress_routine), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"existing_file_name", "new_file_name", "flags", "progress_routine", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .format = "O&O&k|O:CopyFile2", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + LPCWSTR existing_file_name = NULL; + LPCWSTR new_file_name = NULL; + DWORD flags; + PyObject *progress_routine = Py_None; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + _PyUnicode_WideCharString_Converter, &existing_file_name, _PyUnicode_WideCharString_Converter, &new_file_name, &flags, &progress_routine)) { + goto exit; + } + return_value = _winapi_CopyFile2_impl(module, existing_file_name, new_file_name, flags, progress_routine); + +exit: + /* Cleanup for existing_file_name */ + PyMem_Free((void *)existing_file_name); + /* Cleanup for new_file_name */ + PyMem_Free((void *)new_file_name); + + return return_value; +} +/*[clinic end generated code: output=be1343b3759e0c96 input=a9049054013a1b77]*/ From 5fff491bd5d6da579a28b521efd3ef15f3f42c01 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 May 2023 14:10:46 -0700 Subject: [PATCH 0086/1206] [3.12] gh-105035: fix super() calls on unusual types (e.g. meta-types) (GH-105094) (#105117) gh-105035: fix super() calls on unusual types (e.g. meta-types) (GH-105094) (cherry picked from commit 68c75c31536e8c87901934f2d6da81f54f4334f9) Co-authored-by: Carl Meyer --- Lib/test/test_super.py | 12 + ...-05-30-08-09-43.gh-issue-105035.OWUlHy.rst | 2 + Python/bytecodes.c | 4 +- Python/generated_cases.c.h | 442 +++++++++--------- 4 files changed, 239 insertions(+), 221 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py index 698ab48f48eaa1..664cf70b3cf0fa 100644 --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -410,6 +410,18 @@ def method(self): self.assertEqual(C().method(), mysuper) + def test_unusual_getattro(self): + class MyType(type): + pass + + def test(name): + mytype = MyType(name, (MyType,), {}) + super(MyType, type(mytype)).__setattr__(mytype, "bar", 1) + self.assertEqual(mytype.bar, 1) + + test("foo1") + test("foo2") + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst new file mode 100644 index 00000000000000..c0ee2da9d45037 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst @@ -0,0 +1,2 @@ +Fix :func:`super` calls on types with custom :attr:`tp_getattro` +implementation (e.g. meta-types.) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f71a62e051a34f..0baf2451ee4f8a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1660,8 +1660,10 @@ dummy_func( DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; - res2 = _PySuper_Lookup((PyTypeObject *)class, self, name, &method_found); + res2 = _PySuper_Lookup(cls, self, name, + cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); if (res2 == NULL) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 055fb5a0611b96..103373ec0db018 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2408,8 +2408,10 @@ DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; - res2 = _PySuper_Lookup((PyTypeObject *)class, self, name, &method_found); + res2 = _PySuper_Lookup(cls, self, name, + cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); if (res2 == NULL) { @@ -2423,7 +2425,7 @@ res = res2; res2 = NULL; } - #line 2427 "Python/generated_cases.c.h" + #line 2429 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2437,7 +2439,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1695 "Python/bytecodes.c" + #line 1697 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2471,9 +2473,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2475 "Python/generated_cases.c.h" + #line 2477 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1729 "Python/bytecodes.c" + #line 1731 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2482,12 +2484,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2486 "Python/generated_cases.c.h" + #line 2488 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1738 "Python/bytecodes.c" + #line 1740 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2491 "Python/generated_cases.c.h" + #line 2493 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2501,7 +2503,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1743 "Python/bytecodes.c" + #line 1745 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2514,7 +2516,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2518 "Python/generated_cases.c.h" + #line 2520 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2529,7 +2531,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1759 "Python/bytecodes.c" + #line 1761 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2542,7 +2544,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2546 "Python/generated_cases.c.h" + #line 2548 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2557,7 +2559,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1775 "Python/bytecodes.c" + #line 1777 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2584,7 +2586,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2588 "Python/generated_cases.c.h" + #line 2590 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2599,7 +2601,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1805 "Python/bytecodes.c" + #line 1807 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2609,7 +2611,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2613 "Python/generated_cases.c.h" + #line 2615 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2624,7 +2626,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1818 "Python/bytecodes.c" + #line 1820 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2636,7 +2638,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2640 "Python/generated_cases.c.h" + #line 2642 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2650,7 +2652,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1833 "Python/bytecodes.c" + #line 1835 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2674,7 +2676,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2678 "Python/generated_cases.c.h" + #line 2680 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2682,7 +2684,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1859 "Python/bytecodes.c" + #line 1861 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2708,7 +2710,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2712 "Python/generated_cases.c.h" + #line 2714 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2716,7 +2718,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1887 "Python/bytecodes.c" + #line 1889 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2734,7 +2736,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2738 "Python/generated_cases.c.h" + #line 2740 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2745,7 +2747,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1907 "Python/bytecodes.c" + #line 1909 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2784,7 +2786,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2788 "Python/generated_cases.c.h" + #line 2790 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2795,7 +2797,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1948 "Python/bytecodes.c" + #line 1950 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2805,7 +2807,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2809 "Python/generated_cases.c.h" + #line 2811 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2817,7 +2819,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1967 "Python/bytecodes.c" + #line 1969 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2830,12 +2832,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2834 "Python/generated_cases.c.h" + #line 2836 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1980 "Python/bytecodes.c" + #line 1982 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2839 "Python/generated_cases.c.h" + #line 2841 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2846,7 +2848,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1984 "Python/bytecodes.c" + #line 1986 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2857,7 +2859,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2861 "Python/generated_cases.c.h" + #line 2863 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2868,7 +2870,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1998 "Python/bytecodes.c" + #line 2000 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2883,7 +2885,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2887 "Python/generated_cases.c.h" + #line 2889 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2894,7 +2896,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2016 "Python/bytecodes.c" + #line 2018 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2906,7 +2908,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2910 "Python/generated_cases.c.h" + #line 2912 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2917,14 +2919,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2030 "Python/bytecodes.c" + #line 2032 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2923 "Python/generated_cases.c.h" + #line 2925 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2032 "Python/bytecodes.c" + #line 2034 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2928 "Python/generated_cases.c.h" + #line 2930 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2934,15 +2936,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2036 "Python/bytecodes.c" + #line 2038 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2940 "Python/generated_cases.c.h" + #line 2942 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2038 "Python/bytecodes.c" + #line 2040 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2946 "Python/generated_cases.c.h" + #line 2948 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2953,12 +2955,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2043 "Python/bytecodes.c" + #line 2045 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2959 "Python/generated_cases.c.h" + #line 2961 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2045 "Python/bytecodes.c" + #line 2047 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2966,10 +2968,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2970 "Python/generated_cases.c.h" + #line 2972 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2053 "Python/bytecodes.c" + #line 2055 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2978,7 +2980,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2982 "Python/generated_cases.c.h" + #line 2984 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2988,21 +2990,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2064 "Python/bytecodes.c" + #line 2066 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2995 "Python/generated_cases.c.h" + #line 2997 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2067 "Python/bytecodes.c" + #line 2069 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3002 "Python/generated_cases.c.h" + #line 3004 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2072 "Python/bytecodes.c" + #line 2074 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3006 "Python/generated_cases.c.h" + #line 3008 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3011,15 +3013,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2076 "Python/bytecodes.c" + #line 2078 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3018 "Python/generated_cases.c.h" + #line 3020 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2079 "Python/bytecodes.c" + #line 2081 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3023 "Python/generated_cases.c.h" + #line 3025 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3028,29 +3030,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2083 "Python/bytecodes.c" + #line 2085 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3036 "Python/generated_cases.c.h" + #line 3038 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2089 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" JUMPBY(oparg); - #line 3045 "Python/generated_cases.c.h" + #line 3047 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2093 "Python/bytecodes.c" + #line 2095 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3054 "Python/generated_cases.c.h" + #line 3056 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3058,15 +3060,15 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2099 "Python/bytecodes.c" + #line 2101 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3068 "Python/generated_cases.c.h" + #line 3070 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2105 "Python/bytecodes.c" + #line 2107 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3074,22 +3076,22 @@ if (err < 0) goto pop_1_error; } } - #line 3078 "Python/generated_cases.c.h" + #line 3080 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2115 "Python/bytecodes.c" + #line 2117 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3091 "Python/generated_cases.c.h" + #line 3093 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2121 "Python/bytecodes.c" + #line 2123 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3097,63 +3099,63 @@ if (err < 0) goto pop_1_error; } } - #line 3101 "Python/generated_cases.c.h" + #line 3103 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2131 "Python/bytecodes.c" + #line 2133 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3110 "Python/generated_cases.c.h" + #line 3112 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2133 "Python/bytecodes.c" + #line 2135 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3115 "Python/generated_cases.c.h" + #line 3117 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2138 "Python/bytecodes.c" + #line 2140 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3127 "Python/generated_cases.c.h" + #line 3129 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2143 "Python/bytecodes.c" + #line 2145 "Python/bytecodes.c" } - #line 3131 "Python/generated_cases.c.h" + #line 3133 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2147 "Python/bytecodes.c" + #line 2149 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3144 "Python/generated_cases.c.h" + #line 3146 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2156 "Python/bytecodes.c" + #line 2158 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3157 "Python/generated_cases.c.h" + #line 3159 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3164,16 +3166,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2164 "Python/bytecodes.c" + #line 2166 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3173 "Python/generated_cases.c.h" + #line 3175 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2169 "Python/bytecodes.c" + #line 2171 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3181,7 +3183,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3185 "Python/generated_cases.c.h" + #line 3187 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3190,10 +3192,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2179 "Python/bytecodes.c" + #line 2181 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3197 "Python/generated_cases.c.h" + #line 3199 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3203,10 +3205,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2185 "Python/bytecodes.c" + #line 2187 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3210 "Python/generated_cases.c.h" + #line 3212 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3217,11 +3219,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2191 "Python/bytecodes.c" + #line 2193 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3225 "Python/generated_cases.c.h" + #line 3227 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3230,14 +3232,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2197 "Python/bytecodes.c" + #line 2199 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3237 "Python/generated_cases.c.h" + #line 3239 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2200 "Python/bytecodes.c" + #line 2202 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3241 "Python/generated_cases.c.h" + #line 3243 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3245,7 +3247,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2204 "Python/bytecodes.c" + #line 2206 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3268,11 +3270,11 @@ if (iter == NULL) { goto error; } - #line 3272 "Python/generated_cases.c.h" + #line 3274 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2227 "Python/bytecodes.c" + #line 2229 "Python/bytecodes.c" } - #line 3276 "Python/generated_cases.c.h" + #line 3278 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3283,7 +3285,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2246 "Python/bytecodes.c" + #line 2248 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3314,7 +3316,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3318 "Python/generated_cases.c.h" + #line 3320 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3322,7 +3324,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2279 "Python/bytecodes.c" + #line 2281 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3348,14 +3350,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3352 "Python/generated_cases.c.h" + #line 3354 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2307 "Python/bytecodes.c" + #line 2309 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3375,7 +3377,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3379 "Python/generated_cases.c.h" + #line 3381 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3385,7 +3387,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2329 "Python/bytecodes.c" + #line 2331 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3405,7 +3407,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3409 "Python/generated_cases.c.h" + #line 3411 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3415,7 +3417,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2351 "Python/bytecodes.c" + #line 2353 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3433,7 +3435,7 @@ if (next == NULL) { goto error; } - #line 3437 "Python/generated_cases.c.h" + #line 3439 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3442,7 +3444,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2371 "Python/bytecodes.c" + #line 2373 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3458,14 +3460,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3462 "Python/generated_cases.c.h" + #line 3464 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2389 "Python/bytecodes.c" + #line 2391 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3488,16 +3490,16 @@ Py_DECREF(enter); goto error; } - #line 3492 "Python/generated_cases.c.h" + #line 3494 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2412 "Python/bytecodes.c" + #line 2414 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3501 "Python/generated_cases.c.h" + #line 3503 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3509,7 +3511,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2422 "Python/bytecodes.c" + #line 2424 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3535,16 +3537,16 @@ Py_DECREF(enter); goto error; } - #line 3539 "Python/generated_cases.c.h" + #line 3541 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2448 "Python/bytecodes.c" + #line 2450 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3548 "Python/generated_cases.c.h" + #line 3550 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3556,7 +3558,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2457 "Python/bytecodes.c" + #line 2459 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3577,7 +3579,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3581 "Python/generated_cases.c.h" + #line 3583 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3586,7 +3588,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2480 "Python/bytecodes.c" + #line 2482 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3596,7 +3598,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3600 "Python/generated_cases.c.h" + #line 3602 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3610,7 +3612,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2492 "Python/bytecodes.c" + #line 2494 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3627,7 +3629,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3631 "Python/generated_cases.c.h" + #line 3633 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3641,7 +3643,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2511 "Python/bytecodes.c" + #line 2513 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3651,7 +3653,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3655 "Python/generated_cases.c.h" + #line 3657 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3665,7 +3667,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2523 "Python/bytecodes.c" + #line 2525 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3679,7 +3681,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3683 "Python/generated_cases.c.h" + #line 3685 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3688,16 +3690,16 @@ } TARGET(KW_NAMES) { - #line 2539 "Python/bytecodes.c" + #line 2541 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3696 "Python/generated_cases.c.h" + #line 3698 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2545 "Python/bytecodes.c" + #line 2547 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3710,7 +3712,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3714 "Python/generated_cases.c.h" + #line 3716 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3720,7 +3722,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2590 "Python/bytecodes.c" + #line 2592 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3802,7 +3804,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3806 "Python/generated_cases.c.h" + #line 3808 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3814,7 +3816,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2678 "Python/bytecodes.c" + #line 2680 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3824,7 +3826,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3828 "Python/generated_cases.c.h" + #line 3830 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3833,7 +3835,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2690 "Python/bytecodes.c" + #line 2692 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3859,7 +3861,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3863 "Python/generated_cases.c.h" + #line 3865 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3867,7 +3869,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2718 "Python/bytecodes.c" + #line 2720 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3903,7 +3905,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3907 "Python/generated_cases.c.h" + #line 3909 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3911,7 +3913,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2756 "Python/bytecodes.c" + #line 2758 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3921,7 +3923,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3925 "Python/generated_cases.c.h" + #line 3927 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3934,7 +3936,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2768 "Python/bytecodes.c" + #line 2770 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3945,7 +3947,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3949 "Python/generated_cases.c.h" + #line 3951 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3959,7 +3961,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2782 "Python/bytecodes.c" + #line 2784 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3970,7 +3972,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3974 "Python/generated_cases.c.h" + #line 3976 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3984,7 +3986,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2796 "Python/bytecodes.c" + #line 2798 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4006,7 +4008,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4010 "Python/generated_cases.c.h" + #line 4012 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4020,7 +4022,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2821 "Python/bytecodes.c" + #line 2823 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4048,7 +4050,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4052 "Python/generated_cases.c.h" + #line 4054 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4062,7 +4064,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2852 "Python/bytecodes.c" + #line 2854 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4094,7 +4096,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4098 "Python/generated_cases.c.h" + #line 4100 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4108,7 +4110,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2887 "Python/bytecodes.c" + #line 2889 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4140,7 +4142,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4144 "Python/generated_cases.c.h" + #line 4146 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4154,7 +4156,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2922 "Python/bytecodes.c" + #line 2924 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4179,7 +4181,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4183 "Python/generated_cases.c.h" + #line 4185 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4192,7 +4194,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2949 "Python/bytecodes.c" + #line 2951 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4219,7 +4221,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4223 "Python/generated_cases.c.h" + #line 4225 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4231,7 +4233,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2979 "Python/bytecodes.c" + #line 2981 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4249,14 +4251,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4253 "Python/generated_cases.c.h" + #line 4255 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2999 "Python/bytecodes.c" + #line 3001 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4287,7 +4289,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4291 "Python/generated_cases.c.h" + #line 4293 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4300,7 +4302,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3033 "Python/bytecodes.c" + #line 3035 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4329,7 +4331,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4333 "Python/generated_cases.c.h" + #line 4335 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4342,7 +4344,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3065 "Python/bytecodes.c" + #line 3067 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4371,7 +4373,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4375 "Python/generated_cases.c.h" + #line 4377 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4384,7 +4386,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3097 "Python/bytecodes.c" + #line 3099 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4412,7 +4414,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4416 "Python/generated_cases.c.h" + #line 4418 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4422,9 +4424,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3128 "Python/bytecodes.c" + #line 3130 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4428 "Python/generated_cases.c.h" + #line 4430 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4433,7 +4435,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3132 "Python/bytecodes.c" + #line 3134 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4495,14 +4497,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4499 "Python/generated_cases.c.h" + #line 4501 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3194 "Python/bytecodes.c" + #line 3196 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4506 "Python/generated_cases.c.h" + #line 4508 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4517,7 +4519,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3204 "Python/bytecodes.c" + #line 3206 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4546,14 +4548,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4550 "Python/generated_cases.c.h" + #line 4552 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3235 "Python/bytecodes.c" + #line 3237 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4574,7 +4576,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4578 "Python/generated_cases.c.h" + #line 4580 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4582,15 +4584,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3258 "Python/bytecodes.c" + #line 3260 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4588 "Python/generated_cases.c.h" + #line 4590 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3260 "Python/bytecodes.c" + #line 3262 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4594 "Python/generated_cases.c.h" + #line 4596 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4601,7 +4603,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3264 "Python/bytecodes.c" + #line 3266 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4636,7 +4638,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4640 "Python/generated_cases.c.h" + #line 4642 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4645,10 +4647,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3301 "Python/bytecodes.c" + #line 3303 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4652 "Python/generated_cases.c.h" + #line 4654 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4660,7 +4662,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3306 "Python/bytecodes.c" + #line 3308 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4675,12 +4677,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4679 "Python/generated_cases.c.h" + #line 4681 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3321 "Python/bytecodes.c" + #line 3323 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4684 "Python/generated_cases.c.h" + #line 4686 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4690,16 +4692,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3326 "Python/bytecodes.c" + #line 3328 "Python/bytecodes.c" assert(oparg >= 2); - #line 4696 "Python/generated_cases.c.h" + #line 4698 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3330 "Python/bytecodes.c" + #line 3332 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4711,26 +4713,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4715 "Python/generated_cases.c.h" + #line 4717 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3344 "Python/bytecodes.c" + #line 3346 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4721 "Python/generated_cases.c.h" + #line 4723 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3348 "Python/bytecodes.c" + #line 3350 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4728 "Python/generated_cases.c.h" + #line 4730 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3353 "Python/bytecodes.c" + #line 3355 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4739,12 +4741,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4743 "Python/generated_cases.c.h" + #line 4745 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3364 "Python/bytecodes.c" + #line 3366 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4753,12 +4755,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4757 "Python/generated_cases.c.h" + #line 4759 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3375 "Python/bytecodes.c" + #line 3377 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4770,12 +4772,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4774 "Python/generated_cases.c.h" + #line 4776 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3389 "Python/bytecodes.c" + #line 3391 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4787,30 +4789,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4791 "Python/generated_cases.c.h" + #line 4793 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3403 "Python/bytecodes.c" + #line 3405 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4802 "Python/generated_cases.c.h" + #line 4804 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3411 "Python/bytecodes.c" + #line 3413 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4809 "Python/generated_cases.c.h" + #line 4811 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3416 "Python/bytecodes.c" + #line 3418 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4816 "Python/generated_cases.c.h" + #line 4818 "Python/generated_cases.c.h" } From af7b55d37f10594c3aa9815e7b6f0fd8e5ca020f Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 30 May 2023 23:54:31 +0200 Subject: [PATCH 0087/1206] [3.12] gh-89886: Properly quote Autoconf macro arguments (#105062) (#105118) Autoconf 2.70 macros are picky about argument quotation. --- configure | 34 +- configure.ac | 1470 +++++++++++++++++++++++++++----------------------- 2 files changed, 798 insertions(+), 706 deletions(-) diff --git a/configure b/configure index 21a3af145c1369..ed80d95ecba022 100755 --- a/configure +++ b/configure @@ -1847,8 +1847,8 @@ Optional Packages: select hash algorithm for use in Python/pyhash.c (default is SipHash13) --with-tzpath= - Select the default time zone search path for zoneinfo.TZPATH - + Select the default time zone search path for + zoneinfo.TZPATH --with-libs='lib1 ...' link against additional libs (default is no) --with-system-expat build pyexpat module using an installed expat library, see Doc/library/pyexpat.rst (default is no) @@ -7392,6 +7392,7 @@ if test "${with_trace_refs+set}" = set; then : withval=$with_trace_refs; else with_trace_refs=no + fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_trace_refs" >&5 @@ -11193,7 +11194,7 @@ case $ac_sys_system/$ac_sys_release in $as_echo "#define WITH_DYLD 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: always on for Darwin" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: always on for Darwin" >&5 $as_echo "always on for Darwin" >&6; } ;; *) @@ -11750,7 +11751,7 @@ _ACEOF LIBS="-ldl $LIBS" fi - # Dynamic linking for SunOS/Solaris and SYSV + # Dynamic linking for SunOS/Solaris and SYSV { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : @@ -11795,7 +11796,7 @@ _ACEOF LIBS="-ldld $LIBS" fi - # Dynamic linking for HP-UX + # Dynamic linking for HP-UX @@ -11810,8 +11811,7 @@ if test "x$ac_cv_header_uuid_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UUID_H 1 _ACEOF - - for ac_func in uuid_create uuid_enc_be + for ac_func in uuid_create uuid_enc_be do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -11819,8 +11819,7 @@ if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF - - have_uuid=yes + have_uuid=yes LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} LIBUUID_LIBS=${LIBUUID_LIBS-""} @@ -11995,12 +11994,10 @@ if test "x$ac_cv_lib_uuid_uuid_generate_time_safe" = xyes; then : have_uuid=yes $as_echo "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h - fi LIBS=$py_check_lib_save_LIBS - fi done @@ -12124,12 +12121,10 @@ if test "x$ac_cv_lib_uuid_uuid_generate_time_safe" = xyes; then : have_uuid=yes $as_echo "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h - fi LIBS=$py_check_lib_save_LIBS - fi done @@ -12154,8 +12149,7 @@ else LIBUUID_LIBS=$pkg_cv_LIBUUID_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - - have_uuid=yes + have_uuid=yes $as_echo "#define HAVE_UUID_H 1" >>confdefs.h $as_echo "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h @@ -15900,6 +15894,7 @@ if test "${with_valgrind+set}" = set; then : withval=$with_valgrind; else with_valgrind=no + fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_valgrind" >&5 @@ -16151,7 +16146,7 @@ done fi ac_fn_c_check_decl "$LINENO" "dirfd" "ac_cv_have_decl_dirfd" "#include - #include + #include " if test "x$ac_cv_have_decl_dirfd" = xyes; then : @@ -18794,10 +18789,8 @@ if test "x$ac_cv_lib_bsd_openpty" = xyes; then : LIBS="$LIBS -lbsd" fi - fi - fi done @@ -18950,10 +18943,8 @@ if test "x$ac_cv_lib_bsd_forkpty" = xyes; then : LIBS="$LIBS -lbsd" fi - fi - fi done @@ -19010,7 +19001,6 @@ $as_echo "#define GETPGRP_HAVE_ARG 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi done @@ -19038,7 +19028,6 @@ $as_echo "#define SETPGRP_HAVE_ARG 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi done @@ -20458,7 +20447,6 @@ fi ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" if test "x$ac_cv_func_gethostbyname_r" = xyes; then : - $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 6 args" >&5 diff --git a/configure.ac b/configure.ac index c5a79af1a2e2eb..2d3f5191fbf3c3 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ dnl Python's configure.ac file requires autoconf 2.69 and autoconf-archive. dnl # Set VERSION so we only need to edit in one place (i.e., here) -m4_define(PYTHON_VERSION, 3.12) +m4_define([PYTHON_VERSION], [3.12]) AC_PREREQ([2.69]) @@ -73,7 +73,7 @@ dnl PY_CHECK_LIB(LIBRARY, FUNCTION, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], [O dnl Like AC_CHECK_LIB() but does not modify LIBS AC_DEFUN([PY_CHECK_LIB], [AS_VAR_COPY([py_check_lib_save_LIBS], [LIBS])] -[AC_CHECK_LIB($1, $2, $3, $4, $5)] +[AC_CHECK_LIB([$1], [$2], [$3], [$4], [$5])] [AS_VAR_COPY([LIBS], [py_check_lib_save_LIBS])] ) @@ -91,7 +91,7 @@ AC_DEFUN([PY_CHECK_EMSCRIPTEN_PORT], [ AS_VAR_POPDEF([py_libs]) ]) -AC_SUBST(BASECPPFLAGS) +AC_SUBST([BASECPPFLAGS]) if test "$srcdir" != . -a "$srcdir" != "$(pwd)"; then # If we're building out-of-tree, we need to make sure the following # resources get picked up before their $srcdir counterparts. @@ -106,13 +106,13 @@ else BASECPPFLAGS="" fi -AC_SUBST(GITVERSION) -AC_SUBST(GITTAG) -AC_SUBST(GITBRANCH) +AC_SUBST([GITVERSION]) +AC_SUBST([GITTAG]) +AC_SUBST([GITBRANCH]) if test -e $srcdir/.git then -AC_CHECK_PROG(HAS_GIT, git, found, not-found) +AC_CHECK_PROG([HAS_GIT], [git], [found], [not-found]) else HAS_GIT=no-repository fi @@ -131,8 +131,8 @@ AC_CONFIG_SRCDIR([Include/object.h]) AC_CONFIG_HEADERS([pyconfig.h]) AC_CANONICAL_HOST -AC_SUBST(build) -AC_SUBST(host) +AC_SUBST([build]) +AC_SUBST([host]) AS_VAR_IF([cross_compiling], [maybe], [AC_MSG_ERROR([Cross compiling required --host=HOST-TUPLE and --build=ARCH])] @@ -141,8 +141,7 @@ AS_VAR_IF([cross_compiling], [maybe], # pybuilddir.txt will be created by --generate-posix-vars in the Makefile rm -f pybuilddir.txt -AC_ARG_WITH( - [build-python], +AC_ARG_WITH([build-python], [AS_HELP_STRING([--with-build-python=python]PYTHON_VERSION, [path to build python binary for cross compiling (default: _bootstrap_python or python]PYTHON_VERSION[)])], [ @@ -204,7 +203,7 @@ AC_SUBST([PYTHON_FOR_BUILD_DEPS]) AC_CHECK_PROGS([PYTHON_FOR_REGEN], [python$PACKAGE_VERSION python3.12 python3.11 python3.10 python3 python], [python3]) -AC_SUBST(PYTHON_FOR_REGEN) +AC_SUBST([PYTHON_FOR_REGEN]) AC_MSG_CHECKING([Python for regen version]) if command -v "$PYTHON_FOR_REGEN" >/dev/null 2>&1; then @@ -243,38 +242,40 @@ grep -v 'define PACKAGE_' confdefs.h.new rm confdefs.h mv confdefs.h.new confdefs.h -AC_SUBST(VERSION) +AC_SUBST([VERSION]) VERSION=PYTHON_VERSION # Version number of Python's own shared library file. -AC_SUBST(SOVERSION) +AC_SUBST([SOVERSION]) SOVERSION=1.0 # The later definition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables # certain features on NetBSD, so we need _NETBSD_SOURCE to re-enable # them. -AC_DEFINE(_NETBSD_SOURCE, 1, [Define on NetBSD to activate all library features]) +AC_DEFINE([_NETBSD_SOURCE], [1], + [Define on NetBSD to activate all library features]) # The later definition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables # certain features on FreeBSD, so we need __BSD_VISIBLE to re-enable # them. -AC_DEFINE(__BSD_VISIBLE, 1, [Define on FreeBSD to activate all library features]) +AC_DEFINE([__BSD_VISIBLE], [1], + [Define on FreeBSD to activate all library features]) # The later definition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables # certain features on Mac OS X, so we need _DARWIN_C_SOURCE to re-enable # them. -AC_DEFINE(_DARWIN_C_SOURCE, 1, [Define on Darwin to activate all library features]) +AC_DEFINE([_DARWIN_C_SOURCE], [1], + [Define on Darwin to activate all library features]) define_xopen_source=yes # Arguments passed to configure. -AC_SUBST(CONFIG_ARGS) +AC_SUBST([CONFIG_ARGS]) CONFIG_ARGS="$ac_configure_args" dnl Allow users to disable pkg-config or require pkg-config -AC_ARG_WITH( - [pkg-config], +AC_ARG_WITH([pkg-config], [AS_HELP_STRING([[--with-pkg-config=[yes|no|check]]], [use pkg-config to detect build options (default is check)])], [], @@ -303,7 +304,7 @@ if test "$with_pkg_config" = yes -a -z "$PKG_CONFIG"; then fi AC_MSG_CHECKING([for --enable-universalsdk]) -AC_ARG_ENABLE(universalsdk, +AC_ARG_ENABLE([universalsdk], AS_HELP_STRING([--enable-universalsdk@<:@=SDKDIR@:>@], [create a universal binary build. SDKDIR specifies which macOS SDK should be used to perform the build, @@ -344,13 +345,13 @@ AC_ARG_ENABLE(universalsdk, ]) if test -n "${UNIVERSALSDK}" then - AC_MSG_RESULT(${UNIVERSALSDK}) + AC_MSG_RESULT([${UNIVERSALSDK}]) else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi -AC_SUBST(UNIVERSALSDK) +AC_SUBST([UNIVERSALSDK]) -AC_SUBST(ARCH_RUN_32BIT) +AC_SUBST([ARCH_RUN_32BIT]) ARCH_RUN_32BIT="" # For backward compatibility reasons we prefer to select '32-bit' if available, @@ -367,10 +368,10 @@ then fi fi -AC_SUBST(LIPO_32BIT_FLAGS) -AC_SUBST(LIPO_INTEL64_FLAGS) -AC_MSG_CHECKING(for --with-universal-archs) -AC_ARG_WITH(universal-archs, +AC_SUBST([LIPO_32BIT_FLAGS]) +AC_SUBST([LIPO_INTEL64_FLAGS]) +AC_MSG_CHECKING([for --with-universal-archs]) +AC_ARG_WITH([universal-archs], AS_HELP_STRING([--with-universal-archs=ARCH], [specify the kind of macOS universal binary that should be created. This option is only valid when --enable-universalsdk is set; options are: @@ -383,12 +384,12 @@ AC_ARG_WITH(universal-archs, []) if test -n "${UNIVERSALSDK}" then - AC_MSG_RESULT(${UNIVERSAL_ARCHS}) + AC_MSG_RESULT([${UNIVERSAL_ARCHS}]) else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi -AC_ARG_WITH(framework-name, +AC_ARG_WITH([framework-name], AS_HELP_STRING([--with-framework-name=FRAMEWORK], [specify the name for the python framework on macOS only valid when --enable-framework is set. see Mac/README.rst @@ -403,7 +404,7 @@ AC_ARG_WITH(framework-name, PYTHONFRAMEWORKIDENTIFIER=org.python.python ]) dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output -AC_ARG_ENABLE(framework, +AC_ARG_ENABLE([framework], AS_HELP_STRING([--enable-framework@<:@=INSTALLDIR@:>@], [create a Python.framework rather than a traditional Unix install. optional INSTALLDIR specifies the installation path. see Mac/README.rst @@ -486,10 +487,10 @@ AC_ARG_ENABLE(framework, # Add files for Mac specific code to the list of output # files: - AC_CONFIG_FILES(Mac/Makefile) - AC_CONFIG_FILES(Mac/PythonLauncher/Makefile) - AC_CONFIG_FILES(Mac/Resources/framework/Info.plist) - AC_CONFIG_FILES(Mac/Resources/app/Info.plist) + AC_CONFIG_FILES([Mac/Makefile]) + AC_CONFIG_FILES([Mac/PythonLauncher/Makefile]) + AC_CONFIG_FILES([Mac/Resources/framework/Info.plist]) + AC_CONFIG_FILES([Mac/Resources/app/Info.plist]) esac ],[ PYTHONFRAMEWORK= @@ -509,24 +510,25 @@ AC_ARG_ENABLE(framework, enable_framework= ]) -AC_SUBST(PYTHONFRAMEWORK) -AC_SUBST(PYTHONFRAMEWORKIDENTIFIER) -AC_SUBST(PYTHONFRAMEWORKDIR) -AC_SUBST(PYTHONFRAMEWORKPREFIX) -AC_SUBST(PYTHONFRAMEWORKINSTALLDIR) -AC_SUBST(FRAMEWORKINSTALLFIRST) -AC_SUBST(FRAMEWORKINSTALLLAST) -AC_SUBST(FRAMEWORKALTINSTALLFIRST) -AC_SUBST(FRAMEWORKALTINSTALLLAST) -AC_SUBST(FRAMEWORKPYTHONW) -AC_SUBST(FRAMEWORKUNIXTOOLSPREFIX) -AC_SUBST(FRAMEWORKINSTALLAPPSPREFIX) +AC_SUBST([PYTHONFRAMEWORK]) +AC_SUBST([PYTHONFRAMEWORKIDENTIFIER]) +AC_SUBST([PYTHONFRAMEWORKDIR]) +AC_SUBST([PYTHONFRAMEWORKPREFIX]) +AC_SUBST([PYTHONFRAMEWORKINSTALLDIR]) +AC_SUBST([FRAMEWORKINSTALLFIRST]) +AC_SUBST([FRAMEWORKINSTALLLAST]) +AC_SUBST([FRAMEWORKALTINSTALLFIRST]) +AC_SUBST([FRAMEWORKALTINSTALLLAST]) +AC_SUBST([FRAMEWORKPYTHONW]) +AC_SUBST([FRAMEWORKUNIXTOOLSPREFIX]) +AC_SUBST([FRAMEWORKINSTALLAPPSPREFIX]) -AC_DEFINE_UNQUOTED(_PYTHONFRAMEWORK, "${PYTHONFRAMEWORK}", [framework name]) +AC_DEFINE_UNQUOTED([_PYTHONFRAMEWORK], ["${PYTHONFRAMEWORK}"], + [framework name]) # Set name for machine-dependent library files AC_ARG_VAR([MACHDEP], [name for machine-dependent library files]) -AC_MSG_CHECKING(MACHDEP) +AC_MSG_CHECKING([MACHDEP]) if test -z "$MACHDEP" then # avoid using uname for cross builds @@ -582,9 +584,9 @@ then '') MACHDEP="unknown";; esac fi -AC_MSG_RESULT("$MACHDEP") +AC_MSG_RESULT(["$MACHDEP"]) -AC_SUBST(_PYTHON_HOST_PLATFORM) +AC_SUBST([_PYTHON_HOST_PLATFORM]) if test "$cross_compiling" = yes; then case "$host" in *-*-linux*) @@ -634,13 +636,15 @@ case $ac_sys_system/$ac_sys_release in # OpenBSD undoes our definition of __BSD_VISIBLE if _XOPEN_SOURCE is # also defined. This can be overridden by defining _BSD_SOURCE # As this has a different meaning on Linux, only define it on OpenBSD - AC_DEFINE(_BSD_SOURCE, 1, [Define on OpenBSD to activate all library features]) + AC_DEFINE([_BSD_SOURCE], [1], + [Define on OpenBSD to activate all library features]) ;; OpenBSD/*) # OpenBSD undoes our definition of __BSD_VISIBLE if _XOPEN_SOURCE is # also defined. This can be overridden by defining _BSD_SOURCE # As this has a different meaning on Linux, only define it on OpenBSD - AC_DEFINE(_BSD_SOURCE, 1, [Define on OpenBSD to activate all library features]) + AC_DEFINE([_BSD_SOURCE], [1], + [Define on OpenBSD to activate all library features]) ;; # Defining _XOPEN_SOURCE on NetBSD version prior to the introduction of # _NETBSD_SOURCE disables certain features (eg. setgroups). Reported by @@ -696,17 +700,18 @@ esac if test $define_xopen_source = yes then # X/Open 7, incorporating POSIX.1-2008 - AC_DEFINE(_XOPEN_SOURCE, 700, - Define to the level of X/Open that your system supports) + AC_DEFINE([_XOPEN_SOURCE], [700], + [Define to the level of X/Open that your system supports]) # On Tru64 Unix 4.0F, defining _XOPEN_SOURCE also requires # definition of _XOPEN_SOURCE_EXTENDED and _POSIX_C_SOURCE, or else # several APIs are not declared. Since this is also needed in some # cases for HP-UX, we define it globally. - AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, - Define to activate Unix95-and-earlier features) + AC_DEFINE([_XOPEN_SOURCE_EXTENDED], [1], + [Define to activate Unix95-and-earlier features]) - AC_DEFINE(_POSIX_C_SOURCE, 200809L, Define to activate features from IEEE Stds 1003.1-2008) + AC_DEFINE([_POSIX_C_SOURCE], [200809L], + [Define to activate features from IEEE Stds 1003.1-2008]) fi # On HP-UX mbstate_t requires _INCLUDE__STDC_A1_SOURCE @@ -719,14 +724,15 @@ esac if test $define_stdc_a1 = yes then - AC_DEFINE(_INCLUDE__STDC_A1_SOURCE, 1, Define to include mbstate_t for mbrtowc) + AC_DEFINE([_INCLUDE__STDC_A1_SOURCE], [1], + [Define to include mbstate_t for mbrtowc]) fi # Record the configure-time value of MACOSX_DEPLOYMENT_TARGET, # it may influence the way we can build extensions, so distutils # needs to check it -AC_SUBST(CONFIGURE_MACOSX_DEPLOYMENT_TARGET) -AC_SUBST(EXPORT_MACOSX_DEPLOYMENT_TARGET) +AC_SUBST([CONFIGURE_MACOSX_DEPLOYMENT_TARGET]) +AC_SUBST([EXPORT_MACOSX_DEPLOYMENT_TARGET]) CONFIGURE_MACOSX_DEPLOYMENT_TARGET= EXPORT_MACOSX_DEPLOYMENT_TARGET='#' @@ -873,16 +879,16 @@ rm -f conftest.c conftest.out # _POSIX_SOURCE, _POSIX_1_SOURCE, and more AC_USE_SYSTEM_EXTENSIONS -AC_SUBST(CXX) +AC_SUBST([CXX]) preset_cxx="$CXX" if test -z "$CXX" then case "$CC" in - gcc) AC_PATH_TOOL(CXX, [g++], [g++], [notfound]) ;; - cc) AC_PATH_TOOL(CXX, [c++], [c++], [notfound]) ;; - clang|*/clang) AC_PATH_TOOL(CXX, [clang++], [clang++], [notfound]) ;; - icc|*/icc) AC_PATH_TOOL(CXX, [icpc], [icpc], [notfound]) ;; + gcc) AC_PATH_TOOL([CXX], [g++], [g++], [notfound]) ;; + cc) AC_PATH_TOOL([CXX], [c++], [c++], [notfound]) ;; + clang|*/clang) AC_PATH_TOOL([CXX], [clang++], [clang++], [notfound]) ;; + icc|*/icc) AC_PATH_TOOL([CXX], [icpc], [icpc], [notfound]) ;; esac if test "$CXX" = "notfound" then @@ -891,7 +897,7 @@ then fi if test -z "$CXX" then - AC_CHECK_TOOLS(CXX, $CCC c++ g++ gcc CC cxx cc++ cl, notfound) + AC_CHECK_TOOLS([CXX], [$CCC c++ g++ gcc CC cxx cc++ cl], [notfound]) if test "$CXX" = "notfound" then CXX="" @@ -1113,12 +1119,12 @@ if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then elif test x$PLATFORM_TRIPLET != x && test x$MULTIARCH = x; then MULTIARCH=$PLATFORM_TRIPLET fi -AC_SUBST(PLATFORM_TRIPLET) +AC_SUBST([PLATFORM_TRIPLET]) if test x$MULTIARCH != x; then MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" fi -AC_SUBST(MULTIARCH_CPPFLAGS) +AC_SUBST([MULTIARCH_CPPFLAGS]) dnl Support tiers according to https://peps.python.org/pep-0011/ dnl @@ -1166,7 +1172,7 @@ AC_CACHE_CHECK([for -Wl,--no-as-needed], [ac_cv_wl_no_as_needed], [ ac_cv_wl_no_as_needed=no]) LDFLAGS="$save_LDFLAGS" ]) -AC_SUBST(NO_AS_NEEDED) +AC_SUBST([NO_AS_NEEDED]) AC_MSG_CHECKING([for the Android API level]) cat > conftest.c <conftest.out 2>/dev/null; then if test -z "$ANDROID_API_LEVEL"; then AC_MSG_ERROR([Fatal: you must define __ANDROID_API__]) fi - AC_DEFINE_UNQUOTED(ANDROID_API_LEVEL, $ANDROID_API_LEVEL, [The Android API level.]) + AC_DEFINE_UNQUOTED([ANDROID_API_LEVEL], [$ANDROID_API_LEVEL], + [The Android API level.]) AC_MSG_CHECKING([for the Android arm ABI]) AC_MSG_RESULT([$_arm_arch]) @@ -1287,18 +1294,18 @@ AC_MSG_RESULT([$EXEEXT]) # Test whether we're running on a non-case-sensitive system, in which # case we give a warning if no ext is given -AC_SUBST(BUILDEXEEXT) -AC_MSG_CHECKING(for case-insensitive build directory) +AC_SUBST([BUILDEXEEXT]) +AC_MSG_CHECKING([for case-insensitive build directory]) if test ! -d CaseSensitiveTestDir; then mkdir CaseSensitiveTestDir fi if test -d casesensitivetestdir && test -z "$EXEEXT" then - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) BUILDEXEEXT=.exe else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) BUILDEXEEXT=$EXEEXT fi rmdir CaseSensitiveTestDir @@ -1310,13 +1317,13 @@ hp*|HP*) esac;; esac -AC_SUBST(LIBRARY) -AC_MSG_CHECKING(LIBRARY) +AC_SUBST([LIBRARY]) +AC_MSG_CHECKING([LIBRARY]) if test -z "$LIBRARY" then LIBRARY='libpython$(VERSION)$(ABIFLAGS).a' fi -AC_MSG_RESULT($LIBRARY) +AC_MSG_RESULT([$LIBRARY]) # LDLIBRARY is the name of the library to link against (as opposed to the # name of the library into which to insert object files). BLDLIBRARY is also @@ -1334,14 +1341,14 @@ AC_MSG_RESULT($LIBRARY) # # LDVERSION is the shared library version number, normally the Python version # with the ABI build flags appended. -AC_SUBST(LDLIBRARY) -AC_SUBST(DLLLIBRARY) -AC_SUBST(BLDLIBRARY) -AC_SUBST(PY3LIBRARY) -AC_SUBST(LDLIBRARYDIR) -AC_SUBST(INSTSONAME) -AC_SUBST(RUNSHARED) -AC_SUBST(LDVERSION) +AC_SUBST([LDLIBRARY]) +AC_SUBST([DLLLIBRARY]) +AC_SUBST([BLDLIBRARY]) +AC_SUBST([PY3LIBRARY]) +AC_SUBST([LDLIBRARYDIR]) +AC_SUBST([INSTSONAME]) +AC_SUBST([RUNSHARED]) +AC_SUBST([LDVERSION]) LDLIBRARY="$LIBRARY" BLDLIBRARY='$(LDLIBRARY)' INSTSONAME='$(LDLIBRARY)' @@ -1354,8 +1361,8 @@ LDVERSION="$VERSION" # If CXX is set, and if it is needed to link a main function that was # compiled with CXX, LINKCC is CXX instead. Always using CXX is undesirable: # python might then depend on the C++ runtime -AC_SUBST(LINKCC) -AC_MSG_CHECKING(LINKCC) +AC_SUBST([LINKCC]) +AC_MSG_CHECKING([LINKCC]) if test -z "$LINKCC" then LINKCC='$(PURIFY) $(CC)' @@ -1366,30 +1373,30 @@ then LINKCC=qcc;; esac fi -AC_MSG_RESULT($LINKCC) +AC_MSG_RESULT([$LINKCC]) # EXPORTSYMS holds the list of exported symbols for AIX. # EXPORTSFROM holds the module name exporting symbols on AIX. EXPORTSYMS= EXPORTSFROM= -AC_SUBST(EXPORTSYMS) -AC_SUBST(EXPORTSFROM) -AC_MSG_CHECKING(EXPORTSYMS) +AC_SUBST([EXPORTSYMS]) +AC_SUBST([EXPORTSFROM]) +AC_MSG_CHECKING([EXPORTSYMS]) case $ac_sys_system in AIX*) EXPORTSYMS="Modules/python.exp" EXPORTSFROM=. # the main executable ;; esac -AC_MSG_RESULT($EXPORTSYMS) +AC_MSG_RESULT([$EXPORTSYMS]) # GNULD is set to "yes" if the GNU linker is used. If this goes wrong # make sure we default having it set to "no": this is used by # distutils.unixccompiler to know if it should add --enable-new-dtags # to linker command lines, and failing to detect GNU ld simply results # in the same behaviour as before. -AC_SUBST(GNULD) -AC_MSG_CHECKING(for GNU ld) +AC_SUBST([GNULD]) +AC_MSG_CHECKING([for GNU ld]) ac_prog=ld if test "$GCC" = yes; then ac_prog=`$CC -print-prog-name=ld` @@ -1400,10 +1407,10 @@ case `"$ac_prog" -V 2>&1 < /dev/null` in *) GNULD=no;; esac -AC_MSG_RESULT($GNULD) +AC_MSG_RESULT([$GNULD]) -AC_MSG_CHECKING(for --enable-shared) -AC_ARG_ENABLE(shared, +AC_MSG_CHECKING([for --enable-shared]) +AC_ARG_ENABLE([shared], AS_HELP_STRING([--enable-shared], [enable building a shared Python library (default is no)])) if test -z "$enable_shared" @@ -1415,27 +1422,27 @@ then enable_shared="no";; esac fi -AC_MSG_RESULT($enable_shared) +AC_MSG_RESULT([$enable_shared]) # --with-static-libpython STATIC_LIBPYTHON=1 -AC_MSG_CHECKING(for --with-static-libpython) -AC_ARG_WITH(static-libpython, +AC_MSG_CHECKING([for --with-static-libpython]) +AC_ARG_WITH([static-libpython], AS_HELP_STRING([--without-static-libpython], [do not build libpythonMAJOR.MINOR.a and do not install python.o (default is yes)]), [ if test "$withval" = no then - AC_MSG_RESULT(no); + AC_MSG_RESULT([no]); STATIC_LIBPYTHON=0 else - AC_MSG_RESULT(yes); + AC_MSG_RESULT([yes]); fi], -[AC_MSG_RESULT(yes)]) -AC_SUBST(STATIC_LIBPYTHON) +[AC_MSG_RESULT([yes])]) +AC_SUBST([STATIC_LIBPYTHON]) -AC_MSG_CHECKING(for --enable-profiling) -AC_ARG_ENABLE(profiling, +AC_MSG_CHECKING([for --enable-profiling]) +AC_ARG_ENABLE([profiling], AS_HELP_STRING([--enable-profiling], [enable C-level code profiling with gprof (default is no)])) if test "x$enable_profiling" = xyes; then ac_save_cc="$CC" @@ -1447,14 +1454,14 @@ if test "x$enable_profiling" = xyes; then else enable_profiling=no fi -AC_MSG_RESULT($enable_profiling) +AC_MSG_RESULT([$enable_profiling]) if test "x$enable_profiling" = xyes; then BASECFLAGS="-pg $BASECFLAGS" LDFLAGS="-pg $LDFLAGS" fi -AC_MSG_CHECKING(LDLIBRARY) +AC_MSG_CHECKING([LDLIBRARY]) # MacOSX framework builds need more magic. LDLIBRARY is the dynamic # library that we build, but we do not want to link against it (we @@ -1474,7 +1481,8 @@ fi # Other platforms follow if test $enable_shared = "yes"; then PY_ENABLE_SHARED=1 - AC_DEFINE(Py_ENABLE_SHARED, 1, [Defined if Python is built as a shared library.]) + AC_DEFINE([Py_ENABLE_SHARED], [1], + [Defined if Python is built as a shared library.]) case $ac_sys_system in CYGWIN*) LDLIBRARY='libpython$(LDVERSION).dll.a' @@ -1590,7 +1598,7 @@ if test -n "$HOSTRUNNER"; then PYTHON_FOR_BUILD="_PYTHON_HOSTRUNNER='$HOSTRUNNER' $PYTHON_FOR_BUILD" fi -AC_MSG_RESULT($LDLIBRARY) +AC_MSG_RESULT([$LDLIBRARY]) # LIBRARY_DEPS, LINK_PYTHON_OBJS and LINK_PYTHON_DEPS variable AS_CASE([$ac_sys_system/$ac_sys_emscripten_target], @@ -1615,16 +1623,16 @@ else # Link Python program to object files LINK_PYTHON_OBJS='$(LIBRARY_OBJS)' fi -AC_SUBST(LIBRARY_DEPS) -AC_SUBST(LINK_PYTHON_DEPS) -AC_SUBST(LINK_PYTHON_OBJS) +AC_SUBST([LIBRARY_DEPS]) +AC_SUBST([LINK_PYTHON_DEPS]) +AC_SUBST([LINK_PYTHON_OBJS]) # ar program -AC_SUBST(AR) -AC_CHECK_TOOLS(AR, ar aal, ar) +AC_SUBST([AR]) +AC_CHECK_TOOLS([AR], [ar aal], [ar]) # tweak ARFLAGS only if the user didn't set it on the command line -AC_SUBST(ARFLAGS) +AC_SUBST([ARFLAGS]) if test -z "$ARFLAGS" then ARFLAGS="rcs" @@ -1642,7 +1650,7 @@ AC_PROG_INSTALL AC_PROG_MKDIR_P # Not every filesystem supports hard links -AC_SUBST(LN) +AC_SUBST([LN]) if test -z "$LN" ; then case $ac_sys_system in CYGWIN*) LN="ln -s";; @@ -1651,38 +1659,38 @@ if test -z "$LN" ; then fi # For calculating the .so ABI tag. -AC_SUBST(ABIFLAGS) +AC_SUBST([ABIFLAGS]) ABIFLAGS="" # Check for --with-pydebug -AC_MSG_CHECKING(for --with-pydebug) -AC_ARG_WITH(pydebug, - AS_HELP_STRING([--with-pydebug], [build with Py_DEBUG defined (default is no)]), +AC_MSG_CHECKING([for --with-pydebug]) +AC_ARG_WITH([pydebug], + [AS_HELP_STRING([--with-pydebug], [build with Py_DEBUG defined (default is no)]) ], [ if test "$withval" != no then - AC_DEFINE(Py_DEBUG, 1, + AC_DEFINE([Py_DEBUG], [1], [Define if you want to build an interpreter with many run-time checks.]) - AC_MSG_RESULT(yes); + AC_MSG_RESULT([yes]); Py_DEBUG='true' ABIFLAGS="${ABIFLAGS}d" -else AC_MSG_RESULT(no); Py_DEBUG='false' +else AC_MSG_RESULT([no]); Py_DEBUG='false' fi], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) # Check for --with-trace-refs # --with-trace-refs -AC_MSG_CHECKING(for --with-trace-refs) -AC_ARG_WITH(trace-refs, - AS_HELP_STRING( - [--with-trace-refs], - [enable tracing references for debugging purpose (default is no)]),, - with_trace_refs=no) -AC_MSG_RESULT($with_trace_refs) +AC_MSG_CHECKING([for --with-trace-refs]) +AC_ARG_WITH([trace-refs], + [AS_HELP_STRING([--with-trace-refs], [enable tracing references for debugging purpose (default is no)])], + [], [with_trace_refs=no] +) +AC_MSG_RESULT([$with_trace_refs]) if test "$with_trace_refs" = "yes" then - AC_DEFINE(Py_TRACE_REFS, 1, [Define if you want to enable tracing references for debugging purpose]) + AC_DEFINE([Py_TRACE_REFS], [1], + [Define if you want to enable tracing references for debugging purpose]) fi @@ -1691,8 +1699,9 @@ AC_MSG_CHECKING([for --enable-pystats]) AC_ARG_ENABLE([pystats], [AS_HELP_STRING( [--enable-pystats], - [enable internal statistics gathering (default is no)])],, - [enable_pystats=no] + [enable internal statistics gathering (default is no)] + )], + [], [enable_pystats=no] ) AC_MSG_RESULT([$enable_pystats]) @@ -1703,8 +1712,8 @@ AS_VAR_IF([enable_pystats], [yes], [ # Check for --with-assertions. # This allows enabling assertions without Py_DEBUG. assertions='false' -AC_MSG_CHECKING(for --with-assertions) -AC_ARG_WITH(assertions, +AC_MSG_CHECKING([for --with-assertions]) +AC_ARG_WITH([assertions], AS_HELP_STRING([--with-assertions],[build with C assertions enabled (default is no)]), [ if test "$withval" != no @@ -1713,32 +1722,32 @@ then fi], []) if test "$assertions" = 'true'; then - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) elif test "$Py_DEBUG" = 'true'; then assertions='true' - AC_MSG_RESULT(implied by --with-pydebug) + AC_MSG_RESULT([implied by --with-pydebug]) else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi # Enable optimization flags -AC_SUBST(DEF_MAKE_ALL_RULE) -AC_SUBST(DEF_MAKE_RULE) +AC_SUBST([DEF_MAKE_ALL_RULE]) +AC_SUBST([DEF_MAKE_RULE]) Py_OPT='false' -AC_MSG_CHECKING(for --enable-optimizations) -AC_ARG_ENABLE(optimizations, AS_HELP_STRING( +AC_MSG_CHECKING([for --enable-optimizations]) +AC_ARG_ENABLE([optimizations], AS_HELP_STRING( [--enable-optimizations], [enable expensive, stable optimizations (PGO, etc.) (default is no)]), [ if test "$enableval" != no then Py_OPT='true' - AC_MSG_RESULT(yes); + AC_MSG_RESULT([yes]); else Py_OPT='false' - AC_MSG_RESULT(no); + AC_MSG_RESULT([no]); fi], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) if test "$Py_OPT" = 'true' ; then # Intentionally not forcing Py_LTO='true' here. Too many toolchains do not @@ -1768,13 +1777,13 @@ else DEF_MAKE_RULE="all" fi -AC_ARG_VAR(PROFILE_TASK, Python args for PGO generation task) -AC_MSG_CHECKING(PROFILE_TASK) +AC_ARG_VAR([PROFILE_TASK], [Python args for PGO generation task]) +AC_MSG_CHECKING([PROFILE_TASK]) if test -z "$PROFILE_TASK" then PROFILE_TASK='-m test --pgo --timeout=$(TESTTIMEOUT)' fi -AC_MSG_RESULT($PROFILE_TASK) +AC_MSG_RESULT([$PROFILE_TASK]) # Make llvm-related checks work on systems where llvm tools are not installed with their # normal names in the default $PATH (ie: Ubuntu). They exist under the @@ -1797,28 +1806,29 @@ then fi # Enable LTO flags -AC_MSG_CHECKING(for --with-lto) -AC_ARG_WITH(lto, AS_HELP_STRING([--with-lto=@<:@full|thin|no|yes@:>@], [enable Link-Time-Optimization in any build (default is no)]), +AC_MSG_CHECKING([for --with-lto]) +AC_ARG_WITH([lto], + [AS_HELP_STRING([--with-lto=@<:@full|thin|no|yes@:>@], [enable Link-Time-Optimization in any build (default is no)])], [ case "$withval" in full) Py_LTO='true' Py_LTO_POLICY='full' - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ;; thin) Py_LTO='true' Py_LTO_POLICY='thin' - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ;; yes) Py_LTO='true' Py_LTO_POLICY='default' - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ;; no) Py_LTO='false' - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) ;; *) Py_LTO='false' @@ -1826,7 +1836,7 @@ case "$withval" in ;; esac ], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) if test "$Py_LTO" = 'true' ; then case $CC in *clang*) @@ -1834,9 +1844,9 @@ if test "$Py_LTO" = 'true' ; then dnl Clang linker requires -flto in order to link objects with LTO information. dnl Thin LTO is faster and works for object files with full LTO information, too. AX_CHECK_COMPILE_FLAG([-flto=thin],[LDFLAGS_NOLTO="-flto=thin"],[LDFLAGS_NOLTO="-flto"]) - AC_SUBST(LLVM_AR) - AC_PATH_TOOL(LLVM_AR, llvm-ar, '', ${llvm_path}) - AC_SUBST(LLVM_AR_FOUND) + AC_SUBST([LLVM_AR]) + AC_PATH_TOOL([LLVM_AR], [llvm-ar], [''], [${llvm_path}]) + AC_SUBST([LLVM_AR_FOUND]) if test -n "${LLVM_AR}" -a -x "${LLVM_AR}" then LLVM_AR_FOUND="found" @@ -1930,14 +1940,14 @@ if test "$Py_LTO" = 'true' ; then fi # Enable PGO flags. -AC_SUBST(PGO_PROF_GEN_FLAG) -AC_SUBST(PGO_PROF_USE_FLAG) -AC_SUBST(LLVM_PROF_MERGER) -AC_SUBST(LLVM_PROF_FILE) -AC_SUBST(LLVM_PROF_ERR) -AC_SUBST(LLVM_PROFDATA) -AC_PATH_TOOL(LLVM_PROFDATA, llvm-profdata, '', ${llvm_path}) -AC_SUBST(LLVM_PROF_FOUND) +AC_SUBST([PGO_PROF_GEN_FLAG]) +AC_SUBST([PGO_PROF_USE_FLAG]) +AC_SUBST([LLVM_PROF_MERGER]) +AC_SUBST([LLVM_PROF_FILE]) +AC_SUBST([LLVM_PROF_ERR]) +AC_SUBST([LLVM_PROFDATA]) +AC_PATH_TOOL([LLVM_PROFDATA], [llvm-profdata], [''], [${llvm_path}]) +AC_SUBST([LLVM_PROF_FOUND]) if test -n "${LLVM_PROFDATA}" -a -x "${LLVM_PROFDATA}" then LLVM_PROF_FOUND="found" @@ -2007,22 +2017,22 @@ esac # BOLT optimization. Always configured after PGO since it always runs after PGO. Py_BOLT='false' -AC_MSG_CHECKING(for --enable-bolt) -AC_ARG_ENABLE(bolt, AS_HELP_STRING( +AC_MSG_CHECKING([for --enable-bolt]) +AC_ARG_ENABLE([bolt], [AS_HELP_STRING( [--enable-bolt], - [enable usage of the llvm-bolt post-link optimizer (default is no)]), + [enable usage of the llvm-bolt post-link optimizer (default is no)])], [ if test "$enableval" != no then Py_BOLT='true' - AC_MSG_RESULT(yes); + AC_MSG_RESULT([yes]); else Py_BOLT='false' - AC_MSG_RESULT(no); + AC_MSG_RESULT([no]); fi], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) -AC_SUBST(PREBOLT_RULE) +AC_SUBST([PREBOLT_RULE]) if test "$Py_BOLT" = 'true' ; then PREBOLT_RULE="${DEF_MAKE_ALL_RULE}" DEF_MAKE_ALL_RULE="bolt-opt" @@ -2041,27 +2051,27 @@ if test "$Py_BOLT" = 'true' ; then CFLAGS_NODIST="$CFLAGS_NODIST -fno-pie" # We want to add these no-pie flags to linking executables but not shared libraries: LINKCC="$LINKCC -fno-pie -no-pie" - AC_SUBST(LLVM_BOLT) - AC_PATH_TOOL(LLVM_BOLT, llvm-bolt, '', ${llvm_path}) + AC_SUBST([LLVM_BOLT]) + AC_PATH_TOOL([LLVM_BOLT], [llvm-bolt], [''], [${llvm_path}]) if test -n "${LLVM_BOLT}" -a -x "${LLVM_BOLT}" then - AC_MSG_RESULT("Found llvm-bolt") + AC_MSG_RESULT(["Found llvm-bolt"]) else AC_MSG_ERROR([llvm-bolt is required for a --enable-bolt build but could not be found.]) fi - AC_SUBST(MERGE_FDATA) - AC_PATH_TOOL(MERGE_FDATA, merge-fdata, '', ${llvm_path}) + AC_SUBST([MERGE_FDATA]) + AC_PATH_TOOL([MERGE_FDATA], [merge-fdata], [''], [${llvm_path}]) if test -n "${MERGE_FDATA}" -a -x "${MERGE_FDATA}" then - AC_MSG_RESULT("Found merge-fdata") + AC_MSG_RESULT(["Found merge-fdata"]) else AC_MSG_ERROR([merge-fdata is required for a --enable-bolt build but could not be found.]) fi fi dnl Enable BOLT of libpython if built. -AC_SUBST(BOLT_BINARIES) +AC_SUBST([BOLT_BINARIES]) BOLT_BINARIES='$(BUILDPYTHON)' AS_VAR_IF([enable_shared], [yes], [ BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)" @@ -2197,8 +2207,8 @@ AS_VAR_IF([ac_cv_cc_supports_og], [yes], # tweak OPT based on compiler and platform, only if the user didn't set # it on the command line -AC_SUBST(OPT) -AC_SUBST(CFLAGS_ALIASING) +AC_SUBST([OPT]) +AC_SUBST([CFLAGS_ALIASING]) if test "${OPT-unset}" = "unset" then case $GCC in @@ -2304,21 +2314,21 @@ AS_CASE([$enable_wasm_dynamic_linking], [missing], [] ) -AC_SUBST(BASECFLAGS) -AC_SUBST(CFLAGS_NODIST) -AC_SUBST(LDFLAGS_NODIST) -AC_SUBST(LDFLAGS_NOLTO) +AC_SUBST([BASECFLAGS]) +AC_SUBST([CFLAGS_NODIST]) +AC_SUBST([LDFLAGS_NODIST]) +AC_SUBST([LDFLAGS_NOLTO]) AC_SUBST([WASM_ASSETS_DIR]) AC_SUBST([WASM_STDLIB]) # The -arch flags for universal builds on macOS UNIVERSAL_ARCH_FLAGS= -AC_SUBST(UNIVERSAL_ARCH_FLAGS) +AC_SUBST([UNIVERSAL_ARCH_FLAGS]) dnl PY_CHECK_CC_WARNING(ENABLE, WARNING, [MSG]) AC_DEFUN([PY_CHECK_CC_WARNING], [ AS_VAR_PUSHDEF([py_var], [ac_cv_$1_]m4_normalize($2)[_warning]) - AC_CACHE_CHECK(m4_ifblank([$3], [if we can $1 $CC $2 warning], [$3]), [py_var], [ + AC_CACHE_CHECK([m4_ifblank([$3], [if we can $1 $CC $2 warning], [$3])], [py_var], [ AS_VAR_COPY([py_cflags], [CFLAGS]) AS_VAR_APPEND([CFLAGS], ["-W$2 -Werror"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], @@ -2472,7 +2482,7 @@ yes) # used to be here, but non-Apple gcc doesn't accept them. if test "${CC}" = gcc then - AC_MSG_CHECKING(which compiler should be used) + AC_MSG_CHECKING([which compiler should be used]) case "${UNIVERSALSDK}" in */MacOSX10.4u.sdk) # Build using 10.4 SDK, force usage of gcc when the @@ -2482,7 +2492,7 @@ yes) CPP=cpp-4.0 ;; esac - AC_MSG_RESULT($CC) + AC_MSG_RESULT([$CC]) fi LIPO_INTEL64_FLAGS="" @@ -2559,7 +2569,7 @@ yes) # below to pick either 10.3, 10.4, or 10.5 as the target. # 4. If we are running on OS X 10.2 or earlier, good luck! - AC_MSG_CHECKING(which MACOSX_DEPLOYMENT_TARGET to use) + AC_MSG_CHECKING([which MACOSX_DEPLOYMENT_TARGET to use]) cur_target_major=`sw_vers -productVersion | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` cur_target_minor=`sw_vers -productVersion | \ @@ -2596,13 +2606,13 @@ yes) MACOSX_DEPLOYMENT_TARGET="$CONFIGURE_MACOSX_DEPLOYMENT_TARGET" export MACOSX_DEPLOYMENT_TARGET EXPORT_MACOSX_DEPLOYMENT_TARGET='' - AC_MSG_RESULT($MACOSX_DEPLOYMENT_TARGET) + AC_MSG_RESULT([$MACOSX_DEPLOYMENT_TARGET]) - AC_MSG_CHECKING(if specified universal architectures work) + AC_MSG_CHECKING([if specified universal architectures work]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("%d", 42);]])], - [AC_MSG_RESULT(yes)], - [AC_MSG_RESULT(no) - AC_MSG_ERROR(check config.log and use the '--with-universal-archs' option) + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([check config.log and use the '--with-universal-archs' option]) ]) # end of Darwin* tests @@ -2806,7 +2816,8 @@ dnl AC_MSG_RESULT($cpp_type) dnl autoconf 2.71 deprecates STDC_HEADERS, keep for backwards compatibility dnl assume C99 compilers provide ANSI C headers -AC_DEFINE(STDC_HEADERS, 1, [Define to 1 if you have the ANSI C header files.]) +AC_DEFINE([STDC_HEADERS], [1], + [Define to 1 if you have the ANSI C header files.]) # checks for header files AC_CHECK_HEADERS([ \ @@ -2829,7 +2840,7 @@ AC_HEADER_MAJOR # http://permalink.gmane.org/gmane.linux.bluez.kernel/22294 SAVE_CFLAGS=$CFLAGS CFLAGS="-std=c99 $CFLAGS" -AC_CHECK_HEADERS(bluetooth/bluetooth.h) +AC_CHECK_HEADERS([bluetooth/bluetooth.h]) CFLAGS=$SAVE_CFLAGS # On Darwin (OS X) net/if.h requires sys/socket.h to be imported first. @@ -2843,7 +2854,7 @@ AC_CHECK_HEADERS([net/if.h], [], [], ]) # On Linux, netlink.h requires asm/types.h -AC_CHECK_HEADERS(linux/netlink.h,,,[ +AC_CHECK_HEADERS([linux/netlink.h], [], [], [ #ifdef HAVE_ASM_TYPES_H #include #endif @@ -2853,7 +2864,7 @@ AC_CHECK_HEADERS(linux/netlink.h,,,[ ]) # On Linux, qrtr.h requires asm/types.h -AC_CHECK_HEADERS(linux/qrtr.h,,,[ +AC_CHECK_HEADERS([linux/qrtr.h], [], [], [ #ifdef HAVE_ASM_TYPES_H #include #endif @@ -2862,7 +2873,7 @@ AC_CHECK_HEADERS(linux/qrtr.h,,,[ #endif ]) -AC_CHECK_HEADERS(linux/vm_sockets.h,,,[ +AC_CHECK_HEADERS([linux/vm_sockets.h], [], [], [ #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -2870,7 +2881,9 @@ AC_CHECK_HEADERS(linux/vm_sockets.h,,,[ # On Linux, can.h, can/bcm.h, can/j1939.h, can/raw.h require sys/socket.h # On NetBSD, netcan/can.h requires sys/socket.h -AC_CHECK_HEADERS(linux/can.h linux/can/bcm.h linux/can/j1939.h linux/can/raw.h netcan/can.h,,,[ +AC_CHECK_HEADERS( +[linux/can.h linux/can/bcm.h linux/can/j1939.h linux/can/raw.h netcan/can.h], +[], [], [ #ifdef HAVE_SYS_SOCKET_H #include #endif @@ -2882,7 +2895,8 @@ AC_CACHE_CHECK([for clock_t in time.h], [ac_cv_clock_t_time_h], [ ]) dnl checks for "no" AS_VAR_IF([ac_cv_clock_t_time_h], [no], [ - AC_DEFINE(clock_t, long, [Define to 'long' if doesn't define.]) + AC_DEFINE([clock_t], [long], + [Define to 'long' if doesn't define.]) ]) AC_CACHE_CHECK([for makedev], [ac_cv_func_makedev], [ @@ -2900,7 +2914,8 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ]) AS_VAR_IF([ac_cv_func_makedev], [yes], [ - AC_DEFINE(HAVE_MAKEDEV, 1, [Define this if you have the makedev macro.]) + AC_DEFINE([HAVE_MAKEDEV], [1], + [Define this if you have the makedev macro.]) ]) # byte swapping @@ -2917,7 +2932,8 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ]) AS_VAR_IF([ac_cv_func_le64toh], [yes], [ - AC_DEFINE(HAVE_HTOLE64, 1, [Define this if you have le64toh()]) + AC_DEFINE([HAVE_HTOLE64], [1], + [Define this if you have le64toh()]) ]) use_lfs=yes @@ -2931,13 +2947,13 @@ if test "$use_lfs" = "yes"; then # These may affect some typedefs case $ac_sys_system/$ac_sys_release in AIX*) - AC_DEFINE(_LARGE_FILES, 1, + AC_DEFINE([_LARGE_FILES], [1], [This must be defined on AIX systems to enable large file support.]) ;; esac -AC_DEFINE(_LARGEFILE_SOURCE, 1, +AC_DEFINE([_LARGEFILE_SOURCE], [1], [This must be defined on some systems to enable large file support.]) -AC_DEFINE(_FILE_OFFSET_BITS, 64, +AC_DEFINE([_FILE_OFFSET_BITS], [64], [This must be set to 64 on some systems to enable large file support.]) fi @@ -2956,40 +2972,42 @@ AC_DEFINE_UNQUOTED([RETSIGTYPE],[void],[assume C89 semantics that RETSIGTYPE is AC_TYPE_SIZE_T AC_TYPE_UID_T -AC_CHECK_TYPE(ssize_t, - AC_DEFINE(HAVE_SSIZE_T, 1, [Define if your compiler provides ssize_t]),,) -AC_CHECK_TYPE(__uint128_t, - AC_DEFINE(HAVE_GCC_UINT128_T, 1, [Define if your compiler provides __uint128_t]),,) +AC_CHECK_TYPE([ssize_t], + AC_DEFINE([HAVE_SSIZE_T], [1], + [Define if your compiler provides ssize_t]), [], []) +AC_CHECK_TYPE([__uint128_t], + AC_DEFINE([HAVE_GCC_UINT128_T], [1], + [Define if your compiler provides __uint128_t]), [], []) # Sizes and alignments of various common basic types # ANSI C requires sizeof(char) == 1, so no need to check it -AC_CHECK_SIZEOF(int, 4) -AC_CHECK_SIZEOF(long, 4) -AC_CHECK_ALIGNOF(long) -AC_CHECK_SIZEOF(long long, 8) -AC_CHECK_SIZEOF(void *, 4) -AC_CHECK_SIZEOF(short, 2) -AC_CHECK_SIZEOF(float, 4) -AC_CHECK_SIZEOF(double, 8) -AC_CHECK_SIZEOF(fpos_t, 4) -AC_CHECK_SIZEOF(size_t, 4) -AC_CHECK_ALIGNOF(size_t) -AC_CHECK_SIZEOF(pid_t, 4) -AC_CHECK_SIZEOF(uintptr_t) -AC_CHECK_ALIGNOF(max_align_t) +AC_CHECK_SIZEOF([int], [4]) +AC_CHECK_SIZEOF([long], [4]) +AC_CHECK_ALIGNOF([long]) +AC_CHECK_SIZEOF([long long], [8]) +AC_CHECK_SIZEOF([void *], [4]) +AC_CHECK_SIZEOF([short], [2]) +AC_CHECK_SIZEOF([float], [4]) +AC_CHECK_SIZEOF([double], [8]) +AC_CHECK_SIZEOF([fpos_t], [4]) +AC_CHECK_SIZEOF([size_t], [4]) +AC_CHECK_ALIGNOF([size_t]) +AC_CHECK_SIZEOF([pid_t], [4]) +AC_CHECK_SIZEOF([uintptr_t]) +AC_CHECK_ALIGNOF([max_align_t]) AC_TYPE_LONG_DOUBLE -AC_CHECK_SIZEOF(long double, 16) +AC_CHECK_SIZEOF([long double], [16]) -AC_CHECK_SIZEOF(_Bool, 1) +AC_CHECK_SIZEOF([_Bool], [1]) -AC_CHECK_SIZEOF(off_t, [], [ +AC_CHECK_SIZEOF([off_t], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif ]) -AC_MSG_CHECKING(whether to enable large file support) +AC_MSG_CHECKING([whether to enable large file support]) if test "$ac_cv_sizeof_off_t" -gt "$ac_cv_sizeof_long" -a \ "$ac_cv_sizeof_long_long" -ge "$ac_cv_sizeof_off_t"; then have_largefile_support="yes" @@ -3001,17 +3019,17 @@ AS_CASE([$ac_sys_system], [Emscripten], [have_largefile_support="no"] ) AS_VAR_IF([have_largefile_support], [yes], [ - AC_DEFINE(HAVE_LARGEFILE_SUPPORT, 1, + AC_DEFINE([HAVE_LARGEFILE_SUPPORT], [1], [Defined to enable large file support when an off_t is bigger than a long and long long is at least as big as an off_t. You may need to add some flags for configuration and compilation to enable this mode. (For Solaris and Linux, the necessary defines are already defined.)]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ], [ - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) ]) -AC_CHECK_SIZEOF(time_t, [], [ +AC_CHECK_SIZEOF([time_t], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif @@ -3036,7 +3054,7 @@ AC_COMPILE_IFELSE([ ], [ac_cv_have_pthread_t=yes], [ac_cv_have_pthread_t=no]) ]) AS_VAR_IF([ac_cv_have_pthread_t], [yes], [ - AC_CHECK_SIZEOF(pthread_t, [], [ + AC_CHECK_SIZEOF([pthread_t], [], [ #ifdef HAVE_PTHREAD_H #include #endif @@ -3045,7 +3063,7 @@ AS_VAR_IF([ac_cv_have_pthread_t], [yes], [ # Issue #25658: POSIX hasn't defined that pthread_key_t is compatible with int. # This checking will be unnecessary after removing deprecated TLS API. -AC_CHECK_SIZEOF(pthread_key_t, [], [[#include ]]) +AC_CHECK_SIZEOF([pthread_key_t], [], [[#include ]]) AC_CACHE_CHECK([whether pthread_key_t is compatible with int], [ac_cv_pthread_key_t_is_arithmetic_type], [ if test "$ac_cv_sizeof_pthread_key_t" -eq "$ac_cv_sizeof_int" ; then AC_COMPILE_IFELSE( @@ -3058,90 +3076,97 @@ else fi ]) AS_VAR_IF([ac_cv_pthread_key_t_is_arithmetic_type], [yes], [ - AC_DEFINE(PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT, 1, + AC_DEFINE([PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT], [1], [Define if pthread_key_t is compatible with int.]) ]) CC="$ac_save_cc" -AC_MSG_CHECKING(for --enable-framework) +AC_MSG_CHECKING([for --enable-framework]) if test "$enable_framework" then BASECFLAGS="$BASECFLAGS -fno-common -dynamic" # -F. is needed to allow linking to the framework while # in the build location. - AC_DEFINE(WITH_NEXT_FRAMEWORK, 1, + AC_DEFINE([WITH_NEXT_FRAMEWORK], [1], [Define if you want to produce an OpenStep/Rhapsody framework (shared library plus accessory files).]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) if test $enable_shared = "yes" then AC_MSG_ERROR([Specifying both --enable-shared and --enable-framework is not supported, use only --enable-framework instead]) fi else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi # Check for --with-dsymutil -AC_SUBST(DSYMUTIL) -AC_SUBST(DSYMUTIL_PATH) +AC_SUBST([DSYMUTIL]) +AC_SUBST([DSYMUTIL_PATH]) DSYMUTIL= DSYMUTIL_PATH= -AC_MSG_CHECKING(for --with-dsymutil) -AC_ARG_WITH(dsymutil, - AS_HELP_STRING([--with-dsymutil], [link debug information into final executable with dsymutil in macOS (default is no)]), +AC_MSG_CHECKING([for --with-dsymutil]) +AC_ARG_WITH( + [dsymutil], + [AS_HELP_STRING( + [--with-dsymutil], + [link debug information into final executable with dsymutil in macOS (default is no)] + )], [ if test "$withval" != no then if test "$MACHDEP" != "darwin"; then AC_MSG_ERROR([dsymutil debug linking is only available in macOS.]) fi - AC_MSG_RESULT(yes); + AC_MSG_RESULT([yes]); DSYMUTIL='true' -else AC_MSG_RESULT(no); DSYMUTIL= +else AC_MSG_RESULT([no]); DSYMUTIL= fi], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) if test "$DSYMUTIL"; then - AC_PATH_PROG(DSYMUTIL_PATH, [dsymutil], [not found]) + AC_PATH_PROG([DSYMUTIL_PATH], [dsymutil], [not found]) if test "$DSYMUTIL_PATH" = "not found"; then AC_MSG_ERROR([dsymutil command not found on \$PATH]) fi fi -AC_MSG_CHECKING(for dyld) +AC_MSG_CHECKING([for dyld]) case $ac_sys_system/$ac_sys_release in Darwin/*) - AC_DEFINE(WITH_DYLD, 1, + AC_DEFINE([WITH_DYLD], [1], [Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic linker (dyld) instead of the old-style (NextStep) dynamic linker (rld). Dyld is necessary to support frameworks.]) - AC_MSG_RESULT(always on for Darwin) + AC_MSG_RESULT([always on for Darwin]) ;; *) - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) ;; esac -AC_MSG_CHECKING(for --with-address-sanitizer) -AC_ARG_WITH(address_sanitizer, +AC_MSG_CHECKING([for --with-address-sanitizer]) +AC_ARG_WITH([address_sanitizer], AS_HELP_STRING([--with-address-sanitizer], [enable AddressSanitizer memory error detector, 'asan' (default is no)]), [ -AC_MSG_RESULT($withval) +AC_MSG_RESULT([$withval]) BASECFLAGS="-fsanitize=address -fno-omit-frame-pointer $BASECFLAGS" LDFLAGS="-fsanitize=address $LDFLAGS" # ASan works by controlling memory allocation, our own malloc interferes. with_pymalloc="no" ], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) -AC_MSG_CHECKING(for --with-memory-sanitizer) -AC_ARG_WITH(memory_sanitizer, - AS_HELP_STRING([--with-memory-sanitizer], - [enable MemorySanitizer allocation error detector, 'msan' (default is no)]), +AC_MSG_CHECKING([for --with-memory-sanitizer]) +AC_ARG_WITH( + [memory_sanitizer], + [AS_HELP_STRING( + [--with-memory-sanitizer], + [enable MemorySanitizer allocation error detector, 'msan' (default is no)] + )], [ -AC_MSG_RESULT($withval) +AC_MSG_RESULT([$withval]) AX_CHECK_COMPILE_FLAG([-fsanitize=memory],[ BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS" @@ -3149,34 +3174,37 @@ LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS" # MSan works by controlling memory allocation, our own malloc interferes. with_pymalloc="no" ], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) -AC_MSG_CHECKING(for --with-undefined-behavior-sanitizer) -AC_ARG_WITH(undefined_behavior_sanitizer, - AS_HELP_STRING([--with-undefined-behavior-sanitizer], - [enable UndefinedBehaviorSanitizer undefined behaviour detector, 'ubsan' (default is no)]), +AC_MSG_CHECKING([for --with-undefined-behavior-sanitizer]) +AC_ARG_WITH( + [undefined_behavior_sanitizer], + [AS_HELP_STRING( + [--with-undefined-behavior-sanitizer], + [enable UndefinedBehaviorSanitizer undefined behaviour detector, 'ubsan' (default is no)] + )], [ -AC_MSG_RESULT($withval) +AC_MSG_RESULT([$withval]) BASECFLAGS="-fsanitize=undefined $BASECFLAGS" LDFLAGS="-fsanitize=undefined $LDFLAGS" with_ubsan="yes" ], [ -AC_MSG_RESULT(no) +AC_MSG_RESULT([no]) with_ubsan="no" ]) # Set info about shared libraries. -AC_SUBST(SHLIB_SUFFIX) -AC_SUBST(LDSHARED) -AC_SUBST(LDCXXSHARED) -AC_SUBST(BLDSHARED) -AC_SUBST(CCSHARED) -AC_SUBST(LINKFORSHARED) +AC_SUBST([SHLIB_SUFFIX]) +AC_SUBST([LDSHARED]) +AC_SUBST([LDCXXSHARED]) +AC_SUBST([BLDSHARED]) +AC_SUBST([CCSHARED]) +AC_SUBST([LINKFORSHARED]) # SHLIB_SUFFIX is the extension of shared libraries `(including the dot!) # -- usually .so, .sl on HP-UX, .dll on Cygwin -AC_MSG_CHECKING(the extension of shared libraries) +AC_MSG_CHECKING([the extension of shared libraries]) if test -z "$SHLIB_SUFFIX"; then case $ac_sys_system in hp*|HP*) @@ -3189,13 +3217,13 @@ if test -z "$SHLIB_SUFFIX"; then *) SHLIB_SUFFIX=.so;; esac fi -AC_MSG_RESULT($SHLIB_SUFFIX) +AC_MSG_RESULT([$SHLIB_SUFFIX]) # LDSHARED is the ld *command* used to create shared library # -- "cc -G" on SunOS 5.x. # (Shared libraries in this instance are shared modules to be loaded into # Python, as opposed to building Python itself as a shared library.) -AC_MSG_CHECKING(LDSHARED) +AC_MSG_CHECKING([LDSHARED]) if test -z "$LDSHARED" then case $ac_sys_system/$ac_sys_release in @@ -3327,7 +3355,7 @@ if test "$enable_wasm_dynamic_linking" = "yes" -a "$ac_sys_system" = "Emscripten BLDSHARED='$(CC) -shared -sSIDE_MODULE=1' fi -AC_MSG_RESULT($LDSHARED) +AC_MSG_RESULT([$LDSHARED]) LDCXXSHARED=${LDCXXSHARED-$LDSHARED} AC_MSG_CHECKING([BLDSHARED flags]) @@ -3336,7 +3364,7 @@ AC_MSG_RESULT([$BLDSHARED]) # CCSHARED are the C *flags* used to create objects to go into a shared # library (module) -- this is only needed for a few systems -AC_MSG_CHECKING(CCSHARED) +AC_MSG_CHECKING([CCSHARED]) if test -z "$CCSHARED" then case $ac_sys_system/$ac_sys_release in @@ -3372,10 +3400,10 @@ then CCSHARED="-fpic -D__SO_PICABILINUX__ -ftls-model=global-dynamic" esac fi -AC_MSG_RESULT($CCSHARED) +AC_MSG_RESULT([$CCSHARED]) # LINKFORSHARED are the flags passed to the $(CC) command that links # the python executable -- this is only needed for a few systems -AC_MSG_CHECKING(LINKFORSHARED) +AC_MSG_CHECKING([LINKFORSHARED]) if test -z "$LINKFORSHARED" then case $ac_sys_system/$ac_sys_release in @@ -3401,8 +3429,8 @@ then LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED" - AC_DEFINE_UNQUOTED(THREAD_STACK_SIZE, - 0x$stack_size, + AC_DEFINE_UNQUOTED([THREAD_STACK_SIZE], + [0x$stack_size], [Custom thread stack size depending on chosen sanitizer runtimes.]) if test "$enable_framework" @@ -3441,11 +3469,11 @@ then LINKFORSHARED='-Wl,-export-dynamic';; esac fi -AC_MSG_RESULT($LINKFORSHARED) +AC_MSG_RESULT([$LINKFORSHARED]) -AC_SUBST(CFLAGSFORSHARED) -AC_MSG_CHECKING(CFLAGSFORSHARED) +AC_SUBST([CFLAGSFORSHARED]) +AC_MSG_CHECKING([CFLAGSFORSHARED]) if test ! "$LIBRARY" = "$LDLIBRARY" then case $ac_sys_system in @@ -3463,7 +3491,7 @@ AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [ CFLAGSFORSHARED='$(CCSHARED)' ]) -AC_MSG_RESULT($CFLAGSFORSHARED) +AC_MSG_RESULT([$CFLAGSFORSHARED]) # SHLIBS are libraries (except -lc and -lm) to link to the python shared # library (with --enable-shared). @@ -3473,13 +3501,13 @@ AC_MSG_RESULT($CFLAGSFORSHARED) # to LIBS. This, in turn, means that applications linking the shared libpython # don't need to link LIBS explicitly. The default should be only changed # on systems where this approach causes problems. -AC_SUBST(SHLIBS) -AC_MSG_CHECKING(SHLIBS) +AC_SUBST([SHLIBS]) +AC_MSG_CHECKING([SHLIBS]) case "$ac_sys_system" in *) SHLIBS='$(LIBS)';; esac -AC_MSG_RESULT($SHLIBS) +AC_MSG_RESULT([$SHLIBS]) dnl perf trampoline is Linux specific and requires an arch-specific dnl trampoline in asssembly. @@ -3503,9 +3531,9 @@ AS_VAR_IF([perf_trampoline], [yes], [ AC_SUBST([PERF_TRAMPOLINE_OBJ]) # checks for libraries -AC_CHECK_LIB(sendfile, sendfile) -AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV -AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX +AC_CHECK_LIB([sendfile], [sendfile]) +AC_CHECK_LIB([dl], [dlopen]) # Dynamic linking for SunOS/Solaris and SYSV +AC_CHECK_LIB([dld], [shl_load]) # Dynamic linking for HP-UX dnl check for uuid dependencies @@ -3518,9 +3546,9 @@ dnl AIX provides support for RFC4122 (uuid) in libc.a starting with AIX 6.1 dnl (anno 2007). FreeBSD and OpenBSD provides support in libc as well. dnl Little-endian FreeBSD, OpenBSD and NetBSD needs encoding into an octet dnl stream in big-endian byte-order -AC_CHECK_HEADERS([uuid.h], [ - AC_CHECK_FUNCS([uuid_create uuid_enc_be], [ - have_uuid=yes +AC_CHECK_HEADERS([uuid.h], + [AC_CHECK_FUNCS([uuid_create uuid_enc_be], + [have_uuid=yes LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} LIBUUID_LIBS=${LIBUUID_LIBS-""} ]) @@ -3528,8 +3556,8 @@ AC_CHECK_HEADERS([uuid.h], [ AS_VAR_IF([have_uuid], [missing], [ PKG_CHECK_MODULES( - [LIBUUID], [uuid >= 2.20], [ - dnl linux-util's libuuid has uuid_generate_time_safe() since v2.20 (2011) + [LIBUUID], [uuid >= 2.20], + [dnl linux-util's libuuid has uuid_generate_time_safe() since v2.20 (2011) dnl and provides . have_uuid=yes AC_DEFINE([HAVE_UUID_H], [1]) @@ -3540,11 +3568,9 @@ AS_VAR_IF([have_uuid], [missing], [ LDFLAGS="$LDFLAGS $LIBUUID_LIBS" AC_CHECK_HEADERS([uuid/uuid.h], [ PY_CHECK_LIB([uuid], [uuid_generate_time], [have_uuid=yes]) - PY_CHECK_LIB([uuid], [uuid_generate_time_safe], [ - have_uuid=yes - AC_DEFINE([HAVE_UUID_GENERATE_TIME_SAFE], [1]) - ]) - ]) + PY_CHECK_LIB([uuid], [uuid_generate_time_safe], + [have_uuid=yes + AC_DEFINE([HAVE_UUID_GENERATE_TIME_SAFE], [1]) ]) ]) AS_VAR_IF([have_uuid], [yes], [ LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} LIBUUID_LIBS=${LIBUUID_LIBS-"-luuid"} @@ -3570,37 +3596,37 @@ AS_VAR_IF([have_uuid], [missing], [have_uuid=no]) # 'Real Time' functions on Solaris # posix4 on Solaris 2.6 # pthread (first!) on Linux -AC_SEARCH_LIBS(sem_init, pthread rt posix4) +AC_SEARCH_LIBS([sem_init], [pthread rt posix4]) # check if we need libintl for locale functions -AC_CHECK_LIB(intl, textdomain, - [AC_DEFINE(WITH_LIBINTL, 1, +AC_CHECK_LIB([intl], [textdomain], + [AC_DEFINE([WITH_LIBINTL], [1], [Define to 1 if libintl is needed for locale functions.]) LIBS="-lintl $LIBS"]) # checks for system dependent C++ extensions support case "$ac_sys_system" in - AIX*) AC_MSG_CHECKING(for genuine AIX C++ extensions support) + AIX*) AC_MSG_CHECKING([for genuine AIX C++ extensions support]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[#include ]], [[loadAndInit("", 0, "")]]) ],[ - AC_DEFINE(AIX_GENUINE_CPLUSPLUS, 1, + AC_DEFINE([AIX_GENUINE_CPLUSPLUS], [1], [Define for AIX if your compiler is a genuine IBM xlC/xlC_r and you want support for AIX C++ shared extension modules.]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ],[ - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) ]) dnl The AIX_BUILDDATE is obtained from the kernel fileset - bos.mp64 # BUILD_GNU_TYPE + AIX_BUILDDATE are used to construct the platform_tag # of the AIX system used to build/package Python executable. This tag serves # as a baseline for bdist module packages - AC_MSG_CHECKING(for the system builddate) + AC_MSG_CHECKING([for the system builddate]) AIX_BUILDDATE=$(lslpp -Lcq bos.mp64 | awk -F: '{ print $NF }') AC_DEFINE_UNQUOTED([AIX_BUILDDATE], [$AIX_BUILDDATE], [BUILD_GNU_TYPE + AIX_BUILDDATE are used to construct the PEP425 tag of the build system.]) - AC_MSG_RESULT($AIX_BUILDDATE) + AC_MSG_RESULT([$AIX_BUILDDATE]) ;; *) ;; esac @@ -3630,33 +3656,36 @@ if test "$ac_cv_aligned_required" = yes ; then fi # str, bytes and memoryview hash algorithm -AH_TEMPLATE(Py_HASH_ALGORITHM, +AH_TEMPLATE([Py_HASH_ALGORITHM], [Define hash algorithm for str, bytes and memoryview. SipHash24: 1, FNV: 2, SipHash13: 3, externally defined: 0]) -AC_MSG_CHECKING(for --with-hash-algorithm) +AC_MSG_CHECKING([for --with-hash-algorithm]) dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output -AC_ARG_WITH(hash_algorithm, - AS_HELP_STRING([--with-hash-algorithm=@<:@fnv|siphash13|siphash24@:>@], - [select hash algorithm for use in Python/pyhash.c (default is SipHash13)]), +AC_ARG_WITH( + [hash_algorithm], + [AS_HELP_STRING( + [--with-hash-algorithm=@<:@fnv|siphash13|siphash24@:>@], + [select hash algorithm for use in Python/pyhash.c (default is SipHash13)] + )], [ -AC_MSG_RESULT($withval) +AC_MSG_RESULT([$withval]) case "$withval" in siphash13) - AC_DEFINE(Py_HASH_ALGORITHM, 3) + AC_DEFINE([Py_HASH_ALGORITHM], [3]) ;; siphash24) - AC_DEFINE(Py_HASH_ALGORITHM, 1) + AC_DEFINE([Py_HASH_ALGORITHM], [1]) ;; fnv) - AC_DEFINE(Py_HASH_ALGORITHM, 2) + AC_DEFINE([Py_HASH_ALGORITHM], [2]) ;; *) AC_MSG_ERROR([unknown hash algorithm '$withval']) ;; esac ], -[AC_MSG_RESULT(default)]) +[AC_MSG_RESULT([default])]) validate_tzpath() { # Checks that each element of the path is an absolute path @@ -3674,10 +3703,13 @@ validate_tzpath() { } TZPATH="/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/etc/zoneinfo" -AC_MSG_CHECKING(for --with-tzpath) -AC_ARG_WITH(tzpath, - AS_HELP_STRING([--with-tzpath=] - [Select the default time zone search path for zoneinfo.TZPATH]), +AC_MSG_CHECKING([for --with-tzpath]) +AC_ARG_WITH( + [tzpath], + [AS_HELP_STRING( + [--with-tzpath=], + [Select the default time zone search path for zoneinfo.TZPATH] + )], [ case "$withval" in yes) @@ -3686,41 +3718,47 @@ case "$withval" in *) validate_tzpath "$withval" TZPATH="$withval" - AC_MSG_RESULT("$withval") + AC_MSG_RESULT(["$withval"]) ;; esac ], [validate_tzpath "$TZPATH" - AC_MSG_RESULT("$TZPATH")]) -AC_SUBST(TZPATH) + AC_MSG_RESULT(["$TZPATH"])]) +AC_SUBST([TZPATH]) # Most SVR4 platforms (e.g. Solaris) need -lsocket and -lnsl. -AC_CHECK_LIB(nsl, t_open, [LIBS="-lnsl $LIBS"]) # SVR4 -AC_CHECK_LIB(socket, socket, [LIBS="-lsocket $LIBS"], [], $LIBS) # SVR4 sockets +AC_CHECK_LIB([nsl], [t_open], [LIBS="-lnsl $LIBS"]) # SVR4 +AC_CHECK_LIB([socket], [socket], [LIBS="-lsocket $LIBS"], [], $LIBS) # SVR4 sockets case $ac_sys_system/$ac_sys_release in Haiku*) - AC_CHECK_LIB(network, socket, [LIBS="-lnetwork $LIBS"], [], $LIBS) + AC_CHECK_LIB([network], [socket], [LIBS="-lnetwork $LIBS"], [], [$LIBS]) ;; esac -AC_MSG_CHECKING(for --with-libs) -AC_ARG_WITH(libs, - AS_HELP_STRING([--with-libs='lib1 ...'], [link against additional libs (default is no)]), +AC_MSG_CHECKING([for --with-libs]) +AC_ARG_WITH( + [libs], + [AS_HELP_STRING( + [--with-libs='lib1 ...'], + [link against additional libs (default is no)] + )], [ -AC_MSG_RESULT($withval) +AC_MSG_RESULT([$withval]) LIBS="$withval $LIBS" ], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) # Check for use of the system expat library -AC_MSG_CHECKING(for --with-system-expat) -AC_ARG_WITH(system_expat, - AS_HELP_STRING([--with-system-expat], [build pyexpat module using an installed expat library, see Doc/library/pyexpat.rst (default is no)]), - [], - [with_system_expat="no"]) +AC_MSG_CHECKING([for --with-system-expat]) +AC_ARG_WITH( + [system_expat], + [AS_HELP_STRING( + [--with-system-expat], + [build pyexpat module using an installed expat library, see Doc/library/pyexpat.rst (default is no)] + )], [], [with_system_expat="no"]) -AC_MSG_RESULT($with_system_expat) +AC_MSG_RESULT([$with_system_expat]) AS_VAR_IF([with_system_expat], [yes], [ LIBEXPAT_CFLAGS=${LIBEXPAT_CFLAGS-""} @@ -3795,12 +3833,16 @@ AS_VAR_IF([have_libffi], [yes], [ ]) # Check for use of the system libmpdec library -AC_MSG_CHECKING(for --with-system-libmpdec) -AC_ARG_WITH(system_libmpdec, - AS_HELP_STRING([--with-system-libmpdec], [build _decimal module using an installed libmpdec library, see Doc/library/decimal.rst (default is no)]), - [], - [with_system_libmpdec="no"]) -AC_MSG_RESULT($with_system_libmpdec) +AC_MSG_CHECKING([for --with-system-libmpdec]) +AC_ARG_WITH( + [system_libmpdec], + [AS_HELP_STRING( + [--with-system-libmpdec], + [build _decimal module using an installed libmpdec library, see Doc/library/decimal.rst (default is no)] + )], + [], + [with_system_libmpdec="no"]) +AC_MSG_RESULT([$with_system_libmpdec]) AS_VAR_IF([with_system_libmpdec], [yes], [ LIBMPDEC_CFLAGS=${LIBMPDEC_CFLAGS-""} @@ -3821,22 +3863,26 @@ AC_SUBST([LIBMPDEC_CFLAGS]) AC_SUBST([LIBMPDEC_INTERNAL]) # Check whether _decimal should use a coroutine-local or thread-local context -AC_MSG_CHECKING(for --with-decimal-contextvar) -AC_ARG_WITH(decimal_contextvar, - AS_HELP_STRING([--with-decimal-contextvar], [build _decimal module using a coroutine-local rather than a thread-local context (default is yes)]), - [], - [with_decimal_contextvar="yes"]) +AC_MSG_CHECKING([for --with-decimal-contextvar]) +AC_ARG_WITH( + [decimal_contextvar], + [AS_HELP_STRING( + [--with-decimal-contextvar], + [build _decimal module using a coroutine-local rather than a thread-local context (default is yes)] + )], + [], + [with_decimal_contextvar="yes"]) if test "$with_decimal_contextvar" != "no" then - AC_DEFINE(WITH_DECIMAL_CONTEXTVAR, 1, + AC_DEFINE([WITH_DECIMAL_CONTEXTVAR], [1], [Define if you want build the _decimal module using a coroutine-local rather than a thread-local context]) fi -AC_MSG_RESULT($with_decimal_contextvar) +AC_MSG_RESULT([$with_decimal_contextvar]) # Check for libmpdec machine flavor -AC_MSG_CHECKING(for decimal libmpdec machine) +AC_MSG_CHECKING([for decimal libmpdec machine]) AS_CASE([$ac_sys_system], [Darwin*], [libmpdec_system=Darwin], [SunOS*], [libmpdec_system=sunos], @@ -4176,9 +4222,13 @@ AC_CHECK_HEADERS([db.h], [ # Check for --with-dbmliborder AC_MSG_CHECKING([for --with-dbmliborder]) -AC_ARG_WITH(dbmliborder, - AS_HELP_STRING([--with-dbmliborder=db1:db2:...], [override order to check db backends for dbm; a valid value is a colon separated string with the backend names `ndbm', `gdbm' and `bdb'.]), -[], [with_dbmliborder=gdbm:ndbm:bdb]) +AC_ARG_WITH( + [dbmliborder], + [AS_HELP_STRING( + [--with-dbmliborder=db1:db2:...], + [override order to check db backends for dbm; a valid value is a colon separated string with the backend names `ndbm', `gdbm' and `bdb'.] + )], + [], [with_dbmliborder=gdbm:ndbm:bdb]) have_gdbm_dbmliborder=no as_save_IFS=$IFS @@ -4234,13 +4284,13 @@ AC_MSG_RESULT([$DBM_CFLAGS $DBM_LIBS]) # Templates for things AC_DEFINEd more than once. # For a single AC_DEFINE, no template is needed. -AH_TEMPLATE(_REENTRANT, +AH_TEMPLATE([_REENTRANT], [Define to force use of thread-safe errno, h_errno, and other functions]) if test "$ac_cv_pthread_is_default" = yes then # Defining _REENTRANT on system with POSIX threads should not hurt. - AC_DEFINE(_REENTRANT) + AC_DEFINE([_REENTRANT]) posix_threads=yes if test "$ac_sys_system" = "SunOS"; then CFLAGS="$CFLAGS -D_REENTRANT" @@ -4274,17 +4324,17 @@ else # According to the POSIX spec, a pthreads implementation must # define _POSIX_THREADS in unistd.h. Some apparently don't # (e.g. gnu pth with pthread emulation) - AC_MSG_CHECKING(for _POSIX_THREADS in unistd.h) - AC_EGREP_CPP(yes, + AC_MSG_CHECKING([for _POSIX_THREADS in unistd.h]) + AC_EGREP_CPP([yes], [ #include #ifdef _POSIX_THREADS yes #endif ], unistd_defines_pthreads=yes, unistd_defines_pthreads=no) - AC_MSG_RESULT($unistd_defines_pthreads) + AC_MSG_RESULT([$unistd_defines_pthreads]) - AC_DEFINE(_REENTRANT) + AC_DEFINE([_REENTRANT]) # Just looking for pthread_create in libpthread is not enough: # on HP/UX, pthread.h renames pthread_create to a different symbol name. # So we really have to include pthread.h, and then link. @@ -4298,26 +4348,26 @@ yes void * start_routine (void *arg) { exit (0); }]], [[ pthread_create (NULL, NULL, start_routine, NULL)]])],[ - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) posix_threads=yes ],[ LIBS=$_libs - AC_CHECK_FUNC(pthread_detach, [ + AC_CHECK_FUNC([pthread_detach], [ posix_threads=yes ],[ - AC_CHECK_LIB(pthreads, pthread_create, [ + AC_CHECK_LIB([pthreads], [pthread_create], [ posix_threads=yes LIBS="$LIBS -lpthreads" ], [ - AC_CHECK_LIB(c_r, pthread_create, [ + AC_CHECK_LIB([c_r], [pthread_create], [ posix_threads=yes LIBS="$LIBS -lc_r" ], [ - AC_CHECK_LIB(pthread, __pthread_create_system, [ + AC_CHECK_LIB([pthread], [__pthread_create_system], [ posix_threads=yes LIBS="$LIBS -lpthread" ], [ - AC_CHECK_LIB(cma, pthread_create, [ + AC_CHECK_LIB([cma], [pthread_create], [ posix_threads=yes LIBS="$LIBS -lcma" ],[ @@ -4327,7 +4377,7 @@ pthread_create (NULL, NULL, start_routine, NULL)]])],[ ) ])])])])])]) - AC_CHECK_LIB(mpc, usconfig, [ + AC_CHECK_LIB([mpc], [usconfig], [ LIBS="$LIBS -lmpc" ]) @@ -4335,23 +4385,23 @@ fi if test "$posix_threads" = "yes"; then if test "$unistd_defines_pthreads" = "no"; then - AC_DEFINE(_POSIX_THREADS, 1, + AC_DEFINE([_POSIX_THREADS], [1], [Define if you have POSIX threads, and your system does not define that.]) fi # Bug 662787: Using semaphores causes unexplicable hangs on Solaris 8. case $ac_sys_system/$ac_sys_release in - SunOS/5.6) AC_DEFINE(HAVE_PTHREAD_DESTRUCTOR, 1, + SunOS/5.6) AC_DEFINE([HAVE_PTHREAD_DESTRUCTOR], [1], [Defined for Solaris 2.6 bug in pthread header.]) ;; - SunOS/5.8) AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1, + SunOS/5.8) AC_DEFINE([HAVE_BROKEN_POSIX_SEMAPHORES], [1], [Define if the Posix semaphores do not work on your system]) ;; - AIX/*) AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1, + AIX/*) AC_DEFINE([HAVE_BROKEN_POSIX_SEMAPHORES], [1], [Define if the Posix semaphores do not work on your system]) ;; - NetBSD/*) AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1, + NetBSD/*) AC_DEFINE([HAVE_BROKEN_POSIX_SEMAPHORES], [1], [Define if the Posix semaphores do not work on your system]) ;; esac @@ -4376,16 +4426,17 @@ if test "$posix_threads" = "yes"; then [ac_cv_pthread_system_supported=no]) ]) if test "$ac_cv_pthread_system_supported" = "yes"; then - AC_DEFINE(PTHREAD_SYSTEM_SCHED_SUPPORTED, 1, [Defined if PTHREAD_SCOPE_SYSTEM supported.]) + AC_DEFINE([PTHREAD_SYSTEM_SCHED_SUPPORTED], [1], + [Defined if PTHREAD_SCOPE_SYSTEM supported.]) fi - AC_CHECK_FUNCS(pthread_sigmask, + AC_CHECK_FUNCS([pthread_sigmask], [case $ac_sys_system in CYGWIN*) - AC_DEFINE(HAVE_BROKEN_PTHREAD_SIGMASK, 1, + AC_DEFINE([HAVE_BROKEN_PTHREAD_SIGMASK], [1], [Define if pthread_sigmask() does not work on your system.]) ;; esac]) - AC_CHECK_FUNCS(pthread_getcpuclockid) + AC_CHECK_FUNCS([pthread_getcpuclockid]) fi AS_VAR_IF([posix_threads], [stub], [ @@ -4393,18 +4444,20 @@ AS_VAR_IF([posix_threads], [stub], [ ]) # Check for enable-ipv6 -AH_TEMPLATE(ENABLE_IPV6, [Define if --enable-ipv6 is specified]) +AH_TEMPLATE([ENABLE_IPV6], [Define if --enable-ipv6 is specified]) AC_MSG_CHECKING([if --enable-ipv6 is specified]) -AC_ARG_ENABLE(ipv6, - AS_HELP_STRING([--enable-ipv6], - [enable ipv6 (with ipv4) support, see Doc/library/socket.rst (default is yes if supported)]), +AC_ARG_ENABLE([ipv6], + [AS_HELP_STRING( + [--enable-ipv6], + [enable ipv6 (with ipv4) support, see Doc/library/socket.rst (default is yes if supported)] + )], [ case "$enableval" in no) - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) ipv6=no ;; - *) AC_MSG_RESULT(yes) - AC_DEFINE(ENABLE_IPV6) + *) AC_MSG_RESULT([yes]) + AC_DEFINE([ENABLE_IPV6]) ipv6=yes ;; esac ], @@ -4427,23 +4480,23 @@ AS_CASE([$ac_sys_system], AC_MSG_RESULT([$ipv6]) if test "$ipv6" = "yes"; then - AC_MSG_CHECKING(if RFC2553 API is available) + AC_MSG_CHECKING([if RFC2553 API is available]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[#include #include ]], [[struct sockaddr_in6 x; x.sin6_scope_id;]]) ],[ - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ipv6=yes ],[ - AC_MSG_RESULT(no, IPv6 disabled) + AC_MSG_RESULT([no], [IPv6 disabled]) ipv6=no ]) fi if test "$ipv6" = "yes"; then - AC_DEFINE(ENABLE_IPV6) + AC_DEFINE([ENABLE_IPV6]) fi ]) @@ -4458,7 +4511,7 @@ if test "$ipv6" = "yes"; then case $i in inria) dnl http://www.kame.net/ - AC_EGREP_CPP(yes, [ + AC_EGREP_CPP([yes], [ #include #ifdef IPV6_INRIA_VERSION yes @@ -4467,7 +4520,7 @@ yes ;; kame) dnl http://www.kame.net/ - AC_EGREP_CPP(yes, [ + AC_EGREP_CPP([yes], [ #include #ifdef __KAME__ yes @@ -4479,7 +4532,7 @@ yes ;; linux-glibc) dnl http://www.v6.linux.or.jp/ - AC_EGREP_CPP(yes, [ + AC_EGREP_CPP([yes], [ #include #if defined(__GLIBC__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2)) yes @@ -4505,7 +4558,7 @@ yes fi ;; toshiba) - AC_EGREP_CPP(yes, [ + AC_EGREP_CPP([yes], [ #include #ifdef _TOSHIBA_INET6 yes @@ -4515,7 +4568,7 @@ yes ipv6libdir=/usr/local/v6/lib]) ;; v6d) - AC_EGREP_CPP(yes, [ + AC_EGREP_CPP([yes], [ #include #ifdef __V6D__ yes @@ -4526,7 +4579,7 @@ yes BASECFLAGS="-I/usr/local/v6/include $BASECFLAGS"]) ;; zeta) - AC_EGREP_CPP(yes, [ + AC_EGREP_CPP([yes], [ #include #ifdef _ZETA_MINAMI_INET6 yes @@ -4540,7 +4593,7 @@ yes break fi done - AC_MSG_RESULT($ipv6type) + AC_MSG_RESULT([$ipv6type]) fi if test "$ipv6" = "yes" -a "$ipv6lib" != "none"; then @@ -4569,7 +4622,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ /* CAN_RAW_FD_FRAMES available check */ [ac_cv_can_raw_fd_frames=no]) ]) AS_VAR_IF([ac_cv_can_raw_fd_frames], [yes], [ - AC_DEFINE(HAVE_LINUX_CAN_RAW_FD_FRAMES, 1, [Define if compiling using Linux 3.6 or later.]) + AC_DEFINE([HAVE_LINUX_CAN_RAW_FD_FRAMES], [1], + [Define if compiling using Linux 3.6 or later.]) ]) AC_CACHE_CHECK([for CAN_RAW_JOIN_FILTERS], [ac_cv_can_raw_join_filters], [ @@ -4580,28 +4634,31 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ [ac_cv_can_raw_join_filters=no]) ]) AS_VAR_IF([ac_cv_can_raw_join_filters], [yes], [ - AC_DEFINE(HAVE_LINUX_CAN_RAW_JOIN_FILTERS, 1, [Define if compiling using Linux 4.1 or later.]) + AC_DEFINE([HAVE_LINUX_CAN_RAW_JOIN_FILTERS], [1], + [Define if compiling using Linux 4.1 or later.]) ]) # Check for --with-doc-strings -AC_MSG_CHECKING(for --with-doc-strings) -AC_ARG_WITH(doc-strings, - AS_HELP_STRING([--with-doc-strings], [enable documentation strings (default is yes)])) +AC_MSG_CHECKING([for --with-doc-strings]) +AC_ARG_WITH( + [doc-strings], + [AS_HELP_STRING([--with-doc-strings], [enable documentation strings (default is yes)])]) if test -z "$with_doc_strings" then with_doc_strings="yes" fi if test "$with_doc_strings" != "no" then - AC_DEFINE(WITH_DOC_STRINGS, 1, + AC_DEFINE([WITH_DOC_STRINGS], [1], [Define if you want documentation strings in extension modules]) fi -AC_MSG_RESULT($with_doc_strings) +AC_MSG_RESULT([$with_doc_strings]) # Check for Python-specific malloc support -AC_MSG_CHECKING(for --with-pymalloc) -AC_ARG_WITH(pymalloc, - AS_HELP_STRING([--with-pymalloc], [enable specialized mallocs (default is yes)])) +AC_MSG_CHECKING([for --with-pymalloc]) +AC_ARG_WITH( + [pymalloc], + [AS_HELP_STRING([--with-pymalloc], [enable specialized mallocs (default is yes)])]) if test -z "$with_pymalloc" then @@ -4614,16 +4671,17 @@ then fi if test "$with_pymalloc" != "no" then - AC_DEFINE(WITH_PYMALLOC, 1, + AC_DEFINE([WITH_PYMALLOC], [1], [Define if you want to compile in Python-specific mallocs]) fi -AC_MSG_RESULT($with_pymalloc) +AC_MSG_RESULT([$with_pymalloc]) # Check whether objects such as float, tuple and dict are using # freelists to optimization memory allocation. -AC_MSG_CHECKING(for --with-freelists) -AC_ARG_WITH(freelists, - AS_HELP_STRING([--with-freelists], [enable object freelists (default is yes)])) +AC_MSG_CHECKING([for --with-freelists]) +AC_ARG_WITH( + [freelists], + [AS_HELP_STRING([--with-freelists], [enable object freelists (default is yes)])]) if test -z "$with_freelists" then @@ -4631,16 +4689,16 @@ then fi if test "$with_freelists" != "no" then - AC_DEFINE(WITH_FREELISTS, 1, + AC_DEFINE([WITH_FREELISTS], [1], [Define if you want to compile in object freelists optimization]) fi -AC_MSG_RESULT($with_freelists) +AC_MSG_RESULT([$with_freelists]) # Check for --with-c-locale-coercion -AC_MSG_CHECKING(for --with-c-locale-coercion) -AC_ARG_WITH(c-locale-coercion, - AS_HELP_STRING([--with-c-locale-coercion], - [enable C locale coercion to a UTF-8 based locale (default is yes)])) +AC_MSG_CHECKING([for --with-c-locale-coercion]) +AC_ARG_WITH( + [c-locale-coercion], + [AS_HELP_STRING([--with-c-locale-coercion], [enable C locale coercion to a UTF-8 based locale (default is yes)])]) if test -z "$with_c_locale_coercion" then @@ -4648,16 +4706,18 @@ then fi if test "$with_c_locale_coercion" != "no" then - AC_DEFINE(PY_COERCE_C_LOCALE, 1, + AC_DEFINE([PY_COERCE_C_LOCALE], [1], [Define if you want to coerce the C locale to a UTF-8 based locale]) fi -AC_MSG_RESULT($with_c_locale_coercion) +AC_MSG_RESULT([$with_c_locale_coercion]) # Check for Valgrind support AC_MSG_CHECKING([for --with-valgrind]) -AC_ARG_WITH([valgrind], - AS_HELP_STRING([--with-valgrind], [enable Valgrind support (default is no)]),, - with_valgrind=no) +AC_ARG_WITH( + [valgrind], + [AS_HELP_STRING([--with-valgrind], [enable Valgrind support (default is no)])], + [], [with_valgrind=no] +) AC_MSG_RESULT([$with_valgrind]) if test "$with_valgrind" != no; then AC_CHECK_HEADER([valgrind/valgrind.h], @@ -4668,27 +4728,29 @@ if test "$with_valgrind" != no; then fi # Check for DTrace support -AC_MSG_CHECKING(for --with-dtrace) -AC_ARG_WITH(dtrace, - AS_HELP_STRING([--with-dtrace],[enable DTrace support (default is no)]),, - with_dtrace=no) -AC_MSG_RESULT($with_dtrace) - -AC_SUBST(DTRACE) -AC_SUBST(DFLAGS) -AC_SUBST(DTRACE_HEADERS) -AC_SUBST(DTRACE_OBJS) +AC_MSG_CHECKING([for --with-dtrace]) +AC_ARG_WITH( + [dtrace], + [AS_HELP_STRING([--with-dtrace], [enable DTrace support (default is no)])], + [], [with_dtrace=no]) +AC_MSG_RESULT([$with_dtrace]) + +AC_SUBST([DTRACE]) +AC_SUBST([DFLAGS]) +AC_SUBST([DTRACE_HEADERS]) +AC_SUBST([DTRACE_OBJS]) DTRACE= DTRACE_HEADERS= DTRACE_OBJS= if test "$with_dtrace" = "yes" then - AC_PATH_PROG(DTRACE, [dtrace], [not found]) + AC_PATH_PROG([DTRACE], [dtrace], [not found]) if test "$DTRACE" = "not found"; then AC_MSG_ERROR([dtrace command not found on \$PATH]) fi - AC_DEFINE(WITH_DTRACE, 1, [Define if you want to compile in DTrace support]) + AC_DEFINE([WITH_DTRACE], [1], + [Define if you want to compile in DTrace support]) DTRACE_HEADERS="Include/pydtrace_probes.h" # On OS X, DTrace providers do not need to be explicitly compiled and @@ -4721,17 +4783,17 @@ AC_SUBST([PLATFORM_HEADERS]) AC_SUBST([PLATFORM_OBJS]) # -I${DLINCLDIR} is added to the compile rule for importdl.o -AC_SUBST(DLINCLDIR) +AC_SUBST([DLINCLDIR]) DLINCLDIR=. # the dlopen() function means we might want to use dynload_shlib.o. some # platforms have dlopen(), but don't want to use it. -AC_CHECK_FUNCS(dlopen) +AC_CHECK_FUNCS([dlopen]) # DYNLOADFILE specifies which dynload_*.o file we will use for dynamic # loading of modules. -AC_SUBST(DYNLOADFILE) -AC_MSG_CHECKING(DYNLOADFILE) +AC_SUBST([DYNLOADFILE]) +AC_MSG_CHECKING([DYNLOADFILE]) if test -z "$DYNLOADFILE" then case $ac_sys_system/$ac_sys_release in @@ -4746,17 +4808,17 @@ then ;; esac fi -AC_MSG_RESULT($DYNLOADFILE) +AC_MSG_RESULT([$DYNLOADFILE]) if test "$DYNLOADFILE" != "dynload_stub.o" then - AC_DEFINE(HAVE_DYNAMIC_LOADING, 1, + AC_DEFINE([HAVE_DYNAMIC_LOADING], [1], [Defined when any dynamic module loading is enabled.]) fi # MACHDEP_OBJS can be set to platform-specific object files needed by Python -AC_SUBST(MACHDEP_OBJS) -AC_MSG_CHECKING(MACHDEP_OBJS) +AC_SUBST([MACHDEP_OBJS]) +AC_MSG_CHECKING([MACHDEP_OBJS]) if test -z "$MACHDEP_OBJS" then MACHDEP_OBJS=$extra_machdep_objs @@ -4801,14 +4863,15 @@ AC_CHECK_FUNCS([ \ # links. Some libc implementations have a stub lchmod implementation that always # returns an error. if test "$MACHDEP" != linux; then - AC_CHECK_FUNCS(lchmod) + AC_CHECK_FUNCS([lchmod]) fi -AC_CHECK_DECL(dirfd, - AC_DEFINE(HAVE_DIRFD, 1, - Define if you have the 'dirfd' function or macro.), , - [#include - #include ]) +AC_CHECK_DECL([dirfd], + [AC_DEFINE([HAVE_DIRFD], [1], + [Define if you have the 'dirfd' function or macro.])], + [], + [@%:@include + @%:@include ]) # For some functions, having a definition is not sufficient, since # we want to take their address. @@ -4882,16 +4945,17 @@ AC_CACHE_CHECK([for broken unsetenv], [ac_cv_broken_unsetenv], ) ]) AS_VAR_IF([ac_cv_broken_unsetenv], [yes], [ - AC_DEFINE(HAVE_BROKEN_UNSETENV, 1, [Define if 'unsetenv' does not return an int.]) + AC_DEFINE([HAVE_BROKEN_UNSETENV], [1], + [Define if 'unsetenv' does not return an int.]) ]) dnl check for true -AC_CHECK_PROGS(TRUE, true, /bin/true) +AC_CHECK_PROGS([TRUE], [true], [/bin/true]) dnl On some systems (e.g. Solaris 9), hstrerror and inet_aton are in -lresolv dnl On others, they are in the C library, so we to take no action -AC_CHECK_LIB(c, inet_aton, [$ac_cv_prog_TRUE], - AC_CHECK_LIB(resolv, inet_aton) +AC_CHECK_LIB([c], [inet_aton], [$ac_cv_prog_TRUE], + AC_CHECK_LIB([resolv], [inet_aton]) ) # On Tru64, chflags seems to be present, but calling it will @@ -4915,7 +4979,8 @@ if test "$ac_cv_have_chflags" = cross ; then AC_CHECK_FUNC([chflags], [ac_cv_have_chflags="yes"], [ac_cv_have_chflags="no"]) fi if test "$ac_cv_have_chflags" = yes ; then - AC_DEFINE(HAVE_CHFLAGS, 1, [Define to 1 if you have the 'chflags' function.]) + AC_DEFINE([HAVE_CHFLAGS], [1], + [Define to 1 if you have the 'chflags' function.]) fi AC_CACHE_CHECK([for lchflags], [ac_cv_have_lchflags], [dnl @@ -4934,7 +4999,8 @@ if test "$ac_cv_have_lchflags" = cross ; then AC_CHECK_FUNC([lchflags], [ac_cv_have_lchflags="yes"], [ac_cv_have_lchflags="no"]) fi if test "$ac_cv_have_lchflags" = yes ; then - AC_DEFINE(HAVE_LCHFLAGS, 1, [Define to 1 if you have the 'lchflags' function.]) + AC_DEFINE([HAVE_LCHFLAGS], [1], + [Define to 1 if you have the 'lchflags' function.]) fi dnl Check for compression libraries @@ -5043,36 +5109,38 @@ PY_CHECK_FUNC([setgroups], [ # check for openpty, login_tty, and forkpty -AC_CHECK_FUNCS(openpty,, - AC_CHECK_LIB(util,openpty, - [AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lutil"], - AC_CHECK_LIB(bsd,openpty, [AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lbsd"]) - ) -) +AC_CHECK_FUNCS([openpty], [], + [AC_CHECK_LIB([util], [openpty], + [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], + [AC_CHECK_LIB([bsd], [openpty], + [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) AC_SEARCH_LIBS([login_tty], [util], [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] ) -AC_CHECK_FUNCS(forkpty,, - AC_CHECK_LIB(util,forkpty, - [AC_DEFINE(HAVE_FORKPTY) LIBS="$LIBS -lutil"], - AC_CHECK_LIB(bsd,forkpty, [AC_DEFINE(HAVE_FORKPTY) LIBS="$LIBS -lbsd"]) - ) -) +AC_CHECK_FUNCS([forkpty], [], + [AC_CHECK_LIB([util], [forkpty], + [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], + [AC_CHECK_LIB([bsd], [forkpty], + [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) # check for long file support functions -AC_CHECK_FUNCS(fseek64 fseeko fstatvfs ftell64 ftello statvfs) +AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs]) -AC_REPLACE_FUNCS(dup2) -AC_CHECK_FUNCS(getpgrp, - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[getpgrp(0);]])], - [AC_DEFINE(GETPGRP_HAVE_ARG, 1, [Define if getpgrp() must be called as getpgrp(0).])], - []) -) -AC_CHECK_FUNCS(setpgrp, - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[setpgrp(0,0);]])], - [AC_DEFINE(SETPGRP_HAVE_ARG, 1, [Define if setpgrp() must be called as setpgrp(0, 0).])], - []) -) +AC_REPLACE_FUNCS([dup2]) +AC_CHECK_FUNCS([getpgrp], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([@%:@include ], + [getpgrp(0);])], + [AC_DEFINE([GETPGRP_HAVE_ARG], [1], + [Define if getpgrp() must be called as getpgrp(0).])], + [])]) +AC_CHECK_FUNCS([setpgrp], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([@%:@include ], + [setpgrp(0,0);])], + [AC_DEFINE([SETPGRP_HAVE_ARG], [1], + [Define if setpgrp() must be called as setpgrp(0, 0).])], + [])]) # check for namespace functions AC_CHECK_FUNCS([setns unshare]) @@ -5119,36 +5187,36 @@ WITH_SAVE_ENV([ ]) ]) -AC_CHECK_FUNCS(clock_gettime, [], [ - AC_CHECK_LIB(rt, clock_gettime, [ +AC_CHECK_FUNCS([clock_gettime], [], [ + AC_CHECK_LIB([rt], [clock_gettime], [ LIBS="$LIBS -lrt" - AC_DEFINE(HAVE_CLOCK_GETTIME, 1) - AC_DEFINE(TIMEMODULE_LIB, [rt], + AC_DEFINE([HAVE_CLOCK_GETTIME], [1]) + AC_DEFINE([TIMEMODULE_LIB], [rt], [Library needed by timemodule.c: librt may be needed for clock_gettime()]) ]) ]) -AC_CHECK_FUNCS(clock_getres, [], [ - AC_CHECK_LIB(rt, clock_getres, [ - AC_DEFINE(HAVE_CLOCK_GETRES, 1) +AC_CHECK_FUNCS([clock_getres], [], [ + AC_CHECK_LIB([rt], [clock_getres], [ + AC_DEFINE([HAVE_CLOCK_GETRES], [1]) ]) ]) -AC_CHECK_FUNCS(clock_settime, [], [ - AC_CHECK_LIB(rt, clock_settime, [ - AC_DEFINE(HAVE_CLOCK_SETTIME, 1) +AC_CHECK_FUNCS([clock_settime], [], [ + AC_CHECK_LIB([rt], [clock_settime], [ + AC_DEFINE([HAVE_CLOCK_SETTIME], [1]) ]) ]) -AC_CHECK_FUNCS(clock_nanosleep, [], [ - AC_CHECK_LIB(rt, clock_nanosleep, [ - AC_DEFINE(HAVE_CLOCK_NANOSLEEP, 1) +AC_CHECK_FUNCS([clock_nanosleep], [], [ + AC_CHECK_LIB([rt], [clock_nanosleep], [ + AC_DEFINE([HAVE_CLOCK_NANOSLEEP], [1]) ]) ]) -AC_CHECK_FUNCS(nanosleep, [], [ - AC_CHECK_LIB(rt, nanosleep, [ - AC_DEFINE(HAVE_NANOSLEEP, 1) +AC_CHECK_FUNCS([nanosleep], [], [ + AC_CHECK_LIB([rt], [nanosleep], [ + AC_DEFINE([HAVE_NANOSLEEP], [1]) ]) ]) @@ -5166,12 +5234,12 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ]])],[ac_cv_device_macros=yes], [ac_cv_device_macros=no]) ]) AS_VAR_IF([ac_cv_device_macros], [yes], [ - AC_DEFINE(HAVE_DEVICE_MACROS, 1, + AC_DEFINE([HAVE_DEVICE_MACROS], [1], [Define to 1 if you have the device macros.]) ]) dnl no longer used, now always defined for backwards compatibility -AC_DEFINE(SYS_SELECT_WITH_SYS_TIME, 1, +AC_DEFINE([SYS_SELECT_WITH_SYS_TIME], [1], [Define if you can safely include both and (which you can't on SCO ODT 3.0).]) @@ -5301,10 +5369,11 @@ then ])]) ]) else - AC_DEFINE(HAVE_GETADDRINFO, 1, [Define if you have the getaddrinfo function.]) + AC_DEFINE([HAVE_GETADDRINFO], [1], + [Define if you have the getaddrinfo function.]) fi -AC_CHECK_FUNCS(getnameinfo) +AC_CHECK_FUNCS([getnameinfo]) dnl autoconf 2.71 deprecates AC_HEADER_TIME, keep for backwards compatibility dnl TIME_WITH_SYS_TIME works on all supported systems that have sys/time.h @@ -5334,7 +5403,8 @@ AC_CACHE_CHECK([for time.h that defines altzone], [ac_cv_header_time_altzone], [ [ac_cv_header_time_altzone=no]) ]) if test $ac_cv_header_time_altzone = yes; then - AC_DEFINE(HAVE_ALTZONE, 1, [Define this if your time.h defines altzone.]) + AC_DEFINE([HAVE_ALTZONE], [1], + [Define this if your time.h defines altzone.]) fi AC_CACHE_CHECK([for addrinfo], [ac_cv_struct_addrinfo], @@ -5342,7 +5412,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct addrinfo a]] [ac_cv_struct_addrinfo=yes], [ac_cv_struct_addrinfo=no])) if test $ac_cv_struct_addrinfo = yes; then - AC_DEFINE(HAVE_ADDRINFO, 1, [struct addrinfo (netdb.h)]) + AC_DEFINE([HAVE_ADDRINFO], [1], [struct addrinfo (netdb.h)]) fi AC_CACHE_CHECK([for sockaddr_storage], [ac_cv_struct_sockaddr_storage], @@ -5352,7 +5422,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ [ac_cv_struct_sockaddr_storage=yes], [ac_cv_struct_sockaddr_storage=no])) if test $ac_cv_struct_sockaddr_storage = yes; then - AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [struct sockaddr_storage (sys/socket.h)]) + AC_DEFINE([HAVE_SOCKADDR_STORAGE], [1], + [struct sockaddr_storage (sys/socket.h)]) fi AC_CACHE_CHECK([for sockaddr_alg], [ac_cv_struct_sockaddr_alg], @@ -5363,7 +5434,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ [ac_cv_struct_sockaddr_alg=yes], [ac_cv_struct_sockaddr_alg=no])) if test $ac_cv_struct_sockaddr_alg = yes; then - AC_DEFINE(HAVE_SOCKADDR_ALG, 1, [struct sockaddr_alg (linux/if_alg.h)]) + AC_DEFINE([HAVE_SOCKADDR_ALG], [1], + [struct sockaddr_alg (linux/if_alg.h)]) fi # checks for compiler characteristics @@ -5375,7 +5447,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char c;]])], [ac_cv_working_signed_char_c=yes], [ac_cv_working_signed_char_c=no]) ]) AS_VAR_IF([ac_cv_working_signed_char_c], [no], [ - AC_DEFINE(signed, , [Define to empty if the keyword does not work.]) + AC_DEFINE([signed], [], [Define to empty if the keyword does not work.]) ]) AC_CACHE_CHECK([for prototypes], [ac_cv_function_prototypes], [ @@ -5383,7 +5455,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int foo(int x) { return 0; }]], [[return fo [ac_cv_function_prototypes=yes], [ac_cv_function_prototypes=no]) ]) AS_VAR_IF([ac_cv_function_prototypes], [yes], [ - AC_DEFINE(HAVE_PROTOTYPES, 1, + AC_DEFINE([HAVE_PROTOTYPES], [1], [Define if your compiler supports function prototype]) ]) @@ -5402,15 +5474,16 @@ x.sa_len = 0;]])], [ac_cv_struct_sockaddr_sa_len=yes], [ac_cv_struct_sockaddr_sa_len=no]) ]) AS_VAR_IF([ac_cv_struct_sockaddr_sa_len], [yes], [ - AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1, [Define if sockaddr has sa_len member]) + AC_DEFINE([HAVE_SOCKADDR_SA_LEN], [1], + [Define if sockaddr has sa_len member]) ]) # sigh -- gethostbyname_r is a mess; it can have 3, 5 or 6 arguments :-( -AH_TEMPLATE(HAVE_GETHOSTBYNAME_R, +AH_TEMPLATE([HAVE_GETHOSTBYNAME_R], [Define this if you have some version of gethostbyname_r()]) -AC_CHECK_FUNC(gethostbyname_r, [ - AC_DEFINE(HAVE_GETHOSTBYNAME_R) +AC_CHECK_FUNC([gethostbyname_r], + [AC_DEFINE([HAVE_GETHOSTBYNAME_R]) AC_MSG_CHECKING([gethostbyname_r with 6 args]) OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" @@ -5425,12 +5498,12 @@ AC_CHECK_FUNC(gethostbyname_r, [ (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop) ]])],[ - AC_DEFINE(HAVE_GETHOSTBYNAME_R) - AC_DEFINE(HAVE_GETHOSTBYNAME_R_6_ARG, 1, + AC_DEFINE([HAVE_GETHOSTBYNAME_R]) + AC_DEFINE([HAVE_GETHOSTBYNAME_R_6_ARG], [1], [Define this if you have the 6-arg version of gethostbyname_r().]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ],[ - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) AC_MSG_CHECKING([gethostbyname_r with 5 args]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ # include @@ -5444,12 +5517,12 @@ AC_CHECK_FUNC(gethostbyname_r, [ (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop) ]])], [ - AC_DEFINE(HAVE_GETHOSTBYNAME_R) - AC_DEFINE(HAVE_GETHOSTBYNAME_R_5_ARG, 1, + AC_DEFINE([HAVE_GETHOSTBYNAME_R]) + AC_DEFINE([HAVE_GETHOSTBYNAME_R_5_ARG], [1], [Define this if you have the 5-arg version of gethostbyname_r().]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ], [ - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) AC_MSG_CHECKING([gethostbyname_r with 3 args]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ # include @@ -5461,69 +5534,69 @@ AC_CHECK_FUNC(gethostbyname_r, [ (void) gethostbyname_r(name, he, &data); ]])], [ - AC_DEFINE(HAVE_GETHOSTBYNAME_R) - AC_DEFINE(HAVE_GETHOSTBYNAME_R_3_ARG, 1, + AC_DEFINE([HAVE_GETHOSTBYNAME_R]) + AC_DEFINE([HAVE_GETHOSTBYNAME_R_3_ARG], [1], [Define this if you have the 3-arg version of gethostbyname_r().]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) ], [ - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) ]) ]) ]) CFLAGS=$OLD_CFLAGS ], [ - AC_CHECK_FUNCS(gethostbyname) + AC_CHECK_FUNCS([gethostbyname]) ]) -AC_SUBST(HAVE_GETHOSTBYNAME_R_6_ARG) -AC_SUBST(HAVE_GETHOSTBYNAME_R_5_ARG) -AC_SUBST(HAVE_GETHOSTBYNAME_R_3_ARG) -AC_SUBST(HAVE_GETHOSTBYNAME_R) -AC_SUBST(HAVE_GETHOSTBYNAME) +AC_SUBST([HAVE_GETHOSTBYNAME_R_6_ARG]) +AC_SUBST([HAVE_GETHOSTBYNAME_R_5_ARG]) +AC_SUBST([HAVE_GETHOSTBYNAME_R_3_ARG]) +AC_SUBST([HAVE_GETHOSTBYNAME_R]) +AC_SUBST([HAVE_GETHOSTBYNAME]) # checks for system services # (none yet) # Linux requires this for correct f.p. operations -AC_CHECK_FUNC(__fpu_control, +AC_CHECK_FUNC([__fpu_control], [], - [AC_CHECK_LIB(ieee, __fpu_control) + [AC_CHECK_LIB([ieee], [__fpu_control]) ]) # check for --with-libm=... -AC_SUBST(LIBM) +AC_SUBST([LIBM]) case $ac_sys_system in Darwin) ;; *) LIBM=-lm esac -AC_MSG_CHECKING(for --with-libm=STRING) -AC_ARG_WITH(libm, - AS_HELP_STRING([--with-libm=STRING], [override libm math library to STRING (default is system-dependent)]), +AC_MSG_CHECKING([for --with-libm=STRING]) +AC_ARG_WITH([libm], + [AS_HELP_STRING([--with-libm=STRING], [override libm math library to STRING (default is system-dependent)])], [ if test "$withval" = no then LIBM= - AC_MSG_RESULT(force LIBM empty) + AC_MSG_RESULT([force LIBM empty]) elif test "$withval" != yes then LIBM=$withval - AC_MSG_RESULT(set LIBM="$withval") + AC_MSG_RESULT([set LIBM="$withval"]) else AC_MSG_ERROR([proper usage is --with-libm=STRING]) fi], -[AC_MSG_RESULT(default LIBM="$LIBM")]) +[AC_MSG_RESULT([default LIBM="$LIBM"])]) # check for --with-libc=... -AC_SUBST(LIBC) -AC_MSG_CHECKING(for --with-libc=STRING) -AC_ARG_WITH(libc, - AS_HELP_STRING([--with-libc=STRING], [override libc C library to STRING (default is system-dependent)]), +AC_SUBST([LIBC]) +AC_MSG_CHECKING([for --with-libc=STRING]) +AC_ARG_WITH([libc], + [AS_HELP_STRING([--with-libc=STRING], [override libc C library to STRING (default is system-dependent)])], [ if test "$withval" = no then LIBC= - AC_MSG_RESULT(force LIBC empty) + AC_MSG_RESULT([force LIBC empty]) elif test "$withval" != yes then LIBC=$withval - AC_MSG_RESULT(set LIBC="$withval") + AC_MSG_RESULT([set LIBC="$withval"]) else AC_MSG_ERROR([proper usage is --with-libc=STRING]) fi], -[AC_MSG_RESULT(default LIBC="$LIBC")]) +[AC_MSG_RESULT([default LIBC="$LIBC"])]) # ************************************** # * Check for gcc x64 inline assembler * @@ -5537,7 +5610,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ ]) AS_VAR_IF([ac_cv_gcc_asm_for_x64], [yes], [ - AC_DEFINE(HAVE_GCC_ASM_FOR_X64, 1, + AC_DEFINE([HAVE_GCC_ASM_FOR_X64], [1], [Define if we can use x64 gcc inline assembler]) ]) @@ -5548,12 +5621,12 @@ AS_VAR_IF([ac_cv_gcc_asm_for_x64], [yes], [ AX_C_FLOAT_WORDS_BIGENDIAN if test "$ax_cv_c_float_words_bigendian" = "yes" then - AC_DEFINE(DOUBLE_IS_BIG_ENDIAN_IEEE754, 1, + AC_DEFINE([DOUBLE_IS_BIG_ENDIAN_IEEE754], [1], [Define if C doubles are 64-bit IEEE 754 binary format, stored with the most significant byte first]) elif test "$ax_cv_c_float_words_bigendian" = "no" then - AC_DEFINE(DOUBLE_IS_LITTLE_ENDIAN_IEEE754, 1, + AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1], [Define if C doubles are 64-bit IEEE 754 binary format, stored with the least significant byte first]) else @@ -5563,7 +5636,7 @@ else # conversions work. # FLOAT_WORDS_BIGENDIAN doesnt actually detect this case, but if it's not big # or little, then it must be this? - AC_DEFINE(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754, 1, + AC_DEFINE([DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754], [1], [Define if C doubles are 64-bit IEEE 754 binary format, stored in ARM mixed-endian order (byte order 45670123)]) fi @@ -5586,7 +5659,7 @@ AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ ]])],[ac_cv_gcc_asm_for_x87=yes],[ac_cv_gcc_asm_for_x87=no]) ]) AS_VAR_IF([ac_cv_gcc_asm_for_x87], [yes], [ - AC_DEFINE(HAVE_GCC_ASM_FOR_X87, 1, + AC_DEFINE([HAVE_GCC_ASM_FOR_X87], [1], [Define if we can use gcc inline assembler to get and set x87 control word]) ]) @@ -5598,7 +5671,7 @@ AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[ ]])],[ac_cv_gcc_asm_for_mc68881=yes],[ac_cv_gcc_asm_for_mc68881=no]) ]) AS_VAR_IF([ac_cv_gcc_asm_for_mc68881], [yes], [ - AC_DEFINE(HAVE_GCC_ASM_FOR_MC68881, 1, + AC_DEFINE([HAVE_GCC_ASM_FOR_MC68881], [1], [Define if we can use gcc inline assembler to get and set mc68881 fpcr]) ]) @@ -5638,7 +5711,7 @@ CC="$ac_save_cc" ]) AS_VAR_IF([ac_cv_x87_double_rounding], [yes], [ - AC_DEFINE(X87_DOUBLE_ROUNDING, 1, + AC_DEFINE([X87_DOUBLE_ROUNDING], [1], [Define if arithmetic is subject to x87-style double rounding issue]) ]) @@ -5734,7 +5807,7 @@ AC_CHECK_DECLS([RTLD_LAZY, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL, RTLD_NODELETE, RTL # determine what size digit to use for Python's longs AC_MSG_CHECKING([digit size for Python's longs]) -AC_ARG_ENABLE(big-digits, +AC_ARG_ENABLE([big-digits], AS_HELP_STRING([--enable-big-digits@<:@=15|30@:>@],[use big digits (30 or 15 bits) for Python longs (default is 30)]]), [case $enable_big_digits in yes) @@ -5746,14 +5819,15 @@ no) *) AC_MSG_ERROR([bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30]) ;; esac -AC_MSG_RESULT($enable_big_digits) -AC_DEFINE_UNQUOTED(PYLONG_BITS_IN_DIGIT, $enable_big_digits, [Define as the preferred size in bits of long digits]) +AC_MSG_RESULT([$enable_big_digits]) +AC_DEFINE_UNQUOTED([PYLONG_BITS_IN_DIGIT], [$enable_big_digits], + [Define as the preferred size in bits of long digits]) ], -[AC_MSG_RESULT(no value specified)]) +[AC_MSG_RESULT([no value specified])]) # check for wchar.h -AC_CHECK_HEADER(wchar.h, [ - AC_DEFINE(HAVE_WCHAR_H, 1, +AC_CHECK_HEADER([wchar.h], [ + AC_DEFINE([HAVE_WCHAR_H], [1], [Define if the compiler provides a wchar.h header file.]) wchar_h="yes" ], @@ -5763,7 +5837,9 @@ wchar_h="no" # determine wchar_t size if test "$wchar_h" = yes then - AC_CHECK_SIZEOF(wchar_t, 4, [#include ]) + AC_CHECK_SIZEOF([wchar_t], [4], [m4_normalize([ + #include + ])]) fi # check whether wchar_t is signed or not @@ -5784,18 +5860,18 @@ then [ac_cv_wchar_t_signed=yes])]) fi -AC_MSG_CHECKING(whether wchar_t is usable) +AC_MSG_CHECKING([whether wchar_t is usable]) # wchar_t is only usable if it maps to an unsigned type if test "$ac_cv_sizeof_wchar_t" -ge 2 \ -a "$ac_cv_wchar_t_signed" = "no" then - AC_DEFINE(HAVE_USABLE_WCHAR_T, 1, + AC_DEFINE([HAVE_USABLE_WCHAR_T], [1], [Define if you have a useable wchar_t type defined in wchar.h; useable means wchar_t must be an unsigned type with at least 16 bits. (see Include/unicodeobject.h).]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi case $ac_sys_system/$ac_sys_release in @@ -5806,7 +5882,7 @@ SunOS/*) # bpo-43667: In Oracle Solaris, the internal form of wchar_t in # non-Unicode locales is not Unicode and hence cannot be used directly. # https://docs.oracle.com/cd/E37838_01/html/E61053/gmwke.html - AC_DEFINE(HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION, 1, + AC_DEFINE([HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION], [1], [Define if the internal form of wchar_t in non-Unicode locales is not Unicode.]) fi @@ -5832,31 +5908,31 @@ AC_C_BIGENDIAN # # In Python 3.2 and older, --with-wide-unicode added a 'u' flag. # In Python 3.7 and older, --with-pymalloc added a 'm' flag. -AC_SUBST(SOABI) -AC_MSG_CHECKING(ABIFLAGS) -AC_MSG_RESULT($ABIFLAGS) -AC_MSG_CHECKING(SOABI) +AC_SUBST([SOABI]) +AC_MSG_CHECKING([ABIFLAGS]) +AC_MSG_RESULT([$ABIFLAGS]) +AC_MSG_CHECKING([SOABI]) SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} -AC_MSG_RESULT($SOABI) +AC_MSG_RESULT([$SOABI]) # Release and debug (Py_DEBUG) ABI are compatible, but not Py_TRACE_REFS ABI if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then # Similar to SOABI but remove "d" flag from ABIFLAGS - AC_SUBST(ALT_SOABI) + AC_SUBST([ALT_SOABI]) ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} - AC_DEFINE_UNQUOTED(ALT_SOABI, "${ALT_SOABI}", + AC_DEFINE_UNQUOTED([ALT_SOABI], ["${ALT_SOABI}"], [Alternative SOABI used in debug build to load C extensions built in release mode]) fi -AC_SUBST(EXT_SUFFIX) +AC_SUBST([EXT_SUFFIX]) EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX} -AC_MSG_CHECKING(LDVERSION) +AC_MSG_CHECKING([LDVERSION]) LDVERSION='$(VERSION)$(ABIFLAGS)' -AC_MSG_RESULT($LDVERSION) +AC_MSG_RESULT([$LDVERSION]) # On Android and Cygwin the shared libraries must be linked with libpython. -AC_SUBST(LIBPYTHON) +AC_SUBST([LIBPYTHON]) if test "$PY_ENABLE_SHARED" = "1" && ( test -n "$ANDROID_API_LEVEL" || test "$MACHDEP" = "cygwin"); then LIBPYTHON="-lpython${VERSION}${ABIFLAGS}" else @@ -5864,18 +5940,21 @@ else fi -AC_SUBST(BINLIBDEST) +AC_SUBST([BINLIBDEST]) BINLIBDEST='$(LIBDIR)/python$(VERSION)' # Check for --with-platlibdir # /usr/$LIDIRNAME/python$VERSION -AC_SUBST(PLATLIBDIR) +AC_SUBST([PLATLIBDIR]) PLATLIBDIR="lib" -AC_MSG_CHECKING(for --with-platlibdir) -AC_ARG_WITH(platlibdir, - AS_HELP_STRING([--with-platlibdir=DIRNAME], - [Python library directory name (default is "lib")]), +AC_MSG_CHECKING([for --with-platlibdir]) +AC_ARG_WITH( + [platlibdir], + [AS_HELP_STRING( + [--with-platlibdir=DIRNAME], + [Python library directory name (default is "lib")] + )], [ # ignore 3 options: # --with-platlibdir @@ -5883,39 +5962,42 @@ AC_ARG_WITH(platlibdir, # --without-platlibdir if test -n "$withval" -a "$withval" != yes -a "$withval" != no then - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) PLATLIBDIR="$withval" BINLIBDEST='${exec_prefix}/${PLATLIBDIR}/python$(VERSION)' else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) dnl define LIBPL after ABIFLAGS and LDVERSION is defined. -AC_SUBST(PY_ENABLE_SHARED) +AC_SUBST([PY_ENABLE_SHARED]) if test x$PLATFORM_TRIPLET = x; then LIBPL='$(prefix)'"/${PLATLIBDIR}/python${VERSION}/config-${LDVERSION}" else LIBPL='$(prefix)'"/${PLATLIBDIR}/python${VERSION}/config-${LDVERSION}-${PLATFORM_TRIPLET}" fi -AC_SUBST(LIBPL) +AC_SUBST([LIBPL]) # Check for --with-wheel-pkg-dir=PATH -AC_SUBST(WHEEL_PKG_DIR) +AC_SUBST([WHEEL_PKG_DIR]) WHEEL_PKG_DIR="" -AC_MSG_CHECKING(for --with-wheel-pkg-dir) -AC_ARG_WITH(wheel-pkg-dir, - AS_HELP_STRING([--with-wheel-pkg-dir=PATH], - [Directory of wheel packages used by ensurepip (default: none)]), +AC_MSG_CHECKING([for --with-wheel-pkg-dir]) +AC_ARG_WITH( + [wheel-pkg-dir], + [AS_HELP_STRING( + [--with-wheel-pkg-dir=PATH], + [Directory of wheel packages used by ensurepip (default: none)] + )], [ if test -n "$withval"; then - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) WHEEL_PKG_DIR="$withval" else - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi], -[AC_MSG_RESULT(no)]) +[AC_MSG_RESULT([no])]) # Check whether right shifting a negative integer extends the sign bit # or fills with zeros (like the Cray J90, according to Tim Peters). @@ -5931,7 +6013,7 @@ int main(void) [ac_cv_rshift_extends_sign=yes])]) if test "$ac_cv_rshift_extends_sign" = no then - AC_DEFINE(SIGNED_RIGHT_SHIFT_ZERO_FILLS, 1, + AC_DEFINE([SIGNED_RIGHT_SHIFT_ZERO_FILLS], [1], [Define if i>>j for signed int i does not extend the sign bit when i < 0]) fi @@ -5946,7 +6028,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ ]])],[ac_cv_have_getc_unlocked=yes],[ac_cv_have_getc_unlocked=no])]) if test "$ac_cv_have_getc_unlocked" = yes then - AC_DEFINE(HAVE_GETC_UNLOCKED, 1, + AC_DEFINE([HAVE_GETC_UNLOCKED], [1], [Define this if you have flockfile(), getc_unlocked(), and funlockfile()]) fi @@ -6133,7 +6215,7 @@ int main(void) [ac_cv_broken_nice=no])]) if test "$ac_cv_broken_nice" = yes then - AC_DEFINE(HAVE_BROKEN_NICE, 1, + AC_DEFINE([HAVE_BROKEN_NICE], [1], [Define if nice() returns success/failure instead of the new priority.]) fi @@ -6163,7 +6245,7 @@ int main(void) [ac_cv_broken_poll=no])) if test "$ac_cv_broken_poll" = yes then - AC_DEFINE(HAVE_BROKEN_POLL, 1, + AC_DEFINE([HAVE_BROKEN_POLL], [1], [Define if poll() sets errno on invalid file descriptors.]) fi @@ -6238,7 +6320,7 @@ int main(void) [ac_cv_working_tzset=no])]) if test "$ac_cv_working_tzset" = yes then - AC_DEFINE(HAVE_WORKING_TZSET, 1, + AC_DEFINE([HAVE_WORKING_TZSET], [1], [Define if tzset() actually switches the local timezone in a meaningful way.]) fi @@ -6252,7 +6334,7 @@ st.st_mtim.tv_nsec = 1; [ac_cv_stat_tv_nsec=no])) if test "$ac_cv_stat_tv_nsec" = yes then - AC_DEFINE(HAVE_STAT_TV_NSEC, 1, + AC_DEFINE([HAVE_STAT_TV_NSEC], [1], [Define if you have struct stat.st_mtim.tv_nsec]) fi @@ -6266,7 +6348,7 @@ st.st_mtimespec.tv_nsec = 1; [ac_cv_stat_tv_nsec2=no])) if test "$ac_cv_stat_tv_nsec2" = yes then - AC_DEFINE(HAVE_STAT_TV_NSEC2, 1, + AC_DEFINE([HAVE_STAT_TV_NSEC2], [1], [Define if you have struct stat.st_mtimensec]) fi @@ -6393,7 +6475,7 @@ if test "$cross_compiling" = no; then fi # On Solaris, term.h requires curses.h -AC_CHECK_HEADERS(term.h,,,[ +AC_CHECK_HEADERS([term.h], [], [], [ #ifdef HAVE_CURSES_H #include #endif @@ -6410,7 +6492,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ if test "$ac_cv_mvwdelch_is_expression" = yes then - AC_DEFINE(MVWDELCH_IS_EXPRESSION, 1, + AC_DEFINE([MVWDELCH_IS_EXPRESSION], [1], [Define if mvwdelch in curses.h is an expression.]) fi @@ -6432,7 +6514,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ if test "$ac_cv_window_has_flags" = yes then - AC_DEFINE(WINDOW_HAS_FLAGS, 1, + AC_DEFINE([WINDOW_HAS_FLAGS], [1], [Define if WINDOW in curses.h offers a field _flags.]) fi @@ -6490,14 +6572,14 @@ if test "x$cross_compiling" = xyes; then fi fi -AC_CHECK_FILE(/dev/ptmx, [], []) +AC_CHECK_FILE([/dev/ptmx], [], []) if test "x$ac_cv_file__dev_ptmx" = xyes; then - AC_DEFINE(HAVE_DEV_PTMX, 1, + AC_DEFINE([HAVE_DEV_PTMX], [1], [Define to 1 if you have the /dev/ptmx device file.]) fi -AC_CHECK_FILE(/dev/ptc, [], []) +AC_CHECK_FILE([/dev/ptc], [], []) if test "x$ac_cv_file__dev_ptc" = xyes; then - AC_DEFINE(HAVE_DEV_PTC, 1, + AC_DEFINE([HAVE_DEV_PTC], [1], [Define to 1 if you have the /dev/ptc device file.]) fi @@ -6506,9 +6588,12 @@ then LIBS="$LIBS -framework CoreFoundation" fi -AC_CHECK_TYPE(socklen_t,, - AC_DEFINE(socklen_t,int, - [Define to `int' if does not define.]),[ +AC_CHECK_TYPE( + [socklen_t], [], + [AC_DEFINE( + [socklen_t], [int], + [Define to `int' if does not define.] + )], [ #ifdef HAVE_SYS_TYPES_H #include #endif @@ -6534,31 +6619,34 @@ int main(void) { [ac_cv_broken_mbstowcs=no])) if test "$ac_cv_broken_mbstowcs" = yes then - AC_DEFINE(HAVE_BROKEN_MBSTOWCS, 1, + AC_DEFINE([HAVE_BROKEN_MBSTOWCS], [1], [Define if mbstowcs(NULL, "text", 0) does not return the number of wide chars that would be converted.]) fi # Check for --with-computed-gotos -AC_MSG_CHECKING(for --with-computed-gotos) -AC_ARG_WITH(computed-gotos, - AS_HELP_STRING([--with-computed-gotos], - [enable computed gotos in evaluation loop (enabled by default on supported compilers)]), +AC_MSG_CHECKING([for --with-computed-gotos]) +AC_ARG_WITH( + [computed-gotos], + [AS_HELP_STRING( + [--with-computed-gotos], + [enable computed gotos in evaluation loop (enabled by default on supported compilers)] + )], [ if test "$withval" = yes then - AC_DEFINE(USE_COMPUTED_GOTOS, 1, + AC_DEFINE([USE_COMPUTED_GOTOS], [1], [Define if you want to use computed gotos in ceval.c.]) - AC_MSG_RESULT(yes) + AC_MSG_RESULT([yes]) fi if test "$withval" = no then - AC_DEFINE(USE_COMPUTED_GOTOS, 0, + AC_DEFINE([USE_COMPUTED_GOTOS], [0], [Define if you want to use computed gotos in ceval.c.]) - AC_MSG_RESULT(no) + AC_MSG_RESULT([no]) fi ], -[AC_MSG_RESULT(no value specified)]) +[AC_MSG_RESULT([no value specified])]) AC_CACHE_CHECK([whether $CC supports computed gotos], [ac_cv_computed_gotos], AC_RUN_IFELSE([AC_LANG_SOURCE([[[ @@ -6581,24 +6669,25 @@ LABEL2: ac_cv_computed_gotos=no fi])) case "$ac_cv_computed_gotos" in yes*) - AC_DEFINE(HAVE_COMPUTED_GOTOS, 1, + AC_DEFINE([HAVE_COMPUTED_GOTOS], [1], [Define if the C compiler supports computed gotos.]) esac case $ac_sys_system in AIX*) - AC_DEFINE(HAVE_BROKEN_PIPE_BUF, 1, [Define if the system reports an invalid PIPE_BUF value.]) ;; + AC_DEFINE([HAVE_BROKEN_PIPE_BUF], [1], + [Define if the system reports an invalid PIPE_BUF value.]) ;; esac -AC_SUBST(THREADHEADERS) +AC_SUBST([THREADHEADERS]) for h in `(cd $srcdir;echo Python/thread_*.h)` do THREADHEADERS="$THREADHEADERS \$(srcdir)/$h" done -AC_SUBST(SRCDIRS) +AC_SUBST([SRCDIRS]) SRCDIRS="\ Modules \ Modules/_blake2 \ @@ -6621,13 +6710,13 @@ SRCDIRS="\ Python \ Python/frozen_modules \ Python/deepfreeze" -AC_MSG_CHECKING(for build directories) +AC_MSG_CHECKING([for build directories]) for dir in $SRCDIRS; do if test ! -d $dir; then mkdir $dir fi done -AC_MSG_RESULT(done) +AC_MSG_RESULT([done]) # Availability of -O2: AC_CACHE_CHECK([for -O2], [ac_cv_compile_o2], [ @@ -6639,7 +6728,7 @@ CFLAGS="$saved_cflags" # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html -AC_MSG_CHECKING(for glibc _FORTIFY_SOURCE/memmove bug) +AC_MSG_CHECKING([for glibc _FORTIFY_SOURCE/memmove bug]) saved_cflags="$CFLAGS" CFLAGS="-O2 -D_FORTIFY_SOURCE=2" if test "$ac_cv_compile_o2" = no; then @@ -6665,9 +6754,9 @@ int main(void) { [have_glibc_memmove_bug=yes], [have_glibc_memmove_bug=undefined]) CFLAGS="$saved_cflags" -AC_MSG_RESULT($have_glibc_memmove_bug) +AC_MSG_RESULT([$have_glibc_memmove_bug]) if test "$have_glibc_memmove_bug" = yes; then - AC_DEFINE(HAVE_GLIBC_MEMMOVE_BUG, 1, + AC_DEFINE([HAVE_GLIBC_MEMMOVE_BUG], [1], [Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and bcopy.]) fi @@ -6678,7 +6767,7 @@ if test "$ac_cv_gcc_asm_for_x87" = yes; then # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html case $CC in *gcc*) - AC_MSG_CHECKING(for gcc ipa-pure-const bug) + AC_MSG_CHECKING([for gcc ipa-pure-const bug]) saved_cflags="$CFLAGS" CFLAGS="-O2" AC_RUN_IFELSE([AC_LANG_SOURCE([[ @@ -6702,9 +6791,9 @@ if test "$ac_cv_gcc_asm_for_x87" = yes; then [have_ipa_pure_const_bug=yes], [have_ipa_pure_const_bug=undefined]) CFLAGS="$saved_cflags" - AC_MSG_RESULT($have_ipa_pure_const_bug) + AC_MSG_RESULT([$have_ipa_pure_const_bug]) if test "$have_ipa_pure_const_bug" = yes; then - AC_DEFINE(HAVE_IPA_PURE_CONST_BUG, 1, + AC_DEFINE([HAVE_IPA_PURE_CONST_BUG], [1], [Define if gcc has the ipa-pure-const bug.]) fi ;; @@ -6730,7 +6819,7 @@ AC_LINK_IFELSE( ]) AS_VAR_IF([ac_cv_header_stdatomic_h], [yes], [ - AC_DEFINE(HAVE_STD_ATOMIC, 1, + AC_DEFINE([HAVE_STD_ATOMIC], [1], [Has stdatomic.h with atomic_int and atomic_uintptr_t]) ]) @@ -6750,12 +6839,13 @@ AC_LINK_IFELSE( ]) AS_VAR_IF([ac_cv_builtin_atomic], [yes], [ - AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Has builtin __atomic_load_n() and __atomic_store_n() functions]) + AC_DEFINE([HAVE_BUILTIN_ATOMIC], [1], + [Has builtin __atomic_load_n() and __atomic_store_n() functions]) ]) # ensurepip option -AC_MSG_CHECKING(for ensurepip) -AC_ARG_WITH(ensurepip, +AC_MSG_CHECKING([for ensurepip]) +AC_ARG_WITH([ensurepip], [AS_HELP_STRING([--with-ensurepip@<:@=install|upgrade|no@:>@], ["install" or "upgrade" using bundled pip (default is upgrade)])], [], @@ -6766,13 +6856,13 @@ AC_ARG_WITH(ensurepip, [with_ensurepip=upgrade] ) ]) -AS_CASE($with_ensurepip, +AS_CASE([$with_ensurepip], [yes|upgrade],[ENSUREPIP=upgrade], [install],[ENSUREPIP=install], [no],[ENSUREPIP=no], [AC_MSG_ERROR([--with-ensurepip=upgrade|install|no])]) -AC_MSG_RESULT($ENSUREPIP) -AC_SUBST(ENSUREPIP) +AC_MSG_RESULT([$ENSUREPIP]) +AC_SUBST([ENSUREPIP]) # check if the dirent structure of a d_type field and DT_UNKNOWN is defined AC_CACHE_CHECK([if the dirent structure of a d_type field], [ac_cv_dirent_d_type], [ @@ -6790,7 +6880,7 @@ AC_LINK_IFELSE( ]) AS_VAR_IF([ac_cv_dirent_d_type], [yes], [ - AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, + AC_DEFINE([HAVE_DIRENT_D_TYPE], [1], [Define to 1 if the dirent structure has a d_type field]) ]) @@ -6817,7 +6907,7 @@ AC_LINK_IFELSE( ]) AS_VAR_IF([ac_cv_getrandom_syscall], [yes], [ - AC_DEFINE(HAVE_GETRANDOM_SYSCALL, 1, + AC_DEFINE([HAVE_GETRANDOM_SYSCALL], [1], [Define to 1 if the Linux getrandom() syscall is available]) ]) @@ -6843,7 +6933,7 @@ AC_LINK_IFELSE( ]) AS_VAR_IF([ac_cv_func_getrandom], [yes], [ - AC_DEFINE(HAVE_GETRANDOM, 1, + AC_DEFINE([HAVE_GETRANDOM], [1], [Define to 1 if the getrandom() function is available]) ]) @@ -6878,8 +6968,8 @@ AS_VAR_IF([GNULD], [yes], [ rpath_arg="-Wl,-rpath=" ]) -AC_MSG_CHECKING(for --with-openssl-rpath) -AC_ARG_WITH(openssl-rpath, +AC_MSG_CHECKING([for --with-openssl-rpath]) +AC_ARG_WITH([openssl-rpath], AS_HELP_STRING([--with-openssl-rpath=@<:@DIR|auto|no@:>@], [Set runtime library directory (rpath) for OpenSSL libraries, no (default): don't set rpath, @@ -6889,7 +6979,7 @@ AC_ARG_WITH(openssl-rpath, [], [with_openssl_rpath=no] ) -AS_CASE($with_openssl_rpath, +AS_CASE([$with_openssl_rpath], [auto|yes], [ OPENSSL_RPATH=auto dnl look for linker directories @@ -6909,7 +6999,7 @@ AS_CASE($with_openssl_rpath, AC_MSG_ERROR([--with-openssl-rpath "$with_openssl_rpath" is not a directory])) ] ) -AC_MSG_RESULT($OPENSSL_RPATH) +AC_MSG_RESULT([$OPENSSL_RPATH]) # This static linking is NOT OFFICIALLY SUPPORTED and not advertised. # Requires static OpenSSL build with position-independent code. Some features @@ -6990,50 +7080,55 @@ WITH_SAVE_ENV([ ]) # ssl module default cipher suite string -AH_TEMPLATE(PY_SSL_DEFAULT_CIPHERS, +AH_TEMPLATE([PY_SSL_DEFAULT_CIPHERS], [Default cipher suites list for ssl module. 1: Python's preferred selection, 2: leave OpenSSL defaults untouched, 0: custom string]) -AH_TEMPLATE(PY_SSL_DEFAULT_CIPHER_STRING, +AH_TEMPLATE([PY_SSL_DEFAULT_CIPHER_STRING], [Cipher suite string for PY_SSL_DEFAULT_CIPHERS=0] ) -AC_MSG_CHECKING(for --with-ssl-default-suites) -AC_ARG_WITH(ssl-default-suites, - AS_HELP_STRING([--with-ssl-default-suites=@<:@python|openssl|STRING@:>@], - [override default cipher suites string, - python: use Python's preferred selection (default), - openssl: leave OpenSSL's defaults untouched, - STRING: use a custom string, - python and STRING also set TLS 1.2 as minimum TLS version]), +AC_MSG_CHECKING([for --with-ssl-default-suites]) +AC_ARG_WITH( + [ssl-default-suites], + [AS_HELP_STRING( + [--with-ssl-default-suites=@<:@python|openssl|STRING@:>@], + [override default cipher suites string, + python: use Python's preferred selection (default), + openssl: leave OpenSSL's defaults untouched, + STRING: use a custom string, + python and STRING also set TLS 1.2 as minimum TLS version] + )], [ -AC_MSG_RESULT($withval) +AC_MSG_RESULT([$withval]) case "$withval" in python) - AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 1) + AC_DEFINE([PY_SSL_DEFAULT_CIPHERS], [1]) ;; openssl) - AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 2) + AC_DEFINE([PY_SSL_DEFAULT_CIPHERS], [2]) ;; *) - AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 0) - AC_DEFINE_UNQUOTED(PY_SSL_DEFAULT_CIPHER_STRING, "$withval") + AC_DEFINE([PY_SSL_DEFAULT_CIPHERS], [0]) + AC_DEFINE_UNQUOTED([PY_SSL_DEFAULT_CIPHER_STRING], ["$withval"]) ;; esac ], [ -AC_MSG_RESULT(python) -AC_DEFINE(PY_SSL_DEFAULT_CIPHERS, 1) +AC_MSG_RESULT([python]) +AC_DEFINE([PY_SSL_DEFAULT_CIPHERS], [1]) ]) # builtin hash modules default_hashlib_hashes="md5,sha1,sha2,sha3,blake2" AC_DEFINE([PY_BUILTIN_HASHLIB_HASHES], [], [enabled builtin hash modules] ) -AC_MSG_CHECKING(for --with-builtin-hashlib-hashes) -AC_ARG_WITH(builtin-hashlib-hashes, - AS_HELP_STRING([--with-builtin-hashlib-hashes=md5,sha1,sha2,sha3,blake2], - [builtin hash modules, - md5, sha1, sha2, sha3 (with shake), blake2]), +AC_MSG_CHECKING([for --with-builtin-hashlib-hashes]) +AC_ARG_WITH( + [builtin-hashlib-hashes], + [AS_HELP_STRING( + [--with-builtin-hashlib-hashes=md5,sha1,sha2,sha3,blake2], + [builtin hash modules, md5, sha1, sha2, sha3 (with shake), blake2] + )], [ AS_CASE([$with_builtin_hashlib_hashes], [yes], [with_builtin_hashlib_hashes=$default_hashlib_hashes], @@ -7041,13 +7136,14 @@ AC_ARG_WITH(builtin-hashlib-hashes, ) ], [with_builtin_hashlib_hashes=$default_hashlib_hashes]) -AC_MSG_RESULT($with_builtin_hashlib_hashes) -AC_DEFINE_UNQUOTED(PY_BUILTIN_HASHLIB_HASHES, "$with_builtin_hashlib_hashes") +AC_MSG_RESULT([$with_builtin_hashlib_hashes]) +AC_DEFINE_UNQUOTED([PY_BUILTIN_HASHLIB_HASHES], + ["$with_builtin_hashlib_hashes"]) as_save_IFS=$IFS IFS=, for builtin_hash in $with_builtin_hashlib_hashes; do - AS_CASE($builtin_hash, + AS_CASE([$builtin_hash], [md5], [with_builtin_md5=yes], [sha1], [with_builtin_sha1=yes], [sha2], [with_builtin_sha2=yes], @@ -7177,7 +7273,7 @@ AC_DEFUN([PY_STDLIB_MOD], [ m4_pushdef([modstate], [py_cv_module_$1])dnl dnl Check if module has been disabled by PY_STDLIB_MOD_SET_NA() AS_IF([test "$modstate" != "n/a"], [ - AS_IF(m4_ifblank([$2], [true], [$2]), + AS_IF([m4_ifblank([$2], [true], [$2])], [AS_IF([m4_ifblank([$3], [true], [$3])], [modstate=yes], [modstate=missing])], [modstate=disabled]) ]) @@ -7383,8 +7479,16 @@ PY_STDLIB_MOD([xxlimited_35], [test "$with_trace_refs" = "no"], [test "$ac_cv_fu AC_SUBST([MODULE_BLOCK]) # generate output files -AC_CONFIG_FILES(Makefile.pre Misc/python.pc Misc/python-embed.pc Misc/python-config.sh) -AC_CONFIG_FILES([Modules/Setup.bootstrap Modules/Setup.stdlib]) +AC_CONFIG_FILES(m4_normalize([ + Makefile.pre + Misc/python.pc + Misc/python-embed.pc + Misc/python-config.sh +])) +AC_CONFIG_FILES(m4_normalize([ + Modules/Setup.bootstrap + Modules/Setup.stdlib +])) AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix]) AC_OUTPUT From e3fcd9e4fa34f087985f0ab958c6effa20bf071e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 30 May 2023 23:18:55 -0700 Subject: [PATCH 0088/1206] [3.12] gh-103142: Update macOS installer to use OpenSSL 1.1.1u. (GH-105132) (cherry picked from commit f90d3f68db720bd6d0deda8cc0030339ccd43858) Co-authored-by: Ned Deily --- Mac/BuildScript/build-installer.py | 6 +++--- .../macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 177fc2044f694b..9729759434a9f4 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -246,9 +246,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.1.1t", - url="https://www.openssl.org/source/openssl-1.1.1t.tar.gz", - checksum='8dee9b24bdb1dcbf0c3d1e9b02fb8f6bf22165e807f45adeb7c9677536859d3b', + name="OpenSSL 1.1.1u", + url="https://www.openssl.org/source/openssl-1.1.1u.tar.gz", + checksum='e2f8d84b523eecd06c7be7626830370300fbcc15386bf5142d72758f6963ebc6', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst b/Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst new file mode 100644 index 00000000000000..1afd949d6a9f03 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst @@ -0,0 +1 @@ +Update macOS installer to use OpenSSL 1.1.1u. From 4729100239ce5486fce0ff4d62dad52c30e108c3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 00:48:28 -0700 Subject: [PATCH 0089/1206] [3.12] gh-105091: stable_abi.py: Remove "Unixy" check from --all on other platforms (GH-105092) (GH-105133) gh-105091: stable_abi.py: Remove "Unixy" check from --all on other platforms (GH-105092) (cherry picked from commit 0656d23d82cd5b88e578a26c65dd4a64414c833b) Co-authored-by: Petr Viktorin --- Tools/build/stable_abi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tools/build/stable_abi.py b/Tools/build/stable_abi.py index 88db93e935e9be..42b2dd92307bbf 100644 --- a/Tools/build/stable_abi.py +++ b/Tools/build/stable_abi.py @@ -684,7 +684,8 @@ def main(): if args.all: run_all_generators = True - args.unixy_check = True + if UNIXY: + args.unixy_check = True try: file = args.file.open('rb') From 2f8c22f1d6c22f018c78264937db66d52fb18869 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 03:11:39 -0700 Subject: [PATCH 0090/1206] [3.12] gh-105042: Disable unmatched parens syntax error in python tokenize (GH-105061) (#105120) gh-105042: Disable unmatched parens syntax error in python tokenize (GH-105061) (cherry picked from commit 70f315c2d6de87b0514ce16cc00a91a5b60a6098) Co-authored-by: Lysandros Nikolaou --- Lib/test/inspect_fodder.py | 5 +++ Lib/test/test_inspect.py | 4 ++- Lib/test/test_tokenize.py | 7 ++++ Parser/tokenizer.c | 65 +++++++++++++++++++------------------- Python/Python-tokenize.c | 2 +- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/Lib/test/inspect_fodder.py b/Lib/test/inspect_fodder.py index 567dfbab804867..60ba7aa78394e8 100644 --- a/Lib/test/inspect_fodder.py +++ b/Lib/test/inspect_fodder.py @@ -113,3 +113,8 @@ async def asyncf(self): # after asyncf - line 113 # end of WhichComments - line 114 # after WhichComments - line 115 + +# Test that getsource works on a line that includes +# a closing parenthesis with the opening paren being in another line +( +); after_closing = lambda: 1 diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index a7bd680d0f5bcc..6a49e3b5530e16 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -557,7 +557,8 @@ def test_getclasses(self): def test_getfunctions(self): functions = inspect.getmembers(mod, inspect.isfunction) - self.assertEqual(functions, [('eggs', mod.eggs), + self.assertEqual(functions, [('after_closing', mod.after_closing), + ('eggs', mod.eggs), ('lobbest', mod.lobbest), ('spam', mod.spam)]) @@ -641,6 +642,7 @@ def test_getsource(self): self.assertSourceEqual(git.abuse, 29, 39) self.assertSourceEqual(mod.StupidGit, 21, 51) self.assertSourceEqual(mod.lobbest, 75, 76) + self.assertSourceEqual(mod.after_closing, 120, 120) def test_getsourcefile(self): self.assertEqual(normcase(inspect.getsourcefile(mod.spam)), modfile) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index cd11dddd0fe51a..3adcc4e420671c 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1100,6 +1100,13 @@ def test_newline_after_parenthesized_block_with_comment(self): NEWLINE '\\n' (4, 1) (4, 2) """) + def test_closing_parenthesis_from_different_line(self): + self.check_tokenize("); x", """\ + OP ')' (1, 0) (1, 1) + OP ';' (1, 1) (1, 2) + NAME 'x' (1, 3) (1, 4) + """) + class GenerateTokensTest(TokenizeTest): def check_tokenize(self, s, expected): # Format the tokens in s in a table format. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 9058c67ada6486..b6d63e150cfbc4 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2496,41 +2496,42 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t case ')': case ']': case '}': - if (!tok->level) { - if (INSIDE_FSTRING(tok) && !current_tok->curly_bracket_depth && c == '}') { - return MAKE_TOKEN(syntaxerror(tok, "f-string: single '}' is not allowed")); - } + if (INSIDE_FSTRING(tok) && !current_tok->curly_bracket_depth && c == '}') { + return MAKE_TOKEN(syntaxerror(tok, "f-string: single '}' is not allowed")); + } + if (!tok->tok_extra_tokens && !tok->level) { return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c)); } - tok->level--; - int opening = tok->parenstack[tok->level]; - if (!((opening == '(' && c == ')') || - (opening == '[' && c == ']') || - (opening == '{' && c == '}'))) - { - /* If the opening bracket belongs to an f-string's expression - part (e.g. f"{)}") and the closing bracket is an arbitrary - nested expression, then instead of matching a different - syntactical construct with it; we'll throw an unmatched - parentheses error. */ - if (INSIDE_FSTRING(tok) && opening == '{') { - assert(current_tok->curly_bracket_depth >= 0); - int previous_bracket = current_tok->curly_bracket_depth - 1; - if (previous_bracket == current_tok->curly_bracket_expr_start_depth) { - return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c)); + if (tok->level > 0) { + tok->level--; + int opening = tok->parenstack[tok->level]; + if (!tok->tok_extra_tokens && !((opening == '(' && c == ')') || + (opening == '[' && c == ']') || + (opening == '{' && c == '}'))) { + /* If the opening bracket belongs to an f-string's expression + part (e.g. f"{)}") and the closing bracket is an arbitrary + nested expression, then instead of matching a different + syntactical construct with it; we'll throw an unmatched + parentheses error. */ + if (INSIDE_FSTRING(tok) && opening == '{') { + assert(current_tok->curly_bracket_depth >= 0); + int previous_bracket = current_tok->curly_bracket_depth - 1; + if (previous_bracket == current_tok->curly_bracket_expr_start_depth) { + return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c)); + } + } + if (tok->parenlinenostack[tok->level] != tok->lineno) { + return MAKE_TOKEN(syntaxerror(tok, + "closing parenthesis '%c' does not match " + "opening parenthesis '%c' on line %d", + c, opening, tok->parenlinenostack[tok->level])); + } + else { + return MAKE_TOKEN(syntaxerror(tok, + "closing parenthesis '%c' does not match " + "opening parenthesis '%c'", + c, opening)); } - } - if (tok->parenlinenostack[tok->level] != tok->lineno) { - return MAKE_TOKEN(syntaxerror(tok, - "closing parenthesis '%c' does not match " - "opening parenthesis '%c' on line %d", - c, opening, tok->parenlinenostack[tok->level])); - } - else { - return MAKE_TOKEN(syntaxerror(tok, - "closing parenthesis '%c' does not match " - "opening parenthesis '%c'", - c, opening)); } } diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 4eced66b617708..2de1daae8c0ddc 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -82,7 +82,7 @@ _tokenizer_error(struct tok_state *tok) msg = "invalid token"; break; case E_EOF: - if (tok->level) { + if (tok->level > 0) { PyErr_Format(PyExc_SyntaxError, "parenthesis '%c' was never closed", tok->parenstack[tok->level-1]); From c687946f6815a17bc5ceacaf3bbceba5b41e73fd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 03:11:53 -0700 Subject: [PATCH 0091/1206] [3.12] gh-105069: Add a readline-like callable to the tokenizer to consume input iteratively (GH-105070) (#105119) gh-105069: Add a readline-like callable to the tokenizer to consume input iteratively (GH-105070) (cherry picked from commit 9216e69a87d16d871625721ed5a8aa302511f367) Co-authored-by: Pablo Galindo Salgado --- Lib/inspect.py | 2 +- Lib/test/test_tokenize.py | 145 ++++++++++++++++++++---------- Lib/tokenize.py | 32 +++---- Parser/tokenizer.c | 136 +++++++++++++++++++++++++++- Parser/tokenizer.h | 2 + Python/Python-tokenize.c | 12 +-- Python/clinic/Python-tokenize.c.h | 41 +++++---- 7 files changed, 274 insertions(+), 96 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index 55530fc780b35c..15eefdb6570be4 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2203,7 +2203,7 @@ def _signature_strip_non_python_syntax(signature): add(string) if (string == ','): add(' ') - clean_signature = ''.join(text).strip() + clean_signature = ''.join(text).strip().replace("\n", "") return clean_signature, self_parameter diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 3adcc4e420671c..a9a2b7673887c9 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1,6 +1,6 @@ from test import support from test.support import os_helper -from tokenize import (tokenize, _tokenize, untokenize, NUMBER, NAME, OP, +from tokenize import (tokenize, untokenize, NUMBER, NAME, OP, STRING, ENDMARKER, ENCODING, tok_name, detect_encoding, open as tokenize_open, Untokenizer, generate_tokens, NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT, TokenInfo) @@ -51,6 +51,25 @@ def check_tokenize(self, s, expected): [" ENCODING 'utf-8' (0, 0) (0, 0)"] + expected.rstrip().splitlines()) + def test_invalid_readline(self): + def gen(): + yield "sdfosdg" + yield "sdfosdg" + with self.assertRaises(TypeError): + list(tokenize(gen().__next__)) + + def gen(): + yield b"sdfosdg" + yield b"sdfosdg" + with self.assertRaises(TypeError): + list(generate_tokens(gen().__next__)) + + def gen(): + yield "sdfosdg" + 1/0 + with self.assertRaises(ZeroDivisionError): + list(generate_tokens(gen().__next__)) + def test_implicit_newline(self): # Make sure that the tokenizer puts in an implicit NEWLINE # when the input lacks a trailing new line. @@ -1161,7 +1180,8 @@ class TestTokenizerAdheresToPep0263(TestCase): def _testFile(self, filename): path = os.path.join(os.path.dirname(__file__), filename) - TestRoundtrip.check_roundtrip(self, open(path, 'rb')) + with open(path, 'rb') as f: + TestRoundtrip.check_roundtrip(self, f) def test_utf8_coding_cookie_and_no_utf8_bom(self): f = 'tokenize_tests-utf8-coding-cookie-and-no-utf8-bom-sig.txt' @@ -1206,7 +1226,8 @@ def readline(): yield b'' # skip the initial encoding token and the end tokens - tokens = list(_tokenize(readline(), encoding='utf-8'))[:-2] + tokens = list(_generate_tokens_from_c_tokenizer(readline().__next__, encoding='utf-8', + extra_tokens=True))[:-2] expected_tokens = [TokenInfo(3, '"ЉЊЈÐЂ"', (1, 0), (1, 7), '"ЉЊЈÐЂ"\n')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") @@ -1475,13 +1496,13 @@ def test_tokenize(self): def mock_detect_encoding(readline): return encoding, [b'first', b'second'] - def mock__tokenize(readline, encoding): + def mock__tokenize(readline, encoding, **kwargs): nonlocal encoding_used encoding_used = encoding out = [] while True: try: - next_line = next(readline) + next_line = readline() except StopIteration: return out if next_line: @@ -1498,16 +1519,16 @@ def mock_readline(): return str(counter).encode() orig_detect_encoding = tokenize_module.detect_encoding - orig__tokenize = tokenize_module._tokenize + orig_c_token = tokenize_module._generate_tokens_from_c_tokenizer tokenize_module.detect_encoding = mock_detect_encoding - tokenize_module._tokenize = mock__tokenize + tokenize_module._generate_tokens_from_c_tokenizer = mock__tokenize try: results = tokenize(mock_readline) self.assertEqual(list(results)[1:], [b'first', b'second', b'1', b'2', b'3', b'4']) finally: tokenize_module.detect_encoding = orig_detect_encoding - tokenize_module._tokenize = orig__tokenize + tokenize_module._generate_tokens_from_c_tokenizer = orig_c_token self.assertEqual(encoding_used, encoding) @@ -1834,12 +1855,33 @@ class CTokenizeTest(TestCase): def check_tokenize(self, s, expected): # Format the tokens in s in a table format. # The ENDMARKER and final NEWLINE are omitted. + f = StringIO(s) with self.subTest(source=s): result = stringify_tokens_from_source( - _generate_tokens_from_c_tokenizer(s), s + _generate_tokens_from_c_tokenizer(f.readline), s ) self.assertEqual(result, expected.rstrip().splitlines()) + def test_encoding(self): + def readline(encoding): + yield "1+1".encode(encoding) + + expected = [ + TokenInfo(type=NUMBER, string='1', start=(1, 0), end=(1, 1), line='1+1\n'), + TokenInfo(type=OP, string='+', start=(1, 1), end=(1, 2), line='1+1\n'), + TokenInfo(type=NUMBER, string='1', start=(1, 2), end=(1, 3), line='1+1\n'), + TokenInfo(type=NEWLINE, string='\n', start=(1, 3), end=(1, 4), line='1+1\n'), + TokenInfo(type=ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') + ] + for encoding in ["utf-8", "latin-1", "utf-16"]: + with self.subTest(encoding=encoding): + tokens = list(_generate_tokens_from_c_tokenizer( + readline(encoding).__next__, + extra_tokens=True, + encoding=encoding, + )) + self.assertEqual(tokens, expected) + def test_int(self): self.check_tokenize('0xff <= 255', """\ @@ -2675,43 +2717,44 @@ def test_unicode(self): def test_invalid_syntax(self): def get_tokens(string): - return list(_generate_tokens_from_c_tokenizer(string)) - - self.assertRaises(SyntaxError, get_tokens, "(1+2]") - self.assertRaises(SyntaxError, get_tokens, "(1+2}") - self.assertRaises(SyntaxError, get_tokens, "{1+2]") - - self.assertRaises(SyntaxError, get_tokens, "1_") - self.assertRaises(SyntaxError, get_tokens, "1.2_") - self.assertRaises(SyntaxError, get_tokens, "1e2_") - self.assertRaises(SyntaxError, get_tokens, "1e+") - - self.assertRaises(SyntaxError, get_tokens, "\xa0") - self.assertRaises(SyntaxError, get_tokens, "€") - - self.assertRaises(SyntaxError, get_tokens, "0b12") - self.assertRaises(SyntaxError, get_tokens, "0b1_2") - self.assertRaises(SyntaxError, get_tokens, "0b2") - self.assertRaises(SyntaxError, get_tokens, "0b1_") - self.assertRaises(SyntaxError, get_tokens, "0b") - self.assertRaises(SyntaxError, get_tokens, "0o18") - self.assertRaises(SyntaxError, get_tokens, "0o1_8") - self.assertRaises(SyntaxError, get_tokens, "0o8") - self.assertRaises(SyntaxError, get_tokens, "0o1_") - self.assertRaises(SyntaxError, get_tokens, "0o") - self.assertRaises(SyntaxError, get_tokens, "0x1_") - self.assertRaises(SyntaxError, get_tokens, "0x") - self.assertRaises(SyntaxError, get_tokens, "1_") - self.assertRaises(SyntaxError, get_tokens, "012") - self.assertRaises(SyntaxError, get_tokens, "1.2_") - self.assertRaises(SyntaxError, get_tokens, "1e2_") - self.assertRaises(SyntaxError, get_tokens, "1e+") - - self.assertRaises(SyntaxError, get_tokens, "'sdfsdf") - self.assertRaises(SyntaxError, get_tokens, "'''sdfsdf''") - - self.assertRaises(SyntaxError, get_tokens, "("*1000+"a"+")"*1000) - self.assertRaises(SyntaxError, get_tokens, "]") + the_string = StringIO(string) + return list(_generate_tokens_from_c_tokenizer(the_string.readline)) + + for case in [ + "(1+2]", + "(1+2}", + "{1+2]", + "1_", + "1.2_", + "1e2_", + "1e+", + + "\xa0", + "€", + "0b12", + "0b1_2", + "0b2", + "0b1_", + "0b", + "0o18", + "0o1_8", + "0o8", + "0o1_", + "0o", + "0x1_", + "0x", + "1_", + "012", + "1.2_", + "1e2_", + "1e+", + "'sdfsdf", + "'''sdfsdf''", + "("*1000+"a"+")"*1000, + "]", + ]: + with self.subTest(case=case): + self.assertRaises(SyntaxError, get_tokens, case) def test_max_indent(self): MAXINDENT = 100 @@ -2722,20 +2765,24 @@ def generate_source(indents): return source valid = generate_source(MAXINDENT - 1) - tokens = list(_generate_tokens_from_c_tokenizer(valid)) + the_input = StringIO(valid) + tokens = list(_generate_tokens_from_c_tokenizer(the_input.readline)) self.assertEqual(tokens[-2].type, DEDENT) self.assertEqual(tokens[-1].type, ENDMARKER) compile(valid, "", "exec") invalid = generate_source(MAXINDENT) - self.assertRaises(SyntaxError, lambda: list(_generate_tokens_from_c_tokenizer(invalid))) + the_input = StringIO(invalid) + self.assertRaises(SyntaxError, lambda: list(_generate_tokens_from_c_tokenizer(the_input.readline))) self.assertRaises( IndentationError, compile, invalid, "", "exec" ) def test_continuation_lines_indentation(self): def get_tokens(string): - return [(kind, string) for (kind, string, *_) in _generate_tokens_from_c_tokenizer(string)] + the_string = StringIO(string) + return [(kind, string) for (kind, string, *_) + in _generate_tokens_from_c_tokenizer(the_string.readline)] code = dedent(""" def fib(n): diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 4895e94d1dfda7..380dc2ab468b57 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -34,6 +34,7 @@ import sys from token import * from token import EXACT_TOKEN_TYPES +import _tokenize cookie_re = re.compile(r'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)', re.ASCII) blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) @@ -443,12 +444,7 @@ def tokenize(readline): # BOM will already have been stripped. encoding = "utf-8" yield TokenInfo(ENCODING, encoding, (0, 0), (0, 0), '') - yield from _tokenize(rl_gen, encoding) - -def _tokenize(rl_gen, encoding): - source = b"".join(rl_gen).decode(encoding) - for token in _generate_tokens_from_c_tokenizer(source, extra_tokens=True): - yield token + yield from _generate_tokens_from_c_tokenizer(rl_gen.__next__, encoding, extra_tokens=True) def generate_tokens(readline): """Tokenize a source reading Python code as unicode strings. @@ -456,16 +452,7 @@ def generate_tokens(readline): This has the same API as tokenize(), except that it expects the *readline* callable to return str objects instead of bytes. """ - def _gen(): - while True: - try: - line = readline() - except StopIteration: - return - if not line: - return - yield line.encode() - return _tokenize(_gen(), 'utf-8') + return _generate_tokens_from_c_tokenizer(readline, extra_tokens=True) def main(): import argparse @@ -502,9 +489,9 @@ def error(message, filename=None, location=None): tokens = list(tokenize(f.readline)) else: filename = "" - tokens = _tokenize( + tokens = _generate_tokens_from_c_tokenizer( (x.encode('utf-8') for x in iter(sys.stdin.readline, "") - ), "utf-8") + ), "utf-8", extra_tokens=True) # Output the tokenization @@ -531,10 +518,13 @@ def error(message, filename=None, location=None): perror("unexpected error: %s" % err) raise -def _generate_tokens_from_c_tokenizer(source, extra_tokens=False): +def _generate_tokens_from_c_tokenizer(source, encoding=None, extra_tokens=False): """Tokenize a source reading Python code as unicode strings using the internal C tokenizer""" - import _tokenize as c_tokenizer - for info in c_tokenizer.TokenizerIter(source, extra_tokens=extra_tokens): + if encoding is None: + it = _tokenize.TokenizerIter(source, extra_tokens=extra_tokens) + else: + it = _tokenize.TokenizerIter(source, encoding=encoding, extra_tokens=extra_tokens) + for info in it: yield TokenInfo._make(info) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index b6d63e150cfbc4..fae613e3a18c1d 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -103,6 +103,7 @@ tok_new(void) tok->filename = NULL; tok->decoding_readline = NULL; tok->decoding_buffer = NULL; + tok->readline = NULL; tok->type_comments = 0; tok->async_hacks = 0; tok->async_def = 0; @@ -139,8 +140,9 @@ static char * error_ret(struct tok_state *tok) /* XXX */ { tok->decoding_erred = 1; - if (tok->fp != NULL && tok->buf != NULL) /* see _PyTokenizer_Free */ + if ((tok->fp != NULL || tok->readline != NULL) && tok->buf != NULL) {/* see _PyTokenizer_Free */ PyMem_Free(tok->buf); + } tok->buf = tok->cur = tok->inp = NULL; tok->start = NULL; tok->end = NULL; @@ -900,6 +902,33 @@ _PyTokenizer_FromString(const char *str, int exec_input, int preserve_crlf) return tok; } +struct tok_state * +_PyTokenizer_FromReadline(PyObject* readline, const char* enc, + int exec_input, int preserve_crlf) +{ + struct tok_state *tok = tok_new(); + if (tok == NULL) + return NULL; + if ((tok->buf = (char *)PyMem_Malloc(BUFSIZ)) == NULL) { + _PyTokenizer_Free(tok); + return NULL; + } + tok->cur = tok->inp = tok->buf; + tok->end = tok->buf + BUFSIZ; + tok->fp = NULL; + if (enc != NULL) { + tok->encoding = new_string(enc, strlen(enc), tok); + if (!tok->encoding) { + _PyTokenizer_Free(tok); + return NULL; + } + } + tok->decoding_state = STATE_NORMAL; + Py_INCREF(readline); + tok->readline = readline; + return tok; +} + /* Set up tokenizer for UTF-8 string */ struct tok_state * @@ -969,8 +998,9 @@ _PyTokenizer_Free(struct tok_state *tok) } Py_XDECREF(tok->decoding_readline); Py_XDECREF(tok->decoding_buffer); + Py_XDECREF(tok->readline); Py_XDECREF(tok->filename); - if (tok->fp != NULL && tok->buf != NULL) { + if ((tok->readline != NULL || tok->fp != NULL ) && tok->buf != NULL) { PyMem_Free(tok->buf); } if (tok->input) { @@ -1021,6 +1051,71 @@ tok_readline_raw(struct tok_state *tok) return 1; } +static int +tok_readline_string(struct tok_state* tok) { + PyObject* line = NULL; + PyObject* raw_line = PyObject_CallNoArgs(tok->readline); + if (raw_line == NULL) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + return 1; + } + error_ret(tok); + goto error; + } + if(tok->encoding != NULL) { + if (!PyBytes_Check(raw_line)) { + PyErr_Format(PyExc_TypeError, "readline() returned a non-bytes object"); + error_ret(tok); + goto error; + } + line = PyUnicode_Decode(PyBytes_AS_STRING(raw_line), PyBytes_GET_SIZE(raw_line), + tok->encoding, "replace"); + Py_CLEAR(raw_line); + if (line == NULL) { + error_ret(tok); + goto error; + } + } else { + if(!PyUnicode_Check(raw_line)) { + PyErr_Format(PyExc_TypeError, "readline() returned a non-string object"); + error_ret(tok); + goto error; + } + line = raw_line; + raw_line = NULL; + } + Py_ssize_t buflen; + const char* buf = PyUnicode_AsUTF8AndSize(line, &buflen); + if (buf == NULL) { + error_ret(tok); + goto error; + } + + // Make room for the null terminator *and* potentially + // an extra newline character that we may need to artificially + // add. + size_t buffer_size = buflen + 2; + if (!tok_reserve_buf(tok, buffer_size)) { + goto error; + } + memcpy(tok->inp, buf, buflen); + tok->inp += buflen; + *tok->inp = '\0'; + + if (tok->start == NULL) { + tok->buf = tok->cur; + } + tok->line_start = tok->cur; + + Py_DECREF(line); + return 1; +error: + Py_XDECREF(raw_line); + Py_XDECREF(line); + return 0; +} + static int tok_underflow_string(struct tok_state *tok) { char *end = strchr(tok->inp, '\n'); @@ -1195,6 +1290,38 @@ tok_underflow_file(struct tok_state *tok) { return tok->done == E_OK; } +static int +tok_underflow_readline(struct tok_state* tok) { + assert(tok->decoding_state == STATE_NORMAL); + assert(tok->fp == NULL && tok->input == NULL && tok->decoding_readline == NULL); + if (tok->start == NULL && !INSIDE_FSTRING(tok)) { + tok->cur = tok->inp = tok->buf; + } + if (!tok_readline_string(tok)) { + return 0; + } + if (tok->inp == tok->cur) { + tok->done = E_EOF; + return 0; + } + if (tok->inp[-1] != '\n') { + assert(tok->inp + 1 < tok->end); + /* Last line does not end in \n, fake one */ + *tok->inp++ = '\n'; + *tok->inp = '\0'; + } + + ADVANCE_LINENO(); + /* The default encoding is UTF-8, so make sure we don't have any + non-UTF-8 sequences in it. */ + if (!tok->encoding && !ensure_utf8(tok->cur, tok)) { + error_ret(tok); + return 0; + } + assert(tok->done == E_OK); + return tok->done == E_OK; +} + #if defined(Py_DEBUG) static void print_escape(FILE *f, const char *s, Py_ssize_t size) @@ -1238,7 +1365,10 @@ tok_nextc(struct tok_state *tok) if (tok->done != E_OK) { return EOF; } - if (tok->fp == NULL) { + if (tok->readline) { + rc = tok_underflow_readline(tok); + } + else if (tok->fp == NULL) { rc = tok_underflow_string(tok); } else if (tok->prompt != NULL) { diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 02749e355da812..600d4297b6865a 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -109,6 +109,7 @@ struct tok_state { expression (cf. issue 16806) */ PyObject *decoding_readline; /* open(...).readline */ PyObject *decoding_buffer; + PyObject *readline; /* readline() function */ const char* enc; /* Encoding for the current str. */ char* str; /* Source string being tokenized (if tokenizing from a string)*/ char* input; /* Tokenizer's newline translated copy of the string. */ @@ -137,6 +138,7 @@ struct tok_state { extern struct tok_state *_PyTokenizer_FromString(const char *, int, int); extern struct tok_state *_PyTokenizer_FromUTF8(const char *, int, int); +extern struct tok_state *_PyTokenizer_FromReadline(PyObject*, const char*, int, int); extern struct tok_state *_PyTokenizer_FromFile(FILE *, const char*, const char *, const char *); extern void _PyTokenizer_Free(struct tok_state *); diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 2de1daae8c0ddc..a7933b2d6b0187 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -37,15 +37,17 @@ typedef struct @classmethod _tokenizer.tokenizeriter.__new__ as tokenizeriter_new - source: str + readline: object + / * extra_tokens: bool + encoding: str(c_default="NULL") = 'utf-8' [clinic start generated code]*/ static PyObject * -tokenizeriter_new_impl(PyTypeObject *type, const char *source, - int extra_tokens) -/*[clinic end generated code: output=f6f9d8b4beec8106 input=90dc5b6a5df180c2]*/ +tokenizeriter_new_impl(PyTypeObject *type, PyObject *readline, + int extra_tokens, const char *encoding) +/*[clinic end generated code: output=7501a1211683ce16 input=f7dddf8a613ae8bd]*/ { tokenizeriterobject *self = (tokenizeriterobject *)type->tp_alloc(type, 0); if (self == NULL) { @@ -55,7 +57,7 @@ tokenizeriter_new_impl(PyTypeObject *type, const char *source, if (filename == NULL) { return NULL; } - self->tok = _PyTokenizer_FromUTF8(source, 1, 1); + self->tok = _PyTokenizer_FromReadline(readline, encoding, 1, 1); if (self->tok == NULL) { Py_DECREF(filename); return NULL; diff --git a/Python/clinic/Python-tokenize.c.h b/Python/clinic/Python-tokenize.c.h index 7e779388a92dbf..28f5075826e36f 100644 --- a/Python/clinic/Python-tokenize.c.h +++ b/Python/clinic/Python-tokenize.c.h @@ -9,8 +9,8 @@ preserve static PyObject * -tokenizeriter_new_impl(PyTypeObject *type, const char *source, - int extra_tokens); +tokenizeriter_new_impl(PyTypeObject *type, PyObject *readline, + int extra_tokens, const char *encoding); static PyObject * tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) @@ -25,7 +25,7 @@ tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(source), &_Py_ID(extra_tokens), }, + .ob_item = { &_Py_ID(extra_tokens), &_Py_ID(encoding), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -34,43 +34,50 @@ tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"source", "extra_tokens", NULL}; + static const char * const _keywords[] = {"", "extra_tokens", "encoding", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "tokenizeriter", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; + PyObject *argsbuf[3]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); - const char *source; + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2; + PyObject *readline; int extra_tokens; + const char *encoding = NULL; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 1, argsbuf); if (!fastargs) { goto exit; } - if (!PyUnicode_Check(fastargs[0])) { - _PyArg_BadArgument("tokenizeriter", "argument 'source'", "str", fastargs[0]); + readline = fastargs[0]; + extra_tokens = PyObject_IsTrue(fastargs[1]); + if (extra_tokens < 0) { goto exit; } - Py_ssize_t source_length; - source = PyUnicode_AsUTF8AndSize(fastargs[0], &source_length); - if (source == NULL) { + if (!noptargs) { + goto skip_optional_kwonly; + } + if (!PyUnicode_Check(fastargs[2])) { + _PyArg_BadArgument("tokenizeriter", "argument 'encoding'", "str", fastargs[2]); goto exit; } - if (strlen(source) != (size_t)source_length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); + Py_ssize_t encoding_length; + encoding = PyUnicode_AsUTF8AndSize(fastargs[2], &encoding_length); + if (encoding == NULL) { goto exit; } - extra_tokens = PyObject_IsTrue(fastargs[1]); - if (extra_tokens < 0) { + if (strlen(encoding) != (size_t)encoding_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - return_value = tokenizeriter_new_impl(type, source, extra_tokens); +skip_optional_kwonly: + return_value = tokenizeriter_new_impl(type, readline, extra_tokens, encoding); exit: return return_value; } -/*[clinic end generated code: output=940b564c67f6e0e2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=48be65a2808bdfa6 input=a9049054013a1b77]*/ From 01b42f9559b614d729c3f055d09269db13d2433c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 31 May 2023 14:04:21 +0200 Subject: [PATCH 0092/1206] [3.12] gh-105096: Reformat wave documentation (#105136) (#105138) gh-105096: Reformat wave documentation (#105136) Add ".. class::" markups in the wave documentation. * Reformat also wave.py (minor PEP 8 changes). * Remove redundant "import struct": it's already imported at top level. * Remove wave.rst from .nitignore (cherry picked from commit 85e5d03163cac106ac8ec142ef03f1349a48948b) --- Doc/library/wave.rst | 205 ++++++++++++++++++++++--------------------- Doc/tools/.nitignore | 1 - Lib/wave.py | 5 +- 3 files changed, 109 insertions(+), 102 deletions(-) diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index 04a28d97d619eb..bb85dbe365c3f4 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -11,8 +11,9 @@ -------------- -The :mod:`wave` module provides a convenient interface to the WAV sound format. -Only PCM encoded wave files are supported. +The :mod:`wave` module provides a convenient interface to the Waveform Audio +"WAVE" (or "WAV") file format. Only uncompressed PCM encoded wave files are +supported. .. versionchanged:: 3.12 @@ -41,13 +42,12 @@ The :mod:`wave` module defines the following function and exception: value for *mode*. If you pass in a file-like object, the wave object will not close it when its - :meth:`close` method is called; it is the caller's responsibility to close + ``close()`` method is called; it is the caller's responsibility to close the file object. The :func:`.open` function may be used in a :keyword:`with` statement. When - the :keyword:`!with` block completes, the :meth:`Wave_read.close() - ` or :meth:`Wave_write.close() - ` method is called. + the :keyword:`!with` block completes, the :meth:`Wave_read.close()` or + :meth:`Wave_write.close()` method is called. .. versionchanged:: 3.4 Added support for unseekable files. @@ -63,87 +63,91 @@ The :mod:`wave` module defines the following function and exception: Wave_read Objects ----------------- -Wave_read objects, as returned by :func:`.open`, have the following methods: +.. class:: Wave_read + Read a WAV file. -.. method:: Wave_read.close() + Wave_read objects, as returned by :func:`.open`, have the following methods: - Close the stream if it was opened by :mod:`wave`, and make the instance - unusable. This is called automatically on object collection. + .. method:: close() -.. method:: Wave_read.getnchannels() + Close the stream if it was opened by :mod:`wave`, and make the instance + unusable. This is called automatically on object collection. - Returns number of audio channels (``1`` for mono, ``2`` for stereo). + .. method:: getnchannels() -.. method:: Wave_read.getsampwidth() + Returns number of audio channels (``1`` for mono, ``2`` for stereo). - Returns sample width in bytes. + .. method:: getsampwidth() -.. method:: Wave_read.getframerate() + Returns sample width in bytes. - Returns sampling frequency. + .. method:: getframerate() -.. method:: Wave_read.getnframes() + Returns sampling frequency. - Returns number of audio frames. + .. method:: getnframes() -.. method:: Wave_read.getcomptype() + Returns number of audio frames. - Returns compression type (``'NONE'`` is the only supported type). + .. method:: getcomptype() -.. method:: Wave_read.getcompname() + Returns compression type (``'NONE'`` is the only supported type). - Human-readable version of :meth:`getcomptype`. Usually ``'not compressed'`` - parallels ``'NONE'``. + .. method:: getcompname() -.. method:: Wave_read.getparams() + Human-readable version of :meth:`getcomptype`. Usually ``'not compressed'`` + parallels ``'NONE'``. - Returns a :func:`~collections.namedtuple` ``(nchannels, sampwidth, - framerate, nframes, comptype, compname)``, equivalent to output of the - :meth:`get\*` methods. + .. method:: getparams() -.. method:: Wave_read.readframes(n) + Returns a :func:`~collections.namedtuple` ``(nchannels, sampwidth, + framerate, nframes, comptype, compname)``, equivalent to output of the + ``get*()`` methods. - Reads and returns at most *n* frames of audio, as a :class:`bytes` object. + .. method:: readframes(n) -.. method:: Wave_read.rewind() + Reads and returns at most *n* frames of audio, as a :class:`bytes` object. - Rewind the file pointer to the beginning of the audio stream. -The following two methods are defined for compatibility with the :mod:`aifc` -module, and don't do anything interesting. + .. method:: rewind() + Rewind the file pointer to the beginning of the audio stream. -.. method:: Wave_read.getmarkers() + The following two methods are defined for compatibility with the :mod:`aifc` + module, and don't do anything interesting. - Returns ``None``. + .. method:: getmarkers() -.. method:: Wave_read.getmark(id) + Returns ``None``. - Raise an error. -The following two methods define a term "position" which is compatible between -them, and is otherwise implementation dependent. + .. method:: getmark(id) + Raise an error. -.. method:: Wave_read.setpos(pos) + The following two methods define a term "position" which is compatible between + them, and is otherwise implementation dependent. - Set the file pointer to the specified position. + .. method:: setpos(pos) -.. method:: Wave_read.tell() + Set the file pointer to the specified position. - Return current file pointer position. + + .. method:: tell() + + Return current file pointer position. .. _wave-write-objects: @@ -151,97 +155,100 @@ them, and is otherwise implementation dependent. Wave_write Objects ------------------ -For seekable output streams, the ``wave`` header will automatically be updated -to reflect the number of frames actually written. For unseekable streams, the -*nframes* value must be accurate when the first frame data is written. An -accurate *nframes* value can be achieved either by calling -:meth:`~Wave_write.setnframes` or :meth:`~Wave_write.setparams` with the number -of frames that will be written before :meth:`~Wave_write.close` is called and -then using :meth:`~Wave_write.writeframesraw` to write the frame data, or by -calling :meth:`~Wave_write.writeframes` with all of the frame data to be -written. In the latter case :meth:`~Wave_write.writeframes` will calculate -the number of frames in the data and set *nframes* accordingly before writing -the frame data. +.. class:: Wave_write -Wave_write objects, as returned by :func:`.open`, have the following methods: + Write a WAV file. -.. versionchanged:: 3.4 - Added support for unseekable files. + Wave_write objects, as returned by :func:`.open`. + For seekable output streams, the ``wave`` header will automatically be updated + to reflect the number of frames actually written. For unseekable streams, the + *nframes* value must be accurate when the first frame data is written. An + accurate *nframes* value can be achieved either by calling + :meth:`setnframes` or :meth:`setparams` with the number + of frames that will be written before :meth:`close` is called and + then using :meth:`writeframesraw` to write the frame data, or by + calling :meth:`writeframes` with all of the frame data to be + written. In the latter case :meth:`writeframes` will calculate + the number of frames in the data and set *nframes* accordingly before writing + the frame data. -.. method:: Wave_write.close() + .. versionchanged:: 3.4 + Added support for unseekable files. - Make sure *nframes* is correct, and close the file if it was opened by - :mod:`wave`. This method is called upon object collection. It will raise - an exception if the output stream is not seekable and *nframes* does not - match the number of frames actually written. + Wave_write objects have the following methods: + .. method:: close() -.. method:: Wave_write.setnchannels(n) + Make sure *nframes* is correct, and close the file if it was opened by + :mod:`wave`. This method is called upon object collection. It will raise + an exception if the output stream is not seekable and *nframes* does not + match the number of frames actually written. - Set the number of channels. + .. method:: setnchannels(n) -.. method:: Wave_write.setsampwidth(n) + Set the number of channels. - Set the sample width to *n* bytes. + .. method:: setsampwidth(n) -.. method:: Wave_write.setframerate(n) + Set the sample width to *n* bytes. - Set the frame rate to *n*. - .. versionchanged:: 3.2 - A non-integral input to this method is rounded to the nearest - integer. + .. method:: setframerate(n) + Set the frame rate to *n*. -.. method:: Wave_write.setnframes(n) + .. versionchanged:: 3.2 + A non-integral input to this method is rounded to the nearest + integer. - Set the number of frames to *n*. This will be changed later if the number - of frames actually written is different (this update attempt will - raise an error if the output stream is not seekable). + .. method:: setnframes(n) -.. method:: Wave_write.setcomptype(type, name) + Set the number of frames to *n*. This will be changed later if the number + of frames actually written is different (this update attempt will + raise an error if the output stream is not seekable). - Set the compression type and description. At the moment, only compression type - ``NONE`` is supported, meaning no compression. + .. method:: setcomptype(type, name) -.. method:: Wave_write.setparams(tuple) + Set the compression type and description. At the moment, only compression type + ``NONE`` is supported, meaning no compression. - The *tuple* should be ``(nchannels, sampwidth, framerate, nframes, comptype, - compname)``, with values valid for the :meth:`set\*` methods. Sets all - parameters. + .. method:: setparams(tuple) -.. method:: Wave_write.tell() + The *tuple* should be ``(nchannels, sampwidth, framerate, nframes, comptype, + compname)``, with values valid for the ``set*()`` methods. Sets all + parameters. - Return current position in the file, with the same disclaimer for the - :meth:`Wave_read.tell` and :meth:`Wave_read.setpos` methods. + .. method:: tell() -.. method:: Wave_write.writeframesraw(data) + Return current position in the file, with the same disclaimer for the + :meth:`Wave_read.tell` and :meth:`Wave_read.setpos` methods. - Write audio frames, without correcting *nframes*. - .. versionchanged:: 3.4 - Any :term:`bytes-like object` is now accepted. + .. method:: writeframesraw(data) + Write audio frames, without correcting *nframes*. -.. method:: Wave_write.writeframes(data) + .. versionchanged:: 3.4 + Any :term:`bytes-like object` is now accepted. - Write audio frames and make sure *nframes* is correct. It will raise an - error if the output stream is not seekable and the total number of frames - that have been written after *data* has been written does not match the - previously set value for *nframes*. - .. versionchanged:: 3.4 - Any :term:`bytes-like object` is now accepted. + .. method:: writeframes(data) + Write audio frames and make sure *nframes* is correct. It will raise an + error if the output stream is not seekable and the total number of frames + that have been written after *data* has been written does not match the + previously set value for *nframes*. -Note that it is invalid to set any parameters after calling :meth:`writeframes` -or :meth:`writeframesraw`, and any attempt to do so will raise -:exc:`wave.Error`. + .. versionchanged:: 3.4 + Any :term:`bytes-like object` is now accepted. + Note that it is invalid to set any parameters after calling :meth:`writeframes` + or :meth:`writeframesraw`, and any attempt to do so will raise + :exc:`wave.Error`. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 1d3503bf06f085..3a34c0b2cbfff5 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -236,7 +236,6 @@ Doc/library/urllib.error.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst Doc/library/uuid.rst -Doc/library/wave.rst Doc/library/weakref.rst Doc/library/webbrowser.rst Doc/library/winreg.rst diff --git a/Lib/wave.py b/Lib/wave.py index d5858e5d4b80da..4b0c683f6b5e2d 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -92,6 +92,7 @@ class Error(Exception): _wave_params = namedtuple('_wave_params', 'nchannels sampwidth framerate nframes comptype compname') + def _byteswap(data, width): swapped_data = bytearray(len(data)) @@ -104,7 +105,6 @@ def _byteswap(data, width): class _Chunk: def __init__(self, file, align=True, bigendian=True, inclheader=False): - import struct self.closed = False self.align = align # whether to align to word (2-byte) boundaries if bigendian: @@ -214,7 +214,6 @@ def skip(self): raise EOFError - class Wave_read: """Variables used in this class: @@ -411,6 +410,7 @@ def _read_fmt_chunk(self, chunk): self._comptype = 'NONE' self._compname = 'not compressed' + class Wave_write: """Variables used in this class: @@ -638,6 +638,7 @@ def _patchheader(self): self._file.seek(curpos, 0) self._datalength = self._datawritten + def open(f, mode=None): if mode is None: if hasattr(f, 'mode'): From d3c21a9f3327d8bed58b47e6e5ada7c95b0a7bde Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 06:46:26 -0700 Subject: [PATCH 0093/1206] [3.12] gh-97933: add LOAD_FAST_AND_CLEAR to 3.12 What's New bytecode section (GH-105126) (#105142) --- Doc/whatsnew/3.12.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ef9e4012437f7d..c54c5d32ca06bf 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -911,6 +911,9 @@ CPython bytecode changes * Remove the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` instructions. (Contributed by Irit Katriel in :gh:`102859`.) +* Add the :opcode:`LOAD_FAST_AND_CLEAR` instruction as part of the + implementation of :pep:`709`. (Contributed by Carl Meyer in :gh:`101441`.) + * Add the :opcode:`LOAD_FROM_DICT_OR_DEREF`, :opcode:`LOAD_FROM_DICT_OR_GLOBALS`, and :opcode:`LOAD_LOCALS` opcodes as part of the implementation of :pep:`695`. Remove the :opcode:`!LOAD_CLASSDEREF` opcode, which can be replaced with From 4f477c796cbd6db14fa102fecd5afc38a3604850 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 06:47:03 -0700 Subject: [PATCH 0094/1206] [3.12] gh-87729: add LOAD_SUPER_ATTR to 3.12 What's New (GH-105125) (#105143) --- Doc/whatsnew/3.12.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index c54c5d32ca06bf..b496da30c73fc4 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -899,6 +899,10 @@ Optimizations the :mod:`tokenize` module. (Contributed by Marta Gómez Macías and Pablo Galindo in :gh:`102856`.) +* Speed up :func:`super` method calls and attribute loads via the + new :opcode:`LOAD_SUPER_ATTR` instruction. (Contributed by Carl Meyer and + Vladimir Matveev in :gh:`103497`.) + CPython bytecode changes ======================== @@ -920,6 +924,9 @@ CPython bytecode changes :opcode:`LOAD_LOCALS` plus :opcode:`LOAD_FROM_DICT_OR_DEREF`. (Contributed by Jelle Zijlstra in :gh:`103764`.) +* Add the :opcode:`LOAD_SUPER_ATTR` instruction. (Contributed by Carl Meyer and + Vladimir Matveev in :gh:`103497`.) + Demos and Tools =============== From 076f3cda140a45b08c2c9518bc19624aae50d3a3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 10:35:03 -0700 Subject: [PATCH 0095/1206] [3.12] gh-105144: Runtime-checkable protocols: move all 'sanity checks' to `_ProtocolMeta.__subclasscheck__` (GH-105152) (#105160) (cherry picked from commit c05c31db8c9dfd708b9857bb57f8e5f3ce40266d) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 109 +++++++++++++++--- Lib/typing.py | 34 +++--- ...-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst | 5 + 3 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ae9878f872fd78..5480a981ad5647 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1,5 +1,6 @@ import contextlib import collections +import collections.abc from collections import defaultdict from functools import lru_cache, wraps import inspect @@ -2722,19 +2723,41 @@ def x(self): ... self.assertIsSubclass(C, PG) self.assertIsSubclass(BadP, PG) - with self.assertRaises(TypeError): + no_subscripted_generics = ( + "Subscripted generics cannot be used with class and instance checks" + ) + + with self.assertRaisesRegex(TypeError, no_subscripted_generics): issubclass(C, PG[T]) - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, no_subscripted_generics): issubclass(C, PG[C]) - with self.assertRaises(TypeError): + + only_runtime_checkable_protocols = ( + "Instance and class checks can only be used with " + "@runtime_checkable protocols" + ) + + with self.assertRaisesRegex(TypeError, only_runtime_checkable_protocols): issubclass(C, BadP) - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, only_runtime_checkable_protocols): issubclass(C, BadPG) - with self.assertRaises(TypeError): + + with self.assertRaisesRegex(TypeError, no_subscripted_generics): issubclass(P, PG[T]) - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, no_subscripted_generics): issubclass(PG, PG[int]) + only_classes_allowed = r"issubclass\(\) arg 1 must be a class" + + with self.assertRaisesRegex(TypeError, only_classes_allowed): + issubclass(1, P) + with self.assertRaisesRegex(TypeError, only_classes_allowed): + issubclass(1, PG) + with self.assertRaisesRegex(TypeError, only_classes_allowed): + issubclass(1, BadP) + with self.assertRaisesRegex(TypeError, only_classes_allowed): + issubclass(1, BadPG) + def test_protocols_issubclass_non_callable(self): class C: x = 1 @@ -2743,12 +2766,19 @@ class C: class PNonCall(Protocol): x = 1 - with self.assertRaises(TypeError): + non_callable_members_illegal = ( + "Protocols with non-method members don't support issubclass()" + ) + + with self.assertRaisesRegex(TypeError, non_callable_members_illegal): issubclass(C, PNonCall) + self.assertIsInstance(C(), PNonCall) PNonCall.register(C) - with self.assertRaises(TypeError): + + with self.assertRaisesRegex(TypeError, non_callable_members_illegal): issubclass(C, PNonCall) + self.assertIsInstance(C(), PNonCall) # check that non-protocol subclasses are not affected @@ -2759,7 +2789,8 @@ class D(PNonCall): ... D.register(C) self.assertIsSubclass(C, D) self.assertIsInstance(C(), D) - with self.assertRaises(TypeError): + + with self.assertRaisesRegex(TypeError, non_callable_members_illegal): issubclass(D, PNonCall) def test_no_weird_caching_with_issubclass_after_isinstance(self): @@ -2778,7 +2809,10 @@ def __init__(self) -> None: # as the cached result of the isinstance() check immediately above # would mean the issubclass() call would short-circuit # before we got to the "raise TypeError" line - with self.assertRaises(TypeError): + with self.assertRaisesRegex( + TypeError, + "Protocols with non-method members don't support issubclass()" + ): issubclass(Eggs, Spam) def test_no_weird_caching_with_issubclass_after_isinstance_2(self): @@ -2795,7 +2829,10 @@ class Eggs: ... # as the cached result of the isinstance() check immediately above # would mean the issubclass() call would short-circuit # before we got to the "raise TypeError" line - with self.assertRaises(TypeError): + with self.assertRaisesRegex( + TypeError, + "Protocols with non-method members don't support issubclass()" + ): issubclass(Eggs, Spam) def test_no_weird_caching_with_issubclass_after_isinstance_3(self): @@ -2816,7 +2853,10 @@ def __getattr__(self, attr): # as the cached result of the isinstance() check immediately above # would mean the issubclass() call would short-circuit # before we got to the "raise TypeError" line - with self.assertRaises(TypeError): + with self.assertRaisesRegex( + TypeError, + "Protocols with non-method members don't support issubclass()" + ): issubclass(Eggs, Spam) def test_no_weird_caching_with_issubclass_after_isinstance_pep695(self): @@ -2835,7 +2875,10 @@ def __init__(self, x: T) -> None: # as the cached result of the isinstance() check immediately above # would mean the issubclass() call would short-circuit # before we got to the "raise TypeError" line - with self.assertRaises(TypeError): + with self.assertRaisesRegex( + TypeError, + "Protocols with non-method members don't support issubclass()" + ): issubclass(Eggs, Spam) def test_protocols_isinstance(self): @@ -2883,13 +2926,21 @@ def __init__(self): with self.subTest(klass=klass.__name__, proto=proto.__name__): self.assertIsInstance(klass(), proto) - with self.assertRaises(TypeError): + no_subscripted_generics = "Subscripted generics cannot be used with class and instance checks" + + with self.assertRaisesRegex(TypeError, no_subscripted_generics): isinstance(C(), PG[T]) - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, no_subscripted_generics): isinstance(C(), PG[C]) - with self.assertRaises(TypeError): + + only_runtime_checkable_msg = ( + "Instance and class checks can only be used " + "with @runtime_checkable protocols" + ) + + with self.assertRaisesRegex(TypeError, only_runtime_checkable_msg): isinstance(C(), BadP) - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, only_runtime_checkable_msg): isinstance(C(), BadPG) def test_protocols_isinstance_properties_and_descriptors(self): @@ -3274,7 +3325,7 @@ class P(Protocol): class C: pass - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, r"issubclass\(\) arg 1 must be a class"): issubclass(C(), P) def test_defining_generic_protocols(self): @@ -3654,6 +3705,28 @@ def __init__(self): Foo() # Previously triggered RecursionError + def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta(self): + # Ensure the cache is empty, or this test won't work correctly + collections.abc.Sized._abc_registry_clear() + + class Foo(collections.abc.Sized, Protocol): pass + + # gh-105144: this previously raised TypeError + # if a Protocol subclass of Sized had been created + # before any isinstance() checks against Sized + self.assertNotIsInstance(1, collections.abc.Sized) + + def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta_2(self): + # Ensure the cache is empty, or this test won't work correctly + collections.abc.Sized._abc_registry_clear() + + class Foo(typing.Sized, Protocol): pass + + # gh-105144: this previously raised TypeError + # if a Protocol subclass of Sized had been created + # before any isinstance() checks against Sized + self.assertNotIsInstance(1, typing.Sized) + class GenericTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index a7b2566b253421..2383d807ec58d1 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1733,7 +1733,7 @@ def _caller(depth=1, default='__main__'): pass return None -def _allow_reckless_class_checks(depth=3): +def _allow_reckless_class_checks(depth=2): """Allow instance and class checks for special stdlib modules. The abc and functools modules indiscriminately call isinstance() and @@ -1788,14 +1788,22 @@ def __init__(cls, *args, **kwargs): ) def __subclasscheck__(cls, other): + if not isinstance(other, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') if ( getattr(cls, '_is_protocol', False) - and not cls.__callable_proto_members_only__ - and not _allow_reckless_class_checks(depth=2) + and not _allow_reckless_class_checks() ): - raise TypeError( - "Protocols with non-method members don't support issubclass()" - ) + if not cls.__callable_proto_members_only__: + raise TypeError( + "Protocols with non-method members don't support issubclass()" + ) + if not getattr(cls, '_is_runtime_protocol', False): + raise TypeError( + "Instance and class checks can only be used with " + "@runtime_checkable protocols" + ) return super().__subclasscheck__(other) def __instancecheck__(cls, instance): @@ -1807,7 +1815,7 @@ def __instancecheck__(cls, instance): if ( not getattr(cls, '_is_runtime_protocol', False) and - not _allow_reckless_class_checks(depth=2) + not _allow_reckless_class_checks() ): raise TypeError("Instance and class checks can only be used with" " @runtime_checkable protocols") @@ -1875,18 +1883,6 @@ def _proto_hook(other): if not cls.__dict__.get('_is_protocol', False): return NotImplemented - # First, perform various sanity checks. - if not getattr(cls, '_is_runtime_protocol', False): - if _allow_reckless_class_checks(): - return NotImplemented - raise TypeError("Instance and class checks can only be used with" - " @runtime_checkable protocols") - - if not isinstance(other, type): - # Same error message as for issubclass(1, int). - raise TypeError('issubclass() arg 1 must be a class') - - # Second, perform the actual structural compatibility check. for attr in cls.__protocol_attrs__: for base in other.__mro__: # Check if the members appears in the class dictionary... diff --git a/Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst b/Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst new file mode 100644 index 00000000000000..7e4d6fbc4911ba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst @@ -0,0 +1,5 @@ +Fix a recent regression in the :mod:`typing` module. The regression meant +that doing ``class Foo(X, typing.Protocol)``, where ``X`` was a class that +had :class:`abc.ABCMeta` as its metaclass, would then cause subsequent +``isinstance(1, X)`` calls to erroneously raise :exc:`TypeError`. Patch by +Alex Waygood. From e7cb216339e8aa8d00f7f55f9e37864b1720ca0f Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Wed, 31 May 2023 21:37:37 +0100 Subject: [PATCH 0096/1206] [3.12] GH-105113: Improve performance of `pathlib.PurePath.match()` (GH-105114) We now compile a `re.Pattern` object for the entire pattern. This is made more difficult by `fnmatch` not treating directory separators as special when evaluating wildcards (`*`, `?`, etc), and so we arrange the path parts onto separate *lines* in a string, and ensure we don't set `re.DOTALL`. Co-authored-by: Hugo van Kemenade Co-authored-by: Alex Waygood --- Doc/library/pathlib.rst | 7 ++ Lib/pathlib.py | 86 ++++++++++++++++--- ...-05-30-21-27-41.gh-issue-105113.bDUPl_.rst | 2 + 3 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 627f2df9263dec..39b9eb84e7e068 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -569,6 +569,13 @@ Pure paths provide the following methods and properties: >>> PurePath('a/b.py').match('/*.py') False + The *pattern* may be another path object; this speeds up matching the same + pattern against multiple files:: + + >>> pattern = PurePath('*.py') + >>> PurePath('a/b.py').match(pattern) + True + As with other methods, case-sensitivity follows platform defaults:: >>> PurePosixPath('b.py').match('*.PY') diff --git a/Lib/pathlib.py b/Lib/pathlib.py index a42085e3a3f802..29517e4c74db1c 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -54,6 +54,7 @@ def _ignore_error(exception): getattr(exception, 'winerror', None) in _IGNORED_WINERRORS) +@functools.cache def _is_case_sensitive(flavour): return flavour.normcase('Aa') == 'Aa' @@ -61,6 +62,22 @@ def _is_case_sensitive(flavour): # Globbing helpers # + +# fnmatch.translate() returns a regular expression that includes a prefix and +# a suffix, which enable matching newlines and ensure the end of the string is +# matched, respectively. These features are undesirable for our implementation +# of PurePatch.match(), which represents path separators as newlines and joins +# pattern segments together. As a workaround, we define a slice object that +# can remove the prefix and suffix from any translate() result. See the +# _compile_pattern_lines() function for more details. +_FNMATCH_PREFIX, _FNMATCH_SUFFIX = fnmatch.translate('_').split('_') +_FNMATCH_SLICE = slice(len(_FNMATCH_PREFIX), -len(_FNMATCH_SUFFIX)) +_SWAP_SEP_AND_NEWLINE = { + '/': str.maketrans({'/': '\n', '\n': '/'}), + '\\': str.maketrans({'\\': '\n', '\n': '\\'}), +} + + @functools.lru_cache() def _make_selector(pattern_parts, flavour, case_sensitive): pat = pattern_parts[0] @@ -92,6 +109,38 @@ def _compile_pattern(pat, case_sensitive): return re.compile(fnmatch.translate(pat), flags).match +@functools.lru_cache() +def _compile_pattern_lines(pattern_lines, case_sensitive): + """Compile the given pattern lines to an `re.Pattern` object. + + The *pattern_lines* argument is a glob-style pattern (e.g. '*/*.py') with + its path separators and newlines swapped (e.g. '*\n*.py`). By using + newlines to separate path components, and not setting `re.DOTALL`, we + ensure that the `*` wildcard cannot match path separators. + + The returned `re.Pattern` object may have its `match()` method called to + match a complete pattern, or `search()` to match from the right. The + argument supplied to these methods must also have its path separators and + newlines swapped. + """ + + # Match the start of the path, or just after a path separator + parts = ['^'] + for part in pattern_lines.splitlines(keepends=True): + # We slice off the common prefix and suffix added by translate() to + # ensure that re.DOTALL is not set, and the end of the string not + # matched, respectively. With DOTALL not set, '*' wildcards will not + # match path separators, because the '.' characters in the pattern + # will not match newlines. + parts.append(fnmatch.translate(part)[_FNMATCH_SLICE]) + # Match the end of the path, always. + parts.append(r'\Z') + flags = re.MULTILINE + if not case_sensitive: + flags |= re.IGNORECASE + return re.compile(''.join(parts), flags=flags) + + class _Selector: """A selector matches a specific glob pattern part against the children of a given path.""" @@ -274,6 +323,10 @@ class PurePath(object): # to implement comparison methods like `__lt__()`. '_parts_normcase_cached', + # The `_lines_cached` slot stores the string path with path separators + # and newlines swapped. This is used to implement `match()`. + '_lines_cached', + # The `_hash` slot stores the hash of the case-normalized string # path. It's set when `__hash__()` is called for the first time. '_hash', @@ -439,6 +492,16 @@ def _parts_normcase(self): self._parts_normcase_cached = self._str_normcase.split(self._flavour.sep) return self._parts_normcase_cached + @property + def _lines(self): + # Path with separators and newlines swapped, for pattern matching. + try: + return self._lines_cached + except AttributeError: + trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep] + self._lines_cached = str(self).translate(trans) + return self._lines_cached + def __eq__(self, other): if not isinstance(other, PurePath): return NotImplemented @@ -695,23 +758,18 @@ def match(self, path_pattern, *, case_sensitive=None): """ Return True if this path matches the given pattern. """ + if not isinstance(path_pattern, PurePath): + path_pattern = self.with_segments(path_pattern) if case_sensitive is None: case_sensitive = _is_case_sensitive(self._flavour) - pat = self.with_segments(path_pattern) - if not pat.parts: + pattern = _compile_pattern_lines(path_pattern._lines, case_sensitive) + if path_pattern.drive or path_pattern.root: + return pattern.match(self._lines) is not None + elif path_pattern._tail: + return pattern.search(self._lines) is not None + else: raise ValueError("empty pattern") - pat_parts = pat.parts - parts = self.parts - if pat.drive or pat.root: - if len(pat_parts) != len(parts): - return False - elif len(pat_parts) > len(parts): - return False - for part, pat in zip(reversed(parts), reversed(pat_parts)): - match = _compile_pattern(pat, case_sensitive) - if not match(part): - return False - return True + # Can't subclass os.PathLike from PurePath and keep the constructor # optimizations in PurePath.__slots__. diff --git a/Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst b/Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst new file mode 100644 index 00000000000000..59164ae4734e51 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst @@ -0,0 +1,2 @@ +Improve performance of :meth:`pathlib.PurePath.match` by compiling an +:class:`re.Pattern` object for the entire pattern. From f87c6d189418850ac9c2e5f9cb08531cf004f704 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 31 May 2023 15:17:24 -0600 Subject: [PATCH 0097/1206] [3.12] gh-102304: Fix 2 New Stable ABI Functions (gh-104762) (gh-105123) --- Include/object.h | 2 +- Lib/test/test_stable_abi_ctypes.py | 2 ++ Misc/stable_abi.toml | 9 +++++++++ PC/python3dll.c | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Include/object.h b/Include/object.h index 81aeb2d8bd5a69..c2fee85a2c38f6 100644 --- a/Include/object.h +++ b/Include/object.h @@ -590,7 +590,7 @@ you can count such references to the type object.) extern Py_ssize_t _Py_RefTotal; # define _Py_INC_REFTOTAL() _Py_RefTotal++ # define _Py_DEC_REFTOTAL() _Py_RefTotal-- -# elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000 +# elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 PyAPI_FUNC(void) _Py_IncRefTotal_DO_NOT_USE_THIS(void); PyAPI_FUNC(void) _Py_DecRefTotal_DO_NOT_USE_THIS(void); # define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 4ca39d85e5460c..60ad3603ae9223 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -918,6 +918,8 @@ def test_windows_feature_macros(self): ) if feature_macros['Py_REF_DEBUG']: SYMBOL_NAMES += ( + '_Py_DecRefTotal_DO_NOT_USE_THIS', + '_Py_IncRefTotal_DO_NOT_USE_THIS', '_Py_NegativeRefcount', '_Py_RefTotal', ) diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 48299e9b35ff97..1db98483f09f77 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2406,3 +2406,12 @@ added = '3.12' [const.Py_TPFLAGS_ITEMS_AT_END] added = '3.12' + +[function._Py_IncRefTotal_DO_NOT_USE_THIS] + added = '3.12' + ifdef = 'Py_REF_DEBUG' + abi_only = true +[function._Py_DecRefTotal_DO_NOT_USE_THIS] + added = '3.12' + ifdef = 'Py_REF_DEBUG' + abi_only = true diff --git a/PC/python3dll.c b/PC/python3dll.c index 7e848abccfd1fa..f2c0d9dee883d9 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -18,7 +18,9 @@ EXPORT_FUNC(_Py_BuildValue_SizeT) EXPORT_FUNC(_Py_CheckRecursiveCall) EXPORT_FUNC(_Py_Dealloc) EXPORT_FUNC(_Py_DecRef) +EXPORT_FUNC(_Py_DecRefTotal_DO_NOT_USE_THIS) EXPORT_FUNC(_Py_IncRef) +EXPORT_FUNC(_Py_IncRefTotal_DO_NOT_USE_THIS) EXPORT_FUNC(_Py_NegativeRefcount) EXPORT_FUNC(_Py_VaBuildValue_SizeT) EXPORT_FUNC(_PyArg_Parse_SizeT) From 8b516668f2fea6d55edbd7054e27391cfd574d86 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 14:34:21 -0700 Subject: [PATCH 0098/1206] [3.12] gh-102251: Explicitly free state for test modules with state in test_import (GH-105085) (#105170) (cherry picked from commit a99b9d911e0f8cb11b3436bdd8eb649b15d01a50) Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- Lib/test/test_import/__init__.py | 14 ++++++++++---- Modules/_testsinglephase.c | 22 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index e2384a08ecaa90..227c912bc8c322 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -2320,6 +2320,7 @@ def test_variants(self): self.add_module_cleanup(name) with self.subTest(name): loaded = self.load(name) + self.addCleanup(loaded.module._clear_module_state) self.check_common(loaded) self.assertIsNot(loaded.snapshot.state_initialized, None) @@ -2379,14 +2380,19 @@ def test_with_reinit_reloaded(self): # Keep a reference around. basic = self.load(self.NAME) - for name in [ - f'{self.NAME}_with_reinit', # m_size == 0 - f'{self.NAME}_with_state', # m_size > 0 + for name, has_state in [ + (f'{self.NAME}_with_reinit', False), # m_size == 0 + (f'{self.NAME}_with_state', True), # m_size > 0 ]: self.add_module_cleanup(name) - with self.subTest(name): + with self.subTest(name=name, has_state=has_state): loaded = self.load(name) + if has_state: + self.addCleanup(loaded.module._clear_module_state) + reloaded = self.re_load(name, loaded.module) + if has_state: + self.addCleanup(reloaded.module._clear_module_state) self.check_common(loaded) self.check_common(reloaded) diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c index 8e6973f0b052cc..dca7abff89146e 100644 --- a/Modules/_testsinglephase.c +++ b/Modules/_testsinglephase.c @@ -248,6 +248,25 @@ basic__clear_globals(PyObject *self, PyObject *Py_UNUSED(ignored)) basic__clear_globals_doc} +PyDoc_STRVAR(basic__clear_module_state_doc, "_clear_module_state()\n\ +\n\ +Free the module state and set it to uninitialized."); + +static PyObject * +basic__clear_module_state(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + module_state *state = get_module_state(self); + if (state != NULL) { + clear_state(state); + } + Py_RETURN_NONE; +} + +#define _CLEAR_MODULE_STATE_METHODDEF \ + {"_clear_module_state", basic__clear_module_state, METH_NOARGS, \ + basic__clear_module_state_doc} + + /*********************************************/ /* the _testsinglephase module (and aliases) */ /*********************************************/ @@ -408,7 +427,7 @@ PyInit__testsinglephase_with_reinit(void) /* the _testsinglephase_with_state module */ /******************************************/ -/* This ia less typical of legacy extensions in the wild: +/* This is less typical of legacy extensions in the wild: - single-phase init (same as _testsinglephase above) - has some module state - supports repeated initialization @@ -424,6 +443,7 @@ static PyMethodDef TestMethods_WithState[] = { LOOK_UP_SELF_METHODDEF, SUM_METHODDEF, STATE_INITIALIZED_METHODDEF, + _CLEAR_MODULE_STATE_METHODDEF, {NULL, NULL} /* sentinel */ }; From dbd7d7c8e105e0462aec0530a118c016870c45a8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 31 May 2023 14:42:48 -0700 Subject: [PATCH 0099/1206] gh-105146: Update links at end of Windows installer (uninstall/repair) (GH-105147) (cherry picked from commit ed86e14b1672f32f0a31d72070e93d361ee0e2b4) Co-authored-by: Steve Dower --- .../Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst | 2 ++ Tools/msi/bundle/Default.wxl | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst diff --git a/Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst b/Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst new file mode 100644 index 00000000000000..1a5208bc898207 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst @@ -0,0 +1,2 @@ +Updated the links at the end of the installer to point to Discourse rather +than the mailing lists. diff --git a/Tools/msi/bundle/Default.wxl b/Tools/msi/bundle/Default.wxl index e83a540a0e6726..6f8befba3a2523 100644 --- a/Tools/msi/bundle/Default.wxl +++ b/Tools/msi/bundle/Default.wxl @@ -112,10 +112,10 @@ See <a href="https://docs.python.org/[ShortVersion]/whatsnew/[ShortVersion].h Thank you for using [WixBundleName]. Thank you for using [WixBundleName]. -Feel free to email <a href="mailto:python-list@python.org">python-list@python.org</a> if you continue to encounter issues. +Feel free to post at <a href="https://discuss.python.org/c/users/7">discuss.python.org</a> if you continue to encounter issues. Thank you for using [WixBundleName]. -Feel free to email <a href="mailto:python-list@python.org">python-list@python.org</a> if you encountered problems. +Feel free to post at <a href="https://discuss.python.org/c/users/7">discuss.python.org</a> if you encountered problems. Setup failed One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>. You must restart your computer to complete the rollback of the software. @@ -123,7 +123,7 @@ Feel free to email <a href="mailto:python-list@python.org">python-list@pyt Unable to install [WixBundleName] due to an existing install. Use Programs and Features to modify, repair or remove [WixBundleName]. At least Windows 8.1 or Windows Server 2012 are required to install [WixBundleName] -Visit <a href="https://www.python.org/">python.org</a> to download an earlier version of Python. +Visit <a href="https://www.python.org/downloads/">python.org</a> to download an earlier version of Python. Disable path length limit Changes your machine configuration to allow programs, including Python, to bypass the 260 character "MAX_PATH" limitation. From 6375287b37c226eb95d032b4714c43f8c04b7edb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 1 Jun 2023 05:08:37 -0700 Subject: [PATCH 0100/1206] [3.12] gh-89886: Rely on HAVE_SYS_TIME_H (GH-105058) (#105192) Quoting autoconf (v2.71): All current systems provide time.h; it need not be checked for. Not all systems provide sys/time.h, but those that do, all allow you to include it and time.h simultaneously. (cherry picked from commit 9ab587b7146618866cee52c220aecf7bd5b44b02) Co-authored-by: Erlend E. Aasland --- Modules/readline.c | 3 +++ Modules/resource.c | 3 +++ configure | 10 +--------- configure.ac | 10 +++------- pyconfig.h.in | 3 --- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/Modules/readline.c b/Modules/readline.c index fdb6356e1c84b5..2824105a187586 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -11,7 +11,10 @@ #include #include #include // free() +#ifdef HAVE_SYS_TIME_H #include +#endif +#include #if defined(HAVE_SETLOCALE) /* GNU readline() mistakenly sets the LC_CTYPE locale. diff --git a/Modules/resource.c b/Modules/resource.c index 2a8158c9be5359..3c89468c48c56e 100644 --- a/Modules/resource.c +++ b/Modules/resource.c @@ -1,7 +1,10 @@ #include "Python.h" #include +#ifdef HAVE_SYS_TIME_H #include +#endif +#include #include #include #include diff --git a/configure b/configure index ed80d95ecba022..012dac94feddd6 100755 --- a/configure +++ b/configure @@ -19866,14 +19866,6 @@ fi done -if test "x$ac_cv_header_sys_time_h" = xyes; then : - - -$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h - - -fi - # checks for structures { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } @@ -26736,7 +26728,7 @@ $as_echo_n "checking for stdlib extension module pyexpat... " >&6; } if test "$py_cv_module_pyexpat" != "n/a"; then : if true; then : - if true; then : + if test "$ac_cv_header_sys_time_h" = "yes"; then : py_cv_module_pyexpat=yes else py_cv_module_pyexpat=missing diff --git a/configure.ac b/configure.ac index 2d3f5191fbf3c3..c30fb2a08d104e 100644 --- a/configure.ac +++ b/configure.ac @@ -5375,12 +5375,6 @@ fi AC_CHECK_FUNCS([getnameinfo]) -dnl autoconf 2.71 deprecates AC_HEADER_TIME, keep for backwards compatibility -dnl TIME_WITH_SYS_TIME works on all supported systems that have sys/time.h -AS_VAR_IF([ac_cv_header_sys_time_h], [yes], [ - AC_DEFINE([TIME_WITH_SYS_TIME], 1, [Define to 1 if you can safely include both and .]) -]) - # checks for structures AC_STRUCT_TM AC_STRUCT_TIMEZONE @@ -7375,7 +7369,9 @@ PY_STDLIB_MOD([syslog], [], [test "$ac_cv_header_syslog_h" = yes]) PY_STDLIB_MOD([termios], [], [test "$ac_cv_header_termios_h" = yes]) dnl _elementtree loads libexpat via CAPI hook in pyexpat -PY_STDLIB_MOD([pyexpat], [], [], [$LIBEXPAT_CFLAGS], [$LIBEXPAT_LDFLAGS]) +PY_STDLIB_MOD([pyexpat], + [], [test "$ac_cv_header_sys_time_h" = "yes"], + [$LIBEXPAT_CFLAGS], [$LIBEXPAT_LDFLAGS]) PY_STDLIB_MOD([_elementtree], [], [], [$LIBEXPAT_CFLAGS], []) PY_STDLIB_MOD_SIMPLE([_codecs_cn]) PY_STDLIB_MOD_SIMPLE([_codecs_hk]) diff --git a/pyconfig.h.in b/pyconfig.h.in index 2c22b27af65ea3..b33e82c3609c18 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1691,9 +1691,6 @@ /* Library needed by timemodule.c: librt may be needed for clock_gettime() */ #undef TIMEMODULE_LIB -/* Define to 1 if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME - /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME From 25543aecfe1e11c1a7aca02e2a83ddbfbadde85f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 1 Jun 2023 10:13:35 -0700 Subject: [PATCH 0101/1206] [3.12] gh-103142: Upgrade binary builds and CI to OpenSSL 1.1.1u (GH-105174) (#105199) gh-103142: Upgrade binary builds and CI to OpenSSL 1.1.1u (GH-105174) Upgrade builds to OpenSSL 1.1.1u. This OpenSSL version addresses a pile if less-urgent CVEs since 1.1.1t. The Mac/BuildScript/build-installer.py was already updated. Also updates _ssl_data_111.h from OpenSSL 1.1.1u, _ssl_data_300.h from 3.0.9, and adds a new _ssl_data_31.h file from 3.1.1 along with the ssl.c code to use it. Manual edits to the _ssl_data_300.h file prevent it from removing any existing definitions in case those exist in some peoples builds and were important (avoiding regressions during backporting). backports of this prior to 3.12 will not include the openssl 3.1 header. (cherry picked from commit ede89af605b1c0442353435ad22195c16274f65d) Co-authored-by: Gregory P. Smith [Google] --- .azure-pipelines/ci.yml | 4 +- .azure-pipelines/pr.yml | 4 +- .github/workflows/build.yml | 8 +- ...-06-01-03-24-58.gh-issue-103142.GLWDMX.rst | 2 + Modules/_ssl.c | 4 +- Modules/_ssl_data_111.h | 17 +- Modules/_ssl_data_300.h | 152 +- Modules/_ssl_data_31.h | 8605 +++++++++++++++++ PCbuild/get_externals.bat | 4 +- PCbuild/python.props | 4 +- PCbuild/readme.txt | 2 +- Tools/c-analyzer/cpython/_parser.py | 1 + Tools/ssl/multissltests.py | 5 +- 13 files changed, 8794 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst create mode 100644 Modules/_ssl_data_31.h diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index 6302b547982118..fb4a2218ddd8d8 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -57,7 +57,7 @@ jobs: variables: testRunTitle: '$(build.sourceBranchName)-linux' testRunPlatform: linux - openssl_version: 1.1.1t + openssl_version: 1.1.1u steps: - template: ./posix-steps.yml @@ -83,7 +83,7 @@ jobs: variables: testRunTitle: '$(Build.SourceBranchName)-linux-coverage' testRunPlatform: linux-coverage - openssl_version: 1.1.1t + openssl_version: 1.1.1u steps: - template: ./posix-steps.yml diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 5f7218768c18af..b822d58806b9a6 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -57,7 +57,7 @@ jobs: variables: testRunTitle: '$(system.pullRequest.TargetBranch)-linux' testRunPlatform: linux - openssl_version: 1.1.1t + openssl_version: 1.1.1u steps: - template: ./posix-steps.yml @@ -83,7 +83,7 @@ jobs: variables: testRunTitle: '$(Build.SourceBranchName)-linux-coverage' testRunPlatform: linux-coverage - openssl_version: 1.1.1t + openssl_version: 1.1.1u steps: - template: ./posix-steps.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 046c2aaa55f67b..c632d362a4d04a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -264,7 +264,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1t + OPENSSL_VER: 1.1.1u PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v3 @@ -333,7 +333,7 @@ jobs: strategy: fail-fast: false matrix: - openssl_ver: [1.1.1t, 3.0.8, 3.1.0-beta1] + openssl_ver: [1.1.1u, 3.0.9, 3.1.1] env: OPENSSL_VER: ${{ matrix.openssl_ver }} MULTISSL_DIR: ${{ github.workspace }}/multissl @@ -385,7 +385,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_hypothesis == 'true' env: - OPENSSL_VER: 1.1.1t + OPENSSL_VER: 1.1.1u PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v3 @@ -494,7 +494,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1t + OPENSSL_VER: 1.1.1u PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: diff --git a/Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst b/Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst new file mode 100644 index 00000000000000..7e0836879e4f81 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst @@ -0,0 +1,2 @@ +The version of OpenSSL used in our binary builds has been upgraded to 1.1.1u +to address several CVEs. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 59fd401cac270b..de90a4a168d2ed 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -116,7 +116,9 @@ static void _PySSLFixErrno(void) { #endif /* Include generated data (error codes) */ -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#if (OPENSSL_VERSION_NUMBER >= 0x30100000L) +#include "_ssl_data_31.h" +#elif (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include "_ssl_data_300.h" #elif (OPENSSL_VERSION_NUMBER >= 0x10101000L) && !defined(LIBRESSL_VERSION_NUMBER) #include "_ssl_data_111.h" diff --git a/Modules/_ssl_data_111.h b/Modules/_ssl_data_111.h index 85a2f7ec1561ea..093c786e6a26f6 100644 --- a/Modules/_ssl_data_111.h +++ b/Modules/_ssl_data_111.h @@ -1,4 +1,4 @@ -/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2021-04-09T09:36:21.493286 */ +/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2023-06-01T02:58:04.081473 */ static struct py_ssl_library_code library_codes[] = { #ifdef ERR_LIB_ASN1 {"ASN1", ERR_LIB_ASN1}, @@ -1375,6 +1375,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"UNSUPPORTED_COMPRESSION_ALGORITHM", 46, 151}, #endif + #ifdef CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM + {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM}, + #else + {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", 46, 194}, + #endif #ifdef CMS_R_UNSUPPORTED_CONTENT_TYPE {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_TYPE}, #else @@ -4860,6 +4865,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"MISSING_PARAMETERS", 20, 290}, #endif + #ifdef SSL_R_MISSING_PSK_KEX_MODES_EXTENSION + {"MISSING_PSK_KEX_MODES_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION}, + #else + {"MISSING_PSK_KEX_MODES_EXTENSION", 20, 310}, + #endif #ifdef SSL_R_MISSING_RSA_CERTIFICATE {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, SSL_R_MISSING_RSA_CERTIFICATE}, #else @@ -5065,6 +5075,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"NULL_SSL_METHOD_PASSED", 20, 196}, #endif + #ifdef SSL_R_OCSP_CALLBACK_FAILURE + {"OCSP_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_OCSP_CALLBACK_FAILURE}, + #else + {"OCSP_CALLBACK_FAILURE", 20, 294}, + #endif #ifdef SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED}, #else diff --git a/Modules/_ssl_data_300.h b/Modules/_ssl_data_300.h index 6be8b24ee1a021..dc66731f6b6093 100644 --- a/Modules/_ssl_data_300.h +++ b/Modules/_ssl_data_300.h @@ -1,4 +1,4 @@ -/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2021-04-09T09:44:43.288448 */ +/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2023-06-01T03:03:52.163218 */ static struct py_ssl_library_code library_codes[] = { #ifdef ERR_LIB_ASN1 {"ASN1", ERR_LIB_ASN1}, @@ -1035,6 +1035,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"NO_INVERSE", 3, 108}, #endif + #ifdef BN_R_NO_PRIME_CANDIDATE + {"NO_PRIME_CANDIDATE", ERR_LIB_BN, BN_R_NO_PRIME_CANDIDATE}, + #else + {"NO_PRIME_CANDIDATE", 3, 121}, + #endif #ifdef BN_R_NO_SOLUTION {"NO_SOLUTION", ERR_LIB_BN, BN_R_NO_SOLUTION}, #else @@ -1255,6 +1260,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_OPTION", 58, 174}, #endif + #ifdef CMP_R_MISSING_CERTID + {"MISSING_CERTID", ERR_LIB_CMP, CMP_R_MISSING_CERTID}, + #else + {"MISSING_CERTID", 58, 165}, + #endif #ifdef CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION {"MISSING_KEY_INPUT_FOR_CREATING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION}, #else @@ -1280,21 +1290,41 @@ static struct py_ssl_error_code error_codes[] = { #else {"MISSING_PRIVATE_KEY", 58, 131}, #endif + #ifdef CMP_R_MISSING_PRIVATE_KEY_FOR_POPO + {"MISSING_PRIVATE_KEY_FOR_POPO", ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY_FOR_POPO}, + #else + {"MISSING_PRIVATE_KEY_FOR_POPO", 58, 190}, + #endif #ifdef CMP_R_MISSING_PROTECTION {"MISSING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_PROTECTION}, #else {"MISSING_PROTECTION", 58, 143}, #endif + #ifdef CMP_R_MISSING_PUBLIC_KEY + {"MISSING_PUBLIC_KEY", ERR_LIB_CMP, CMP_R_MISSING_PUBLIC_KEY}, + #else + {"MISSING_PUBLIC_KEY", 58, 183}, + #endif #ifdef CMP_R_MISSING_REFERENCE_CERT {"MISSING_REFERENCE_CERT", ERR_LIB_CMP, CMP_R_MISSING_REFERENCE_CERT}, #else {"MISSING_REFERENCE_CERT", 58, 168}, #endif + #ifdef CMP_R_MISSING_SECRET + {"MISSING_SECRET", ERR_LIB_CMP, CMP_R_MISSING_SECRET}, + #else + {"MISSING_SECRET", 58, 178}, + #endif #ifdef CMP_R_MISSING_SENDER_IDENTIFICATION {"MISSING_SENDER_IDENTIFICATION", ERR_LIB_CMP, CMP_R_MISSING_SENDER_IDENTIFICATION}, #else {"MISSING_SENDER_IDENTIFICATION", 58, 111}, #endif + #ifdef CMP_R_MISSING_TRUST_ANCHOR + {"MISSING_TRUST_ANCHOR", ERR_LIB_CMP, CMP_R_MISSING_TRUST_ANCHOR}, + #else + {"MISSING_TRUST_ANCHOR", 58, 179}, + #endif #ifdef CMP_R_MISSING_TRUST_STORE {"MISSING_TRUST_STORE", ERR_LIB_CMP, CMP_R_MISSING_TRUST_STORE}, #else @@ -1455,6 +1485,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"WRONG_ALGORITHM_OID", 58, 138}, #endif + #ifdef CMP_R_WRONG_CERTID + {"WRONG_CERTID", ERR_LIB_CMP, CMP_R_WRONG_CERTID}, + #else + {"WRONG_CERTID", 58, 189}, + #endif #ifdef CMP_R_WRONG_CERTID_IN_RP {"WRONG_CERTID_IN_RP", ERR_LIB_CMP, CMP_R_WRONG_CERTID_IN_RP}, #else @@ -1885,6 +1920,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"UNSUPPORTED_COMPRESSION_ALGORITHM", 46, 151}, #endif + #ifdef CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM + {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM}, + #else + {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", 46, 194}, + #endif #ifdef CMS_R_UNSUPPORTED_CONTENT_TYPE {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_TYPE}, #else @@ -2045,6 +2085,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"RECURSIVE_DIRECTORY_INCLUDE", 14, 111}, #endif + #ifdef CONF_R_RELATIVE_PATH + {"RELATIVE_PATH", ERR_LIB_CONF, CONF_R_RELATIVE_PATH}, + #else + {"RELATIVE_PATH", 14, 125}, + #endif #ifdef CONF_R_SSL_COMMAND_SECTION_EMPTY {"SSL_COMMAND_SECTION_EMPTY", ERR_LIB_CONF, CONF_R_SSL_COMMAND_SECTION_EMPTY}, #else @@ -2235,6 +2280,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INSUFFICIENT_SECURE_DATA_SPACE", 15, 108}, #endif + #ifdef CRYPTO_R_INVALID_NEGATIVE_VALUE + {"INVALID_NEGATIVE_VALUE", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NEGATIVE_VALUE}, + #else + {"INVALID_NEGATIVE_VALUE", 15, 122}, + #endif #ifdef CRYPTO_R_INVALID_NULL_ARGUMENT {"INVALID_NULL_ARGUMENT", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NULL_ARGUMENT}, #else @@ -2605,6 +2655,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"SEED_LEN_SMALL", 10, 110}, #endif + #ifdef DSA_R_TOO_MANY_RETRIES + {"TOO_MANY_RETRIES", ERR_LIB_DSA, DSA_R_TOO_MANY_RETRIES}, + #else + {"TOO_MANY_RETRIES", 10, 116}, + #endif #ifdef DSO_R_CTRL_FAILED {"CTRL_FAILED", ERR_LIB_DSO, DSO_R_CTRL_FAILED}, #else @@ -2745,6 +2800,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"EC_GROUP_NEW_BY_NAME_FAILURE", 16, 119}, #endif + #ifdef EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED + {"EXPLICIT_PARAMS_NOT_SUPPORTED", ERR_LIB_EC, EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED}, + #else + {"EXPLICIT_PARAMS_NOT_SUPPORTED", 16, 127}, + #endif #ifdef EC_R_FAILED_MAKING_PUBLIC_KEY {"FAILED_MAKING_PUBLIC_KEY", ERR_LIB_EC, EC_R_FAILED_MAKING_PUBLIC_KEY}, #else @@ -2850,6 +2910,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_KEY", 16, 116}, #endif + #ifdef EC_R_INVALID_LENGTH + {"INVALID_LENGTH", ERR_LIB_EC, EC_R_INVALID_LENGTH}, + #else + {"INVALID_LENGTH", 16, 117}, + #endif #ifdef EC_R_INVALID_NAMED_GROUP_CONVERSION {"INVALID_NAMED_GROUP_CONVERSION", ERR_LIB_EC, EC_R_INVALID_NAMED_GROUP_CONVERSION}, #else @@ -3010,6 +3075,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"SLOT_FULL", 16, 108}, #endif + #ifdef EC_R_TOO_MANY_RETRIES + {"TOO_MANY_RETRIES", ERR_LIB_EC, EC_R_TOO_MANY_RETRIES}, + #else + {"TOO_MANY_RETRIES", 16, 176}, + #endif #ifdef EC_R_UNDEFINED_GENERATOR {"UNDEFINED_GENERATOR", ERR_LIB_EC, EC_R_UNDEFINED_GENERATOR}, #else @@ -3690,6 +3760,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"PUBLIC_KEY_NOT_RSA", 6, 106}, #endif + #ifdef EVP_R_SETTING_XOF_FAILED + {"SETTING_XOF_FAILED", ERR_LIB_EVP, EVP_R_SETTING_XOF_FAILED}, + #else + {"SETTING_XOF_FAILED", 6, 227}, + #endif #ifdef EVP_R_SET_DEFAULT_PROPERTY_FAILURE {"SET_DEFAULT_PROPERTY_FAILURE", ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE}, #else @@ -3865,6 +3940,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"FAILED_READING_DATA", 61, 128}, #endif + #ifdef HTTP_R_HEADER_PARSE_ERROR + {"HEADER_PARSE_ERROR", ERR_LIB_HTTP, HTTP_R_HEADER_PARSE_ERROR}, + #else + {"HEADER_PARSE_ERROR", 61, 126}, + #endif #ifdef HTTP_R_INCONSISTENT_CONTENT_LENGTH {"INCONSISTENT_CONTENT_LENGTH", ERR_LIB_HTTP, HTTP_R_INCONSISTENT_CONTENT_LENGTH}, #else @@ -3935,6 +4015,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"RESPONSE_PARSE_ERROR", 61, 104}, #endif + #ifdef HTTP_R_RETRY_TIMEOUT + {"RETRY_TIMEOUT", ERR_LIB_HTTP, HTTP_R_RETRY_TIMEOUT}, + #else + {"RETRY_TIMEOUT", 61, 129}, + #endif + #ifdef HTTP_R_SERVER_CANCELED_CONNECTION + {"SERVER_CANCELED_CONNECTION", ERR_LIB_HTTP, HTTP_R_SERVER_CANCELED_CONNECTION}, + #else + {"SERVER_CANCELED_CONNECTION", 61, 127}, + #endif #ifdef HTTP_R_SOCK_NOT_SUPPORTED {"SOCK_NOT_SUPPORTED", ERR_LIB_HTTP, HTTP_R_SOCK_NOT_SUPPORTED}, #else @@ -4100,6 +4190,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"UNSUPPORTED_REQUESTORNAME_TYPE", 39, 129}, #endif + #ifdef OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT + {"COULD_NOT_DECODE_OBJECT", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT}, + #else + {"COULD_NOT_DECODE_OBJECT", 60, 101}, + #endif + #ifdef OSSL_DECODER_R_DECODER_NOT_FOUND + {"DECODER_NOT_FOUND", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_DECODER_NOT_FOUND}, + #else + {"DECODER_NOT_FOUND", 60, 102}, + #endif #ifdef OSSL_DECODER_R_MISSING_GET_PARAMS {"MISSING_GET_PARAMS", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_MISSING_GET_PARAMS}, #else @@ -4190,6 +4290,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"NOT_PARAMETERS", 44, 104}, #endif + #ifdef OSSL_STORE_R_NO_LOADERS_FOUND + {"NO_LOADERS_FOUND", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NO_LOADERS_FOUND}, + #else + {"NO_LOADERS_FOUND", 44, 123}, + #endif #ifdef OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR {"PASSPHRASE_CALLBACK_ERROR", ERR_LIB_OSSL_STORE, OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR}, #else @@ -4935,6 +5040,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_DIGEST_SIZE", 57, 218}, #endif + #ifdef PROV_R_INVALID_INPUT_LENGTH + {"INVALID_INPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH}, + #else + {"INVALID_INPUT_LENGTH", 57, 230}, + #endif #ifdef PROV_R_INVALID_ITERATION_COUNT {"INVALID_ITERATION_COUNT", ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT}, #else @@ -4970,6 +5080,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_MODE", 57, 125}, #endif + #ifdef PROV_R_INVALID_OUTPUT_LENGTH + {"INVALID_OUTPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH}, + #else + {"INVALID_OUTPUT_LENGTH", 57, 217}, + #endif #ifdef PROV_R_INVALID_PADDING_MODE {"INVALID_PADDING_MODE", ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE}, #else @@ -5035,6 +5150,16 @@ static struct py_ssl_error_code error_codes[] = { #else {"KEY_SIZE_TOO_SMALL", 57, 171}, #endif + #ifdef PROV_R_LENGTH_TOO_LARGE + {"LENGTH_TOO_LARGE", ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE}, + #else + {"LENGTH_TOO_LARGE", 57, 202}, + #endif + #ifdef PROV_R_MISMATCHING_DOMAIN_PARAMETERS + {"MISMATCHING_DOMAIN_PARAMETERS", ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS}, + #else + {"MISMATCHING_DOMAIN_PARAMETERS", 57, 203}, + #endif #ifdef PROV_R_MISSING_CEK_ALG {"MISSING_CEK_ALG", ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG}, #else @@ -5695,6 +5820,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_LABEL", 4, 160}, #endif + #ifdef RSA_R_INVALID_LENGTH + {"INVALID_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_LENGTH}, + #else + {"INVALID_LENGTH", 4, 181}, + #endif #ifdef RSA_R_INVALID_MESSAGE_LENGTH {"INVALID_MESSAGE_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_MESSAGE_LENGTH}, #else @@ -5880,6 +6010,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"Q_NOT_PRIME", 4, 129}, #endif + #ifdef RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT + {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", ERR_LIB_RSA, RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT}, + #else + {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", 4, 180}, + #endif #ifdef RSA_R_RSA_OPERATIONS_NOT_SUPPORTED {"RSA_OPERATIONS_NOT_SUPPORTED", ERR_LIB_RSA, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED}, #else @@ -6680,6 +6815,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"INVALID_TICKET_KEYS_LENGTH", 20, 325}, #endif + #ifdef SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED + {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", ERR_LIB_SSL, SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED}, + #else + {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", 20, 333}, + #endif #ifdef SSL_R_LENGTH_MISMATCH {"LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH}, #else @@ -6725,6 +6865,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"MISSING_PARAMETERS", 20, 290}, #endif + #ifdef SSL_R_MISSING_PSK_KEX_MODES_EXTENSION + {"MISSING_PSK_KEX_MODES_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION}, + #else + {"MISSING_PSK_KEX_MODES_EXTENSION", 20, 310}, + #endif #ifdef SSL_R_MISSING_RSA_CERTIFICATE {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, SSL_R_MISSING_RSA_CERTIFICATE}, #else @@ -6940,6 +7085,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"NULL_SSL_METHOD_PASSED", 20, 196}, #endif + #ifdef SSL_R_OCSP_CALLBACK_FAILURE + {"OCSP_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_OCSP_CALLBACK_FAILURE}, + #else + {"OCSP_CALLBACK_FAILURE", 20, 305}, + #endif #ifdef SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED}, #else diff --git a/Modules/_ssl_data_31.h b/Modules/_ssl_data_31.h new file mode 100644 index 00000000000000..c589c501f4e948 --- /dev/null +++ b/Modules/_ssl_data_31.h @@ -0,0 +1,8605 @@ +/* File generated by Tools/ssl/make_ssl_data.py *//* Generated on 2023-06-01T03:04:00.275280 */ +static struct py_ssl_library_code library_codes[] = { +#ifdef ERR_LIB_ASN1 + {"ASN1", ERR_LIB_ASN1}, +#endif +#ifdef ERR_LIB_ASYNC + {"ASYNC", ERR_LIB_ASYNC}, +#endif +#ifdef ERR_LIB_BIO + {"BIO", ERR_LIB_BIO}, +#endif +#ifdef ERR_LIB_BN + {"BN", ERR_LIB_BN}, +#endif +#ifdef ERR_LIB_BUF + {"BUF", ERR_LIB_BUF}, +#endif +#ifdef ERR_LIB_CMP + {"CMP", ERR_LIB_CMP}, +#endif +#ifdef ERR_LIB_CMS + {"CMS", ERR_LIB_CMS}, +#endif +#ifdef ERR_LIB_COMP + {"COMP", ERR_LIB_COMP}, +#endif +#ifdef ERR_LIB_CONF + {"CONF", ERR_LIB_CONF}, +#endif +#ifdef ERR_LIB_CRMF + {"CRMF", ERR_LIB_CRMF}, +#endif +#ifdef ERR_LIB_CRYPTO + {"CRYPTO", ERR_LIB_CRYPTO}, +#endif +#ifdef ERR_LIB_CT + {"CT", ERR_LIB_CT}, +#endif +#ifdef ERR_LIB_DH + {"DH", ERR_LIB_DH}, +#endif +#ifdef ERR_LIB_DSA + {"DSA", ERR_LIB_DSA}, +#endif +#ifdef ERR_LIB_DSO + {"DSO", ERR_LIB_DSO}, +#endif +#ifdef ERR_LIB_EC + {"EC", ERR_LIB_EC}, +#endif +#ifdef ERR_LIB_ECDH + {"ECDH", ERR_LIB_ECDH}, +#endif +#ifdef ERR_LIB_ECDSA + {"ECDSA", ERR_LIB_ECDSA}, +#endif +#ifdef ERR_LIB_ENGINE + {"ENGINE", ERR_LIB_ENGINE}, +#endif +#ifdef ERR_LIB_ESS + {"ESS", ERR_LIB_ESS}, +#endif +#ifdef ERR_LIB_EVP + {"EVP", ERR_LIB_EVP}, +#endif +#ifdef ERR_LIB_FIPS + {"FIPS", ERR_LIB_FIPS}, +#endif +#ifdef ERR_LIB_HMAC + {"HMAC", ERR_LIB_HMAC}, +#endif +#ifdef ERR_LIB_HTTP + {"HTTP", ERR_LIB_HTTP}, +#endif +#ifdef ERR_LIB_JPAKE + {"JPAKE", ERR_LIB_JPAKE}, +#endif +#ifdef ERR_LIB_KDF + {"KDF", ERR_LIB_KDF}, +#endif +#ifdef ERR_LIB_MASK + {"MASK", ERR_LIB_MASK}, +#endif +#ifdef ERR_LIB_METH + {"METH", ERR_LIB_METH}, +#endif +#ifdef ERR_LIB_NONE + {"NONE", ERR_LIB_NONE}, +#endif +#ifdef ERR_LIB_OBJ + {"OBJ", ERR_LIB_OBJ}, +#endif +#ifdef ERR_LIB_OCSP + {"OCSP", ERR_LIB_OCSP}, +#endif +#ifdef ERR_LIB_OFFSET + {"OFFSET", ERR_LIB_OFFSET}, +#endif +#ifdef ERR_LIB_OSSL_DECODER + {"OSSL_DECODER", ERR_LIB_OSSL_DECODER}, +#endif +#ifdef ERR_LIB_OSSL_ENCODER + {"OSSL_ENCODER", ERR_LIB_OSSL_ENCODER}, +#endif +#ifdef ERR_LIB_OSSL_STORE + {"OSSL_STORE", ERR_LIB_OSSL_STORE}, +#endif +#ifdef ERR_LIB_PEM + {"PEM", ERR_LIB_PEM}, +#endif +#ifdef ERR_LIB_PKCS12 + {"PKCS12", ERR_LIB_PKCS12}, +#endif +#ifdef ERR_LIB_PKCS7 + {"PKCS7", ERR_LIB_PKCS7}, +#endif +#ifdef ERR_LIB_PROP + {"PROP", ERR_LIB_PROP}, +#endif +#ifdef ERR_LIB_PROV + {"PROV", ERR_LIB_PROV}, +#endif +#ifdef ERR_LIB_PROXY + {"PROXY", ERR_LIB_PROXY}, +#endif +#ifdef ERR_LIB_RAND + {"RAND", ERR_LIB_RAND}, +#endif +#ifdef ERR_LIB_RSA + {"RSA", ERR_LIB_RSA}, +#endif +#ifdef ERR_LIB_RSAREF + {"RSAREF", ERR_LIB_RSAREF}, +#endif +#ifdef ERR_LIB_SM2 + {"SM2", ERR_LIB_SM2}, +#endif +#ifdef ERR_LIB_SSL + {"SSL", ERR_LIB_SSL}, +#endif +#ifdef ERR_LIB_SSL2 + {"SSL2", ERR_LIB_SSL2}, +#endif +#ifdef ERR_LIB_SSL23 + {"SSL23", ERR_LIB_SSL23}, +#endif +#ifdef ERR_LIB_SSL3 + {"SSL3", ERR_LIB_SSL3}, +#endif +#ifdef ERR_LIB_SYS + {"SYS", ERR_LIB_SYS}, +#endif +#ifdef ERR_LIB_TS + {"TS", ERR_LIB_TS}, +#endif +#ifdef ERR_LIB_UI + {"UI", ERR_LIB_UI}, +#endif +#ifdef ERR_LIB_USER + {"USER", ERR_LIB_USER}, +#endif +#ifdef ERR_LIB_X509 + {"X509", ERR_LIB_X509}, +#endif +#ifdef ERR_LIB_X509V3 + {"X509V3", ERR_LIB_X509V3}, +#endif + { NULL } +}; + + +static struct py_ssl_error_code error_codes[] = { + #ifdef ASN1_R_ADDING_OBJECT + {"ADDING_OBJECT", ERR_LIB_ASN1, ASN1_R_ADDING_OBJECT}, + #else + {"ADDING_OBJECT", 13, 171}, + #endif + #ifdef ASN1_R_ASN1_PARSE_ERROR + {"ASN1_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_ASN1_PARSE_ERROR}, + #else + {"ASN1_PARSE_ERROR", 13, 203}, + #endif + #ifdef ASN1_R_ASN1_SIG_PARSE_ERROR + {"ASN1_SIG_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_ASN1_SIG_PARSE_ERROR}, + #else + {"ASN1_SIG_PARSE_ERROR", 13, 204}, + #endif + #ifdef ASN1_R_AUX_ERROR + {"AUX_ERROR", ERR_LIB_ASN1, ASN1_R_AUX_ERROR}, + #else + {"AUX_ERROR", 13, 100}, + #endif + #ifdef ASN1_R_BAD_OBJECT_HEADER + {"BAD_OBJECT_HEADER", ERR_LIB_ASN1, ASN1_R_BAD_OBJECT_HEADER}, + #else + {"BAD_OBJECT_HEADER", 13, 102}, + #endif + #ifdef ASN1_R_BAD_TEMPLATE + {"BAD_TEMPLATE", ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE}, + #else + {"BAD_TEMPLATE", 13, 230}, + #endif + #ifdef ASN1_R_BMPSTRING_IS_WRONG_LENGTH + {"BMPSTRING_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH}, + #else + {"BMPSTRING_IS_WRONG_LENGTH", 13, 214}, + #endif + #ifdef ASN1_R_BN_LIB + {"BN_LIB", ERR_LIB_ASN1, ASN1_R_BN_LIB}, + #else + {"BN_LIB", 13, 105}, + #endif + #ifdef ASN1_R_BOOLEAN_IS_WRONG_LENGTH + {"BOOLEAN_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH}, + #else + {"BOOLEAN_IS_WRONG_LENGTH", 13, 106}, + #endif + #ifdef ASN1_R_BUFFER_TOO_SMALL + {"BUFFER_TOO_SMALL", ERR_LIB_ASN1, ASN1_R_BUFFER_TOO_SMALL}, + #else + {"BUFFER_TOO_SMALL", 13, 107}, + #endif + #ifdef ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER + {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", ERR_LIB_ASN1, ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER}, + #else + {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", 13, 108}, + #endif + #ifdef ASN1_R_CONTEXT_NOT_INITIALISED + {"CONTEXT_NOT_INITIALISED", ERR_LIB_ASN1, ASN1_R_CONTEXT_NOT_INITIALISED}, + #else + {"CONTEXT_NOT_INITIALISED", 13, 217}, + #endif + #ifdef ASN1_R_DATA_IS_WRONG + {"DATA_IS_WRONG", ERR_LIB_ASN1, ASN1_R_DATA_IS_WRONG}, + #else + {"DATA_IS_WRONG", 13, 109}, + #endif + #ifdef ASN1_R_DECODE_ERROR + {"DECODE_ERROR", ERR_LIB_ASN1, ASN1_R_DECODE_ERROR}, + #else + {"DECODE_ERROR", 13, 110}, + #endif + #ifdef ASN1_R_DEPTH_EXCEEDED + {"DEPTH_EXCEEDED", ERR_LIB_ASN1, ASN1_R_DEPTH_EXCEEDED}, + #else + {"DEPTH_EXCEEDED", 13, 174}, + #endif + #ifdef ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED + {"DIGEST_AND_KEY_TYPE_NOT_SUPPORTED", ERR_LIB_ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED}, + #else + {"DIGEST_AND_KEY_TYPE_NOT_SUPPORTED", 13, 198}, + #endif + #ifdef ASN1_R_ENCODE_ERROR + {"ENCODE_ERROR", ERR_LIB_ASN1, ASN1_R_ENCODE_ERROR}, + #else + {"ENCODE_ERROR", 13, 112}, + #endif + #ifdef ASN1_R_ERROR_GETTING_TIME + {"ERROR_GETTING_TIME", ERR_LIB_ASN1, ASN1_R_ERROR_GETTING_TIME}, + #else + {"ERROR_GETTING_TIME", 13, 173}, + #endif + #ifdef ASN1_R_ERROR_LOADING_SECTION + {"ERROR_LOADING_SECTION", ERR_LIB_ASN1, ASN1_R_ERROR_LOADING_SECTION}, + #else + {"ERROR_LOADING_SECTION", 13, 172}, + #endif + #ifdef ASN1_R_ERROR_SETTING_CIPHER_PARAMS + {"ERROR_SETTING_CIPHER_PARAMS", ERR_LIB_ASN1, ASN1_R_ERROR_SETTING_CIPHER_PARAMS}, + #else + {"ERROR_SETTING_CIPHER_PARAMS", 13, 114}, + #endif + #ifdef ASN1_R_EXPECTING_AN_INTEGER + {"EXPECTING_AN_INTEGER", ERR_LIB_ASN1, ASN1_R_EXPECTING_AN_INTEGER}, + #else + {"EXPECTING_AN_INTEGER", 13, 115}, + #endif + #ifdef ASN1_R_EXPECTING_AN_OBJECT + {"EXPECTING_AN_OBJECT", ERR_LIB_ASN1, ASN1_R_EXPECTING_AN_OBJECT}, + #else + {"EXPECTING_AN_OBJECT", 13, 116}, + #endif + #ifdef ASN1_R_EXPLICIT_LENGTH_MISMATCH + {"EXPLICIT_LENGTH_MISMATCH", ERR_LIB_ASN1, ASN1_R_EXPLICIT_LENGTH_MISMATCH}, + #else + {"EXPLICIT_LENGTH_MISMATCH", 13, 119}, + #endif + #ifdef ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED + {"EXPLICIT_TAG_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED}, + #else + {"EXPLICIT_TAG_NOT_CONSTRUCTED", 13, 120}, + #endif + #ifdef ASN1_R_FIELD_MISSING + {"FIELD_MISSING", ERR_LIB_ASN1, ASN1_R_FIELD_MISSING}, + #else + {"FIELD_MISSING", 13, 121}, + #endif + #ifdef ASN1_R_FIRST_NUM_TOO_LARGE + {"FIRST_NUM_TOO_LARGE", ERR_LIB_ASN1, ASN1_R_FIRST_NUM_TOO_LARGE}, + #else + {"FIRST_NUM_TOO_LARGE", 13, 122}, + #endif + #ifdef ASN1_R_HEADER_TOO_LONG + {"HEADER_TOO_LONG", ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG}, + #else + {"HEADER_TOO_LONG", 13, 123}, + #endif + #ifdef ASN1_R_ILLEGAL_BITSTRING_FORMAT + {"ILLEGAL_BITSTRING_FORMAT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT}, + #else + {"ILLEGAL_BITSTRING_FORMAT", 13, 175}, + #endif + #ifdef ASN1_R_ILLEGAL_BOOLEAN + {"ILLEGAL_BOOLEAN", ERR_LIB_ASN1, ASN1_R_ILLEGAL_BOOLEAN}, + #else + {"ILLEGAL_BOOLEAN", 13, 176}, + #endif + #ifdef ASN1_R_ILLEGAL_CHARACTERS + {"ILLEGAL_CHARACTERS", ERR_LIB_ASN1, ASN1_R_ILLEGAL_CHARACTERS}, + #else + {"ILLEGAL_CHARACTERS", 13, 124}, + #endif + #ifdef ASN1_R_ILLEGAL_FORMAT + {"ILLEGAL_FORMAT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_FORMAT}, + #else + {"ILLEGAL_FORMAT", 13, 177}, + #endif + #ifdef ASN1_R_ILLEGAL_HEX + {"ILLEGAL_HEX", ERR_LIB_ASN1, ASN1_R_ILLEGAL_HEX}, + #else + {"ILLEGAL_HEX", 13, 178}, + #endif + #ifdef ASN1_R_ILLEGAL_IMPLICIT_TAG + {"ILLEGAL_IMPLICIT_TAG", ERR_LIB_ASN1, ASN1_R_ILLEGAL_IMPLICIT_TAG}, + #else + {"ILLEGAL_IMPLICIT_TAG", 13, 179}, + #endif + #ifdef ASN1_R_ILLEGAL_INTEGER + {"ILLEGAL_INTEGER", ERR_LIB_ASN1, ASN1_R_ILLEGAL_INTEGER}, + #else + {"ILLEGAL_INTEGER", 13, 180}, + #endif + #ifdef ASN1_R_ILLEGAL_NEGATIVE_VALUE + {"ILLEGAL_NEGATIVE_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NEGATIVE_VALUE}, + #else + {"ILLEGAL_NEGATIVE_VALUE", 13, 226}, + #endif + #ifdef ASN1_R_ILLEGAL_NESTED_TAGGING + {"ILLEGAL_NESTED_TAGGING", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING}, + #else + {"ILLEGAL_NESTED_TAGGING", 13, 181}, + #endif + #ifdef ASN1_R_ILLEGAL_NULL + {"ILLEGAL_NULL", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NULL}, + #else + {"ILLEGAL_NULL", 13, 125}, + #endif + #ifdef ASN1_R_ILLEGAL_NULL_VALUE + {"ILLEGAL_NULL_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_NULL_VALUE}, + #else + {"ILLEGAL_NULL_VALUE", 13, 182}, + #endif + #ifdef ASN1_R_ILLEGAL_OBJECT + {"ILLEGAL_OBJECT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OBJECT}, + #else + {"ILLEGAL_OBJECT", 13, 183}, + #endif + #ifdef ASN1_R_ILLEGAL_OPTIONAL_ANY + {"ILLEGAL_OPTIONAL_ANY", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OPTIONAL_ANY}, + #else + {"ILLEGAL_OPTIONAL_ANY", 13, 126}, + #endif + #ifdef ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE + {"ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE}, + #else + {"ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE", 13, 170}, + #endif + #ifdef ASN1_R_ILLEGAL_PADDING + {"ILLEGAL_PADDING", ERR_LIB_ASN1, ASN1_R_ILLEGAL_PADDING}, + #else + {"ILLEGAL_PADDING", 13, 221}, + #endif + #ifdef ASN1_R_ILLEGAL_TAGGED_ANY + {"ILLEGAL_TAGGED_ANY", ERR_LIB_ASN1, ASN1_R_ILLEGAL_TAGGED_ANY}, + #else + {"ILLEGAL_TAGGED_ANY", 13, 127}, + #endif + #ifdef ASN1_R_ILLEGAL_TIME_VALUE + {"ILLEGAL_TIME_VALUE", ERR_LIB_ASN1, ASN1_R_ILLEGAL_TIME_VALUE}, + #else + {"ILLEGAL_TIME_VALUE", 13, 184}, + #endif + #ifdef ASN1_R_ILLEGAL_ZERO_CONTENT + {"ILLEGAL_ZERO_CONTENT", ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT}, + #else + {"ILLEGAL_ZERO_CONTENT", 13, 222}, + #endif + #ifdef ASN1_R_INTEGER_NOT_ASCII_FORMAT + {"INTEGER_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT}, + #else + {"INTEGER_NOT_ASCII_FORMAT", 13, 185}, + #endif + #ifdef ASN1_R_INTEGER_TOO_LARGE_FOR_LONG + {"INTEGER_TOO_LARGE_FOR_LONG", ERR_LIB_ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG}, + #else + {"INTEGER_TOO_LARGE_FOR_LONG", 13, 128}, + #endif + #ifdef ASN1_R_INVALID_BIT_STRING_BITS_LEFT + {"INVALID_BIT_STRING_BITS_LEFT", ERR_LIB_ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT}, + #else + {"INVALID_BIT_STRING_BITS_LEFT", 13, 220}, + #endif + #ifdef ASN1_R_INVALID_BMPSTRING_LENGTH + {"INVALID_BMPSTRING_LENGTH", ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH}, + #else + {"INVALID_BMPSTRING_LENGTH", 13, 129}, + #endif + #ifdef ASN1_R_INVALID_DIGIT + {"INVALID_DIGIT", ERR_LIB_ASN1, ASN1_R_INVALID_DIGIT}, + #else + {"INVALID_DIGIT", 13, 130}, + #endif + #ifdef ASN1_R_INVALID_MIME_TYPE + {"INVALID_MIME_TYPE", ERR_LIB_ASN1, ASN1_R_INVALID_MIME_TYPE}, + #else + {"INVALID_MIME_TYPE", 13, 205}, + #endif + #ifdef ASN1_R_INVALID_MODIFIER + {"INVALID_MODIFIER", ERR_LIB_ASN1, ASN1_R_INVALID_MODIFIER}, + #else + {"INVALID_MODIFIER", 13, 186}, + #endif + #ifdef ASN1_R_INVALID_NUMBER + {"INVALID_NUMBER", ERR_LIB_ASN1, ASN1_R_INVALID_NUMBER}, + #else + {"INVALID_NUMBER", 13, 187}, + #endif + #ifdef ASN1_R_INVALID_OBJECT_ENCODING + {"INVALID_OBJECT_ENCODING", ERR_LIB_ASN1, ASN1_R_INVALID_OBJECT_ENCODING}, + #else + {"INVALID_OBJECT_ENCODING", 13, 216}, + #endif + #ifdef ASN1_R_INVALID_SCRYPT_PARAMETERS + {"INVALID_SCRYPT_PARAMETERS", ERR_LIB_ASN1, ASN1_R_INVALID_SCRYPT_PARAMETERS}, + #else + {"INVALID_SCRYPT_PARAMETERS", 13, 227}, + #endif + #ifdef ASN1_R_INVALID_SEPARATOR + {"INVALID_SEPARATOR", ERR_LIB_ASN1, ASN1_R_INVALID_SEPARATOR}, + #else + {"INVALID_SEPARATOR", 13, 131}, + #endif + #ifdef ASN1_R_INVALID_STRING_TABLE_VALUE + {"INVALID_STRING_TABLE_VALUE", ERR_LIB_ASN1, ASN1_R_INVALID_STRING_TABLE_VALUE}, + #else + {"INVALID_STRING_TABLE_VALUE", 13, 218}, + #endif + #ifdef ASN1_R_INVALID_UNIVERSALSTRING_LENGTH + {"INVALID_UNIVERSALSTRING_LENGTH", ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH}, + #else + {"INVALID_UNIVERSALSTRING_LENGTH", 13, 133}, + #endif + #ifdef ASN1_R_INVALID_UTF8STRING + {"INVALID_UTF8STRING", ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING}, + #else + {"INVALID_UTF8STRING", 13, 134}, + #endif + #ifdef ASN1_R_INVALID_VALUE + {"INVALID_VALUE", ERR_LIB_ASN1, ASN1_R_INVALID_VALUE}, + #else + {"INVALID_VALUE", 13, 219}, + #endif + #ifdef ASN1_R_LENGTH_TOO_LONG + {"LENGTH_TOO_LONG", ERR_LIB_ASN1, ASN1_R_LENGTH_TOO_LONG}, + #else + {"LENGTH_TOO_LONG", 13, 231}, + #endif + #ifdef ASN1_R_LIST_ERROR + {"LIST_ERROR", ERR_LIB_ASN1, ASN1_R_LIST_ERROR}, + #else + {"LIST_ERROR", 13, 188}, + #endif + #ifdef ASN1_R_MIME_NO_CONTENT_TYPE + {"MIME_NO_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_MIME_NO_CONTENT_TYPE}, + #else + {"MIME_NO_CONTENT_TYPE", 13, 206}, + #endif + #ifdef ASN1_R_MIME_PARSE_ERROR + {"MIME_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_MIME_PARSE_ERROR}, + #else + {"MIME_PARSE_ERROR", 13, 207}, + #endif + #ifdef ASN1_R_MIME_SIG_PARSE_ERROR + {"MIME_SIG_PARSE_ERROR", ERR_LIB_ASN1, ASN1_R_MIME_SIG_PARSE_ERROR}, + #else + {"MIME_SIG_PARSE_ERROR", 13, 208}, + #endif + #ifdef ASN1_R_MISSING_EOC + {"MISSING_EOC", ERR_LIB_ASN1, ASN1_R_MISSING_EOC}, + #else + {"MISSING_EOC", 13, 137}, + #endif + #ifdef ASN1_R_MISSING_SECOND_NUMBER + {"MISSING_SECOND_NUMBER", ERR_LIB_ASN1, ASN1_R_MISSING_SECOND_NUMBER}, + #else + {"MISSING_SECOND_NUMBER", 13, 138}, + #endif + #ifdef ASN1_R_MISSING_VALUE + {"MISSING_VALUE", ERR_LIB_ASN1, ASN1_R_MISSING_VALUE}, + #else + {"MISSING_VALUE", 13, 189}, + #endif + #ifdef ASN1_R_MSTRING_NOT_UNIVERSAL + {"MSTRING_NOT_UNIVERSAL", ERR_LIB_ASN1, ASN1_R_MSTRING_NOT_UNIVERSAL}, + #else + {"MSTRING_NOT_UNIVERSAL", 13, 139}, + #endif + #ifdef ASN1_R_MSTRING_WRONG_TAG + {"MSTRING_WRONG_TAG", ERR_LIB_ASN1, ASN1_R_MSTRING_WRONG_TAG}, + #else + {"MSTRING_WRONG_TAG", 13, 140}, + #endif + #ifdef ASN1_R_NESTED_ASN1_STRING + {"NESTED_ASN1_STRING", ERR_LIB_ASN1, ASN1_R_NESTED_ASN1_STRING}, + #else + {"NESTED_ASN1_STRING", 13, 197}, + #endif + #ifdef ASN1_R_NESTED_TOO_DEEP + {"NESTED_TOO_DEEP", ERR_LIB_ASN1, ASN1_R_NESTED_TOO_DEEP}, + #else + {"NESTED_TOO_DEEP", 13, 201}, + #endif + #ifdef ASN1_R_NON_HEX_CHARACTERS + {"NON_HEX_CHARACTERS", ERR_LIB_ASN1, ASN1_R_NON_HEX_CHARACTERS}, + #else + {"NON_HEX_CHARACTERS", 13, 141}, + #endif + #ifdef ASN1_R_NOT_ASCII_FORMAT + {"NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_NOT_ASCII_FORMAT}, + #else + {"NOT_ASCII_FORMAT", 13, 190}, + #endif + #ifdef ASN1_R_NOT_ENOUGH_DATA + {"NOT_ENOUGH_DATA", ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA}, + #else + {"NOT_ENOUGH_DATA", 13, 142}, + #endif + #ifdef ASN1_R_NO_CONTENT_TYPE + {"NO_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_NO_CONTENT_TYPE}, + #else + {"NO_CONTENT_TYPE", 13, 209}, + #endif + #ifdef ASN1_R_NO_MATCHING_CHOICE_TYPE + {"NO_MATCHING_CHOICE_TYPE", ERR_LIB_ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE}, + #else + {"NO_MATCHING_CHOICE_TYPE", 13, 143}, + #endif + #ifdef ASN1_R_NO_MULTIPART_BODY_FAILURE + {"NO_MULTIPART_BODY_FAILURE", ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BODY_FAILURE}, + #else + {"NO_MULTIPART_BODY_FAILURE", 13, 210}, + #endif + #ifdef ASN1_R_NO_MULTIPART_BOUNDARY + {"NO_MULTIPART_BOUNDARY", ERR_LIB_ASN1, ASN1_R_NO_MULTIPART_BOUNDARY}, + #else + {"NO_MULTIPART_BOUNDARY", 13, 211}, + #endif + #ifdef ASN1_R_NO_SIG_CONTENT_TYPE + {"NO_SIG_CONTENT_TYPE", ERR_LIB_ASN1, ASN1_R_NO_SIG_CONTENT_TYPE}, + #else + {"NO_SIG_CONTENT_TYPE", 13, 212}, + #endif + #ifdef ASN1_R_NULL_IS_WRONG_LENGTH + {"NULL_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_NULL_IS_WRONG_LENGTH}, + #else + {"NULL_IS_WRONG_LENGTH", 13, 144}, + #endif + #ifdef ASN1_R_OBJECT_NOT_ASCII_FORMAT + {"OBJECT_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT}, + #else + {"OBJECT_NOT_ASCII_FORMAT", 13, 191}, + #endif + #ifdef ASN1_R_ODD_NUMBER_OF_CHARS + {"ODD_NUMBER_OF_CHARS", ERR_LIB_ASN1, ASN1_R_ODD_NUMBER_OF_CHARS}, + #else + {"ODD_NUMBER_OF_CHARS", 13, 145}, + #endif + #ifdef ASN1_R_SECOND_NUMBER_TOO_LARGE + {"SECOND_NUMBER_TOO_LARGE", ERR_LIB_ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE}, + #else + {"SECOND_NUMBER_TOO_LARGE", 13, 147}, + #endif + #ifdef ASN1_R_SEQUENCE_LENGTH_MISMATCH + {"SEQUENCE_LENGTH_MISMATCH", ERR_LIB_ASN1, ASN1_R_SEQUENCE_LENGTH_MISMATCH}, + #else + {"SEQUENCE_LENGTH_MISMATCH", 13, 148}, + #endif + #ifdef ASN1_R_SEQUENCE_NOT_CONSTRUCTED + {"SEQUENCE_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_SEQUENCE_NOT_CONSTRUCTED}, + #else + {"SEQUENCE_NOT_CONSTRUCTED", 13, 149}, + #endif + #ifdef ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG + {"SEQUENCE_OR_SET_NEEDS_CONFIG", ERR_LIB_ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG}, + #else + {"SEQUENCE_OR_SET_NEEDS_CONFIG", 13, 192}, + #endif + #ifdef ASN1_R_SHORT_LINE + {"SHORT_LINE", ERR_LIB_ASN1, ASN1_R_SHORT_LINE}, + #else + {"SHORT_LINE", 13, 150}, + #endif + #ifdef ASN1_R_SIG_INVALID_MIME_TYPE + {"SIG_INVALID_MIME_TYPE", ERR_LIB_ASN1, ASN1_R_SIG_INVALID_MIME_TYPE}, + #else + {"SIG_INVALID_MIME_TYPE", 13, 213}, + #endif + #ifdef ASN1_R_STREAMING_NOT_SUPPORTED + {"STREAMING_NOT_SUPPORTED", ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED}, + #else + {"STREAMING_NOT_SUPPORTED", 13, 202}, + #endif + #ifdef ASN1_R_STRING_TOO_LONG + {"STRING_TOO_LONG", ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG}, + #else + {"STRING_TOO_LONG", 13, 151}, + #endif + #ifdef ASN1_R_STRING_TOO_SHORT + {"STRING_TOO_SHORT", ERR_LIB_ASN1, ASN1_R_STRING_TOO_SHORT}, + #else + {"STRING_TOO_SHORT", 13, 152}, + #endif + #ifdef ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD + {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", ERR_LIB_ASN1, ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD}, + #else + {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", 13, 154}, + #endif + #ifdef ASN1_R_TIME_NOT_ASCII_FORMAT + {"TIME_NOT_ASCII_FORMAT", ERR_LIB_ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT}, + #else + {"TIME_NOT_ASCII_FORMAT", 13, 193}, + #endif + #ifdef ASN1_R_TOO_LARGE + {"TOO_LARGE", ERR_LIB_ASN1, ASN1_R_TOO_LARGE}, + #else + {"TOO_LARGE", 13, 223}, + #endif + #ifdef ASN1_R_TOO_LONG + {"TOO_LONG", ERR_LIB_ASN1, ASN1_R_TOO_LONG}, + #else + {"TOO_LONG", 13, 155}, + #endif + #ifdef ASN1_R_TOO_SMALL + {"TOO_SMALL", ERR_LIB_ASN1, ASN1_R_TOO_SMALL}, + #else + {"TOO_SMALL", 13, 224}, + #endif + #ifdef ASN1_R_TYPE_NOT_CONSTRUCTED + {"TYPE_NOT_CONSTRUCTED", ERR_LIB_ASN1, ASN1_R_TYPE_NOT_CONSTRUCTED}, + #else + {"TYPE_NOT_CONSTRUCTED", 13, 156}, + #endif + #ifdef ASN1_R_TYPE_NOT_PRIMITIVE + {"TYPE_NOT_PRIMITIVE", ERR_LIB_ASN1, ASN1_R_TYPE_NOT_PRIMITIVE}, + #else + {"TYPE_NOT_PRIMITIVE", 13, 195}, + #endif + #ifdef ASN1_R_UNEXPECTED_EOC + {"UNEXPECTED_EOC", ERR_LIB_ASN1, ASN1_R_UNEXPECTED_EOC}, + #else + {"UNEXPECTED_EOC", 13, 159}, + #endif + #ifdef ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH + {"UNIVERSALSTRING_IS_WRONG_LENGTH", ERR_LIB_ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH}, + #else + {"UNIVERSALSTRING_IS_WRONG_LENGTH", 13, 215}, + #endif + #ifdef ASN1_R_UNKNOWN_DIGEST + {"UNKNOWN_DIGEST", ERR_LIB_ASN1, ASN1_R_UNKNOWN_DIGEST}, + #else + {"UNKNOWN_DIGEST", 13, 229}, + #endif + #ifdef ASN1_R_UNKNOWN_FORMAT + {"UNKNOWN_FORMAT", ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT}, + #else + {"UNKNOWN_FORMAT", 13, 160}, + #endif + #ifdef ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM + {"UNKNOWN_MESSAGE_DIGEST_ALGORITHM", ERR_LIB_ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM}, + #else + {"UNKNOWN_MESSAGE_DIGEST_ALGORITHM", 13, 161}, + #endif + #ifdef ASN1_R_UNKNOWN_OBJECT_TYPE + {"UNKNOWN_OBJECT_TYPE", ERR_LIB_ASN1, ASN1_R_UNKNOWN_OBJECT_TYPE}, + #else + {"UNKNOWN_OBJECT_TYPE", 13, 162}, + #endif + #ifdef ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE + {"UNKNOWN_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE}, + #else + {"UNKNOWN_PUBLIC_KEY_TYPE", 13, 163}, + #endif + #ifdef ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM + {"UNKNOWN_SIGNATURE_ALGORITHM", ERR_LIB_ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM}, + #else + {"UNKNOWN_SIGNATURE_ALGORITHM", 13, 199}, + #endif + #ifdef ASN1_R_UNKNOWN_TAG + {"UNKNOWN_TAG", ERR_LIB_ASN1, ASN1_R_UNKNOWN_TAG}, + #else + {"UNKNOWN_TAG", 13, 194}, + #endif + #ifdef ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE + {"UNSUPPORTED_ANY_DEFINED_BY_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE}, + #else + {"UNSUPPORTED_ANY_DEFINED_BY_TYPE", 13, 164}, + #endif + #ifdef ASN1_R_UNSUPPORTED_CIPHER + {"UNSUPPORTED_CIPHER", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_CIPHER}, + #else + {"UNSUPPORTED_CIPHER", 13, 228}, + #endif + #ifdef ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE + {"UNSUPPORTED_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE}, + #else + {"UNSUPPORTED_PUBLIC_KEY_TYPE", 13, 167}, + #endif + #ifdef ASN1_R_UNSUPPORTED_TYPE + {"UNSUPPORTED_TYPE", ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_TYPE}, + #else + {"UNSUPPORTED_TYPE", 13, 196}, + #endif + #ifdef ASN1_R_WRONG_INTEGER_TYPE + {"WRONG_INTEGER_TYPE", ERR_LIB_ASN1, ASN1_R_WRONG_INTEGER_TYPE}, + #else + {"WRONG_INTEGER_TYPE", 13, 225}, + #endif + #ifdef ASN1_R_WRONG_PUBLIC_KEY_TYPE + {"WRONG_PUBLIC_KEY_TYPE", ERR_LIB_ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE}, + #else + {"WRONG_PUBLIC_KEY_TYPE", 13, 200}, + #endif + #ifdef ASN1_R_WRONG_TAG + {"WRONG_TAG", ERR_LIB_ASN1, ASN1_R_WRONG_TAG}, + #else + {"WRONG_TAG", 13, 168}, + #endif + #ifdef ASYNC_R_FAILED_TO_SET_POOL + {"FAILED_TO_SET_POOL", ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SET_POOL}, + #else + {"FAILED_TO_SET_POOL", 51, 101}, + #endif + #ifdef ASYNC_R_FAILED_TO_SWAP_CONTEXT + {"FAILED_TO_SWAP_CONTEXT", ERR_LIB_ASYNC, ASYNC_R_FAILED_TO_SWAP_CONTEXT}, + #else + {"FAILED_TO_SWAP_CONTEXT", 51, 102}, + #endif + #ifdef ASYNC_R_INIT_FAILED + {"INIT_FAILED", ERR_LIB_ASYNC, ASYNC_R_INIT_FAILED}, + #else + {"INIT_FAILED", 51, 105}, + #endif + #ifdef ASYNC_R_INVALID_POOL_SIZE + {"INVALID_POOL_SIZE", ERR_LIB_ASYNC, ASYNC_R_INVALID_POOL_SIZE}, + #else + {"INVALID_POOL_SIZE", 51, 103}, + #endif + #ifdef BIO_R_ACCEPT_ERROR + {"ACCEPT_ERROR", ERR_LIB_BIO, BIO_R_ACCEPT_ERROR}, + #else + {"ACCEPT_ERROR", 32, 100}, + #endif + #ifdef BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET + {"ADDRINFO_ADDR_IS_NOT_AF_INET", ERR_LIB_BIO, BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET}, + #else + {"ADDRINFO_ADDR_IS_NOT_AF_INET", 32, 141}, + #endif + #ifdef BIO_R_AMBIGUOUS_HOST_OR_SERVICE + {"AMBIGUOUS_HOST_OR_SERVICE", ERR_LIB_BIO, BIO_R_AMBIGUOUS_HOST_OR_SERVICE}, + #else + {"AMBIGUOUS_HOST_OR_SERVICE", 32, 129}, + #endif + #ifdef BIO_R_BAD_FOPEN_MODE + {"BAD_FOPEN_MODE", ERR_LIB_BIO, BIO_R_BAD_FOPEN_MODE}, + #else + {"BAD_FOPEN_MODE", 32, 101}, + #endif + #ifdef BIO_R_BROKEN_PIPE + {"BROKEN_PIPE", ERR_LIB_BIO, BIO_R_BROKEN_PIPE}, + #else + {"BROKEN_PIPE", 32, 124}, + #endif + #ifdef BIO_R_CONNECT_ERROR + {"CONNECT_ERROR", ERR_LIB_BIO, BIO_R_CONNECT_ERROR}, + #else + {"CONNECT_ERROR", 32, 103}, + #endif + #ifdef BIO_R_CONNECT_TIMEOUT + {"CONNECT_TIMEOUT", ERR_LIB_BIO, BIO_R_CONNECT_TIMEOUT}, + #else + {"CONNECT_TIMEOUT", 32, 147}, + #endif + #ifdef BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET + {"GETHOSTBYNAME_ADDR_IS_NOT_AF_INET", ERR_LIB_BIO, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET}, + #else + {"GETHOSTBYNAME_ADDR_IS_NOT_AF_INET", 32, 107}, + #endif + #ifdef BIO_R_GETSOCKNAME_ERROR + {"GETSOCKNAME_ERROR", ERR_LIB_BIO, BIO_R_GETSOCKNAME_ERROR}, + #else + {"GETSOCKNAME_ERROR", 32, 132}, + #endif + #ifdef BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS + {"GETSOCKNAME_TRUNCATED_ADDRESS", ERR_LIB_BIO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS}, + #else + {"GETSOCKNAME_TRUNCATED_ADDRESS", 32, 133}, + #endif + #ifdef BIO_R_GETTING_SOCKTYPE + {"GETTING_SOCKTYPE", ERR_LIB_BIO, BIO_R_GETTING_SOCKTYPE}, + #else + {"GETTING_SOCKTYPE", 32, 134}, + #endif + #ifdef BIO_R_INVALID_ARGUMENT + {"INVALID_ARGUMENT", ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT}, + #else + {"INVALID_ARGUMENT", 32, 125}, + #endif + #ifdef BIO_R_INVALID_SOCKET + {"INVALID_SOCKET", ERR_LIB_BIO, BIO_R_INVALID_SOCKET}, + #else + {"INVALID_SOCKET", 32, 135}, + #endif + #ifdef BIO_R_IN_USE + {"IN_USE", ERR_LIB_BIO, BIO_R_IN_USE}, + #else + {"IN_USE", 32, 123}, + #endif + #ifdef BIO_R_LENGTH_TOO_LONG + {"LENGTH_TOO_LONG", ERR_LIB_BIO, BIO_R_LENGTH_TOO_LONG}, + #else + {"LENGTH_TOO_LONG", 32, 102}, + #endif + #ifdef BIO_R_LISTEN_V6_ONLY + {"LISTEN_V6_ONLY", ERR_LIB_BIO, BIO_R_LISTEN_V6_ONLY}, + #else + {"LISTEN_V6_ONLY", 32, 136}, + #endif + #ifdef BIO_R_LOOKUP_RETURNED_NOTHING + {"LOOKUP_RETURNED_NOTHING", ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING}, + #else + {"LOOKUP_RETURNED_NOTHING", 32, 142}, + #endif + #ifdef BIO_R_MALFORMED_HOST_OR_SERVICE + {"MALFORMED_HOST_OR_SERVICE", ERR_LIB_BIO, BIO_R_MALFORMED_HOST_OR_SERVICE}, + #else + {"MALFORMED_HOST_OR_SERVICE", 32, 130}, + #endif + #ifdef BIO_R_NBIO_CONNECT_ERROR + {"NBIO_CONNECT_ERROR", ERR_LIB_BIO, BIO_R_NBIO_CONNECT_ERROR}, + #else + {"NBIO_CONNECT_ERROR", 32, 110}, + #endif + #ifdef BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED + {"NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED", ERR_LIB_BIO, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED}, + #else + {"NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED", 32, 143}, + #endif + #ifdef BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED + {"NO_HOSTNAME_OR_SERVICE_SPECIFIED", ERR_LIB_BIO, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED}, + #else + {"NO_HOSTNAME_OR_SERVICE_SPECIFIED", 32, 144}, + #endif + #ifdef BIO_R_NO_PORT_DEFINED + {"NO_PORT_DEFINED", ERR_LIB_BIO, BIO_R_NO_PORT_DEFINED}, + #else + {"NO_PORT_DEFINED", 32, 113}, + #endif + #ifdef BIO_R_NO_SUCH_FILE + {"NO_SUCH_FILE", ERR_LIB_BIO, BIO_R_NO_SUCH_FILE}, + #else + {"NO_SUCH_FILE", 32, 128}, + #endif + #ifdef BIO_R_TRANSFER_ERROR + {"TRANSFER_ERROR", ERR_LIB_BIO, BIO_R_TRANSFER_ERROR}, + #else + {"TRANSFER_ERROR", 32, 104}, + #endif + #ifdef BIO_R_TRANSFER_TIMEOUT + {"TRANSFER_TIMEOUT", ERR_LIB_BIO, BIO_R_TRANSFER_TIMEOUT}, + #else + {"TRANSFER_TIMEOUT", 32, 105}, + #endif + #ifdef BIO_R_UNABLE_TO_BIND_SOCKET + {"UNABLE_TO_BIND_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_BIND_SOCKET}, + #else + {"UNABLE_TO_BIND_SOCKET", 32, 117}, + #endif + #ifdef BIO_R_UNABLE_TO_CREATE_SOCKET + {"UNABLE_TO_CREATE_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET}, + #else + {"UNABLE_TO_CREATE_SOCKET", 32, 118}, + #endif + #ifdef BIO_R_UNABLE_TO_KEEPALIVE + {"UNABLE_TO_KEEPALIVE", ERR_LIB_BIO, BIO_R_UNABLE_TO_KEEPALIVE}, + #else + {"UNABLE_TO_KEEPALIVE", 32, 137}, + #endif + #ifdef BIO_R_UNABLE_TO_LISTEN_SOCKET + {"UNABLE_TO_LISTEN_SOCKET", ERR_LIB_BIO, BIO_R_UNABLE_TO_LISTEN_SOCKET}, + #else + {"UNABLE_TO_LISTEN_SOCKET", 32, 119}, + #endif + #ifdef BIO_R_UNABLE_TO_NODELAY + {"UNABLE_TO_NODELAY", ERR_LIB_BIO, BIO_R_UNABLE_TO_NODELAY}, + #else + {"UNABLE_TO_NODELAY", 32, 138}, + #endif + #ifdef BIO_R_UNABLE_TO_REUSEADDR + {"UNABLE_TO_REUSEADDR", ERR_LIB_BIO, BIO_R_UNABLE_TO_REUSEADDR}, + #else + {"UNABLE_TO_REUSEADDR", 32, 139}, + #endif + #ifdef BIO_R_UNAVAILABLE_IP_FAMILY + {"UNAVAILABLE_IP_FAMILY", ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY}, + #else + {"UNAVAILABLE_IP_FAMILY", 32, 145}, + #endif + #ifdef BIO_R_UNINITIALIZED + {"UNINITIALIZED", ERR_LIB_BIO, BIO_R_UNINITIALIZED}, + #else + {"UNINITIALIZED", 32, 120}, + #endif + #ifdef BIO_R_UNKNOWN_INFO_TYPE + {"UNKNOWN_INFO_TYPE", ERR_LIB_BIO, BIO_R_UNKNOWN_INFO_TYPE}, + #else + {"UNKNOWN_INFO_TYPE", 32, 140}, + #endif + #ifdef BIO_R_UNSUPPORTED_IP_FAMILY + {"UNSUPPORTED_IP_FAMILY", ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY}, + #else + {"UNSUPPORTED_IP_FAMILY", 32, 146}, + #endif + #ifdef BIO_R_UNSUPPORTED_METHOD + {"UNSUPPORTED_METHOD", ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD}, + #else + {"UNSUPPORTED_METHOD", 32, 121}, + #endif + #ifdef BIO_R_UNSUPPORTED_PROTOCOL_FAMILY + {"UNSUPPORTED_PROTOCOL_FAMILY", ERR_LIB_BIO, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY}, + #else + {"UNSUPPORTED_PROTOCOL_FAMILY", 32, 131}, + #endif + #ifdef BIO_R_WRITE_TO_READ_ONLY_BIO + {"WRITE_TO_READ_ONLY_BIO", ERR_LIB_BIO, BIO_R_WRITE_TO_READ_ONLY_BIO}, + #else + {"WRITE_TO_READ_ONLY_BIO", 32, 126}, + #endif + #ifdef BIO_R_WSASTARTUP + {"WSASTARTUP", ERR_LIB_BIO, BIO_R_WSASTARTUP}, + #else + {"WSASTARTUP", 32, 122}, + #endif + #ifdef BN_R_ARG2_LT_ARG3 + {"ARG2_LT_ARG3", ERR_LIB_BN, BN_R_ARG2_LT_ARG3}, + #else + {"ARG2_LT_ARG3", 3, 100}, + #endif + #ifdef BN_R_BAD_RECIPROCAL + {"BAD_RECIPROCAL", ERR_LIB_BN, BN_R_BAD_RECIPROCAL}, + #else + {"BAD_RECIPROCAL", 3, 101}, + #endif + #ifdef BN_R_BIGNUM_TOO_LONG + {"BIGNUM_TOO_LONG", ERR_LIB_BN, BN_R_BIGNUM_TOO_LONG}, + #else + {"BIGNUM_TOO_LONG", 3, 114}, + #endif + #ifdef BN_R_BITS_TOO_SMALL + {"BITS_TOO_SMALL", ERR_LIB_BN, BN_R_BITS_TOO_SMALL}, + #else + {"BITS_TOO_SMALL", 3, 118}, + #endif + #ifdef BN_R_CALLED_WITH_EVEN_MODULUS + {"CALLED_WITH_EVEN_MODULUS", ERR_LIB_BN, BN_R_CALLED_WITH_EVEN_MODULUS}, + #else + {"CALLED_WITH_EVEN_MODULUS", 3, 102}, + #endif + #ifdef BN_R_DIV_BY_ZERO + {"DIV_BY_ZERO", ERR_LIB_BN, BN_R_DIV_BY_ZERO}, + #else + {"DIV_BY_ZERO", 3, 103}, + #endif + #ifdef BN_R_ENCODING_ERROR + {"ENCODING_ERROR", ERR_LIB_BN, BN_R_ENCODING_ERROR}, + #else + {"ENCODING_ERROR", 3, 104}, + #endif + #ifdef BN_R_EXPAND_ON_STATIC_BIGNUM_DATA + {"EXPAND_ON_STATIC_BIGNUM_DATA", ERR_LIB_BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA}, + #else + {"EXPAND_ON_STATIC_BIGNUM_DATA", 3, 105}, + #endif + #ifdef BN_R_INPUT_NOT_REDUCED + {"INPUT_NOT_REDUCED", ERR_LIB_BN, BN_R_INPUT_NOT_REDUCED}, + #else + {"INPUT_NOT_REDUCED", 3, 110}, + #endif + #ifdef BN_R_INVALID_LENGTH + {"INVALID_LENGTH", ERR_LIB_BN, BN_R_INVALID_LENGTH}, + #else + {"INVALID_LENGTH", 3, 106}, + #endif + #ifdef BN_R_INVALID_RANGE + {"INVALID_RANGE", ERR_LIB_BN, BN_R_INVALID_RANGE}, + #else + {"INVALID_RANGE", 3, 115}, + #endif + #ifdef BN_R_INVALID_SHIFT + {"INVALID_SHIFT", ERR_LIB_BN, BN_R_INVALID_SHIFT}, + #else + {"INVALID_SHIFT", 3, 119}, + #endif + #ifdef BN_R_NOT_A_SQUARE + {"NOT_A_SQUARE", ERR_LIB_BN, BN_R_NOT_A_SQUARE}, + #else + {"NOT_A_SQUARE", 3, 111}, + #endif + #ifdef BN_R_NOT_INITIALIZED + {"NOT_INITIALIZED", ERR_LIB_BN, BN_R_NOT_INITIALIZED}, + #else + {"NOT_INITIALIZED", 3, 107}, + #endif + #ifdef BN_R_NO_INVERSE + {"NO_INVERSE", ERR_LIB_BN, BN_R_NO_INVERSE}, + #else + {"NO_INVERSE", 3, 108}, + #endif + #ifdef BN_R_NO_PRIME_CANDIDATE + {"NO_PRIME_CANDIDATE", ERR_LIB_BN, BN_R_NO_PRIME_CANDIDATE}, + #else + {"NO_PRIME_CANDIDATE", 3, 121}, + #endif + #ifdef BN_R_NO_SOLUTION + {"NO_SOLUTION", ERR_LIB_BN, BN_R_NO_SOLUTION}, + #else + {"NO_SOLUTION", 3, 116}, + #endif + #ifdef BN_R_NO_SUITABLE_DIGEST + {"NO_SUITABLE_DIGEST", ERR_LIB_BN, BN_R_NO_SUITABLE_DIGEST}, + #else + {"NO_SUITABLE_DIGEST", 3, 120}, + #endif + #ifdef BN_R_PRIVATE_KEY_TOO_LARGE + {"PRIVATE_KEY_TOO_LARGE", ERR_LIB_BN, BN_R_PRIVATE_KEY_TOO_LARGE}, + #else + {"PRIVATE_KEY_TOO_LARGE", 3, 117}, + #endif + #ifdef BN_R_P_IS_NOT_PRIME + {"P_IS_NOT_PRIME", ERR_LIB_BN, BN_R_P_IS_NOT_PRIME}, + #else + {"P_IS_NOT_PRIME", 3, 112}, + #endif + #ifdef BN_R_TOO_MANY_ITERATIONS + {"TOO_MANY_ITERATIONS", ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS}, + #else + {"TOO_MANY_ITERATIONS", 3, 113}, + #endif + #ifdef BN_R_TOO_MANY_TEMPORARY_VARIABLES + {"TOO_MANY_TEMPORARY_VARIABLES", ERR_LIB_BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES}, + #else + {"TOO_MANY_TEMPORARY_VARIABLES", 3, 109}, + #endif + #ifdef CMP_R_ALGORITHM_NOT_SUPPORTED + {"ALGORITHM_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_ALGORITHM_NOT_SUPPORTED}, + #else + {"ALGORITHM_NOT_SUPPORTED", 58, 139}, + #endif + #ifdef CMP_R_BAD_CHECKAFTER_IN_POLLREP + {"BAD_CHECKAFTER_IN_POLLREP", ERR_LIB_CMP, CMP_R_BAD_CHECKAFTER_IN_POLLREP}, + #else + {"BAD_CHECKAFTER_IN_POLLREP", 58, 167}, + #endif + #ifdef CMP_R_BAD_REQUEST_ID + {"BAD_REQUEST_ID", ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID}, + #else + {"BAD_REQUEST_ID", 58, 108}, + #endif + #ifdef CMP_R_CERTHASH_UNMATCHED + {"CERTHASH_UNMATCHED", ERR_LIB_CMP, CMP_R_CERTHASH_UNMATCHED}, + #else + {"CERTHASH_UNMATCHED", 58, 156}, + #endif + #ifdef CMP_R_CERTID_NOT_FOUND + {"CERTID_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTID_NOT_FOUND}, + #else + {"CERTID_NOT_FOUND", 58, 109}, + #endif + #ifdef CMP_R_CERTIFICATE_NOT_ACCEPTED + {"CERTIFICATE_NOT_ACCEPTED", ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_ACCEPTED}, + #else + {"CERTIFICATE_NOT_ACCEPTED", 58, 169}, + #endif + #ifdef CMP_R_CERTIFICATE_NOT_FOUND + {"CERTIFICATE_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_FOUND}, + #else + {"CERTIFICATE_NOT_FOUND", 58, 112}, + #endif + #ifdef CMP_R_CERTREQMSG_NOT_FOUND + {"CERTREQMSG_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTREQMSG_NOT_FOUND}, + #else + {"CERTREQMSG_NOT_FOUND", 58, 157}, + #endif + #ifdef CMP_R_CERTRESPONSE_NOT_FOUND + {"CERTRESPONSE_NOT_FOUND", ERR_LIB_CMP, CMP_R_CERTRESPONSE_NOT_FOUND}, + #else + {"CERTRESPONSE_NOT_FOUND", 58, 113}, + #endif + #ifdef CMP_R_CERT_AND_KEY_DO_NOT_MATCH + {"CERT_AND_KEY_DO_NOT_MATCH", ERR_LIB_CMP, CMP_R_CERT_AND_KEY_DO_NOT_MATCH}, + #else + {"CERT_AND_KEY_DO_NOT_MATCH", 58, 114}, + #endif + #ifdef CMP_R_CHECKAFTER_OUT_OF_RANGE + {"CHECKAFTER_OUT_OF_RANGE", ERR_LIB_CMP, CMP_R_CHECKAFTER_OUT_OF_RANGE}, + #else + {"CHECKAFTER_OUT_OF_RANGE", 58, 181}, + #endif + #ifdef CMP_R_ENCOUNTERED_KEYUPDATEWARNING + {"ENCOUNTERED_KEYUPDATEWARNING", ERR_LIB_CMP, CMP_R_ENCOUNTERED_KEYUPDATEWARNING}, + #else + {"ENCOUNTERED_KEYUPDATEWARNING", 58, 176}, + #endif + #ifdef CMP_R_ENCOUNTERED_WAITING + {"ENCOUNTERED_WAITING", ERR_LIB_CMP, CMP_R_ENCOUNTERED_WAITING}, + #else + {"ENCOUNTERED_WAITING", 58, 162}, + #endif + #ifdef CMP_R_ERROR_CALCULATING_PROTECTION + {"ERROR_CALCULATING_PROTECTION", ERR_LIB_CMP, CMP_R_ERROR_CALCULATING_PROTECTION}, + #else + {"ERROR_CALCULATING_PROTECTION", 58, 115}, + #endif + #ifdef CMP_R_ERROR_CREATING_CERTCONF + {"ERROR_CREATING_CERTCONF", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTCONF}, + #else + {"ERROR_CREATING_CERTCONF", 58, 116}, + #endif + #ifdef CMP_R_ERROR_CREATING_CERTREP + {"ERROR_CREATING_CERTREP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTREP}, + #else + {"ERROR_CREATING_CERTREP", 58, 117}, + #endif + #ifdef CMP_R_ERROR_CREATING_CERTREQ + {"ERROR_CREATING_CERTREQ", ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTREQ}, + #else + {"ERROR_CREATING_CERTREQ", 58, 163}, + #endif + #ifdef CMP_R_ERROR_CREATING_ERROR + {"ERROR_CREATING_ERROR", ERR_LIB_CMP, CMP_R_ERROR_CREATING_ERROR}, + #else + {"ERROR_CREATING_ERROR", 58, 118}, + #endif + #ifdef CMP_R_ERROR_CREATING_GENM + {"ERROR_CREATING_GENM", ERR_LIB_CMP, CMP_R_ERROR_CREATING_GENM}, + #else + {"ERROR_CREATING_GENM", 58, 119}, + #endif + #ifdef CMP_R_ERROR_CREATING_GENP + {"ERROR_CREATING_GENP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_GENP}, + #else + {"ERROR_CREATING_GENP", 58, 120}, + #endif + #ifdef CMP_R_ERROR_CREATING_PKICONF + {"ERROR_CREATING_PKICONF", ERR_LIB_CMP, CMP_R_ERROR_CREATING_PKICONF}, + #else + {"ERROR_CREATING_PKICONF", 58, 122}, + #endif + #ifdef CMP_R_ERROR_CREATING_POLLREP + {"ERROR_CREATING_POLLREP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_POLLREP}, + #else + {"ERROR_CREATING_POLLREP", 58, 123}, + #endif + #ifdef CMP_R_ERROR_CREATING_POLLREQ + {"ERROR_CREATING_POLLREQ", ERR_LIB_CMP, CMP_R_ERROR_CREATING_POLLREQ}, + #else + {"ERROR_CREATING_POLLREQ", 58, 124}, + #endif + #ifdef CMP_R_ERROR_CREATING_RP + {"ERROR_CREATING_RP", ERR_LIB_CMP, CMP_R_ERROR_CREATING_RP}, + #else + {"ERROR_CREATING_RP", 58, 125}, + #endif + #ifdef CMP_R_ERROR_CREATING_RR + {"ERROR_CREATING_RR", ERR_LIB_CMP, CMP_R_ERROR_CREATING_RR}, + #else + {"ERROR_CREATING_RR", 58, 126}, + #endif + #ifdef CMP_R_ERROR_PARSING_PKISTATUS + {"ERROR_PARSING_PKISTATUS", ERR_LIB_CMP, CMP_R_ERROR_PARSING_PKISTATUS}, + #else + {"ERROR_PARSING_PKISTATUS", 58, 107}, + #endif + #ifdef CMP_R_ERROR_PROCESSING_MESSAGE + {"ERROR_PROCESSING_MESSAGE", ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE}, + #else + {"ERROR_PROCESSING_MESSAGE", 58, 158}, + #endif + #ifdef CMP_R_ERROR_PROTECTING_MESSAGE + {"ERROR_PROTECTING_MESSAGE", ERR_LIB_CMP, CMP_R_ERROR_PROTECTING_MESSAGE}, + #else + {"ERROR_PROTECTING_MESSAGE", 58, 127}, + #endif + #ifdef CMP_R_ERROR_SETTING_CERTHASH + {"ERROR_SETTING_CERTHASH", ERR_LIB_CMP, CMP_R_ERROR_SETTING_CERTHASH}, + #else + {"ERROR_SETTING_CERTHASH", 58, 128}, + #endif + #ifdef CMP_R_ERROR_UNEXPECTED_CERTCONF + {"ERROR_UNEXPECTED_CERTCONF", ERR_LIB_CMP, CMP_R_ERROR_UNEXPECTED_CERTCONF}, + #else + {"ERROR_UNEXPECTED_CERTCONF", 58, 160}, + #endif + #ifdef CMP_R_ERROR_VALIDATING_PROTECTION + {"ERROR_VALIDATING_PROTECTION", ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION}, + #else + {"ERROR_VALIDATING_PROTECTION", 58, 140}, + #endif + #ifdef CMP_R_ERROR_VALIDATING_SIGNATURE + {"ERROR_VALIDATING_SIGNATURE", ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_SIGNATURE}, + #else + {"ERROR_VALIDATING_SIGNATURE", 58, 171}, + #endif + #ifdef CMP_R_FAILED_BUILDING_OWN_CHAIN + {"FAILED_BUILDING_OWN_CHAIN", ERR_LIB_CMP, CMP_R_FAILED_BUILDING_OWN_CHAIN}, + #else + {"FAILED_BUILDING_OWN_CHAIN", 58, 164}, + #endif + #ifdef CMP_R_FAILED_EXTRACTING_PUBKEY + {"FAILED_EXTRACTING_PUBKEY", ERR_LIB_CMP, CMP_R_FAILED_EXTRACTING_PUBKEY}, + #else + {"FAILED_EXTRACTING_PUBKEY", 58, 141}, + #endif + #ifdef CMP_R_FAILURE_OBTAINING_RANDOM + {"FAILURE_OBTAINING_RANDOM", ERR_LIB_CMP, CMP_R_FAILURE_OBTAINING_RANDOM}, + #else + {"FAILURE_OBTAINING_RANDOM", 58, 110}, + #endif + #ifdef CMP_R_FAIL_INFO_OUT_OF_RANGE + {"FAIL_INFO_OUT_OF_RANGE", ERR_LIB_CMP, CMP_R_FAIL_INFO_OUT_OF_RANGE}, + #else + {"FAIL_INFO_OUT_OF_RANGE", 58, 129}, + #endif + #ifdef CMP_R_INVALID_ARGS + {"INVALID_ARGS", ERR_LIB_CMP, CMP_R_INVALID_ARGS}, + #else + {"INVALID_ARGS", 58, 100}, + #endif + #ifdef CMP_R_INVALID_OPTION + {"INVALID_OPTION", ERR_LIB_CMP, CMP_R_INVALID_OPTION}, + #else + {"INVALID_OPTION", 58, 174}, + #endif + #ifdef CMP_R_MISSING_CERTID + {"MISSING_CERTID", ERR_LIB_CMP, CMP_R_MISSING_CERTID}, + #else + {"MISSING_CERTID", 58, 165}, + #endif + #ifdef CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION + {"MISSING_KEY_INPUT_FOR_CREATING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION}, + #else + {"MISSING_KEY_INPUT_FOR_CREATING_PROTECTION", 58, 130}, + #endif + #ifdef CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE + {"MISSING_KEY_USAGE_DIGITALSIGNATURE", ERR_LIB_CMP, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE}, + #else + {"MISSING_KEY_USAGE_DIGITALSIGNATURE", 58, 142}, + #endif + #ifdef CMP_R_MISSING_P10CSR + {"MISSING_P10CSR", ERR_LIB_CMP, CMP_R_MISSING_P10CSR}, + #else + {"MISSING_P10CSR", 58, 121}, + #endif + #ifdef CMP_R_MISSING_PBM_SECRET + {"MISSING_PBM_SECRET", ERR_LIB_CMP, CMP_R_MISSING_PBM_SECRET}, + #else + {"MISSING_PBM_SECRET", 58, 166}, + #endif + #ifdef CMP_R_MISSING_PRIVATE_KEY + {"MISSING_PRIVATE_KEY", ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY}, + #else + {"MISSING_PRIVATE_KEY", 58, 131}, + #endif + #ifdef CMP_R_MISSING_PRIVATE_KEY_FOR_POPO + {"MISSING_PRIVATE_KEY_FOR_POPO", ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY_FOR_POPO}, + #else + {"MISSING_PRIVATE_KEY_FOR_POPO", 58, 190}, + #endif + #ifdef CMP_R_MISSING_PROTECTION + {"MISSING_PROTECTION", ERR_LIB_CMP, CMP_R_MISSING_PROTECTION}, + #else + {"MISSING_PROTECTION", 58, 143}, + #endif + #ifdef CMP_R_MISSING_PUBLIC_KEY + {"MISSING_PUBLIC_KEY", ERR_LIB_CMP, CMP_R_MISSING_PUBLIC_KEY}, + #else + {"MISSING_PUBLIC_KEY", 58, 183}, + #endif + #ifdef CMP_R_MISSING_REFERENCE_CERT + {"MISSING_REFERENCE_CERT", ERR_LIB_CMP, CMP_R_MISSING_REFERENCE_CERT}, + #else + {"MISSING_REFERENCE_CERT", 58, 168}, + #endif + #ifdef CMP_R_MISSING_SECRET + {"MISSING_SECRET", ERR_LIB_CMP, CMP_R_MISSING_SECRET}, + #else + {"MISSING_SECRET", 58, 178}, + #endif + #ifdef CMP_R_MISSING_SENDER_IDENTIFICATION + {"MISSING_SENDER_IDENTIFICATION", ERR_LIB_CMP, CMP_R_MISSING_SENDER_IDENTIFICATION}, + #else + {"MISSING_SENDER_IDENTIFICATION", 58, 111}, + #endif + #ifdef CMP_R_MISSING_TRUST_ANCHOR + {"MISSING_TRUST_ANCHOR", ERR_LIB_CMP, CMP_R_MISSING_TRUST_ANCHOR}, + #else + {"MISSING_TRUST_ANCHOR", 58, 179}, + #endif + #ifdef CMP_R_MISSING_TRUST_STORE + {"MISSING_TRUST_STORE", ERR_LIB_CMP, CMP_R_MISSING_TRUST_STORE}, + #else + {"MISSING_TRUST_STORE", 58, 144}, + #endif + #ifdef CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED + {"MULTIPLE_REQUESTS_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED}, + #else + {"MULTIPLE_REQUESTS_NOT_SUPPORTED", 58, 161}, + #endif + #ifdef CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED + {"MULTIPLE_RESPONSES_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED}, + #else + {"MULTIPLE_RESPONSES_NOT_SUPPORTED", 58, 170}, + #endif + #ifdef CMP_R_MULTIPLE_SAN_SOURCES + {"MULTIPLE_SAN_SOURCES", ERR_LIB_CMP, CMP_R_MULTIPLE_SAN_SOURCES}, + #else + {"MULTIPLE_SAN_SOURCES", 58, 102}, + #endif + #ifdef CMP_R_NO_STDIO + {"NO_STDIO", ERR_LIB_CMP, CMP_R_NO_STDIO}, + #else + {"NO_STDIO", 58, 194}, + #endif + #ifdef CMP_R_NO_SUITABLE_SENDER_CERT + {"NO_SUITABLE_SENDER_CERT", ERR_LIB_CMP, CMP_R_NO_SUITABLE_SENDER_CERT}, + #else + {"NO_SUITABLE_SENDER_CERT", 58, 145}, + #endif + #ifdef CMP_R_NULL_ARGUMENT + {"NULL_ARGUMENT", ERR_LIB_CMP, CMP_R_NULL_ARGUMENT}, + #else + {"NULL_ARGUMENT", 58, 103}, + #endif + #ifdef CMP_R_PKIBODY_ERROR + {"PKIBODY_ERROR", ERR_LIB_CMP, CMP_R_PKIBODY_ERROR}, + #else + {"PKIBODY_ERROR", 58, 146}, + #endif + #ifdef CMP_R_PKISTATUSINFO_NOT_FOUND + {"PKISTATUSINFO_NOT_FOUND", ERR_LIB_CMP, CMP_R_PKISTATUSINFO_NOT_FOUND}, + #else + {"PKISTATUSINFO_NOT_FOUND", 58, 132}, + #endif + #ifdef CMP_R_POLLING_FAILED + {"POLLING_FAILED", ERR_LIB_CMP, CMP_R_POLLING_FAILED}, + #else + {"POLLING_FAILED", 58, 172}, + #endif + #ifdef CMP_R_POTENTIALLY_INVALID_CERTIFICATE + {"POTENTIALLY_INVALID_CERTIFICATE", ERR_LIB_CMP, CMP_R_POTENTIALLY_INVALID_CERTIFICATE}, + #else + {"POTENTIALLY_INVALID_CERTIFICATE", 58, 147}, + #endif + #ifdef CMP_R_RECEIVED_ERROR + {"RECEIVED_ERROR", ERR_LIB_CMP, CMP_R_RECEIVED_ERROR}, + #else + {"RECEIVED_ERROR", 58, 180}, + #endif + #ifdef CMP_R_RECIPNONCE_UNMATCHED + {"RECIPNONCE_UNMATCHED", ERR_LIB_CMP, CMP_R_RECIPNONCE_UNMATCHED}, + #else + {"RECIPNONCE_UNMATCHED", 58, 148}, + #endif + #ifdef CMP_R_REQUEST_NOT_ACCEPTED + {"REQUEST_NOT_ACCEPTED", ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED}, + #else + {"REQUEST_NOT_ACCEPTED", 58, 149}, + #endif + #ifdef CMP_R_REQUEST_REJECTED_BY_SERVER + {"REQUEST_REJECTED_BY_SERVER", ERR_LIB_CMP, CMP_R_REQUEST_REJECTED_BY_SERVER}, + #else + {"REQUEST_REJECTED_BY_SERVER", 58, 182}, + #endif + #ifdef CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED + {"SENDER_GENERALNAME_TYPE_NOT_SUPPORTED", ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED}, + #else + {"SENDER_GENERALNAME_TYPE_NOT_SUPPORTED", 58, 150}, + #endif + #ifdef CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG + {"SRVCERT_DOES_NOT_VALIDATE_MSG", ERR_LIB_CMP, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG}, + #else + {"SRVCERT_DOES_NOT_VALIDATE_MSG", 58, 151}, + #endif + #ifdef CMP_R_TOTAL_TIMEOUT + {"TOTAL_TIMEOUT", ERR_LIB_CMP, CMP_R_TOTAL_TIMEOUT}, + #else + {"TOTAL_TIMEOUT", 58, 184}, + #endif + #ifdef CMP_R_TRANSACTIONID_UNMATCHED + {"TRANSACTIONID_UNMATCHED", ERR_LIB_CMP, CMP_R_TRANSACTIONID_UNMATCHED}, + #else + {"TRANSACTIONID_UNMATCHED", 58, 152}, + #endif + #ifdef CMP_R_TRANSFER_ERROR + {"TRANSFER_ERROR", ERR_LIB_CMP, CMP_R_TRANSFER_ERROR}, + #else + {"TRANSFER_ERROR", 58, 159}, + #endif + #ifdef CMP_R_UNEXPECTED_PKIBODY + {"UNEXPECTED_PKIBODY", ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY}, + #else + {"UNEXPECTED_PKIBODY", 58, 133}, + #endif + #ifdef CMP_R_UNEXPECTED_PKISTATUS + {"UNEXPECTED_PKISTATUS", ERR_LIB_CMP, CMP_R_UNEXPECTED_PKISTATUS}, + #else + {"UNEXPECTED_PKISTATUS", 58, 185}, + #endif + #ifdef CMP_R_UNEXPECTED_PVNO + {"UNEXPECTED_PVNO", ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO}, + #else + {"UNEXPECTED_PVNO", 58, 153}, + #endif + #ifdef CMP_R_UNKNOWN_ALGORITHM_ID + {"UNKNOWN_ALGORITHM_ID", ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID}, + #else + {"UNKNOWN_ALGORITHM_ID", 58, 134}, + #endif + #ifdef CMP_R_UNKNOWN_CERT_TYPE + {"UNKNOWN_CERT_TYPE", ERR_LIB_CMP, CMP_R_UNKNOWN_CERT_TYPE}, + #else + {"UNKNOWN_CERT_TYPE", 58, 135}, + #endif + #ifdef CMP_R_UNKNOWN_PKISTATUS + {"UNKNOWN_PKISTATUS", ERR_LIB_CMP, CMP_R_UNKNOWN_PKISTATUS}, + #else + {"UNKNOWN_PKISTATUS", 58, 186}, + #endif + #ifdef CMP_R_UNSUPPORTED_ALGORITHM + {"UNSUPPORTED_ALGORITHM", ERR_LIB_CMP, CMP_R_UNSUPPORTED_ALGORITHM}, + #else + {"UNSUPPORTED_ALGORITHM", 58, 136}, + #endif + #ifdef CMP_R_UNSUPPORTED_KEY_TYPE + {"UNSUPPORTED_KEY_TYPE", ERR_LIB_CMP, CMP_R_UNSUPPORTED_KEY_TYPE}, + #else + {"UNSUPPORTED_KEY_TYPE", 58, 137}, + #endif + #ifdef CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC + {"UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC", ERR_LIB_CMP, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC}, + #else + {"UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC", 58, 154}, + #endif + #ifdef CMP_R_VALUE_TOO_LARGE + {"VALUE_TOO_LARGE", ERR_LIB_CMP, CMP_R_VALUE_TOO_LARGE}, + #else + {"VALUE_TOO_LARGE", 58, 175}, + #endif + #ifdef CMP_R_VALUE_TOO_SMALL + {"VALUE_TOO_SMALL", ERR_LIB_CMP, CMP_R_VALUE_TOO_SMALL}, + #else + {"VALUE_TOO_SMALL", 58, 177}, + #endif + #ifdef CMP_R_WRONG_ALGORITHM_OID + {"WRONG_ALGORITHM_OID", ERR_LIB_CMP, CMP_R_WRONG_ALGORITHM_OID}, + #else + {"WRONG_ALGORITHM_OID", 58, 138}, + #endif + #ifdef CMP_R_WRONG_CERTID + {"WRONG_CERTID", ERR_LIB_CMP, CMP_R_WRONG_CERTID}, + #else + {"WRONG_CERTID", 58, 189}, + #endif + #ifdef CMP_R_WRONG_CERTID_IN_RP + {"WRONG_CERTID_IN_RP", ERR_LIB_CMP, CMP_R_WRONG_CERTID_IN_RP}, + #else + {"WRONG_CERTID_IN_RP", 58, 187}, + #endif + #ifdef CMP_R_WRONG_PBM_VALUE + {"WRONG_PBM_VALUE", ERR_LIB_CMP, CMP_R_WRONG_PBM_VALUE}, + #else + {"WRONG_PBM_VALUE", 58, 155}, + #endif + #ifdef CMP_R_WRONG_RP_COMPONENT_COUNT + {"WRONG_RP_COMPONENT_COUNT", ERR_LIB_CMP, CMP_R_WRONG_RP_COMPONENT_COUNT}, + #else + {"WRONG_RP_COMPONENT_COUNT", 58, 188}, + #endif + #ifdef CMP_R_WRONG_SERIAL_IN_RP + {"WRONG_SERIAL_IN_RP", ERR_LIB_CMP, CMP_R_WRONG_SERIAL_IN_RP}, + #else + {"WRONG_SERIAL_IN_RP", 58, 173}, + #endif + #ifdef CMS_R_ADD_SIGNER_ERROR + {"ADD_SIGNER_ERROR", ERR_LIB_CMS, CMS_R_ADD_SIGNER_ERROR}, + #else + {"ADD_SIGNER_ERROR", 46, 99}, + #endif + #ifdef CMS_R_ATTRIBUTE_ERROR + {"ATTRIBUTE_ERROR", ERR_LIB_CMS, CMS_R_ATTRIBUTE_ERROR}, + #else + {"ATTRIBUTE_ERROR", 46, 161}, + #endif + #ifdef CMS_R_CERTIFICATE_ALREADY_PRESENT + {"CERTIFICATE_ALREADY_PRESENT", ERR_LIB_CMS, CMS_R_CERTIFICATE_ALREADY_PRESENT}, + #else + {"CERTIFICATE_ALREADY_PRESENT", 46, 175}, + #endif + #ifdef CMS_R_CERTIFICATE_HAS_NO_KEYID + {"CERTIFICATE_HAS_NO_KEYID", ERR_LIB_CMS, CMS_R_CERTIFICATE_HAS_NO_KEYID}, + #else + {"CERTIFICATE_HAS_NO_KEYID", 46, 160}, + #endif + #ifdef CMS_R_CERTIFICATE_VERIFY_ERROR + {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_CMS, CMS_R_CERTIFICATE_VERIFY_ERROR}, + #else + {"CERTIFICATE_VERIFY_ERROR", 46, 100}, + #endif + #ifdef CMS_R_CIPHER_AEAD_SET_TAG_ERROR + {"CIPHER_AEAD_SET_TAG_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_AEAD_SET_TAG_ERROR}, + #else + {"CIPHER_AEAD_SET_TAG_ERROR", 46, 184}, + #endif + #ifdef CMS_R_CIPHER_GET_TAG + {"CIPHER_GET_TAG", ERR_LIB_CMS, CMS_R_CIPHER_GET_TAG}, + #else + {"CIPHER_GET_TAG", 46, 185}, + #endif + #ifdef CMS_R_CIPHER_INITIALISATION_ERROR + {"CIPHER_INITIALISATION_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_INITIALISATION_ERROR}, + #else + {"CIPHER_INITIALISATION_ERROR", 46, 101}, + #endif + #ifdef CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR + {"CIPHER_PARAMETER_INITIALISATION_ERROR", ERR_LIB_CMS, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR}, + #else + {"CIPHER_PARAMETER_INITIALISATION_ERROR", 46, 102}, + #endif + #ifdef CMS_R_CMS_DATAFINAL_ERROR + {"CMS_DATAFINAL_ERROR", ERR_LIB_CMS, CMS_R_CMS_DATAFINAL_ERROR}, + #else + {"CMS_DATAFINAL_ERROR", 46, 103}, + #endif + #ifdef CMS_R_CMS_LIB + {"CMS_LIB", ERR_LIB_CMS, CMS_R_CMS_LIB}, + #else + {"CMS_LIB", 46, 104}, + #endif + #ifdef CMS_R_CONTENTIDENTIFIER_MISMATCH + {"CONTENTIDENTIFIER_MISMATCH", ERR_LIB_CMS, CMS_R_CONTENTIDENTIFIER_MISMATCH}, + #else + {"CONTENTIDENTIFIER_MISMATCH", 46, 170}, + #endif + #ifdef CMS_R_CONTENT_NOT_FOUND + {"CONTENT_NOT_FOUND", ERR_LIB_CMS, CMS_R_CONTENT_NOT_FOUND}, + #else + {"CONTENT_NOT_FOUND", 46, 105}, + #endif + #ifdef CMS_R_CONTENT_TYPE_MISMATCH + {"CONTENT_TYPE_MISMATCH", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_MISMATCH}, + #else + {"CONTENT_TYPE_MISMATCH", 46, 171}, + #endif + #ifdef CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA + {"CONTENT_TYPE_NOT_COMPRESSED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_COMPRESSED_DATA}, + #else + {"CONTENT_TYPE_NOT_COMPRESSED_DATA", 46, 106}, + #endif + #ifdef CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA + {"CONTENT_TYPE_NOT_ENVELOPED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA}, + #else + {"CONTENT_TYPE_NOT_ENVELOPED_DATA", 46, 107}, + #endif + #ifdef CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA + {"CONTENT_TYPE_NOT_SIGNED_DATA", ERR_LIB_CMS, CMS_R_CONTENT_TYPE_NOT_SIGNED_DATA}, + #else + {"CONTENT_TYPE_NOT_SIGNED_DATA", 46, 108}, + #endif + #ifdef CMS_R_CONTENT_VERIFY_ERROR + {"CONTENT_VERIFY_ERROR", ERR_LIB_CMS, CMS_R_CONTENT_VERIFY_ERROR}, + #else + {"CONTENT_VERIFY_ERROR", 46, 109}, + #endif + #ifdef CMS_R_CTRL_ERROR + {"CTRL_ERROR", ERR_LIB_CMS, CMS_R_CTRL_ERROR}, + #else + {"CTRL_ERROR", 46, 110}, + #endif + #ifdef CMS_R_CTRL_FAILURE + {"CTRL_FAILURE", ERR_LIB_CMS, CMS_R_CTRL_FAILURE}, + #else + {"CTRL_FAILURE", 46, 111}, + #endif + #ifdef CMS_R_DECODE_ERROR + {"DECODE_ERROR", ERR_LIB_CMS, CMS_R_DECODE_ERROR}, + #else + {"DECODE_ERROR", 46, 187}, + #endif + #ifdef CMS_R_DECRYPT_ERROR + {"DECRYPT_ERROR", ERR_LIB_CMS, CMS_R_DECRYPT_ERROR}, + #else + {"DECRYPT_ERROR", 46, 112}, + #endif + #ifdef CMS_R_ERROR_GETTING_PUBLIC_KEY + {"ERROR_GETTING_PUBLIC_KEY", ERR_LIB_CMS, CMS_R_ERROR_GETTING_PUBLIC_KEY}, + #else + {"ERROR_GETTING_PUBLIC_KEY", 46, 113}, + #endif + #ifdef CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE + {"ERROR_READING_MESSAGEDIGEST_ATTRIBUTE", ERR_LIB_CMS, CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE}, + #else + {"ERROR_READING_MESSAGEDIGEST_ATTRIBUTE", 46, 114}, + #endif + #ifdef CMS_R_ERROR_SETTING_KEY + {"ERROR_SETTING_KEY", ERR_LIB_CMS, CMS_R_ERROR_SETTING_KEY}, + #else + {"ERROR_SETTING_KEY", 46, 115}, + #endif + #ifdef CMS_R_ERROR_SETTING_RECIPIENTINFO + {"ERROR_SETTING_RECIPIENTINFO", ERR_LIB_CMS, CMS_R_ERROR_SETTING_RECIPIENTINFO}, + #else + {"ERROR_SETTING_RECIPIENTINFO", 46, 116}, + #endif + #ifdef CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR + {"ESS_SIGNING_CERTID_MISMATCH_ERROR", ERR_LIB_CMS, CMS_R_ESS_SIGNING_CERTID_MISMATCH_ERROR}, + #else + {"ESS_SIGNING_CERTID_MISMATCH_ERROR", 46, 183}, + #endif + #ifdef CMS_R_INVALID_ENCRYPTED_KEY_LENGTH + {"INVALID_ENCRYPTED_KEY_LENGTH", ERR_LIB_CMS, CMS_R_INVALID_ENCRYPTED_KEY_LENGTH}, + #else + {"INVALID_ENCRYPTED_KEY_LENGTH", 46, 117}, + #endif + #ifdef CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER + {"INVALID_KEY_ENCRYPTION_PARAMETER", ERR_LIB_CMS, CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER}, + #else + {"INVALID_KEY_ENCRYPTION_PARAMETER", 46, 176}, + #endif + #ifdef CMS_R_INVALID_KEY_LENGTH + {"INVALID_KEY_LENGTH", ERR_LIB_CMS, CMS_R_INVALID_KEY_LENGTH}, + #else + {"INVALID_KEY_LENGTH", 46, 118}, + #endif + #ifdef CMS_R_INVALID_LABEL + {"INVALID_LABEL", ERR_LIB_CMS, CMS_R_INVALID_LABEL}, + #else + {"INVALID_LABEL", 46, 190}, + #endif + #ifdef CMS_R_INVALID_OAEP_PARAMETERS + {"INVALID_OAEP_PARAMETERS", ERR_LIB_CMS, CMS_R_INVALID_OAEP_PARAMETERS}, + #else + {"INVALID_OAEP_PARAMETERS", 46, 191}, + #endif + #ifdef CMS_R_KDF_PARAMETER_ERROR + {"KDF_PARAMETER_ERROR", ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR}, + #else + {"KDF_PARAMETER_ERROR", 46, 186}, + #endif + #ifdef CMS_R_MD_BIO_INIT_ERROR + {"MD_BIO_INIT_ERROR", ERR_LIB_CMS, CMS_R_MD_BIO_INIT_ERROR}, + #else + {"MD_BIO_INIT_ERROR", 46, 119}, + #endif + #ifdef CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH + {"MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH}, + #else + {"MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH", 46, 120}, + #endif + #ifdef CMS_R_MESSAGEDIGEST_WRONG_LENGTH + {"MESSAGEDIGEST_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MESSAGEDIGEST_WRONG_LENGTH}, + #else + {"MESSAGEDIGEST_WRONG_LENGTH", 46, 121}, + #endif + #ifdef CMS_R_MSGSIGDIGEST_ERROR + {"MSGSIGDIGEST_ERROR", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_ERROR}, + #else + {"MSGSIGDIGEST_ERROR", 46, 172}, + #endif + #ifdef CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE + {"MSGSIGDIGEST_VERIFICATION_FAILURE", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_VERIFICATION_FAILURE}, + #else + {"MSGSIGDIGEST_VERIFICATION_FAILURE", 46, 162}, + #endif + #ifdef CMS_R_MSGSIGDIGEST_WRONG_LENGTH + {"MSGSIGDIGEST_WRONG_LENGTH", ERR_LIB_CMS, CMS_R_MSGSIGDIGEST_WRONG_LENGTH}, + #else + {"MSGSIGDIGEST_WRONG_LENGTH", 46, 163}, + #endif + #ifdef CMS_R_NEED_ONE_SIGNER + {"NEED_ONE_SIGNER", ERR_LIB_CMS, CMS_R_NEED_ONE_SIGNER}, + #else + {"NEED_ONE_SIGNER", 46, 164}, + #endif + #ifdef CMS_R_NOT_A_SIGNED_RECEIPT + {"NOT_A_SIGNED_RECEIPT", ERR_LIB_CMS, CMS_R_NOT_A_SIGNED_RECEIPT}, + #else + {"NOT_A_SIGNED_RECEIPT", 46, 165}, + #endif + #ifdef CMS_R_NOT_ENCRYPTED_DATA + {"NOT_ENCRYPTED_DATA", ERR_LIB_CMS, CMS_R_NOT_ENCRYPTED_DATA}, + #else + {"NOT_ENCRYPTED_DATA", 46, 122}, + #endif + #ifdef CMS_R_NOT_KEK + {"NOT_KEK", ERR_LIB_CMS, CMS_R_NOT_KEK}, + #else + {"NOT_KEK", 46, 123}, + #endif + #ifdef CMS_R_NOT_KEY_AGREEMENT + {"NOT_KEY_AGREEMENT", ERR_LIB_CMS, CMS_R_NOT_KEY_AGREEMENT}, + #else + {"NOT_KEY_AGREEMENT", 46, 181}, + #endif + #ifdef CMS_R_NOT_KEY_TRANSPORT + {"NOT_KEY_TRANSPORT", ERR_LIB_CMS, CMS_R_NOT_KEY_TRANSPORT}, + #else + {"NOT_KEY_TRANSPORT", 46, 124}, + #endif + #ifdef CMS_R_NOT_PWRI + {"NOT_PWRI", ERR_LIB_CMS, CMS_R_NOT_PWRI}, + #else + {"NOT_PWRI", 46, 177}, + #endif + #ifdef CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE + {"NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, + #else + {"NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 46, 125}, + #endif + #ifdef CMS_R_NO_CIPHER + {"NO_CIPHER", ERR_LIB_CMS, CMS_R_NO_CIPHER}, + #else + {"NO_CIPHER", 46, 126}, + #endif + #ifdef CMS_R_NO_CONTENT + {"NO_CONTENT", ERR_LIB_CMS, CMS_R_NO_CONTENT}, + #else + {"NO_CONTENT", 46, 127}, + #endif + #ifdef CMS_R_NO_CONTENT_TYPE + {"NO_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_NO_CONTENT_TYPE}, + #else + {"NO_CONTENT_TYPE", 46, 173}, + #endif + #ifdef CMS_R_NO_DEFAULT_DIGEST + {"NO_DEFAULT_DIGEST", ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST}, + #else + {"NO_DEFAULT_DIGEST", 46, 128}, + #endif + #ifdef CMS_R_NO_DIGEST_SET + {"NO_DIGEST_SET", ERR_LIB_CMS, CMS_R_NO_DIGEST_SET}, + #else + {"NO_DIGEST_SET", 46, 129}, + #endif + #ifdef CMS_R_NO_KEY + {"NO_KEY", ERR_LIB_CMS, CMS_R_NO_KEY}, + #else + {"NO_KEY", 46, 130}, + #endif + #ifdef CMS_R_NO_KEY_OR_CERT + {"NO_KEY_OR_CERT", ERR_LIB_CMS, CMS_R_NO_KEY_OR_CERT}, + #else + {"NO_KEY_OR_CERT", 46, 174}, + #endif + #ifdef CMS_R_NO_MATCHING_DIGEST + {"NO_MATCHING_DIGEST", ERR_LIB_CMS, CMS_R_NO_MATCHING_DIGEST}, + #else + {"NO_MATCHING_DIGEST", 46, 131}, + #endif + #ifdef CMS_R_NO_MATCHING_RECIPIENT + {"NO_MATCHING_RECIPIENT", ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT}, + #else + {"NO_MATCHING_RECIPIENT", 46, 132}, + #endif + #ifdef CMS_R_NO_MATCHING_SIGNATURE + {"NO_MATCHING_SIGNATURE", ERR_LIB_CMS, CMS_R_NO_MATCHING_SIGNATURE}, + #else + {"NO_MATCHING_SIGNATURE", 46, 166}, + #endif + #ifdef CMS_R_NO_MSGSIGDIGEST + {"NO_MSGSIGDIGEST", ERR_LIB_CMS, CMS_R_NO_MSGSIGDIGEST}, + #else + {"NO_MSGSIGDIGEST", 46, 167}, + #endif + #ifdef CMS_R_NO_PASSWORD + {"NO_PASSWORD", ERR_LIB_CMS, CMS_R_NO_PASSWORD}, + #else + {"NO_PASSWORD", 46, 178}, + #endif + #ifdef CMS_R_NO_PRIVATE_KEY + {"NO_PRIVATE_KEY", ERR_LIB_CMS, CMS_R_NO_PRIVATE_KEY}, + #else + {"NO_PRIVATE_KEY", 46, 133}, + #endif + #ifdef CMS_R_NO_PUBLIC_KEY + {"NO_PUBLIC_KEY", ERR_LIB_CMS, CMS_R_NO_PUBLIC_KEY}, + #else + {"NO_PUBLIC_KEY", 46, 134}, + #endif + #ifdef CMS_R_NO_RECEIPT_REQUEST + {"NO_RECEIPT_REQUEST", ERR_LIB_CMS, CMS_R_NO_RECEIPT_REQUEST}, + #else + {"NO_RECEIPT_REQUEST", 46, 168}, + #endif + #ifdef CMS_R_NO_SIGNERS + {"NO_SIGNERS", ERR_LIB_CMS, CMS_R_NO_SIGNERS}, + #else + {"NO_SIGNERS", 46, 135}, + #endif + #ifdef CMS_R_PEER_KEY_ERROR + {"PEER_KEY_ERROR", ERR_LIB_CMS, CMS_R_PEER_KEY_ERROR}, + #else + {"PEER_KEY_ERROR", 46, 188}, + #endif + #ifdef CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_CMS, CMS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, + #else + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 46, 136}, + #endif + #ifdef CMS_R_RECEIPT_DECODE_ERROR + {"RECEIPT_DECODE_ERROR", ERR_LIB_CMS, CMS_R_RECEIPT_DECODE_ERROR}, + #else + {"RECEIPT_DECODE_ERROR", 46, 169}, + #endif + #ifdef CMS_R_RECIPIENT_ERROR + {"RECIPIENT_ERROR", ERR_LIB_CMS, CMS_R_RECIPIENT_ERROR}, + #else + {"RECIPIENT_ERROR", 46, 137}, + #endif + #ifdef CMS_R_SHARED_INFO_ERROR + {"SHARED_INFO_ERROR", ERR_LIB_CMS, CMS_R_SHARED_INFO_ERROR}, + #else + {"SHARED_INFO_ERROR", 46, 189}, + #endif + #ifdef CMS_R_SIGNER_CERTIFICATE_NOT_FOUND + {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_CMS, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND}, + #else + {"SIGNER_CERTIFICATE_NOT_FOUND", 46, 138}, + #endif + #ifdef CMS_R_SIGNFINAL_ERROR + {"SIGNFINAL_ERROR", ERR_LIB_CMS, CMS_R_SIGNFINAL_ERROR}, + #else + {"SIGNFINAL_ERROR", 46, 139}, + #endif + #ifdef CMS_R_SMIME_TEXT_ERROR + {"SMIME_TEXT_ERROR", ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR}, + #else + {"SMIME_TEXT_ERROR", 46, 140}, + #endif + #ifdef CMS_R_STORE_INIT_ERROR + {"STORE_INIT_ERROR", ERR_LIB_CMS, CMS_R_STORE_INIT_ERROR}, + #else + {"STORE_INIT_ERROR", 46, 141}, + #endif + #ifdef CMS_R_TYPE_NOT_COMPRESSED_DATA + {"TYPE_NOT_COMPRESSED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_COMPRESSED_DATA}, + #else + {"TYPE_NOT_COMPRESSED_DATA", 46, 142}, + #endif + #ifdef CMS_R_TYPE_NOT_DATA + {"TYPE_NOT_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_DATA}, + #else + {"TYPE_NOT_DATA", 46, 143}, + #endif + #ifdef CMS_R_TYPE_NOT_DIGESTED_DATA + {"TYPE_NOT_DIGESTED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_DIGESTED_DATA}, + #else + {"TYPE_NOT_DIGESTED_DATA", 46, 144}, + #endif + #ifdef CMS_R_TYPE_NOT_ENCRYPTED_DATA + {"TYPE_NOT_ENCRYPTED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_ENCRYPTED_DATA}, + #else + {"TYPE_NOT_ENCRYPTED_DATA", 46, 145}, + #endif + #ifdef CMS_R_TYPE_NOT_ENVELOPED_DATA + {"TYPE_NOT_ENVELOPED_DATA", ERR_LIB_CMS, CMS_R_TYPE_NOT_ENVELOPED_DATA}, + #else + {"TYPE_NOT_ENVELOPED_DATA", 46, 146}, + #endif + #ifdef CMS_R_UNABLE_TO_FINALIZE_CONTEXT + {"UNABLE_TO_FINALIZE_CONTEXT", ERR_LIB_CMS, CMS_R_UNABLE_TO_FINALIZE_CONTEXT}, + #else + {"UNABLE_TO_FINALIZE_CONTEXT", 46, 147}, + #endif + #ifdef CMS_R_UNKNOWN_CIPHER + {"UNKNOWN_CIPHER", ERR_LIB_CMS, CMS_R_UNKNOWN_CIPHER}, + #else + {"UNKNOWN_CIPHER", 46, 148}, + #endif + #ifdef CMS_R_UNKNOWN_DIGEST_ALGORITHM + {"UNKNOWN_DIGEST_ALGORITHM", ERR_LIB_CMS, CMS_R_UNKNOWN_DIGEST_ALGORITHM}, + #else + {"UNKNOWN_DIGEST_ALGORITHM", 46, 149}, + #endif + #ifdef CMS_R_UNKNOWN_ID + {"UNKNOWN_ID", ERR_LIB_CMS, CMS_R_UNKNOWN_ID}, + #else + {"UNKNOWN_ID", 46, 150}, + #endif + #ifdef CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM + {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, + #else + {"UNSUPPORTED_COMPRESSION_ALGORITHM", 46, 151}, + #endif + #ifdef CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM + {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM}, + #else + {"UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM", 46, 194}, + #endif + #ifdef CMS_R_UNSUPPORTED_CONTENT_TYPE + {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_TYPE}, + #else + {"UNSUPPORTED_CONTENT_TYPE", 46, 152}, + #endif + #ifdef CMS_R_UNSUPPORTED_ENCRYPTION_TYPE + {"UNSUPPORTED_ENCRYPTION_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_ENCRYPTION_TYPE}, + #else + {"UNSUPPORTED_ENCRYPTION_TYPE", 46, 192}, + #endif + #ifdef CMS_R_UNSUPPORTED_KEK_ALGORITHM + {"UNSUPPORTED_KEK_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEK_ALGORITHM}, + #else + {"UNSUPPORTED_KEK_ALGORITHM", 46, 153}, + #endif + #ifdef CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM + {"UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM}, + #else + {"UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM", 46, 179}, + #endif + #ifdef CMS_R_UNSUPPORTED_LABEL_SOURCE + {"UNSUPPORTED_LABEL_SOURCE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_LABEL_SOURCE}, + #else + {"UNSUPPORTED_LABEL_SOURCE", 46, 193}, + #endif + #ifdef CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE + {"UNSUPPORTED_RECIPIENTINFO_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE}, + #else + {"UNSUPPORTED_RECIPIENTINFO_TYPE", 46, 155}, + #endif + #ifdef CMS_R_UNSUPPORTED_RECIPIENT_TYPE + {"UNSUPPORTED_RECIPIENT_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_RECIPIENT_TYPE}, + #else + {"UNSUPPORTED_RECIPIENT_TYPE", 46, 154}, + #endif + #ifdef CMS_R_UNSUPPORTED_TYPE + {"UNSUPPORTED_TYPE", ERR_LIB_CMS, CMS_R_UNSUPPORTED_TYPE}, + #else + {"UNSUPPORTED_TYPE", 46, 156}, + #endif + #ifdef CMS_R_UNWRAP_ERROR + {"UNWRAP_ERROR", ERR_LIB_CMS, CMS_R_UNWRAP_ERROR}, + #else + {"UNWRAP_ERROR", 46, 157}, + #endif + #ifdef CMS_R_UNWRAP_FAILURE + {"UNWRAP_FAILURE", ERR_LIB_CMS, CMS_R_UNWRAP_FAILURE}, + #else + {"UNWRAP_FAILURE", 46, 180}, + #endif + #ifdef CMS_R_VERIFICATION_FAILURE + {"VERIFICATION_FAILURE", ERR_LIB_CMS, CMS_R_VERIFICATION_FAILURE}, + #else + {"VERIFICATION_FAILURE", 46, 158}, + #endif + #ifdef CMS_R_WRAP_ERROR + {"WRAP_ERROR", ERR_LIB_CMS, CMS_R_WRAP_ERROR}, + #else + {"WRAP_ERROR", 46, 159}, + #endif + #ifdef COMP_R_ZLIB_DEFLATE_ERROR + {"ZLIB_DEFLATE_ERROR", ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR}, + #else + {"ZLIB_DEFLATE_ERROR", 41, 99}, + #endif + #ifdef COMP_R_ZLIB_INFLATE_ERROR + {"ZLIB_INFLATE_ERROR", ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR}, + #else + {"ZLIB_INFLATE_ERROR", 41, 100}, + #endif + #ifdef COMP_R_ZLIB_NOT_SUPPORTED + {"ZLIB_NOT_SUPPORTED", ERR_LIB_COMP, COMP_R_ZLIB_NOT_SUPPORTED}, + #else + {"ZLIB_NOT_SUPPORTED", 41, 101}, + #endif + #ifdef CONF_R_ERROR_LOADING_DSO + {"ERROR_LOADING_DSO", ERR_LIB_CONF, CONF_R_ERROR_LOADING_DSO}, + #else + {"ERROR_LOADING_DSO", 14, 110}, + #endif + #ifdef CONF_R_INVALID_PRAGMA + {"INVALID_PRAGMA", ERR_LIB_CONF, CONF_R_INVALID_PRAGMA}, + #else + {"INVALID_PRAGMA", 14, 122}, + #endif + #ifdef CONF_R_LIST_CANNOT_BE_NULL + {"LIST_CANNOT_BE_NULL", ERR_LIB_CONF, CONF_R_LIST_CANNOT_BE_NULL}, + #else + {"LIST_CANNOT_BE_NULL", 14, 115}, + #endif + #ifdef CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION + {"MANDATORY_BRACES_IN_VARIABLE_EXPANSION", ERR_LIB_CONF, CONF_R_MANDATORY_BRACES_IN_VARIABLE_EXPANSION}, + #else + {"MANDATORY_BRACES_IN_VARIABLE_EXPANSION", 14, 123}, + #endif + #ifdef CONF_R_MISSING_CLOSE_SQUARE_BRACKET + {"MISSING_CLOSE_SQUARE_BRACKET", ERR_LIB_CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET}, + #else + {"MISSING_CLOSE_SQUARE_BRACKET", 14, 100}, + #endif + #ifdef CONF_R_MISSING_EQUAL_SIGN + {"MISSING_EQUAL_SIGN", ERR_LIB_CONF, CONF_R_MISSING_EQUAL_SIGN}, + #else + {"MISSING_EQUAL_SIGN", 14, 101}, + #endif + #ifdef CONF_R_MISSING_INIT_FUNCTION + {"MISSING_INIT_FUNCTION", ERR_LIB_CONF, CONF_R_MISSING_INIT_FUNCTION}, + #else + {"MISSING_INIT_FUNCTION", 14, 112}, + #endif + #ifdef CONF_R_MODULE_INITIALIZATION_ERROR + {"MODULE_INITIALIZATION_ERROR", ERR_LIB_CONF, CONF_R_MODULE_INITIALIZATION_ERROR}, + #else + {"MODULE_INITIALIZATION_ERROR", 14, 109}, + #endif + #ifdef CONF_R_NO_CLOSE_BRACE + {"NO_CLOSE_BRACE", ERR_LIB_CONF, CONF_R_NO_CLOSE_BRACE}, + #else + {"NO_CLOSE_BRACE", 14, 102}, + #endif + #ifdef CONF_R_NO_CONF + {"NO_CONF", ERR_LIB_CONF, CONF_R_NO_CONF}, + #else + {"NO_CONF", 14, 105}, + #endif + #ifdef CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE + {"NO_CONF_OR_ENVIRONMENT_VARIABLE", ERR_LIB_CONF, CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE}, + #else + {"NO_CONF_OR_ENVIRONMENT_VARIABLE", 14, 106}, + #endif + #ifdef CONF_R_NO_SECTION + {"NO_SECTION", ERR_LIB_CONF, CONF_R_NO_SECTION}, + #else + {"NO_SECTION", 14, 107}, + #endif + #ifdef CONF_R_NO_SUCH_FILE + {"NO_SUCH_FILE", ERR_LIB_CONF, CONF_R_NO_SUCH_FILE}, + #else + {"NO_SUCH_FILE", 14, 114}, + #endif + #ifdef CONF_R_NO_VALUE + {"NO_VALUE", ERR_LIB_CONF, CONF_R_NO_VALUE}, + #else + {"NO_VALUE", 14, 108}, + #endif + #ifdef CONF_R_NUMBER_TOO_LARGE + {"NUMBER_TOO_LARGE", ERR_LIB_CONF, CONF_R_NUMBER_TOO_LARGE}, + #else + {"NUMBER_TOO_LARGE", 14, 121}, + #endif + #ifdef CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION + {"OPENSSL_CONF_REFERENCES_MISSING_SECTION", ERR_LIB_CONF, CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION}, + #else + {"OPENSSL_CONF_REFERENCES_MISSING_SECTION", 14, 124}, + #endif + #ifdef CONF_R_RECURSIVE_DIRECTORY_INCLUDE + {"RECURSIVE_DIRECTORY_INCLUDE", ERR_LIB_CONF, CONF_R_RECURSIVE_DIRECTORY_INCLUDE}, + #else + {"RECURSIVE_DIRECTORY_INCLUDE", 14, 111}, + #endif + #ifdef CONF_R_RELATIVE_PATH + {"RELATIVE_PATH", ERR_LIB_CONF, CONF_R_RELATIVE_PATH}, + #else + {"RELATIVE_PATH", 14, 125}, + #endif + #ifdef CONF_R_SSL_COMMAND_SECTION_EMPTY + {"SSL_COMMAND_SECTION_EMPTY", ERR_LIB_CONF, CONF_R_SSL_COMMAND_SECTION_EMPTY}, + #else + {"SSL_COMMAND_SECTION_EMPTY", 14, 117}, + #endif + #ifdef CONF_R_SSL_COMMAND_SECTION_NOT_FOUND + {"SSL_COMMAND_SECTION_NOT_FOUND", ERR_LIB_CONF, CONF_R_SSL_COMMAND_SECTION_NOT_FOUND}, + #else + {"SSL_COMMAND_SECTION_NOT_FOUND", 14, 118}, + #endif + #ifdef CONF_R_SSL_SECTION_EMPTY + {"SSL_SECTION_EMPTY", ERR_LIB_CONF, CONF_R_SSL_SECTION_EMPTY}, + #else + {"SSL_SECTION_EMPTY", 14, 119}, + #endif + #ifdef CONF_R_SSL_SECTION_NOT_FOUND + {"SSL_SECTION_NOT_FOUND", ERR_LIB_CONF, CONF_R_SSL_SECTION_NOT_FOUND}, + #else + {"SSL_SECTION_NOT_FOUND", 14, 120}, + #endif + #ifdef CONF_R_UNABLE_TO_CREATE_NEW_SECTION + {"UNABLE_TO_CREATE_NEW_SECTION", ERR_LIB_CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION}, + #else + {"UNABLE_TO_CREATE_NEW_SECTION", 14, 103}, + #endif + #ifdef CONF_R_UNKNOWN_MODULE_NAME + {"UNKNOWN_MODULE_NAME", ERR_LIB_CONF, CONF_R_UNKNOWN_MODULE_NAME}, + #else + {"UNKNOWN_MODULE_NAME", 14, 113}, + #endif + #ifdef CONF_R_VARIABLE_EXPANSION_TOO_LONG + {"VARIABLE_EXPANSION_TOO_LONG", ERR_LIB_CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG}, + #else + {"VARIABLE_EXPANSION_TOO_LONG", 14, 116}, + #endif + #ifdef CONF_R_VARIABLE_HAS_NO_VALUE + {"VARIABLE_HAS_NO_VALUE", ERR_LIB_CONF, CONF_R_VARIABLE_HAS_NO_VALUE}, + #else + {"VARIABLE_HAS_NO_VALUE", 14, 104}, + #endif + #ifdef CRMF_R_BAD_PBM_ITERATIONCOUNT + {"BAD_PBM_ITERATIONCOUNT", ERR_LIB_CRMF, CRMF_R_BAD_PBM_ITERATIONCOUNT}, + #else + {"BAD_PBM_ITERATIONCOUNT", 56, 100}, + #endif + #ifdef CRMF_R_CRMFERROR + {"CRMFERROR", ERR_LIB_CRMF, CRMF_R_CRMFERROR}, + #else + {"CRMFERROR", 56, 102}, + #endif + #ifdef CRMF_R_ERROR + {"ERROR", ERR_LIB_CRMF, CRMF_R_ERROR}, + #else + {"ERROR", 56, 103}, + #endif + #ifdef CRMF_R_ERROR_DECODING_CERTIFICATE + {"ERROR_DECODING_CERTIFICATE", ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_CERTIFICATE}, + #else + {"ERROR_DECODING_CERTIFICATE", 56, 104}, + #endif + #ifdef CRMF_R_ERROR_DECRYPTING_CERTIFICATE + {"ERROR_DECRYPTING_CERTIFICATE", ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_CERTIFICATE}, + #else + {"ERROR_DECRYPTING_CERTIFICATE", 56, 105}, + #endif + #ifdef CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY + {"ERROR_DECRYPTING_SYMMETRIC_KEY", ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY}, + #else + {"ERROR_DECRYPTING_SYMMETRIC_KEY", 56, 106}, + #endif + #ifdef CRMF_R_FAILURE_OBTAINING_RANDOM + {"FAILURE_OBTAINING_RANDOM", ERR_LIB_CRMF, CRMF_R_FAILURE_OBTAINING_RANDOM}, + #else + {"FAILURE_OBTAINING_RANDOM", 56, 107}, + #endif + #ifdef CRMF_R_ITERATIONCOUNT_BELOW_100 + {"ITERATIONCOUNT_BELOW_100", ERR_LIB_CRMF, CRMF_R_ITERATIONCOUNT_BELOW_100}, + #else + {"ITERATIONCOUNT_BELOW_100", 56, 108}, + #endif + #ifdef CRMF_R_MALFORMED_IV + {"MALFORMED_IV", ERR_LIB_CRMF, CRMF_R_MALFORMED_IV}, + #else + {"MALFORMED_IV", 56, 101}, + #endif + #ifdef CRMF_R_NULL_ARGUMENT + {"NULL_ARGUMENT", ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT}, + #else + {"NULL_ARGUMENT", 56, 109}, + #endif + #ifdef CRMF_R_POPOSKINPUT_NOT_SUPPORTED + {"POPOSKINPUT_NOT_SUPPORTED", ERR_LIB_CRMF, CRMF_R_POPOSKINPUT_NOT_SUPPORTED}, + #else + {"POPOSKINPUT_NOT_SUPPORTED", 56, 113}, + #endif + #ifdef CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY + {"POPO_INCONSISTENT_PUBLIC_KEY", ERR_LIB_CRMF, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY}, + #else + {"POPO_INCONSISTENT_PUBLIC_KEY", 56, 117}, + #endif + #ifdef CRMF_R_POPO_MISSING + {"POPO_MISSING", ERR_LIB_CRMF, CRMF_R_POPO_MISSING}, + #else + {"POPO_MISSING", 56, 121}, + #endif + #ifdef CRMF_R_POPO_MISSING_PUBLIC_KEY + {"POPO_MISSING_PUBLIC_KEY", ERR_LIB_CRMF, CRMF_R_POPO_MISSING_PUBLIC_KEY}, + #else + {"POPO_MISSING_PUBLIC_KEY", 56, 118}, + #endif + #ifdef CRMF_R_POPO_MISSING_SUBJECT + {"POPO_MISSING_SUBJECT", ERR_LIB_CRMF, CRMF_R_POPO_MISSING_SUBJECT}, + #else + {"POPO_MISSING_SUBJECT", 56, 119}, + #endif + #ifdef CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED + {"POPO_RAVERIFIED_NOT_ACCEPTED", ERR_LIB_CRMF, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED}, + #else + {"POPO_RAVERIFIED_NOT_ACCEPTED", 56, 120}, + #endif + #ifdef CRMF_R_SETTING_MAC_ALGOR_FAILURE + {"SETTING_MAC_ALGOR_FAILURE", ERR_LIB_CRMF, CRMF_R_SETTING_MAC_ALGOR_FAILURE}, + #else + {"SETTING_MAC_ALGOR_FAILURE", 56, 110}, + #endif + #ifdef CRMF_R_SETTING_OWF_ALGOR_FAILURE + {"SETTING_OWF_ALGOR_FAILURE", ERR_LIB_CRMF, CRMF_R_SETTING_OWF_ALGOR_FAILURE}, + #else + {"SETTING_OWF_ALGOR_FAILURE", 56, 111}, + #endif + #ifdef CRMF_R_UNSUPPORTED_ALGORITHM + {"UNSUPPORTED_ALGORITHM", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_ALGORITHM}, + #else + {"UNSUPPORTED_ALGORITHM", 56, 112}, + #endif + #ifdef CRMF_R_UNSUPPORTED_CIPHER + {"UNSUPPORTED_CIPHER", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_CIPHER}, + #else + {"UNSUPPORTED_CIPHER", 56, 114}, + #endif + #ifdef CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO + {"UNSUPPORTED_METHOD_FOR_CREATING_POPO", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO}, + #else + {"UNSUPPORTED_METHOD_FOR_CREATING_POPO", 56, 115}, + #endif + #ifdef CRMF_R_UNSUPPORTED_POPO_METHOD + {"UNSUPPORTED_POPO_METHOD", ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_POPO_METHOD}, + #else + {"UNSUPPORTED_POPO_METHOD", 56, 116}, + #endif + #ifdef CRYPTO_R_BAD_ALGORITHM_NAME + {"BAD_ALGORITHM_NAME", ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME}, + #else + {"BAD_ALGORITHM_NAME", 15, 117}, + #endif + #ifdef CRYPTO_R_CONFLICTING_NAMES + {"CONFLICTING_NAMES", ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES}, + #else + {"CONFLICTING_NAMES", 15, 118}, + #endif + #ifdef CRYPTO_R_HEX_STRING_TOO_SHORT + {"HEX_STRING_TOO_SHORT", ERR_LIB_CRYPTO, CRYPTO_R_HEX_STRING_TOO_SHORT}, + #else + {"HEX_STRING_TOO_SHORT", 15, 121}, + #endif + #ifdef CRYPTO_R_ILLEGAL_HEX_DIGIT + {"ILLEGAL_HEX_DIGIT", ERR_LIB_CRYPTO, CRYPTO_R_ILLEGAL_HEX_DIGIT}, + #else + {"ILLEGAL_HEX_DIGIT", 15, 102}, + #endif + #ifdef CRYPTO_R_INSUFFICIENT_DATA_SPACE + {"INSUFFICIENT_DATA_SPACE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_DATA_SPACE}, + #else + {"INSUFFICIENT_DATA_SPACE", 15, 106}, + #endif + #ifdef CRYPTO_R_INSUFFICIENT_PARAM_SIZE + {"INSUFFICIENT_PARAM_SIZE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_PARAM_SIZE}, + #else + {"INSUFFICIENT_PARAM_SIZE", 15, 107}, + #endif + #ifdef CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE + {"INSUFFICIENT_SECURE_DATA_SPACE", ERR_LIB_CRYPTO, CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE}, + #else + {"INSUFFICIENT_SECURE_DATA_SPACE", 15, 108}, + #endif + #ifdef CRYPTO_R_INTEGER_OVERFLOW + {"INTEGER_OVERFLOW", ERR_LIB_CRYPTO, CRYPTO_R_INTEGER_OVERFLOW}, + #else + {"INTEGER_OVERFLOW", 15, 127}, + #endif + #ifdef CRYPTO_R_INVALID_NEGATIVE_VALUE + {"INVALID_NEGATIVE_VALUE", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NEGATIVE_VALUE}, + #else + {"INVALID_NEGATIVE_VALUE", 15, 122}, + #endif + #ifdef CRYPTO_R_INVALID_NULL_ARGUMENT + {"INVALID_NULL_ARGUMENT", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NULL_ARGUMENT}, + #else + {"INVALID_NULL_ARGUMENT", 15, 109}, + #endif + #ifdef CRYPTO_R_INVALID_OSSL_PARAM_TYPE + {"INVALID_OSSL_PARAM_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_INVALID_OSSL_PARAM_TYPE}, + #else + {"INVALID_OSSL_PARAM_TYPE", 15, 110}, + #endif + #ifdef CRYPTO_R_NO_PARAMS_TO_MERGE + {"NO_PARAMS_TO_MERGE", ERR_LIB_CRYPTO, CRYPTO_R_NO_PARAMS_TO_MERGE}, + #else + {"NO_PARAMS_TO_MERGE", 15, 131}, + #endif + #ifdef CRYPTO_R_NO_SPACE_FOR_TERMINATING_NULL + {"NO_SPACE_FOR_TERMINATING_NULL", ERR_LIB_CRYPTO, CRYPTO_R_NO_SPACE_FOR_TERMINATING_NULL}, + #else + {"NO_SPACE_FOR_TERMINATING_NULL", 15, 128}, + #endif + #ifdef CRYPTO_R_ODD_NUMBER_OF_DIGITS + {"ODD_NUMBER_OF_DIGITS", ERR_LIB_CRYPTO, CRYPTO_R_ODD_NUMBER_OF_DIGITS}, + #else + {"ODD_NUMBER_OF_DIGITS", 15, 103}, + #endif + #ifdef CRYPTO_R_PARAM_CANNOT_BE_REPRESENTED_EXACTLY + {"PARAM_CANNOT_BE_REPRESENTED_EXACTLY", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_CANNOT_BE_REPRESENTED_EXACTLY}, + #else + {"PARAM_CANNOT_BE_REPRESENTED_EXACTLY", 15, 123}, + #endif + #ifdef CRYPTO_R_PARAM_NOT_INTEGER_TYPE + {"PARAM_NOT_INTEGER_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_NOT_INTEGER_TYPE}, + #else + {"PARAM_NOT_INTEGER_TYPE", 15, 124}, + #endif + #ifdef CRYPTO_R_PARAM_OF_INCOMPATIBLE_TYPE + {"PARAM_OF_INCOMPATIBLE_TYPE", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_OF_INCOMPATIBLE_TYPE}, + #else + {"PARAM_OF_INCOMPATIBLE_TYPE", 15, 129}, + #endif + #ifdef CRYPTO_R_PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED + {"PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED}, + #else + {"PARAM_UNSIGNED_INTEGER_NEGATIVE_VALUE_UNSUPPORTED", 15, 125}, + #endif + #ifdef CRYPTO_R_PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT + {"PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT}, + #else + {"PARAM_UNSUPPORTED_FLOATING_POINT_FORMAT", 15, 130}, + #endif + #ifdef CRYPTO_R_PARAM_VALUE_TOO_LARGE_FOR_DESTINATION + {"PARAM_VALUE_TOO_LARGE_FOR_DESTINATION", ERR_LIB_CRYPTO, CRYPTO_R_PARAM_VALUE_TOO_LARGE_FOR_DESTINATION}, + #else + {"PARAM_VALUE_TOO_LARGE_FOR_DESTINATION", 15, 126}, + #endif + #ifdef CRYPTO_R_PROVIDER_ALREADY_EXISTS + {"PROVIDER_ALREADY_EXISTS", ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_ALREADY_EXISTS}, + #else + {"PROVIDER_ALREADY_EXISTS", 15, 104}, + #endif + #ifdef CRYPTO_R_PROVIDER_SECTION_ERROR + {"PROVIDER_SECTION_ERROR", ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_SECTION_ERROR}, + #else + {"PROVIDER_SECTION_ERROR", 15, 105}, + #endif + #ifdef CRYPTO_R_RANDOM_SECTION_ERROR + {"RANDOM_SECTION_ERROR", ERR_LIB_CRYPTO, CRYPTO_R_RANDOM_SECTION_ERROR}, + #else + {"RANDOM_SECTION_ERROR", 15, 119}, + #endif + #ifdef CRYPTO_R_SECURE_MALLOC_FAILURE + {"SECURE_MALLOC_FAILURE", ERR_LIB_CRYPTO, CRYPTO_R_SECURE_MALLOC_FAILURE}, + #else + {"SECURE_MALLOC_FAILURE", 15, 111}, + #endif + #ifdef CRYPTO_R_STRING_TOO_LONG + {"STRING_TOO_LONG", ERR_LIB_CRYPTO, CRYPTO_R_STRING_TOO_LONG}, + #else + {"STRING_TOO_LONG", 15, 112}, + #endif + #ifdef CRYPTO_R_TOO_MANY_BYTES + {"TOO_MANY_BYTES", ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_BYTES}, + #else + {"TOO_MANY_BYTES", 15, 113}, + #endif + #ifdef CRYPTO_R_TOO_MANY_RECORDS + {"TOO_MANY_RECORDS", ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_RECORDS}, + #else + {"TOO_MANY_RECORDS", 15, 114}, + #endif + #ifdef CRYPTO_R_TOO_SMALL_BUFFER + {"TOO_SMALL_BUFFER", ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER}, + #else + {"TOO_SMALL_BUFFER", 15, 116}, + #endif + #ifdef CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION + {"UNKNOWN_NAME_IN_RANDOM_SECTION", ERR_LIB_CRYPTO, CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION}, + #else + {"UNKNOWN_NAME_IN_RANDOM_SECTION", 15, 120}, + #endif + #ifdef CRYPTO_R_ZERO_LENGTH_NUMBER + {"ZERO_LENGTH_NUMBER", ERR_LIB_CRYPTO, CRYPTO_R_ZERO_LENGTH_NUMBER}, + #else + {"ZERO_LENGTH_NUMBER", 15, 115}, + #endif + #ifdef CT_R_BASE64_DECODE_ERROR + {"BASE64_DECODE_ERROR", ERR_LIB_CT, CT_R_BASE64_DECODE_ERROR}, + #else + {"BASE64_DECODE_ERROR", 50, 108}, + #endif + #ifdef CT_R_INVALID_LOG_ID_LENGTH + {"INVALID_LOG_ID_LENGTH", ERR_LIB_CT, CT_R_INVALID_LOG_ID_LENGTH}, + #else + {"INVALID_LOG_ID_LENGTH", 50, 100}, + #endif + #ifdef CT_R_LOG_CONF_INVALID + {"LOG_CONF_INVALID", ERR_LIB_CT, CT_R_LOG_CONF_INVALID}, + #else + {"LOG_CONF_INVALID", 50, 109}, + #endif + #ifdef CT_R_LOG_CONF_INVALID_KEY + {"LOG_CONF_INVALID_KEY", ERR_LIB_CT, CT_R_LOG_CONF_INVALID_KEY}, + #else + {"LOG_CONF_INVALID_KEY", 50, 110}, + #endif + #ifdef CT_R_LOG_CONF_MISSING_DESCRIPTION + {"LOG_CONF_MISSING_DESCRIPTION", ERR_LIB_CT, CT_R_LOG_CONF_MISSING_DESCRIPTION}, + #else + {"LOG_CONF_MISSING_DESCRIPTION", 50, 111}, + #endif + #ifdef CT_R_LOG_CONF_MISSING_KEY + {"LOG_CONF_MISSING_KEY", ERR_LIB_CT, CT_R_LOG_CONF_MISSING_KEY}, + #else + {"LOG_CONF_MISSING_KEY", 50, 112}, + #endif + #ifdef CT_R_LOG_KEY_INVALID + {"LOG_KEY_INVALID", ERR_LIB_CT, CT_R_LOG_KEY_INVALID}, + #else + {"LOG_KEY_INVALID", 50, 113}, + #endif + #ifdef CT_R_SCT_FUTURE_TIMESTAMP + {"SCT_FUTURE_TIMESTAMP", ERR_LIB_CT, CT_R_SCT_FUTURE_TIMESTAMP}, + #else + {"SCT_FUTURE_TIMESTAMP", 50, 116}, + #endif + #ifdef CT_R_SCT_INVALID + {"SCT_INVALID", ERR_LIB_CT, CT_R_SCT_INVALID}, + #else + {"SCT_INVALID", 50, 104}, + #endif + #ifdef CT_R_SCT_INVALID_SIGNATURE + {"SCT_INVALID_SIGNATURE", ERR_LIB_CT, CT_R_SCT_INVALID_SIGNATURE}, + #else + {"SCT_INVALID_SIGNATURE", 50, 107}, + #endif + #ifdef CT_R_SCT_LIST_INVALID + {"SCT_LIST_INVALID", ERR_LIB_CT, CT_R_SCT_LIST_INVALID}, + #else + {"SCT_LIST_INVALID", 50, 105}, + #endif + #ifdef CT_R_SCT_LOG_ID_MISMATCH + {"SCT_LOG_ID_MISMATCH", ERR_LIB_CT, CT_R_SCT_LOG_ID_MISMATCH}, + #else + {"SCT_LOG_ID_MISMATCH", 50, 114}, + #endif + #ifdef CT_R_SCT_NOT_SET + {"SCT_NOT_SET", ERR_LIB_CT, CT_R_SCT_NOT_SET}, + #else + {"SCT_NOT_SET", 50, 106}, + #endif + #ifdef CT_R_SCT_UNSUPPORTED_VERSION + {"SCT_UNSUPPORTED_VERSION", ERR_LIB_CT, CT_R_SCT_UNSUPPORTED_VERSION}, + #else + {"SCT_UNSUPPORTED_VERSION", 50, 115}, + #endif + #ifdef CT_R_UNRECOGNIZED_SIGNATURE_NID + {"UNRECOGNIZED_SIGNATURE_NID", ERR_LIB_CT, CT_R_UNRECOGNIZED_SIGNATURE_NID}, + #else + {"UNRECOGNIZED_SIGNATURE_NID", 50, 101}, + #endif + #ifdef CT_R_UNSUPPORTED_ENTRY_TYPE + {"UNSUPPORTED_ENTRY_TYPE", ERR_LIB_CT, CT_R_UNSUPPORTED_ENTRY_TYPE}, + #else + {"UNSUPPORTED_ENTRY_TYPE", 50, 102}, + #endif + #ifdef CT_R_UNSUPPORTED_VERSION + {"UNSUPPORTED_VERSION", ERR_LIB_CT, CT_R_UNSUPPORTED_VERSION}, + #else + {"UNSUPPORTED_VERSION", 50, 103}, + #endif + #ifdef DH_R_BAD_FFC_PARAMETERS + {"BAD_FFC_PARAMETERS", ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS}, + #else + {"BAD_FFC_PARAMETERS", 5, 127}, + #endif + #ifdef DH_R_BAD_GENERATOR + {"BAD_GENERATOR", ERR_LIB_DH, DH_R_BAD_GENERATOR}, + #else + {"BAD_GENERATOR", 5, 101}, + #endif + #ifdef DH_R_BN_DECODE_ERROR + {"BN_DECODE_ERROR", ERR_LIB_DH, DH_R_BN_DECODE_ERROR}, + #else + {"BN_DECODE_ERROR", 5, 109}, + #endif + #ifdef DH_R_BN_ERROR + {"BN_ERROR", ERR_LIB_DH, DH_R_BN_ERROR}, + #else + {"BN_ERROR", 5, 106}, + #endif + #ifdef DH_R_CHECK_INVALID_J_VALUE + {"CHECK_INVALID_J_VALUE", ERR_LIB_DH, DH_R_CHECK_INVALID_J_VALUE}, + #else + {"CHECK_INVALID_J_VALUE", 5, 115}, + #endif + #ifdef DH_R_CHECK_INVALID_Q_VALUE + {"CHECK_INVALID_Q_VALUE", ERR_LIB_DH, DH_R_CHECK_INVALID_Q_VALUE}, + #else + {"CHECK_INVALID_Q_VALUE", 5, 116}, + #endif + #ifdef DH_R_CHECK_PUBKEY_INVALID + {"CHECK_PUBKEY_INVALID", ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID}, + #else + {"CHECK_PUBKEY_INVALID", 5, 122}, + #endif + #ifdef DH_R_CHECK_PUBKEY_TOO_LARGE + {"CHECK_PUBKEY_TOO_LARGE", ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_LARGE}, + #else + {"CHECK_PUBKEY_TOO_LARGE", 5, 123}, + #endif + #ifdef DH_R_CHECK_PUBKEY_TOO_SMALL + {"CHECK_PUBKEY_TOO_SMALL", ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_SMALL}, + #else + {"CHECK_PUBKEY_TOO_SMALL", 5, 124}, + #endif + #ifdef DH_R_CHECK_P_NOT_PRIME + {"CHECK_P_NOT_PRIME", ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME}, + #else + {"CHECK_P_NOT_PRIME", 5, 117}, + #endif + #ifdef DH_R_CHECK_P_NOT_SAFE_PRIME + {"CHECK_P_NOT_SAFE_PRIME", ERR_LIB_DH, DH_R_CHECK_P_NOT_SAFE_PRIME}, + #else + {"CHECK_P_NOT_SAFE_PRIME", 5, 118}, + #endif + #ifdef DH_R_CHECK_Q_NOT_PRIME + {"CHECK_Q_NOT_PRIME", ERR_LIB_DH, DH_R_CHECK_Q_NOT_PRIME}, + #else + {"CHECK_Q_NOT_PRIME", 5, 119}, + #endif + #ifdef DH_R_DECODE_ERROR + {"DECODE_ERROR", ERR_LIB_DH, DH_R_DECODE_ERROR}, + #else + {"DECODE_ERROR", 5, 104}, + #endif + #ifdef DH_R_INVALID_PARAMETER_NAME + {"INVALID_PARAMETER_NAME", ERR_LIB_DH, DH_R_INVALID_PARAMETER_NAME}, + #else + {"INVALID_PARAMETER_NAME", 5, 110}, + #endif + #ifdef DH_R_INVALID_PARAMETER_NID + {"INVALID_PARAMETER_NID", ERR_LIB_DH, DH_R_INVALID_PARAMETER_NID}, + #else + {"INVALID_PARAMETER_NID", 5, 114}, + #endif + #ifdef DH_R_INVALID_PUBKEY + {"INVALID_PUBKEY", ERR_LIB_DH, DH_R_INVALID_PUBKEY}, + #else + {"INVALID_PUBKEY", 5, 102}, + #endif + #ifdef DH_R_INVALID_SECRET + {"INVALID_SECRET", ERR_LIB_DH, DH_R_INVALID_SECRET}, + #else + {"INVALID_SECRET", 5, 128}, + #endif + #ifdef DH_R_KDF_PARAMETER_ERROR + {"KDF_PARAMETER_ERROR", ERR_LIB_DH, DH_R_KDF_PARAMETER_ERROR}, + #else + {"KDF_PARAMETER_ERROR", 5, 112}, + #endif + #ifdef DH_R_KEYS_NOT_SET + {"KEYS_NOT_SET", ERR_LIB_DH, DH_R_KEYS_NOT_SET}, + #else + {"KEYS_NOT_SET", 5, 108}, + #endif + #ifdef DH_R_MISSING_PUBKEY + {"MISSING_PUBKEY", ERR_LIB_DH, DH_R_MISSING_PUBKEY}, + #else + {"MISSING_PUBKEY", 5, 125}, + #endif + #ifdef DH_R_MODULUS_TOO_LARGE + {"MODULUS_TOO_LARGE", ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE}, + #else + {"MODULUS_TOO_LARGE", 5, 103}, + #endif + #ifdef DH_R_MODULUS_TOO_SMALL + {"MODULUS_TOO_SMALL", ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL}, + #else + {"MODULUS_TOO_SMALL", 5, 126}, + #endif + #ifdef DH_R_NOT_SUITABLE_GENERATOR + {"NOT_SUITABLE_GENERATOR", ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR}, + #else + {"NOT_SUITABLE_GENERATOR", 5, 120}, + #endif + #ifdef DH_R_NO_PARAMETERS_SET + {"NO_PARAMETERS_SET", ERR_LIB_DH, DH_R_NO_PARAMETERS_SET}, + #else + {"NO_PARAMETERS_SET", 5, 107}, + #endif + #ifdef DH_R_NO_PRIVATE_VALUE + {"NO_PRIVATE_VALUE", ERR_LIB_DH, DH_R_NO_PRIVATE_VALUE}, + #else + {"NO_PRIVATE_VALUE", 5, 100}, + #endif + #ifdef DH_R_PARAMETER_ENCODING_ERROR + {"PARAMETER_ENCODING_ERROR", ERR_LIB_DH, DH_R_PARAMETER_ENCODING_ERROR}, + #else + {"PARAMETER_ENCODING_ERROR", 5, 105}, + #endif + #ifdef DH_R_PEER_KEY_ERROR + {"PEER_KEY_ERROR", ERR_LIB_DH, DH_R_PEER_KEY_ERROR}, + #else + {"PEER_KEY_ERROR", 5, 111}, + #endif + #ifdef DH_R_SHARED_INFO_ERROR + {"SHARED_INFO_ERROR", ERR_LIB_DH, DH_R_SHARED_INFO_ERROR}, + #else + {"SHARED_INFO_ERROR", 5, 113}, + #endif + #ifdef DH_R_UNABLE_TO_CHECK_GENERATOR + {"UNABLE_TO_CHECK_GENERATOR", ERR_LIB_DH, DH_R_UNABLE_TO_CHECK_GENERATOR}, + #else + {"UNABLE_TO_CHECK_GENERATOR", 5, 121}, + #endif + #ifdef DSA_R_BAD_FFC_PARAMETERS + {"BAD_FFC_PARAMETERS", ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS}, + #else + {"BAD_FFC_PARAMETERS", 10, 114}, + #endif + #ifdef DSA_R_BAD_Q_VALUE + {"BAD_Q_VALUE", ERR_LIB_DSA, DSA_R_BAD_Q_VALUE}, + #else + {"BAD_Q_VALUE", 10, 102}, + #endif + #ifdef DSA_R_BN_DECODE_ERROR + {"BN_DECODE_ERROR", ERR_LIB_DSA, DSA_R_BN_DECODE_ERROR}, + #else + {"BN_DECODE_ERROR", 10, 108}, + #endif + #ifdef DSA_R_BN_ERROR + {"BN_ERROR", ERR_LIB_DSA, DSA_R_BN_ERROR}, + #else + {"BN_ERROR", 10, 109}, + #endif + #ifdef DSA_R_DECODE_ERROR + {"DECODE_ERROR", ERR_LIB_DSA, DSA_R_DECODE_ERROR}, + #else + {"DECODE_ERROR", 10, 104}, + #endif + #ifdef DSA_R_INVALID_DIGEST_TYPE + {"INVALID_DIGEST_TYPE", ERR_LIB_DSA, DSA_R_INVALID_DIGEST_TYPE}, + #else + {"INVALID_DIGEST_TYPE", 10, 106}, + #endif + #ifdef DSA_R_INVALID_PARAMETERS + {"INVALID_PARAMETERS", ERR_LIB_DSA, DSA_R_INVALID_PARAMETERS}, + #else + {"INVALID_PARAMETERS", 10, 112}, + #endif + #ifdef DSA_R_MISSING_PARAMETERS + {"MISSING_PARAMETERS", ERR_LIB_DSA, DSA_R_MISSING_PARAMETERS}, + #else + {"MISSING_PARAMETERS", 10, 101}, + #endif + #ifdef DSA_R_MISSING_PRIVATE_KEY + {"MISSING_PRIVATE_KEY", ERR_LIB_DSA, DSA_R_MISSING_PRIVATE_KEY}, + #else + {"MISSING_PRIVATE_KEY", 10, 111}, + #endif + #ifdef DSA_R_MODULUS_TOO_LARGE + {"MODULUS_TOO_LARGE", ERR_LIB_DSA, DSA_R_MODULUS_TOO_LARGE}, + #else + {"MODULUS_TOO_LARGE", 10, 103}, + #endif + #ifdef DSA_R_NO_PARAMETERS_SET + {"NO_PARAMETERS_SET", ERR_LIB_DSA, DSA_R_NO_PARAMETERS_SET}, + #else + {"NO_PARAMETERS_SET", 10, 107}, + #endif + #ifdef DSA_R_PARAMETER_ENCODING_ERROR + {"PARAMETER_ENCODING_ERROR", ERR_LIB_DSA, DSA_R_PARAMETER_ENCODING_ERROR}, + #else + {"PARAMETER_ENCODING_ERROR", 10, 105}, + #endif + #ifdef DSA_R_P_NOT_PRIME + {"P_NOT_PRIME", ERR_LIB_DSA, DSA_R_P_NOT_PRIME}, + #else + {"P_NOT_PRIME", 10, 115}, + #endif + #ifdef DSA_R_Q_NOT_PRIME + {"Q_NOT_PRIME", ERR_LIB_DSA, DSA_R_Q_NOT_PRIME}, + #else + {"Q_NOT_PRIME", 10, 113}, + #endif + #ifdef DSA_R_SEED_LEN_SMALL + {"SEED_LEN_SMALL", ERR_LIB_DSA, DSA_R_SEED_LEN_SMALL}, + #else + {"SEED_LEN_SMALL", 10, 110}, + #endif + #ifdef DSA_R_TOO_MANY_RETRIES + {"TOO_MANY_RETRIES", ERR_LIB_DSA, DSA_R_TOO_MANY_RETRIES}, + #else + {"TOO_MANY_RETRIES", 10, 116}, + #endif + #ifdef DSO_R_CTRL_FAILED + {"CTRL_FAILED", ERR_LIB_DSO, DSO_R_CTRL_FAILED}, + #else + {"CTRL_FAILED", 37, 100}, + #endif + #ifdef DSO_R_DSO_ALREADY_LOADED + {"DSO_ALREADY_LOADED", ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED}, + #else + {"DSO_ALREADY_LOADED", 37, 110}, + #endif + #ifdef DSO_R_EMPTY_FILE_STRUCTURE + {"EMPTY_FILE_STRUCTURE", ERR_LIB_DSO, DSO_R_EMPTY_FILE_STRUCTURE}, + #else + {"EMPTY_FILE_STRUCTURE", 37, 113}, + #endif + #ifdef DSO_R_FAILURE + {"FAILURE", ERR_LIB_DSO, DSO_R_FAILURE}, + #else + {"FAILURE", 37, 114}, + #endif + #ifdef DSO_R_FILENAME_TOO_BIG + {"FILENAME_TOO_BIG", ERR_LIB_DSO, DSO_R_FILENAME_TOO_BIG}, + #else + {"FILENAME_TOO_BIG", 37, 101}, + #endif + #ifdef DSO_R_FINISH_FAILED + {"FINISH_FAILED", ERR_LIB_DSO, DSO_R_FINISH_FAILED}, + #else + {"FINISH_FAILED", 37, 102}, + #endif + #ifdef DSO_R_INCORRECT_FILE_SYNTAX + {"INCORRECT_FILE_SYNTAX", ERR_LIB_DSO, DSO_R_INCORRECT_FILE_SYNTAX}, + #else + {"INCORRECT_FILE_SYNTAX", 37, 115}, + #endif + #ifdef DSO_R_LOAD_FAILED + {"LOAD_FAILED", ERR_LIB_DSO, DSO_R_LOAD_FAILED}, + #else + {"LOAD_FAILED", 37, 103}, + #endif + #ifdef DSO_R_NAME_TRANSLATION_FAILED + {"NAME_TRANSLATION_FAILED", ERR_LIB_DSO, DSO_R_NAME_TRANSLATION_FAILED}, + #else + {"NAME_TRANSLATION_FAILED", 37, 109}, + #endif + #ifdef DSO_R_NO_FILENAME + {"NO_FILENAME", ERR_LIB_DSO, DSO_R_NO_FILENAME}, + #else + {"NO_FILENAME", 37, 111}, + #endif + #ifdef DSO_R_NULL_HANDLE + {"NULL_HANDLE", ERR_LIB_DSO, DSO_R_NULL_HANDLE}, + #else + {"NULL_HANDLE", 37, 104}, + #endif + #ifdef DSO_R_SET_FILENAME_FAILED + {"SET_FILENAME_FAILED", ERR_LIB_DSO, DSO_R_SET_FILENAME_FAILED}, + #else + {"SET_FILENAME_FAILED", 37, 112}, + #endif + #ifdef DSO_R_STACK_ERROR + {"STACK_ERROR", ERR_LIB_DSO, DSO_R_STACK_ERROR}, + #else + {"STACK_ERROR", 37, 105}, + #endif + #ifdef DSO_R_SYM_FAILURE + {"SYM_FAILURE", ERR_LIB_DSO, DSO_R_SYM_FAILURE}, + #else + {"SYM_FAILURE", 37, 106}, + #endif + #ifdef DSO_R_UNLOAD_FAILED + {"UNLOAD_FAILED", ERR_LIB_DSO, DSO_R_UNLOAD_FAILED}, + #else + {"UNLOAD_FAILED", 37, 107}, + #endif + #ifdef DSO_R_UNSUPPORTED + {"UNSUPPORTED", ERR_LIB_DSO, DSO_R_UNSUPPORTED}, + #else + {"UNSUPPORTED", 37, 108}, + #endif + #ifdef EC_R_ASN1_ERROR + {"ASN1_ERROR", ERR_LIB_EC, EC_R_ASN1_ERROR}, + #else + {"ASN1_ERROR", 16, 115}, + #endif + #ifdef EC_R_BAD_SIGNATURE + {"BAD_SIGNATURE", ERR_LIB_EC, EC_R_BAD_SIGNATURE}, + #else + {"BAD_SIGNATURE", 16, 156}, + #endif + #ifdef EC_R_BIGNUM_OUT_OF_RANGE + {"BIGNUM_OUT_OF_RANGE", ERR_LIB_EC, EC_R_BIGNUM_OUT_OF_RANGE}, + #else + {"BIGNUM_OUT_OF_RANGE", 16, 144}, + #endif + #ifdef EC_R_BUFFER_TOO_SMALL + {"BUFFER_TOO_SMALL", ERR_LIB_EC, EC_R_BUFFER_TOO_SMALL}, + #else + {"BUFFER_TOO_SMALL", 16, 100}, + #endif + #ifdef EC_R_CANNOT_INVERT + {"CANNOT_INVERT", ERR_LIB_EC, EC_R_CANNOT_INVERT}, + #else + {"CANNOT_INVERT", 16, 165}, + #endif + #ifdef EC_R_COORDINATES_OUT_OF_RANGE + {"COORDINATES_OUT_OF_RANGE", ERR_LIB_EC, EC_R_COORDINATES_OUT_OF_RANGE}, + #else + {"COORDINATES_OUT_OF_RANGE", 16, 146}, + #endif + #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_ECDH + {"CURVE_DOES_NOT_SUPPORT_ECDH", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_ECDH}, + #else + {"CURVE_DOES_NOT_SUPPORT_ECDH", 16, 160}, + #endif + #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_ECDSA + {"CURVE_DOES_NOT_SUPPORT_ECDSA", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_ECDSA}, + #else + {"CURVE_DOES_NOT_SUPPORT_ECDSA", 16, 170}, + #endif + #ifdef EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING + {"CURVE_DOES_NOT_SUPPORT_SIGNING", ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING}, + #else + {"CURVE_DOES_NOT_SUPPORT_SIGNING", 16, 159}, + #endif + #ifdef EC_R_DECODE_ERROR + {"DECODE_ERROR", ERR_LIB_EC, EC_R_DECODE_ERROR}, + #else + {"DECODE_ERROR", 16, 142}, + #endif + #ifdef EC_R_DISCRIMINANT_IS_ZERO + {"DISCRIMINANT_IS_ZERO", ERR_LIB_EC, EC_R_DISCRIMINANT_IS_ZERO}, + #else + {"DISCRIMINANT_IS_ZERO", 16, 118}, + #endif + #ifdef EC_R_EC_GROUP_NEW_BY_NAME_FAILURE + {"EC_GROUP_NEW_BY_NAME_FAILURE", ERR_LIB_EC, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE}, + #else + {"EC_GROUP_NEW_BY_NAME_FAILURE", 16, 119}, + #endif + #ifdef EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED + {"EXPLICIT_PARAMS_NOT_SUPPORTED", ERR_LIB_EC, EC_R_EXPLICIT_PARAMS_NOT_SUPPORTED}, + #else + {"EXPLICIT_PARAMS_NOT_SUPPORTED", 16, 127}, + #endif + #ifdef EC_R_FAILED_MAKING_PUBLIC_KEY + {"FAILED_MAKING_PUBLIC_KEY", ERR_LIB_EC, EC_R_FAILED_MAKING_PUBLIC_KEY}, + #else + {"FAILED_MAKING_PUBLIC_KEY", 16, 166}, + #endif + #ifdef EC_R_FIELD_TOO_LARGE + {"FIELD_TOO_LARGE", ERR_LIB_EC, EC_R_FIELD_TOO_LARGE}, + #else + {"FIELD_TOO_LARGE", 16, 143}, + #endif + #ifdef EC_R_GF2M_NOT_SUPPORTED + {"GF2M_NOT_SUPPORTED", ERR_LIB_EC, EC_R_GF2M_NOT_SUPPORTED}, + #else + {"GF2M_NOT_SUPPORTED", 16, 147}, + #endif + #ifdef EC_R_GROUP2PKPARAMETERS_FAILURE + {"GROUP2PKPARAMETERS_FAILURE", ERR_LIB_EC, EC_R_GROUP2PKPARAMETERS_FAILURE}, + #else + {"GROUP2PKPARAMETERS_FAILURE", 16, 120}, + #endif + #ifdef EC_R_I2D_ECPKPARAMETERS_FAILURE + {"I2D_ECPKPARAMETERS_FAILURE", ERR_LIB_EC, EC_R_I2D_ECPKPARAMETERS_FAILURE}, + #else + {"I2D_ECPKPARAMETERS_FAILURE", 16, 121}, + #endif + #ifdef EC_R_INCOMPATIBLE_OBJECTS + {"INCOMPATIBLE_OBJECTS", ERR_LIB_EC, EC_R_INCOMPATIBLE_OBJECTS}, + #else + {"INCOMPATIBLE_OBJECTS", 16, 101}, + #endif + #ifdef EC_R_INVALID_A + {"INVALID_A", ERR_LIB_EC, EC_R_INVALID_A}, + #else + {"INVALID_A", 16, 168}, + #endif + #ifdef EC_R_INVALID_ARGUMENT + {"INVALID_ARGUMENT", ERR_LIB_EC, EC_R_INVALID_ARGUMENT}, + #else + {"INVALID_ARGUMENT", 16, 112}, + #endif + #ifdef EC_R_INVALID_B + {"INVALID_B", ERR_LIB_EC, EC_R_INVALID_B}, + #else + {"INVALID_B", 16, 169}, + #endif + #ifdef EC_R_INVALID_COFACTOR + {"INVALID_COFACTOR", ERR_LIB_EC, EC_R_INVALID_COFACTOR}, + #else + {"INVALID_COFACTOR", 16, 171}, + #endif + #ifdef EC_R_INVALID_COMPRESSED_POINT + {"INVALID_COMPRESSED_POINT", ERR_LIB_EC, EC_R_INVALID_COMPRESSED_POINT}, + #else + {"INVALID_COMPRESSED_POINT", 16, 110}, + #endif + #ifdef EC_R_INVALID_COMPRESSION_BIT + {"INVALID_COMPRESSION_BIT", ERR_LIB_EC, EC_R_INVALID_COMPRESSION_BIT}, + #else + {"INVALID_COMPRESSION_BIT", 16, 109}, + #endif + #ifdef EC_R_INVALID_CURVE + {"INVALID_CURVE", ERR_LIB_EC, EC_R_INVALID_CURVE}, + #else + {"INVALID_CURVE", 16, 141}, + #endif + #ifdef EC_R_INVALID_DIGEST + {"INVALID_DIGEST", ERR_LIB_EC, EC_R_INVALID_DIGEST}, + #else + {"INVALID_DIGEST", 16, 151}, + #endif + #ifdef EC_R_INVALID_DIGEST_TYPE + {"INVALID_DIGEST_TYPE", ERR_LIB_EC, EC_R_INVALID_DIGEST_TYPE}, + #else + {"INVALID_DIGEST_TYPE", 16, 138}, + #endif + #ifdef EC_R_INVALID_ENCODING + {"INVALID_ENCODING", ERR_LIB_EC, EC_R_INVALID_ENCODING}, + #else + {"INVALID_ENCODING", 16, 102}, + #endif + #ifdef EC_R_INVALID_FIELD + {"INVALID_FIELD", ERR_LIB_EC, EC_R_INVALID_FIELD}, + #else + {"INVALID_FIELD", 16, 103}, + #endif + #ifdef EC_R_INVALID_FORM + {"INVALID_FORM", ERR_LIB_EC, EC_R_INVALID_FORM}, + #else + {"INVALID_FORM", 16, 104}, + #endif + #ifdef EC_R_INVALID_GENERATOR + {"INVALID_GENERATOR", ERR_LIB_EC, EC_R_INVALID_GENERATOR}, + #else + {"INVALID_GENERATOR", 16, 173}, + #endif + #ifdef EC_R_INVALID_GROUP_ORDER + {"INVALID_GROUP_ORDER", ERR_LIB_EC, EC_R_INVALID_GROUP_ORDER}, + #else + {"INVALID_GROUP_ORDER", 16, 122}, + #endif + #ifdef EC_R_INVALID_KEY + {"INVALID_KEY", ERR_LIB_EC, EC_R_INVALID_KEY}, + #else + {"INVALID_KEY", 16, 116}, + #endif + #ifdef EC_R_INVALID_LENGTH + {"INVALID_LENGTH", ERR_LIB_EC, EC_R_INVALID_LENGTH}, + #else + {"INVALID_LENGTH", 16, 117}, + #endif + #ifdef EC_R_INVALID_NAMED_GROUP_CONVERSION + {"INVALID_NAMED_GROUP_CONVERSION", ERR_LIB_EC, EC_R_INVALID_NAMED_GROUP_CONVERSION}, + #else + {"INVALID_NAMED_GROUP_CONVERSION", 16, 174}, + #endif + #ifdef EC_R_INVALID_OUTPUT_LENGTH + {"INVALID_OUTPUT_LENGTH", ERR_LIB_EC, EC_R_INVALID_OUTPUT_LENGTH}, + #else + {"INVALID_OUTPUT_LENGTH", 16, 161}, + #endif + #ifdef EC_R_INVALID_P + {"INVALID_P", ERR_LIB_EC, EC_R_INVALID_P}, + #else + {"INVALID_P", 16, 172}, + #endif + #ifdef EC_R_INVALID_PEER_KEY + {"INVALID_PEER_KEY", ERR_LIB_EC, EC_R_INVALID_PEER_KEY}, + #else + {"INVALID_PEER_KEY", 16, 133}, + #endif + #ifdef EC_R_INVALID_PENTANOMIAL_BASIS + {"INVALID_PENTANOMIAL_BASIS", ERR_LIB_EC, EC_R_INVALID_PENTANOMIAL_BASIS}, + #else + {"INVALID_PENTANOMIAL_BASIS", 16, 132}, + #endif + #ifdef EC_R_INVALID_PRIVATE_KEY + {"INVALID_PRIVATE_KEY", ERR_LIB_EC, EC_R_INVALID_PRIVATE_KEY}, + #else + {"INVALID_PRIVATE_KEY", 16, 123}, + #endif + #ifdef EC_R_INVALID_SEED + {"INVALID_SEED", ERR_LIB_EC, EC_R_INVALID_SEED}, + #else + {"INVALID_SEED", 16, 175}, + #endif + #ifdef EC_R_INVALID_TRINOMIAL_BASIS + {"INVALID_TRINOMIAL_BASIS", ERR_LIB_EC, EC_R_INVALID_TRINOMIAL_BASIS}, + #else + {"INVALID_TRINOMIAL_BASIS", 16, 137}, + #endif + #ifdef EC_R_KDF_PARAMETER_ERROR + {"KDF_PARAMETER_ERROR", ERR_LIB_EC, EC_R_KDF_PARAMETER_ERROR}, + #else + {"KDF_PARAMETER_ERROR", 16, 148}, + #endif + #ifdef EC_R_KEYS_NOT_SET + {"KEYS_NOT_SET", ERR_LIB_EC, EC_R_KEYS_NOT_SET}, + #else + {"KEYS_NOT_SET", 16, 140}, + #endif + #ifdef EC_R_LADDER_POST_FAILURE + {"LADDER_POST_FAILURE", ERR_LIB_EC, EC_R_LADDER_POST_FAILURE}, + #else + {"LADDER_POST_FAILURE", 16, 136}, + #endif + #ifdef EC_R_LADDER_PRE_FAILURE + {"LADDER_PRE_FAILURE", ERR_LIB_EC, EC_R_LADDER_PRE_FAILURE}, + #else + {"LADDER_PRE_FAILURE", 16, 153}, + #endif + #ifdef EC_R_LADDER_STEP_FAILURE + {"LADDER_STEP_FAILURE", ERR_LIB_EC, EC_R_LADDER_STEP_FAILURE}, + #else + {"LADDER_STEP_FAILURE", 16, 162}, + #endif + #ifdef EC_R_MISSING_OID + {"MISSING_OID", ERR_LIB_EC, EC_R_MISSING_OID}, + #else + {"MISSING_OID", 16, 167}, + #endif + #ifdef EC_R_MISSING_PARAMETERS + {"MISSING_PARAMETERS", ERR_LIB_EC, EC_R_MISSING_PARAMETERS}, + #else + {"MISSING_PARAMETERS", 16, 124}, + #endif + #ifdef EC_R_MISSING_PRIVATE_KEY + {"MISSING_PRIVATE_KEY", ERR_LIB_EC, EC_R_MISSING_PRIVATE_KEY}, + #else + {"MISSING_PRIVATE_KEY", 16, 125}, + #endif + #ifdef EC_R_NEED_NEW_SETUP_VALUES + {"NEED_NEW_SETUP_VALUES", ERR_LIB_EC, EC_R_NEED_NEW_SETUP_VALUES}, + #else + {"NEED_NEW_SETUP_VALUES", 16, 157}, + #endif + #ifdef EC_R_NOT_A_NIST_PRIME + {"NOT_A_NIST_PRIME", ERR_LIB_EC, EC_R_NOT_A_NIST_PRIME}, + #else + {"NOT_A_NIST_PRIME", 16, 135}, + #endif + #ifdef EC_R_NOT_IMPLEMENTED + {"NOT_IMPLEMENTED", ERR_LIB_EC, EC_R_NOT_IMPLEMENTED}, + #else + {"NOT_IMPLEMENTED", 16, 126}, + #endif + #ifdef EC_R_NOT_INITIALIZED + {"NOT_INITIALIZED", ERR_LIB_EC, EC_R_NOT_INITIALIZED}, + #else + {"NOT_INITIALIZED", 16, 111}, + #endif + #ifdef EC_R_NO_PARAMETERS_SET + {"NO_PARAMETERS_SET", ERR_LIB_EC, EC_R_NO_PARAMETERS_SET}, + #else + {"NO_PARAMETERS_SET", 16, 139}, + #endif + #ifdef EC_R_NO_PRIVATE_VALUE + {"NO_PRIVATE_VALUE", ERR_LIB_EC, EC_R_NO_PRIVATE_VALUE}, + #else + {"NO_PRIVATE_VALUE", 16, 154}, + #endif + #ifdef EC_R_OPERATION_NOT_SUPPORTED + {"OPERATION_NOT_SUPPORTED", ERR_LIB_EC, EC_R_OPERATION_NOT_SUPPORTED}, + #else + {"OPERATION_NOT_SUPPORTED", 16, 152}, + #endif + #ifdef EC_R_PASSED_NULL_PARAMETER + {"PASSED_NULL_PARAMETER", ERR_LIB_EC, EC_R_PASSED_NULL_PARAMETER}, + #else + {"PASSED_NULL_PARAMETER", 16, 134}, + #endif + #ifdef EC_R_PEER_KEY_ERROR + {"PEER_KEY_ERROR", ERR_LIB_EC, EC_R_PEER_KEY_ERROR}, + #else + {"PEER_KEY_ERROR", 16, 149}, + #endif + #ifdef EC_R_POINT_ARITHMETIC_FAILURE + {"POINT_ARITHMETIC_FAILURE", ERR_LIB_EC, EC_R_POINT_ARITHMETIC_FAILURE}, + #else + {"POINT_ARITHMETIC_FAILURE", 16, 155}, + #endif + #ifdef EC_R_POINT_AT_INFINITY + {"POINT_AT_INFINITY", ERR_LIB_EC, EC_R_POINT_AT_INFINITY}, + #else + {"POINT_AT_INFINITY", 16, 106}, + #endif + #ifdef EC_R_POINT_COORDINATES_BLIND_FAILURE + {"POINT_COORDINATES_BLIND_FAILURE", ERR_LIB_EC, EC_R_POINT_COORDINATES_BLIND_FAILURE}, + #else + {"POINT_COORDINATES_BLIND_FAILURE", 16, 163}, + #endif + #ifdef EC_R_POINT_IS_NOT_ON_CURVE + {"POINT_IS_NOT_ON_CURVE", ERR_LIB_EC, EC_R_POINT_IS_NOT_ON_CURVE}, + #else + {"POINT_IS_NOT_ON_CURVE", 16, 107}, + #endif + #ifdef EC_R_RANDOM_NUMBER_GENERATION_FAILED + {"RANDOM_NUMBER_GENERATION_FAILED", ERR_LIB_EC, EC_R_RANDOM_NUMBER_GENERATION_FAILED}, + #else + {"RANDOM_NUMBER_GENERATION_FAILED", 16, 158}, + #endif + #ifdef EC_R_SHARED_INFO_ERROR + {"SHARED_INFO_ERROR", ERR_LIB_EC, EC_R_SHARED_INFO_ERROR}, + #else + {"SHARED_INFO_ERROR", 16, 150}, + #endif + #ifdef EC_R_SLOT_FULL + {"SLOT_FULL", ERR_LIB_EC, EC_R_SLOT_FULL}, + #else + {"SLOT_FULL", 16, 108}, + #endif + #ifdef EC_R_TOO_MANY_RETRIES + {"TOO_MANY_RETRIES", ERR_LIB_EC, EC_R_TOO_MANY_RETRIES}, + #else + {"TOO_MANY_RETRIES", 16, 176}, + #endif + #ifdef EC_R_UNDEFINED_GENERATOR + {"UNDEFINED_GENERATOR", ERR_LIB_EC, EC_R_UNDEFINED_GENERATOR}, + #else + {"UNDEFINED_GENERATOR", 16, 113}, + #endif + #ifdef EC_R_UNDEFINED_ORDER + {"UNDEFINED_ORDER", ERR_LIB_EC, EC_R_UNDEFINED_ORDER}, + #else + {"UNDEFINED_ORDER", 16, 128}, + #endif + #ifdef EC_R_UNKNOWN_COFACTOR + {"UNKNOWN_COFACTOR", ERR_LIB_EC, EC_R_UNKNOWN_COFACTOR}, + #else + {"UNKNOWN_COFACTOR", 16, 164}, + #endif + #ifdef EC_R_UNKNOWN_GROUP + {"UNKNOWN_GROUP", ERR_LIB_EC, EC_R_UNKNOWN_GROUP}, + #else + {"UNKNOWN_GROUP", 16, 129}, + #endif + #ifdef EC_R_UNKNOWN_ORDER + {"UNKNOWN_ORDER", ERR_LIB_EC, EC_R_UNKNOWN_ORDER}, + #else + {"UNKNOWN_ORDER", 16, 114}, + #endif + #ifdef EC_R_UNSUPPORTED_FIELD + {"UNSUPPORTED_FIELD", ERR_LIB_EC, EC_R_UNSUPPORTED_FIELD}, + #else + {"UNSUPPORTED_FIELD", 16, 131}, + #endif + #ifdef EC_R_WRONG_CURVE_PARAMETERS + {"WRONG_CURVE_PARAMETERS", ERR_LIB_EC, EC_R_WRONG_CURVE_PARAMETERS}, + #else + {"WRONG_CURVE_PARAMETERS", 16, 145}, + #endif + #ifdef EC_R_WRONG_ORDER + {"WRONG_ORDER", ERR_LIB_EC, EC_R_WRONG_ORDER}, + #else + {"WRONG_ORDER", 16, 130}, + #endif + #ifdef ENGINE_R_ALREADY_LOADED + {"ALREADY_LOADED", ERR_LIB_ENGINE, ENGINE_R_ALREADY_LOADED}, + #else + {"ALREADY_LOADED", 38, 100}, + #endif + #ifdef ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER + {"ARGUMENT_IS_NOT_A_NUMBER", ERR_LIB_ENGINE, ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER}, + #else + {"ARGUMENT_IS_NOT_A_NUMBER", 38, 133}, + #endif + #ifdef ENGINE_R_CMD_NOT_EXECUTABLE + {"CMD_NOT_EXECUTABLE", ERR_LIB_ENGINE, ENGINE_R_CMD_NOT_EXECUTABLE}, + #else + {"CMD_NOT_EXECUTABLE", 38, 134}, + #endif + #ifdef ENGINE_R_COMMAND_TAKES_INPUT + {"COMMAND_TAKES_INPUT", ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_INPUT}, + #else + {"COMMAND_TAKES_INPUT", 38, 135}, + #endif + #ifdef ENGINE_R_COMMAND_TAKES_NO_INPUT + {"COMMAND_TAKES_NO_INPUT", ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_NO_INPUT}, + #else + {"COMMAND_TAKES_NO_INPUT", 38, 136}, + #endif + #ifdef ENGINE_R_CONFLICTING_ENGINE_ID + {"CONFLICTING_ENGINE_ID", ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID}, + #else + {"CONFLICTING_ENGINE_ID", 38, 103}, + #endif + #ifdef ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED + {"CTRL_COMMAND_NOT_IMPLEMENTED", ERR_LIB_ENGINE, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED}, + #else + {"CTRL_COMMAND_NOT_IMPLEMENTED", 38, 119}, + #endif + #ifdef ENGINE_R_DSO_FAILURE + {"DSO_FAILURE", ERR_LIB_ENGINE, ENGINE_R_DSO_FAILURE}, + #else + {"DSO_FAILURE", 38, 104}, + #endif + #ifdef ENGINE_R_DSO_NOT_FOUND + {"DSO_NOT_FOUND", ERR_LIB_ENGINE, ENGINE_R_DSO_NOT_FOUND}, + #else + {"DSO_NOT_FOUND", 38, 132}, + #endif + #ifdef ENGINE_R_ENGINES_SECTION_ERROR + {"ENGINES_SECTION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINES_SECTION_ERROR}, + #else + {"ENGINES_SECTION_ERROR", 38, 148}, + #endif + #ifdef ENGINE_R_ENGINE_CONFIGURATION_ERROR + {"ENGINE_CONFIGURATION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINE_CONFIGURATION_ERROR}, + #else + {"ENGINE_CONFIGURATION_ERROR", 38, 102}, + #endif + #ifdef ENGINE_R_ENGINE_IS_NOT_IN_LIST + {"ENGINE_IS_NOT_IN_LIST", ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST}, + #else + {"ENGINE_IS_NOT_IN_LIST", 38, 105}, + #endif + #ifdef ENGINE_R_ENGINE_SECTION_ERROR + {"ENGINE_SECTION_ERROR", ERR_LIB_ENGINE, ENGINE_R_ENGINE_SECTION_ERROR}, + #else + {"ENGINE_SECTION_ERROR", 38, 149}, + #endif + #ifdef ENGINE_R_FAILED_LOADING_PRIVATE_KEY + {"FAILED_LOADING_PRIVATE_KEY", ERR_LIB_ENGINE, ENGINE_R_FAILED_LOADING_PRIVATE_KEY}, + #else + {"FAILED_LOADING_PRIVATE_KEY", 38, 128}, + #endif + #ifdef ENGINE_R_FAILED_LOADING_PUBLIC_KEY + {"FAILED_LOADING_PUBLIC_KEY", ERR_LIB_ENGINE, ENGINE_R_FAILED_LOADING_PUBLIC_KEY}, + #else + {"FAILED_LOADING_PUBLIC_KEY", 38, 129}, + #endif + #ifdef ENGINE_R_FINISH_FAILED + {"FINISH_FAILED", ERR_LIB_ENGINE, ENGINE_R_FINISH_FAILED}, + #else + {"FINISH_FAILED", 38, 106}, + #endif + #ifdef ENGINE_R_ID_OR_NAME_MISSING + {"ID_OR_NAME_MISSING", ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING}, + #else + {"ID_OR_NAME_MISSING", 38, 108}, + #endif + #ifdef ENGINE_R_INIT_FAILED + {"INIT_FAILED", ERR_LIB_ENGINE, ENGINE_R_INIT_FAILED}, + #else + {"INIT_FAILED", 38, 109}, + #endif + #ifdef ENGINE_R_INTERNAL_LIST_ERROR + {"INTERNAL_LIST_ERROR", ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR}, + #else + {"INTERNAL_LIST_ERROR", 38, 110}, + #endif + #ifdef ENGINE_R_INVALID_ARGUMENT + {"INVALID_ARGUMENT", ERR_LIB_ENGINE, ENGINE_R_INVALID_ARGUMENT}, + #else + {"INVALID_ARGUMENT", 38, 143}, + #endif + #ifdef ENGINE_R_INVALID_CMD_NAME + {"INVALID_CMD_NAME", ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME}, + #else + {"INVALID_CMD_NAME", 38, 137}, + #endif + #ifdef ENGINE_R_INVALID_CMD_NUMBER + {"INVALID_CMD_NUMBER", ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER}, + #else + {"INVALID_CMD_NUMBER", 38, 138}, + #endif + #ifdef ENGINE_R_INVALID_INIT_VALUE + {"INVALID_INIT_VALUE", ERR_LIB_ENGINE, ENGINE_R_INVALID_INIT_VALUE}, + #else + {"INVALID_INIT_VALUE", 38, 151}, + #endif + #ifdef ENGINE_R_INVALID_STRING + {"INVALID_STRING", ERR_LIB_ENGINE, ENGINE_R_INVALID_STRING}, + #else + {"INVALID_STRING", 38, 150}, + #endif + #ifdef ENGINE_R_NOT_INITIALISED + {"NOT_INITIALISED", ERR_LIB_ENGINE, ENGINE_R_NOT_INITIALISED}, + #else + {"NOT_INITIALISED", 38, 117}, + #endif + #ifdef ENGINE_R_NOT_LOADED + {"NOT_LOADED", ERR_LIB_ENGINE, ENGINE_R_NOT_LOADED}, + #else + {"NOT_LOADED", 38, 112}, + #endif + #ifdef ENGINE_R_NO_CONTROL_FUNCTION + {"NO_CONTROL_FUNCTION", ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION}, + #else + {"NO_CONTROL_FUNCTION", 38, 120}, + #endif + #ifdef ENGINE_R_NO_INDEX + {"NO_INDEX", ERR_LIB_ENGINE, ENGINE_R_NO_INDEX}, + #else + {"NO_INDEX", 38, 144}, + #endif + #ifdef ENGINE_R_NO_LOAD_FUNCTION + {"NO_LOAD_FUNCTION", ERR_LIB_ENGINE, ENGINE_R_NO_LOAD_FUNCTION}, + #else + {"NO_LOAD_FUNCTION", 38, 125}, + #endif + #ifdef ENGINE_R_NO_REFERENCE + {"NO_REFERENCE", ERR_LIB_ENGINE, ENGINE_R_NO_REFERENCE}, + #else + {"NO_REFERENCE", 38, 130}, + #endif + #ifdef ENGINE_R_NO_SUCH_ENGINE + {"NO_SUCH_ENGINE", ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE}, + #else + {"NO_SUCH_ENGINE", 38, 116}, + #endif + #ifdef ENGINE_R_UNIMPLEMENTED_CIPHER + {"UNIMPLEMENTED_CIPHER", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_CIPHER}, + #else + {"UNIMPLEMENTED_CIPHER", 38, 146}, + #endif + #ifdef ENGINE_R_UNIMPLEMENTED_DIGEST + {"UNIMPLEMENTED_DIGEST", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_DIGEST}, + #else + {"UNIMPLEMENTED_DIGEST", 38, 147}, + #endif + #ifdef ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD + {"UNIMPLEMENTED_PUBLIC_KEY_METHOD", ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD}, + #else + {"UNIMPLEMENTED_PUBLIC_KEY_METHOD", 38, 101}, + #endif + #ifdef ENGINE_R_VERSION_INCOMPATIBILITY + {"VERSION_INCOMPATIBILITY", ERR_LIB_ENGINE, ENGINE_R_VERSION_INCOMPATIBILITY}, + #else + {"VERSION_INCOMPATIBILITY", 38, 145}, + #endif + #ifdef ESS_R_EMPTY_ESS_CERT_ID_LIST + {"EMPTY_ESS_CERT_ID_LIST", ERR_LIB_ESS, ESS_R_EMPTY_ESS_CERT_ID_LIST}, + #else + {"EMPTY_ESS_CERT_ID_LIST", 54, 107}, + #endif + #ifdef ESS_R_ESS_CERT_DIGEST_ERROR + {"ESS_CERT_DIGEST_ERROR", ERR_LIB_ESS, ESS_R_ESS_CERT_DIGEST_ERROR}, + #else + {"ESS_CERT_DIGEST_ERROR", 54, 103}, + #endif + #ifdef ESS_R_ESS_CERT_ID_NOT_FOUND + {"ESS_CERT_ID_NOT_FOUND", ERR_LIB_ESS, ESS_R_ESS_CERT_ID_NOT_FOUND}, + #else + {"ESS_CERT_ID_NOT_FOUND", 54, 104}, + #endif + #ifdef ESS_R_ESS_CERT_ID_WRONG_ORDER + {"ESS_CERT_ID_WRONG_ORDER", ERR_LIB_ESS, ESS_R_ESS_CERT_ID_WRONG_ORDER}, + #else + {"ESS_CERT_ID_WRONG_ORDER", 54, 105}, + #endif + #ifdef ESS_R_ESS_DIGEST_ALG_UNKNOWN + {"ESS_DIGEST_ALG_UNKNOWN", ERR_LIB_ESS, ESS_R_ESS_DIGEST_ALG_UNKNOWN}, + #else + {"ESS_DIGEST_ALG_UNKNOWN", 54, 106}, + #endif + #ifdef ESS_R_ESS_SIGNING_CERTIFICATE_ERROR + {"ESS_SIGNING_CERTIFICATE_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERTIFICATE_ERROR}, + #else + {"ESS_SIGNING_CERTIFICATE_ERROR", 54, 102}, + #endif + #ifdef ESS_R_ESS_SIGNING_CERT_ADD_ERROR + {"ESS_SIGNING_CERT_ADD_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERT_ADD_ERROR}, + #else + {"ESS_SIGNING_CERT_ADD_ERROR", 54, 100}, + #endif + #ifdef ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR + {"ESS_SIGNING_CERT_V2_ADD_ERROR", ERR_LIB_ESS, ESS_R_ESS_SIGNING_CERT_V2_ADD_ERROR}, + #else + {"ESS_SIGNING_CERT_V2_ADD_ERROR", 54, 101}, + #endif + #ifdef ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE + {"MISSING_SIGNING_CERTIFICATE_ATTRIBUTE", ERR_LIB_ESS, ESS_R_MISSING_SIGNING_CERTIFICATE_ATTRIBUTE}, + #else + {"MISSING_SIGNING_CERTIFICATE_ATTRIBUTE", 54, 108}, + #endif + #ifdef EVP_R_AES_KEY_SETUP_FAILED + {"AES_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_AES_KEY_SETUP_FAILED}, + #else + {"AES_KEY_SETUP_FAILED", 6, 143}, + #endif + #ifdef EVP_R_ARIA_KEY_SETUP_FAILED + {"ARIA_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_ARIA_KEY_SETUP_FAILED}, + #else + {"ARIA_KEY_SETUP_FAILED", 6, 176}, + #endif + #ifdef EVP_R_BAD_ALGORITHM_NAME + {"BAD_ALGORITHM_NAME", ERR_LIB_EVP, EVP_R_BAD_ALGORITHM_NAME}, + #else + {"BAD_ALGORITHM_NAME", 6, 200}, + #endif + #ifdef EVP_R_BAD_DECRYPT + {"BAD_DECRYPT", ERR_LIB_EVP, EVP_R_BAD_DECRYPT}, + #else + {"BAD_DECRYPT", 6, 100}, + #endif + #ifdef EVP_R_BAD_KEY_LENGTH + {"BAD_KEY_LENGTH", ERR_LIB_EVP, EVP_R_BAD_KEY_LENGTH}, + #else + {"BAD_KEY_LENGTH", 6, 195}, + #endif + #ifdef EVP_R_BUFFER_TOO_SMALL + {"BUFFER_TOO_SMALL", ERR_LIB_EVP, EVP_R_BUFFER_TOO_SMALL}, + #else + {"BUFFER_TOO_SMALL", 6, 155}, + #endif + #ifdef EVP_R_CACHE_CONSTANTS_FAILED + {"CACHE_CONSTANTS_FAILED", ERR_LIB_EVP, EVP_R_CACHE_CONSTANTS_FAILED}, + #else + {"CACHE_CONSTANTS_FAILED", 6, 225}, + #endif + #ifdef EVP_R_CAMELLIA_KEY_SETUP_FAILED + {"CAMELLIA_KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_CAMELLIA_KEY_SETUP_FAILED}, + #else + {"CAMELLIA_KEY_SETUP_FAILED", 6, 157}, + #endif + #ifdef EVP_R_CANNOT_GET_PARAMETERS + {"CANNOT_GET_PARAMETERS", ERR_LIB_EVP, EVP_R_CANNOT_GET_PARAMETERS}, + #else + {"CANNOT_GET_PARAMETERS", 6, 197}, + #endif + #ifdef EVP_R_CANNOT_SET_PARAMETERS + {"CANNOT_SET_PARAMETERS", ERR_LIB_EVP, EVP_R_CANNOT_SET_PARAMETERS}, + #else + {"CANNOT_SET_PARAMETERS", 6, 198}, + #endif + #ifdef EVP_R_CIPHER_NOT_GCM_MODE + {"CIPHER_NOT_GCM_MODE", ERR_LIB_EVP, EVP_R_CIPHER_NOT_GCM_MODE}, + #else + {"CIPHER_NOT_GCM_MODE", 6, 184}, + #endif + #ifdef EVP_R_CIPHER_PARAMETER_ERROR + {"CIPHER_PARAMETER_ERROR", ERR_LIB_EVP, EVP_R_CIPHER_PARAMETER_ERROR}, + #else + {"CIPHER_PARAMETER_ERROR", 6, 122}, + #endif + #ifdef EVP_R_COMMAND_NOT_SUPPORTED + {"COMMAND_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED}, + #else + {"COMMAND_NOT_SUPPORTED", 6, 147}, + #endif + #ifdef EVP_R_CONFLICTING_ALGORITHM_NAME + {"CONFLICTING_ALGORITHM_NAME", ERR_LIB_EVP, EVP_R_CONFLICTING_ALGORITHM_NAME}, + #else + {"CONFLICTING_ALGORITHM_NAME", 6, 201}, + #endif + #ifdef EVP_R_COPY_ERROR + {"COPY_ERROR", ERR_LIB_EVP, EVP_R_COPY_ERROR}, + #else + {"COPY_ERROR", 6, 173}, + #endif + #ifdef EVP_R_CTRL_NOT_IMPLEMENTED + {"CTRL_NOT_IMPLEMENTED", ERR_LIB_EVP, EVP_R_CTRL_NOT_IMPLEMENTED}, + #else + {"CTRL_NOT_IMPLEMENTED", 6, 132}, + #endif + #ifdef EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED + {"CTRL_OPERATION_NOT_IMPLEMENTED", ERR_LIB_EVP, EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED}, + #else + {"CTRL_OPERATION_NOT_IMPLEMENTED", 6, 133}, + #endif + #ifdef EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH + {"DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH", ERR_LIB_EVP, EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH}, + #else + {"DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH", 6, 138}, + #endif + #ifdef EVP_R_DECODE_ERROR + {"DECODE_ERROR", ERR_LIB_EVP, EVP_R_DECODE_ERROR}, + #else + {"DECODE_ERROR", 6, 114}, + #endif + #ifdef EVP_R_DEFAULT_QUERY_PARSE_ERROR + {"DEFAULT_QUERY_PARSE_ERROR", ERR_LIB_EVP, EVP_R_DEFAULT_QUERY_PARSE_ERROR}, + #else + {"DEFAULT_QUERY_PARSE_ERROR", 6, 210}, + #endif + #ifdef EVP_R_DIFFERENT_KEY_TYPES + {"DIFFERENT_KEY_TYPES", ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES}, + #else + {"DIFFERENT_KEY_TYPES", 6, 101}, + #endif + #ifdef EVP_R_DIFFERENT_PARAMETERS + {"DIFFERENT_PARAMETERS", ERR_LIB_EVP, EVP_R_DIFFERENT_PARAMETERS}, + #else + {"DIFFERENT_PARAMETERS", 6, 153}, + #endif + #ifdef EVP_R_ERROR_LOADING_SECTION + {"ERROR_LOADING_SECTION", ERR_LIB_EVP, EVP_R_ERROR_LOADING_SECTION}, + #else + {"ERROR_LOADING_SECTION", 6, 165}, + #endif + #ifdef EVP_R_EXPECTING_AN_HMAC_KEY + {"EXPECTING_AN_HMAC_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_AN_HMAC_KEY}, + #else + {"EXPECTING_AN_HMAC_KEY", 6, 174}, + #endif + #ifdef EVP_R_EXPECTING_AN_RSA_KEY + {"EXPECTING_AN_RSA_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_AN_RSA_KEY}, + #else + {"EXPECTING_AN_RSA_KEY", 6, 127}, + #endif + #ifdef EVP_R_EXPECTING_A_DH_KEY + {"EXPECTING_A_DH_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_DH_KEY}, + #else + {"EXPECTING_A_DH_KEY", 6, 128}, + #endif + #ifdef EVP_R_EXPECTING_A_DSA_KEY + {"EXPECTING_A_DSA_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_DSA_KEY}, + #else + {"EXPECTING_A_DSA_KEY", 6, 129}, + #endif + #ifdef EVP_R_EXPECTING_A_ECX_KEY + {"EXPECTING_A_ECX_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_ECX_KEY}, + #else + {"EXPECTING_A_ECX_KEY", 6, 219}, + #endif + #ifdef EVP_R_EXPECTING_A_EC_KEY + {"EXPECTING_A_EC_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_EC_KEY}, + #else + {"EXPECTING_A_EC_KEY", 6, 142}, + #endif + #ifdef EVP_R_EXPECTING_A_POLY1305_KEY + {"EXPECTING_A_POLY1305_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_POLY1305_KEY}, + #else + {"EXPECTING_A_POLY1305_KEY", 6, 164}, + #endif + #ifdef EVP_R_EXPECTING_A_SIPHASH_KEY + {"EXPECTING_A_SIPHASH_KEY", ERR_LIB_EVP, EVP_R_EXPECTING_A_SIPHASH_KEY}, + #else + {"EXPECTING_A_SIPHASH_KEY", 6, 175}, + #endif + #ifdef EVP_R_FINAL_ERROR + {"FINAL_ERROR", ERR_LIB_EVP, EVP_R_FINAL_ERROR}, + #else + {"FINAL_ERROR", 6, 188}, + #endif + #ifdef EVP_R_GENERATE_ERROR + {"GENERATE_ERROR", ERR_LIB_EVP, EVP_R_GENERATE_ERROR}, + #else + {"GENERATE_ERROR", 6, 214}, + #endif + #ifdef EVP_R_GET_RAW_KEY_FAILED + {"GET_RAW_KEY_FAILED", ERR_LIB_EVP, EVP_R_GET_RAW_KEY_FAILED}, + #else + {"GET_RAW_KEY_FAILED", 6, 182}, + #endif + #ifdef EVP_R_ILLEGAL_SCRYPT_PARAMETERS + {"ILLEGAL_SCRYPT_PARAMETERS", ERR_LIB_EVP, EVP_R_ILLEGAL_SCRYPT_PARAMETERS}, + #else + {"ILLEGAL_SCRYPT_PARAMETERS", 6, 171}, + #endif + #ifdef EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS + {"INACCESSIBLE_DOMAIN_PARAMETERS", ERR_LIB_EVP, EVP_R_INACCESSIBLE_DOMAIN_PARAMETERS}, + #else + {"INACCESSIBLE_DOMAIN_PARAMETERS", 6, 204}, + #endif + #ifdef EVP_R_INACCESSIBLE_KEY + {"INACCESSIBLE_KEY", ERR_LIB_EVP, EVP_R_INACCESSIBLE_KEY}, + #else + {"INACCESSIBLE_KEY", 6, 203}, + #endif + #ifdef EVP_R_INITIALIZATION_ERROR + {"INITIALIZATION_ERROR", ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR}, + #else + {"INITIALIZATION_ERROR", 6, 134}, + #endif + #ifdef EVP_R_INPUT_NOT_INITIALIZED + {"INPUT_NOT_INITIALIZED", ERR_LIB_EVP, EVP_R_INPUT_NOT_INITIALIZED}, + #else + {"INPUT_NOT_INITIALIZED", 6, 111}, + #endif + #ifdef EVP_R_INVALID_CUSTOM_LENGTH + {"INVALID_CUSTOM_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_CUSTOM_LENGTH}, + #else + {"INVALID_CUSTOM_LENGTH", 6, 185}, + #endif + #ifdef EVP_R_INVALID_DIGEST + {"INVALID_DIGEST", ERR_LIB_EVP, EVP_R_INVALID_DIGEST}, + #else + {"INVALID_DIGEST", 6, 152}, + #endif + #ifdef EVP_R_INVALID_IV_LENGTH + {"INVALID_IV_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH}, + #else + {"INVALID_IV_LENGTH", 6, 194}, + #endif + #ifdef EVP_R_INVALID_KEY + {"INVALID_KEY", ERR_LIB_EVP, EVP_R_INVALID_KEY}, + #else + {"INVALID_KEY", 6, 163}, + #endif + #ifdef EVP_R_INVALID_KEY_LENGTH + {"INVALID_KEY_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_KEY_LENGTH}, + #else + {"INVALID_KEY_LENGTH", 6, 130}, + #endif + #ifdef EVP_R_INVALID_LENGTH + {"INVALID_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_LENGTH}, + #else + {"INVALID_LENGTH", 6, 221}, + #endif + #ifdef EVP_R_INVALID_NULL_ALGORITHM + {"INVALID_NULL_ALGORITHM", ERR_LIB_EVP, EVP_R_INVALID_NULL_ALGORITHM}, + #else + {"INVALID_NULL_ALGORITHM", 6, 218}, + #endif + #ifdef EVP_R_INVALID_OPERATION + {"INVALID_OPERATION", ERR_LIB_EVP, EVP_R_INVALID_OPERATION}, + #else + {"INVALID_OPERATION", 6, 148}, + #endif + #ifdef EVP_R_INVALID_PROVIDER_FUNCTIONS + {"INVALID_PROVIDER_FUNCTIONS", ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS}, + #else + {"INVALID_PROVIDER_FUNCTIONS", 6, 193}, + #endif + #ifdef EVP_R_INVALID_SALT_LENGTH + {"INVALID_SALT_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SALT_LENGTH}, + #else + {"INVALID_SALT_LENGTH", 6, 186}, + #endif + #ifdef EVP_R_INVALID_SECRET_LENGTH + {"INVALID_SECRET_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SECRET_LENGTH}, + #else + {"INVALID_SECRET_LENGTH", 6, 223}, + #endif + #ifdef EVP_R_INVALID_SEED_LENGTH + {"INVALID_SEED_LENGTH", ERR_LIB_EVP, EVP_R_INVALID_SEED_LENGTH}, + #else + {"INVALID_SEED_LENGTH", 6, 220}, + #endif + #ifdef EVP_R_INVALID_VALUE + {"INVALID_VALUE", ERR_LIB_EVP, EVP_R_INVALID_VALUE}, + #else + {"INVALID_VALUE", 6, 222}, + #endif + #ifdef EVP_R_KEYMGMT_EXPORT_FAILURE + {"KEYMGMT_EXPORT_FAILURE", ERR_LIB_EVP, EVP_R_KEYMGMT_EXPORT_FAILURE}, + #else + {"KEYMGMT_EXPORT_FAILURE", 6, 205}, + #endif + #ifdef EVP_R_KEY_SETUP_FAILED + {"KEY_SETUP_FAILED", ERR_LIB_EVP, EVP_R_KEY_SETUP_FAILED}, + #else + {"KEY_SETUP_FAILED", 6, 180}, + #endif + #ifdef EVP_R_LOCKING_NOT_SUPPORTED + {"LOCKING_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_LOCKING_NOT_SUPPORTED}, + #else + {"LOCKING_NOT_SUPPORTED", 6, 213}, + #endif + #ifdef EVP_R_MEMORY_LIMIT_EXCEEDED + {"MEMORY_LIMIT_EXCEEDED", ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED}, + #else + {"MEMORY_LIMIT_EXCEEDED", 6, 172}, + #endif + #ifdef EVP_R_MESSAGE_DIGEST_IS_NULL + {"MESSAGE_DIGEST_IS_NULL", ERR_LIB_EVP, EVP_R_MESSAGE_DIGEST_IS_NULL}, + #else + {"MESSAGE_DIGEST_IS_NULL", 6, 159}, + #endif + #ifdef EVP_R_METHOD_NOT_SUPPORTED + {"METHOD_NOT_SUPPORTED", ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED}, + #else + {"METHOD_NOT_SUPPORTED", 6, 144}, + #endif + #ifdef EVP_R_MISSING_PARAMETERS + {"MISSING_PARAMETERS", ERR_LIB_EVP, EVP_R_MISSING_PARAMETERS}, + #else + {"MISSING_PARAMETERS", 6, 103}, + #endif + #ifdef EVP_R_NOT_ABLE_TO_COPY_CTX + {"NOT_ABLE_TO_COPY_CTX", ERR_LIB_EVP, EVP_R_NOT_ABLE_TO_COPY_CTX}, + #else + {"NOT_ABLE_TO_COPY_CTX", 6, 190}, + #endif + #ifdef EVP_R_NOT_XOF_OR_INVALID_LENGTH + {"NOT_XOF_OR_INVALID_LENGTH", ERR_LIB_EVP, EVP_R_NOT_XOF_OR_INVALID_LENGTH}, + #else + {"NOT_XOF_OR_INVALID_LENGTH", 6, 178}, + #endif + #ifdef EVP_R_NO_CIPHER_SET + {"NO_CIPHER_SET", ERR_LIB_EVP, EVP_R_NO_CIPHER_SET}, + #else + {"NO_CIPHER_SET", 6, 131}, + #endif + #ifdef EVP_R_NO_DEFAULT_DIGEST + {"NO_DEFAULT_DIGEST", ERR_LIB_EVP, EVP_R_NO_DEFAULT_DIGEST}, + #else + {"NO_DEFAULT_DIGEST", 6, 158}, + #endif + #ifdef EVP_R_NO_DIGEST_SET + {"NO_DIGEST_SET", ERR_LIB_EVP, EVP_R_NO_DIGEST_SET}, + #else + {"NO_DIGEST_SET", 6, 139}, + #endif + #ifdef EVP_R_NO_IMPORT_FUNCTION + {"NO_IMPORT_FUNCTION", ERR_LIB_EVP, EVP_R_NO_IMPORT_FUNCTION}, + #else + {"NO_IMPORT_FUNCTION", 6, 206}, + #endif + #ifdef EVP_R_NO_KEYMGMT_AVAILABLE + {"NO_KEYMGMT_AVAILABLE", ERR_LIB_EVP, EVP_R_NO_KEYMGMT_AVAILABLE}, + #else + {"NO_KEYMGMT_AVAILABLE", 6, 199}, + #endif + #ifdef EVP_R_NO_KEYMGMT_PRESENT + {"NO_KEYMGMT_PRESENT", ERR_LIB_EVP, EVP_R_NO_KEYMGMT_PRESENT}, + #else + {"NO_KEYMGMT_PRESENT", 6, 196}, + #endif + #ifdef EVP_R_NO_KEY_SET + {"NO_KEY_SET", ERR_LIB_EVP, EVP_R_NO_KEY_SET}, + #else + {"NO_KEY_SET", 6, 154}, + #endif + #ifdef EVP_R_NO_OPERATION_SET + {"NO_OPERATION_SET", ERR_LIB_EVP, EVP_R_NO_OPERATION_SET}, + #else + {"NO_OPERATION_SET", 6, 149}, + #endif + #ifdef EVP_R_NULL_MAC_PKEY_CTX + {"NULL_MAC_PKEY_CTX", ERR_LIB_EVP, EVP_R_NULL_MAC_PKEY_CTX}, + #else + {"NULL_MAC_PKEY_CTX", 6, 208}, + #endif + #ifdef EVP_R_ONLY_ONESHOT_SUPPORTED + {"ONLY_ONESHOT_SUPPORTED", ERR_LIB_EVP, EVP_R_ONLY_ONESHOT_SUPPORTED}, + #else + {"ONLY_ONESHOT_SUPPORTED", 6, 177}, + #endif + #ifdef EVP_R_OPERATION_NOT_INITIALIZED + {"OPERATION_NOT_INITIALIZED", ERR_LIB_EVP, EVP_R_OPERATION_NOT_INITIALIZED}, + #else + {"OPERATION_NOT_INITIALIZED", 6, 151}, + #endif + #ifdef EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE + {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, + #else + {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 6, 150}, + #endif + #ifdef EVP_R_OUTPUT_WOULD_OVERFLOW + {"OUTPUT_WOULD_OVERFLOW", ERR_LIB_EVP, EVP_R_OUTPUT_WOULD_OVERFLOW}, + #else + {"OUTPUT_WOULD_OVERFLOW", 6, 202}, + #endif + #ifdef EVP_R_PARAMETER_TOO_LARGE + {"PARAMETER_TOO_LARGE", ERR_LIB_EVP, EVP_R_PARAMETER_TOO_LARGE}, + #else + {"PARAMETER_TOO_LARGE", 6, 187}, + #endif + #ifdef EVP_R_PARTIALLY_OVERLAPPING + {"PARTIALLY_OVERLAPPING", ERR_LIB_EVP, EVP_R_PARTIALLY_OVERLAPPING}, + #else + {"PARTIALLY_OVERLAPPING", 6, 162}, + #endif + #ifdef EVP_R_PBKDF2_ERROR + {"PBKDF2_ERROR", ERR_LIB_EVP, EVP_R_PBKDF2_ERROR}, + #else + {"PBKDF2_ERROR", 6, 181}, + #endif + #ifdef EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED + {"PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED", ERR_LIB_EVP, EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED}, + #else + {"PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED", 6, 179}, + #endif + #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR + {"PRIVATE_KEY_DECODE_ERROR", ERR_LIB_EVP, EVP_R_PRIVATE_KEY_DECODE_ERROR}, + #else + {"PRIVATE_KEY_DECODE_ERROR", 6, 145}, + #endif + #ifdef EVP_R_PRIVATE_KEY_ENCODE_ERROR + {"PRIVATE_KEY_ENCODE_ERROR", ERR_LIB_EVP, EVP_R_PRIVATE_KEY_ENCODE_ERROR}, + #else + {"PRIVATE_KEY_ENCODE_ERROR", 6, 146}, + #endif + #ifdef EVP_R_PUBLIC_KEY_NOT_RSA + {"PUBLIC_KEY_NOT_RSA", ERR_LIB_EVP, EVP_R_PUBLIC_KEY_NOT_RSA}, + #else + {"PUBLIC_KEY_NOT_RSA", 6, 106}, + #endif + #ifdef EVP_R_SETTING_XOF_FAILED + {"SETTING_XOF_FAILED", ERR_LIB_EVP, EVP_R_SETTING_XOF_FAILED}, + #else + {"SETTING_XOF_FAILED", 6, 227}, + #endif + #ifdef EVP_R_SET_DEFAULT_PROPERTY_FAILURE + {"SET_DEFAULT_PROPERTY_FAILURE", ERR_LIB_EVP, EVP_R_SET_DEFAULT_PROPERTY_FAILURE}, + #else + {"SET_DEFAULT_PROPERTY_FAILURE", 6, 209}, + #endif + #ifdef EVP_R_TOO_MANY_RECORDS + {"TOO_MANY_RECORDS", ERR_LIB_EVP, EVP_R_TOO_MANY_RECORDS}, + #else + {"TOO_MANY_RECORDS", 6, 183}, + #endif + #ifdef EVP_R_UNABLE_TO_ENABLE_LOCKING + {"UNABLE_TO_ENABLE_LOCKING", ERR_LIB_EVP, EVP_R_UNABLE_TO_ENABLE_LOCKING}, + #else + {"UNABLE_TO_ENABLE_LOCKING", 6, 212}, + #endif + #ifdef EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE + {"UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE", ERR_LIB_EVP, EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE}, + #else + {"UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE", 6, 215}, + #endif + #ifdef EVP_R_UNABLE_TO_GET_RANDOM_STRENGTH + {"UNABLE_TO_GET_RANDOM_STRENGTH", ERR_LIB_EVP, EVP_R_UNABLE_TO_GET_RANDOM_STRENGTH}, + #else + {"UNABLE_TO_GET_RANDOM_STRENGTH", 6, 216}, + #endif + #ifdef EVP_R_UNABLE_TO_LOCK_CONTEXT + {"UNABLE_TO_LOCK_CONTEXT", ERR_LIB_EVP, EVP_R_UNABLE_TO_LOCK_CONTEXT}, + #else + {"UNABLE_TO_LOCK_CONTEXT", 6, 211}, + #endif + #ifdef EVP_R_UNABLE_TO_SET_CALLBACKS + {"UNABLE_TO_SET_CALLBACKS", ERR_LIB_EVP, EVP_R_UNABLE_TO_SET_CALLBACKS}, + #else + {"UNABLE_TO_SET_CALLBACKS", 6, 217}, + #endif + #ifdef EVP_R_UNKNOWN_CIPHER + {"UNKNOWN_CIPHER", ERR_LIB_EVP, EVP_R_UNKNOWN_CIPHER}, + #else + {"UNKNOWN_CIPHER", 6, 160}, + #endif + #ifdef EVP_R_UNKNOWN_DIGEST + {"UNKNOWN_DIGEST", ERR_LIB_EVP, EVP_R_UNKNOWN_DIGEST}, + #else + {"UNKNOWN_DIGEST", 6, 161}, + #endif + #ifdef EVP_R_UNKNOWN_KEY_TYPE + {"UNKNOWN_KEY_TYPE", ERR_LIB_EVP, EVP_R_UNKNOWN_KEY_TYPE}, + #else + {"UNKNOWN_KEY_TYPE", 6, 207}, + #endif + #ifdef EVP_R_UNKNOWN_OPTION + {"UNKNOWN_OPTION", ERR_LIB_EVP, EVP_R_UNKNOWN_OPTION}, + #else + {"UNKNOWN_OPTION", 6, 169}, + #endif + #ifdef EVP_R_UNKNOWN_PBE_ALGORITHM + {"UNKNOWN_PBE_ALGORITHM", ERR_LIB_EVP, EVP_R_UNKNOWN_PBE_ALGORITHM}, + #else + {"UNKNOWN_PBE_ALGORITHM", 6, 121}, + #endif + #ifdef EVP_R_UNSUPPORTED_ALGORITHM + {"UNSUPPORTED_ALGORITHM", ERR_LIB_EVP, EVP_R_UNSUPPORTED_ALGORITHM}, + #else + {"UNSUPPORTED_ALGORITHM", 6, 156}, + #endif + #ifdef EVP_R_UNSUPPORTED_CIPHER + {"UNSUPPORTED_CIPHER", ERR_LIB_EVP, EVP_R_UNSUPPORTED_CIPHER}, + #else + {"UNSUPPORTED_CIPHER", 6, 107}, + #endif + #ifdef EVP_R_UNSUPPORTED_KEYLENGTH + {"UNSUPPORTED_KEYLENGTH", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEYLENGTH}, + #else + {"UNSUPPORTED_KEYLENGTH", 6, 123}, + #endif + #ifdef EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION + {"UNSUPPORTED_KEY_DERIVATION_FUNCTION", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION}, + #else + {"UNSUPPORTED_KEY_DERIVATION_FUNCTION", 6, 124}, + #endif + #ifdef EVP_R_UNSUPPORTED_KEY_SIZE + {"UNSUPPORTED_KEY_SIZE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_SIZE}, + #else + {"UNSUPPORTED_KEY_SIZE", 6, 108}, + #endif + #ifdef EVP_R_UNSUPPORTED_KEY_TYPE + {"UNSUPPORTED_KEY_TYPE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_KEY_TYPE}, + #else + {"UNSUPPORTED_KEY_TYPE", 6, 224}, + #endif + #ifdef EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS + {"UNSUPPORTED_NUMBER_OF_ROUNDS", ERR_LIB_EVP, EVP_R_UNSUPPORTED_NUMBER_OF_ROUNDS}, + #else + {"UNSUPPORTED_NUMBER_OF_ROUNDS", 6, 135}, + #endif + #ifdef EVP_R_UNSUPPORTED_PRF + {"UNSUPPORTED_PRF", ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRF}, + #else + {"UNSUPPORTED_PRF", 6, 125}, + #endif + #ifdef EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM + {"UNSUPPORTED_PRIVATE_KEY_ALGORITHM", ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM}, + #else + {"UNSUPPORTED_PRIVATE_KEY_ALGORITHM", 6, 118}, + #endif + #ifdef EVP_R_UNSUPPORTED_SALT_TYPE + {"UNSUPPORTED_SALT_TYPE", ERR_LIB_EVP, EVP_R_UNSUPPORTED_SALT_TYPE}, + #else + {"UNSUPPORTED_SALT_TYPE", 6, 126}, + #endif + #ifdef EVP_R_UPDATE_ERROR + {"UPDATE_ERROR", ERR_LIB_EVP, EVP_R_UPDATE_ERROR}, + #else + {"UPDATE_ERROR", 6, 189}, + #endif + #ifdef EVP_R_WRAP_MODE_NOT_ALLOWED + {"WRAP_MODE_NOT_ALLOWED", ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED}, + #else + {"WRAP_MODE_NOT_ALLOWED", 6, 170}, + #endif + #ifdef EVP_R_WRONG_FINAL_BLOCK_LENGTH + {"WRONG_FINAL_BLOCK_LENGTH", ERR_LIB_EVP, EVP_R_WRONG_FINAL_BLOCK_LENGTH}, + #else + {"WRONG_FINAL_BLOCK_LENGTH", 6, 109}, + #endif + #ifdef EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE + {"XTS_DATA_UNIT_IS_TOO_LARGE", ERR_LIB_EVP, EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE}, + #else + {"XTS_DATA_UNIT_IS_TOO_LARGE", 6, 191}, + #endif + #ifdef EVP_R_XTS_DUPLICATED_KEYS + {"XTS_DUPLICATED_KEYS", ERR_LIB_EVP, EVP_R_XTS_DUPLICATED_KEYS}, + #else + {"XTS_DUPLICATED_KEYS", 6, 192}, + #endif + #ifdef HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN + {"ASN1_LEN_EXCEEDS_MAX_RESP_LEN", ERR_LIB_HTTP, HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN}, + #else + {"ASN1_LEN_EXCEEDS_MAX_RESP_LEN", 61, 108}, + #endif + #ifdef HTTP_R_CONNECT_FAILURE + {"CONNECT_FAILURE", ERR_LIB_HTTP, HTTP_R_CONNECT_FAILURE}, + #else + {"CONNECT_FAILURE", 61, 100}, + #endif + #ifdef HTTP_R_ERROR_PARSING_ASN1_LENGTH + {"ERROR_PARSING_ASN1_LENGTH", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_ASN1_LENGTH}, + #else + {"ERROR_PARSING_ASN1_LENGTH", 61, 109}, + #endif + #ifdef HTTP_R_ERROR_PARSING_CONTENT_LENGTH + {"ERROR_PARSING_CONTENT_LENGTH", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_CONTENT_LENGTH}, + #else + {"ERROR_PARSING_CONTENT_LENGTH", 61, 119}, + #endif + #ifdef HTTP_R_ERROR_PARSING_URL + {"ERROR_PARSING_URL", ERR_LIB_HTTP, HTTP_R_ERROR_PARSING_URL}, + #else + {"ERROR_PARSING_URL", 61, 101}, + #endif + #ifdef HTTP_R_ERROR_RECEIVING + {"ERROR_RECEIVING", ERR_LIB_HTTP, HTTP_R_ERROR_RECEIVING}, + #else + {"ERROR_RECEIVING", 61, 103}, + #endif + #ifdef HTTP_R_ERROR_SENDING + {"ERROR_SENDING", ERR_LIB_HTTP, HTTP_R_ERROR_SENDING}, + #else + {"ERROR_SENDING", 61, 102}, + #endif + #ifdef HTTP_R_FAILED_READING_DATA + {"FAILED_READING_DATA", ERR_LIB_HTTP, HTTP_R_FAILED_READING_DATA}, + #else + {"FAILED_READING_DATA", 61, 128}, + #endif + #ifdef HTTP_R_HEADER_PARSE_ERROR + {"HEADER_PARSE_ERROR", ERR_LIB_HTTP, HTTP_R_HEADER_PARSE_ERROR}, + #else + {"HEADER_PARSE_ERROR", 61, 126}, + #endif + #ifdef HTTP_R_INCONSISTENT_CONTENT_LENGTH + {"INCONSISTENT_CONTENT_LENGTH", ERR_LIB_HTTP, HTTP_R_INCONSISTENT_CONTENT_LENGTH}, + #else + {"INCONSISTENT_CONTENT_LENGTH", 61, 120}, + #endif + #ifdef HTTP_R_INVALID_PORT_NUMBER + {"INVALID_PORT_NUMBER", ERR_LIB_HTTP, HTTP_R_INVALID_PORT_NUMBER}, + #else + {"INVALID_PORT_NUMBER", 61, 123}, + #endif + #ifdef HTTP_R_INVALID_URL_PATH + {"INVALID_URL_PATH", ERR_LIB_HTTP, HTTP_R_INVALID_URL_PATH}, + #else + {"INVALID_URL_PATH", 61, 125}, + #endif + #ifdef HTTP_R_INVALID_URL_SCHEME + {"INVALID_URL_SCHEME", ERR_LIB_HTTP, HTTP_R_INVALID_URL_SCHEME}, + #else + {"INVALID_URL_SCHEME", 61, 124}, + #endif + #ifdef HTTP_R_MAX_RESP_LEN_EXCEEDED + {"MAX_RESP_LEN_EXCEEDED", ERR_LIB_HTTP, HTTP_R_MAX_RESP_LEN_EXCEEDED}, + #else + {"MAX_RESP_LEN_EXCEEDED", 61, 117}, + #endif + #ifdef HTTP_R_MISSING_ASN1_ENCODING + {"MISSING_ASN1_ENCODING", ERR_LIB_HTTP, HTTP_R_MISSING_ASN1_ENCODING}, + #else + {"MISSING_ASN1_ENCODING", 61, 110}, + #endif + #ifdef HTTP_R_MISSING_CONTENT_TYPE + {"MISSING_CONTENT_TYPE", ERR_LIB_HTTP, HTTP_R_MISSING_CONTENT_TYPE}, + #else + {"MISSING_CONTENT_TYPE", 61, 121}, + #endif + #ifdef HTTP_R_MISSING_REDIRECT_LOCATION + {"MISSING_REDIRECT_LOCATION", ERR_LIB_HTTP, HTTP_R_MISSING_REDIRECT_LOCATION}, + #else + {"MISSING_REDIRECT_LOCATION", 61, 111}, + #endif + #ifdef HTTP_R_RECEIVED_ERROR + {"RECEIVED_ERROR", ERR_LIB_HTTP, HTTP_R_RECEIVED_ERROR}, + #else + {"RECEIVED_ERROR", 61, 105}, + #endif + #ifdef HTTP_R_RECEIVED_WRONG_HTTP_VERSION + {"RECEIVED_WRONG_HTTP_VERSION", ERR_LIB_HTTP, HTTP_R_RECEIVED_WRONG_HTTP_VERSION}, + #else + {"RECEIVED_WRONG_HTTP_VERSION", 61, 106}, + #endif + #ifdef HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP + {"REDIRECTION_FROM_HTTPS_TO_HTTP", ERR_LIB_HTTP, HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP}, + #else + {"REDIRECTION_FROM_HTTPS_TO_HTTP", 61, 112}, + #endif + #ifdef HTTP_R_REDIRECTION_NOT_ENABLED + {"REDIRECTION_NOT_ENABLED", ERR_LIB_HTTP, HTTP_R_REDIRECTION_NOT_ENABLED}, + #else + {"REDIRECTION_NOT_ENABLED", 61, 116}, + #endif + #ifdef HTTP_R_RESPONSE_LINE_TOO_LONG + {"RESPONSE_LINE_TOO_LONG", ERR_LIB_HTTP, HTTP_R_RESPONSE_LINE_TOO_LONG}, + #else + {"RESPONSE_LINE_TOO_LONG", 61, 113}, + #endif + #ifdef HTTP_R_RESPONSE_PARSE_ERROR + {"RESPONSE_PARSE_ERROR", ERR_LIB_HTTP, HTTP_R_RESPONSE_PARSE_ERROR}, + #else + {"RESPONSE_PARSE_ERROR", 61, 104}, + #endif + #ifdef HTTP_R_RETRY_TIMEOUT + {"RETRY_TIMEOUT", ERR_LIB_HTTP, HTTP_R_RETRY_TIMEOUT}, + #else + {"RETRY_TIMEOUT", 61, 129}, + #endif + #ifdef HTTP_R_SERVER_CANCELED_CONNECTION + {"SERVER_CANCELED_CONNECTION", ERR_LIB_HTTP, HTTP_R_SERVER_CANCELED_CONNECTION}, + #else + {"SERVER_CANCELED_CONNECTION", 61, 127}, + #endif + #ifdef HTTP_R_SOCK_NOT_SUPPORTED + {"SOCK_NOT_SUPPORTED", ERR_LIB_HTTP, HTTP_R_SOCK_NOT_SUPPORTED}, + #else + {"SOCK_NOT_SUPPORTED", 61, 122}, + #endif + #ifdef HTTP_R_STATUS_CODE_UNSUPPORTED + {"STATUS_CODE_UNSUPPORTED", ERR_LIB_HTTP, HTTP_R_STATUS_CODE_UNSUPPORTED}, + #else + {"STATUS_CODE_UNSUPPORTED", 61, 114}, + #endif + #ifdef HTTP_R_TLS_NOT_ENABLED + {"TLS_NOT_ENABLED", ERR_LIB_HTTP, HTTP_R_TLS_NOT_ENABLED}, + #else + {"TLS_NOT_ENABLED", 61, 107}, + #endif + #ifdef HTTP_R_TOO_MANY_REDIRECTIONS + {"TOO_MANY_REDIRECTIONS", ERR_LIB_HTTP, HTTP_R_TOO_MANY_REDIRECTIONS}, + #else + {"TOO_MANY_REDIRECTIONS", 61, 115}, + #endif + #ifdef HTTP_R_UNEXPECTED_CONTENT_TYPE + {"UNEXPECTED_CONTENT_TYPE", ERR_LIB_HTTP, HTTP_R_UNEXPECTED_CONTENT_TYPE}, + #else + {"UNEXPECTED_CONTENT_TYPE", 61, 118}, + #endif + #ifdef OBJ_R_OID_EXISTS + {"OID_EXISTS", ERR_LIB_OBJ, OBJ_R_OID_EXISTS}, + #else + {"OID_EXISTS", 8, 102}, + #endif + #ifdef OBJ_R_UNKNOWN_NID + {"UNKNOWN_NID", ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID}, + #else + {"UNKNOWN_NID", 8, 101}, + #endif + #ifdef OBJ_R_UNKNOWN_OBJECT_NAME + {"UNKNOWN_OBJECT_NAME", ERR_LIB_OBJ, OBJ_R_UNKNOWN_OBJECT_NAME}, + #else + {"UNKNOWN_OBJECT_NAME", 8, 103}, + #endif + #ifdef OCSP_R_CERTIFICATE_VERIFY_ERROR + {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_OCSP, OCSP_R_CERTIFICATE_VERIFY_ERROR}, + #else + {"CERTIFICATE_VERIFY_ERROR", 39, 101}, + #endif + #ifdef OCSP_R_DIGEST_ERR + {"DIGEST_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_ERR}, + #else + {"DIGEST_ERR", 39, 102}, + #endif + #ifdef OCSP_R_DIGEST_NAME_ERR + {"DIGEST_NAME_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_NAME_ERR}, + #else + {"DIGEST_NAME_ERR", 39, 106}, + #endif + #ifdef OCSP_R_DIGEST_SIZE_ERR + {"DIGEST_SIZE_ERR", ERR_LIB_OCSP, OCSP_R_DIGEST_SIZE_ERR}, + #else + {"DIGEST_SIZE_ERR", 39, 107}, + #endif + #ifdef OCSP_R_ERROR_IN_NEXTUPDATE_FIELD + {"ERROR_IN_NEXTUPDATE_FIELD", ERR_LIB_OCSP, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD}, + #else + {"ERROR_IN_NEXTUPDATE_FIELD", 39, 122}, + #endif + #ifdef OCSP_R_ERROR_IN_THISUPDATE_FIELD + {"ERROR_IN_THISUPDATE_FIELD", ERR_LIB_OCSP, OCSP_R_ERROR_IN_THISUPDATE_FIELD}, + #else + {"ERROR_IN_THISUPDATE_FIELD", 39, 123}, + #endif + #ifdef OCSP_R_MISSING_OCSPSIGNING_USAGE + {"MISSING_OCSPSIGNING_USAGE", ERR_LIB_OCSP, OCSP_R_MISSING_OCSPSIGNING_USAGE}, + #else + {"MISSING_OCSPSIGNING_USAGE", 39, 103}, + #endif + #ifdef OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE + {"NEXTUPDATE_BEFORE_THISUPDATE", ERR_LIB_OCSP, OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE}, + #else + {"NEXTUPDATE_BEFORE_THISUPDATE", 39, 124}, + #endif + #ifdef OCSP_R_NOT_BASIC_RESPONSE + {"NOT_BASIC_RESPONSE", ERR_LIB_OCSP, OCSP_R_NOT_BASIC_RESPONSE}, + #else + {"NOT_BASIC_RESPONSE", 39, 104}, + #endif + #ifdef OCSP_R_NO_CERTIFICATES_IN_CHAIN + {"NO_CERTIFICATES_IN_CHAIN", ERR_LIB_OCSP, OCSP_R_NO_CERTIFICATES_IN_CHAIN}, + #else + {"NO_CERTIFICATES_IN_CHAIN", 39, 105}, + #endif + #ifdef OCSP_R_NO_RESPONSE_DATA + {"NO_RESPONSE_DATA", ERR_LIB_OCSP, OCSP_R_NO_RESPONSE_DATA}, + #else + {"NO_RESPONSE_DATA", 39, 108}, + #endif + #ifdef OCSP_R_NO_REVOKED_TIME + {"NO_REVOKED_TIME", ERR_LIB_OCSP, OCSP_R_NO_REVOKED_TIME}, + #else + {"NO_REVOKED_TIME", 39, 109}, + #endif + #ifdef OCSP_R_NO_SIGNER_KEY + {"NO_SIGNER_KEY", ERR_LIB_OCSP, OCSP_R_NO_SIGNER_KEY}, + #else + {"NO_SIGNER_KEY", 39, 130}, + #endif + #ifdef OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_OCSP, OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, + #else + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 39, 110}, + #endif + #ifdef OCSP_R_REQUEST_NOT_SIGNED + {"REQUEST_NOT_SIGNED", ERR_LIB_OCSP, OCSP_R_REQUEST_NOT_SIGNED}, + #else + {"REQUEST_NOT_SIGNED", 39, 128}, + #endif + #ifdef OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA + {"RESPONSE_CONTAINS_NO_REVOCATION_DATA", ERR_LIB_OCSP, OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA}, + #else + {"RESPONSE_CONTAINS_NO_REVOCATION_DATA", 39, 111}, + #endif + #ifdef OCSP_R_ROOT_CA_NOT_TRUSTED + {"ROOT_CA_NOT_TRUSTED", ERR_LIB_OCSP, OCSP_R_ROOT_CA_NOT_TRUSTED}, + #else + {"ROOT_CA_NOT_TRUSTED", 39, 112}, + #endif + #ifdef OCSP_R_SIGNATURE_FAILURE + {"SIGNATURE_FAILURE", ERR_LIB_OCSP, OCSP_R_SIGNATURE_FAILURE}, + #else + {"SIGNATURE_FAILURE", 39, 117}, + #endif + #ifdef OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND + {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_OCSP, OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND}, + #else + {"SIGNER_CERTIFICATE_NOT_FOUND", 39, 118}, + #endif + #ifdef OCSP_R_STATUS_EXPIRED + {"STATUS_EXPIRED", ERR_LIB_OCSP, OCSP_R_STATUS_EXPIRED}, + #else + {"STATUS_EXPIRED", 39, 125}, + #endif + #ifdef OCSP_R_STATUS_NOT_YET_VALID + {"STATUS_NOT_YET_VALID", ERR_LIB_OCSP, OCSP_R_STATUS_NOT_YET_VALID}, + #else + {"STATUS_NOT_YET_VALID", 39, 126}, + #endif + #ifdef OCSP_R_STATUS_TOO_OLD + {"STATUS_TOO_OLD", ERR_LIB_OCSP, OCSP_R_STATUS_TOO_OLD}, + #else + {"STATUS_TOO_OLD", 39, 127}, + #endif + #ifdef OCSP_R_UNKNOWN_MESSAGE_DIGEST + {"UNKNOWN_MESSAGE_DIGEST", ERR_LIB_OCSP, OCSP_R_UNKNOWN_MESSAGE_DIGEST}, + #else + {"UNKNOWN_MESSAGE_DIGEST", 39, 119}, + #endif + #ifdef OCSP_R_UNKNOWN_NID + {"UNKNOWN_NID", ERR_LIB_OCSP, OCSP_R_UNKNOWN_NID}, + #else + {"UNKNOWN_NID", 39, 120}, + #endif + #ifdef OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE + {"UNSUPPORTED_REQUESTORNAME_TYPE", ERR_LIB_OCSP, OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE}, + #else + {"UNSUPPORTED_REQUESTORNAME_TYPE", 39, 129}, + #endif + #ifdef OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT + {"COULD_NOT_DECODE_OBJECT", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_COULD_NOT_DECODE_OBJECT}, + #else + {"COULD_NOT_DECODE_OBJECT", 60, 101}, + #endif + #ifdef OSSL_DECODER_R_DECODER_NOT_FOUND + {"DECODER_NOT_FOUND", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_DECODER_NOT_FOUND}, + #else + {"DECODER_NOT_FOUND", 60, 102}, + #endif + #ifdef OSSL_DECODER_R_MISSING_GET_PARAMS + {"MISSING_GET_PARAMS", ERR_LIB_OSSL_DECODER, OSSL_DECODER_R_MISSING_GET_PARAMS}, + #else + {"MISSING_GET_PARAMS", 60, 100}, + #endif + #ifdef OSSL_ENCODER_R_ENCODER_NOT_FOUND + {"ENCODER_NOT_FOUND", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_ENCODER_NOT_FOUND}, + #else + {"ENCODER_NOT_FOUND", 59, 101}, + #endif + #ifdef OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY + {"INCORRECT_PROPERTY_QUERY", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_INCORRECT_PROPERTY_QUERY}, + #else + {"INCORRECT_PROPERTY_QUERY", 59, 100}, + #endif + #ifdef OSSL_ENCODER_R_MISSING_GET_PARAMS + {"MISSING_GET_PARAMS", ERR_LIB_OSSL_ENCODER, OSSL_ENCODER_R_MISSING_GET_PARAMS}, + #else + {"MISSING_GET_PARAMS", 59, 102}, + #endif + #ifdef OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE + {"AMBIGUOUS_CONTENT_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_AMBIGUOUS_CONTENT_TYPE}, + #else + {"AMBIGUOUS_CONTENT_TYPE", 44, 107}, + #endif + #ifdef OSSL_STORE_R_BAD_PASSWORD_READ + {"BAD_PASSWORD_READ", ERR_LIB_OSSL_STORE, OSSL_STORE_R_BAD_PASSWORD_READ}, + #else + {"BAD_PASSWORD_READ", 44, 115}, + #endif + #ifdef OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC + {"ERROR_VERIFYING_PKCS12_MAC", ERR_LIB_OSSL_STORE, OSSL_STORE_R_ERROR_VERIFYING_PKCS12_MAC}, + #else + {"ERROR_VERIFYING_PKCS12_MAC", 44, 113}, + #endif + #ifdef OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST + {"FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST", ERR_LIB_OSSL_STORE, OSSL_STORE_R_FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST}, + #else + {"FINGERPRINT_SIZE_DOES_NOT_MATCH_DIGEST", 44, 121}, + #endif + #ifdef OSSL_STORE_R_INVALID_SCHEME + {"INVALID_SCHEME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_INVALID_SCHEME}, + #else + {"INVALID_SCHEME", 44, 106}, + #endif + #ifdef OSSL_STORE_R_IS_NOT_A + {"IS_NOT_A", ERR_LIB_OSSL_STORE, OSSL_STORE_R_IS_NOT_A}, + #else + {"IS_NOT_A", 44, 112}, + #endif + #ifdef OSSL_STORE_R_LOADER_INCOMPLETE + {"LOADER_INCOMPLETE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE}, + #else + {"LOADER_INCOMPLETE", 44, 116}, + #endif + #ifdef OSSL_STORE_R_LOADING_STARTED + {"LOADING_STARTED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADING_STARTED}, + #else + {"LOADING_STARTED", 44, 117}, + #endif + #ifdef OSSL_STORE_R_NOT_A_CERTIFICATE + {"NOT_A_CERTIFICATE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CERTIFICATE}, + #else + {"NOT_A_CERTIFICATE", 44, 100}, + #endif + #ifdef OSSL_STORE_R_NOT_A_CRL + {"NOT_A_CRL", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_CRL}, + #else + {"NOT_A_CRL", 44, 101}, + #endif + #ifdef OSSL_STORE_R_NOT_A_NAME + {"NOT_A_NAME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_NAME}, + #else + {"NOT_A_NAME", 44, 103}, + #endif + #ifdef OSSL_STORE_R_NOT_A_PRIVATE_KEY + {"NOT_A_PRIVATE_KEY", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PRIVATE_KEY}, + #else + {"NOT_A_PRIVATE_KEY", 44, 102}, + #endif + #ifdef OSSL_STORE_R_NOT_A_PUBLIC_KEY + {"NOT_A_PUBLIC_KEY", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_A_PUBLIC_KEY}, + #else + {"NOT_A_PUBLIC_KEY", 44, 122}, + #endif + #ifdef OSSL_STORE_R_NOT_PARAMETERS + {"NOT_PARAMETERS", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NOT_PARAMETERS}, + #else + {"NOT_PARAMETERS", 44, 104}, + #endif + #ifdef OSSL_STORE_R_NO_LOADERS_FOUND + {"NO_LOADERS_FOUND", ERR_LIB_OSSL_STORE, OSSL_STORE_R_NO_LOADERS_FOUND}, + #else + {"NO_LOADERS_FOUND", 44, 123}, + #endif + #ifdef OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR + {"PASSPHRASE_CALLBACK_ERROR", ERR_LIB_OSSL_STORE, OSSL_STORE_R_PASSPHRASE_CALLBACK_ERROR}, + #else + {"PASSPHRASE_CALLBACK_ERROR", 44, 114}, + #endif + #ifdef OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE + {"PATH_MUST_BE_ABSOLUTE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_PATH_MUST_BE_ABSOLUTE}, + #else + {"PATH_MUST_BE_ABSOLUTE", 44, 108}, + #endif + #ifdef OSSL_STORE_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES + {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", ERR_LIB_OSSL_STORE, OSSL_STORE_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES}, + #else + {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", 44, 119}, + #endif + #ifdef OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED + {"UI_PROCESS_INTERRUPTED_OR_CANCELLED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UI_PROCESS_INTERRUPTED_OR_CANCELLED}, + #else + {"UI_PROCESS_INTERRUPTED_OR_CANCELLED", 44, 109}, + #endif + #ifdef OSSL_STORE_R_UNREGISTERED_SCHEME + {"UNREGISTERED_SCHEME", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNREGISTERED_SCHEME}, + #else + {"UNREGISTERED_SCHEME", 44, 105}, + #endif + #ifdef OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE + {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_CONTENT_TYPE}, + #else + {"UNSUPPORTED_CONTENT_TYPE", 44, 110}, + #endif + #ifdef OSSL_STORE_R_UNSUPPORTED_OPERATION + {"UNSUPPORTED_OPERATION", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_OPERATION}, + #else + {"UNSUPPORTED_OPERATION", 44, 118}, + #endif + #ifdef OSSL_STORE_R_UNSUPPORTED_SEARCH_TYPE + {"UNSUPPORTED_SEARCH_TYPE", ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNSUPPORTED_SEARCH_TYPE}, + #else + {"UNSUPPORTED_SEARCH_TYPE", 44, 120}, + #endif + #ifdef OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED + {"URI_AUTHORITY_UNSUPPORTED", ERR_LIB_OSSL_STORE, OSSL_STORE_R_URI_AUTHORITY_UNSUPPORTED}, + #else + {"URI_AUTHORITY_UNSUPPORTED", 44, 111}, + #endif + #ifdef PEM_R_BAD_BASE64_DECODE + {"BAD_BASE64_DECODE", ERR_LIB_PEM, PEM_R_BAD_BASE64_DECODE}, + #else + {"BAD_BASE64_DECODE", 9, 100}, + #endif + #ifdef PEM_R_BAD_DECRYPT + {"BAD_DECRYPT", ERR_LIB_PEM, PEM_R_BAD_DECRYPT}, + #else + {"BAD_DECRYPT", 9, 101}, + #endif + #ifdef PEM_R_BAD_END_LINE + {"BAD_END_LINE", ERR_LIB_PEM, PEM_R_BAD_END_LINE}, + #else + {"BAD_END_LINE", 9, 102}, + #endif + #ifdef PEM_R_BAD_IV_CHARS + {"BAD_IV_CHARS", ERR_LIB_PEM, PEM_R_BAD_IV_CHARS}, + #else + {"BAD_IV_CHARS", 9, 103}, + #endif + #ifdef PEM_R_BAD_MAGIC_NUMBER + {"BAD_MAGIC_NUMBER", ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER}, + #else + {"BAD_MAGIC_NUMBER", 9, 116}, + #endif + #ifdef PEM_R_BAD_PASSWORD_READ + {"BAD_PASSWORD_READ", ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ}, + #else + {"BAD_PASSWORD_READ", 9, 104}, + #endif + #ifdef PEM_R_BAD_VERSION_NUMBER + {"BAD_VERSION_NUMBER", ERR_LIB_PEM, PEM_R_BAD_VERSION_NUMBER}, + #else + {"BAD_VERSION_NUMBER", 9, 117}, + #endif + #ifdef PEM_R_BIO_WRITE_FAILURE + {"BIO_WRITE_FAILURE", ERR_LIB_PEM, PEM_R_BIO_WRITE_FAILURE}, + #else + {"BIO_WRITE_FAILURE", 9, 118}, + #endif + #ifdef PEM_R_CIPHER_IS_NULL + {"CIPHER_IS_NULL", ERR_LIB_PEM, PEM_R_CIPHER_IS_NULL}, + #else + {"CIPHER_IS_NULL", 9, 127}, + #endif + #ifdef PEM_R_ERROR_CONVERTING_PRIVATE_KEY + {"ERROR_CONVERTING_PRIVATE_KEY", ERR_LIB_PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY}, + #else + {"ERROR_CONVERTING_PRIVATE_KEY", 9, 115}, + #endif + #ifdef PEM_R_EXPECTING_DSS_KEY_BLOB + {"EXPECTING_DSS_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_DSS_KEY_BLOB}, + #else + {"EXPECTING_DSS_KEY_BLOB", 9, 131}, + #endif + #ifdef PEM_R_EXPECTING_PRIVATE_KEY_BLOB + {"EXPECTING_PRIVATE_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PRIVATE_KEY_BLOB}, + #else + {"EXPECTING_PRIVATE_KEY_BLOB", 9, 119}, + #endif + #ifdef PEM_R_EXPECTING_PUBLIC_KEY_BLOB + {"EXPECTING_PUBLIC_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PUBLIC_KEY_BLOB}, + #else + {"EXPECTING_PUBLIC_KEY_BLOB", 9, 120}, + #endif + #ifdef PEM_R_EXPECTING_RSA_KEY_BLOB + {"EXPECTING_RSA_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_RSA_KEY_BLOB}, + #else + {"EXPECTING_RSA_KEY_BLOB", 9, 132}, + #endif + #ifdef PEM_R_HEADER_TOO_LONG + {"HEADER_TOO_LONG", ERR_LIB_PEM, PEM_R_HEADER_TOO_LONG}, + #else + {"HEADER_TOO_LONG", 9, 128}, + #endif + #ifdef PEM_R_INCONSISTENT_HEADER + {"INCONSISTENT_HEADER", ERR_LIB_PEM, PEM_R_INCONSISTENT_HEADER}, + #else + {"INCONSISTENT_HEADER", 9, 121}, + #endif + #ifdef PEM_R_KEYBLOB_HEADER_PARSE_ERROR + {"KEYBLOB_HEADER_PARSE_ERROR", ERR_LIB_PEM, PEM_R_KEYBLOB_HEADER_PARSE_ERROR}, + #else + {"KEYBLOB_HEADER_PARSE_ERROR", 9, 122}, + #endif + #ifdef PEM_R_KEYBLOB_TOO_SHORT + {"KEYBLOB_TOO_SHORT", ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT}, + #else + {"KEYBLOB_TOO_SHORT", 9, 123}, + #endif + #ifdef PEM_R_MISSING_DEK_IV + {"MISSING_DEK_IV", ERR_LIB_PEM, PEM_R_MISSING_DEK_IV}, + #else + {"MISSING_DEK_IV", 9, 129}, + #endif + #ifdef PEM_R_NOT_DEK_INFO + {"NOT_DEK_INFO", ERR_LIB_PEM, PEM_R_NOT_DEK_INFO}, + #else + {"NOT_DEK_INFO", 9, 105}, + #endif + #ifdef PEM_R_NOT_ENCRYPTED + {"NOT_ENCRYPTED", ERR_LIB_PEM, PEM_R_NOT_ENCRYPTED}, + #else + {"NOT_ENCRYPTED", 9, 106}, + #endif + #ifdef PEM_R_NOT_PROC_TYPE + {"NOT_PROC_TYPE", ERR_LIB_PEM, PEM_R_NOT_PROC_TYPE}, + #else + {"NOT_PROC_TYPE", 9, 107}, + #endif + #ifdef PEM_R_NO_START_LINE + {"NO_START_LINE", ERR_LIB_PEM, PEM_R_NO_START_LINE}, + #else + {"NO_START_LINE", 9, 108}, + #endif + #ifdef PEM_R_PROBLEMS_GETTING_PASSWORD + {"PROBLEMS_GETTING_PASSWORD", ERR_LIB_PEM, PEM_R_PROBLEMS_GETTING_PASSWORD}, + #else + {"PROBLEMS_GETTING_PASSWORD", 9, 109}, + #endif + #ifdef PEM_R_PVK_DATA_TOO_SHORT + {"PVK_DATA_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT}, + #else + {"PVK_DATA_TOO_SHORT", 9, 124}, + #endif + #ifdef PEM_R_PVK_TOO_SHORT + {"PVK_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT}, + #else + {"PVK_TOO_SHORT", 9, 125}, + #endif + #ifdef PEM_R_READ_KEY + {"READ_KEY", ERR_LIB_PEM, PEM_R_READ_KEY}, + #else + {"READ_KEY", 9, 111}, + #endif + #ifdef PEM_R_SHORT_HEADER + {"SHORT_HEADER", ERR_LIB_PEM, PEM_R_SHORT_HEADER}, + #else + {"SHORT_HEADER", 9, 112}, + #endif + #ifdef PEM_R_UNEXPECTED_DEK_IV + {"UNEXPECTED_DEK_IV", ERR_LIB_PEM, PEM_R_UNEXPECTED_DEK_IV}, + #else + {"UNEXPECTED_DEK_IV", 9, 130}, + #endif + #ifdef PEM_R_UNSUPPORTED_CIPHER + {"UNSUPPORTED_CIPHER", ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER}, + #else + {"UNSUPPORTED_CIPHER", 9, 113}, + #endif + #ifdef PEM_R_UNSUPPORTED_ENCRYPTION + {"UNSUPPORTED_ENCRYPTION", ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION}, + #else + {"UNSUPPORTED_ENCRYPTION", 9, 114}, + #endif + #ifdef PEM_R_UNSUPPORTED_KEY_COMPONENTS + {"UNSUPPORTED_KEY_COMPONENTS", ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS}, + #else + {"UNSUPPORTED_KEY_COMPONENTS", 9, 126}, + #endif + #ifdef PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE + {"UNSUPPORTED_PUBLIC_KEY_TYPE", ERR_LIB_PEM, PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE}, + #else + {"UNSUPPORTED_PUBLIC_KEY_TYPE", 9, 110}, + #endif + #ifdef PKCS12_R_CANT_PACK_STRUCTURE + {"CANT_PACK_STRUCTURE", ERR_LIB_PKCS12, PKCS12_R_CANT_PACK_STRUCTURE}, + #else + {"CANT_PACK_STRUCTURE", 35, 100}, + #endif + #ifdef PKCS12_R_CONTENT_TYPE_NOT_DATA + {"CONTENT_TYPE_NOT_DATA", ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA}, + #else + {"CONTENT_TYPE_NOT_DATA", 35, 121}, + #endif + #ifdef PKCS12_R_DECODE_ERROR + {"DECODE_ERROR", ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR}, + #else + {"DECODE_ERROR", 35, 101}, + #endif + #ifdef PKCS12_R_ENCODE_ERROR + {"ENCODE_ERROR", ERR_LIB_PKCS12, PKCS12_R_ENCODE_ERROR}, + #else + {"ENCODE_ERROR", 35, 102}, + #endif + #ifdef PKCS12_R_ENCRYPT_ERROR + {"ENCRYPT_ERROR", ERR_LIB_PKCS12, PKCS12_R_ENCRYPT_ERROR}, + #else + {"ENCRYPT_ERROR", 35, 103}, + #endif + #ifdef PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE + {"ERROR_SETTING_ENCRYPTED_DATA_TYPE", ERR_LIB_PKCS12, PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE}, + #else + {"ERROR_SETTING_ENCRYPTED_DATA_TYPE", 35, 120}, + #endif + #ifdef PKCS12_R_INVALID_NULL_ARGUMENT + {"INVALID_NULL_ARGUMENT", ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_ARGUMENT}, + #else + {"INVALID_NULL_ARGUMENT", 35, 104}, + #endif + #ifdef PKCS12_R_INVALID_NULL_PKCS12_POINTER + {"INVALID_NULL_PKCS12_POINTER", ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_PKCS12_POINTER}, + #else + {"INVALID_NULL_PKCS12_POINTER", 35, 105}, + #endif + #ifdef PKCS12_R_INVALID_TYPE + {"INVALID_TYPE", ERR_LIB_PKCS12, PKCS12_R_INVALID_TYPE}, + #else + {"INVALID_TYPE", 35, 112}, + #endif + #ifdef PKCS12_R_IV_GEN_ERROR + {"IV_GEN_ERROR", ERR_LIB_PKCS12, PKCS12_R_IV_GEN_ERROR}, + #else + {"IV_GEN_ERROR", 35, 106}, + #endif + #ifdef PKCS12_R_KEY_GEN_ERROR + {"KEY_GEN_ERROR", ERR_LIB_PKCS12, PKCS12_R_KEY_GEN_ERROR}, + #else + {"KEY_GEN_ERROR", 35, 107}, + #endif + #ifdef PKCS12_R_MAC_ABSENT + {"MAC_ABSENT", ERR_LIB_PKCS12, PKCS12_R_MAC_ABSENT}, + #else + {"MAC_ABSENT", 35, 108}, + #endif + #ifdef PKCS12_R_MAC_GENERATION_ERROR + {"MAC_GENERATION_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_GENERATION_ERROR}, + #else + {"MAC_GENERATION_ERROR", 35, 109}, + #endif + #ifdef PKCS12_R_MAC_SETUP_ERROR + {"MAC_SETUP_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_SETUP_ERROR}, + #else + {"MAC_SETUP_ERROR", 35, 110}, + #endif + #ifdef PKCS12_R_MAC_STRING_SET_ERROR + {"MAC_STRING_SET_ERROR", ERR_LIB_PKCS12, PKCS12_R_MAC_STRING_SET_ERROR}, + #else + {"MAC_STRING_SET_ERROR", 35, 111}, + #endif + #ifdef PKCS12_R_MAC_VERIFY_FAILURE + {"MAC_VERIFY_FAILURE", ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE}, + #else + {"MAC_VERIFY_FAILURE", 35, 113}, + #endif + #ifdef PKCS12_R_PARSE_ERROR + {"PARSE_ERROR", ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR}, + #else + {"PARSE_ERROR", 35, 114}, + #endif + #ifdef PKCS12_R_PKCS12_CIPHERFINAL_ERROR + {"PKCS12_CIPHERFINAL_ERROR", ERR_LIB_PKCS12, PKCS12_R_PKCS12_CIPHERFINAL_ERROR}, + #else + {"PKCS12_CIPHERFINAL_ERROR", 35, 116}, + #endif + #ifdef PKCS12_R_UNKNOWN_DIGEST_ALGORITHM + {"UNKNOWN_DIGEST_ALGORITHM", ERR_LIB_PKCS12, PKCS12_R_UNKNOWN_DIGEST_ALGORITHM}, + #else + {"UNKNOWN_DIGEST_ALGORITHM", 35, 118}, + #endif + #ifdef PKCS12_R_UNSUPPORTED_PKCS12_MODE + {"UNSUPPORTED_PKCS12_MODE", ERR_LIB_PKCS12, PKCS12_R_UNSUPPORTED_PKCS12_MODE}, + #else + {"UNSUPPORTED_PKCS12_MODE", 35, 119}, + #endif + #ifdef PKCS7_R_CERTIFICATE_VERIFY_ERROR + {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_PKCS7, PKCS7_R_CERTIFICATE_VERIFY_ERROR}, + #else + {"CERTIFICATE_VERIFY_ERROR", 33, 117}, + #endif + #ifdef PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER + {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", ERR_LIB_PKCS7, PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER}, + #else + {"CIPHER_HAS_NO_OBJECT_IDENTIFIER", 33, 144}, + #endif + #ifdef PKCS7_R_CIPHER_NOT_INITIALIZED + {"CIPHER_NOT_INITIALIZED", ERR_LIB_PKCS7, PKCS7_R_CIPHER_NOT_INITIALIZED}, + #else + {"CIPHER_NOT_INITIALIZED", 33, 116}, + #endif + #ifdef PKCS7_R_CONTENT_AND_DATA_PRESENT + {"CONTENT_AND_DATA_PRESENT", ERR_LIB_PKCS7, PKCS7_R_CONTENT_AND_DATA_PRESENT}, + #else + {"CONTENT_AND_DATA_PRESENT", 33, 118}, + #endif + #ifdef PKCS7_R_CTRL_ERROR + {"CTRL_ERROR", ERR_LIB_PKCS7, PKCS7_R_CTRL_ERROR}, + #else + {"CTRL_ERROR", 33, 152}, + #endif + #ifdef PKCS7_R_DECRYPT_ERROR + {"DECRYPT_ERROR", ERR_LIB_PKCS7, PKCS7_R_DECRYPT_ERROR}, + #else + {"DECRYPT_ERROR", 33, 119}, + #endif + #ifdef PKCS7_R_DIGEST_FAILURE + {"DIGEST_FAILURE", ERR_LIB_PKCS7, PKCS7_R_DIGEST_FAILURE}, + #else + {"DIGEST_FAILURE", 33, 101}, + #endif + #ifdef PKCS7_R_ENCRYPTION_CTRL_FAILURE + {"ENCRYPTION_CTRL_FAILURE", ERR_LIB_PKCS7, PKCS7_R_ENCRYPTION_CTRL_FAILURE}, + #else + {"ENCRYPTION_CTRL_FAILURE", 33, 149}, + #endif + #ifdef PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE + {"ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_PKCS7, PKCS7_R_ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, + #else + {"ENCRYPTION_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 33, 150}, + #endif + #ifdef PKCS7_R_ERROR_ADDING_RECIPIENT + {"ERROR_ADDING_RECIPIENT", ERR_LIB_PKCS7, PKCS7_R_ERROR_ADDING_RECIPIENT}, + #else + {"ERROR_ADDING_RECIPIENT", 33, 120}, + #endif + #ifdef PKCS7_R_ERROR_SETTING_CIPHER + {"ERROR_SETTING_CIPHER", ERR_LIB_PKCS7, PKCS7_R_ERROR_SETTING_CIPHER}, + #else + {"ERROR_SETTING_CIPHER", 33, 121}, + #endif + #ifdef PKCS7_R_INVALID_NULL_POINTER + {"INVALID_NULL_POINTER", ERR_LIB_PKCS7, PKCS7_R_INVALID_NULL_POINTER}, + #else + {"INVALID_NULL_POINTER", 33, 143}, + #endif + #ifdef PKCS7_R_INVALID_SIGNED_DATA_TYPE + {"INVALID_SIGNED_DATA_TYPE", ERR_LIB_PKCS7, PKCS7_R_INVALID_SIGNED_DATA_TYPE}, + #else + {"INVALID_SIGNED_DATA_TYPE", 33, 155}, + #endif + #ifdef PKCS7_R_NO_CONTENT + {"NO_CONTENT", ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT}, + #else + {"NO_CONTENT", 33, 122}, + #endif + #ifdef PKCS7_R_NO_DEFAULT_DIGEST + {"NO_DEFAULT_DIGEST", ERR_LIB_PKCS7, PKCS7_R_NO_DEFAULT_DIGEST}, + #else + {"NO_DEFAULT_DIGEST", 33, 151}, + #endif + #ifdef PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND + {"NO_MATCHING_DIGEST_TYPE_FOUND", ERR_LIB_PKCS7, PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND}, + #else + {"NO_MATCHING_DIGEST_TYPE_FOUND", 33, 154}, + #endif + #ifdef PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE + {"NO_RECIPIENT_MATCHES_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE}, + #else + {"NO_RECIPIENT_MATCHES_CERTIFICATE", 33, 115}, + #endif + #ifdef PKCS7_R_NO_SIGNATURES_ON_DATA + {"NO_SIGNATURES_ON_DATA", ERR_LIB_PKCS7, PKCS7_R_NO_SIGNATURES_ON_DATA}, + #else + {"NO_SIGNATURES_ON_DATA", 33, 123}, + #endif + #ifdef PKCS7_R_NO_SIGNERS + {"NO_SIGNERS", ERR_LIB_PKCS7, PKCS7_R_NO_SIGNERS}, + #else + {"NO_SIGNERS", 33, 142}, + #endif + #ifdef PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE + {"OPERATION_NOT_SUPPORTED_ON_THIS_TYPE", ERR_LIB_PKCS7, PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE}, + #else + {"OPERATION_NOT_SUPPORTED_ON_THIS_TYPE", 33, 104}, + #endif + #ifdef PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR + {"PKCS7_ADD_SIGNATURE_ERROR", ERR_LIB_PKCS7, PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR}, + #else + {"PKCS7_ADD_SIGNATURE_ERROR", 33, 124}, + #endif + #ifdef PKCS7_R_PKCS7_ADD_SIGNER_ERROR + {"PKCS7_ADD_SIGNER_ERROR", ERR_LIB_PKCS7, PKCS7_R_PKCS7_ADD_SIGNER_ERROR}, + #else + {"PKCS7_ADD_SIGNER_ERROR", 33, 153}, + #endif + #ifdef PKCS7_R_PKCS7_DATASIGN + {"PKCS7_DATASIGN", ERR_LIB_PKCS7, PKCS7_R_PKCS7_DATASIGN}, + #else + {"PKCS7_DATASIGN", 33, 145}, + #endif + #ifdef PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, + #else + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 33, 127}, + #endif + #ifdef PKCS7_R_SIGNATURE_FAILURE + {"SIGNATURE_FAILURE", ERR_LIB_PKCS7, PKCS7_R_SIGNATURE_FAILURE}, + #else + {"SIGNATURE_FAILURE", 33, 105}, + #endif + #ifdef PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND + {"SIGNER_CERTIFICATE_NOT_FOUND", ERR_LIB_PKCS7, PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND}, + #else + {"SIGNER_CERTIFICATE_NOT_FOUND", 33, 128}, + #endif + #ifdef PKCS7_R_SIGNING_CTRL_FAILURE + {"SIGNING_CTRL_FAILURE", ERR_LIB_PKCS7, PKCS7_R_SIGNING_CTRL_FAILURE}, + #else + {"SIGNING_CTRL_FAILURE", 33, 147}, + #endif + #ifdef PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE + {"SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", ERR_LIB_PKCS7, PKCS7_R_SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE}, + #else + {"SIGNING_NOT_SUPPORTED_FOR_THIS_KEY_TYPE", 33, 148}, + #endif + #ifdef PKCS7_R_SMIME_TEXT_ERROR + {"SMIME_TEXT_ERROR", ERR_LIB_PKCS7, PKCS7_R_SMIME_TEXT_ERROR}, + #else + {"SMIME_TEXT_ERROR", 33, 129}, + #endif + #ifdef PKCS7_R_UNABLE_TO_FIND_CERTIFICATE + {"UNABLE_TO_FIND_CERTIFICATE", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_CERTIFICATE}, + #else + {"UNABLE_TO_FIND_CERTIFICATE", 33, 106}, + #endif + #ifdef PKCS7_R_UNABLE_TO_FIND_MEM_BIO + {"UNABLE_TO_FIND_MEM_BIO", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MEM_BIO}, + #else + {"UNABLE_TO_FIND_MEM_BIO", 33, 107}, + #endif + #ifdef PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST + {"UNABLE_TO_FIND_MESSAGE_DIGEST", ERR_LIB_PKCS7, PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST}, + #else + {"UNABLE_TO_FIND_MESSAGE_DIGEST", 33, 108}, + #endif + #ifdef PKCS7_R_UNKNOWN_DIGEST_TYPE + {"UNKNOWN_DIGEST_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_DIGEST_TYPE}, + #else + {"UNKNOWN_DIGEST_TYPE", 33, 109}, + #endif + #ifdef PKCS7_R_UNKNOWN_OPERATION + {"UNKNOWN_OPERATION", ERR_LIB_PKCS7, PKCS7_R_UNKNOWN_OPERATION}, + #else + {"UNKNOWN_OPERATION", 33, 110}, + #endif + #ifdef PKCS7_R_UNSUPPORTED_CIPHER_TYPE + {"UNSUPPORTED_CIPHER_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CIPHER_TYPE}, + #else + {"UNSUPPORTED_CIPHER_TYPE", 33, 111}, + #endif + #ifdef PKCS7_R_UNSUPPORTED_CONTENT_TYPE + {"UNSUPPORTED_CONTENT_TYPE", ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE}, + #else + {"UNSUPPORTED_CONTENT_TYPE", 33, 112}, + #endif + #ifdef PKCS7_R_WRONG_CONTENT_TYPE + {"WRONG_CONTENT_TYPE", ERR_LIB_PKCS7, PKCS7_R_WRONG_CONTENT_TYPE}, + #else + {"WRONG_CONTENT_TYPE", 33, 113}, + #endif + #ifdef PKCS7_R_WRONG_PKCS7_TYPE + {"WRONG_PKCS7_TYPE", ERR_LIB_PKCS7, PKCS7_R_WRONG_PKCS7_TYPE}, + #else + {"WRONG_PKCS7_TYPE", 33, 114}, + #endif + #ifdef PROP_R_NAME_TOO_LONG + {"NAME_TOO_LONG", ERR_LIB_PROP, PROP_R_NAME_TOO_LONG}, + #else + {"NAME_TOO_LONG", 55, 100}, + #endif + #ifdef PROP_R_NOT_AN_ASCII_CHARACTER + {"NOT_AN_ASCII_CHARACTER", ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER}, + #else + {"NOT_AN_ASCII_CHARACTER", 55, 101}, + #endif + #ifdef PROP_R_NOT_AN_HEXADECIMAL_DIGIT + {"NOT_AN_HEXADECIMAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT}, + #else + {"NOT_AN_HEXADECIMAL_DIGIT", 55, 102}, + #endif + #ifdef PROP_R_NOT_AN_IDENTIFIER + {"NOT_AN_IDENTIFIER", ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER}, + #else + {"NOT_AN_IDENTIFIER", 55, 103}, + #endif + #ifdef PROP_R_NOT_AN_OCTAL_DIGIT + {"NOT_AN_OCTAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT}, + #else + {"NOT_AN_OCTAL_DIGIT", 55, 104}, + #endif + #ifdef PROP_R_NOT_A_DECIMAL_DIGIT + {"NOT_A_DECIMAL_DIGIT", ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT}, + #else + {"NOT_A_DECIMAL_DIGIT", 55, 105}, + #endif + #ifdef PROP_R_NO_MATCHING_STRING_DELIMITER + {"NO_MATCHING_STRING_DELIMITER", ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER}, + #else + {"NO_MATCHING_STRING_DELIMITER", 55, 106}, + #endif + #ifdef PROP_R_NO_VALUE + {"NO_VALUE", ERR_LIB_PROP, PROP_R_NO_VALUE}, + #else + {"NO_VALUE", 55, 107}, + #endif + #ifdef PROP_R_PARSE_FAILED + {"PARSE_FAILED", ERR_LIB_PROP, PROP_R_PARSE_FAILED}, + #else + {"PARSE_FAILED", 55, 108}, + #endif + #ifdef PROP_R_STRING_TOO_LONG + {"STRING_TOO_LONG", ERR_LIB_PROP, PROP_R_STRING_TOO_LONG}, + #else + {"STRING_TOO_LONG", 55, 109}, + #endif + #ifdef PROP_R_TRAILING_CHARACTERS + {"TRAILING_CHARACTERS", ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS}, + #else + {"TRAILING_CHARACTERS", 55, 110}, + #endif + #ifdef PROV_R_ADDITIONAL_INPUT_TOO_LONG + {"ADDITIONAL_INPUT_TOO_LONG", ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG}, + #else + {"ADDITIONAL_INPUT_TOO_LONG", 57, 184}, + #endif + #ifdef PROV_R_ALGORITHM_MISMATCH + {"ALGORITHM_MISMATCH", ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH}, + #else + {"ALGORITHM_MISMATCH", 57, 173}, + #endif + #ifdef PROV_R_ALREADY_INSTANTIATED + {"ALREADY_INSTANTIATED", ERR_LIB_PROV, PROV_R_ALREADY_INSTANTIATED}, + #else + {"ALREADY_INSTANTIATED", 57, 185}, + #endif + #ifdef PROV_R_BAD_DECRYPT + {"BAD_DECRYPT", ERR_LIB_PROV, PROV_R_BAD_DECRYPT}, + #else + {"BAD_DECRYPT", 57, 100}, + #endif + #ifdef PROV_R_BAD_ENCODING + {"BAD_ENCODING", ERR_LIB_PROV, PROV_R_BAD_ENCODING}, + #else + {"BAD_ENCODING", 57, 141}, + #endif + #ifdef PROV_R_BAD_LENGTH + {"BAD_LENGTH", ERR_LIB_PROV, PROV_R_BAD_LENGTH}, + #else + {"BAD_LENGTH", 57, 142}, + #endif + #ifdef PROV_R_BAD_TLS_CLIENT_VERSION + {"BAD_TLS_CLIENT_VERSION", ERR_LIB_PROV, PROV_R_BAD_TLS_CLIENT_VERSION}, + #else + {"BAD_TLS_CLIENT_VERSION", 57, 161}, + #endif + #ifdef PROV_R_BN_ERROR + {"BN_ERROR", ERR_LIB_PROV, PROV_R_BN_ERROR}, + #else + {"BN_ERROR", 57, 160}, + #endif + #ifdef PROV_R_CIPHER_OPERATION_FAILED + {"CIPHER_OPERATION_FAILED", ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED}, + #else + {"CIPHER_OPERATION_FAILED", 57, 102}, + #endif + #ifdef PROV_R_DERIVATION_FUNCTION_INIT_FAILED + {"DERIVATION_FUNCTION_INIT_FAILED", ERR_LIB_PROV, PROV_R_DERIVATION_FUNCTION_INIT_FAILED}, + #else + {"DERIVATION_FUNCTION_INIT_FAILED", 57, 205}, + #endif + #ifdef PROV_R_DIGEST_NOT_ALLOWED + {"DIGEST_NOT_ALLOWED", ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED}, + #else + {"DIGEST_NOT_ALLOWED", 57, 174}, + #endif + #ifdef PROV_R_EMS_NOT_ENABLED + {"EMS_NOT_ENABLED", ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED}, + #else + {"EMS_NOT_ENABLED", 57, 233}, + #endif + #ifdef PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK + {"ENTROPY_SOURCE_STRENGTH_TOO_WEAK", ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK}, + #else + {"ENTROPY_SOURCE_STRENGTH_TOO_WEAK", 57, 186}, + #endif + #ifdef PROV_R_ERROR_INSTANTIATING_DRBG + {"ERROR_INSTANTIATING_DRBG", ERR_LIB_PROV, PROV_R_ERROR_INSTANTIATING_DRBG}, + #else + {"ERROR_INSTANTIATING_DRBG", 57, 188}, + #endif + #ifdef PROV_R_ERROR_RETRIEVING_ENTROPY + {"ERROR_RETRIEVING_ENTROPY", ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_ENTROPY}, + #else + {"ERROR_RETRIEVING_ENTROPY", 57, 189}, + #endif + #ifdef PROV_R_ERROR_RETRIEVING_NONCE + {"ERROR_RETRIEVING_NONCE", ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE}, + #else + {"ERROR_RETRIEVING_NONCE", 57, 190}, + #endif + #ifdef PROV_R_FAILED_DURING_DERIVATION + {"FAILED_DURING_DERIVATION", ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION}, + #else + {"FAILED_DURING_DERIVATION", 57, 164}, + #endif + #ifdef PROV_R_FAILED_TO_CREATE_LOCK + {"FAILED_TO_CREATE_LOCK", ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK}, + #else + {"FAILED_TO_CREATE_LOCK", 57, 180}, + #endif + #ifdef PROV_R_FAILED_TO_DECRYPT + {"FAILED_TO_DECRYPT", ERR_LIB_PROV, PROV_R_FAILED_TO_DECRYPT}, + #else + {"FAILED_TO_DECRYPT", 57, 162}, + #endif + #ifdef PROV_R_FAILED_TO_GENERATE_KEY + {"FAILED_TO_GENERATE_KEY", ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY}, + #else + {"FAILED_TO_GENERATE_KEY", 57, 121}, + #endif + #ifdef PROV_R_FAILED_TO_GET_PARAMETER + {"FAILED_TO_GET_PARAMETER", ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER}, + #else + {"FAILED_TO_GET_PARAMETER", 57, 103}, + #endif + #ifdef PROV_R_FAILED_TO_SET_PARAMETER + {"FAILED_TO_SET_PARAMETER", ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER}, + #else + {"FAILED_TO_SET_PARAMETER", 57, 104}, + #endif + #ifdef PROV_R_FAILED_TO_SIGN + {"FAILED_TO_SIGN", ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN}, + #else + {"FAILED_TO_SIGN", 57, 175}, + #endif + #ifdef PROV_R_FIPS_MODULE_CONDITIONAL_ERROR + {"FIPS_MODULE_CONDITIONAL_ERROR", ERR_LIB_PROV, PROV_R_FIPS_MODULE_CONDITIONAL_ERROR}, + #else + {"FIPS_MODULE_CONDITIONAL_ERROR", 57, 227}, + #endif + #ifdef PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE + {"FIPS_MODULE_ENTERING_ERROR_STATE", ERR_LIB_PROV, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE}, + #else + {"FIPS_MODULE_ENTERING_ERROR_STATE", 57, 224}, + #endif + #ifdef PROV_R_FIPS_MODULE_IN_ERROR_STATE + {"FIPS_MODULE_IN_ERROR_STATE", ERR_LIB_PROV, PROV_R_FIPS_MODULE_IN_ERROR_STATE}, + #else + {"FIPS_MODULE_IN_ERROR_STATE", 57, 225}, + #endif + #ifdef PROV_R_GENERATE_ERROR + {"GENERATE_ERROR", ERR_LIB_PROV, PROV_R_GENERATE_ERROR}, + #else + {"GENERATE_ERROR", 57, 191}, + #endif + #ifdef PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE + {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", ERR_LIB_PROV, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE}, + #else + {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", 57, 165}, + #endif + #ifdef PROV_R_INDICATOR_INTEGRITY_FAILURE + {"INDICATOR_INTEGRITY_FAILURE", ERR_LIB_PROV, PROV_R_INDICATOR_INTEGRITY_FAILURE}, + #else + {"INDICATOR_INTEGRITY_FAILURE", 57, 210}, + #endif + #ifdef PROV_R_INSUFFICIENT_DRBG_STRENGTH + {"INSUFFICIENT_DRBG_STRENGTH", ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH}, + #else + {"INSUFFICIENT_DRBG_STRENGTH", 57, 181}, + #endif + #ifdef PROV_R_INVALID_AAD + {"INVALID_AAD", ERR_LIB_PROV, PROV_R_INVALID_AAD}, + #else + {"INVALID_AAD", 57, 108}, + #endif + #ifdef PROV_R_INVALID_CONFIG_DATA + {"INVALID_CONFIG_DATA", ERR_LIB_PROV, PROV_R_INVALID_CONFIG_DATA}, + #else + {"INVALID_CONFIG_DATA", 57, 211}, + #endif + #ifdef PROV_R_INVALID_CONSTANT_LENGTH + {"INVALID_CONSTANT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_CONSTANT_LENGTH}, + #else + {"INVALID_CONSTANT_LENGTH", 57, 157}, + #endif + #ifdef PROV_R_INVALID_CURVE + {"INVALID_CURVE", ERR_LIB_PROV, PROV_R_INVALID_CURVE}, + #else + {"INVALID_CURVE", 57, 176}, + #endif + #ifdef PROV_R_INVALID_CUSTOM_LENGTH + {"INVALID_CUSTOM_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_CUSTOM_LENGTH}, + #else + {"INVALID_CUSTOM_LENGTH", 57, 111}, + #endif + #ifdef PROV_R_INVALID_DATA + {"INVALID_DATA", ERR_LIB_PROV, PROV_R_INVALID_DATA}, + #else + {"INVALID_DATA", 57, 115}, + #endif + #ifdef PROV_R_INVALID_DIGEST + {"INVALID_DIGEST", ERR_LIB_PROV, PROV_R_INVALID_DIGEST}, + #else + {"INVALID_DIGEST", 57, 122}, + #endif + #ifdef PROV_R_INVALID_DIGEST_LENGTH + {"INVALID_DIGEST_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH}, + #else + {"INVALID_DIGEST_LENGTH", 57, 166}, + #endif + #ifdef PROV_R_INVALID_DIGEST_SIZE + {"INVALID_DIGEST_SIZE", ERR_LIB_PROV, PROV_R_INVALID_DIGEST_SIZE}, + #else + {"INVALID_DIGEST_SIZE", 57, 218}, + #endif + #ifdef PROV_R_INVALID_INPUT_LENGTH + {"INVALID_INPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH}, + #else + {"INVALID_INPUT_LENGTH", 57, 230}, + #endif + #ifdef PROV_R_INVALID_ITERATION_COUNT + {"INVALID_ITERATION_COUNT", ERR_LIB_PROV, PROV_R_INVALID_ITERATION_COUNT}, + #else + {"INVALID_ITERATION_COUNT", 57, 123}, + #endif + #ifdef PROV_R_INVALID_IV_LENGTH + {"INVALID_IV_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH}, + #else + {"INVALID_IV_LENGTH", 57, 109}, + #endif + #ifdef PROV_R_INVALID_KEY + {"INVALID_KEY", ERR_LIB_PROV, PROV_R_INVALID_KEY}, + #else + {"INVALID_KEY", 57, 158}, + #endif + #ifdef PROV_R_INVALID_KEY_LENGTH + {"INVALID_KEY_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH}, + #else + {"INVALID_KEY_LENGTH", 57, 105}, + #endif + #ifdef PROV_R_INVALID_MAC + {"INVALID_MAC", ERR_LIB_PROV, PROV_R_INVALID_MAC}, + #else + {"INVALID_MAC", 57, 151}, + #endif + #ifdef PROV_R_INVALID_MGF1_MD + {"INVALID_MGF1_MD", ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD}, + #else + {"INVALID_MGF1_MD", 57, 167}, + #endif + #ifdef PROV_R_INVALID_MODE + {"INVALID_MODE", ERR_LIB_PROV, PROV_R_INVALID_MODE}, + #else + {"INVALID_MODE", 57, 125}, + #endif + #ifdef PROV_R_INVALID_OUTPUT_LENGTH + {"INVALID_OUTPUT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_OUTPUT_LENGTH}, + #else + {"INVALID_OUTPUT_LENGTH", 57, 217}, + #endif + #ifdef PROV_R_INVALID_PADDING_MODE + {"INVALID_PADDING_MODE", ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE}, + #else + {"INVALID_PADDING_MODE", 57, 168}, + #endif + #ifdef PROV_R_INVALID_PUBINFO + {"INVALID_PUBINFO", ERR_LIB_PROV, PROV_R_INVALID_PUBINFO}, + #else + {"INVALID_PUBINFO", 57, 198}, + #endif + #ifdef PROV_R_INVALID_SALT_LENGTH + {"INVALID_SALT_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH}, + #else + {"INVALID_SALT_LENGTH", 57, 112}, + #endif + #ifdef PROV_R_INVALID_SEED_LENGTH + {"INVALID_SEED_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH}, + #else + {"INVALID_SEED_LENGTH", 57, 154}, + #endif + #ifdef PROV_R_INVALID_SIGNATURE_SIZE + {"INVALID_SIGNATURE_SIZE", ERR_LIB_PROV, PROV_R_INVALID_SIGNATURE_SIZE}, + #else + {"INVALID_SIGNATURE_SIZE", 57, 179}, + #endif + #ifdef PROV_R_INVALID_STATE + {"INVALID_STATE", ERR_LIB_PROV, PROV_R_INVALID_STATE}, + #else + {"INVALID_STATE", 57, 212}, + #endif + #ifdef PROV_R_INVALID_TAG + {"INVALID_TAG", ERR_LIB_PROV, PROV_R_INVALID_TAG}, + #else + {"INVALID_TAG", 57, 110}, + #endif + #ifdef PROV_R_INVALID_TAG_LENGTH + {"INVALID_TAG_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_TAG_LENGTH}, + #else + {"INVALID_TAG_LENGTH", 57, 118}, + #endif + #ifdef PROV_R_INVALID_UKM_LENGTH + {"INVALID_UKM_LENGTH", ERR_LIB_PROV, PROV_R_INVALID_UKM_LENGTH}, + #else + {"INVALID_UKM_LENGTH", 57, 200}, + #endif + #ifdef PROV_R_INVALID_X931_DIGEST + {"INVALID_X931_DIGEST", ERR_LIB_PROV, PROV_R_INVALID_X931_DIGEST}, + #else + {"INVALID_X931_DIGEST", 57, 170}, + #endif + #ifdef PROV_R_IN_ERROR_STATE + {"IN_ERROR_STATE", ERR_LIB_PROV, PROV_R_IN_ERROR_STATE}, + #else + {"IN_ERROR_STATE", 57, 192}, + #endif + #ifdef PROV_R_KEY_SETUP_FAILED + {"KEY_SETUP_FAILED", ERR_LIB_PROV, PROV_R_KEY_SETUP_FAILED}, + #else + {"KEY_SETUP_FAILED", 57, 101}, + #endif + #ifdef PROV_R_KEY_SIZE_TOO_SMALL + {"KEY_SIZE_TOO_SMALL", ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL}, + #else + {"KEY_SIZE_TOO_SMALL", 57, 171}, + #endif + #ifdef PROV_R_LENGTH_TOO_LARGE + {"LENGTH_TOO_LARGE", ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE}, + #else + {"LENGTH_TOO_LARGE", 57, 202}, + #endif + #ifdef PROV_R_MISMATCHING_DOMAIN_PARAMETERS + {"MISMATCHING_DOMAIN_PARAMETERS", ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS}, + #else + {"MISMATCHING_DOMAIN_PARAMETERS", 57, 203}, + #endif + #ifdef PROV_R_MISSING_CEK_ALG + {"MISSING_CEK_ALG", ERR_LIB_PROV, PROV_R_MISSING_CEK_ALG}, + #else + {"MISSING_CEK_ALG", 57, 144}, + #endif + #ifdef PROV_R_MISSING_CIPHER + {"MISSING_CIPHER", ERR_LIB_PROV, PROV_R_MISSING_CIPHER}, + #else + {"MISSING_CIPHER", 57, 155}, + #endif + #ifdef PROV_R_MISSING_CONFIG_DATA + {"MISSING_CONFIG_DATA", ERR_LIB_PROV, PROV_R_MISSING_CONFIG_DATA}, + #else + {"MISSING_CONFIG_DATA", 57, 213}, + #endif + #ifdef PROV_R_MISSING_CONSTANT + {"MISSING_CONSTANT", ERR_LIB_PROV, PROV_R_MISSING_CONSTANT}, + #else + {"MISSING_CONSTANT", 57, 156}, + #endif + #ifdef PROV_R_MISSING_KEY + {"MISSING_KEY", ERR_LIB_PROV, PROV_R_MISSING_KEY}, + #else + {"MISSING_KEY", 57, 128}, + #endif + #ifdef PROV_R_MISSING_MAC + {"MISSING_MAC", ERR_LIB_PROV, PROV_R_MISSING_MAC}, + #else + {"MISSING_MAC", 57, 150}, + #endif + #ifdef PROV_R_MISSING_MESSAGE_DIGEST + {"MISSING_MESSAGE_DIGEST", ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST}, + #else + {"MISSING_MESSAGE_DIGEST", 57, 129}, + #endif + #ifdef PROV_R_MISSING_OID + {"MISSING_OID", ERR_LIB_PROV, PROV_R_MISSING_OID}, + #else + {"MISSING_OID", 57, 209}, + #endif + #ifdef PROV_R_MISSING_PASS + {"MISSING_PASS", ERR_LIB_PROV, PROV_R_MISSING_PASS}, + #else + {"MISSING_PASS", 57, 130}, + #endif + #ifdef PROV_R_MISSING_SALT + {"MISSING_SALT", ERR_LIB_PROV, PROV_R_MISSING_SALT}, + #else + {"MISSING_SALT", 57, 131}, + #endif + #ifdef PROV_R_MISSING_SECRET + {"MISSING_SECRET", ERR_LIB_PROV, PROV_R_MISSING_SECRET}, + #else + {"MISSING_SECRET", 57, 132}, + #endif + #ifdef PROV_R_MISSING_SEED + {"MISSING_SEED", ERR_LIB_PROV, PROV_R_MISSING_SEED}, + #else + {"MISSING_SEED", 57, 140}, + #endif + #ifdef PROV_R_MISSING_SESSION_ID + {"MISSING_SESSION_ID", ERR_LIB_PROV, PROV_R_MISSING_SESSION_ID}, + #else + {"MISSING_SESSION_ID", 57, 133}, + #endif + #ifdef PROV_R_MISSING_TYPE + {"MISSING_TYPE", ERR_LIB_PROV, PROV_R_MISSING_TYPE}, + #else + {"MISSING_TYPE", 57, 134}, + #endif + #ifdef PROV_R_MISSING_XCGHASH + {"MISSING_XCGHASH", ERR_LIB_PROV, PROV_R_MISSING_XCGHASH}, + #else + {"MISSING_XCGHASH", 57, 135}, + #endif + #ifdef PROV_R_MODULE_INTEGRITY_FAILURE + {"MODULE_INTEGRITY_FAILURE", ERR_LIB_PROV, PROV_R_MODULE_INTEGRITY_FAILURE}, + #else + {"MODULE_INTEGRITY_FAILURE", 57, 214}, + #endif + #ifdef PROV_R_NOT_A_PRIVATE_KEY + {"NOT_A_PRIVATE_KEY", ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY}, + #else + {"NOT_A_PRIVATE_KEY", 57, 221}, + #endif + #ifdef PROV_R_NOT_A_PUBLIC_KEY + {"NOT_A_PUBLIC_KEY", ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY}, + #else + {"NOT_A_PUBLIC_KEY", 57, 220}, + #endif + #ifdef PROV_R_NOT_INSTANTIATED + {"NOT_INSTANTIATED", ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED}, + #else + {"NOT_INSTANTIATED", 57, 193}, + #endif + #ifdef PROV_R_NOT_PARAMETERS + {"NOT_PARAMETERS", ERR_LIB_PROV, PROV_R_NOT_PARAMETERS}, + #else + {"NOT_PARAMETERS", 57, 226}, + #endif + #ifdef PROV_R_NOT_SUPPORTED + {"NOT_SUPPORTED", ERR_LIB_PROV, PROV_R_NOT_SUPPORTED}, + #else + {"NOT_SUPPORTED", 57, 136}, + #endif + #ifdef PROV_R_NOT_XOF_OR_INVALID_LENGTH + {"NOT_XOF_OR_INVALID_LENGTH", ERR_LIB_PROV, PROV_R_NOT_XOF_OR_INVALID_LENGTH}, + #else + {"NOT_XOF_OR_INVALID_LENGTH", 57, 113}, + #endif + #ifdef PROV_R_NO_KEY_SET + {"NO_KEY_SET", ERR_LIB_PROV, PROV_R_NO_KEY_SET}, + #else + {"NO_KEY_SET", 57, 114}, + #endif + #ifdef PROV_R_NO_PARAMETERS_SET + {"NO_PARAMETERS_SET", ERR_LIB_PROV, PROV_R_NO_PARAMETERS_SET}, + #else + {"NO_PARAMETERS_SET", 57, 177}, + #endif + #ifdef PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE + {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_PROV, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, + #else + {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 57, 178}, + #endif + #ifdef PROV_R_OUTPUT_BUFFER_TOO_SMALL + {"OUTPUT_BUFFER_TOO_SMALL", ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL}, + #else + {"OUTPUT_BUFFER_TOO_SMALL", 57, 106}, + #endif + #ifdef PROV_R_PARENT_CANNOT_GENERATE_RANDOM_NUMBERS + {"PARENT_CANNOT_GENERATE_RANDOM_NUMBERS", ERR_LIB_PROV, PROV_R_PARENT_CANNOT_GENERATE_RANDOM_NUMBERS}, + #else + {"PARENT_CANNOT_GENERATE_RANDOM_NUMBERS", 57, 228}, + #endif + #ifdef PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED + {"PARENT_CANNOT_SUPPLY_ENTROPY_SEED", ERR_LIB_PROV, PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED}, + #else + {"PARENT_CANNOT_SUPPLY_ENTROPY_SEED", 57, 187}, + #endif + #ifdef PROV_R_PARENT_LOCKING_NOT_ENABLED + {"PARENT_LOCKING_NOT_ENABLED", ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED}, + #else + {"PARENT_LOCKING_NOT_ENABLED", 57, 182}, + #endif + #ifdef PROV_R_PARENT_STRENGTH_TOO_WEAK + {"PARENT_STRENGTH_TOO_WEAK", ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK}, + #else + {"PARENT_STRENGTH_TOO_WEAK", 57, 194}, + #endif + #ifdef PROV_R_PATH_MUST_BE_ABSOLUTE + {"PATH_MUST_BE_ABSOLUTE", ERR_LIB_PROV, PROV_R_PATH_MUST_BE_ABSOLUTE}, + #else + {"PATH_MUST_BE_ABSOLUTE", 57, 219}, + #endif + #ifdef PROV_R_PERSONALISATION_STRING_TOO_LONG + {"PERSONALISATION_STRING_TOO_LONG", ERR_LIB_PROV, PROV_R_PERSONALISATION_STRING_TOO_LONG}, + #else + {"PERSONALISATION_STRING_TOO_LONG", 57, 195}, + #endif + #ifdef PROV_R_PSS_SALTLEN_TOO_SMALL + {"PSS_SALTLEN_TOO_SMALL", ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL}, + #else + {"PSS_SALTLEN_TOO_SMALL", 57, 172}, + #endif + #ifdef PROV_R_REQUEST_TOO_LARGE_FOR_DRBG + {"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG}, + #else + {"REQUEST_TOO_LARGE_FOR_DRBG", 57, 196}, + #endif + #ifdef PROV_R_REQUIRE_CTR_MODE_CIPHER + {"REQUIRE_CTR_MODE_CIPHER", ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER}, + #else + {"REQUIRE_CTR_MODE_CIPHER", 57, 206}, + #endif + #ifdef PROV_R_RESEED_ERROR + {"RESEED_ERROR", ERR_LIB_PROV, PROV_R_RESEED_ERROR}, + #else + {"RESEED_ERROR", 57, 197}, + #endif + #ifdef PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES + {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", ERR_LIB_PROV, PROV_R_SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES}, + #else + {"SEARCH_ONLY_SUPPORTED_FOR_DIRECTORIES", 57, 222}, + #endif + #ifdef PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT + {"SEED_SOURCES_MUST_NOT_HAVE_A_PARENT", ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT}, + #else + {"SEED_SOURCES_MUST_NOT_HAVE_A_PARENT", 57, 229}, + #endif + #ifdef PROV_R_SELF_TEST_KAT_FAILURE + {"SELF_TEST_KAT_FAILURE", ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE}, + #else + {"SELF_TEST_KAT_FAILURE", 57, 215}, + #endif + #ifdef PROV_R_SELF_TEST_POST_FAILURE + {"SELF_TEST_POST_FAILURE", ERR_LIB_PROV, PROV_R_SELF_TEST_POST_FAILURE}, + #else + {"SELF_TEST_POST_FAILURE", 57, 216}, + #endif + #ifdef PROV_R_TAG_NOT_NEEDED + {"TAG_NOT_NEEDED", ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED}, + #else + {"TAG_NOT_NEEDED", 57, 120}, + #endif + #ifdef PROV_R_TAG_NOT_SET + {"TAG_NOT_SET", ERR_LIB_PROV, PROV_R_TAG_NOT_SET}, + #else + {"TAG_NOT_SET", 57, 119}, + #endif + #ifdef PROV_R_TOO_MANY_RECORDS + {"TOO_MANY_RECORDS", ERR_LIB_PROV, PROV_R_TOO_MANY_RECORDS}, + #else + {"TOO_MANY_RECORDS", 57, 126}, + #endif + #ifdef PROV_R_UNABLE_TO_FIND_CIPHERS + {"UNABLE_TO_FIND_CIPHERS", ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS}, + #else + {"UNABLE_TO_FIND_CIPHERS", 57, 207}, + #endif + #ifdef PROV_R_UNABLE_TO_GET_PARENT_STRENGTH + {"UNABLE_TO_GET_PARENT_STRENGTH", ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH}, + #else + {"UNABLE_TO_GET_PARENT_STRENGTH", 57, 199}, + #endif + #ifdef PROV_R_UNABLE_TO_GET_PASSPHRASE + {"UNABLE_TO_GET_PASSPHRASE", ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PASSPHRASE}, + #else + {"UNABLE_TO_GET_PASSPHRASE", 57, 159}, + #endif + #ifdef PROV_R_UNABLE_TO_INITIALISE_CIPHERS + {"UNABLE_TO_INITIALISE_CIPHERS", ERR_LIB_PROV, PROV_R_UNABLE_TO_INITIALISE_CIPHERS}, + #else + {"UNABLE_TO_INITIALISE_CIPHERS", 57, 208}, + #endif + #ifdef PROV_R_UNABLE_TO_LOAD_SHA256 + {"UNABLE_TO_LOAD_SHA256", ERR_LIB_PROV, PROV_R_UNABLE_TO_LOAD_SHA256}, + #else + {"UNABLE_TO_LOAD_SHA256", 57, 147}, + #endif + #ifdef PROV_R_UNABLE_TO_LOCK_PARENT + {"UNABLE_TO_LOCK_PARENT", ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT}, + #else + {"UNABLE_TO_LOCK_PARENT", 57, 201}, + #endif + #ifdef PROV_R_UNABLE_TO_RESEED + {"UNABLE_TO_RESEED", ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED}, + #else + {"UNABLE_TO_RESEED", 57, 204}, + #endif + #ifdef PROV_R_UNSUPPORTED_CEK_ALG + {"UNSUPPORTED_CEK_ALG", ERR_LIB_PROV, PROV_R_UNSUPPORTED_CEK_ALG}, + #else + {"UNSUPPORTED_CEK_ALG", 57, 145}, + #endif + #ifdef PROV_R_UNSUPPORTED_KEY_SIZE + {"UNSUPPORTED_KEY_SIZE", ERR_LIB_PROV, PROV_R_UNSUPPORTED_KEY_SIZE}, + #else + {"UNSUPPORTED_KEY_SIZE", 57, 153}, + #endif + #ifdef PROV_R_UNSUPPORTED_MAC_TYPE + {"UNSUPPORTED_MAC_TYPE", ERR_LIB_PROV, PROV_R_UNSUPPORTED_MAC_TYPE}, + #else + {"UNSUPPORTED_MAC_TYPE", 57, 137}, + #endif + #ifdef PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS + {"UNSUPPORTED_NUMBER_OF_ROUNDS", ERR_LIB_PROV, PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS}, + #else + {"UNSUPPORTED_NUMBER_OF_ROUNDS", 57, 152}, + #endif + #ifdef PROV_R_URI_AUTHORITY_UNSUPPORTED + {"URI_AUTHORITY_UNSUPPORTED", ERR_LIB_PROV, PROV_R_URI_AUTHORITY_UNSUPPORTED}, + #else + {"URI_AUTHORITY_UNSUPPORTED", 57, 223}, + #endif + #ifdef PROV_R_VALUE_ERROR + {"VALUE_ERROR", ERR_LIB_PROV, PROV_R_VALUE_ERROR}, + #else + {"VALUE_ERROR", 57, 138}, + #endif + #ifdef PROV_R_WRONG_FINAL_BLOCK_LENGTH + {"WRONG_FINAL_BLOCK_LENGTH", ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH}, + #else + {"WRONG_FINAL_BLOCK_LENGTH", 57, 107}, + #endif + #ifdef PROV_R_WRONG_OUTPUT_BUFFER_SIZE + {"WRONG_OUTPUT_BUFFER_SIZE", ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE}, + #else + {"WRONG_OUTPUT_BUFFER_SIZE", 57, 139}, + #endif + #ifdef PROV_R_XOF_DIGESTS_NOT_ALLOWED + {"XOF_DIGESTS_NOT_ALLOWED", ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED}, + #else + {"XOF_DIGESTS_NOT_ALLOWED", 57, 183}, + #endif + #ifdef PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE + {"XTS_DATA_UNIT_IS_TOO_LARGE", ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE}, + #else + {"XTS_DATA_UNIT_IS_TOO_LARGE", 57, 148}, + #endif + #ifdef PROV_R_XTS_DUPLICATED_KEYS + {"XTS_DUPLICATED_KEYS", ERR_LIB_PROV, PROV_R_XTS_DUPLICATED_KEYS}, + #else + {"XTS_DUPLICATED_KEYS", 57, 149}, + #endif + #ifdef RAND_R_ADDITIONAL_INPUT_TOO_LONG + {"ADDITIONAL_INPUT_TOO_LONG", ERR_LIB_RAND, RAND_R_ADDITIONAL_INPUT_TOO_LONG}, + #else + {"ADDITIONAL_INPUT_TOO_LONG", 36, 102}, + #endif + #ifdef RAND_R_ALREADY_INSTANTIATED + {"ALREADY_INSTANTIATED", ERR_LIB_RAND, RAND_R_ALREADY_INSTANTIATED}, + #else + {"ALREADY_INSTANTIATED", 36, 103}, + #endif + #ifdef RAND_R_ARGUMENT_OUT_OF_RANGE + {"ARGUMENT_OUT_OF_RANGE", ERR_LIB_RAND, RAND_R_ARGUMENT_OUT_OF_RANGE}, + #else + {"ARGUMENT_OUT_OF_RANGE", 36, 105}, + #endif + #ifdef RAND_R_CANNOT_OPEN_FILE + {"CANNOT_OPEN_FILE", ERR_LIB_RAND, RAND_R_CANNOT_OPEN_FILE}, + #else + {"CANNOT_OPEN_FILE", 36, 121}, + #endif + #ifdef RAND_R_DRBG_ALREADY_INITIALIZED + {"DRBG_ALREADY_INITIALIZED", ERR_LIB_RAND, RAND_R_DRBG_ALREADY_INITIALIZED}, + #else + {"DRBG_ALREADY_INITIALIZED", 36, 129}, + #endif + #ifdef RAND_R_DRBG_NOT_INITIALISED + {"DRBG_NOT_INITIALISED", ERR_LIB_RAND, RAND_R_DRBG_NOT_INITIALISED}, + #else + {"DRBG_NOT_INITIALISED", 36, 104}, + #endif + #ifdef RAND_R_ENTROPY_INPUT_TOO_LONG + {"ENTROPY_INPUT_TOO_LONG", ERR_LIB_RAND, RAND_R_ENTROPY_INPUT_TOO_LONG}, + #else + {"ENTROPY_INPUT_TOO_LONG", 36, 106}, + #endif + #ifdef RAND_R_ENTROPY_OUT_OF_RANGE + {"ENTROPY_OUT_OF_RANGE", ERR_LIB_RAND, RAND_R_ENTROPY_OUT_OF_RANGE}, + #else + {"ENTROPY_OUT_OF_RANGE", 36, 124}, + #endif + #ifdef RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED + {"ERROR_ENTROPY_POOL_WAS_IGNORED", ERR_LIB_RAND, RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED}, + #else + {"ERROR_ENTROPY_POOL_WAS_IGNORED", 36, 127}, + #endif + #ifdef RAND_R_ERROR_INITIALISING_DRBG + {"ERROR_INITIALISING_DRBG", ERR_LIB_RAND, RAND_R_ERROR_INITIALISING_DRBG}, + #else + {"ERROR_INITIALISING_DRBG", 36, 107}, + #endif + #ifdef RAND_R_ERROR_INSTANTIATING_DRBG + {"ERROR_INSTANTIATING_DRBG", ERR_LIB_RAND, RAND_R_ERROR_INSTANTIATING_DRBG}, + #else + {"ERROR_INSTANTIATING_DRBG", 36, 108}, + #endif + #ifdef RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT + {"ERROR_RETRIEVING_ADDITIONAL_INPUT", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_ADDITIONAL_INPUT}, + #else + {"ERROR_RETRIEVING_ADDITIONAL_INPUT", 36, 109}, + #endif + #ifdef RAND_R_ERROR_RETRIEVING_ENTROPY + {"ERROR_RETRIEVING_ENTROPY", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_ENTROPY}, + #else + {"ERROR_RETRIEVING_ENTROPY", 36, 110}, + #endif + #ifdef RAND_R_ERROR_RETRIEVING_NONCE + {"ERROR_RETRIEVING_NONCE", ERR_LIB_RAND, RAND_R_ERROR_RETRIEVING_NONCE}, + #else + {"ERROR_RETRIEVING_NONCE", 36, 111}, + #endif + #ifdef RAND_R_FAILED_TO_CREATE_LOCK + {"FAILED_TO_CREATE_LOCK", ERR_LIB_RAND, RAND_R_FAILED_TO_CREATE_LOCK}, + #else + {"FAILED_TO_CREATE_LOCK", 36, 126}, + #endif + #ifdef RAND_R_FUNC_NOT_IMPLEMENTED + {"FUNC_NOT_IMPLEMENTED", ERR_LIB_RAND, RAND_R_FUNC_NOT_IMPLEMENTED}, + #else + {"FUNC_NOT_IMPLEMENTED", 36, 101}, + #endif + #ifdef RAND_R_FWRITE_ERROR + {"FWRITE_ERROR", ERR_LIB_RAND, RAND_R_FWRITE_ERROR}, + #else + {"FWRITE_ERROR", 36, 123}, + #endif + #ifdef RAND_R_GENERATE_ERROR + {"GENERATE_ERROR", ERR_LIB_RAND, RAND_R_GENERATE_ERROR}, + #else + {"GENERATE_ERROR", 36, 112}, + #endif + #ifdef RAND_R_INSUFFICIENT_DRBG_STRENGTH + {"INSUFFICIENT_DRBG_STRENGTH", ERR_LIB_RAND, RAND_R_INSUFFICIENT_DRBG_STRENGTH}, + #else + {"INSUFFICIENT_DRBG_STRENGTH", 36, 139}, + #endif + #ifdef RAND_R_INTERNAL_ERROR + {"INTERNAL_ERROR", ERR_LIB_RAND, RAND_R_INTERNAL_ERROR}, + #else + {"INTERNAL_ERROR", 36, 113}, + #endif + #ifdef RAND_R_IN_ERROR_STATE + {"IN_ERROR_STATE", ERR_LIB_RAND, RAND_R_IN_ERROR_STATE}, + #else + {"IN_ERROR_STATE", 36, 114}, + #endif + #ifdef RAND_R_NOT_A_REGULAR_FILE + {"NOT_A_REGULAR_FILE", ERR_LIB_RAND, RAND_R_NOT_A_REGULAR_FILE}, + #else + {"NOT_A_REGULAR_FILE", 36, 122}, + #endif + #ifdef RAND_R_NOT_INSTANTIATED + {"NOT_INSTANTIATED", ERR_LIB_RAND, RAND_R_NOT_INSTANTIATED}, + #else + {"NOT_INSTANTIATED", 36, 115}, + #endif + #ifdef RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED + {"NO_DRBG_IMPLEMENTATION_SELECTED", ERR_LIB_RAND, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED}, + #else + {"NO_DRBG_IMPLEMENTATION_SELECTED", 36, 128}, + #endif + #ifdef RAND_R_PARENT_LOCKING_NOT_ENABLED + {"PARENT_LOCKING_NOT_ENABLED", ERR_LIB_RAND, RAND_R_PARENT_LOCKING_NOT_ENABLED}, + #else + {"PARENT_LOCKING_NOT_ENABLED", 36, 130}, + #endif + #ifdef RAND_R_PARENT_STRENGTH_TOO_WEAK + {"PARENT_STRENGTH_TOO_WEAK", ERR_LIB_RAND, RAND_R_PARENT_STRENGTH_TOO_WEAK}, + #else + {"PARENT_STRENGTH_TOO_WEAK", 36, 131}, + #endif + #ifdef RAND_R_PERSONALISATION_STRING_TOO_LONG + {"PERSONALISATION_STRING_TOO_LONG", ERR_LIB_RAND, RAND_R_PERSONALISATION_STRING_TOO_LONG}, + #else + {"PERSONALISATION_STRING_TOO_LONG", 36, 116}, + #endif + #ifdef RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED + {"PREDICTION_RESISTANCE_NOT_SUPPORTED", ERR_LIB_RAND, RAND_R_PREDICTION_RESISTANCE_NOT_SUPPORTED}, + #else + {"PREDICTION_RESISTANCE_NOT_SUPPORTED", 36, 133}, + #endif + #ifdef RAND_R_PRNG_NOT_SEEDED + {"PRNG_NOT_SEEDED", ERR_LIB_RAND, RAND_R_PRNG_NOT_SEEDED}, + #else + {"PRNG_NOT_SEEDED", 36, 100}, + #endif + #ifdef RAND_R_RANDOM_POOL_OVERFLOW + {"RANDOM_POOL_OVERFLOW", ERR_LIB_RAND, RAND_R_RANDOM_POOL_OVERFLOW}, + #else + {"RANDOM_POOL_OVERFLOW", 36, 125}, + #endif + #ifdef RAND_R_RANDOM_POOL_UNDERFLOW + {"RANDOM_POOL_UNDERFLOW", ERR_LIB_RAND, RAND_R_RANDOM_POOL_UNDERFLOW}, + #else + {"RANDOM_POOL_UNDERFLOW", 36, 134}, + #endif + #ifdef RAND_R_REQUEST_TOO_LARGE_FOR_DRBG + {"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_RAND, RAND_R_REQUEST_TOO_LARGE_FOR_DRBG}, + #else + {"REQUEST_TOO_LARGE_FOR_DRBG", 36, 117}, + #endif + #ifdef RAND_R_RESEED_ERROR + {"RESEED_ERROR", ERR_LIB_RAND, RAND_R_RESEED_ERROR}, + #else + {"RESEED_ERROR", 36, 118}, + #endif + #ifdef RAND_R_SELFTEST_FAILURE + {"SELFTEST_FAILURE", ERR_LIB_RAND, RAND_R_SELFTEST_FAILURE}, + #else + {"SELFTEST_FAILURE", 36, 119}, + #endif + #ifdef RAND_R_TOO_LITTLE_NONCE_REQUESTED + {"TOO_LITTLE_NONCE_REQUESTED", ERR_LIB_RAND, RAND_R_TOO_LITTLE_NONCE_REQUESTED}, + #else + {"TOO_LITTLE_NONCE_REQUESTED", 36, 135}, + #endif + #ifdef RAND_R_TOO_MUCH_NONCE_REQUESTED + {"TOO_MUCH_NONCE_REQUESTED", ERR_LIB_RAND, RAND_R_TOO_MUCH_NONCE_REQUESTED}, + #else + {"TOO_MUCH_NONCE_REQUESTED", 36, 136}, + #endif + #ifdef RAND_R_UNABLE_TO_CREATE_DRBG + {"UNABLE_TO_CREATE_DRBG", ERR_LIB_RAND, RAND_R_UNABLE_TO_CREATE_DRBG}, + #else + {"UNABLE_TO_CREATE_DRBG", 36, 143}, + #endif + #ifdef RAND_R_UNABLE_TO_FETCH_DRBG + {"UNABLE_TO_FETCH_DRBG", ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG}, + #else + {"UNABLE_TO_FETCH_DRBG", 36, 144}, + #endif + #ifdef RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER + {"UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER", ERR_LIB_RAND, RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER}, + #else + {"UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER", 36, 141}, + #endif + #ifdef RAND_R_UNABLE_TO_GET_PARENT_STRENGTH + {"UNABLE_TO_GET_PARENT_STRENGTH", ERR_LIB_RAND, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH}, + #else + {"UNABLE_TO_GET_PARENT_STRENGTH", 36, 138}, + #endif + #ifdef RAND_R_UNABLE_TO_LOCK_PARENT + {"UNABLE_TO_LOCK_PARENT", ERR_LIB_RAND, RAND_R_UNABLE_TO_LOCK_PARENT}, + #else + {"UNABLE_TO_LOCK_PARENT", 36, 140}, + #endif + #ifdef RAND_R_UNSUPPORTED_DRBG_FLAGS + {"UNSUPPORTED_DRBG_FLAGS", ERR_LIB_RAND, RAND_R_UNSUPPORTED_DRBG_FLAGS}, + #else + {"UNSUPPORTED_DRBG_FLAGS", 36, 132}, + #endif + #ifdef RAND_R_UNSUPPORTED_DRBG_TYPE + {"UNSUPPORTED_DRBG_TYPE", ERR_LIB_RAND, RAND_R_UNSUPPORTED_DRBG_TYPE}, + #else + {"UNSUPPORTED_DRBG_TYPE", 36, 120}, + #endif + #ifdef RSA_R_ALGORITHM_MISMATCH + {"ALGORITHM_MISMATCH", ERR_LIB_RSA, RSA_R_ALGORITHM_MISMATCH}, + #else + {"ALGORITHM_MISMATCH", 4, 100}, + #endif + #ifdef RSA_R_BAD_E_VALUE + {"BAD_E_VALUE", ERR_LIB_RSA, RSA_R_BAD_E_VALUE}, + #else + {"BAD_E_VALUE", 4, 101}, + #endif + #ifdef RSA_R_BAD_FIXED_HEADER_DECRYPT + {"BAD_FIXED_HEADER_DECRYPT", ERR_LIB_RSA, RSA_R_BAD_FIXED_HEADER_DECRYPT}, + #else + {"BAD_FIXED_HEADER_DECRYPT", 4, 102}, + #endif + #ifdef RSA_R_BAD_PAD_BYTE_COUNT + {"BAD_PAD_BYTE_COUNT", ERR_LIB_RSA, RSA_R_BAD_PAD_BYTE_COUNT}, + #else + {"BAD_PAD_BYTE_COUNT", 4, 103}, + #endif + #ifdef RSA_R_BAD_SIGNATURE + {"BAD_SIGNATURE", ERR_LIB_RSA, RSA_R_BAD_SIGNATURE}, + #else + {"BAD_SIGNATURE", 4, 104}, + #endif + #ifdef RSA_R_BLOCK_TYPE_IS_NOT_01 + {"BLOCK_TYPE_IS_NOT_01", ERR_LIB_RSA, RSA_R_BLOCK_TYPE_IS_NOT_01}, + #else + {"BLOCK_TYPE_IS_NOT_01", 4, 106}, + #endif + #ifdef RSA_R_BLOCK_TYPE_IS_NOT_02 + {"BLOCK_TYPE_IS_NOT_02", ERR_LIB_RSA, RSA_R_BLOCK_TYPE_IS_NOT_02}, + #else + {"BLOCK_TYPE_IS_NOT_02", 4, 107}, + #endif + #ifdef RSA_R_DATA_GREATER_THAN_MOD_LEN + {"DATA_GREATER_THAN_MOD_LEN", ERR_LIB_RSA, RSA_R_DATA_GREATER_THAN_MOD_LEN}, + #else + {"DATA_GREATER_THAN_MOD_LEN", 4, 108}, + #endif + #ifdef RSA_R_DATA_TOO_LARGE + {"DATA_TOO_LARGE", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE}, + #else + {"DATA_TOO_LARGE", 4, 109}, + #endif + #ifdef RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE + {"DATA_TOO_LARGE_FOR_KEY_SIZE", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE}, + #else + {"DATA_TOO_LARGE_FOR_KEY_SIZE", 4, 110}, + #endif + #ifdef RSA_R_DATA_TOO_LARGE_FOR_MODULUS + {"DATA_TOO_LARGE_FOR_MODULUS", ERR_LIB_RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS}, + #else + {"DATA_TOO_LARGE_FOR_MODULUS", 4, 132}, + #endif + #ifdef RSA_R_DATA_TOO_SMALL + {"DATA_TOO_SMALL", ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL}, + #else + {"DATA_TOO_SMALL", 4, 111}, + #endif + #ifdef RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE + {"DATA_TOO_SMALL_FOR_KEY_SIZE", ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE}, + #else + {"DATA_TOO_SMALL_FOR_KEY_SIZE", 4, 122}, + #endif + #ifdef RSA_R_DIGEST_DOES_NOT_MATCH + {"DIGEST_DOES_NOT_MATCH", ERR_LIB_RSA, RSA_R_DIGEST_DOES_NOT_MATCH}, + #else + {"DIGEST_DOES_NOT_MATCH", 4, 158}, + #endif + #ifdef RSA_R_DIGEST_NOT_ALLOWED + {"DIGEST_NOT_ALLOWED", ERR_LIB_RSA, RSA_R_DIGEST_NOT_ALLOWED}, + #else + {"DIGEST_NOT_ALLOWED", 4, 145}, + #endif + #ifdef RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY + {"DIGEST_TOO_BIG_FOR_RSA_KEY", ERR_LIB_RSA, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY}, + #else + {"DIGEST_TOO_BIG_FOR_RSA_KEY", 4, 112}, + #endif + #ifdef RSA_R_DMP1_NOT_CONGRUENT_TO_D + {"DMP1_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_DMP1_NOT_CONGRUENT_TO_D}, + #else + {"DMP1_NOT_CONGRUENT_TO_D", 4, 124}, + #endif + #ifdef RSA_R_DMQ1_NOT_CONGRUENT_TO_D + {"DMQ1_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_DMQ1_NOT_CONGRUENT_TO_D}, + #else + {"DMQ1_NOT_CONGRUENT_TO_D", 4, 125}, + #endif + #ifdef RSA_R_D_E_NOT_CONGRUENT_TO_1 + {"D_E_NOT_CONGRUENT_TO_1", ERR_LIB_RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1}, + #else + {"D_E_NOT_CONGRUENT_TO_1", 4, 123}, + #endif + #ifdef RSA_R_FIRST_OCTET_INVALID + {"FIRST_OCTET_INVALID", ERR_LIB_RSA, RSA_R_FIRST_OCTET_INVALID}, + #else + {"FIRST_OCTET_INVALID", 4, 133}, + #endif + #ifdef RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE + {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", ERR_LIB_RSA, RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE}, + #else + {"ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", 4, 144}, + #endif + #ifdef RSA_R_INVALID_DIGEST + {"INVALID_DIGEST", ERR_LIB_RSA, RSA_R_INVALID_DIGEST}, + #else + {"INVALID_DIGEST", 4, 157}, + #endif + #ifdef RSA_R_INVALID_DIGEST_LENGTH + {"INVALID_DIGEST_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_DIGEST_LENGTH}, + #else + {"INVALID_DIGEST_LENGTH", 4, 143}, + #endif + #ifdef RSA_R_INVALID_HEADER + {"INVALID_HEADER", ERR_LIB_RSA, RSA_R_INVALID_HEADER}, + #else + {"INVALID_HEADER", 4, 137}, + #endif + #ifdef RSA_R_INVALID_KEYPAIR + {"INVALID_KEYPAIR", ERR_LIB_RSA, RSA_R_INVALID_KEYPAIR}, + #else + {"INVALID_KEYPAIR", 4, 171}, + #endif + #ifdef RSA_R_INVALID_KEY_LENGTH + {"INVALID_KEY_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_KEY_LENGTH}, + #else + {"INVALID_KEY_LENGTH", 4, 173}, + #endif + #ifdef RSA_R_INVALID_LABEL + {"INVALID_LABEL", ERR_LIB_RSA, RSA_R_INVALID_LABEL}, + #else + {"INVALID_LABEL", 4, 160}, + #endif + #ifdef RSA_R_INVALID_LENGTH + {"INVALID_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_LENGTH}, + #else + {"INVALID_LENGTH", 4, 181}, + #endif + #ifdef RSA_R_INVALID_MESSAGE_LENGTH + {"INVALID_MESSAGE_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_MESSAGE_LENGTH}, + #else + {"INVALID_MESSAGE_LENGTH", 4, 131}, + #endif + #ifdef RSA_R_INVALID_MGF1_MD + {"INVALID_MGF1_MD", ERR_LIB_RSA, RSA_R_INVALID_MGF1_MD}, + #else + {"INVALID_MGF1_MD", 4, 156}, + #endif + #ifdef RSA_R_INVALID_MODULUS + {"INVALID_MODULUS", ERR_LIB_RSA, RSA_R_INVALID_MODULUS}, + #else + {"INVALID_MODULUS", 4, 174}, + #endif + #ifdef RSA_R_INVALID_MULTI_PRIME_KEY + {"INVALID_MULTI_PRIME_KEY", ERR_LIB_RSA, RSA_R_INVALID_MULTI_PRIME_KEY}, + #else + {"INVALID_MULTI_PRIME_KEY", 4, 167}, + #endif + #ifdef RSA_R_INVALID_OAEP_PARAMETERS + {"INVALID_OAEP_PARAMETERS", ERR_LIB_RSA, RSA_R_INVALID_OAEP_PARAMETERS}, + #else + {"INVALID_OAEP_PARAMETERS", 4, 161}, + #endif + #ifdef RSA_R_INVALID_PADDING + {"INVALID_PADDING", ERR_LIB_RSA, RSA_R_INVALID_PADDING}, + #else + {"INVALID_PADDING", 4, 138}, + #endif + #ifdef RSA_R_INVALID_PADDING_MODE + {"INVALID_PADDING_MODE", ERR_LIB_RSA, RSA_R_INVALID_PADDING_MODE}, + #else + {"INVALID_PADDING_MODE", 4, 141}, + #endif + #ifdef RSA_R_INVALID_PSS_PARAMETERS + {"INVALID_PSS_PARAMETERS", ERR_LIB_RSA, RSA_R_INVALID_PSS_PARAMETERS}, + #else + {"INVALID_PSS_PARAMETERS", 4, 149}, + #endif + #ifdef RSA_R_INVALID_PSS_SALTLEN + {"INVALID_PSS_SALTLEN", ERR_LIB_RSA, RSA_R_INVALID_PSS_SALTLEN}, + #else + {"INVALID_PSS_SALTLEN", 4, 146}, + #endif + #ifdef RSA_R_INVALID_REQUEST + {"INVALID_REQUEST", ERR_LIB_RSA, RSA_R_INVALID_REQUEST}, + #else + {"INVALID_REQUEST", 4, 175}, + #endif + #ifdef RSA_R_INVALID_SALT_LENGTH + {"INVALID_SALT_LENGTH", ERR_LIB_RSA, RSA_R_INVALID_SALT_LENGTH}, + #else + {"INVALID_SALT_LENGTH", 4, 150}, + #endif + #ifdef RSA_R_INVALID_STRENGTH + {"INVALID_STRENGTH", ERR_LIB_RSA, RSA_R_INVALID_STRENGTH}, + #else + {"INVALID_STRENGTH", 4, 176}, + #endif + #ifdef RSA_R_INVALID_TRAILER + {"INVALID_TRAILER", ERR_LIB_RSA, RSA_R_INVALID_TRAILER}, + #else + {"INVALID_TRAILER", 4, 139}, + #endif + #ifdef RSA_R_INVALID_X931_DIGEST + {"INVALID_X931_DIGEST", ERR_LIB_RSA, RSA_R_INVALID_X931_DIGEST}, + #else + {"INVALID_X931_DIGEST", 4, 142}, + #endif + #ifdef RSA_R_IQMP_NOT_INVERSE_OF_Q + {"IQMP_NOT_INVERSE_OF_Q", ERR_LIB_RSA, RSA_R_IQMP_NOT_INVERSE_OF_Q}, + #else + {"IQMP_NOT_INVERSE_OF_Q", 4, 126}, + #endif + #ifdef RSA_R_KEY_PRIME_NUM_INVALID + {"KEY_PRIME_NUM_INVALID", ERR_LIB_RSA, RSA_R_KEY_PRIME_NUM_INVALID}, + #else + {"KEY_PRIME_NUM_INVALID", 4, 165}, + #endif + #ifdef RSA_R_KEY_SIZE_TOO_SMALL + {"KEY_SIZE_TOO_SMALL", ERR_LIB_RSA, RSA_R_KEY_SIZE_TOO_SMALL}, + #else + {"KEY_SIZE_TOO_SMALL", 4, 120}, + #endif + #ifdef RSA_R_LAST_OCTET_INVALID + {"LAST_OCTET_INVALID", ERR_LIB_RSA, RSA_R_LAST_OCTET_INVALID}, + #else + {"LAST_OCTET_INVALID", 4, 134}, + #endif + #ifdef RSA_R_MGF1_DIGEST_NOT_ALLOWED + {"MGF1_DIGEST_NOT_ALLOWED", ERR_LIB_RSA, RSA_R_MGF1_DIGEST_NOT_ALLOWED}, + #else + {"MGF1_DIGEST_NOT_ALLOWED", 4, 152}, + #endif + #ifdef RSA_R_MISSING_PRIVATE_KEY + {"MISSING_PRIVATE_KEY", ERR_LIB_RSA, RSA_R_MISSING_PRIVATE_KEY}, + #else + {"MISSING_PRIVATE_KEY", 4, 179}, + #endif + #ifdef RSA_R_MODULUS_TOO_LARGE + {"MODULUS_TOO_LARGE", ERR_LIB_RSA, RSA_R_MODULUS_TOO_LARGE}, + #else + {"MODULUS_TOO_LARGE", 4, 105}, + #endif + #ifdef RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R + {"MP_COEFFICIENT_NOT_INVERSE_OF_R", ERR_LIB_RSA, RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R}, + #else + {"MP_COEFFICIENT_NOT_INVERSE_OF_R", 4, 168}, + #endif + #ifdef RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D + {"MP_EXPONENT_NOT_CONGRUENT_TO_D", ERR_LIB_RSA, RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D}, + #else + {"MP_EXPONENT_NOT_CONGRUENT_TO_D", 4, 169}, + #endif + #ifdef RSA_R_MP_R_NOT_PRIME + {"MP_R_NOT_PRIME", ERR_LIB_RSA, RSA_R_MP_R_NOT_PRIME}, + #else + {"MP_R_NOT_PRIME", 4, 170}, + #endif + #ifdef RSA_R_NO_PUBLIC_EXPONENT + {"NO_PUBLIC_EXPONENT", ERR_LIB_RSA, RSA_R_NO_PUBLIC_EXPONENT}, + #else + {"NO_PUBLIC_EXPONENT", 4, 140}, + #endif + #ifdef RSA_R_NULL_BEFORE_BLOCK_MISSING + {"NULL_BEFORE_BLOCK_MISSING", ERR_LIB_RSA, RSA_R_NULL_BEFORE_BLOCK_MISSING}, + #else + {"NULL_BEFORE_BLOCK_MISSING", 4, 113}, + #endif + #ifdef RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES + {"N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES", ERR_LIB_RSA, RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES}, + #else + {"N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES", 4, 172}, + #endif + #ifdef RSA_R_N_DOES_NOT_EQUAL_P_Q + {"N_DOES_NOT_EQUAL_P_Q", ERR_LIB_RSA, RSA_R_N_DOES_NOT_EQUAL_P_Q}, + #else + {"N_DOES_NOT_EQUAL_P_Q", 4, 127}, + #endif + #ifdef RSA_R_OAEP_DECODING_ERROR + {"OAEP_DECODING_ERROR", ERR_LIB_RSA, RSA_R_OAEP_DECODING_ERROR}, + #else + {"OAEP_DECODING_ERROR", 4, 121}, + #endif + #ifdef RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE + {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", ERR_LIB_RSA, RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE}, + #else + {"OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE", 4, 148}, + #endif + #ifdef RSA_R_PADDING_CHECK_FAILED + {"PADDING_CHECK_FAILED", ERR_LIB_RSA, RSA_R_PADDING_CHECK_FAILED}, + #else + {"PADDING_CHECK_FAILED", 4, 114}, + #endif + #ifdef RSA_R_PAIRWISE_TEST_FAILURE + {"PAIRWISE_TEST_FAILURE", ERR_LIB_RSA, RSA_R_PAIRWISE_TEST_FAILURE}, + #else + {"PAIRWISE_TEST_FAILURE", 4, 177}, + #endif + #ifdef RSA_R_PKCS_DECODING_ERROR + {"PKCS_DECODING_ERROR", ERR_LIB_RSA, RSA_R_PKCS_DECODING_ERROR}, + #else + {"PKCS_DECODING_ERROR", 4, 159}, + #endif + #ifdef RSA_R_PSS_SALTLEN_TOO_SMALL + {"PSS_SALTLEN_TOO_SMALL", ERR_LIB_RSA, RSA_R_PSS_SALTLEN_TOO_SMALL}, + #else + {"PSS_SALTLEN_TOO_SMALL", 4, 164}, + #endif + #ifdef RSA_R_PUB_EXPONENT_OUT_OF_RANGE + {"PUB_EXPONENT_OUT_OF_RANGE", ERR_LIB_RSA, RSA_R_PUB_EXPONENT_OUT_OF_RANGE}, + #else + {"PUB_EXPONENT_OUT_OF_RANGE", 4, 178}, + #endif + #ifdef RSA_R_P_NOT_PRIME + {"P_NOT_PRIME", ERR_LIB_RSA, RSA_R_P_NOT_PRIME}, + #else + {"P_NOT_PRIME", 4, 128}, + #endif + #ifdef RSA_R_Q_NOT_PRIME + {"Q_NOT_PRIME", ERR_LIB_RSA, RSA_R_Q_NOT_PRIME}, + #else + {"Q_NOT_PRIME", 4, 129}, + #endif + #ifdef RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT + {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", ERR_LIB_RSA, RSA_R_RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT}, + #else + {"RANDOMNESS_SOURCE_STRENGTH_INSUFFICIENT", 4, 180}, + #endif + #ifdef RSA_R_RSA_OPERATIONS_NOT_SUPPORTED + {"RSA_OPERATIONS_NOT_SUPPORTED", ERR_LIB_RSA, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED}, + #else + {"RSA_OPERATIONS_NOT_SUPPORTED", 4, 130}, + #endif + #ifdef RSA_R_SLEN_CHECK_FAILED + {"SLEN_CHECK_FAILED", ERR_LIB_RSA, RSA_R_SLEN_CHECK_FAILED}, + #else + {"SLEN_CHECK_FAILED", 4, 136}, + #endif + #ifdef RSA_R_SLEN_RECOVERY_FAILED + {"SLEN_RECOVERY_FAILED", ERR_LIB_RSA, RSA_R_SLEN_RECOVERY_FAILED}, + #else + {"SLEN_RECOVERY_FAILED", 4, 135}, + #endif + #ifdef RSA_R_SSLV3_ROLLBACK_ATTACK + {"SSLV3_ROLLBACK_ATTACK", ERR_LIB_RSA, RSA_R_SSLV3_ROLLBACK_ATTACK}, + #else + {"SSLV3_ROLLBACK_ATTACK", 4, 115}, + #endif + #ifdef RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD + {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", ERR_LIB_RSA, RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD}, + #else + {"THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD", 4, 116}, + #endif + #ifdef RSA_R_UNKNOWN_ALGORITHM_TYPE + {"UNKNOWN_ALGORITHM_TYPE", ERR_LIB_RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE}, + #else + {"UNKNOWN_ALGORITHM_TYPE", 4, 117}, + #endif + #ifdef RSA_R_UNKNOWN_DIGEST + {"UNKNOWN_DIGEST", ERR_LIB_RSA, RSA_R_UNKNOWN_DIGEST}, + #else + {"UNKNOWN_DIGEST", 4, 166}, + #endif + #ifdef RSA_R_UNKNOWN_MASK_DIGEST + {"UNKNOWN_MASK_DIGEST", ERR_LIB_RSA, RSA_R_UNKNOWN_MASK_DIGEST}, + #else + {"UNKNOWN_MASK_DIGEST", 4, 151}, + #endif + #ifdef RSA_R_UNKNOWN_PADDING_TYPE + {"UNKNOWN_PADDING_TYPE", ERR_LIB_RSA, RSA_R_UNKNOWN_PADDING_TYPE}, + #else + {"UNKNOWN_PADDING_TYPE", 4, 118}, + #endif + #ifdef RSA_R_UNSUPPORTED_ENCRYPTION_TYPE + {"UNSUPPORTED_ENCRYPTION_TYPE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_ENCRYPTION_TYPE}, + #else + {"UNSUPPORTED_ENCRYPTION_TYPE", 4, 162}, + #endif + #ifdef RSA_R_UNSUPPORTED_LABEL_SOURCE + {"UNSUPPORTED_LABEL_SOURCE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_LABEL_SOURCE}, + #else + {"UNSUPPORTED_LABEL_SOURCE", 4, 163}, + #endif + #ifdef RSA_R_UNSUPPORTED_MASK_ALGORITHM + {"UNSUPPORTED_MASK_ALGORITHM", ERR_LIB_RSA, RSA_R_UNSUPPORTED_MASK_ALGORITHM}, + #else + {"UNSUPPORTED_MASK_ALGORITHM", 4, 153}, + #endif + #ifdef RSA_R_UNSUPPORTED_MASK_PARAMETER + {"UNSUPPORTED_MASK_PARAMETER", ERR_LIB_RSA, RSA_R_UNSUPPORTED_MASK_PARAMETER}, + #else + {"UNSUPPORTED_MASK_PARAMETER", 4, 154}, + #endif + #ifdef RSA_R_UNSUPPORTED_SIGNATURE_TYPE + {"UNSUPPORTED_SIGNATURE_TYPE", ERR_LIB_RSA, RSA_R_UNSUPPORTED_SIGNATURE_TYPE}, + #else + {"UNSUPPORTED_SIGNATURE_TYPE", 4, 155}, + #endif + #ifdef RSA_R_VALUE_MISSING + {"VALUE_MISSING", ERR_LIB_RSA, RSA_R_VALUE_MISSING}, + #else + {"VALUE_MISSING", 4, 147}, + #endif + #ifdef RSA_R_WRONG_SIGNATURE_LENGTH + {"WRONG_SIGNATURE_LENGTH", ERR_LIB_RSA, RSA_R_WRONG_SIGNATURE_LENGTH}, + #else + {"WRONG_SIGNATURE_LENGTH", 4, 119}, + #endif + #ifdef SM2_R_ASN1_ERROR + {"ASN1_ERROR", ERR_LIB_SM2, SM2_R_ASN1_ERROR}, + #else + {"ASN1_ERROR", 53, 100}, + #endif + #ifdef SM2_R_BAD_SIGNATURE + {"BAD_SIGNATURE", ERR_LIB_SM2, SM2_R_BAD_SIGNATURE}, + #else + {"BAD_SIGNATURE", 53, 101}, + #endif + #ifdef SM2_R_BUFFER_TOO_SMALL + {"BUFFER_TOO_SMALL", ERR_LIB_SM2, SM2_R_BUFFER_TOO_SMALL}, + #else + {"BUFFER_TOO_SMALL", 53, 107}, + #endif + #ifdef SM2_R_DIST_ID_TOO_LARGE + {"DIST_ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_DIST_ID_TOO_LARGE}, + #else + {"DIST_ID_TOO_LARGE", 53, 110}, + #endif + #ifdef SM2_R_ID_NOT_SET + {"ID_NOT_SET", ERR_LIB_SM2, SM2_R_ID_NOT_SET}, + #else + {"ID_NOT_SET", 53, 112}, + #endif + #ifdef SM2_R_ID_TOO_LARGE + {"ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_ID_TOO_LARGE}, + #else + {"ID_TOO_LARGE", 53, 111}, + #endif + #ifdef SM2_R_INVALID_CURVE + {"INVALID_CURVE", ERR_LIB_SM2, SM2_R_INVALID_CURVE}, + #else + {"INVALID_CURVE", 53, 108}, + #endif + #ifdef SM2_R_INVALID_DIGEST + {"INVALID_DIGEST", ERR_LIB_SM2, SM2_R_INVALID_DIGEST}, + #else + {"INVALID_DIGEST", 53, 102}, + #endif + #ifdef SM2_R_INVALID_DIGEST_TYPE + {"INVALID_DIGEST_TYPE", ERR_LIB_SM2, SM2_R_INVALID_DIGEST_TYPE}, + #else + {"INVALID_DIGEST_TYPE", 53, 103}, + #endif + #ifdef SM2_R_INVALID_ENCODING + {"INVALID_ENCODING", ERR_LIB_SM2, SM2_R_INVALID_ENCODING}, + #else + {"INVALID_ENCODING", 53, 104}, + #endif + #ifdef SM2_R_INVALID_FIELD + {"INVALID_FIELD", ERR_LIB_SM2, SM2_R_INVALID_FIELD}, + #else + {"INVALID_FIELD", 53, 105}, + #endif + #ifdef SM2_R_INVALID_PRIVATE_KEY + {"INVALID_PRIVATE_KEY", ERR_LIB_SM2, SM2_R_INVALID_PRIVATE_KEY}, + #else + {"INVALID_PRIVATE_KEY", 53, 113}, + #endif + #ifdef SM2_R_NO_PARAMETERS_SET + {"NO_PARAMETERS_SET", ERR_LIB_SM2, SM2_R_NO_PARAMETERS_SET}, + #else + {"NO_PARAMETERS_SET", 53, 109}, + #endif + #ifdef SM2_R_USER_ID_TOO_LARGE + {"USER_ID_TOO_LARGE", ERR_LIB_SM2, SM2_R_USER_ID_TOO_LARGE}, + #else + {"USER_ID_TOO_LARGE", 53, 106}, + #endif + #ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY + {"APPLICATION_DATA_AFTER_CLOSE_NOTIFY", ERR_LIB_SSL, SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY}, + #else + {"APPLICATION_DATA_AFTER_CLOSE_NOTIFY", 20, 291}, + #endif + #ifdef SSL_R_APP_DATA_IN_HANDSHAKE + {"APP_DATA_IN_HANDSHAKE", ERR_LIB_SSL, SSL_R_APP_DATA_IN_HANDSHAKE}, + #else + {"APP_DATA_IN_HANDSHAKE", 20, 100}, + #endif + #ifdef SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT + {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", ERR_LIB_SSL, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT}, + #else + {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", 20, 272}, + #endif + #ifdef SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE + {"AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE", ERR_LIB_SSL, SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE}, + #else + {"AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE", 20, 158}, + #endif + #ifdef SSL_R_BAD_CHANGE_CIPHER_SPEC + {"BAD_CHANGE_CIPHER_SPEC", ERR_LIB_SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC}, + #else + {"BAD_CHANGE_CIPHER_SPEC", 20, 103}, + #endif + #ifdef SSL_R_BAD_CIPHER + {"BAD_CIPHER", ERR_LIB_SSL, SSL_R_BAD_CIPHER}, + #else + {"BAD_CIPHER", 20, 186}, + #endif + #ifdef SSL_R_BAD_DATA + {"BAD_DATA", ERR_LIB_SSL, SSL_R_BAD_DATA}, + #else + {"BAD_DATA", 20, 390}, + #endif + #ifdef SSL_R_BAD_DATA_RETURNED_BY_CALLBACK + {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK}, + #else + {"BAD_DATA_RETURNED_BY_CALLBACK", 20, 106}, + #endif + #ifdef SSL_R_BAD_DECOMPRESSION + {"BAD_DECOMPRESSION", ERR_LIB_SSL, SSL_R_BAD_DECOMPRESSION}, + #else + {"BAD_DECOMPRESSION", 20, 107}, + #endif + #ifdef SSL_R_BAD_DH_VALUE + {"BAD_DH_VALUE", ERR_LIB_SSL, SSL_R_BAD_DH_VALUE}, + #else + {"BAD_DH_VALUE", 20, 102}, + #endif + #ifdef SSL_R_BAD_DIGEST_LENGTH + {"BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DIGEST_LENGTH}, + #else + {"BAD_DIGEST_LENGTH", 20, 111}, + #endif + #ifdef SSL_R_BAD_EARLY_DATA + {"BAD_EARLY_DATA", ERR_LIB_SSL, SSL_R_BAD_EARLY_DATA}, + #else + {"BAD_EARLY_DATA", 20, 233}, + #endif + #ifdef SSL_R_BAD_ECC_CERT + {"BAD_ECC_CERT", ERR_LIB_SSL, SSL_R_BAD_ECC_CERT}, + #else + {"BAD_ECC_CERT", 20, 304}, + #endif + #ifdef SSL_R_BAD_ECPOINT + {"BAD_ECPOINT", ERR_LIB_SSL, SSL_R_BAD_ECPOINT}, + #else + {"BAD_ECPOINT", 20, 306}, + #endif + #ifdef SSL_R_BAD_EXTENSION + {"BAD_EXTENSION", ERR_LIB_SSL, SSL_R_BAD_EXTENSION}, + #else + {"BAD_EXTENSION", 20, 110}, + #endif + #ifdef SSL_R_BAD_HANDSHAKE_LENGTH + {"BAD_HANDSHAKE_LENGTH", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_LENGTH}, + #else + {"BAD_HANDSHAKE_LENGTH", 20, 332}, + #endif + #ifdef SSL_R_BAD_HANDSHAKE_STATE + {"BAD_HANDSHAKE_STATE", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_STATE}, + #else + {"BAD_HANDSHAKE_STATE", 20, 236}, + #endif + #ifdef SSL_R_BAD_HELLO_REQUEST + {"BAD_HELLO_REQUEST", ERR_LIB_SSL, SSL_R_BAD_HELLO_REQUEST}, + #else + {"BAD_HELLO_REQUEST", 20, 105}, + #endif + #ifdef SSL_R_BAD_HRR_VERSION + {"BAD_HRR_VERSION", ERR_LIB_SSL, SSL_R_BAD_HRR_VERSION}, + #else + {"BAD_HRR_VERSION", 20, 263}, + #endif + #ifdef SSL_R_BAD_KEY_SHARE + {"BAD_KEY_SHARE", ERR_LIB_SSL, SSL_R_BAD_KEY_SHARE}, + #else + {"BAD_KEY_SHARE", 20, 108}, + #endif + #ifdef SSL_R_BAD_KEY_UPDATE + {"BAD_KEY_UPDATE", ERR_LIB_SSL, SSL_R_BAD_KEY_UPDATE}, + #else + {"BAD_KEY_UPDATE", 20, 122}, + #endif + #ifdef SSL_R_BAD_LEGACY_VERSION + {"BAD_LEGACY_VERSION", ERR_LIB_SSL, SSL_R_BAD_LEGACY_VERSION}, + #else + {"BAD_LEGACY_VERSION", 20, 292}, + #endif + #ifdef SSL_R_BAD_LENGTH + {"BAD_LENGTH", ERR_LIB_SSL, SSL_R_BAD_LENGTH}, + #else + {"BAD_LENGTH", 20, 271}, + #endif + #ifdef SSL_R_BAD_PACKET + {"BAD_PACKET", ERR_LIB_SSL, SSL_R_BAD_PACKET}, + #else + {"BAD_PACKET", 20, 240}, + #endif + #ifdef SSL_R_BAD_PACKET_LENGTH + {"BAD_PACKET_LENGTH", ERR_LIB_SSL, SSL_R_BAD_PACKET_LENGTH}, + #else + {"BAD_PACKET_LENGTH", 20, 115}, + #endif + #ifdef SSL_R_BAD_PROTOCOL_VERSION_NUMBER + {"BAD_PROTOCOL_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_BAD_PROTOCOL_VERSION_NUMBER}, + #else + {"BAD_PROTOCOL_VERSION_NUMBER", 20, 116}, + #endif + #ifdef SSL_R_BAD_PSK + {"BAD_PSK", ERR_LIB_SSL, SSL_R_BAD_PSK}, + #else + {"BAD_PSK", 20, 219}, + #endif + #ifdef SSL_R_BAD_PSK_IDENTITY + {"BAD_PSK_IDENTITY", ERR_LIB_SSL, SSL_R_BAD_PSK_IDENTITY}, + #else + {"BAD_PSK_IDENTITY", 20, 114}, + #endif + #ifdef SSL_R_BAD_RECORD_TYPE + {"BAD_RECORD_TYPE", ERR_LIB_SSL, SSL_R_BAD_RECORD_TYPE}, + #else + {"BAD_RECORD_TYPE", 20, 443}, + #endif + #ifdef SSL_R_BAD_RSA_ENCRYPT + {"BAD_RSA_ENCRYPT", ERR_LIB_SSL, SSL_R_BAD_RSA_ENCRYPT}, + #else + {"BAD_RSA_ENCRYPT", 20, 119}, + #endif + #ifdef SSL_R_BAD_SIGNATURE + {"BAD_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_SIGNATURE}, + #else + {"BAD_SIGNATURE", 20, 123}, + #endif + #ifdef SSL_R_BAD_SRP_A_LENGTH + {"BAD_SRP_A_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SRP_A_LENGTH}, + #else + {"BAD_SRP_A_LENGTH", 20, 347}, + #endif + #ifdef SSL_R_BAD_SRP_PARAMETERS + {"BAD_SRP_PARAMETERS", ERR_LIB_SSL, SSL_R_BAD_SRP_PARAMETERS}, + #else + {"BAD_SRP_PARAMETERS", 20, 371}, + #endif + #ifdef SSL_R_BAD_SRTP_MKI_VALUE + {"BAD_SRTP_MKI_VALUE", ERR_LIB_SSL, SSL_R_BAD_SRTP_MKI_VALUE}, + #else + {"BAD_SRTP_MKI_VALUE", 20, 352}, + #endif + #ifdef SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST + {"BAD_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST}, + #else + {"BAD_SRTP_PROTECTION_PROFILE_LIST", 20, 353}, + #endif + #ifdef SSL_R_BAD_SSL_FILETYPE + {"BAD_SSL_FILETYPE", ERR_LIB_SSL, SSL_R_BAD_SSL_FILETYPE}, + #else + {"BAD_SSL_FILETYPE", 20, 124}, + #endif + #ifdef SSL_R_BAD_VALUE + {"BAD_VALUE", ERR_LIB_SSL, SSL_R_BAD_VALUE}, + #else + {"BAD_VALUE", 20, 384}, + #endif + #ifdef SSL_R_BAD_WRITE_RETRY + {"BAD_WRITE_RETRY", ERR_LIB_SSL, SSL_R_BAD_WRITE_RETRY}, + #else + {"BAD_WRITE_RETRY", 20, 127}, + #endif + #ifdef SSL_R_BINDER_DOES_NOT_VERIFY + {"BINDER_DOES_NOT_VERIFY", ERR_LIB_SSL, SSL_R_BINDER_DOES_NOT_VERIFY}, + #else + {"BINDER_DOES_NOT_VERIFY", 20, 253}, + #endif + #ifdef SSL_R_BIO_NOT_SET + {"BIO_NOT_SET", ERR_LIB_SSL, SSL_R_BIO_NOT_SET}, + #else + {"BIO_NOT_SET", 20, 128}, + #endif + #ifdef SSL_R_BLOCK_CIPHER_PAD_IS_WRONG + {"BLOCK_CIPHER_PAD_IS_WRONG", ERR_LIB_SSL, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG}, + #else + {"BLOCK_CIPHER_PAD_IS_WRONG", 20, 129}, + #endif + #ifdef SSL_R_BN_LIB + {"BN_LIB", ERR_LIB_SSL, SSL_R_BN_LIB}, + #else + {"BN_LIB", 20, 130}, + #endif + #ifdef SSL_R_CALLBACK_FAILED + {"CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_CALLBACK_FAILED}, + #else + {"CALLBACK_FAILED", 20, 234}, + #endif + #ifdef SSL_R_CANNOT_CHANGE_CIPHER + {"CANNOT_CHANGE_CIPHER", ERR_LIB_SSL, SSL_R_CANNOT_CHANGE_CIPHER}, + #else + {"CANNOT_CHANGE_CIPHER", 20, 109}, + #endif + #ifdef SSL_R_CANNOT_GET_GROUP_NAME + {"CANNOT_GET_GROUP_NAME", ERR_LIB_SSL, SSL_R_CANNOT_GET_GROUP_NAME}, + #else + {"CANNOT_GET_GROUP_NAME", 20, 299}, + #endif + #ifdef SSL_R_CA_DN_LENGTH_MISMATCH + {"CA_DN_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CA_DN_LENGTH_MISMATCH}, + #else + {"CA_DN_LENGTH_MISMATCH", 20, 131}, + #endif + #ifdef SSL_R_CA_KEY_TOO_SMALL + {"CA_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_CA_KEY_TOO_SMALL}, + #else + {"CA_KEY_TOO_SMALL", 20, 397}, + #endif + #ifdef SSL_R_CA_MD_TOO_WEAK + {"CA_MD_TOO_WEAK", ERR_LIB_SSL, SSL_R_CA_MD_TOO_WEAK}, + #else + {"CA_MD_TOO_WEAK", 20, 398}, + #endif + #ifdef SSL_R_CCS_RECEIVED_EARLY + {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, SSL_R_CCS_RECEIVED_EARLY}, + #else + {"CCS_RECEIVED_EARLY", 20, 133}, + #endif + #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED + {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED}, + #else + {"CERTIFICATE_VERIFY_FAILED", 20, 134}, + #endif + #ifdef SSL_R_CERT_CB_ERROR + {"CERT_CB_ERROR", ERR_LIB_SSL, SSL_R_CERT_CB_ERROR}, + #else + {"CERT_CB_ERROR", 20, 377}, + #endif + #ifdef SSL_R_CERT_LENGTH_MISMATCH + {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CERT_LENGTH_MISMATCH}, + #else + {"CERT_LENGTH_MISMATCH", 20, 135}, + #endif + #ifdef SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED + {"CIPHERSUITE_DIGEST_HAS_CHANGED", ERR_LIB_SSL, SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED}, + #else + {"CIPHERSUITE_DIGEST_HAS_CHANGED", 20, 218}, + #endif + #ifdef SSL_R_CIPHER_CODE_WRONG_LENGTH + {"CIPHER_CODE_WRONG_LENGTH", ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH}, + #else + {"CIPHER_CODE_WRONG_LENGTH", 20, 137}, + #endif + #ifdef SSL_R_CLIENTHELLO_TLSEXT + {"CLIENTHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_CLIENTHELLO_TLSEXT}, + #else + {"CLIENTHELLO_TLSEXT", 20, 226}, + #endif + #ifdef SSL_R_COMPRESSED_LENGTH_TOO_LONG + {"COMPRESSED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_COMPRESSED_LENGTH_TOO_LONG}, + #else + {"COMPRESSED_LENGTH_TOO_LONG", 20, 140}, + #endif + #ifdef SSL_R_COMPRESSION_DISABLED + {"COMPRESSION_DISABLED", ERR_LIB_SSL, SSL_R_COMPRESSION_DISABLED}, + #else + {"COMPRESSION_DISABLED", 20, 343}, + #endif + #ifdef SSL_R_COMPRESSION_FAILURE + {"COMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_COMPRESSION_FAILURE}, + #else + {"COMPRESSION_FAILURE", 20, 141}, + #endif + #ifdef SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE + {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", ERR_LIB_SSL, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE}, + #else + {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", 20, 307}, + #endif + #ifdef SSL_R_COMPRESSION_LIBRARY_ERROR + {"COMPRESSION_LIBRARY_ERROR", ERR_LIB_SSL, SSL_R_COMPRESSION_LIBRARY_ERROR}, + #else + {"COMPRESSION_LIBRARY_ERROR", 20, 142}, + #endif + #ifdef SSL_R_CONNECTION_TYPE_NOT_SET + {"CONNECTION_TYPE_NOT_SET", ERR_LIB_SSL, SSL_R_CONNECTION_TYPE_NOT_SET}, + #else + {"CONNECTION_TYPE_NOT_SET", 20, 144}, + #endif + #ifdef SSL_R_CONTEXT_NOT_DANE_ENABLED + {"CONTEXT_NOT_DANE_ENABLED", ERR_LIB_SSL, SSL_R_CONTEXT_NOT_DANE_ENABLED}, + #else + {"CONTEXT_NOT_DANE_ENABLED", 20, 167}, + #endif + #ifdef SSL_R_COOKIE_GEN_CALLBACK_FAILURE + {"COOKIE_GEN_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_COOKIE_GEN_CALLBACK_FAILURE}, + #else + {"COOKIE_GEN_CALLBACK_FAILURE", 20, 400}, + #endif + #ifdef SSL_R_COOKIE_MISMATCH + {"COOKIE_MISMATCH", ERR_LIB_SSL, SSL_R_COOKIE_MISMATCH}, + #else + {"COOKIE_MISMATCH", 20, 308}, + #endif + #ifdef SSL_R_COPY_PARAMETERS_FAILED + {"COPY_PARAMETERS_FAILED", ERR_LIB_SSL, SSL_R_COPY_PARAMETERS_FAILED}, + #else + {"COPY_PARAMETERS_FAILED", 20, 296}, + #endif + #ifdef SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED + {"CUSTOM_EXT_HANDLER_ALREADY_INSTALLED", ERR_LIB_SSL, SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED}, + #else + {"CUSTOM_EXT_HANDLER_ALREADY_INSTALLED", 20, 206}, + #endif + #ifdef SSL_R_DANE_ALREADY_ENABLED + {"DANE_ALREADY_ENABLED", ERR_LIB_SSL, SSL_R_DANE_ALREADY_ENABLED}, + #else + {"DANE_ALREADY_ENABLED", 20, 172}, + #endif + #ifdef SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL + {"DANE_CANNOT_OVERRIDE_MTYPE_FULL", ERR_LIB_SSL, SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL}, + #else + {"DANE_CANNOT_OVERRIDE_MTYPE_FULL", 20, 173}, + #endif + #ifdef SSL_R_DANE_NOT_ENABLED + {"DANE_NOT_ENABLED", ERR_LIB_SSL, SSL_R_DANE_NOT_ENABLED}, + #else + {"DANE_NOT_ENABLED", 20, 175}, + #endif + #ifdef SSL_R_DANE_TLSA_BAD_CERTIFICATE + {"DANE_TLSA_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE}, + #else + {"DANE_TLSA_BAD_CERTIFICATE", 20, 180}, + #endif + #ifdef SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE + {"DANE_TLSA_BAD_CERTIFICATE_USAGE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE}, + #else + {"DANE_TLSA_BAD_CERTIFICATE_USAGE", 20, 184}, + #endif + #ifdef SSL_R_DANE_TLSA_BAD_DATA_LENGTH + {"DANE_TLSA_BAD_DATA_LENGTH", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_DATA_LENGTH}, + #else + {"DANE_TLSA_BAD_DATA_LENGTH", 20, 189}, + #endif + #ifdef SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH + {"DANE_TLSA_BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH}, + #else + {"DANE_TLSA_BAD_DIGEST_LENGTH", 20, 192}, + #endif + #ifdef SSL_R_DANE_TLSA_BAD_MATCHING_TYPE + {"DANE_TLSA_BAD_MATCHING_TYPE", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE}, + #else + {"DANE_TLSA_BAD_MATCHING_TYPE", 20, 200}, + #endif + #ifdef SSL_R_DANE_TLSA_BAD_PUBLIC_KEY + {"DANE_TLSA_BAD_PUBLIC_KEY", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY}, + #else + {"DANE_TLSA_BAD_PUBLIC_KEY", 20, 201}, + #endif + #ifdef SSL_R_DANE_TLSA_BAD_SELECTOR + {"DANE_TLSA_BAD_SELECTOR", ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_SELECTOR}, + #else + {"DANE_TLSA_BAD_SELECTOR", 20, 202}, + #endif + #ifdef SSL_R_DANE_TLSA_NULL_DATA + {"DANE_TLSA_NULL_DATA", ERR_LIB_SSL, SSL_R_DANE_TLSA_NULL_DATA}, + #else + {"DANE_TLSA_NULL_DATA", 20, 203}, + #endif + #ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED + {"DATA_BETWEEN_CCS_AND_FINISHED", ERR_LIB_SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED}, + #else + {"DATA_BETWEEN_CCS_AND_FINISHED", 20, 145}, + #endif + #ifdef SSL_R_DATA_LENGTH_TOO_LONG + {"DATA_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_DATA_LENGTH_TOO_LONG}, + #else + {"DATA_LENGTH_TOO_LONG", 20, 146}, + #endif + #ifdef SSL_R_DECRYPTION_FAILED + {"DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED}, + #else + {"DECRYPTION_FAILED", 20, 147}, + #endif + #ifdef SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC + {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC}, + #else + {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", 20, 281}, + #endif + #ifdef SSL_R_DH_KEY_TOO_SMALL + {"DH_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_DH_KEY_TOO_SMALL}, + #else + {"DH_KEY_TOO_SMALL", 20, 394}, + #endif + #ifdef SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG + {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG}, + #else + {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", 20, 148}, + #endif + #ifdef SSL_R_DIGEST_CHECK_FAILED + {"DIGEST_CHECK_FAILED", ERR_LIB_SSL, SSL_R_DIGEST_CHECK_FAILED}, + #else + {"DIGEST_CHECK_FAILED", 20, 149}, + #endif + #ifdef SSL_R_DTLS_MESSAGE_TOO_BIG + {"DTLS_MESSAGE_TOO_BIG", ERR_LIB_SSL, SSL_R_DTLS_MESSAGE_TOO_BIG}, + #else + {"DTLS_MESSAGE_TOO_BIG", 20, 334}, + #endif + #ifdef SSL_R_DUPLICATE_COMPRESSION_ID + {"DUPLICATE_COMPRESSION_ID", ERR_LIB_SSL, SSL_R_DUPLICATE_COMPRESSION_ID}, + #else + {"DUPLICATE_COMPRESSION_ID", 20, 309}, + #endif + #ifdef SSL_R_ECC_CERT_NOT_FOR_SIGNING + {"ECC_CERT_NOT_FOR_SIGNING", ERR_LIB_SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING}, + #else + {"ECC_CERT_NOT_FOR_SIGNING", 20, 318}, + #endif + #ifdef SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE + {"ECDH_REQUIRED_FOR_SUITEB_MODE", ERR_LIB_SSL, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE}, + #else + {"ECDH_REQUIRED_FOR_SUITEB_MODE", 20, 374}, + #endif + #ifdef SSL_R_EE_KEY_TOO_SMALL + {"EE_KEY_TOO_SMALL", ERR_LIB_SSL, SSL_R_EE_KEY_TOO_SMALL}, + #else + {"EE_KEY_TOO_SMALL", 20, 399}, + #endif + #ifdef SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST + {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", ERR_LIB_SSL, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST}, + #else + {"EMPTY_SRTP_PROTECTION_PROFILE_LIST", 20, 354}, + #endif + #ifdef SSL_R_ENCRYPTED_LENGTH_TOO_LONG + {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG}, + #else + {"ENCRYPTED_LENGTH_TOO_LONG", 20, 150}, + #endif + #ifdef SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST + {"ERROR_IN_RECEIVED_CIPHER_LIST", ERR_LIB_SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST}, + #else + {"ERROR_IN_RECEIVED_CIPHER_LIST", 20, 151}, + #endif + #ifdef SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN + {"ERROR_SETTING_TLSA_BASE_DOMAIN", ERR_LIB_SSL, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN}, + #else + {"ERROR_SETTING_TLSA_BASE_DOMAIN", 20, 204}, + #endif + #ifdef SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE + {"EXCEEDS_MAX_FRAGMENT_SIZE", ERR_LIB_SSL, SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE}, + #else + {"EXCEEDS_MAX_FRAGMENT_SIZE", 20, 194}, + #endif + #ifdef SSL_R_EXCESSIVE_MESSAGE_SIZE + {"EXCESSIVE_MESSAGE_SIZE", ERR_LIB_SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE}, + #else + {"EXCESSIVE_MESSAGE_SIZE", 20, 152}, + #endif + #ifdef SSL_R_EXTENSION_NOT_RECEIVED + {"EXTENSION_NOT_RECEIVED", ERR_LIB_SSL, SSL_R_EXTENSION_NOT_RECEIVED}, + #else + {"EXTENSION_NOT_RECEIVED", 20, 279}, + #endif + #ifdef SSL_R_EXTRA_DATA_IN_MESSAGE + {"EXTRA_DATA_IN_MESSAGE", ERR_LIB_SSL, SSL_R_EXTRA_DATA_IN_MESSAGE}, + #else + {"EXTRA_DATA_IN_MESSAGE", 20, 153}, + #endif + #ifdef SSL_R_EXT_LENGTH_MISMATCH + {"EXT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_EXT_LENGTH_MISMATCH}, + #else + {"EXT_LENGTH_MISMATCH", 20, 163}, + #endif + #ifdef SSL_R_FAILED_TO_INIT_ASYNC + {"FAILED_TO_INIT_ASYNC", ERR_LIB_SSL, SSL_R_FAILED_TO_INIT_ASYNC}, + #else + {"FAILED_TO_INIT_ASYNC", 20, 405}, + #endif + #ifdef SSL_R_FRAGMENTED_CLIENT_HELLO + {"FRAGMENTED_CLIENT_HELLO", ERR_LIB_SSL, SSL_R_FRAGMENTED_CLIENT_HELLO}, + #else + {"FRAGMENTED_CLIENT_HELLO", 20, 401}, + #endif + #ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS + {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, SSL_R_GOT_A_FIN_BEFORE_A_CCS}, + #else + {"GOT_A_FIN_BEFORE_A_CCS", 20, 154}, + #endif + #ifdef SSL_R_HTTPS_PROXY_REQUEST + {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, SSL_R_HTTPS_PROXY_REQUEST}, + #else + {"HTTPS_PROXY_REQUEST", 20, 155}, + #endif + #ifdef SSL_R_HTTP_REQUEST + {"HTTP_REQUEST", ERR_LIB_SSL, SSL_R_HTTP_REQUEST}, + #else + {"HTTP_REQUEST", 20, 156}, + #endif + #ifdef SSL_R_ILLEGAL_POINT_COMPRESSION + {"ILLEGAL_POINT_COMPRESSION", ERR_LIB_SSL, SSL_R_ILLEGAL_POINT_COMPRESSION}, + #else + {"ILLEGAL_POINT_COMPRESSION", 20, 162}, + #endif + #ifdef SSL_R_ILLEGAL_SUITEB_DIGEST + {"ILLEGAL_SUITEB_DIGEST", ERR_LIB_SSL, SSL_R_ILLEGAL_SUITEB_DIGEST}, + #else + {"ILLEGAL_SUITEB_DIGEST", 20, 380}, + #endif + #ifdef SSL_R_INAPPROPRIATE_FALLBACK + {"INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_INAPPROPRIATE_FALLBACK}, + #else + {"INAPPROPRIATE_FALLBACK", 20, 373}, + #endif + #ifdef SSL_R_INCONSISTENT_COMPRESSION + {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, SSL_R_INCONSISTENT_COMPRESSION}, + #else + {"INCONSISTENT_COMPRESSION", 20, 340}, + #endif + #ifdef SSL_R_INCONSISTENT_EARLY_DATA_ALPN + {"INCONSISTENT_EARLY_DATA_ALPN", ERR_LIB_SSL, SSL_R_INCONSISTENT_EARLY_DATA_ALPN}, + #else + {"INCONSISTENT_EARLY_DATA_ALPN", 20, 222}, + #endif + #ifdef SSL_R_INCONSISTENT_EARLY_DATA_SNI + {"INCONSISTENT_EARLY_DATA_SNI", ERR_LIB_SSL, SSL_R_INCONSISTENT_EARLY_DATA_SNI}, + #else + {"INCONSISTENT_EARLY_DATA_SNI", 20, 231}, + #endif + #ifdef SSL_R_INCONSISTENT_EXTMS + {"INCONSISTENT_EXTMS", ERR_LIB_SSL, SSL_R_INCONSISTENT_EXTMS}, + #else + {"INCONSISTENT_EXTMS", 20, 104}, + #endif + #ifdef SSL_R_INSUFFICIENT_SECURITY + {"INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_INSUFFICIENT_SECURITY}, + #else + {"INSUFFICIENT_SECURITY", 20, 241}, + #endif + #ifdef SSL_R_INVALID_ALERT + {"INVALID_ALERT", ERR_LIB_SSL, SSL_R_INVALID_ALERT}, + #else + {"INVALID_ALERT", 20, 205}, + #endif + #ifdef SSL_R_INVALID_CCS_MESSAGE + {"INVALID_CCS_MESSAGE", ERR_LIB_SSL, SSL_R_INVALID_CCS_MESSAGE}, + #else + {"INVALID_CCS_MESSAGE", 20, 260}, + #endif + #ifdef SSL_R_INVALID_CERTIFICATE_OR_ALG + {"INVALID_CERTIFICATE_OR_ALG", ERR_LIB_SSL, SSL_R_INVALID_CERTIFICATE_OR_ALG}, + #else + {"INVALID_CERTIFICATE_OR_ALG", 20, 238}, + #endif + #ifdef SSL_R_INVALID_COMMAND + {"INVALID_COMMAND", ERR_LIB_SSL, SSL_R_INVALID_COMMAND}, + #else + {"INVALID_COMMAND", 20, 280}, + #endif + #ifdef SSL_R_INVALID_COMPRESSION_ALGORITHM + {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_INVALID_COMPRESSION_ALGORITHM}, + #else + {"INVALID_COMPRESSION_ALGORITHM", 20, 341}, + #endif + #ifdef SSL_R_INVALID_CONFIG + {"INVALID_CONFIG", ERR_LIB_SSL, SSL_R_INVALID_CONFIG}, + #else + {"INVALID_CONFIG", 20, 283}, + #endif + #ifdef SSL_R_INVALID_CONFIGURATION_NAME + {"INVALID_CONFIGURATION_NAME", ERR_LIB_SSL, SSL_R_INVALID_CONFIGURATION_NAME}, + #else + {"INVALID_CONFIGURATION_NAME", 20, 113}, + #endif + #ifdef SSL_R_INVALID_CONTEXT + {"INVALID_CONTEXT", ERR_LIB_SSL, SSL_R_INVALID_CONTEXT}, + #else + {"INVALID_CONTEXT", 20, 282}, + #endif + #ifdef SSL_R_INVALID_CT_VALIDATION_TYPE + {"INVALID_CT_VALIDATION_TYPE", ERR_LIB_SSL, SSL_R_INVALID_CT_VALIDATION_TYPE}, + #else + {"INVALID_CT_VALIDATION_TYPE", 20, 212}, + #endif + #ifdef SSL_R_INVALID_KEY_UPDATE_TYPE + {"INVALID_KEY_UPDATE_TYPE", ERR_LIB_SSL, SSL_R_INVALID_KEY_UPDATE_TYPE}, + #else + {"INVALID_KEY_UPDATE_TYPE", 20, 120}, + #endif + #ifdef SSL_R_INVALID_MAX_EARLY_DATA + {"INVALID_MAX_EARLY_DATA", ERR_LIB_SSL, SSL_R_INVALID_MAX_EARLY_DATA}, + #else + {"INVALID_MAX_EARLY_DATA", 20, 174}, + #endif + #ifdef SSL_R_INVALID_NULL_CMD_NAME + {"INVALID_NULL_CMD_NAME", ERR_LIB_SSL, SSL_R_INVALID_NULL_CMD_NAME}, + #else + {"INVALID_NULL_CMD_NAME", 20, 385}, + #endif + #ifdef SSL_R_INVALID_SEQUENCE_NUMBER + {"INVALID_SEQUENCE_NUMBER", ERR_LIB_SSL, SSL_R_INVALID_SEQUENCE_NUMBER}, + #else + {"INVALID_SEQUENCE_NUMBER", 20, 402}, + #endif + #ifdef SSL_R_INVALID_SERVERINFO_DATA + {"INVALID_SERVERINFO_DATA", ERR_LIB_SSL, SSL_R_INVALID_SERVERINFO_DATA}, + #else + {"INVALID_SERVERINFO_DATA", 20, 388}, + #endif + #ifdef SSL_R_INVALID_SESSION_ID + {"INVALID_SESSION_ID", ERR_LIB_SSL, SSL_R_INVALID_SESSION_ID}, + #else + {"INVALID_SESSION_ID", 20, 999}, + #endif + #ifdef SSL_R_INVALID_SRP_USERNAME + {"INVALID_SRP_USERNAME", ERR_LIB_SSL, SSL_R_INVALID_SRP_USERNAME}, + #else + {"INVALID_SRP_USERNAME", 20, 357}, + #endif + #ifdef SSL_R_INVALID_STATUS_RESPONSE + {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_INVALID_STATUS_RESPONSE}, + #else + {"INVALID_STATUS_RESPONSE", 20, 328}, + #endif + #ifdef SSL_R_INVALID_TICKET_KEYS_LENGTH + {"INVALID_TICKET_KEYS_LENGTH", ERR_LIB_SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH}, + #else + {"INVALID_TICKET_KEYS_LENGTH", 20, 325}, + #endif + #ifdef SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED + {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", ERR_LIB_SSL, SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED}, + #else + {"LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED", 20, 333}, + #endif + #ifdef SSL_R_LENGTH_MISMATCH + {"LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH}, + #else + {"LENGTH_MISMATCH", 20, 159}, + #endif + #ifdef SSL_R_LENGTH_TOO_LONG + {"LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_LENGTH_TOO_LONG}, + #else + {"LENGTH_TOO_LONG", 20, 404}, + #endif + #ifdef SSL_R_LENGTH_TOO_SHORT + {"LENGTH_TOO_SHORT", ERR_LIB_SSL, SSL_R_LENGTH_TOO_SHORT}, + #else + {"LENGTH_TOO_SHORT", 20, 160}, + #endif + #ifdef SSL_R_LIBRARY_BUG + {"LIBRARY_BUG", ERR_LIB_SSL, SSL_R_LIBRARY_BUG}, + #else + {"LIBRARY_BUG", 20, 274}, + #endif + #ifdef SSL_R_LIBRARY_HAS_NO_CIPHERS + {"LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS}, + #else + {"LIBRARY_HAS_NO_CIPHERS", 20, 161}, + #endif + #ifdef SSL_R_MISSING_DSA_SIGNING_CERT + {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_DSA_SIGNING_CERT}, + #else + {"MISSING_DSA_SIGNING_CERT", 20, 165}, + #endif + #ifdef SSL_R_MISSING_ECDSA_SIGNING_CERT + {"MISSING_ECDSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_ECDSA_SIGNING_CERT}, + #else + {"MISSING_ECDSA_SIGNING_CERT", 20, 381}, + #endif + #ifdef SSL_R_MISSING_FATAL + {"MISSING_FATAL", ERR_LIB_SSL, SSL_R_MISSING_FATAL}, + #else + {"MISSING_FATAL", 20, 256}, + #endif + #ifdef SSL_R_MISSING_PARAMETERS + {"MISSING_PARAMETERS", ERR_LIB_SSL, SSL_R_MISSING_PARAMETERS}, + #else + {"MISSING_PARAMETERS", 20, 290}, + #endif + #ifdef SSL_R_MISSING_PSK_KEX_MODES_EXTENSION + {"MISSING_PSK_KEX_MODES_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION}, + #else + {"MISSING_PSK_KEX_MODES_EXTENSION", 20, 310}, + #endif + #ifdef SSL_R_MISSING_RSA_CERTIFICATE + {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, SSL_R_MISSING_RSA_CERTIFICATE}, + #else + {"MISSING_RSA_CERTIFICATE", 20, 168}, + #endif + #ifdef SSL_R_MISSING_RSA_ENCRYPTING_CERT + {"MISSING_RSA_ENCRYPTING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_ENCRYPTING_CERT}, + #else + {"MISSING_RSA_ENCRYPTING_CERT", 20, 169}, + #endif + #ifdef SSL_R_MISSING_RSA_SIGNING_CERT + {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_SIGNING_CERT}, + #else + {"MISSING_RSA_SIGNING_CERT", 20, 170}, + #endif + #ifdef SSL_R_MISSING_SIGALGS_EXTENSION + {"MISSING_SIGALGS_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_SIGALGS_EXTENSION}, + #else + {"MISSING_SIGALGS_EXTENSION", 20, 112}, + #endif + #ifdef SSL_R_MISSING_SIGNING_CERT + {"MISSING_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_SIGNING_CERT}, + #else + {"MISSING_SIGNING_CERT", 20, 221}, + #endif + #ifdef SSL_R_MISSING_SRP_PARAM + {"MISSING_SRP_PARAM", ERR_LIB_SSL, SSL_R_MISSING_SRP_PARAM}, + #else + {"MISSING_SRP_PARAM", 20, 358}, + #endif + #ifdef SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION + {"MISSING_SUPPORTED_GROUPS_EXTENSION", ERR_LIB_SSL, SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION}, + #else + {"MISSING_SUPPORTED_GROUPS_EXTENSION", 20, 209}, + #endif + #ifdef SSL_R_MISSING_TMP_DH_KEY + {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_DH_KEY}, + #else + {"MISSING_TMP_DH_KEY", 20, 171}, + #endif + #ifdef SSL_R_MISSING_TMP_ECDH_KEY + {"MISSING_TMP_ECDH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_ECDH_KEY}, + #else + {"MISSING_TMP_ECDH_KEY", 20, 311}, + #endif + #ifdef SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA + {"MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA", ERR_LIB_SSL, SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA}, + #else + {"MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA", 20, 293}, + #endif + #ifdef SSL_R_NOT_ON_RECORD_BOUNDARY + {"NOT_ON_RECORD_BOUNDARY", ERR_LIB_SSL, SSL_R_NOT_ON_RECORD_BOUNDARY}, + #else + {"NOT_ON_RECORD_BOUNDARY", 20, 182}, + #endif + #ifdef SSL_R_NOT_REPLACING_CERTIFICATE + {"NOT_REPLACING_CERTIFICATE", ERR_LIB_SSL, SSL_R_NOT_REPLACING_CERTIFICATE}, + #else + {"NOT_REPLACING_CERTIFICATE", 20, 289}, + #endif + #ifdef SSL_R_NOT_SERVER + {"NOT_SERVER", ERR_LIB_SSL, SSL_R_NOT_SERVER}, + #else + {"NOT_SERVER", 20, 284}, + #endif + #ifdef SSL_R_NO_APPLICATION_PROTOCOL + {"NO_APPLICATION_PROTOCOL", ERR_LIB_SSL, SSL_R_NO_APPLICATION_PROTOCOL}, + #else + {"NO_APPLICATION_PROTOCOL", 20, 235}, + #endif + #ifdef SSL_R_NO_CERTIFICATES_RETURNED + {"NO_CERTIFICATES_RETURNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATES_RETURNED}, + #else + {"NO_CERTIFICATES_RETURNED", 20, 176}, + #endif + #ifdef SSL_R_NO_CERTIFICATE_ASSIGNED + {"NO_CERTIFICATE_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_ASSIGNED}, + #else + {"NO_CERTIFICATE_ASSIGNED", 20, 177}, + #endif + #ifdef SSL_R_NO_CERTIFICATE_SET + {"NO_CERTIFICATE_SET", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET}, + #else + {"NO_CERTIFICATE_SET", 20, 179}, + #endif + #ifdef SSL_R_NO_CHANGE_FOLLOWING_HRR + {"NO_CHANGE_FOLLOWING_HRR", ERR_LIB_SSL, SSL_R_NO_CHANGE_FOLLOWING_HRR}, + #else + {"NO_CHANGE_FOLLOWING_HRR", 20, 214}, + #endif + #ifdef SSL_R_NO_CIPHERS_AVAILABLE + {"NO_CIPHERS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_CIPHERS_AVAILABLE}, + #else + {"NO_CIPHERS_AVAILABLE", 20, 181}, + #endif + #ifdef SSL_R_NO_CIPHERS_SPECIFIED + {"NO_CIPHERS_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_CIPHERS_SPECIFIED}, + #else + {"NO_CIPHERS_SPECIFIED", 20, 183}, + #endif + #ifdef SSL_R_NO_CIPHER_MATCH + {"NO_CIPHER_MATCH", ERR_LIB_SSL, SSL_R_NO_CIPHER_MATCH}, + #else + {"NO_CIPHER_MATCH", 20, 185}, + #endif + #ifdef SSL_R_NO_CLIENT_CERT_METHOD + {"NO_CLIENT_CERT_METHOD", ERR_LIB_SSL, SSL_R_NO_CLIENT_CERT_METHOD}, + #else + {"NO_CLIENT_CERT_METHOD", 20, 331}, + #endif + #ifdef SSL_R_NO_COMPRESSION_SPECIFIED + {"NO_COMPRESSION_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_COMPRESSION_SPECIFIED}, + #else + {"NO_COMPRESSION_SPECIFIED", 20, 187}, + #endif + #ifdef SSL_R_NO_COOKIE_CALLBACK_SET + {"NO_COOKIE_CALLBACK_SET", ERR_LIB_SSL, SSL_R_NO_COOKIE_CALLBACK_SET}, + #else + {"NO_COOKIE_CALLBACK_SET", 20, 287}, + #endif + #ifdef SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER + {"NO_GOST_CERTIFICATE_SENT_BY_PEER", ERR_LIB_SSL, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER}, + #else + {"NO_GOST_CERTIFICATE_SENT_BY_PEER", 20, 330}, + #endif + #ifdef SSL_R_NO_METHOD_SPECIFIED + {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED}, + #else + {"NO_METHOD_SPECIFIED", 20, 188}, + #endif + #ifdef SSL_R_NO_PEM_EXTENSIONS + {"NO_PEM_EXTENSIONS", ERR_LIB_SSL, SSL_R_NO_PEM_EXTENSIONS}, + #else + {"NO_PEM_EXTENSIONS", 20, 389}, + #endif + #ifdef SSL_R_NO_PRIVATE_KEY_ASSIGNED + {"NO_PRIVATE_KEY_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED}, + #else + {"NO_PRIVATE_KEY_ASSIGNED", 20, 190}, + #endif + #ifdef SSL_R_NO_PROTOCOLS_AVAILABLE + {"NO_PROTOCOLS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_PROTOCOLS_AVAILABLE}, + #else + {"NO_PROTOCOLS_AVAILABLE", 20, 191}, + #endif + #ifdef SSL_R_NO_RENEGOTIATION + {"NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_NO_RENEGOTIATION}, + #else + {"NO_RENEGOTIATION", 20, 339}, + #endif + #ifdef SSL_R_NO_REQUIRED_DIGEST + {"NO_REQUIRED_DIGEST", ERR_LIB_SSL, SSL_R_NO_REQUIRED_DIGEST}, + #else + {"NO_REQUIRED_DIGEST", 20, 324}, + #endif + #ifdef SSL_R_NO_SHARED_CIPHER + {"NO_SHARED_CIPHER", ERR_LIB_SSL, SSL_R_NO_SHARED_CIPHER}, + #else + {"NO_SHARED_CIPHER", 20, 193}, + #endif + #ifdef SSL_R_NO_SHARED_GROUPS + {"NO_SHARED_GROUPS", ERR_LIB_SSL, SSL_R_NO_SHARED_GROUPS}, + #else + {"NO_SHARED_GROUPS", 20, 410}, + #endif + #ifdef SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS + {"NO_SHARED_SIGNATURE_ALGORITHMS", ERR_LIB_SSL, SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS}, + #else + {"NO_SHARED_SIGNATURE_ALGORITHMS", 20, 376}, + #endif + #ifdef SSL_R_NO_SRTP_PROFILES + {"NO_SRTP_PROFILES", ERR_LIB_SSL, SSL_R_NO_SRTP_PROFILES}, + #else + {"NO_SRTP_PROFILES", 20, 359}, + #endif + #ifdef SSL_R_NO_SUITABLE_DIGEST_ALGORITHM + {"NO_SUITABLE_DIGEST_ALGORITHM", ERR_LIB_SSL, SSL_R_NO_SUITABLE_DIGEST_ALGORITHM}, + #else + {"NO_SUITABLE_DIGEST_ALGORITHM", 20, 297}, + #endif + #ifdef SSL_R_NO_SUITABLE_GROUPS + {"NO_SUITABLE_GROUPS", ERR_LIB_SSL, SSL_R_NO_SUITABLE_GROUPS}, + #else + {"NO_SUITABLE_GROUPS", 20, 295}, + #endif + #ifdef SSL_R_NO_SUITABLE_KEY_SHARE + {"NO_SUITABLE_KEY_SHARE", ERR_LIB_SSL, SSL_R_NO_SUITABLE_KEY_SHARE}, + #else + {"NO_SUITABLE_KEY_SHARE", 20, 101}, + #endif + #ifdef SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM + {"NO_SUITABLE_SIGNATURE_ALGORITHM", ERR_LIB_SSL, SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM}, + #else + {"NO_SUITABLE_SIGNATURE_ALGORITHM", 20, 118}, + #endif + #ifdef SSL_R_NO_VALID_SCTS + {"NO_VALID_SCTS", ERR_LIB_SSL, SSL_R_NO_VALID_SCTS}, + #else + {"NO_VALID_SCTS", 20, 216}, + #endif + #ifdef SSL_R_NO_VERIFY_COOKIE_CALLBACK + {"NO_VERIFY_COOKIE_CALLBACK", ERR_LIB_SSL, SSL_R_NO_VERIFY_COOKIE_CALLBACK}, + #else + {"NO_VERIFY_COOKIE_CALLBACK", 20, 403}, + #endif + #ifdef SSL_R_NULL_SSL_CTX + {"NULL_SSL_CTX", ERR_LIB_SSL, SSL_R_NULL_SSL_CTX}, + #else + {"NULL_SSL_CTX", 20, 195}, + #endif + #ifdef SSL_R_NULL_SSL_METHOD_PASSED + {"NULL_SSL_METHOD_PASSED", ERR_LIB_SSL, SSL_R_NULL_SSL_METHOD_PASSED}, + #else + {"NULL_SSL_METHOD_PASSED", 20, 196}, + #endif + #ifdef SSL_R_OCSP_CALLBACK_FAILURE + {"OCSP_CALLBACK_FAILURE", ERR_LIB_SSL, SSL_R_OCSP_CALLBACK_FAILURE}, + #else + {"OCSP_CALLBACK_FAILURE", 20, 305}, + #endif + #ifdef SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED + {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED}, + #else + {"OLD_SESSION_CIPHER_NOT_RETURNED", 20, 197}, + #endif + #ifdef SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED + {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED}, + #else + {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", 20, 344}, + #endif + #ifdef SSL_R_OVERFLOW_ERROR + {"OVERFLOW_ERROR", ERR_LIB_SSL, SSL_R_OVERFLOW_ERROR}, + #else + {"OVERFLOW_ERROR", 20, 237}, + #endif + #ifdef SSL_R_PACKET_LENGTH_TOO_LONG + {"PACKET_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PACKET_LENGTH_TOO_LONG}, + #else + {"PACKET_LENGTH_TOO_LONG", 20, 198}, + #endif + #ifdef SSL_R_PARSE_TLSEXT + {"PARSE_TLSEXT", ERR_LIB_SSL, SSL_R_PARSE_TLSEXT}, + #else + {"PARSE_TLSEXT", 20, 227}, + #endif + #ifdef SSL_R_PATH_TOO_LONG + {"PATH_TOO_LONG", ERR_LIB_SSL, SSL_R_PATH_TOO_LONG}, + #else + {"PATH_TOO_LONG", 20, 270}, + #endif + #ifdef SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE + {"PEER_DID_NOT_RETURN_A_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE}, + #else + {"PEER_DID_NOT_RETURN_A_CERTIFICATE", 20, 199}, + #endif + #ifdef SSL_R_PEM_NAME_BAD_PREFIX + {"PEM_NAME_BAD_PREFIX", ERR_LIB_SSL, SSL_R_PEM_NAME_BAD_PREFIX}, + #else + {"PEM_NAME_BAD_PREFIX", 20, 391}, + #endif + #ifdef SSL_R_PEM_NAME_TOO_SHORT + {"PEM_NAME_TOO_SHORT", ERR_LIB_SSL, SSL_R_PEM_NAME_TOO_SHORT}, + #else + {"PEM_NAME_TOO_SHORT", 20, 392}, + #endif + #ifdef SSL_R_PIPELINE_FAILURE + {"PIPELINE_FAILURE", ERR_LIB_SSL, SSL_R_PIPELINE_FAILURE}, + #else + {"PIPELINE_FAILURE", 20, 406}, + #endif + #ifdef SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR + {"POST_HANDSHAKE_AUTH_ENCODING_ERR", ERR_LIB_SSL, SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR}, + #else + {"POST_HANDSHAKE_AUTH_ENCODING_ERR", 20, 278}, + #endif + #ifdef SSL_R_PRIVATE_KEY_MISMATCH + {"PRIVATE_KEY_MISMATCH", ERR_LIB_SSL, SSL_R_PRIVATE_KEY_MISMATCH}, + #else + {"PRIVATE_KEY_MISMATCH", 20, 288}, + #endif + #ifdef SSL_R_PROTOCOL_IS_SHUTDOWN + {"PROTOCOL_IS_SHUTDOWN", ERR_LIB_SSL, SSL_R_PROTOCOL_IS_SHUTDOWN}, + #else + {"PROTOCOL_IS_SHUTDOWN", 20, 207}, + #endif + #ifdef SSL_R_PSK_IDENTITY_NOT_FOUND + {"PSK_IDENTITY_NOT_FOUND", ERR_LIB_SSL, SSL_R_PSK_IDENTITY_NOT_FOUND}, + #else + {"PSK_IDENTITY_NOT_FOUND", 20, 223}, + #endif + #ifdef SSL_R_PSK_NO_CLIENT_CB + {"PSK_NO_CLIENT_CB", ERR_LIB_SSL, SSL_R_PSK_NO_CLIENT_CB}, + #else + {"PSK_NO_CLIENT_CB", 20, 224}, + #endif + #ifdef SSL_R_PSK_NO_SERVER_CB + {"PSK_NO_SERVER_CB", ERR_LIB_SSL, SSL_R_PSK_NO_SERVER_CB}, + #else + {"PSK_NO_SERVER_CB", 20, 225}, + #endif + #ifdef SSL_R_READ_BIO_NOT_SET + {"READ_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_READ_BIO_NOT_SET}, + #else + {"READ_BIO_NOT_SET", 20, 211}, + #endif + #ifdef SSL_R_READ_TIMEOUT_EXPIRED + {"READ_TIMEOUT_EXPIRED", ERR_LIB_SSL, SSL_R_READ_TIMEOUT_EXPIRED}, + #else + {"READ_TIMEOUT_EXPIRED", 20, 312}, + #endif + #ifdef SSL_R_RECORD_LENGTH_MISMATCH + {"RECORD_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_RECORD_LENGTH_MISMATCH}, + #else + {"RECORD_LENGTH_MISMATCH", 20, 213}, + #endif + #ifdef SSL_R_RECORD_TOO_SMALL + {"RECORD_TOO_SMALL", ERR_LIB_SSL, SSL_R_RECORD_TOO_SMALL}, + #else + {"RECORD_TOO_SMALL", 20, 298}, + #endif + #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG + {"RENEGOTIATE_EXT_TOO_LONG", ERR_LIB_SSL, SSL_R_RENEGOTIATE_EXT_TOO_LONG}, + #else + {"RENEGOTIATE_EXT_TOO_LONG", 20, 335}, + #endif + #ifdef SSL_R_RENEGOTIATION_ENCODING_ERR + {"RENEGOTIATION_ENCODING_ERR", ERR_LIB_SSL, SSL_R_RENEGOTIATION_ENCODING_ERR}, + #else + {"RENEGOTIATION_ENCODING_ERR", 20, 336}, + #endif + #ifdef SSL_R_RENEGOTIATION_MISMATCH + {"RENEGOTIATION_MISMATCH", ERR_LIB_SSL, SSL_R_RENEGOTIATION_MISMATCH}, + #else + {"RENEGOTIATION_MISMATCH", 20, 337}, + #endif + #ifdef SSL_R_REQUEST_PENDING + {"REQUEST_PENDING", ERR_LIB_SSL, SSL_R_REQUEST_PENDING}, + #else + {"REQUEST_PENDING", 20, 285}, + #endif + #ifdef SSL_R_REQUEST_SENT + {"REQUEST_SENT", ERR_LIB_SSL, SSL_R_REQUEST_SENT}, + #else + {"REQUEST_SENT", 20, 286}, + #endif + #ifdef SSL_R_REQUIRED_CIPHER_MISSING + {"REQUIRED_CIPHER_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_CIPHER_MISSING}, + #else + {"REQUIRED_CIPHER_MISSING", 20, 215}, + #endif + #ifdef SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING + {"REQUIRED_COMPRESSION_ALGORITHM_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING}, + #else + {"REQUIRED_COMPRESSION_ALGORITHM_MISSING", 20, 342}, + #endif + #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING + {"SCSV_RECEIVED_WHEN_RENEGOTIATING", ERR_LIB_SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING}, + #else + {"SCSV_RECEIVED_WHEN_RENEGOTIATING", 20, 345}, + #endif + #ifdef SSL_R_SCT_VERIFICATION_FAILED + {"SCT_VERIFICATION_FAILED", ERR_LIB_SSL, SSL_R_SCT_VERIFICATION_FAILED}, + #else + {"SCT_VERIFICATION_FAILED", 20, 208}, + #endif + #ifdef SSL_R_SERVERHELLO_TLSEXT + {"SERVERHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_SERVERHELLO_TLSEXT}, + #else + {"SERVERHELLO_TLSEXT", 20, 275}, + #endif + #ifdef SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED + {"SESSION_ID_CONTEXT_UNINITIALIZED", ERR_LIB_SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED}, + #else + {"SESSION_ID_CONTEXT_UNINITIALIZED", 20, 277}, + #endif + #ifdef SSL_R_SHUTDOWN_WHILE_IN_INIT + {"SHUTDOWN_WHILE_IN_INIT", ERR_LIB_SSL, SSL_R_SHUTDOWN_WHILE_IN_INIT}, + #else + {"SHUTDOWN_WHILE_IN_INIT", 20, 407}, + #endif + #ifdef SSL_R_SIGNATURE_ALGORITHMS_ERROR + {"SIGNATURE_ALGORITHMS_ERROR", ERR_LIB_SSL, SSL_R_SIGNATURE_ALGORITHMS_ERROR}, + #else + {"SIGNATURE_ALGORITHMS_ERROR", 20, 360}, + #endif + #ifdef SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE + {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE}, + #else + {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", 20, 220}, + #endif + #ifdef SSL_R_SRP_A_CALC + {"SRP_A_CALC", ERR_LIB_SSL, SSL_R_SRP_A_CALC}, + #else + {"SRP_A_CALC", 20, 361}, + #endif + #ifdef SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES + {"SRTP_COULD_NOT_ALLOCATE_PROFILES", ERR_LIB_SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES}, + #else + {"SRTP_COULD_NOT_ALLOCATE_PROFILES", 20, 362}, + #endif + #ifdef SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG + {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", ERR_LIB_SSL, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG}, + #else + {"SRTP_PROTECTION_PROFILE_LIST_TOO_LONG", 20, 363}, + #endif + #ifdef SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE + {"SRTP_UNKNOWN_PROTECTION_PROFILE", ERR_LIB_SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE}, + #else + {"SRTP_UNKNOWN_PROTECTION_PROFILE", 20, 364}, + #endif + #ifdef SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH + {"SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH}, + #else + {"SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH", 20, 232}, + #endif + #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME + {"SSL3_EXT_INVALID_SERVERNAME", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME}, + #else + {"SSL3_EXT_INVALID_SERVERNAME", 20, 319}, + #endif + #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE + {"SSL3_EXT_INVALID_SERVERNAME_TYPE", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE}, + #else + {"SSL3_EXT_INVALID_SERVERNAME_TYPE", 20, 320}, + #endif + #ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG + {"SSL3_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL3_SESSION_ID_TOO_LONG}, + #else + {"SSL3_SESSION_ID_TOO_LONG", 20, 300}, + #endif + #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE + {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE}, + #else + {"SSLV3_ALERT_BAD_CERTIFICATE", 20, 1042}, + #endif + #ifdef SSL_R_SSLV3_ALERT_BAD_RECORD_MAC + {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC}, + #else + {"SSLV3_ALERT_BAD_RECORD_MAC", 20, 1020}, + #endif + #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED + {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED}, + #else + {"SSLV3_ALERT_CERTIFICATE_EXPIRED", 20, 1045}, + #endif + #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED + {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED}, + #else + {"SSLV3_ALERT_CERTIFICATE_REVOKED", 20, 1044}, + #endif + #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN + {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN}, + #else + {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", 20, 1046}, + #endif + #ifdef SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE + {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE}, + #else + {"SSLV3_ALERT_DECOMPRESSION_FAILURE", 20, 1030}, + #endif + #ifdef SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE + {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE}, + #else + {"SSLV3_ALERT_HANDSHAKE_FAILURE", 20, 1040}, + #endif + #ifdef SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER + {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER}, + #else + {"SSLV3_ALERT_ILLEGAL_PARAMETER", 20, 1047}, + #endif + #ifdef SSL_R_SSLV3_ALERT_NO_CERTIFICATE + {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_NO_CERTIFICATE}, + #else + {"SSLV3_ALERT_NO_CERTIFICATE", 20, 1041}, + #endif + #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE + {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE}, + #else + {"SSLV3_ALERT_UNEXPECTED_MESSAGE", 20, 1010}, + #endif + #ifdef SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE + {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE}, + #else + {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", 20, 1043}, + #endif + #ifdef SSL_R_SSL_COMMAND_SECTION_EMPTY + {"SSL_COMMAND_SECTION_EMPTY", ERR_LIB_SSL, SSL_R_SSL_COMMAND_SECTION_EMPTY}, + #else + {"SSL_COMMAND_SECTION_EMPTY", 20, 117}, + #endif + #ifdef SSL_R_SSL_COMMAND_SECTION_NOT_FOUND + {"SSL_COMMAND_SECTION_NOT_FOUND", ERR_LIB_SSL, SSL_R_SSL_COMMAND_SECTION_NOT_FOUND}, + #else + {"SSL_COMMAND_SECTION_NOT_FOUND", 20, 125}, + #endif + #ifdef SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION + {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", ERR_LIB_SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION}, + #else + {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", 20, 228}, + #endif + #ifdef SSL_R_SSL_HANDSHAKE_FAILURE + {"SSL_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSL_HANDSHAKE_FAILURE}, + #else + {"SSL_HANDSHAKE_FAILURE", 20, 229}, + #endif + #ifdef SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS + {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS}, + #else + {"SSL_LIBRARY_HAS_NO_CIPHERS", 20, 230}, + #endif + #ifdef SSL_R_SSL_NEGATIVE_LENGTH + {"SSL_NEGATIVE_LENGTH", ERR_LIB_SSL, SSL_R_SSL_NEGATIVE_LENGTH}, + #else + {"SSL_NEGATIVE_LENGTH", 20, 372}, + #endif + #ifdef SSL_R_SSL_SECTION_EMPTY + {"SSL_SECTION_EMPTY", ERR_LIB_SSL, SSL_R_SSL_SECTION_EMPTY}, + #else + {"SSL_SECTION_EMPTY", 20, 126}, + #endif + #ifdef SSL_R_SSL_SECTION_NOT_FOUND + {"SSL_SECTION_NOT_FOUND", ERR_LIB_SSL, SSL_R_SSL_SECTION_NOT_FOUND}, + #else + {"SSL_SECTION_NOT_FOUND", 20, 136}, + #endif + #ifdef SSL_R_SSL_SESSION_ID_CALLBACK_FAILED + {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED}, + #else + {"SSL_SESSION_ID_CALLBACK_FAILED", 20, 301}, + #endif + #ifdef SSL_R_SSL_SESSION_ID_CONFLICT + {"SSL_SESSION_ID_CONFLICT", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONFLICT}, + #else + {"SSL_SESSION_ID_CONFLICT", 20, 302}, + #endif + #ifdef SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG + {"SSL_SESSION_ID_CONTEXT_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG}, + #else + {"SSL_SESSION_ID_CONTEXT_TOO_LONG", 20, 273}, + #endif + #ifdef SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH + {"SSL_SESSION_ID_HAS_BAD_LENGTH", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH}, + #else + {"SSL_SESSION_ID_HAS_BAD_LENGTH", 20, 303}, + #endif + #ifdef SSL_R_SSL_SESSION_ID_TOO_LONG + {"SSL_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_TOO_LONG}, + #else + {"SSL_SESSION_ID_TOO_LONG", 20, 408}, + #endif + #ifdef SSL_R_SSL_SESSION_VERSION_MISMATCH + {"SSL_SESSION_VERSION_MISMATCH", ERR_LIB_SSL, SSL_R_SSL_SESSION_VERSION_MISMATCH}, + #else + {"SSL_SESSION_VERSION_MISMATCH", 20, 210}, + #endif + #ifdef SSL_R_STILL_IN_INIT + {"STILL_IN_INIT", ERR_LIB_SSL, SSL_R_STILL_IN_INIT}, + #else + {"STILL_IN_INIT", 20, 121}, + #endif + #ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED + {"TLSV13_ALERT_CERTIFICATE_REQUIRED", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED}, + #else + {"TLSV13_ALERT_CERTIFICATE_REQUIRED", 20, 1116}, + #endif + #ifdef SSL_R_TLSV13_ALERT_MISSING_EXTENSION + {"TLSV13_ALERT_MISSING_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV13_ALERT_MISSING_EXTENSION}, + #else + {"TLSV13_ALERT_MISSING_EXTENSION", 20, 1109}, + #endif + #ifdef SSL_R_TLSV1_ALERT_ACCESS_DENIED + {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_ACCESS_DENIED}, + #else + {"TLSV1_ALERT_ACCESS_DENIED", 20, 1049}, + #endif + #ifdef SSL_R_TLSV1_ALERT_DECODE_ERROR + {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECODE_ERROR}, + #else + {"TLSV1_ALERT_DECODE_ERROR", 20, 1050}, + #endif + #ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED + {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED}, + #else + {"TLSV1_ALERT_DECRYPTION_FAILED", 20, 1021}, + #endif + #ifdef SSL_R_TLSV1_ALERT_DECRYPT_ERROR + {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPT_ERROR}, + #else + {"TLSV1_ALERT_DECRYPT_ERROR", 20, 1051}, + #endif + #ifdef SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION + {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION}, + #else + {"TLSV1_ALERT_EXPORT_RESTRICTION", 20, 1060}, + #endif + #ifdef SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK + {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK}, + #else + {"TLSV1_ALERT_INAPPROPRIATE_FALLBACK", 20, 1086}, + #endif + #ifdef SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY + {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY}, + #else + {"TLSV1_ALERT_INSUFFICIENT_SECURITY", 20, 1071}, + #endif + #ifdef SSL_R_TLSV1_ALERT_INTERNAL_ERROR + {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INTERNAL_ERROR}, + #else + {"TLSV1_ALERT_INTERNAL_ERROR", 20, 1080}, + #endif + #ifdef SSL_R_TLSV1_ALERT_NO_RENEGOTIATION + {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION}, + #else + {"TLSV1_ALERT_NO_RENEGOTIATION", 20, 1100}, + #endif + #ifdef SSL_R_TLSV1_ALERT_PROTOCOL_VERSION + {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION}, + #else + {"TLSV1_ALERT_PROTOCOL_VERSION", 20, 1070}, + #endif + #ifdef SSL_R_TLSV1_ALERT_RECORD_OVERFLOW + {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW}, + #else + {"TLSV1_ALERT_RECORD_OVERFLOW", 20, 1022}, + #endif + #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA + {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_CA}, + #else + {"TLSV1_ALERT_UNKNOWN_CA", 20, 1048}, + #endif + #ifdef SSL_R_TLSV1_ALERT_USER_CANCELLED + {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_USER_CANCELLED}, + #else + {"TLSV1_ALERT_USER_CANCELLED", 20, 1090}, + #endif + #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE + {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE}, + #else + {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", 20, 1114}, + #endif + #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE + {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE}, + #else + {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", 20, 1113}, + #endif + #ifdef SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE + {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE}, + #else + {"TLSV1_CERTIFICATE_UNOBTAINABLE", 20, 1111}, + #endif + #ifdef SSL_R_TLSV1_UNRECOGNIZED_NAME + {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, SSL_R_TLSV1_UNRECOGNIZED_NAME}, + #else + {"TLSV1_UNRECOGNIZED_NAME", 20, 1112}, + #endif + #ifdef SSL_R_TLSV1_UNSUPPORTED_EXTENSION + {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV1_UNSUPPORTED_EXTENSION}, + #else + {"TLSV1_UNSUPPORTED_EXTENSION", 20, 1110}, + #endif + #ifdef SSL_R_TLS_ILLEGAL_EXPORTER_LABEL + {"TLS_ILLEGAL_EXPORTER_LABEL", ERR_LIB_SSL, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL}, + #else + {"TLS_ILLEGAL_EXPORTER_LABEL", 20, 367}, + #endif + #ifdef SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST + {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST}, + #else + {"TLS_INVALID_ECPOINTFORMAT_LIST", 20, 157}, + #endif + #ifdef SSL_R_TOO_MANY_KEY_UPDATES + {"TOO_MANY_KEY_UPDATES", ERR_LIB_SSL, SSL_R_TOO_MANY_KEY_UPDATES}, + #else + {"TOO_MANY_KEY_UPDATES", 20, 132}, + #endif + #ifdef SSL_R_TOO_MANY_WARN_ALERTS + {"TOO_MANY_WARN_ALERTS", ERR_LIB_SSL, SSL_R_TOO_MANY_WARN_ALERTS}, + #else + {"TOO_MANY_WARN_ALERTS", 20, 409}, + #endif + #ifdef SSL_R_TOO_MUCH_EARLY_DATA + {"TOO_MUCH_EARLY_DATA", ERR_LIB_SSL, SSL_R_TOO_MUCH_EARLY_DATA}, + #else + {"TOO_MUCH_EARLY_DATA", 20, 164}, + #endif + #ifdef SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS + {"UNABLE_TO_FIND_ECDH_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS}, + #else + {"UNABLE_TO_FIND_ECDH_PARAMETERS", 20, 314}, + #endif + #ifdef SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS + {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS}, + #else + {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", 20, 239}, + #endif + #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES + {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES}, + #else + {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", 20, 242}, + #endif + #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES + {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES}, + #else + {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", 20, 243}, + #endif + #ifdef SSL_R_UNEXPECTED_CCS_MESSAGE + {"UNEXPECTED_CCS_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_CCS_MESSAGE}, + #else + {"UNEXPECTED_CCS_MESSAGE", 20, 262}, + #endif + #ifdef SSL_R_UNEXPECTED_END_OF_EARLY_DATA + {"UNEXPECTED_END_OF_EARLY_DATA", ERR_LIB_SSL, SSL_R_UNEXPECTED_END_OF_EARLY_DATA}, + #else + {"UNEXPECTED_END_OF_EARLY_DATA", 20, 178}, + #endif + #ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING + {"UNEXPECTED_EOF_WHILE_READING", ERR_LIB_SSL, SSL_R_UNEXPECTED_EOF_WHILE_READING}, + #else + {"UNEXPECTED_EOF_WHILE_READING", 20, 294}, + #endif + #ifdef SSL_R_UNEXPECTED_MESSAGE + {"UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE}, + #else + {"UNEXPECTED_MESSAGE", 20, 244}, + #endif + #ifdef SSL_R_UNEXPECTED_RECORD + {"UNEXPECTED_RECORD", ERR_LIB_SSL, SSL_R_UNEXPECTED_RECORD}, + #else + {"UNEXPECTED_RECORD", 20, 245}, + #endif + #ifdef SSL_R_UNINITIALIZED + {"UNINITIALIZED", ERR_LIB_SSL, SSL_R_UNINITIALIZED}, + #else + {"UNINITIALIZED", 20, 276}, + #endif + #ifdef SSL_R_UNKNOWN_ALERT_TYPE + {"UNKNOWN_ALERT_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_ALERT_TYPE}, + #else + {"UNKNOWN_ALERT_TYPE", 20, 246}, + #endif + #ifdef SSL_R_UNKNOWN_CERTIFICATE_TYPE + {"UNKNOWN_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE}, + #else + {"UNKNOWN_CERTIFICATE_TYPE", 20, 247}, + #endif + #ifdef SSL_R_UNKNOWN_CIPHER_RETURNED + {"UNKNOWN_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_RETURNED}, + #else + {"UNKNOWN_CIPHER_RETURNED", 20, 248}, + #endif + #ifdef SSL_R_UNKNOWN_CIPHER_TYPE + {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_TYPE}, + #else + {"UNKNOWN_CIPHER_TYPE", 20, 249}, + #endif + #ifdef SSL_R_UNKNOWN_CMD_NAME + {"UNKNOWN_CMD_NAME", ERR_LIB_SSL, SSL_R_UNKNOWN_CMD_NAME}, + #else + {"UNKNOWN_CMD_NAME", 20, 386}, + #endif + #ifdef SSL_R_UNKNOWN_COMMAND + {"UNKNOWN_COMMAND", ERR_LIB_SSL, SSL_R_UNKNOWN_COMMAND}, + #else + {"UNKNOWN_COMMAND", 20, 139}, + #endif + #ifdef SSL_R_UNKNOWN_DIGEST + {"UNKNOWN_DIGEST", ERR_LIB_SSL, SSL_R_UNKNOWN_DIGEST}, + #else + {"UNKNOWN_DIGEST", 20, 368}, + #endif + #ifdef SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE + {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE}, + #else + {"UNKNOWN_KEY_EXCHANGE_TYPE", 20, 250}, + #endif + #ifdef SSL_R_UNKNOWN_PKEY_TYPE + {"UNKNOWN_PKEY_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_PKEY_TYPE}, + #else + {"UNKNOWN_PKEY_TYPE", 20, 251}, + #endif + #ifdef SSL_R_UNKNOWN_PROTOCOL + {"UNKNOWN_PROTOCOL", ERR_LIB_SSL, SSL_R_UNKNOWN_PROTOCOL}, + #else + {"UNKNOWN_PROTOCOL", 20, 252}, + #endif + #ifdef SSL_R_UNKNOWN_SSL_VERSION + {"UNKNOWN_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNKNOWN_SSL_VERSION}, + #else + {"UNKNOWN_SSL_VERSION", 20, 254}, + #endif + #ifdef SSL_R_UNKNOWN_STATE + {"UNKNOWN_STATE", ERR_LIB_SSL, SSL_R_UNKNOWN_STATE}, + #else + {"UNKNOWN_STATE", 20, 255}, + #endif + #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED + {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", ERR_LIB_SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED}, + #else + {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", 20, 338}, + #endif + #ifdef SSL_R_UNSOLICITED_EXTENSION + {"UNSOLICITED_EXTENSION", ERR_LIB_SSL, SSL_R_UNSOLICITED_EXTENSION}, + #else + {"UNSOLICITED_EXTENSION", 20, 217}, + #endif + #ifdef SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM + {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, + #else + {"UNSUPPORTED_COMPRESSION_ALGORITHM", 20, 257}, + #endif + #ifdef SSL_R_UNSUPPORTED_ELLIPTIC_CURVE + {"UNSUPPORTED_ELLIPTIC_CURVE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE}, + #else + {"UNSUPPORTED_ELLIPTIC_CURVE", 20, 315}, + #endif + #ifdef SSL_R_UNSUPPORTED_PROTOCOL + {"UNSUPPORTED_PROTOCOL", ERR_LIB_SSL, SSL_R_UNSUPPORTED_PROTOCOL}, + #else + {"UNSUPPORTED_PROTOCOL", 20, 258}, + #endif + #ifdef SSL_R_UNSUPPORTED_SSL_VERSION + {"UNSUPPORTED_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNSUPPORTED_SSL_VERSION}, + #else + {"UNSUPPORTED_SSL_VERSION", 20, 259}, + #endif + #ifdef SSL_R_UNSUPPORTED_STATUS_TYPE + {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_STATUS_TYPE}, + #else + {"UNSUPPORTED_STATUS_TYPE", 20, 329}, + #endif + #ifdef SSL_R_USE_SRTP_NOT_NEGOTIATED + {"USE_SRTP_NOT_NEGOTIATED", ERR_LIB_SSL, SSL_R_USE_SRTP_NOT_NEGOTIATED}, + #else + {"USE_SRTP_NOT_NEGOTIATED", 20, 369}, + #endif + #ifdef SSL_R_VERSION_TOO_HIGH + {"VERSION_TOO_HIGH", ERR_LIB_SSL, SSL_R_VERSION_TOO_HIGH}, + #else + {"VERSION_TOO_HIGH", 20, 166}, + #endif + #ifdef SSL_R_VERSION_TOO_LOW + {"VERSION_TOO_LOW", ERR_LIB_SSL, SSL_R_VERSION_TOO_LOW}, + #else + {"VERSION_TOO_LOW", 20, 396}, + #endif + #ifdef SSL_R_WRONG_CERTIFICATE_TYPE + {"WRONG_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_CERTIFICATE_TYPE}, + #else + {"WRONG_CERTIFICATE_TYPE", 20, 383}, + #endif + #ifdef SSL_R_WRONG_CIPHER_RETURNED + {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_WRONG_CIPHER_RETURNED}, + #else + {"WRONG_CIPHER_RETURNED", 20, 261}, + #endif + #ifdef SSL_R_WRONG_CURVE + {"WRONG_CURVE", ERR_LIB_SSL, SSL_R_WRONG_CURVE}, + #else + {"WRONG_CURVE", 20, 378}, + #endif + #ifdef SSL_R_WRONG_SIGNATURE_LENGTH + {"WRONG_SIGNATURE_LENGTH", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_LENGTH}, + #else + {"WRONG_SIGNATURE_LENGTH", 20, 264}, + #endif + #ifdef SSL_R_WRONG_SIGNATURE_SIZE + {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_SIZE}, + #else + {"WRONG_SIGNATURE_SIZE", 20, 265}, + #endif + #ifdef SSL_R_WRONG_SIGNATURE_TYPE + {"WRONG_SIGNATURE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_TYPE}, + #else + {"WRONG_SIGNATURE_TYPE", 20, 370}, + #endif + #ifdef SSL_R_WRONG_SSL_VERSION + {"WRONG_SSL_VERSION", ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION}, + #else + {"WRONG_SSL_VERSION", 20, 266}, + #endif + #ifdef SSL_R_WRONG_VERSION_NUMBER + {"WRONG_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_WRONG_VERSION_NUMBER}, + #else + {"WRONG_VERSION_NUMBER", 20, 267}, + #endif + #ifdef SSL_R_X509_LIB + {"X509_LIB", ERR_LIB_SSL, SSL_R_X509_LIB}, + #else + {"X509_LIB", 20, 268}, + #endif + #ifdef SSL_R_X509_VERIFICATION_SETUP_PROBLEMS + {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS}, + #else + {"X509_VERIFICATION_SETUP_PROBLEMS", 20, 269}, + #endif + #ifdef TS_R_BAD_PKCS7_TYPE + {"BAD_PKCS7_TYPE", ERR_LIB_TS, TS_R_BAD_PKCS7_TYPE}, + #else + {"BAD_PKCS7_TYPE", 47, 132}, + #endif + #ifdef TS_R_BAD_TYPE + {"BAD_TYPE", ERR_LIB_TS, TS_R_BAD_TYPE}, + #else + {"BAD_TYPE", 47, 133}, + #endif + #ifdef TS_R_CANNOT_LOAD_CERT + {"CANNOT_LOAD_CERT", ERR_LIB_TS, TS_R_CANNOT_LOAD_CERT}, + #else + {"CANNOT_LOAD_CERT", 47, 137}, + #endif + #ifdef TS_R_CANNOT_LOAD_KEY + {"CANNOT_LOAD_KEY", ERR_LIB_TS, TS_R_CANNOT_LOAD_KEY}, + #else + {"CANNOT_LOAD_KEY", 47, 138}, + #endif + #ifdef TS_R_CERTIFICATE_VERIFY_ERROR + {"CERTIFICATE_VERIFY_ERROR", ERR_LIB_TS, TS_R_CERTIFICATE_VERIFY_ERROR}, + #else + {"CERTIFICATE_VERIFY_ERROR", 47, 100}, + #endif + #ifdef TS_R_COULD_NOT_SET_ENGINE + {"COULD_NOT_SET_ENGINE", ERR_LIB_TS, TS_R_COULD_NOT_SET_ENGINE}, + #else + {"COULD_NOT_SET_ENGINE", 47, 127}, + #endif + #ifdef TS_R_COULD_NOT_SET_TIME + {"COULD_NOT_SET_TIME", ERR_LIB_TS, TS_R_COULD_NOT_SET_TIME}, + #else + {"COULD_NOT_SET_TIME", 47, 115}, + #endif + #ifdef TS_R_DETACHED_CONTENT + {"DETACHED_CONTENT", ERR_LIB_TS, TS_R_DETACHED_CONTENT}, + #else + {"DETACHED_CONTENT", 47, 134}, + #endif + #ifdef TS_R_ESS_ADD_SIGNING_CERT_ERROR + {"ESS_ADD_SIGNING_CERT_ERROR", ERR_LIB_TS, TS_R_ESS_ADD_SIGNING_CERT_ERROR}, + #else + {"ESS_ADD_SIGNING_CERT_ERROR", 47, 116}, + #endif + #ifdef TS_R_ESS_ADD_SIGNING_CERT_V2_ERROR + {"ESS_ADD_SIGNING_CERT_V2_ERROR", ERR_LIB_TS, TS_R_ESS_ADD_SIGNING_CERT_V2_ERROR}, + #else + {"ESS_ADD_SIGNING_CERT_V2_ERROR", 47, 139}, + #endif + #ifdef TS_R_ESS_SIGNING_CERTIFICATE_ERROR + {"ESS_SIGNING_CERTIFICATE_ERROR", ERR_LIB_TS, TS_R_ESS_SIGNING_CERTIFICATE_ERROR}, + #else + {"ESS_SIGNING_CERTIFICATE_ERROR", 47, 101}, + #endif + #ifdef TS_R_INVALID_NULL_POINTER + {"INVALID_NULL_POINTER", ERR_LIB_TS, TS_R_INVALID_NULL_POINTER}, + #else + {"INVALID_NULL_POINTER", 47, 102}, + #endif + #ifdef TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE + {"INVALID_SIGNER_CERTIFICATE_PURPOSE", ERR_LIB_TS, TS_R_INVALID_SIGNER_CERTIFICATE_PURPOSE}, + #else + {"INVALID_SIGNER_CERTIFICATE_PURPOSE", 47, 117}, + #endif + #ifdef TS_R_MESSAGE_IMPRINT_MISMATCH + {"MESSAGE_IMPRINT_MISMATCH", ERR_LIB_TS, TS_R_MESSAGE_IMPRINT_MISMATCH}, + #else + {"MESSAGE_IMPRINT_MISMATCH", 47, 103}, + #endif + #ifdef TS_R_NONCE_MISMATCH + {"NONCE_MISMATCH", ERR_LIB_TS, TS_R_NONCE_MISMATCH}, + #else + {"NONCE_MISMATCH", 47, 104}, + #endif + #ifdef TS_R_NONCE_NOT_RETURNED + {"NONCE_NOT_RETURNED", ERR_LIB_TS, TS_R_NONCE_NOT_RETURNED}, + #else + {"NONCE_NOT_RETURNED", 47, 105}, + #endif + #ifdef TS_R_NO_CONTENT + {"NO_CONTENT", ERR_LIB_TS, TS_R_NO_CONTENT}, + #else + {"NO_CONTENT", 47, 106}, + #endif + #ifdef TS_R_NO_TIME_STAMP_TOKEN + {"NO_TIME_STAMP_TOKEN", ERR_LIB_TS, TS_R_NO_TIME_STAMP_TOKEN}, + #else + {"NO_TIME_STAMP_TOKEN", 47, 107}, + #endif + #ifdef TS_R_PKCS7_ADD_SIGNATURE_ERROR + {"PKCS7_ADD_SIGNATURE_ERROR", ERR_LIB_TS, TS_R_PKCS7_ADD_SIGNATURE_ERROR}, + #else + {"PKCS7_ADD_SIGNATURE_ERROR", 47, 118}, + #endif + #ifdef TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR + {"PKCS7_ADD_SIGNED_ATTR_ERROR", ERR_LIB_TS, TS_R_PKCS7_ADD_SIGNED_ATTR_ERROR}, + #else + {"PKCS7_ADD_SIGNED_ATTR_ERROR", 47, 119}, + #endif + #ifdef TS_R_PKCS7_TO_TS_TST_INFO_FAILED + {"PKCS7_TO_TS_TST_INFO_FAILED", ERR_LIB_TS, TS_R_PKCS7_TO_TS_TST_INFO_FAILED}, + #else + {"PKCS7_TO_TS_TST_INFO_FAILED", 47, 129}, + #endif + #ifdef TS_R_POLICY_MISMATCH + {"POLICY_MISMATCH", ERR_LIB_TS, TS_R_POLICY_MISMATCH}, + #else + {"POLICY_MISMATCH", 47, 108}, + #endif + #ifdef TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", ERR_LIB_TS, TS_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE}, + #else + {"PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE", 47, 120}, + #endif + #ifdef TS_R_RESPONSE_SETUP_ERROR + {"RESPONSE_SETUP_ERROR", ERR_LIB_TS, TS_R_RESPONSE_SETUP_ERROR}, + #else + {"RESPONSE_SETUP_ERROR", 47, 121}, + #endif + #ifdef TS_R_SIGNATURE_FAILURE + {"SIGNATURE_FAILURE", ERR_LIB_TS, TS_R_SIGNATURE_FAILURE}, + #else + {"SIGNATURE_FAILURE", 47, 109}, + #endif + #ifdef TS_R_THERE_MUST_BE_ONE_SIGNER + {"THERE_MUST_BE_ONE_SIGNER", ERR_LIB_TS, TS_R_THERE_MUST_BE_ONE_SIGNER}, + #else + {"THERE_MUST_BE_ONE_SIGNER", 47, 110}, + #endif + #ifdef TS_R_TIME_SYSCALL_ERROR + {"TIME_SYSCALL_ERROR", ERR_LIB_TS, TS_R_TIME_SYSCALL_ERROR}, + #else + {"TIME_SYSCALL_ERROR", 47, 122}, + #endif + #ifdef TS_R_TOKEN_NOT_PRESENT + {"TOKEN_NOT_PRESENT", ERR_LIB_TS, TS_R_TOKEN_NOT_PRESENT}, + #else + {"TOKEN_NOT_PRESENT", 47, 130}, + #endif + #ifdef TS_R_TOKEN_PRESENT + {"TOKEN_PRESENT", ERR_LIB_TS, TS_R_TOKEN_PRESENT}, + #else + {"TOKEN_PRESENT", 47, 131}, + #endif + #ifdef TS_R_TSA_NAME_MISMATCH + {"TSA_NAME_MISMATCH", ERR_LIB_TS, TS_R_TSA_NAME_MISMATCH}, + #else + {"TSA_NAME_MISMATCH", 47, 111}, + #endif + #ifdef TS_R_TSA_UNTRUSTED + {"TSA_UNTRUSTED", ERR_LIB_TS, TS_R_TSA_UNTRUSTED}, + #else + {"TSA_UNTRUSTED", 47, 112}, + #endif + #ifdef TS_R_TST_INFO_SETUP_ERROR + {"TST_INFO_SETUP_ERROR", ERR_LIB_TS, TS_R_TST_INFO_SETUP_ERROR}, + #else + {"TST_INFO_SETUP_ERROR", 47, 123}, + #endif + #ifdef TS_R_TS_DATASIGN + {"TS_DATASIGN", ERR_LIB_TS, TS_R_TS_DATASIGN}, + #else + {"TS_DATASIGN", 47, 124}, + #endif + #ifdef TS_R_UNACCEPTABLE_POLICY + {"UNACCEPTABLE_POLICY", ERR_LIB_TS, TS_R_UNACCEPTABLE_POLICY}, + #else + {"UNACCEPTABLE_POLICY", 47, 125}, + #endif + #ifdef TS_R_UNSUPPORTED_MD_ALGORITHM + {"UNSUPPORTED_MD_ALGORITHM", ERR_LIB_TS, TS_R_UNSUPPORTED_MD_ALGORITHM}, + #else + {"UNSUPPORTED_MD_ALGORITHM", 47, 126}, + #endif + #ifdef TS_R_UNSUPPORTED_VERSION + {"UNSUPPORTED_VERSION", ERR_LIB_TS, TS_R_UNSUPPORTED_VERSION}, + #else + {"UNSUPPORTED_VERSION", 47, 113}, + #endif + #ifdef TS_R_VAR_BAD_VALUE + {"VAR_BAD_VALUE", ERR_LIB_TS, TS_R_VAR_BAD_VALUE}, + #else + {"VAR_BAD_VALUE", 47, 135}, + #endif + #ifdef TS_R_VAR_LOOKUP_FAILURE + {"VAR_LOOKUP_FAILURE", ERR_LIB_TS, TS_R_VAR_LOOKUP_FAILURE}, + #else + {"VAR_LOOKUP_FAILURE", 47, 136}, + #endif + #ifdef TS_R_WRONG_CONTENT_TYPE + {"WRONG_CONTENT_TYPE", ERR_LIB_TS, TS_R_WRONG_CONTENT_TYPE}, + #else + {"WRONG_CONTENT_TYPE", 47, 114}, + #endif + #ifdef UI_R_COMMON_OK_AND_CANCEL_CHARACTERS + {"COMMON_OK_AND_CANCEL_CHARACTERS", ERR_LIB_UI, UI_R_COMMON_OK_AND_CANCEL_CHARACTERS}, + #else + {"COMMON_OK_AND_CANCEL_CHARACTERS", 40, 104}, + #endif + #ifdef UI_R_INDEX_TOO_LARGE + {"INDEX_TOO_LARGE", ERR_LIB_UI, UI_R_INDEX_TOO_LARGE}, + #else + {"INDEX_TOO_LARGE", 40, 102}, + #endif + #ifdef UI_R_INDEX_TOO_SMALL + {"INDEX_TOO_SMALL", ERR_LIB_UI, UI_R_INDEX_TOO_SMALL}, + #else + {"INDEX_TOO_SMALL", 40, 103}, + #endif + #ifdef UI_R_NO_RESULT_BUFFER + {"NO_RESULT_BUFFER", ERR_LIB_UI, UI_R_NO_RESULT_BUFFER}, + #else + {"NO_RESULT_BUFFER", 40, 105}, + #endif + #ifdef UI_R_PROCESSING_ERROR + {"PROCESSING_ERROR", ERR_LIB_UI, UI_R_PROCESSING_ERROR}, + #else + {"PROCESSING_ERROR", 40, 107}, + #endif + #ifdef UI_R_RESULT_TOO_LARGE + {"RESULT_TOO_LARGE", ERR_LIB_UI, UI_R_RESULT_TOO_LARGE}, + #else + {"RESULT_TOO_LARGE", 40, 100}, + #endif + #ifdef UI_R_RESULT_TOO_SMALL + {"RESULT_TOO_SMALL", ERR_LIB_UI, UI_R_RESULT_TOO_SMALL}, + #else + {"RESULT_TOO_SMALL", 40, 101}, + #endif + #ifdef UI_R_SYSASSIGN_ERROR + {"SYSASSIGN_ERROR", ERR_LIB_UI, UI_R_SYSASSIGN_ERROR}, + #else + {"SYSASSIGN_ERROR", 40, 109}, + #endif + #ifdef UI_R_SYSDASSGN_ERROR + {"SYSDASSGN_ERROR", ERR_LIB_UI, UI_R_SYSDASSGN_ERROR}, + #else + {"SYSDASSGN_ERROR", 40, 110}, + #endif + #ifdef UI_R_SYSQIOW_ERROR + {"SYSQIOW_ERROR", ERR_LIB_UI, UI_R_SYSQIOW_ERROR}, + #else + {"SYSQIOW_ERROR", 40, 111}, + #endif + #ifdef UI_R_UNKNOWN_CONTROL_COMMAND + {"UNKNOWN_CONTROL_COMMAND", ERR_LIB_UI, UI_R_UNKNOWN_CONTROL_COMMAND}, + #else + {"UNKNOWN_CONTROL_COMMAND", 40, 106}, + #endif + #ifdef UI_R_UNKNOWN_TTYGET_ERRNO_VALUE + {"UNKNOWN_TTYGET_ERRNO_VALUE", ERR_LIB_UI, UI_R_UNKNOWN_TTYGET_ERRNO_VALUE}, + #else + {"UNKNOWN_TTYGET_ERRNO_VALUE", 40, 108}, + #endif + #ifdef UI_R_USER_DATA_DUPLICATION_UNSUPPORTED + {"USER_DATA_DUPLICATION_UNSUPPORTED", ERR_LIB_UI, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED}, + #else + {"USER_DATA_DUPLICATION_UNSUPPORTED", 40, 112}, + #endif + #ifdef X509V3_R_BAD_IP_ADDRESS + {"BAD_IP_ADDRESS", ERR_LIB_X509V3, X509V3_R_BAD_IP_ADDRESS}, + #else + {"BAD_IP_ADDRESS", 34, 118}, + #endif + #ifdef X509V3_R_BAD_OBJECT + {"BAD_OBJECT", ERR_LIB_X509V3, X509V3_R_BAD_OBJECT}, + #else + {"BAD_OBJECT", 34, 119}, + #endif + #ifdef X509V3_R_BN_DEC2BN_ERROR + {"BN_DEC2BN_ERROR", ERR_LIB_X509V3, X509V3_R_BN_DEC2BN_ERROR}, + #else + {"BN_DEC2BN_ERROR", 34, 100}, + #endif + #ifdef X509V3_R_BN_TO_ASN1_INTEGER_ERROR + {"BN_TO_ASN1_INTEGER_ERROR", ERR_LIB_X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR}, + #else + {"BN_TO_ASN1_INTEGER_ERROR", 34, 101}, + #endif + #ifdef X509V3_R_DIRNAME_ERROR + {"DIRNAME_ERROR", ERR_LIB_X509V3, X509V3_R_DIRNAME_ERROR}, + #else + {"DIRNAME_ERROR", 34, 149}, + #endif + #ifdef X509V3_R_DISTPOINT_ALREADY_SET + {"DISTPOINT_ALREADY_SET", ERR_LIB_X509V3, X509V3_R_DISTPOINT_ALREADY_SET}, + #else + {"DISTPOINT_ALREADY_SET", 34, 160}, + #endif + #ifdef X509V3_R_DUPLICATE_ZONE_ID + {"DUPLICATE_ZONE_ID", ERR_LIB_X509V3, X509V3_R_DUPLICATE_ZONE_ID}, + #else + {"DUPLICATE_ZONE_ID", 34, 133}, + #endif + #ifdef X509V3_R_EMPTY_KEY_USAGE + {"EMPTY_KEY_USAGE", ERR_LIB_X509V3, X509V3_R_EMPTY_KEY_USAGE}, + #else + {"EMPTY_KEY_USAGE", 34, 169}, + #endif + #ifdef X509V3_R_ERROR_CONVERTING_ZONE + {"ERROR_CONVERTING_ZONE", ERR_LIB_X509V3, X509V3_R_ERROR_CONVERTING_ZONE}, + #else + {"ERROR_CONVERTING_ZONE", 34, 131}, + #endif + #ifdef X509V3_R_ERROR_CREATING_EXTENSION + {"ERROR_CREATING_EXTENSION", ERR_LIB_X509V3, X509V3_R_ERROR_CREATING_EXTENSION}, + #else + {"ERROR_CREATING_EXTENSION", 34, 144}, + #endif + #ifdef X509V3_R_ERROR_IN_EXTENSION + {"ERROR_IN_EXTENSION", ERR_LIB_X509V3, X509V3_R_ERROR_IN_EXTENSION}, + #else + {"ERROR_IN_EXTENSION", 34, 128}, + #endif + #ifdef X509V3_R_EXPECTED_A_SECTION_NAME + {"EXPECTED_A_SECTION_NAME", ERR_LIB_X509V3, X509V3_R_EXPECTED_A_SECTION_NAME}, + #else + {"EXPECTED_A_SECTION_NAME", 34, 137}, + #endif + #ifdef X509V3_R_EXTENSION_EXISTS + {"EXTENSION_EXISTS", ERR_LIB_X509V3, X509V3_R_EXTENSION_EXISTS}, + #else + {"EXTENSION_EXISTS", 34, 145}, + #endif + #ifdef X509V3_R_EXTENSION_NAME_ERROR + {"EXTENSION_NAME_ERROR", ERR_LIB_X509V3, X509V3_R_EXTENSION_NAME_ERROR}, + #else + {"EXTENSION_NAME_ERROR", 34, 115}, + #endif + #ifdef X509V3_R_EXTENSION_NOT_FOUND + {"EXTENSION_NOT_FOUND", ERR_LIB_X509V3, X509V3_R_EXTENSION_NOT_FOUND}, + #else + {"EXTENSION_NOT_FOUND", 34, 102}, + #endif + #ifdef X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED + {"EXTENSION_SETTING_NOT_SUPPORTED", ERR_LIB_X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED}, + #else + {"EXTENSION_SETTING_NOT_SUPPORTED", 34, 103}, + #endif + #ifdef X509V3_R_EXTENSION_VALUE_ERROR + {"EXTENSION_VALUE_ERROR", ERR_LIB_X509V3, X509V3_R_EXTENSION_VALUE_ERROR}, + #else + {"EXTENSION_VALUE_ERROR", 34, 116}, + #endif + #ifdef X509V3_R_ILLEGAL_EMPTY_EXTENSION + {"ILLEGAL_EMPTY_EXTENSION", ERR_LIB_X509V3, X509V3_R_ILLEGAL_EMPTY_EXTENSION}, + #else + {"ILLEGAL_EMPTY_EXTENSION", 34, 151}, + #endif + #ifdef X509V3_R_INCORRECT_POLICY_SYNTAX_TAG + {"INCORRECT_POLICY_SYNTAX_TAG", ERR_LIB_X509V3, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG}, + #else + {"INCORRECT_POLICY_SYNTAX_TAG", 34, 152}, + #endif + #ifdef X509V3_R_INVALID_ASNUMBER + {"INVALID_ASNUMBER", ERR_LIB_X509V3, X509V3_R_INVALID_ASNUMBER}, + #else + {"INVALID_ASNUMBER", 34, 162}, + #endif + #ifdef X509V3_R_INVALID_ASRANGE + {"INVALID_ASRANGE", ERR_LIB_X509V3, X509V3_R_INVALID_ASRANGE}, + #else + {"INVALID_ASRANGE", 34, 163}, + #endif + #ifdef X509V3_R_INVALID_BOOLEAN_STRING + {"INVALID_BOOLEAN_STRING", ERR_LIB_X509V3, X509V3_R_INVALID_BOOLEAN_STRING}, + #else + {"INVALID_BOOLEAN_STRING", 34, 104}, + #endif + #ifdef X509V3_R_INVALID_CERTIFICATE + {"INVALID_CERTIFICATE", ERR_LIB_X509V3, X509V3_R_INVALID_CERTIFICATE}, + #else + {"INVALID_CERTIFICATE", 34, 158}, + #endif + #ifdef X509V3_R_INVALID_EMPTY_NAME + {"INVALID_EMPTY_NAME", ERR_LIB_X509V3, X509V3_R_INVALID_EMPTY_NAME}, + #else + {"INVALID_EMPTY_NAME", 34, 108}, + #endif + #ifdef X509V3_R_INVALID_EXTENSION_STRING + {"INVALID_EXTENSION_STRING", ERR_LIB_X509V3, X509V3_R_INVALID_EXTENSION_STRING}, + #else + {"INVALID_EXTENSION_STRING", 34, 105}, + #endif + #ifdef X509V3_R_INVALID_INHERITANCE + {"INVALID_INHERITANCE", ERR_LIB_X509V3, X509V3_R_INVALID_INHERITANCE}, + #else + {"INVALID_INHERITANCE", 34, 165}, + #endif + #ifdef X509V3_R_INVALID_IPADDRESS + {"INVALID_IPADDRESS", ERR_LIB_X509V3, X509V3_R_INVALID_IPADDRESS}, + #else + {"INVALID_IPADDRESS", 34, 166}, + #endif + #ifdef X509V3_R_INVALID_MULTIPLE_RDNS + {"INVALID_MULTIPLE_RDNS", ERR_LIB_X509V3, X509V3_R_INVALID_MULTIPLE_RDNS}, + #else + {"INVALID_MULTIPLE_RDNS", 34, 161}, + #endif + #ifdef X509V3_R_INVALID_NAME + {"INVALID_NAME", ERR_LIB_X509V3, X509V3_R_INVALID_NAME}, + #else + {"INVALID_NAME", 34, 106}, + #endif + #ifdef X509V3_R_INVALID_NULL_ARGUMENT + {"INVALID_NULL_ARGUMENT", ERR_LIB_X509V3, X509V3_R_INVALID_NULL_ARGUMENT}, + #else + {"INVALID_NULL_ARGUMENT", 34, 107}, + #endif + #ifdef X509V3_R_INVALID_NULL_VALUE + {"INVALID_NULL_VALUE", ERR_LIB_X509V3, X509V3_R_INVALID_NULL_VALUE}, + #else + {"INVALID_NULL_VALUE", 34, 109}, + #endif + #ifdef X509V3_R_INVALID_NUMBER + {"INVALID_NUMBER", ERR_LIB_X509V3, X509V3_R_INVALID_NUMBER}, + #else + {"INVALID_NUMBER", 34, 140}, + #endif + #ifdef X509V3_R_INVALID_NUMBERS + {"INVALID_NUMBERS", ERR_LIB_X509V3, X509V3_R_INVALID_NUMBERS}, + #else + {"INVALID_NUMBERS", 34, 141}, + #endif + #ifdef X509V3_R_INVALID_OBJECT_IDENTIFIER + {"INVALID_OBJECT_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER}, + #else + {"INVALID_OBJECT_IDENTIFIER", 34, 110}, + #endif + #ifdef X509V3_R_INVALID_OPTION + {"INVALID_OPTION", ERR_LIB_X509V3, X509V3_R_INVALID_OPTION}, + #else + {"INVALID_OPTION", 34, 138}, + #endif + #ifdef X509V3_R_INVALID_POLICY_IDENTIFIER + {"INVALID_POLICY_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER}, + #else + {"INVALID_POLICY_IDENTIFIER", 34, 134}, + #endif + #ifdef X509V3_R_INVALID_PROXY_POLICY_SETTING + {"INVALID_PROXY_POLICY_SETTING", ERR_LIB_X509V3, X509V3_R_INVALID_PROXY_POLICY_SETTING}, + #else + {"INVALID_PROXY_POLICY_SETTING", 34, 153}, + #endif + #ifdef X509V3_R_INVALID_PURPOSE + {"INVALID_PURPOSE", ERR_LIB_X509V3, X509V3_R_INVALID_PURPOSE}, + #else + {"INVALID_PURPOSE", 34, 146}, + #endif + #ifdef X509V3_R_INVALID_SAFI + {"INVALID_SAFI", ERR_LIB_X509V3, X509V3_R_INVALID_SAFI}, + #else + {"INVALID_SAFI", 34, 164}, + #endif + #ifdef X509V3_R_INVALID_SECTION + {"INVALID_SECTION", ERR_LIB_X509V3, X509V3_R_INVALID_SECTION}, + #else + {"INVALID_SECTION", 34, 135}, + #endif + #ifdef X509V3_R_INVALID_SYNTAX + {"INVALID_SYNTAX", ERR_LIB_X509V3, X509V3_R_INVALID_SYNTAX}, + #else + {"INVALID_SYNTAX", 34, 143}, + #endif + #ifdef X509V3_R_ISSUER_DECODE_ERROR + {"ISSUER_DECODE_ERROR", ERR_LIB_X509V3, X509V3_R_ISSUER_DECODE_ERROR}, + #else + {"ISSUER_DECODE_ERROR", 34, 126}, + #endif + #ifdef X509V3_R_MISSING_VALUE + {"MISSING_VALUE", ERR_LIB_X509V3, X509V3_R_MISSING_VALUE}, + #else + {"MISSING_VALUE", 34, 124}, + #endif + #ifdef X509V3_R_NEED_ORGANIZATION_AND_NUMBERS + {"NEED_ORGANIZATION_AND_NUMBERS", ERR_LIB_X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS}, + #else + {"NEED_ORGANIZATION_AND_NUMBERS", 34, 142}, + #endif + #ifdef X509V3_R_NEGATIVE_PATHLEN + {"NEGATIVE_PATHLEN", ERR_LIB_X509V3, X509V3_R_NEGATIVE_PATHLEN}, + #else + {"NEGATIVE_PATHLEN", 34, 168}, + #endif + #ifdef X509V3_R_NO_CONFIG_DATABASE + {"NO_CONFIG_DATABASE", ERR_LIB_X509V3, X509V3_R_NO_CONFIG_DATABASE}, + #else + {"NO_CONFIG_DATABASE", 34, 136}, + #endif + #ifdef X509V3_R_NO_ISSUER_CERTIFICATE + {"NO_ISSUER_CERTIFICATE", ERR_LIB_X509V3, X509V3_R_NO_ISSUER_CERTIFICATE}, + #else + {"NO_ISSUER_CERTIFICATE", 34, 121}, + #endif + #ifdef X509V3_R_NO_ISSUER_DETAILS + {"NO_ISSUER_DETAILS", ERR_LIB_X509V3, X509V3_R_NO_ISSUER_DETAILS}, + #else + {"NO_ISSUER_DETAILS", 34, 127}, + #endif + #ifdef X509V3_R_NO_POLICY_IDENTIFIER + {"NO_POLICY_IDENTIFIER", ERR_LIB_X509V3, X509V3_R_NO_POLICY_IDENTIFIER}, + #else + {"NO_POLICY_IDENTIFIER", 34, 139}, + #endif + #ifdef X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED + {"NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED", ERR_LIB_X509V3, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED}, + #else + {"NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED", 34, 154}, + #endif + #ifdef X509V3_R_NO_PUBLIC_KEY + {"NO_PUBLIC_KEY", ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY}, + #else + {"NO_PUBLIC_KEY", 34, 114}, + #endif + #ifdef X509V3_R_NO_SUBJECT_DETAILS + {"NO_SUBJECT_DETAILS", ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS}, + #else + {"NO_SUBJECT_DETAILS", 34, 125}, + #endif + #ifdef X509V3_R_OPERATION_NOT_DEFINED + {"OPERATION_NOT_DEFINED", ERR_LIB_X509V3, X509V3_R_OPERATION_NOT_DEFINED}, + #else + {"OPERATION_NOT_DEFINED", 34, 148}, + #endif + #ifdef X509V3_R_OTHERNAME_ERROR + {"OTHERNAME_ERROR", ERR_LIB_X509V3, X509V3_R_OTHERNAME_ERROR}, + #else + {"OTHERNAME_ERROR", 34, 147}, + #endif + #ifdef X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED + {"POLICY_LANGUAGE_ALREADY_DEFINED", ERR_LIB_X509V3, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED}, + #else + {"POLICY_LANGUAGE_ALREADY_DEFINED", 34, 155}, + #endif + #ifdef X509V3_R_POLICY_PATH_LENGTH + {"POLICY_PATH_LENGTH", ERR_LIB_X509V3, X509V3_R_POLICY_PATH_LENGTH}, + #else + {"POLICY_PATH_LENGTH", 34, 156}, + #endif + #ifdef X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED + {"POLICY_PATH_LENGTH_ALREADY_DEFINED", ERR_LIB_X509V3, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED}, + #else + {"POLICY_PATH_LENGTH_ALREADY_DEFINED", 34, 157}, + #endif + #ifdef X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY + {"POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY", ERR_LIB_X509V3, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY}, + #else + {"POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY", 34, 159}, + #endif + #ifdef X509V3_R_SECTION_NOT_FOUND + {"SECTION_NOT_FOUND", ERR_LIB_X509V3, X509V3_R_SECTION_NOT_FOUND}, + #else + {"SECTION_NOT_FOUND", 34, 150}, + #endif + #ifdef X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS + {"UNABLE_TO_GET_ISSUER_DETAILS", ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS}, + #else + {"UNABLE_TO_GET_ISSUER_DETAILS", 34, 122}, + #endif + #ifdef X509V3_R_UNABLE_TO_GET_ISSUER_KEYID + {"UNABLE_TO_GET_ISSUER_KEYID", ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID}, + #else + {"UNABLE_TO_GET_ISSUER_KEYID", 34, 123}, + #endif + #ifdef X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT + {"UNKNOWN_BIT_STRING_ARGUMENT", ERR_LIB_X509V3, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT}, + #else + {"UNKNOWN_BIT_STRING_ARGUMENT", 34, 111}, + #endif + #ifdef X509V3_R_UNKNOWN_EXTENSION + {"UNKNOWN_EXTENSION", ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION}, + #else + {"UNKNOWN_EXTENSION", 34, 129}, + #endif + #ifdef X509V3_R_UNKNOWN_EXTENSION_NAME + {"UNKNOWN_EXTENSION_NAME", ERR_LIB_X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME}, + #else + {"UNKNOWN_EXTENSION_NAME", 34, 130}, + #endif + #ifdef X509V3_R_UNKNOWN_OPTION + {"UNKNOWN_OPTION", ERR_LIB_X509V3, X509V3_R_UNKNOWN_OPTION}, + #else + {"UNKNOWN_OPTION", 34, 120}, + #endif + #ifdef X509V3_R_UNSUPPORTED_OPTION + {"UNSUPPORTED_OPTION", ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_OPTION}, + #else + {"UNSUPPORTED_OPTION", 34, 117}, + #endif + #ifdef X509V3_R_UNSUPPORTED_TYPE + {"UNSUPPORTED_TYPE", ERR_LIB_X509V3, X509V3_R_UNSUPPORTED_TYPE}, + #else + {"UNSUPPORTED_TYPE", 34, 167}, + #endif + #ifdef X509V3_R_USER_TOO_LONG + {"USER_TOO_LONG", ERR_LIB_X509V3, X509V3_R_USER_TOO_LONG}, + #else + {"USER_TOO_LONG", 34, 132}, + #endif + #ifdef X509_R_AKID_MISMATCH + {"AKID_MISMATCH", ERR_LIB_X509, X509_R_AKID_MISMATCH}, + #else + {"AKID_MISMATCH", 11, 110}, + #endif + #ifdef X509_R_BAD_SELECTOR + {"BAD_SELECTOR", ERR_LIB_X509, X509_R_BAD_SELECTOR}, + #else + {"BAD_SELECTOR", 11, 133}, + #endif + #ifdef X509_R_BAD_X509_FILETYPE + {"BAD_X509_FILETYPE", ERR_LIB_X509, X509_R_BAD_X509_FILETYPE}, + #else + {"BAD_X509_FILETYPE", 11, 100}, + #endif + #ifdef X509_R_BASE64_DECODE_ERROR + {"BASE64_DECODE_ERROR", ERR_LIB_X509, X509_R_BASE64_DECODE_ERROR}, + #else + {"BASE64_DECODE_ERROR", 11, 118}, + #endif + #ifdef X509_R_CANT_CHECK_DH_KEY + {"CANT_CHECK_DH_KEY", ERR_LIB_X509, X509_R_CANT_CHECK_DH_KEY}, + #else + {"CANT_CHECK_DH_KEY", 11, 114}, + #endif + #ifdef X509_R_CERTIFICATE_VERIFICATION_FAILED + {"CERTIFICATE_VERIFICATION_FAILED", ERR_LIB_X509, X509_R_CERTIFICATE_VERIFICATION_FAILED}, + #else + {"CERTIFICATE_VERIFICATION_FAILED", 11, 139}, + #endif + #ifdef X509_R_CERT_ALREADY_IN_HASH_TABLE + {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, X509_R_CERT_ALREADY_IN_HASH_TABLE}, + #else + {"CERT_ALREADY_IN_HASH_TABLE", 11, 101}, + #endif + #ifdef X509_R_CRL_ALREADY_DELTA + {"CRL_ALREADY_DELTA", ERR_LIB_X509, X509_R_CRL_ALREADY_DELTA}, + #else + {"CRL_ALREADY_DELTA", 11, 127}, + #endif + #ifdef X509_R_CRL_VERIFY_FAILURE + {"CRL_VERIFY_FAILURE", ERR_LIB_X509, X509_R_CRL_VERIFY_FAILURE}, + #else + {"CRL_VERIFY_FAILURE", 11, 131}, + #endif + #ifdef X509_R_ERROR_GETTING_MD_BY_NID + {"ERROR_GETTING_MD_BY_NID", ERR_LIB_X509, X509_R_ERROR_GETTING_MD_BY_NID}, + #else + {"ERROR_GETTING_MD_BY_NID", 11, 141}, + #endif + #ifdef X509_R_ERROR_USING_SIGINF_SET + {"ERROR_USING_SIGINF_SET", ERR_LIB_X509, X509_R_ERROR_USING_SIGINF_SET}, + #else + {"ERROR_USING_SIGINF_SET", 11, 142}, + #endif + #ifdef X509_R_IDP_MISMATCH + {"IDP_MISMATCH", ERR_LIB_X509, X509_R_IDP_MISMATCH}, + #else + {"IDP_MISMATCH", 11, 128}, + #endif + #ifdef X509_R_INVALID_ATTRIBUTES + {"INVALID_ATTRIBUTES", ERR_LIB_X509, X509_R_INVALID_ATTRIBUTES}, + #else + {"INVALID_ATTRIBUTES", 11, 138}, + #endif + #ifdef X509_R_INVALID_DIRECTORY + {"INVALID_DIRECTORY", ERR_LIB_X509, X509_R_INVALID_DIRECTORY}, + #else + {"INVALID_DIRECTORY", 11, 113}, + #endif + #ifdef X509_R_INVALID_DISTPOINT + {"INVALID_DISTPOINT", ERR_LIB_X509, X509_R_INVALID_DISTPOINT}, + #else + {"INVALID_DISTPOINT", 11, 143}, + #endif + #ifdef X509_R_INVALID_FIELD_NAME + {"INVALID_FIELD_NAME", ERR_LIB_X509, X509_R_INVALID_FIELD_NAME}, + #else + {"INVALID_FIELD_NAME", 11, 119}, + #endif + #ifdef X509_R_INVALID_TRUST + {"INVALID_TRUST", ERR_LIB_X509, X509_R_INVALID_TRUST}, + #else + {"INVALID_TRUST", 11, 123}, + #endif + #ifdef X509_R_ISSUER_MISMATCH + {"ISSUER_MISMATCH", ERR_LIB_X509, X509_R_ISSUER_MISMATCH}, + #else + {"ISSUER_MISMATCH", 11, 129}, + #endif + #ifdef X509_R_KEY_TYPE_MISMATCH + {"KEY_TYPE_MISMATCH", ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH}, + #else + {"KEY_TYPE_MISMATCH", 11, 115}, + #endif + #ifdef X509_R_KEY_VALUES_MISMATCH + {"KEY_VALUES_MISMATCH", ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH}, + #else + {"KEY_VALUES_MISMATCH", 11, 116}, + #endif + #ifdef X509_R_LOADING_CERT_DIR + {"LOADING_CERT_DIR", ERR_LIB_X509, X509_R_LOADING_CERT_DIR}, + #else + {"LOADING_CERT_DIR", 11, 103}, + #endif + #ifdef X509_R_LOADING_DEFAULTS + {"LOADING_DEFAULTS", ERR_LIB_X509, X509_R_LOADING_DEFAULTS}, + #else + {"LOADING_DEFAULTS", 11, 104}, + #endif + #ifdef X509_R_METHOD_NOT_SUPPORTED + {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED}, + #else + {"METHOD_NOT_SUPPORTED", 11, 124}, + #endif + #ifdef X509_R_NAME_TOO_LONG + {"NAME_TOO_LONG", ERR_LIB_X509, X509_R_NAME_TOO_LONG}, + #else + {"NAME_TOO_LONG", 11, 134}, + #endif + #ifdef X509_R_NEWER_CRL_NOT_NEWER + {"NEWER_CRL_NOT_NEWER", ERR_LIB_X509, X509_R_NEWER_CRL_NOT_NEWER}, + #else + {"NEWER_CRL_NOT_NEWER", 11, 132}, + #endif + #ifdef X509_R_NO_CERTIFICATE_FOUND + {"NO_CERTIFICATE_FOUND", ERR_LIB_X509, X509_R_NO_CERTIFICATE_FOUND}, + #else + {"NO_CERTIFICATE_FOUND", 11, 135}, + #endif + #ifdef X509_R_NO_CERTIFICATE_OR_CRL_FOUND + {"NO_CERTIFICATE_OR_CRL_FOUND", ERR_LIB_X509, X509_R_NO_CERTIFICATE_OR_CRL_FOUND}, + #else + {"NO_CERTIFICATE_OR_CRL_FOUND", 11, 136}, + #endif + #ifdef X509_R_NO_CERT_SET_FOR_US_TO_VERIFY + {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY}, + #else + {"NO_CERT_SET_FOR_US_TO_VERIFY", 11, 105}, + #endif + #ifdef X509_R_NO_CRL_FOUND + {"NO_CRL_FOUND", ERR_LIB_X509, X509_R_NO_CRL_FOUND}, + #else + {"NO_CRL_FOUND", 11, 137}, + #endif + #ifdef X509_R_NO_CRL_NUMBER + {"NO_CRL_NUMBER", ERR_LIB_X509, X509_R_NO_CRL_NUMBER}, + #else + {"NO_CRL_NUMBER", 11, 130}, + #endif + #ifdef X509_R_PUBLIC_KEY_DECODE_ERROR + {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_DECODE_ERROR}, + #else + {"PUBLIC_KEY_DECODE_ERROR", 11, 125}, + #endif + #ifdef X509_R_PUBLIC_KEY_ENCODE_ERROR + {"PUBLIC_KEY_ENCODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_ENCODE_ERROR}, + #else + {"PUBLIC_KEY_ENCODE_ERROR", 11, 126}, + #endif + #ifdef X509_R_SHOULD_RETRY + {"SHOULD_RETRY", ERR_LIB_X509, X509_R_SHOULD_RETRY}, + #else + {"SHOULD_RETRY", 11, 106}, + #endif + #ifdef X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN + {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", ERR_LIB_X509, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN}, + #else + {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", 11, 107}, + #endif + #ifdef X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY + {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY}, + #else + {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", 11, 108}, + #endif + #ifdef X509_R_UNKNOWN_KEY_TYPE + {"UNKNOWN_KEY_TYPE", ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE}, + #else + {"UNKNOWN_KEY_TYPE", 11, 117}, + #endif + #ifdef X509_R_UNKNOWN_NID + {"UNKNOWN_NID", ERR_LIB_X509, X509_R_UNKNOWN_NID}, + #else + {"UNKNOWN_NID", 11, 109}, + #endif + #ifdef X509_R_UNKNOWN_PURPOSE_ID + {"UNKNOWN_PURPOSE_ID", ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID}, + #else + {"UNKNOWN_PURPOSE_ID", 11, 121}, + #endif + #ifdef X509_R_UNKNOWN_SIGID_ALGS + {"UNKNOWN_SIGID_ALGS", ERR_LIB_X509, X509_R_UNKNOWN_SIGID_ALGS}, + #else + {"UNKNOWN_SIGID_ALGS", 11, 144}, + #endif + #ifdef X509_R_UNKNOWN_TRUST_ID + {"UNKNOWN_TRUST_ID", ERR_LIB_X509, X509_R_UNKNOWN_TRUST_ID}, + #else + {"UNKNOWN_TRUST_ID", 11, 120}, + #endif + #ifdef X509_R_UNSUPPORTED_ALGORITHM + {"UNSUPPORTED_ALGORITHM", ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM}, + #else + {"UNSUPPORTED_ALGORITHM", 11, 111}, + #endif + #ifdef X509_R_WRONG_LOOKUP_TYPE + {"WRONG_LOOKUP_TYPE", ERR_LIB_X509, X509_R_WRONG_LOOKUP_TYPE}, + #else + {"WRONG_LOOKUP_TYPE", 11, 112}, + #endif + #ifdef X509_R_WRONG_TYPE + {"WRONG_TYPE", ERR_LIB_X509, X509_R_WRONG_TYPE}, + #else + {"WRONG_TYPE", 11, 122}, + #endif + { NULL } +}; + diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 39003d954d705a..534a9ebcfd151a 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1t +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1u set libraries=%libraries% sqlite-3.42.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 @@ -77,7 +77,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1t +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1u if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.13.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/python.props b/PCbuild/python.props index 1d959699f3cfb0..68052ef668aa6c 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -74,8 +74,8 @@ $(ExternalsDir)libffi-3.4.4\ $(libffiDir)$(ArchName)\ $(libffiOutDir)include - $(ExternalsDir)openssl-1.1.1t\ - $(ExternalsDir)openssl-bin-1.1.1t\$(ArchName)\ + $(ExternalsDir)openssl-1.1.1u\ + $(ExternalsDir)openssl-bin-1.1.1u\$(ArchName)\ $(opensslOutDir)include $(ExternalsDir)\nasm-2.11.06\ $(ExternalsDir)\zlib-1.2.13\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 3629525e33d56c..784d3ce6a60660 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -169,7 +169,7 @@ _lzma Homepage: https://tukaani.org/xz/ _ssl - Python wrapper for version 1.1.1t of the OpenSSL secure sockets + Python wrapper for version 1.1.1u of the OpenSSL secure sockets library, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 9bd54db0f59c51..2ee341f8dd137d 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -71,6 +71,7 @@ def clean_lines(text): # only huge constants (safe but parsing is slow) Modules/_ssl_data.h +Modules/_ssl_data_31.h Modules/_ssl_data_300.h Modules/_ssl_data_111.h Modules/cjkcodecs/mappings_*.h diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index c0fbee9ca6f98f..f9809c9b54665b 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -46,8 +46,9 @@ ] OPENSSL_RECENT_VERSIONS = [ - "1.1.1t", - "3.0.8" + "1.1.1u", + "3.0.9", + "3.1.1", ] LIBRESSL_OLD_VERSIONS = [ From 83c7386cee59d8dfe9fa8f5db80ab4afeb3a7b8a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 2 Jun 2023 00:19:19 +0200 Subject: [PATCH 0102/1206] [3.12] GH-89886: Bump to GNU Autoconf v2.71 (#104925) (#105207) Co-authored-by: Christian Heimes --- .github/workflows/build.yml | 6 +- Doc/whatsnew/3.12.rst | 4 + Makefile.pre.in | 2 +- ...3-05-26-15-44-20.gh-issue-89886._iSW-p.rst | 2 + aclocal.m4 | 12 +- configure | 18541 +++++++++------- configure.ac | 11 +- pyconfig.h.in | 95 +- 8 files changed, 10919 insertions(+), 7754 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c632d362a4d04a..99acce905a8472 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,10 +143,10 @@ jobs: run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - name: Configure ccache action uses: hendrikmuhs/ccache-action@v1.2 - - name: Check Autoconf version 2.69 and aclocal 1.16.3 + - name: Check Autoconf and aclocal versions run: | - grep "Generated by GNU Autoconf 2.69" configure - grep "aclocal 1.16.3" aclocal.m4 + grep "Generated by GNU Autoconf 2.71" configure + grep "aclocal 1.16.4" aclocal.m4 grep -q "runstatedir" configure grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4 - name: Configure CPython diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b496da30c73fc4..2966abe7eea544 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1506,6 +1506,10 @@ Build Changes * ``PYTHON_FOR_REGEN`` now require Python 3.10 or newer. +* Autoconf 2.71 and aclocal 1.16.4 is now required to regenerate + :file:`!configure`. + (Contributed by Christian Heimes in :gh:`89886`.) + C API Changes ============= diff --git a/Makefile.pre.in b/Makefile.pre.in index 2482b637739a79..e2adc3cb49f2a9 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2584,7 +2584,7 @@ regen-configure: @if command -v podman >/dev/null; then RUNTIME="podman"; else RUNTIME="docker"; fi; \ if ! command -v $$RUNTIME; then echo "$@ needs either Podman or Docker container runtime." >&2; exit 1; fi; \ if command -v selinuxenabled >/dev/null && selinuxenabled; then OPT=":Z"; fi; \ - CMD="$$RUNTIME run --rm --pull=always -v $(abs_srcdir):/src$$OPT quay.io/tiran/cpython_autoconf:269"; \ + CMD="$$RUNTIME run --rm --pull=always -v $(abs_srcdir):/src$$OPT quay.io/tiran/cpython_autoconf:271"; \ echo $$CMD; \ $$CMD || exit $? diff --git a/Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst b/Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst new file mode 100644 index 00000000000000..83559545e86141 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst @@ -0,0 +1,2 @@ +Autoconf 2.71 and aclocal 1.16.4 is now required to regenerate +:file:`!configure`. diff --git a/aclocal.m4 b/aclocal.m4 index 6a33c0cc9d9e8c..da8ee95b9c7f6b 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.16.3 -*- Autoconf -*- +# generated automatically by aclocal 1.16.4 -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -184,7 +184,7 @@ AS_VAR_POPDEF([CACHEVAR])dnl # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 10 +#serial 11 AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) AC_DEFUN([AX_CHECK_OPENSSL], [ @@ -227,7 +227,7 @@ AC_DEFUN([AX_CHECK_OPENSSL], [ if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do - AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) + AC_MSG_CHECKING([for include/openssl/ssl.h in $ssldir]) if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" @@ -621,7 +621,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -652,7 +652,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 2006-2020 Free Software Foundation, Inc. +# Copyright (C) 2006-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/configure b/configure index 012dac94feddd6..a4d4996b065798 100755 --- a/configure +++ b/configure @@ -1,11 +1,12 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for python 3.12. +# Generated by GNU Autoconf 2.71 for python 3.12. # # Report bugs to . # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -16,14 +17,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -33,46 +36,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -81,13 +84,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -96,8 +92,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -109,30 +109,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -154,20 +134,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -187,42 +169,53 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -230,14 +223,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -255,18 +255,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org and + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and $0: https://github.com/python/cpython/issues/ about your $0: system, including any error possibly output before this $0: message. Then install a modern shell, or manually run @@ -294,6 +295,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -311,6 +313,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -325,7 +335,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -334,7 +344,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -373,12 +383,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -390,18 +401,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -413,9 +433,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -442,7 +462,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -486,7 +506,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -500,6 +520,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -513,6 +537,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -588,40 +619,36 @@ PACKAGE_URL='' ac_unique_file="Include/object.h" # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= ac_subst_vars='LTLIBOBJS MODULE_BLOCK MODULE_XXLIMITED_35_FALSE @@ -1208,8 +1235,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -1250,9 +1275,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1276,9 +1301,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1489,9 +1514,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1505,9 +1530,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1551,9 +1576,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1569,7 +1594,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1633,7 +1658,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1994,9 +2019,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -2024,7 +2049,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -2032,7 +2058,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -2042,9 +2068,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF python configure 3.12 -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -2061,14 +2087,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2076,14 +2102,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -2105,7 +2132,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2113,14 +2140,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -2130,139 +2158,6 @@ fi } # ac_fn_c_try_cpp -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## -------------------------------------------------------- ## -## Report this to https://github.com/python/cpython/issues/ ## -## -------------------------------------------------------- ##" - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in @@ -2270,26 +2165,28 @@ fi ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -2300,14 +2197,14 @@ $as_echo "$ac_res" >&6; } ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2315,17 +2212,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -2340,6 +2238,49 @@ fi } # ac_fn_c_try_link +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that +# executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache @@ -2347,17 +2288,18 @@ fi ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof ($2)) return 0; @@ -2365,12 +2307,13 @@ if (sizeof ($2)) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof (($2))) return 0; @@ -2378,18 +2321,19 @@ if (sizeof (($2))) return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop eval "$3=yes" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type @@ -2408,7 +2352,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -2418,14 +2362,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2435,9 +2380,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid; break -else +else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= @@ -2445,14 +2391,14 @@ else fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -2462,14 +2408,15 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -2479,9 +2426,10 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_lo=$ac_mid; break -else +else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= @@ -2489,14 +2437,14 @@ else fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else +else $as_nop ac_lo= ac_hi= fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val @@ -2504,7 +2452,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2514,12 +2462,13 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_hi=$ac_mid -else +else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; @@ -2529,12 +2478,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } #include #include int -main () +main (void) { FILE *f = fopen ("conftest.val", "w"); @@ -2562,9 +2511,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : echo >>conftest.val; read $3 &5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. @@ -2595,16 +2546,9 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif + which can conflict with char $2 (); below. */ +#include #undef $2 /* Override any GCC internal prototype to avoid an error. @@ -2622,47 +2566,51 @@ choke me #endif int -main () +main (void) { return $2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func -# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES -# --------------------------------------------- +# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR +# ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -# accordingly. -ac_fn_c_check_decl () +# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. +ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +printf %s "checking whether $as_decl_name is declared... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + eval ac_save_FLAGS=\$$6 + as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { #ifndef $as_decl_name #ifdef __cplusplus @@ -2676,19 +2624,22 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + eval $6=\$ac_save_FLAGS + fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno -} # ac_fn_c_check_decl +} # ac_fn_check_decl # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- @@ -2697,16 +2648,17 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +printf %s "checking for $2.$3... " >&6; } +if eval test \${$4+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (ac_aggr.$3) @@ -2715,14 +2667,15 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) @@ -2731,29 +2684,50 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop eval "$4=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 3.12, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -2786,8 +2760,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -2822,7 +2800,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2857,11 +2835,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2872,8 +2852,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2897,7 +2877,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2905,14 +2885,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2920,15 +2900,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2936,8 +2916,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2951,63 +2931,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -3017,75 +2982,493 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif + +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" +as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" +as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" + +# Auxiliary files required by this configure script. +ac_aux_files="install-sh config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## @@ -3130,11 +3513,12 @@ if test -e $srcdir/.git then # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_HAS_GIT+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_HAS_GIT+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$HAS_GIT"; then ac_cv_prog_HAS_GIT="$HAS_GIT" # Let the user override the test. else @@ -3142,11 +3526,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAS_GIT="found" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3158,11 +3546,11 @@ fi fi HAS_GIT=$ac_cv_prog_HAS_GIT if test -n "$HAS_GIT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAS_GIT" >&5 -$as_echo "$HAS_GIT" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAS_GIT" >&5 +printf "%s\n" "$HAS_GIT" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3184,55 +3572,30 @@ fi ac_config_headers="$ac_config_headers pyconfig.h" -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -3251,21 +3614,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -3287,7 +3651,8 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac -if test "x$cross_compiling" = xmaybe; then : +if test "x$cross_compiling" = xmaybe +then : as_fn_error $? "Cross compiling required --host=HOST-TUPLE and --build=ARCH" "$LINENO" 5 fi @@ -3297,15 +3662,18 @@ rm -f pybuilddir.txt # Check whether --with-build-python was given. -if test "${with_build_python+set}" = set; then : +if test ${with_build_python+y} +then : withval=$with_build_python; - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-build-python" >&5 -$as_echo_n "checking for --with-build-python... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-build-python" >&5 +printf %s "checking for --with-build-python... " >&6; } - if test "x$with_build_python" = xyes; then : + if test "x$with_build_python" = xyes +then : with_build_python=python$PACKAGE_VERSION fi - if test "x$with_build_python" = xno; then : + if test "x$with_build_python" = xno +then : as_fn_error $? "invalid --with-build-python option: expected path or \"yes\", not \"no\"" "$LINENO" 5 fi @@ -3319,12 +3687,13 @@ fi ac_cv_prog_PYTHON_FOR_REGEN=$with_build_python PYTHON_FOR_FREEZE="$with_build_python" PYTHON_FOR_BUILD='_PYTHON_PROJECT_BASE=$(abs_builddir) _PYTHON_HOST_PLATFORM=$(_PYTHON_HOST_PLATFORM) PYTHONPATH=$(shell test -f pybuilddir.txt && echo $(abs_builddir)/`cat pybuilddir.txt`:)$(srcdir)/Lib _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) '$with_build_python - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_build_python" >&5 -$as_echo "$with_build_python" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_build_python" >&5 +printf "%s\n" "$with_build_python" >&6; } -else +else $as_nop - if test "x$cross_compiling" = xyes; then : + if test "x$cross_compiling" = xyes +then : as_fn_error $? "Cross compiling requires --with-build-python" "$LINENO" 5 fi @@ -3336,13 +3705,14 @@ fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python interpreter freezing" >&5 -$as_echo_n "checking for Python interpreter freezing... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_FOR_FREEZE" >&5 -$as_echo "$PYTHON_FOR_FREEZE" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Python interpreter freezing" >&5 +printf %s "checking for Python interpreter freezing... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PYTHON_FOR_FREEZE" >&5 +printf "%s\n" "$PYTHON_FOR_FREEZE" >&6; } -if test "x$cross_compiling" = xyes; then : +if test "x$cross_compiling" = xyes +then : FREEZE_MODULE_BOOTSTRAP='$(PYTHON_FOR_FREEZE) $(srcdir)/Programs/_freeze_module.py' FREEZE_MODULE_BOOTSTRAP_DEPS='$(srcdir)/Programs/_freeze_module.py' @@ -3350,7 +3720,7 @@ if test "x$cross_compiling" = xyes; then : FREEZE_MODULE_DEPS='$(FREEZE_MODULE_BOOTSTRAP_DEPS)' PYTHON_FOR_BUILD_DEPS='' -else +else $as_nop FREEZE_MODULE_BOOTSTRAP='./Programs/_freeze_module' FREEZE_MODULE_BOOTSTRAP_DEPS="Programs/_freeze_module" @@ -3370,11 +3740,12 @@ for ac_prog in python$PACKAGE_VERSION python3.12 python3.11 python3.10 python3 p do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PYTHON_FOR_REGEN+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_PYTHON_FOR_REGEN+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$PYTHON_FOR_REGEN"; then ac_cv_prog_PYTHON_FOR_REGEN="$PYTHON_FOR_REGEN" # Let the user override the test. else @@ -3382,11 +3753,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PYTHON_FOR_REGEN="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3397,11 +3772,11 @@ fi fi PYTHON_FOR_REGEN=$ac_cv_prog_PYTHON_FOR_REGEN if test -n "$PYTHON_FOR_REGEN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_FOR_REGEN" >&5 -$as_echo "$PYTHON_FOR_REGEN" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PYTHON_FOR_REGEN" >&5 +printf "%s\n" "$PYTHON_FOR_REGEN" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3411,14 +3786,14 @@ test -n "$PYTHON_FOR_REGEN" || PYTHON_FOR_REGEN="python3" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Python for regen version" >&5 -$as_echo_n "checking Python for regen version... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking Python for regen version" >&5 +printf %s "checking Python for regen version... " >&6; } if command -v "$PYTHON_FOR_REGEN" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $($PYTHON_FOR_REGEN -V 2>/dev/null)" >&5 -$as_echo "$($PYTHON_FOR_REGEN -V 2>/dev/null)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $($PYTHON_FOR_REGEN -V 2>/dev/null)" >&5 +printf "%s\n" "$($PYTHON_FOR_REGEN -V 2>/dev/null)" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: missing" >&5 -$as_echo "missing" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: missing" >&5 +printf "%s\n" "missing" >&6; } fi @@ -3446,21 +3821,21 @@ SOVERSION=1.0 # certain features on NetBSD, so we need _NETBSD_SOURCE to re-enable # them. -$as_echo "#define _NETBSD_SOURCE 1" >>confdefs.h +printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h # The later definition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables # certain features on FreeBSD, so we need __BSD_VISIBLE to re-enable # them. -$as_echo "#define __BSD_VISIBLE 1" >>confdefs.h +printf "%s\n" "#define __BSD_VISIBLE 1" >>confdefs.h # The later definition of _XOPEN_SOURCE and _POSIX_C_SOURCE disables # certain features on Mac OS X, so we need _DARWIN_C_SOURCE to re-enable # them. -$as_echo "#define _DARWIN_C_SOURCE 1" >>confdefs.h +printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h @@ -3472,9 +3847,10 @@ CONFIG_ARGS="$ac_configure_args" # Check whether --with-pkg-config was given. -if test "${with_pkg_config+set}" = set; then : +if test ${with_pkg_config+y} +then : withval=$with_pkg_config; -else +else $as_nop with_pkg_config=check fi @@ -3498,11 +3874,12 @@ if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. @@ -3512,11 +3889,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3528,11 +3909,11 @@ esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -$as_echo "$PKG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3541,11 +3922,12 @@ if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. @@ -3555,11 +3937,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3571,11 +3957,11 @@ esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -$as_echo "$ac_pt_PKG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then @@ -3583,8 +3969,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG @@ -3596,14 +3982,14 @@ fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 -$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi @@ -3622,10 +4008,11 @@ if test "$with_pkg_config" = yes -a -z "$PKG_CONFIG"; then as_fn_error $? "pkg-config is required" "$LINENO" 5] fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-universalsdk" >&5 -$as_echo_n "checking for --enable-universalsdk... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-universalsdk" >&5 +printf %s "checking for --enable-universalsdk... " >&6; } # Check whether --enable-universalsdk was given. -if test "${enable_universalsdk+set}" = set; then : +if test ${enable_universalsdk+y} +then : enableval=$enable_universalsdk; case $enableval in yes) @@ -3657,7 +4044,7 @@ if test "${enable_universalsdk+set}" = set; then : esac -else +else $as_nop UNIVERSALSDK= enable_universalsdk= @@ -3666,11 +4053,11 @@ fi if test -n "${UNIVERSALSDK}" then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${UNIVERSALSDK}" >&5 -$as_echo "${UNIVERSALSDK}" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${UNIVERSALSDK}" >&5 +printf "%s\n" "${UNIVERSALSDK}" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3693,11 +4080,12 @@ fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-universal-archs" >&5 -$as_echo_n "checking for --with-universal-archs... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-universal-archs" >&5 +printf %s "checking for --with-universal-archs... " >&6; } # Check whether --with-universal-archs was given. -if test "${with_universal_archs+set}" = set; then : +if test ${with_universal_archs+y} +then : withval=$with_universal_archs; UNIVERSAL_ARCHS="$withval" @@ -3705,22 +4093,23 @@ fi if test -n "${UNIVERSALSDK}" then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${UNIVERSAL_ARCHS}" >&5 -$as_echo "${UNIVERSAL_ARCHS}" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${UNIVERSAL_ARCHS}" >&5 +printf "%s\n" "${UNIVERSAL_ARCHS}" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi # Check whether --with-framework-name was given. -if test "${with_framework_name+set}" = set; then : +if test ${with_framework_name+y} +then : withval=$with_framework_name; PYTHONFRAMEWORK=${withval} PYTHONFRAMEWORKDIR=${withval}.framework PYTHONFRAMEWORKIDENTIFIER=org.python.`echo $withval | tr 'A-Z' 'a-z'` -else +else $as_nop PYTHONFRAMEWORK=Python PYTHONFRAMEWORKDIR=Python.framework @@ -3729,7 +4118,8 @@ else fi # Check whether --enable-framework was given. -if test "${enable_framework+set}" = set; then : +if test ${enable_framework+y} +then : enableval=$enable_framework; case $enableval in yes) @@ -3818,7 +4208,7 @@ if test "${enable_framework+set}" = set; then : esac -else +else $as_nop PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework @@ -3853,15 +4243,13 @@ fi -cat >>confdefs.h <<_ACEOF -#define _PYTHONFRAMEWORK "${PYTHONFRAMEWORK}" -_ACEOF +printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h # Set name for machine-dependent library files -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 -$as_echo_n "checking MACHDEP... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 +printf %s "checking MACHDEP... " >&6; } if test -z "$MACHDEP" then # avoid using uname for cross builds @@ -3917,8 +4305,8 @@ then '') MACHDEP="unknown";; esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5 -$as_echo "\"$MACHDEP\"" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5 +printf "%s\n" "\"$MACHDEP\"" >&6; } if test "$cross_compiling" = yes; then @@ -3970,7 +4358,7 @@ case $ac_sys_system/$ac_sys_release in # also defined. This can be overridden by defining _BSD_SOURCE # As this has a different meaning on Linux, only define it on OpenBSD -$as_echo "#define _BSD_SOURCE 1" >>confdefs.h +printf "%s\n" "#define _BSD_SOURCE 1" >>confdefs.h ;; OpenBSD/*) @@ -3978,7 +4366,7 @@ $as_echo "#define _BSD_SOURCE 1" >>confdefs.h # also defined. This can be overridden by defining _BSD_SOURCE # As this has a different meaning on Linux, only define it on OpenBSD -$as_echo "#define _BSD_SOURCE 1" >>confdefs.h +printf "%s\n" "#define _BSD_SOURCE 1" >>confdefs.h ;; # Defining _XOPEN_SOURCE on NetBSD version prior to the introduction of @@ -4036,7 +4424,7 @@ if test $define_xopen_source = yes then # X/Open 7, incorporating POSIX.1-2008 -$as_echo "#define _XOPEN_SOURCE 700" >>confdefs.h +printf "%s\n" "#define _XOPEN_SOURCE 700" >>confdefs.h # On Tru64 Unix 4.0F, defining _XOPEN_SOURCE also requires @@ -4044,11 +4432,11 @@ $as_echo "#define _XOPEN_SOURCE 700" >>confdefs.h # several APIs are not declared. Since this is also needed in some # cases for HP-UX, we define it globally. -$as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h +printf "%s\n" "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h -$as_echo "#define _POSIX_C_SOURCE 200809L" >>confdefs.h +printf "%s\n" "#define _POSIX_C_SOURCE 200809L" >>confdefs.h fi @@ -4063,7 +4451,7 @@ esac if test $define_stdc_a1 = yes then -$as_echo "#define _INCLUDE__STDC_A1_SOURCE 1" >>confdefs.h +printf "%s\n" "#define _INCLUDE__STDC_A1_SOURCE 1" >>confdefs.h fi @@ -4111,11 +4499,12 @@ if test "$ac_sys_system" = "Darwin" then # Extract the first word of "xcrun", so it can be a program name with args. set dummy xcrun; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_HAS_XCRUN+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_HAS_XCRUN+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$HAS_XCRUN"; then ac_cv_prog_HAS_XCRUN="$HAS_XCRUN" # Let the user override the test. else @@ -4123,11 +4512,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAS_XCRUN="yes" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4139,16 +4532,16 @@ fi fi HAS_XCRUN=$ac_cv_prog_HAS_XCRUN if test -n "$HAS_XCRUN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAS_XCRUN" >&5 -$as_echo "$HAS_XCRUN" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAS_XCRUN" >&5 +printf "%s\n" "$HAS_XCRUN" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking macOS SDKROOT" >&5 -$as_echo_n "checking macOS SDKROOT... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking macOS SDKROOT" >&5 +printf %s "checking macOS SDKROOT... " >&6; } if test -z "$SDKROOT"; then if test "$HAS_XCRUN" = "yes"; then SDKROOT=$(xcrun --show-sdk-path) @@ -4156,8 +4549,8 @@ $as_echo_n "checking macOS SDKROOT... " >&6; } SDKROOT="/" fi fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SDKROOT" >&5 -$as_echo "$SDKROOT" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SDKROOT" >&5 +printf "%s\n" "$SDKROOT" >&6; } # Compiler selection on MacOSX is more complicated than # AC_PROG_CC can handle, see Mac/README for more @@ -4187,8 +4580,8 @@ $as_echo "$SDKROOT" >&6; } then if test -n "`"$found_gcc" --version | grep llvm-gcc`" then - { $as_echo "$as_me:${as_lineno-$LINENO}: Detected llvm-gcc, falling back to clang" >&5 -$as_echo "$as_me: Detected llvm-gcc, falling back to clang" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Detected llvm-gcc, falling back to clang" >&5 +printf "%s\n" "$as_me: Detected llvm-gcc, falling back to clang" >&6;} CC="$found_clang" CXX="$found_clang++" fi @@ -4196,8 +4589,8 @@ $as_echo "$as_me: Detected llvm-gcc, falling back to clang" >&6;} elif test -z "$found_gcc" -a -n "$found_clang" then - { $as_echo "$as_me:${as_lineno-$LINENO}: No GCC found, use CLANG" >&5 -$as_echo "$as_me: No GCC found, use CLANG" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No GCC found, use CLANG" >&5 +printf "%s\n" "$as_me: No GCC found, use CLANG" >&6;} CC="$found_clang" CXX="$found_clang++" @@ -4206,8 +4599,8 @@ $as_echo "$as_me: No GCC found, use CLANG" >&6;} found_clang=`/usr/bin/xcrun -find clang 2>/dev/null` if test -n "${found_clang}" then - { $as_echo "$as_me:${as_lineno-$LINENO}: Using clang from Xcode.app" >&5 -$as_echo "$as_me: Using clang from Xcode.app" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Using clang from Xcode.app" >&5 +printf "%s\n" "$as_me: Using clang from Xcode.app" >&6;} CC="${found_clang}" CXX="`/usr/bin/xcrun -find clang++`" @@ -4216,6 +4609,15 @@ $as_echo "$as_me: Using clang from Xcode.app" >&6;} fi fi fi + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4224,11 +4626,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4236,11 +4639,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4251,11 +4658,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4264,11 +4671,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -4276,11 +4684,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4291,11 +4703,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -4303,8 +4715,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -4317,11 +4729,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4329,11 +4742,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4344,11 +4761,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4357,11 +4774,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4370,15 +4788,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4394,18 +4816,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4416,11 +4838,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4428,11 +4851,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4443,11 +4870,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4460,11 +4887,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -4472,11 +4900,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4487,11 +4919,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4503,8 +4935,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -4512,47 +4944,151 @@ esac fi fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } done + done +IFS=$as_save_IFS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi -int -main () -{ - ; - return 0; +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion -version; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; } _ACEOF ac_clean_files_save=$ac_clean_files @@ -4560,9 +5096,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -4583,11 +5119,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -4604,7 +5141,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -4620,44 +5157,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -4671,15 +5210,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -4688,7 +5227,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -4700,8 +5239,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -4709,10 +5248,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -4720,39 +5259,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -4766,11 +5306,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -4779,31 +5320,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -4813,29 +5355,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -4844,57 +5390,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -4909,94 +5458,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -5010,40 +5609,36 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + if test ${ac_cv_prog_CPP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -5055,10 +5650,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -5068,7 +5664,8 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : break fi @@ -5080,29 +5677,24 @@ fi else ac_cv_prog_CPP=$CPP fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -5114,10 +5706,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -5127,11 +5720,12 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi @@ -5142,11 +5736,12 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +printf %s "checking for grep that handles long lines and -e... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST @@ -5154,10 +5749,15 @@ else for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in grep ggrep + do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP @@ -5166,13 +5766,13 @@ case `"$ac_path_GREP" --version 2>&1` in ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 - $as_echo_n 0123456789 >"conftest.in" + printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" + printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val @@ -5200,16 +5800,17 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if ${ac_cv_path_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +printf %s "checking for a sed that does not truncate output... " >&6; } +if test ${ac_cv_path_SED+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" @@ -5223,10 +5824,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in sed gsed + do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + ac_path_SED="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED @@ -5235,13 +5841,13 @@ case `"$ac_path_SED" --version 2>&1` in ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 - $as_echo_n 0123456789 >"conftest.in" + printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" + printf "%s\n" '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val @@ -5269,16 +5875,17 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +printf %s "checking for egrep... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else @@ -5289,10 +5896,15 @@ else for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in egrep + do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP @@ -5301,13 +5913,13 @@ case `"$ac_path_EGREP" --version 2>&1` in ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 - $as_echo_n 0123456789 >"conftest.in" + printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" + printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val @@ -5336,17 +5948,18 @@ fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CC compiler name" >&5 -$as_echo_n "checking for CC compiler name... " >&6; } -if ${ac_cv_cc_name+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CC compiler name" >&5 +printf %s "checking for CC compiler name... " >&6; } +if test ${ac_cv_cc_name+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat > conftest.c <&5 -$as_echo "$ac_cv_cc_name" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_name" >&5 +printf "%s\n" "$ac_cv_cc_name" >&6; } # checks for UNIX variants that set C preprocessor variables # may set _GNU_SOURCE, __EXTENSIONS__, _POSIX_PTHREAD_SEMANTICS, # _POSIX_SOURCE, _POSIX_1_SOURCE, and more +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done + -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else + + + + + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if test ${ac_cv_safe_to_define___extensions__+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -#include -#include +# define __EXTENSIONS__ 1 + $ac_includes_default int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_safe_to_define___extensions__=yes +else $as_nop + ac_cv_safe_to_define___extensions__=no fi -rm -f conftest* - +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 +printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } +if test ${ac_cv_should_define__xopen_source+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_should_define__xopen_source=no + if test $ac_cv_header_wchar_h = yes +then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* + #include + mbstate_t x; +int +main (void) +{ -fi + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) + #define _XOPEN_SOURCE 500 + #include + mbstate_t x; int -main () +main (void) { - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; + + ; return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_should_define__xopen_source=yes fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi - +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 +printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } -$as_echo "#define STDC_HEADERS 1" >>confdefs.h + printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h -fi + printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF + printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h -fi + printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h -done + printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h + printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h + printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = xyes; then : - MINIX=yes -else - MINIX= -fi + printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h + printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h - if test "$MINIX" = yes; then + printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h -$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h + printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h -$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h + printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h -$as_echo "#define _MINIX 1" >>confdefs.h + printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h - fi + if test $ac_cv_header_minix_config_h = yes +then : + MINIX=yes + printf "%s\n" "#define _MINIX 1" >>confdefs.h + printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if ${ac_cv_safe_to_define___extensions__+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_safe_to_define___extensions__=yes -else - ac_cv_safe_to_define___extensions__=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else $as_nop + MINIX= fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } - test $ac_cv_safe_to_define___extensions__ = yes && - $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h - - $as_echo "#define _ALL_SOURCE 1" >>confdefs.h - - $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + if test $ac_cv_safe_to_define___extensions__ = yes +then : + printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h - $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h +fi + if test $ac_cv_should_define__xopen_source = yes +then : + printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h +fi @@ -5580,11 +6172,12 @@ then gcc) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}g++", so it can be a program name with args. set dummy ${ac_tool_prefix}g++; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $CXX in [\\/]* | ?:[\\/]*) ac_cv_path_CXX="$CXX" # Let the user override the test with a path. @@ -5594,11 +6187,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5610,11 +6207,11 @@ esac fi CXX=$ac_cv_path_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5623,11 +6220,12 @@ if test -z "$ac_cv_path_CXX"; then ac_pt_CXX=$CXX # Extract the first word of "g++", so it can be a program name with args. set dummy g++; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_CXX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. @@ -5637,11 +6235,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5653,11 +6255,11 @@ esac fi ac_pt_CXX=$ac_cv_path_ac_pt_CXX if test -n "$ac_pt_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 -$as_echo "$ac_pt_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 +printf "%s\n" "$ac_pt_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then @@ -5665,8 +6267,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_pt_CXX @@ -5678,11 +6280,12 @@ fi cc) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}c++", so it can be a program name with args. set dummy ${ac_tool_prefix}c++; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $CXX in [\\/]* | ?:[\\/]*) ac_cv_path_CXX="$CXX" # Let the user override the test with a path. @@ -5692,11 +6295,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5708,11 +6315,11 @@ esac fi CXX=$ac_cv_path_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5721,11 +6328,12 @@ if test -z "$ac_cv_path_CXX"; then ac_pt_CXX=$CXX # Extract the first word of "c++", so it can be a program name with args. set dummy c++; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_CXX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. @@ -5735,11 +6343,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5751,11 +6363,11 @@ esac fi ac_pt_CXX=$ac_cv_path_ac_pt_CXX if test -n "$ac_pt_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 -$as_echo "$ac_pt_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 +printf "%s\n" "$ac_pt_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then @@ -5763,8 +6375,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_pt_CXX @@ -5776,11 +6388,12 @@ fi clang|*/clang) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang++", so it can be a program name with args. set dummy ${ac_tool_prefix}clang++; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $CXX in [\\/]* | ?:[\\/]*) ac_cv_path_CXX="$CXX" # Let the user override the test with a path. @@ -5790,11 +6403,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5806,11 +6423,11 @@ esac fi CXX=$ac_cv_path_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5819,11 +6436,12 @@ if test -z "$ac_cv_path_CXX"; then ac_pt_CXX=$CXX # Extract the first word of "clang++", so it can be a program name with args. set dummy clang++; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_CXX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. @@ -5833,11 +6451,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5849,11 +6471,11 @@ esac fi ac_pt_CXX=$ac_cv_path_ac_pt_CXX if test -n "$ac_pt_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 -$as_echo "$ac_pt_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 +printf "%s\n" "$ac_pt_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then @@ -5861,8 +6483,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_pt_CXX @@ -5874,11 +6496,12 @@ fi icc|*/icc) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}icpc", so it can be a program name with args. set dummy ${ac_tool_prefix}icpc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $CXX in [\\/]* | ?:[\\/]*) ac_cv_path_CXX="$CXX" # Let the user override the test with a path. @@ -5888,11 +6511,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5904,11 +6531,11 @@ esac fi CXX=$ac_cv_path_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5917,11 +6544,12 @@ if test -z "$ac_cv_path_CXX"; then ac_pt_CXX=$CXX # Extract the first word of "icpc", so it can be a program name with args. set dummy icpc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_CXX in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_CXX="$ac_pt_CXX" # Let the user override the test with a path. @@ -5931,11 +6559,15 @@ else for as_dir in notfound do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_CXX="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_CXX="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5947,11 +6579,11 @@ esac fi ac_pt_CXX=$ac_cv_path_ac_pt_CXX if test -n "$ac_pt_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 -$as_echo "$ac_pt_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_CXX" >&5 +printf "%s\n" "$ac_pt_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_CXX" = x; then @@ -5959,8 +6591,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_pt_CXX @@ -5982,11 +6614,12 @@ then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else @@ -5994,11 +6627,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6009,11 +6646,11 @@ fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -6026,11 +6663,12 @@ if test -z "$CXX"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else @@ -6038,11 +6676,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6053,11 +6695,11 @@ fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +printf "%s\n" "$ac_ct_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -6069,8 +6711,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX @@ -6084,12 +6726,12 @@ fi fi if test "$preset_cxx" != "$CXX" then - { $as_echo "$as_me:${as_lineno-$LINENO}: + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: By default, distutils will build C++ extension modules with \"$CXX\". If this is not intended, then set CXX on the configure command line. " >&5 -$as_echo "$as_me: +printf "%s\n" "$as_me: By default, distutils will build C++ extension modules with \"$CXX\". If this is not intended, then set CXX on the configure command line. @@ -6097,8 +6739,8 @@ $as_echo "$as_me: fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the platform triplet based on compiler characteristics" >&5 -$as_echo_n "checking for the platform triplet based on compiler characteristics... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the platform triplet based on compiler characteristics" >&5 +printf %s "checking for the platform triplet based on compiler characteristics... " >&6; } cat > conftest.c <conftest.out 2>/dev/null; then PLATFORM_TRIPLET=`echo "$PLATFORM_TRIPLET" | sed 's/linux-gnu/linux-musl/'` ;; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PLATFORM_TRIPLET" >&5 -$as_echo "$PLATFORM_TRIPLET" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PLATFORM_TRIPLET" >&5 +printf "%s\n" "$PLATFORM_TRIPLET" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 -$as_echo "none" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 +printf "%s\n" "none" >&6; } fi rm -f conftest.c conftest.out -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for multiarch" >&5 -$as_echo_n "checking for multiarch... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for multiarch" >&5 +printf %s "checking for multiarch... " >&6; } case $ac_sys_system in #( Darwin*) : MULTIARCH="" ;; #( @@ -6302,8 +6944,8 @@ case $ac_sys_system in #( ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5 -$as_echo "$MULTIARCH" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5 +printf "%s\n" "$MULTIARCH" >&6; } if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then if test x$PLATFORM_TRIPLET != x$MULTIARCH; then @@ -6319,8 +6961,8 @@ if test x$MULTIARCH != x; then fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PEP 11 support tier" >&5 -$as_echo_n "checking for PEP 11 support tier... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PEP 11 support tier" >&5 +printf %s "checking for PEP 11 support tier... " >&6; } case $host/$ac_cv_cc_name in #( x86_64-*-linux-gnu/gcc) : PY_SUPPORT_TIER=1 ;; #( @@ -6363,31 +7005,30 @@ esac case $PY_SUPPORT_TIER in #( 1) : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $host/$ac_cv_cc_name has tier 1 (supported)" >&5 -$as_echo "$host/$ac_cv_cc_name has tier 1 (supported)" >&6; } ;; #( + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $host/$ac_cv_cc_name has tier 1 (supported)" >&5 +printf "%s\n" "$host/$ac_cv_cc_name has tier 1 (supported)" >&6; } ;; #( 2) : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $host/$ac_cv_cc_name has tier 2 (supported)" >&5 -$as_echo "$host/$ac_cv_cc_name has tier 2 (supported)" >&6; } ;; #( + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $host/$ac_cv_cc_name has tier 2 (supported)" >&5 +printf "%s\n" "$host/$ac_cv_cc_name has tier 2 (supported)" >&6; } ;; #( 3) : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $host/$ac_cv_cc_name has tier 3 (partially supported)" >&5 -$as_echo "$host/$ac_cv_cc_name has tier 3 (partially supported)" >&6; } ;; #( + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $host/$ac_cv_cc_name has tier 3 (partially supported)" >&5 +printf "%s\n" "$host/$ac_cv_cc_name has tier 3 (partially supported)" >&6; } ;; #( *) : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $host/$ac_cv_cc_name is not supported" >&5 -$as_echo "$as_me: WARNING: $host/$ac_cv_cc_name is not supported" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $host/$ac_cv_cc_name is not supported" >&5 +printf "%s\n" "$as_me: WARNING: $host/$ac_cv_cc_name is not supported" >&2;} ;; esac -cat >>confdefs.h <<_ACEOF -#define PY_SUPPORT_TIER $PY_SUPPORT_TIER -_ACEOF +printf "%s\n" "#define PY_SUPPORT_TIER $PY_SUPPORT_TIER" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wl,--no-as-needed" >&5 -$as_echo_n "checking for -Wl,--no-as-needed... " >&6; } -if ${ac_cv_wl_no_as_needed+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -Wl,--no-as-needed" >&5 +printf %s "checking for -Wl,--no-as-needed... " >&6; } +if test ${ac_cv_wl_no_as_needed+y} +then : + printf %s "(cached) " >&6 +else $as_nop save_LDFLAGS="$LDFLAGS" as_fn_append LDFLAGS " -Wl,--no-as-needed" @@ -6395,31 +7036,32 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : NO_AS_NEEDED="-Wl,--no-as-needed" ac_cv_wl_no_as_needed=yes -else +else $as_nop NO_AS_NEEDED="" ac_cv_wl_no_as_needed=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wl_no_as_needed" >&5 -$as_echo "$ac_cv_wl_no_as_needed" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wl_no_as_needed" >&5 +printf "%s\n" "$ac_cv_wl_no_as_needed" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Android API level" >&5 -$as_echo_n "checking for the Android API level... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the Android API level" >&5 +printf %s "checking for the Android API level... " >&6; } cat > conftest.c <conftest.out 2>/dev/null; then ANDROID_API_LEVEL=`sed -n -e '/__ANDROID_API__/d' -e 's/^android_api = //p' conftest.out` _arm_arch=`sed -n -e '/__ARM_ARCH/d' -e 's/^arm_arch = //p' conftest.out` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ANDROID_API_LEVEL" >&5 -$as_echo "$ANDROID_API_LEVEL" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ANDROID_API_LEVEL" >&5 +printf "%s\n" "$ANDROID_API_LEVEL" >&6; } if test -z "$ANDROID_API_LEVEL"; then as_fn_error $? "Fatal: you must define __ANDROID_API__" "$LINENO" 5 fi -cat >>confdefs.h <<_ACEOF -#define ANDROID_API_LEVEL $ANDROID_API_LEVEL -_ACEOF +printf "%s\n" "#define ANDROID_API_LEVEL $ANDROID_API_LEVEL" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Android arm ABI" >&5 -$as_echo_n "checking for the Android arm ABI... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_arm_arch" >&5 -$as_echo "$_arm_arch" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the Android arm ABI" >&5 +printf %s "checking for the Android arm ABI... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $_arm_arch" >&5 +printf "%s\n" "$_arm_arch" >&6; } if test "$_arm_arch" = 7; then BASECFLAGS="${BASECFLAGS} -mfloat-abi=softfp -mfpu=vfpv3-d16" LDFLAGS="${LDFLAGS} -march=armv7-a -Wl,--fix-cortex-a8" fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not Android" >&5 -$as_echo "not Android" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not Android" >&5 +printf "%s\n" "not Android" >&6; } fi rm -f conftest.c conftest.out @@ -6468,13 +7108,15 @@ case $ac_sys_system/$ac_sys_release in #( ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-emscripten-target" >&5 -$as_echo_n "checking for --with-emscripten-target... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-emscripten-target" >&5 +printf %s "checking for --with-emscripten-target... " >&6; } # Check whether --with-emscripten-target was given. -if test "${with_emscripten_target+set}" = set; then : +if test ${with_emscripten_target+y} +then : withval=$with_emscripten_target; - if test "x$ac_sys_system" = xEmscripten; then : + if test "x$ac_sys_system" = xEmscripten +then : case $with_emscripten_target in #( browser) : @@ -6490,27 +7132,29 @@ if test "${with_emscripten_target+set}" = set; then : ;; esac -else +else $as_nop as_fn_error $? "--with-emscripten-target only applies to Emscripten" "$LINENO" 5 fi -else +else $as_nop - if test "x$ac_sys_system" = xEmscripten; then : + if test "x$ac_sys_system" = xEmscripten +then : ac_sys_emscripten_target=browser fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_sys_emscripten_target" >&5 -$as_echo "$ac_sys_emscripten_target" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_sys_emscripten_target" >&5 +printf "%s\n" "$ac_sys_emscripten_target" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-wasm-dynamic-linking" >&5 -$as_echo_n "checking for --enable-wasm-dynamic-linking... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-wasm-dynamic-linking" >&5 +printf %s "checking for --enable-wasm-dynamic-linking... " >&6; } # Check whether --enable-wasm-dynamic-linking was given. -if test "${enable_wasm_dynamic_linking+set}" = set; then : +if test ${enable_wasm_dynamic_linking+y} +then : enableval=$enable_wasm_dynamic_linking; case $ac_sys_system in #( Emscripten) : @@ -6522,19 +7166,20 @@ if test "${enable_wasm_dynamic_linking+set}" = set; then : ;; esac -else +else $as_nop enable_wasm_dynamic_linking=missing fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_dynamic_linking" >&5 -$as_echo "$enable_wasm_dynamic_linking" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_dynamic_linking" >&5 +printf "%s\n" "$enable_wasm_dynamic_linking" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-wasm-pthreads" >&5 -$as_echo_n "checking for --enable-wasm-pthreads... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-wasm-pthreads" >&5 +printf %s "checking for --enable-wasm-pthreads... " >&6; } # Check whether --enable-wasm-pthreads was given. -if test "${enable_wasm_pthreads+set}" = set; then : +if test ${enable_wasm_pthreads+y} +then : enableval=$enable_wasm_pthreads; case $ac_sys_system in #( Emscripten) : @@ -6546,20 +7191,21 @@ if test "${enable_wasm_pthreads+set}" = set; then : ;; esac -else +else $as_nop enable_wasm_pthreads=missing fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_pthreads" >&5 -$as_echo "$enable_wasm_pthreads" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_wasm_pthreads" >&5 +printf "%s\n" "$enable_wasm_pthreads" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-suffix" >&5 -$as_echo_n "checking for --with-suffix... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-suffix" >&5 +printf %s "checking for --with-suffix... " >&6; } # Check whether --with-suffix was given. -if test "${with_suffix+set}" = set; then : +if test ${with_suffix+y} +then : withval=$with_suffix; case $with_suffix in #( no) : @@ -6571,7 +7217,7 @@ if test "${with_suffix+set}" = set; then : ;; esac -else +else $as_nop case $ac_sys_system/$ac_sys_emscripten_target in #( Emscripten/browser*) : @@ -6587,26 +7233,26 @@ esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXEEXT" >&5 -$as_echo "$EXEEXT" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXEEXT" >&5 +printf "%s\n" "$EXEEXT" >&6; } # Test whether we're running on a non-case-sensitive system, in which # case we give a warning if no ext is given -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for case-insensitive build directory" >&5 -$as_echo_n "checking for case-insensitive build directory... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for case-insensitive build directory" >&5 +printf %s "checking for case-insensitive build directory... " >&6; } if test ! -d CaseSensitiveTestDir; then mkdir CaseSensitiveTestDir fi if test -d casesensitivetestdir && test -z "$EXEEXT" then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } BUILDEXEEXT=.exe else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } BUILDEXEEXT=$EXEEXT fi rmdir CaseSensitiveTestDir @@ -6619,14 +7265,14 @@ hp*|HP*) esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LIBRARY" >&5 -$as_echo_n "checking LIBRARY... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LIBRARY" >&5 +printf %s "checking LIBRARY... " >&6; } if test -z "$LIBRARY" then LIBRARY='libpython$(VERSION)$(ABIFLAGS).a' fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBRARY" >&5 -$as_echo "$LIBRARY" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIBRARY" >&5 +printf "%s\n" "$LIBRARY" >&6; } # LDLIBRARY is the name of the library to link against (as opposed to the # name of the library into which to insert object files). BLDLIBRARY is also @@ -6665,8 +7311,8 @@ LDVERSION="$VERSION" # compiled with CXX, LINKCC is CXX instead. Always using CXX is undesirable: # python might then depend on the C++ runtime -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LINKCC" >&5 -$as_echo_n "checking LINKCC... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LINKCC" >&5 +printf %s "checking LINKCC... " >&6; } if test -z "$LINKCC" then LINKCC='$(PURIFY) $(CC)' @@ -6677,8 +7323,8 @@ then LINKCC=qcc;; esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINKCC" >&5 -$as_echo "$LINKCC" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LINKCC" >&5 +printf "%s\n" "$LINKCC" >&6; } # EXPORTSYMS holds the list of exported symbols for AIX. # EXPORTSFROM holds the module name exporting symbols on AIX. @@ -6686,16 +7332,16 @@ EXPORTSYMS= EXPORTSFROM= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking EXPORTSYMS" >&5 -$as_echo_n "checking EXPORTSYMS... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking EXPORTSYMS" >&5 +printf %s "checking EXPORTSYMS... " >&6; } case $ac_sys_system in AIX*) EXPORTSYMS="Modules/python.exp" EXPORTSFROM=. # the main executable ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXPORTSYMS" >&5 -$as_echo "$EXPORTSYMS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXPORTSYMS" >&5 +printf "%s\n" "$EXPORTSYMS" >&6; } # GNULD is set to "yes" if the GNU linker is used. If this goes wrong # make sure we default having it set to "no": this is used by @@ -6703,8 +7349,8 @@ $as_echo "$EXPORTSYMS" >&6; } # to linker command lines, and failing to detect GNU ld simply results # in the same behaviour as before. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +printf %s "checking for GNU ld... " >&6; } ac_prog=ld if test "$GCC" = yes; then ac_prog=`$CC -print-prog-name=ld` @@ -6715,13 +7361,14 @@ case `"$ac_prog" -V 2>&1 < /dev/null` in *) GNULD=no;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GNULD" >&5 -$as_echo "$GNULD" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GNULD" >&5 +printf "%s\n" "$GNULD" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-shared" >&5 -$as_echo_n "checking for --enable-shared... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-shared" >&5 +printf %s "checking for --enable-shared... " >&6; } # Check whether --enable-shared was given. -if test "${enable_shared+set}" = set; then : +if test ${enable_shared+y} +then : enableval=$enable_shared; fi @@ -6735,37 +7382,39 @@ then enable_shared="no";; esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -$as_echo "$enable_shared" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +printf "%s\n" "$enable_shared" >&6; } # --with-static-libpython STATIC_LIBPYTHON=1 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-static-libpython" >&5 -$as_echo_n "checking for --with-static-libpython... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-static-libpython" >&5 +printf %s "checking for --with-static-libpython... " >&6; } # Check whether --with-static-libpython was given. -if test "${with_static_libpython+set}" = set; then : +if test ${with_static_libpython+y} +then : withval=$with_static_libpython; if test "$withval" = no then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; }; STATIC_LIBPYTHON=0 else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; }; fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-profiling" >&5 -$as_echo_n "checking for --enable-profiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-profiling" >&5 +printf %s "checking for --enable-profiling... " >&6; } # Check whether --enable-profiling was given. -if test "${enable_profiling+set}" = set; then : +if test ${enable_profiling+y} +then : enableval=$enable_profiling; fi @@ -6776,27 +7425,28 @@ if test "x$enable_profiling" = xyes; then /* end confdefs.h. */ int main(void) { return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : -else +else $as_nop enable_profiling=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CC="$ac_save_cc" else enable_profiling=no fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_profiling" >&5 -$as_echo "$enable_profiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_profiling" >&5 +printf "%s\n" "$enable_profiling" >&6; } if test "x$enable_profiling" = xyes; then BASECFLAGS="-pg $BASECFLAGS" LDFLAGS="-pg $LDFLAGS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LDLIBRARY" >&5 -$as_echo_n "checking LDLIBRARY... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDLIBRARY" >&5 +printf %s "checking LDLIBRARY... " >&6; } # MacOSX framework builds need more magic. LDLIBRARY is the dynamic # library that we build, but we do not want to link against it (we @@ -6817,7 +7467,7 @@ fi if test $enable_shared = "yes"; then PY_ENABLE_SHARED=1 -$as_echo "#define Py_ENABLE_SHARED 1" >>confdefs.h +printf "%s\n" "#define Py_ENABLE_SHARED 1" >>confdefs.h case $ac_sys_system in CYGWIN*) @@ -6890,11 +7540,12 @@ then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}node", so it can be a program name with args. set dummy ${ac_tool_prefix}node; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_NODE+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_NODE+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $NODE in [\\/]* | ?:[\\/]*) ac_cv_path_NODE="$NODE" # Let the user override the test with a path. @@ -6904,11 +7555,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_NODE="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_NODE="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6920,11 +7575,11 @@ esac fi NODE=$ac_cv_path_NODE if test -n "$NODE"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NODE" >&5 -$as_echo "$NODE" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NODE" >&5 +printf "%s\n" "$NODE" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -6933,11 +7588,12 @@ if test -z "$ac_cv_path_NODE"; then ac_pt_NODE=$NODE # Extract the first word of "node", so it can be a program name with args. set dummy node; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_NODE+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_NODE+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_NODE in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_NODE="$ac_pt_NODE" # Let the user override the test with a path. @@ -6947,11 +7603,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_NODE="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_NODE="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6963,11 +7623,11 @@ esac fi ac_pt_NODE=$ac_cv_path_ac_pt_NODE if test -n "$ac_pt_NODE"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_NODE" >&5 -$as_echo "$ac_pt_NODE" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_NODE" >&5 +printf "%s\n" "$ac_pt_NODE" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_NODE" = x; then @@ -6975,8 +7635,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NODE=$ac_pt_NODE @@ -6988,11 +7648,12 @@ fi HOSTRUNNER="$NODE" # bigint for ctypes c_longlong, c_longdouble # no longer available in Node 16 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for node --experimental-wasm-bigint" >&5 -$as_echo_n "checking for node --experimental-wasm-bigint... " >&6; } -if ${ac_cv_tool_node_wasm_bigint+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for node --experimental-wasm-bigint" >&5 +printf %s "checking for node --experimental-wasm-bigint... " >&6; } +if test ${ac_cv_tool_node_wasm_bigint+y} +then : + printf %s "(cached) " >&6 +else $as_nop if $NODE -v --experimental-wasm-bigint > /dev/null 2>&1; then ac_cv_tool_node_wasm_bigint=yes @@ -7001,23 +7662,26 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_tool_node_wasm_bigint" >&5 -$as_echo "$ac_cv_tool_node_wasm_bigint" >&6; } - if test "x$ac_cv_tool_node_wasm_bigint" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_tool_node_wasm_bigint" >&5 +printf "%s\n" "$ac_cv_tool_node_wasm_bigint" >&6; } + if test "x$ac_cv_tool_node_wasm_bigint" = xyes +then : as_fn_append HOSTRUNNER " --experimental-wasm-bigint" fi - if test "x$enable_wasm_pthreads" = xyes; then : + if test "x$enable_wasm_pthreads" = xyes +then : as_fn_append HOSTRUNNER " --experimental-wasm-threads" # no longer available in Node 16 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for node --experimental-wasm-bulk-memory" >&5 -$as_echo_n "checking for node --experimental-wasm-bulk-memory... " >&6; } -if ${ac_cv_tool_node_wasm_bulk_memory+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for node --experimental-wasm-bulk-memory" >&5 +printf %s "checking for node --experimental-wasm-bulk-memory... " >&6; } +if test ${ac_cv_tool_node_wasm_bulk_memory+y} +then : + printf %s "(cached) " >&6 +else $as_nop if $NODE -v --experimental-wasm-bulk-memory > /dev/null 2>&1; then ac_cv_tool_node_wasm_bulk_memory=yes @@ -7026,9 +7690,10 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_tool_node_wasm_bulk_memory" >&5 -$as_echo "$ac_cv_tool_node_wasm_bulk_memory" >&6; } - if test "x$ac_cv_tool_node_wasm_bulk_memory" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_tool_node_wasm_bulk_memory" >&5 +printf "%s\n" "$ac_cv_tool_node_wasm_bulk_memory" >&6; } + if test "x$ac_cv_tool_node_wasm_bulk_memory" = xyes +then : as_fn_append HOSTRUNNER " --experimental-wasm-bulk-memory" @@ -7036,7 +7701,8 @@ fi fi - if test "x$host_cpu" = xwasm64; then : + if test "x$host_cpu" = xwasm64 +then : as_fn_append HOSTRUNNER " --experimental-wasm-memory64" fi ;; #( @@ -7048,17 +7714,17 @@ fi esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking HOSTRUNNER" >&5 -$as_echo_n "checking HOSTRUNNER... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HOSTRUNNER" >&5 -$as_echo "$HOSTRUNNER" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking HOSTRUNNER" >&5 +printf %s "checking HOSTRUNNER... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HOSTRUNNER" >&5 +printf "%s\n" "$HOSTRUNNER" >&6; } if test -n "$HOSTRUNNER"; then PYTHON_FOR_BUILD="_PYTHON_HOSTRUNNER='$HOSTRUNNER' $PYTHON_FOR_BUILD" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDLIBRARY" >&5 -$as_echo "$LDLIBRARY" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDLIBRARY" >&5 +printf "%s\n" "$LDLIBRARY" >&6; } # LIBRARY_DEPS, LINK_PYTHON_OBJS and LINK_PYTHON_DEPS variable case $ac_sys_system/$ac_sys_emscripten_target in #( @@ -7097,11 +7763,12 @@ if test -n "$ac_tool_prefix"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else @@ -7109,11 +7776,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7124,11 +7795,11 @@ fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf "%s\n" "$AR" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -7141,11 +7812,12 @@ if test -z "$AR"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else @@ -7153,11 +7825,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7168,11 +7844,11 @@ fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +printf "%s\n" "$ac_ct_AR" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -7184,8 +7860,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR @@ -7208,7 +7884,8 @@ hp*|HP*) INSTALL="${srcdir}/install-sh -c" fi esac -# Find a good install program. We prefer a C program (faster), + + # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install @@ -7222,20 +7899,25 @@ esac # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +case $as_dir in #(( + ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; @@ -7245,13 +7927,13 @@ case $as_dir/ in #(( # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else @@ -7259,12 +7941,12 @@ case $as_dir/ in #(( echo one > conftest.one echo two > conftest.two mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi @@ -7280,7 +7962,7 @@ IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi - if test "${ac_cv_path_install+set}" = set; then + if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a @@ -7290,8 +7972,8 @@ fi INSTALL=$ac_install_sh fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. @@ -7301,25 +7983,31 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 -$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 +printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then - if ${ac_cv_path_mkdir+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test ${ac_cv_path_mkdir+y} +then : + printf %s "(cached) " >&6 +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue - case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir (GNU coreutils) '* | \ - 'mkdir (coreutils) '* | \ + as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue + case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir ('*'coreutils) '* | \ + 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done @@ -7330,7 +8018,7 @@ IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version - if test "${ac_cv_path_mkdir+set}" = set; then + if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a @@ -7340,8 +8028,8 @@ fi MKDIR_P="$ac_install_sh -d" fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -$as_echo "$MKDIR_P" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +printf "%s\n" "$MKDIR_P" >&6; } # Not every filesystem supports hard links @@ -7358,72 +8046,76 @@ fi ABIFLAGS="" # Check for --with-pydebug -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pydebug" >&5 -$as_echo_n "checking for --with-pydebug... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-pydebug" >&5 +printf %s "checking for --with-pydebug... " >&6; } # Check whether --with-pydebug was given. -if test "${with_pydebug+set}" = set; then : +if test ${with_pydebug+y} +then : withval=$with_pydebug; if test "$withval" != no then -$as_echo "#define Py_DEBUG 1" >>confdefs.h +printf "%s\n" "#define Py_DEBUG 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; }; Py_DEBUG='true' ABIFLAGS="${ABIFLAGS}d" -else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; Py_DEBUG='false' +else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; }; Py_DEBUG='false' fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi # Check for --with-trace-refs # --with-trace-refs -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-trace-refs" >&5 -$as_echo_n "checking for --with-trace-refs... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-trace-refs" >&5 +printf %s "checking for --with-trace-refs... " >&6; } # Check whether --with-trace-refs was given. -if test "${with_trace_refs+set}" = set; then : +if test ${with_trace_refs+y} +then : withval=$with_trace_refs; -else +else $as_nop with_trace_refs=no fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_trace_refs" >&5 -$as_echo "$with_trace_refs" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_trace_refs" >&5 +printf "%s\n" "$with_trace_refs" >&6; } if test "$with_trace_refs" = "yes" then -$as_echo "#define Py_TRACE_REFS 1" >>confdefs.h +printf "%s\n" "#define Py_TRACE_REFS 1" >>confdefs.h fi # Check for --enable-pystats -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-pystats" >&5 -$as_echo_n "checking for --enable-pystats... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-pystats" >&5 +printf %s "checking for --enable-pystats... " >&6; } # Check whether --enable-pystats was given. -if test "${enable_pystats+set}" = set; then : +if test ${enable_pystats+y} +then : enableval=$enable_pystats; -else +else $as_nop enable_pystats=no fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pystats" >&5 -$as_echo "$enable_pystats" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_pystats" >&5 +printf "%s\n" "$enable_pystats" >&6; } -if test "x$enable_pystats" = xyes; then : +if test "x$enable_pystats" = xyes +then : -$as_echo "#define Py_STATS 1" >>confdefs.h +printf "%s\n" "#define Py_STATS 1" >>confdefs.h fi @@ -7431,11 +8123,12 @@ fi # Check for --with-assertions. # This allows enabling assertions without Py_DEBUG. assertions='false' -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-assertions" >&5 -$as_echo_n "checking for --with-assertions... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-assertions" >&5 +printf %s "checking for --with-assertions... " >&6; } # Check whether --with-assertions was given. -if test "${with_assertions+set}" = set; then : +if test ${with_assertions+y} +then : withval=$with_assertions; if test "$withval" != no then @@ -7444,39 +8137,40 @@ fi fi if test "$assertions" = 'true'; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } elif test "$Py_DEBUG" = 'true'; then assertions='true' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: implied by --with-pydebug" >&5 -$as_echo "implied by --with-pydebug" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: implied by --with-pydebug" >&5 +printf "%s\n" "implied by --with-pydebug" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi # Enable optimization flags Py_OPT='false' -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-optimizations" >&5 -$as_echo_n "checking for --enable-optimizations... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-optimizations" >&5 +printf %s "checking for --enable-optimizations... " >&6; } # Check whether --enable-optimizations was given. -if test "${enable_optimizations+set}" = set; then : +if test ${enable_optimizations+y} +then : enableval=$enable_optimizations; if test "$enableval" != no then Py_OPT='true' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; }; else Py_OPT='false' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; }; fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -7490,11 +8184,12 @@ if test "$Py_OPT" = 'true' ; then DEF_MAKE_RULE="build_all" case $CC in *gcc*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-semantic-interposition" >&5 -$as_echo_n "checking whether C compiler accepts -fno-semantic-interposition... " >&6; } -if ${ax_cv_check_cflags___fno_semantic_interposition+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-semantic-interposition" >&5 +printf %s "checking whether C compiler accepts -fno-semantic-interposition... " >&6; } +if test ${ax_cv_check_cflags___fno_semantic_interposition+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fno-semantic-interposition" @@ -7502,29 +8197,31 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ax_cv_check_cflags___fno_semantic_interposition=yes -else +else $as_nop ax_cv_check_cflags___fno_semantic_interposition=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fno_semantic_interposition" >&5 -$as_echo "$ax_cv_check_cflags___fno_semantic_interposition" >&6; } -if test "x$ax_cv_check_cflags___fno_semantic_interposition" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fno_semantic_interposition" >&5 +printf "%s\n" "$ax_cv_check_cflags___fno_semantic_interposition" >&6; } +if test "x$ax_cv_check_cflags___fno_semantic_interposition" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -fno-semantic-interposition" LDFLAGS_NODIST="$LDFLAGS_NODIST -fno-semantic-interposition" -else +else $as_nop : fi @@ -7541,14 +8238,14 @@ else fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking PROFILE_TASK" >&5 -$as_echo_n "checking PROFILE_TASK... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PROFILE_TASK" >&5 +printf %s "checking PROFILE_TASK... " >&6; } if test -z "$PROFILE_TASK" then PROFILE_TASK='-m test --pgo --timeout=$(TESTTIMEOUT)' fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROFILE_TASK" >&5 -$as_echo "$PROFILE_TASK" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PROFILE_TASK" >&5 +printf "%s\n" "$PROFILE_TASK" >&6; } # Make llvm-related checks work on systems where llvm tools are not installed with their # normal names in the default $PATH (ie: Ubuntu). They exist under the @@ -7571,35 +8268,36 @@ then fi # Enable LTO flags -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lto" >&5 -$as_echo_n "checking for --with-lto... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-lto" >&5 +printf %s "checking for --with-lto... " >&6; } # Check whether --with-lto was given. -if test "${with_lto+set}" = set; then : +if test ${with_lto+y} +then : withval=$with_lto; case "$withval" in full) Py_LTO='true' Py_LTO_POLICY='full' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; thin) Py_LTO='true' Py_LTO_POLICY='thin' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; yes) Py_LTO='true' Py_LTO_POLICY='default' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; no) Py_LTO='false' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ;; *) Py_LTO='false' @@ -7607,20 +8305,21 @@ $as_echo "no" >&6; } ;; esac -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "$Py_LTO" = 'true' ; then case $CC in *clang*) LDFLAGS_NOLTO="-fno-lto" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 -$as_echo_n "checking whether C compiler accepts -flto=thin... " >&6; } -if ${ax_cv_check_cflags___flto_thin+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 +printf %s "checking whether C compiler accepts -flto=thin... " >&6; } +if test ${ax_cv_check_cflags___flto_thin+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -flto=thin" @@ -7628,26 +8327,28 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ax_cv_check_cflags___flto_thin=yes -else +else $as_nop ax_cv_check_cflags___flto_thin=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 -$as_echo "$ax_cv_check_cflags___flto_thin" >&6; } -if test "x$ax_cv_check_cflags___flto_thin" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 +printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } +if test "x$ax_cv_check_cflags___flto_thin" = xyes +then : LDFLAGS_NOLTO="-flto=thin" -else +else $as_nop LDFLAGS_NOLTO="-flto" fi @@ -7655,11 +8356,12 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}llvm-ar", so it can be a program name with args. set dummy ${ac_tool_prefix}llvm-ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_LLVM_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_LLVM_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $LLVM_AR in [\\/]* | ?:[\\/]*) ac_cv_path_LLVM_AR="$LLVM_AR" # Let the user override the test with a path. @@ -7669,11 +8371,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_LLVM_AR="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_LLVM_AR="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7685,11 +8391,11 @@ esac fi LLVM_AR=$ac_cv_path_LLVM_AR if test -n "$LLVM_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_AR" >&5 -$as_echo "$LLVM_AR" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LLVM_AR" >&5 +printf "%s\n" "$LLVM_AR" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -7698,11 +8404,12 @@ if test -z "$ac_cv_path_LLVM_AR"; then ac_pt_LLVM_AR=$LLVM_AR # Extract the first word of "llvm-ar", so it can be a program name with args. set dummy llvm-ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_LLVM_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_LLVM_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_LLVM_AR in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_LLVM_AR="$ac_pt_LLVM_AR" # Let the user override the test with a path. @@ -7712,11 +8419,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_LLVM_AR="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_LLVM_AR="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7728,11 +8439,11 @@ esac fi ac_pt_LLVM_AR=$ac_cv_path_ac_pt_LLVM_AR if test -n "$ac_pt_LLVM_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_AR" >&5 -$as_echo "$ac_pt_LLVM_AR" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_AR" >&5 +printf "%s\n" "$ac_pt_LLVM_AR" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_LLVM_AR" = x; then @@ -7740,8 +8451,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LLVM_AR=$ac_pt_LLVM_AR @@ -7765,8 +8476,8 @@ fi then LLVM_AR='/usr/bin/xcrun ar' LLVM_AR_FOUND=found - { $as_echo "$as_me:${as_lineno-$LINENO}: llvm-ar found via xcrun: ${LLVM_AR}" >&5 -$as_echo "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: llvm-ar found via xcrun: ${LLVM_AR}" >&5 +printf "%s\n" "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;} fi fi if test $LLVM_AR_FOUND = not-found @@ -7783,11 +8494,12 @@ $as_echo "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;} if test $Py_LTO_POLICY = default then # Check that ThinLTO is accepted. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 -$as_echo_n "checking whether C compiler accepts -flto=thin... " >&6; } -if ${ax_cv_check_cflags___flto_thin+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 +printf %s "checking whether C compiler accepts -flto=thin... " >&6; } +if test ${ax_cv_check_cflags___flto_thin+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -flto=thin" @@ -7795,29 +8507,31 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ax_cv_check_cflags___flto_thin=yes -else +else $as_nop ax_cv_check_cflags___flto_thin=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 -$as_echo "$ax_cv_check_cflags___flto_thin" >&6; } -if test "x$ax_cv_check_cflags___flto_thin" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 +printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } +if test "x$ax_cv_check_cflags___flto_thin" = xyes +then : LTOFLAGS="-flto=thin -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" LTOCFLAGS="-flto=thin" -else +else $as_nop LTOFLAGS="-flto -Wl,-export_dynamic -Wl,-object_path_lto,\"\$@\".lto" LTOCFLAGS="-flto" @@ -7834,11 +8548,12 @@ fi if test $Py_LTO_POLICY = default then # Check that ThinLTO is accepted - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 -$as_echo_n "checking whether C compiler accepts -flto=thin... " >&6; } -if ${ax_cv_check_cflags___flto_thin+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -flto=thin" >&5 +printf %s "checking whether C compiler accepts -flto=thin... " >&6; } +if test ${ax_cv_check_cflags___flto_thin+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -flto=thin" @@ -7846,26 +8561,28 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ax_cv_check_cflags___flto_thin=yes -else +else $as_nop ax_cv_check_cflags___flto_thin=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 -$as_echo "$ax_cv_check_cflags___flto_thin" >&6; } -if test "x$ax_cv_check_cflags___flto_thin" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___flto_thin" >&5 +printf "%s\n" "$ax_cv_check_cflags___flto_thin" >&6; } +if test "x$ax_cv_check_cflags___flto_thin" = xyes +then : LTOFLAGS="-flto=thin" -else +else $as_nop LTOFLAGS="-flto" fi @@ -7921,11 +8638,12 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}llvm-profdata", so it can be a program name with args. set dummy ${ac_tool_prefix}llvm-profdata; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_LLVM_PROFDATA+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_LLVM_PROFDATA+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $LLVM_PROFDATA in [\\/]* | ?:[\\/]*) ac_cv_path_LLVM_PROFDATA="$LLVM_PROFDATA" # Let the user override the test with a path. @@ -7935,11 +8653,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_LLVM_PROFDATA="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_LLVM_PROFDATA="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7951,11 +8673,11 @@ esac fi LLVM_PROFDATA=$ac_cv_path_LLVM_PROFDATA if test -n "$LLVM_PROFDATA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_PROFDATA" >&5 -$as_echo "$LLVM_PROFDATA" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LLVM_PROFDATA" >&5 +printf "%s\n" "$LLVM_PROFDATA" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -7964,11 +8686,12 @@ if test -z "$ac_cv_path_LLVM_PROFDATA"; then ac_pt_LLVM_PROFDATA=$LLVM_PROFDATA # Extract the first word of "llvm-profdata", so it can be a program name with args. set dummy llvm-profdata; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_LLVM_PROFDATA+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_LLVM_PROFDATA+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_LLVM_PROFDATA in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_LLVM_PROFDATA="$ac_pt_LLVM_PROFDATA" # Let the user override the test with a path. @@ -7978,11 +8701,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_LLVM_PROFDATA="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_LLVM_PROFDATA="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -7994,11 +8721,11 @@ esac fi ac_pt_LLVM_PROFDATA=$ac_cv_path_ac_pt_LLVM_PROFDATA if test -n "$ac_pt_LLVM_PROFDATA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_PROFDATA" >&5 -$as_echo "$ac_pt_LLVM_PROFDATA" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_PROFDATA" >&5 +printf "%s\n" "$ac_pt_LLVM_PROFDATA" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_LLVM_PROFDATA" = x; then @@ -8006,8 +8733,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LLVM_PROFDATA=$ac_pt_LLVM_PROFDATA @@ -8032,8 +8759,8 @@ then # https://apple.stackexchange.com/questions/197053/ LLVM_PROFDATA='/usr/bin/xcrun llvm-profdata' LLVM_PROF_FOUND=found - { $as_echo "$as_me:${as_lineno-$LINENO}: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&5 -$as_echo "$as_me: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&5 +printf "%s\n" "$as_me: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&6;} fi fi LLVM_PROF_ERR=no @@ -8087,24 +8814,25 @@ esac # BOLT optimization. Always configured after PGO since it always runs after PGO. Py_BOLT='false' -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-bolt" >&5 -$as_echo_n "checking for --enable-bolt... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-bolt" >&5 +printf %s "checking for --enable-bolt... " >&6; } # Check whether --enable-bolt was given. -if test "${enable_bolt+set}" = set; then : +if test ${enable_bolt+y} +then : enableval=$enable_bolt; if test "$enableval" != no then Py_BOLT='true' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; }; else Py_BOLT='false' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; }; fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -8116,11 +8844,12 @@ if test "$Py_BOLT" = 'true' ; then # -fno-reorder-blocks-and-partition is required for bolt to work. # Possibly GCC only. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-reorder-blocks-and-partition" >&5 -$as_echo_n "checking whether C compiler accepts -fno-reorder-blocks-and-partition... " >&6; } -if ${ax_cv_check_cflags___fno_reorder_blocks_and_partition+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-reorder-blocks-and-partition" >&5 +printf %s "checking whether C compiler accepts -fno-reorder-blocks-and-partition... " >&6; } +if test ${ax_cv_check_cflags___fno_reorder_blocks_and_partition+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fno-reorder-blocks-and-partition" @@ -8128,28 +8857,30 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ax_cv_check_cflags___fno_reorder_blocks_and_partition=yes -else +else $as_nop ax_cv_check_cflags___fno_reorder_blocks_and_partition=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&5 -$as_echo "$ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&6; } -if test "x$ax_cv_check_cflags___fno_reorder_blocks_and_partition" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&5 +printf "%s\n" "$ax_cv_check_cflags___fno_reorder_blocks_and_partition" >&6; } +if test "x$ax_cv_check_cflags___fno_reorder_blocks_and_partition" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -fno-reorder-blocks-and-partition" -else +else $as_nop : fi @@ -8165,11 +8896,12 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}llvm-bolt", so it can be a program name with args. set dummy ${ac_tool_prefix}llvm-bolt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_LLVM_BOLT+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_LLVM_BOLT+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $LLVM_BOLT in [\\/]* | ?:[\\/]*) ac_cv_path_LLVM_BOLT="$LLVM_BOLT" # Let the user override the test with a path. @@ -8179,11 +8911,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_LLVM_BOLT="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_LLVM_BOLT="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -8195,11 +8931,11 @@ esac fi LLVM_BOLT=$ac_cv_path_LLVM_BOLT if test -n "$LLVM_BOLT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_BOLT" >&5 -$as_echo "$LLVM_BOLT" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LLVM_BOLT" >&5 +printf "%s\n" "$LLVM_BOLT" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -8208,11 +8944,12 @@ if test -z "$ac_cv_path_LLVM_BOLT"; then ac_pt_LLVM_BOLT=$LLVM_BOLT # Extract the first word of "llvm-bolt", so it can be a program name with args. set dummy llvm-bolt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_LLVM_BOLT+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_LLVM_BOLT+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_LLVM_BOLT in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_LLVM_BOLT="$ac_pt_LLVM_BOLT" # Let the user override the test with a path. @@ -8222,11 +8959,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_LLVM_BOLT="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_LLVM_BOLT="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -8238,11 +8979,11 @@ esac fi ac_pt_LLVM_BOLT=$ac_cv_path_ac_pt_LLVM_BOLT if test -n "$ac_pt_LLVM_BOLT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_BOLT" >&5 -$as_echo "$ac_pt_LLVM_BOLT" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_BOLT" >&5 +printf "%s\n" "$ac_pt_LLVM_BOLT" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_LLVM_BOLT" = x; then @@ -8250,8 +8991,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LLVM_BOLT=$ac_pt_LLVM_BOLT @@ -8262,8 +9003,8 @@ fi if test -n "${LLVM_BOLT}" -a -x "${LLVM_BOLT}" then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"Found llvm-bolt\"" >&5 -$as_echo "\"Found llvm-bolt\"" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"Found llvm-bolt\"" >&5 +printf "%s\n" "\"Found llvm-bolt\"" >&6; } else as_fn_error $? "llvm-bolt is required for a --enable-bolt build but could not be found." "$LINENO" 5 fi @@ -8272,11 +9013,12 @@ $as_echo "\"Found llvm-bolt\"" >&6; } if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}merge-fdata", so it can be a program name with args. set dummy ${ac_tool_prefix}merge-fdata; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_MERGE_FDATA+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_MERGE_FDATA+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $MERGE_FDATA in [\\/]* | ?:[\\/]*) ac_cv_path_MERGE_FDATA="$MERGE_FDATA" # Let the user override the test with a path. @@ -8286,11 +9028,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_MERGE_FDATA="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_MERGE_FDATA="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -8302,11 +9048,11 @@ esac fi MERGE_FDATA=$ac_cv_path_MERGE_FDATA if test -n "$MERGE_FDATA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MERGE_FDATA" >&5 -$as_echo "$MERGE_FDATA" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MERGE_FDATA" >&5 +printf "%s\n" "$MERGE_FDATA" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -8315,11 +9061,12 @@ if test -z "$ac_cv_path_MERGE_FDATA"; then ac_pt_MERGE_FDATA=$MERGE_FDATA # Extract the first word of "merge-fdata", so it can be a program name with args. set dummy merge-fdata; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_MERGE_FDATA+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_MERGE_FDATA+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_MERGE_FDATA in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_MERGE_FDATA="$ac_pt_MERGE_FDATA" # Let the user override the test with a path. @@ -8329,11 +9076,15 @@ else for as_dir in ${llvm_path} do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_MERGE_FDATA="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_MERGE_FDATA="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -8345,11 +9096,11 @@ esac fi ac_pt_MERGE_FDATA=$ac_cv_path_ac_pt_MERGE_FDATA if test -n "$ac_pt_MERGE_FDATA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_MERGE_FDATA" >&5 -$as_echo "$ac_pt_MERGE_FDATA" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_MERGE_FDATA" >&5 +printf "%s\n" "$ac_pt_MERGE_FDATA" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_MERGE_FDATA" = x; then @@ -8357,8 +9108,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MERGE_FDATA=$ac_pt_MERGE_FDATA @@ -8369,8 +9120,8 @@ fi if test -n "${MERGE_FDATA}" -a -x "${MERGE_FDATA}" then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"Found merge-fdata\"" >&5 -$as_echo "\"Found merge-fdata\"" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"Found merge-fdata\"" >&5 +printf "%s\n" "\"Found merge-fdata\"" >&6; } else as_fn_error $? "merge-fdata is required for a --enable-bolt build but could not be found." "$LINENO" 5 fi @@ -8378,32 +9129,33 @@ fi BOLT_BINARIES='$(BUILDPYTHON)' -if test "x$enable_shared" = xyes; then : +if test "x$enable_shared" = xyes +then : BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking BOLT_INSTRUMENT_FLAGS" >&5 -$as_echo_n "checking BOLT_INSTRUMENT_FLAGS... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BOLT_INSTRUMENT_FLAGS" >&5 +printf %s "checking BOLT_INSTRUMENT_FLAGS... " >&6; } if test -z "${BOLT_INSTRUMENT_FLAGS}" then BOLT_INSTRUMENT_FLAGS= fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOLT_INSTRUMENT_FLAGS" >&5 -$as_echo "$BOLT_INSTRUMENT_FLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BOLT_INSTRUMENT_FLAGS" >&5 +printf "%s\n" "$BOLT_INSTRUMENT_FLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking BOLT_APPLY_FLAGS" >&5 -$as_echo_n "checking BOLT_APPLY_FLAGS... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BOLT_APPLY_FLAGS" >&5 +printf %s "checking BOLT_APPLY_FLAGS... " >&6; } if test -z "${BOLT_APPLY_FLAGS}" then BOLT_APPLY_FLAGS=" -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot " fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 -$as_echo "$BOLT_APPLY_FLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 +printf "%s\n" "$BOLT_APPLY_FLAGS" >&6; } # XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be # merged with this chunk of code? @@ -8433,76 +9185,82 @@ esac save_CFLAGS=$CFLAGS CFLAGS="-fstrict-overflow -fno-strict-overflow" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fstrict-overflow and -fno-strict-overflow" >&5 -$as_echo_n "checking if $CC supports -fstrict-overflow and -fno-strict-overflow... " >&6; } -if ${ac_cv_cc_supports_fstrict_overflow+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fstrict-overflow and -fno-strict-overflow" >&5 +printf %s "checking if $CC supports -fstrict-overflow and -fno-strict-overflow... " >&6; } +if test ${ac_cv_cc_supports_fstrict_overflow+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_cc_supports_fstrict_overflow=yes -else +else $as_nop ac_cv_cc_supports_fstrict_overflow=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_fstrict_overflow" >&5 -$as_echo "$ac_cv_cc_supports_fstrict_overflow" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_fstrict_overflow" >&5 +printf "%s\n" "$ac_cv_cc_supports_fstrict_overflow" >&6; } CFLAGS=$save_CFLAGS -if test "x$ac_cv_cc_supports_fstrict_overflow" = xyes; then : +if test "x$ac_cv_cc_supports_fstrict_overflow" = xyes +then : STRICT_OVERFLOW_CFLAGS="-fstrict-overflow" NO_STRICT_OVERFLOW_CFLAGS="-fno-strict-overflow" -else +else $as_nop STRICT_OVERFLOW_CFLAGS="" NO_STRICT_OVERFLOW_CFLAGS="" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-strict-overflow" >&5 -$as_echo_n "checking for --with-strict-overflow... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-strict-overflow" >&5 +printf %s "checking for --with-strict-overflow... " >&6; } # Check whether --with-strict-overflow was given. -if test "${with_strict_overflow+set}" = set; then : +if test ${with_strict_overflow+y} +then : withval=$with_strict_overflow; - if test "x$ac_cv_cc_supports_fstrict_overflow" = xno; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&5 -$as_echo "$as_me: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&2;} + if test "x$ac_cv_cc_supports_fstrict_overflow" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&5 +printf "%s\n" "$as_me: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&2;} fi -else +else $as_nop with_strict_overflow=no fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_strict_overflow" >&5 -$as_echo "$with_strict_overflow" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_strict_overflow" >&5 +printf "%s\n" "$with_strict_overflow" >&6; } # Check if CC supports -Og optimization level save_CFLAGS=$CFLAGS CFLAGS="-Og" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Og optimization level" >&5 -$as_echo_n "checking if $CC supports -Og optimization level... " >&6; } -if ${ac_cv_cc_supports_og+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Og optimization level" >&5 +printf %s "checking if $CC supports -Og optimization level... " >&6; } +if test ${ac_cv_cc_supports_og+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -8510,26 +9268,28 @@ main () } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_cc_supports_og=yes -else +else $as_nop ac_cv_cc_supports_og=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_og" >&5 -$as_echo "$ac_cv_cc_supports_og" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_og" >&5 +printf "%s\n" "$ac_cv_cc_supports_og" >&6; } CFLAGS=$save_CFLAGS # Optimization messes up debuggers, so turn it off for # debug builds. PYDEBUG_CFLAGS="-O0" -if test "x$ac_cv_cc_supports_og" = xyes; then : +if test "x$ac_cv_cc_supports_og" = xyes +then : PYDEBUG_CFLAGS="-Og" fi @@ -8577,9 +9337,10 @@ fi case $ac_sys_system in #( Emscripten) : - if test "x$Py_DEBUG" = xyes; then : + if test "x$Py_DEBUG" = xyes +then : wasm_debug=yes -else +else $as_nop wasm_debug=no fi @@ -8589,13 +9350,15 @@ fi as_fn_append LDFLAGS_NODIST " -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js" - if test "x$enable_wasm_dynamic_linking" = xyes; then : + if test "x$enable_wasm_dynamic_linking" = xyes +then : as_fn_append LINKFORSHARED " -sMAIN_MODULE" fi - if test "x$enable_wasm_pthreads" = xyes; then : + if test "x$enable_wasm_pthreads" = xyes +then : as_fn_append CFLAGS_NODIST " -pthread" as_fn_append LDFLAGS_NODIST " -sUSE_PTHREADS" @@ -8606,7 +9369,8 @@ fi case $ac_sys_emscripten_target in #( browser*) : - if test "x$ac_sys_emscripten_target" = xbrowser-debug; then : + if test "x$ac_sys_emscripten_target" = xbrowser-debug +then : wasm_debug=yes fi as_fn_append LINKFORSHARED " --preload-file=\$(WASM_ASSETS_DIR)" @@ -8616,7 +9380,8 @@ fi ;; #( node*) : - if test "x$ac_sys_emscripten_target" = xnode-debug; then : + if test "x$ac_sys_emscripten_target" = xnode-debug +then : wasm_debug=yes fi as_fn_append LDFLAGS_NODIST " -sALLOW_MEMORY_GROWTH -sNODERAWFS" @@ -8628,12 +9393,13 @@ fi ;; esac - if test "x$wasm_debug" = xyes; then : + if test "x$wasm_debug" = xyes +then : as_fn_append LDFLAGS_NODIST " -sASSERTIONS" as_fn_append LINKFORSHARED " $WASM_LINKFORSHARED_DEBUG" -else +else $as_nop as_fn_append LINKFORSHARED " -O2 -g0" @@ -8642,13 +9408,13 @@ fi WASI) : -$as_echo "#define _WASI_EMULATED_SIGNAL 1" >>confdefs.h +printf "%s\n" "#define _WASI_EMULATED_SIGNAL 1" >>confdefs.h -$as_echo "#define _WASI_EMULATED_GETPID 1" >>confdefs.h +printf "%s\n" "#define _WASI_EMULATED_GETPID 1" >>confdefs.h -$as_echo "#define _WASI_EMULATED_PROCESS_CLOCKS 1" >>confdefs.h +printf "%s\n" "#define _WASI_EMULATED_PROCESS_CLOCKS 1" >>confdefs.h LIBS="$LIBS -lwasi-emulated-signal -lwasi-emulated-getpid -lwasi-emulated-process-clocks" echo "#define _WASI_EMULATED_SIGNAL 1" >> confdefs.h @@ -8686,9 +9452,10 @@ UNIVERSAL_ARCH_FLAGS= # tweak BASECFLAGS based on compiler and platform -if test "x$with_strict_overflow" = xyes; then : +if test "x$with_strict_overflow" = xyes +then : BASECFLAGS="$BASECFLAGS $STRICT_OVERFLOW_CFLAGS" -else +else $as_nop BASECFLAGS="$BASECFLAGS $NO_STRICT_OVERFLOW_CFLAGS" fi @@ -8698,11 +9465,12 @@ yes) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can add -Wextra" >&5 -$as_echo_n "checking if we can add -Wextra... " >&6; } -if ${ac_cv_enable_extra_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Wextra" >&5 +printf %s "checking if we can add -Wextra... " >&6; } +if test ${ac_cv_enable_extra_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wextra -Werror" @@ -8710,27 +9478,29 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_enable_extra_warning=yes -else +else $as_nop ac_cv_enable_extra_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_extra_warning" >&5 -$as_echo "$ac_cv_enable_extra_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_extra_warning" >&5 +printf "%s\n" "$ac_cv_enable_extra_warning" >&6; } - if test "x$ac_cv_enable_extra_warning" = xyes; then : + if test "x$ac_cv_enable_extra_warning" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -Wextra" fi @@ -8741,17 +9511,18 @@ fi ac_save_cc="$CC" CC="$CC -fno-strict-aliasing" save_CFLAGS="$CFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts and needs -fno-strict-aliasing" >&5 -$as_echo_n "checking whether $CC accepts and needs -fno-strict-aliasing... " >&6; } -if ${ac_cv_no_strict_aliasing+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts and needs -fno-strict-aliasing" >&5 +printf %s "checking whether $CC accepts and needs -fno-strict-aliasing... " >&6; } +if test ${ac_cv_no_strict_aliasing+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -8759,7 +9530,8 @@ main () } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : CC="$ac_save_cc -fstrict-aliasing" CFLAGS="$CFLAGS -Werror -Wstrict-aliasing" @@ -8768,7 +9540,7 @@ if ac_fn_c_try_compile "$LINENO"; then : void f(int **x) {} int -main () +main (void) { double *x; f((int **) &x); ; @@ -8776,29 +9548,31 @@ double *x; f((int **) &x); } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_no_strict_aliasing=no -else +else $as_nop ac_cv_no_strict_aliasing=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else +else $as_nop ac_cv_no_strict_aliasing=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_no_strict_aliasing" >&5 -$as_echo "$ac_cv_no_strict_aliasing" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_no_strict_aliasing" >&5 +printf "%s\n" "$ac_cv_no_strict_aliasing" >&6; } CFLAGS="$save_CFLAGS" CC="$ac_save_cc" - if test "x$ac_cv_no_strict_aliasing" = xyes; then : + if test "x$ac_cv_no_strict_aliasing" = xyes +then : BASECFLAGS="$BASECFLAGS -fno-strict-aliasing" fi @@ -8809,11 +9583,12 @@ fi ac_cv_disable_unused_result_warning=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC unused-result warning" >&5 -$as_echo_n "checking if we can disable $CC unused-result warning... " >&6; } -if ${ac_cv_disable_unused_result_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC unused-result warning" >&5 +printf %s "checking if we can disable $CC unused-result warning... " >&6; } +if test ${ac_cv_disable_unused_result_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wunused-result -Werror" @@ -8821,41 +9596,44 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_disable_unused_result_warning=yes -else +else $as_nop ac_cv_disable_unused_result_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_result_warning" >&5 -$as_echo "$ac_cv_disable_unused_result_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_result_warning" >&5 +printf "%s\n" "$ac_cv_disable_unused_result_warning" >&6; } ;; #( *) : ;; esac - if test "x$ac_cv_disable_unused_result_warning" = xyes; then : + if test "x$ac_cv_disable_unused_result_warning" = xyes +then : BASECFLAGS="$BASECFLAGS -Wno-unused-result" CFLAGS_NODIST="$CFLAGS_NODIST -Wno-unused-result" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC unused-parameter warning" >&5 -$as_echo_n "checking if we can disable $CC unused-parameter warning... " >&6; } -if ${ac_cv_disable_unused_parameter_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC unused-parameter warning" >&5 +printf %s "checking if we can disable $CC unused-parameter warning... " >&6; } +if test ${ac_cv_disable_unused_parameter_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wunused-parameter -Werror" @@ -8863,37 +9641,40 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_disable_unused_parameter_warning=yes -else +else $as_nop ac_cv_disable_unused_parameter_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_parameter_warning" >&5 -$as_echo "$ac_cv_disable_unused_parameter_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_unused_parameter_warning" >&5 +printf "%s\n" "$ac_cv_disable_unused_parameter_warning" >&6; } - if test "x$ac_cv_disable_unused_parameter_warning" = xyes; then : + if test "x$ac_cv_disable_unused_parameter_warning" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -Wno-unused-parameter" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC int-conversion warning" >&5 -$as_echo_n "checking if we can disable $CC int-conversion warning... " >&6; } -if ${ac_cv_disable_int_conversion_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC int-conversion warning" >&5 +printf %s "checking if we can disable $CC int-conversion warning... " >&6; } +if test ${ac_cv_disable_int_conversion_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wint-conversion -Werror" @@ -8901,37 +9682,40 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_disable_int_conversion_warning=yes -else +else $as_nop ac_cv_disable_int_conversion_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_int_conversion_warning" >&5 -$as_echo "$ac_cv_disable_int_conversion_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_int_conversion_warning" >&5 +printf "%s\n" "$ac_cv_disable_int_conversion_warning" >&6; } - if test "x$ac_cv_disable_int_conversion" = xyes; then : + if test "x$ac_cv_disable_int_conversion" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -Wno-int-conversion" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC missing-field-initializers warning" >&5 -$as_echo_n "checking if we can disable $CC missing-field-initializers warning... " >&6; } -if ${ac_cv_disable_missing_field_initializers_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can disable $CC missing-field-initializers warning" >&5 +printf %s "checking if we can disable $CC missing-field-initializers warning... " >&6; } +if test ${ac_cv_disable_missing_field_initializers_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wmissing-field-initializers -Werror" @@ -8939,37 +9723,40 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_disable_missing_field_initializers_warning=yes -else +else $as_nop ac_cv_disable_missing_field_initializers_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_missing_field_initializers_warning" >&5 -$as_echo "$ac_cv_disable_missing_field_initializers_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_disable_missing_field_initializers_warning" >&5 +printf "%s\n" "$ac_cv_disable_missing_field_initializers_warning" >&6; } - if test "x$ac_cv_disable_missing_field_initializers_warning" = xyes; then : + if test "x$ac_cv_disable_missing_field_initializers_warning" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -Wno-missing-field-initializers" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can enable $CC sign-compare warning" >&5 -$as_echo_n "checking if we can enable $CC sign-compare warning... " >&6; } -if ${ac_cv_enable_sign_compare_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can enable $CC sign-compare warning" >&5 +printf %s "checking if we can enable $CC sign-compare warning... " >&6; } +if test ${ac_cv_enable_sign_compare_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wsign-compare -Werror" @@ -8977,37 +9764,40 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_enable_sign_compare_warning=yes -else +else $as_nop ac_cv_enable_sign_compare_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_sign_compare_warning" >&5 -$as_echo "$ac_cv_enable_sign_compare_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_sign_compare_warning" >&5 +printf "%s\n" "$ac_cv_enable_sign_compare_warning" >&6; } - if test "x$ac_cv_enable_sign_compare_warning" = xyes; then : + if test "x$ac_cv_enable_sign_compare_warning" = xyes +then : BASECFLAGS="$BASECFLAGS -Wsign-compare" fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can enable $CC unreachable-code warning" >&5 -$as_echo_n "checking if we can enable $CC unreachable-code warning... " >&6; } -if ${ac_cv_enable_unreachable_code_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can enable $CC unreachable-code warning" >&5 +printf %s "checking if we can enable $CC unreachable-code warning... " >&6; } +if test ${ac_cv_enable_unreachable_code_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wunreachable-code -Werror" @@ -9015,24 +9805,25 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_enable_unreachable_code_warning=yes -else +else $as_nop ac_cv_enable_unreachable_code_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_unreachable_code_warning" >&5 -$as_echo "$ac_cv_enable_unreachable_code_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_unreachable_code_warning" >&5 +printf "%s\n" "$ac_cv_enable_unreachable_code_warning" >&6; } # Don't enable unreachable code warning in debug mode, since it usually @@ -9053,11 +9844,12 @@ $as_echo "$ac_cv_enable_unreachable_code_warning" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can enable $CC strict-prototypes warning" >&5 -$as_echo_n "checking if we can enable $CC strict-prototypes warning... " >&6; } -if ${ac_cv_enable_strict_prototypes_warning+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can enable $CC strict-prototypes warning" >&5 +printf %s "checking if we can enable $CC strict-prototypes warning... " >&6; } +if test ${ac_cv_enable_strict_prototypes_warning+y} +then : + printf %s "(cached) " >&6 +else $as_nop py_cflags=$CFLAGS as_fn_append CFLAGS "-Wstrict-prototypes -Werror" @@ -9065,43 +9857,46 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_enable_strict_prototypes_warning=yes -else +else $as_nop ac_cv_enable_strict_prototypes_warning=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$py_cflags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_strict_prototypes_warning" >&5 -$as_echo "$ac_cv_enable_strict_prototypes_warning" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_strict_prototypes_warning" >&5 +printf "%s\n" "$ac_cv_enable_strict_prototypes_warning" >&6; } - if test "x$ac_cv_enable_strict_prototypes_warning" = xyes; then : + if test "x$ac_cv_enable_strict_prototypes_warning" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -Wstrict-prototypes" fi ac_save_cc="$CC" CC="$CC -Werror=implicit-function-declaration" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can make implicit function declaration an error in $CC" >&5 -$as_echo_n "checking if we can make implicit function declaration an error in $CC... " >&6; } -if ${ac_cv_enable_implicit_function_declaration_error+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can make implicit function declaration an error in $CC" >&5 +printf %s "checking if we can make implicit function declaration an error in $CC... " >&6; } +if test ${ac_cv_enable_implicit_function_declaration_error+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -9109,38 +9904,41 @@ main () } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_enable_implicit_function_declaration_error=yes -else +else $as_nop ac_cv_enable_implicit_function_declaration_error=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_implicit_function_declaration_error" >&5 -$as_echo "$ac_cv_enable_implicit_function_declaration_error" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_implicit_function_declaration_error" >&5 +printf "%s\n" "$ac_cv_enable_implicit_function_declaration_error" >&6; } CC="$ac_save_cc" - if test "x$ac_cv_enable_implicit_function_declaration_error" = xyes; then : + if test "x$ac_cv_enable_implicit_function_declaration_error" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -Werror=implicit-function-declaration" fi ac_save_cc="$CC" CC="$CC -fvisibility=hidden" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can use visibility in $CC" >&5 -$as_echo_n "checking if we can use visibility in $CC... " >&6; } -if ${ac_cv_enable_visibility+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can use visibility in $CC" >&5 +printf %s "checking if we can use visibility in $CC... " >&6; } +if test ${ac_cv_enable_visibility+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -9148,22 +9946,24 @@ main () } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_enable_visibility=yes -else +else $as_nop ac_cv_enable_visibility=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_visibility" >&5 -$as_echo "$ac_cv_enable_visibility" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_visibility" >&5 +printf "%s\n" "$ac_cv_enable_visibility" >&6; } CC="$ac_save_cc" - if test "x$ac_cv_enable_visibility" = xyes; then : + if test "x$ac_cv_enable_visibility" = xyes +then : CFLAGS_NODIST="$CFLAGS_NODIST -fvisibility=hidden" fi @@ -9186,8 +9986,8 @@ fi # used to be here, but non-Apple gcc doesn't accept them. if test "${CC}" = gcc then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking which compiler should be used" >&5 -$as_echo_n "checking which compiler should be used... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which compiler should be used" >&5 +printf %s "checking which compiler should be used... " >&6; } case "${UNIVERSALSDK}" in */MacOSX10.4u.sdk) # Build using 10.4 SDK, force usage of gcc when the @@ -9197,8 +9997,8 @@ $as_echo_n "checking which compiler should be used... " >&6; } CPP=cpp-4.0 ;; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } fi LIPO_INTEL64_FLAGS="" @@ -9275,8 +10075,8 @@ $as_echo "$CC" >&6; } # below to pick either 10.3, 10.4, or 10.5 as the target. # 4. If we are running on OS X 10.2 or earlier, good luck! - { $as_echo "$as_me:${as_lineno-$LINENO}: checking which MACOSX_DEPLOYMENT_TARGET to use" >&5 -$as_echo_n "checking which MACOSX_DEPLOYMENT_TARGET to use... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which MACOSX_DEPLOYMENT_TARGET to use" >&5 +printf %s "checking which MACOSX_DEPLOYMENT_TARGET to use... " >&6; } cur_target_major=`sw_vers -productVersion | \ sed 's/\([0-9]*\)\.\([0-9]*\).*/\1/'` cur_target_minor=`sw_vers -productVersion | \ @@ -9313,32 +10113,33 @@ $as_echo_n "checking which MACOSX_DEPLOYMENT_TARGET to use... " >&6; } MACOSX_DEPLOYMENT_TARGET="$CONFIGURE_MACOSX_DEPLOYMENT_TARGET" export MACOSX_DEPLOYMENT_TARGET EXPORT_MACOSX_DEPLOYMENT_TARGET='' - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MACOSX_DEPLOYMENT_TARGET" >&5 -$as_echo "$MACOSX_DEPLOYMENT_TARGET" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MACOSX_DEPLOYMENT_TARGET" >&5 +printf "%s\n" "$MACOSX_DEPLOYMENT_TARGET" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if specified universal architectures work" >&5 -$as_echo_n "checking if specified universal architectures work... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if specified universal architectures work" >&5 +printf %s "checking if specified universal architectures work... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { printf("%d", 42); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +if ac_fn_c_try_link "$LINENO" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } as_fn_error $? "check config.log and use the '--with-universal-archs' option" "$LINENO" 5 fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext # end of Darwin* tests @@ -9384,14 +10185,16 @@ fi # complain if unaccepted options are passed (e.g. gcc on Mac OS X). # So we have to see first whether pthreads are available without # options before we can check whether -Kpthread improves anything. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads are available without options" >&5 -$as_echo_n "checking whether pthreads are available without options... " >&6; } -if ${ac_cv_pthread_is_default+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads are available without options" >&5 +printf %s "checking whether pthreads are available without options... " >&6; } +if test ${ac_cv_pthread_is_default+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_pthread_is_default=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9409,13 +10212,14 @@ int main(void){ } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_pthread_is_default=yes ac_cv_kthread=no ac_cv_pthread=no -else +else $as_nop ac_cv_pthread_is_default=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -9424,8 +10228,8 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_is_default" >&5 -$as_echo "$ac_cv_pthread_is_default" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_is_default" >&5 +printf "%s\n" "$ac_cv_pthread_is_default" >&6; } if test $ac_cv_pthread_is_default = yes @@ -9437,16 +10241,18 @@ else # Some compilers won't report that they do not support -Kpthread, # so we need to run a program to see whether it really made the # function available. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kpthread" >&5 -$as_echo_n "checking whether $CC accepts -Kpthread... " >&6; } -if ${ac_cv_kpthread+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kpthread" >&5 +printf %s "checking whether $CC accepts -Kpthread... " >&6; } +if test ${ac_cv_kpthread+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cc="$CC" CC="$CC -Kpthread" -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : ac_cv_kpthread=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9464,9 +10270,10 @@ int main(void){ } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_kpthread=yes -else +else $as_nop ac_cv_kpthread=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -9475,8 +10282,8 @@ fi CC="$ac_save_cc" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kpthread" >&5 -$as_echo "$ac_cv_kpthread" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kpthread" >&5 +printf "%s\n" "$ac_cv_kpthread" >&6; } fi if test $ac_cv_kpthread = no -a $ac_cv_pthread_is_default = no @@ -9486,16 +10293,18 @@ then # Some compilers won't report that they do not support -Kthread, # so we need to run a program to see whether it really made the # function available. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kthread" >&5 -$as_echo_n "checking whether $CC accepts -Kthread... " >&6; } -if ${ac_cv_kthread+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kthread" >&5 +printf %s "checking whether $CC accepts -Kthread... " >&6; } +if test ${ac_cv_kthread+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cc="$CC" CC="$CC -Kthread" -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : ac_cv_kthread=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9513,9 +10322,10 @@ int main(void){ } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_kthread=yes -else +else $as_nop ac_cv_kthread=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -9524,8 +10334,8 @@ fi CC="$ac_save_cc" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kthread" >&5 -$as_echo "$ac_cv_kthread" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_kthread" >&5 +printf "%s\n" "$ac_cv_kthread" >&6; } fi if test $ac_cv_kthread = no -a $ac_cv_pthread_is_default = no @@ -9535,16 +10345,18 @@ then # Some compilers won't report that they do not support -pthread, # so we need to run a program to see whether it really made the # function available. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -pthread" >&5 -$as_echo_n "checking whether $CC accepts -pthread... " >&6; } -if ${ac_cv_pthread+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -pthread" >&5 +printf %s "checking whether $CC accepts -pthread... " >&6; } +if test ${ac_cv_pthread+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cc="$CC" CC="$CC -pthread" -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : ac_cv_pthread=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -9562,9 +10374,10 @@ int main(void){ } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_pthread=yes -else +else $as_nop ac_cv_pthread=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -9573,19 +10386,20 @@ fi CC="$ac_save_cc" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread" >&5 -$as_echo "$ac_cv_pthread" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread" >&5 +printf "%s\n" "$ac_cv_pthread" >&6; } fi # If we have set a CC compiler flag for thread support then # check if it works for CXX, too. if test ! -z "$CXX" then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX also accepts flags for thread support" >&5 -$as_echo_n "checking whether $CXX also accepts flags for thread support... " >&6; } -if ${ac_cv_cxx_thread+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX also accepts flags for thread support" >&5 +printf %s "checking whether $CXX also accepts flags for thread support... " >&6; } +if test ${ac_cv_cxx_thread+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cxx="$CXX" if test "$ac_cv_kpthread" = "yes" @@ -9619,520 +10433,990 @@ then fi CXX="$ac_save_cxx" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_thread" >&5 -$as_echo "$ac_cv_cxx_thread" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_thread" >&5 +printf "%s\n" "$ac_cv_cxx_thread" >&6; } else ac_cv_cxx_thread=no fi -$as_echo "#define STDC_HEADERS 1" >>confdefs.h +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h # checks for header files -for ac_header in \ - alloca.h asm/types.h bluetooth.h conio.h crypt.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \ - ieeefp.h io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/memfd.h \ - linux/random.h linux/soundcard.h \ - linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \ - sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \ - sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \ - sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h sys/param.h sys/poll.h \ - sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \ - sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.h sys/termio.h sys/time.h sys/times.h \ - sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h sys/xattr.h sysexits.h syslog.h \ - termios.h util.h utime.h utmp.h \ +ac_fn_c_check_header_compile "$LINENO" "alloca.h" "ac_cv_header_alloca_h" "$ac_includes_default" +if test "x$ac_cv_header_alloca_h" = xyes +then : + printf "%s\n" "#define HAVE_ALLOCA_H 1" >>confdefs.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "asm/types.h" "ac_cv_header_asm_types_h" "$ac_includes_default" +if test "x$ac_cv_header_asm_types_h" = xyes +then : + printf "%s\n" "#define HAVE_ASM_TYPES_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "bluetooth.h" "ac_cv_header_bluetooth_h" "$ac_includes_default" +if test "x$ac_cv_header_bluetooth_h" = xyes +then : + printf "%s\n" "#define HAVE_BLUETOOTH_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "conio.h" "ac_cv_header_conio_h" "$ac_includes_default" +if test "x$ac_cv_header_conio_h" = xyes +then : + printf "%s\n" "#define HAVE_CONIO_H 1" >>confdefs.h -ac_header_dirent=no -for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do - as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 -$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if eval \${$as_ac_Header+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include <$ac_hdr> +fi +ac_fn_c_check_header_compile "$LINENO" "crypt.h" "ac_cv_header_crypt_h" "$ac_includes_default" +if test "x$ac_cv_header_crypt_h" = xyes +then : + printf "%s\n" "#define HAVE_CRYPT_H 1" >>confdefs.h -int -main () -{ -if ((DIR *) 0) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$as_ac_Header=yes" -else - eval "$as_ac_Header=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_fn_c_check_header_compile "$LINENO" "direct.h" "ac_cv_header_direct_h" "$ac_includes_default" +if test "x$ac_cv_header_direct_h" = xyes +then : + printf "%s\n" "#define HAVE_DIRECT_H 1" >>confdefs.h + fi -eval ac_res=\$$as_ac_Header - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" +if test "x$ac_cv_header_dlfcn_h" = xyes +then : + printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h -ac_header_dirent=$ac_hdr; break fi +ac_fn_c_check_header_compile "$LINENO" "endian.h" "ac_cv_header_endian_h" "$ac_includes_default" +if test "x$ac_cv_header_endian_h" = xyes +then : + printf "%s\n" "#define HAVE_ENDIAN_H 1" >>confdefs.h -done -# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. -if test $ac_header_dirent = dirent.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 -$as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +fi +ac_fn_c_check_header_compile "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" +if test "x$ac_cv_header_errno_h" = xyes +then : + printf "%s\n" "#define HAVE_ERRNO_H 1" >>confdefs.h -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char opendir (); -int -main () -{ -return opendir (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dir; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_opendir=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : - break +ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" +if test "x$ac_cv_header_fcntl_h" = xyes +then : + printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h + fi -done -if ${ac_cv_search_opendir+:} false; then : +ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default" +if test "x$ac_cv_header_grp_h" = xyes +then : + printf "%s\n" "#define HAVE_GRP_H 1" >>confdefs.h -else - ac_cv_search_opendir=no fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +ac_fn_c_check_header_compile "$LINENO" "ieeefp.h" "ac_cv_header_ieeefp_h" "$ac_includes_default" +if test "x$ac_cv_header_ieeefp_h" = xyes +then : + printf "%s\n" "#define HAVE_IEEEFP_H 1" >>confdefs.h + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 -$as_echo "$ac_cv_search_opendir" >&6; } -ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" +ac_fn_c_check_header_compile "$LINENO" "io.h" "ac_cv_header_io_h" "$ac_includes_default" +if test "x$ac_cv_header_io_h" = xyes +then : + printf "%s\n" "#define HAVE_IO_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" +if test "x$ac_cv_header_langinfo_h" = xyes +then : + printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 -$as_echo_n "checking for library containing opendir... " >&6; } -if ${ac_cv_search_opendir+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +fi +ac_fn_c_check_header_compile "$LINENO" "libintl.h" "ac_cv_header_libintl_h" "$ac_includes_default" +if test "x$ac_cv_header_libintl_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBINTL_H 1" >>confdefs.h -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char opendir (); -int -main () -{ -return opendir (); - ; - return 0; -} -_ACEOF -for ac_lib in '' x; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_opendir=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_opendir+:} false; then : - break +ac_fn_c_check_header_compile "$LINENO" "libutil.h" "ac_cv_header_libutil_h" "$ac_includes_default" +if test "x$ac_cv_header_libutil_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBUTIL_H 1" >>confdefs.h + fi -done -if ${ac_cv_search_opendir+:} false; then : +ac_fn_c_check_header_compile "$LINENO" "linux/auxvec.h" "ac_cv_header_linux_auxvec_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_auxvec_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_AUXVEC_H 1" >>confdefs.h -else - ac_cv_search_opendir=no fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +ac_fn_c_check_header_compile "$LINENO" "sys/auxv.h" "ac_cv_header_sys_auxv_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_auxv_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_AUXV_H 1" >>confdefs.h + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 -$as_echo "$ac_cv_search_opendir" >&6; } -ac_res=$ac_cv_search_opendir -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" +ac_fn_c_check_header_compile "$LINENO" "linux/fs.h" "ac_cv_header_linux_fs_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_fs_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_FS_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "linux/memfd.h" "ac_cv_header_linux_memfd_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_memfd_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_MEMFD_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "linux/random.h" "ac_cv_header_linux_random_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_random_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_RANDOM_H 1" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 -$as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if ${ac_cv_header_sys_types_h_makedev+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -return makedev(0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_header_sys_types_h_makedev=yes -else - ac_cv_header_sys_types_h_makedev=no fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +ac_fn_c_check_header_compile "$LINENO" "linux/soundcard.h" "ac_cv_header_linux_soundcard_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_soundcard_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_SOUNDCARD_H 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5 -$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; } +ac_fn_c_check_header_compile "$LINENO" "linux/tipc.h" "ac_cv_header_linux_tipc_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_tipc_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_TIPC_H 1" >>confdefs.h -if test $ac_cv_header_sys_types_h_makedev = no; then -ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : +fi +ac_fn_c_check_header_compile "$LINENO" "linux/wait.h" "ac_cv_header_linux_wait_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_wait_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_WAIT_H 1" >>confdefs.h -$as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" +if test "x$ac_cv_header_netdb_h" = xyes +then : + printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "net/ethernet.h" "ac_cv_header_net_ethernet_h" "$ac_includes_default" +if test "x$ac_cv_header_net_ethernet_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_ETHERNET_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" +if test "x$ac_cv_header_netinet_in_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "netpacket/packet.h" "ac_cv_header_netpacket_packet_h" "$ac_includes_default" +if test "x$ac_cv_header_netpacket_packet_h" = xyes +then : + printf "%s\n" "#define HAVE_NETPACKET_PACKET_H 1" >>confdefs.h - if test $ac_cv_header_sys_mkdev_h = no; then - ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : +fi +ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default" +if test "x$ac_cv_header_poll_h" = xyes +then : + printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h -$as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "process.h" "ac_cv_header_process_h" "$ac_includes_default" +if test "x$ac_cv_header_process_h" = xyes +then : + printf "%s\n" "#define HAVE_PROCESS_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes +then : + printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "pty.h" "ac_cv_header_pty_h" "$ac_includes_default" +if test "x$ac_cv_header_pty_h" = xyes +then : + printf "%s\n" "#define HAVE_PTY_H 1" >>confdefs.h - fi fi +ac_fn_c_check_header_compile "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" +if test "x$ac_cv_header_sched_h" = xyes +then : + printf "%s\n" "#define HAVE_SCHED_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" "$ac_includes_default" +if test "x$ac_cv_header_setjmp_h" = xyes +then : + printf "%s\n" "#define HAVE_SETJMP_H 1" >>confdefs.h -# bluetooth/bluetooth.h has been known to not compile with -std=c99. -# http://permalink.gmane.org/gmane.linux.bluez.kernel/22294 -SAVE_CFLAGS=$CFLAGS -CFLAGS="-std=c99 $CFLAGS" -for ac_header in bluetooth/bluetooth.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" -if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_BLUETOOTH_BLUETOOTH_H 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "shadow.h" "ac_cv_header_shadow_h" "$ac_includes_default" +if test "x$ac_cv_header_shadow_h" = xyes +then : + printf "%s\n" "#define HAVE_SHADOW_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "signal.h" "ac_cv_header_signal_h" "$ac_includes_default" +if test "x$ac_cv_header_signal_h" = xyes +then : + printf "%s\n" "#define HAVE_SIGNAL_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "spawn.h" "ac_cv_header_spawn_h" "$ac_includes_default" +if test "x$ac_cv_header_spawn_h" = xyes +then : + printf "%s\n" "#define HAVE_SPAWN_H 1" >>confdefs.h -CFLAGS=$SAVE_CFLAGS +fi +ac_fn_c_check_header_compile "$LINENO" "stropts.h" "ac_cv_header_stropts_h" "$ac_includes_default" +if test "x$ac_cv_header_stropts_h" = xyes +then : + printf "%s\n" "#define HAVE_STROPTS_H 1" >>confdefs.h -# On Darwin (OS X) net/if.h requires sys/socket.h to be imported first. -for ac_header in net/if.h -do : - ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif +fi +ac_fn_c_check_header_compile "$LINENO" "sys/audioio.h" "ac_cv_header_sys_audioio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_audioio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_AUDIOIO_H 1" >>confdefs.h -" -if test "x$ac_cv_header_net_if_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_NET_IF_H 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/bsdtty.h" "ac_cv_header_sys_bsdtty_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_bsdtty_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_BSDTTY_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "sys/devpoll.h" "ac_cv_header_sys_devpoll_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_devpoll_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_DEVPOLL_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "sys/endian.h" "ac_cv_header_sys_endian_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_endian_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_ENDIAN_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_epoll_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_EPOLL_H 1" >>confdefs.h -# On Linux, netlink.h requires asm/types.h -for ac_header in linux/netlink.h -do : - ac_fn_c_check_header_compile "$LINENO" "linux/netlink.h" "ac_cv_header_linux_netlink_h" " -#ifdef HAVE_ASM_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +fi +ac_fn_c_check_header_compile "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_event_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_EVENT_H 1" >>confdefs.h -" -if test "x$ac_cv_header_linux_netlink_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LINUX_NETLINK_H 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/eventfd.h" "ac_cv_header_sys_eventfd_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_eventfd_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_EVENTFD_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "sys/file.h" "ac_cv_header_sys_file_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_file_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_FILE_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_ioctl_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/kern_control.h" "ac_cv_header_sys_kern_control_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_kern_control_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_KERN_CONTROL_H 1" >>confdefs.h -# On Linux, qrtr.h requires asm/types.h -for ac_header in linux/qrtr.h -do : - ac_fn_c_check_header_compile "$LINENO" "linux/qrtr.h" "ac_cv_header_linux_qrtr_h" " -#ifdef HAVE_ASM_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +fi +ac_fn_c_check_header_compile "$LINENO" "sys/loadavg.h" "ac_cv_header_sys_loadavg_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_loadavg_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_LOADAVG_H 1" >>confdefs.h -" -if test "x$ac_cv_header_linux_qrtr_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LINUX_QRTR_H 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/lock.h" "ac_cv_header_sys_lock_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_lock_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_LOCK_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "sys/memfd.h" "ac_cv_header_sys_memfd_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_memfd_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_MEMFD_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mkdev_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_MKDEV_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_MMAN_H 1" >>confdefs.h -for ac_header in linux/vm_sockets.h -do : - ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" " -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +fi +ac_fn_c_check_header_compile "$LINENO" "sys/modem.h" "ac_cv_header_sys_modem_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_modem_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_MODEM_H 1" >>confdefs.h -" -if test "x$ac_cv_header_linux_vm_sockets_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LINUX_VM_SOCKETS_H 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_param_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_poll_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_POLL_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_random_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_resource_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_RESOURCE_H 1" >>confdefs.h -# On Linux, can.h, can/bcm.h, can/j1939.h, can/raw.h require sys/socket.h -# On NetBSD, netcan/can.h requires sys/socket.h -for ac_header in linux/can.h linux/can/bcm.h linux/can/j1939.h linux/can/raw.h netcan/can.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" " -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +fi +ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_select_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sendfile.h" "ac_cv_header_sys_sendfile_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sendfile_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SENDFILE_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_socket_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "sys/soundcard.h" "ac_cv_header_sys_soundcard_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_soundcard_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SOUNDCARD_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_stat_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_STAT_H 1" >>confdefs.h -# checks for typedefs -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_t in time.h" >&5 -$as_echo_n "checking for clock_t in time.h... " >&6; } -if ${ac_cv_clock_t_time_h+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi +ac_fn_c_check_header_compile "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_statvfs_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_STATVFS_H 1" >>confdefs.h - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sys_domain.h" "ac_cv_header_sys_sys_domain_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sys_domain_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SYS_DOMAIN_H 1" >>confdefs.h -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "clock_t" >/dev/null 2>&1; then : - ac_cv_clock_t_time_h=yes -else - ac_cv_clock_t_time_h=no fi -rm -f conftest* +ac_fn_c_check_header_compile "$LINENO" "sys/syscall.h" "ac_cv_header_sys_syscall_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_syscall_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SYSCALL_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sysmacros_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_SYSMACROS_H 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_clock_t_time_h" >&5 -$as_echo "$ac_cv_clock_t_time_h" >&6; } -if test "x$ac_cv_clock_t_time_h" = xno; then : +ac_fn_c_check_header_compile "$LINENO" "sys/termio.h" "ac_cv_header_sys_termio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_termio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TERMIO_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_time_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h -$as_echo "#define clock_t long" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/times.h" "ac_cv_header_sys_times_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_times_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TIMES_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "sys/uio.h" "ac_cv_header_sys_uio_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_uio_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_UIO_H 1" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for makedev" >&5 -$as_echo_n "checking for makedev... " >&6; } -if ${ac_cv_func_makedev+:} false; then : - $as_echo_n "(cached) " >&6 -else +fi +ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_un_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +fi +ac_fn_c_check_header_compile "$LINENO" "sys/utsname.h" "ac_cv_header_sys_utsname_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_utsname_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_UTSNAME_H 1" >>confdefs.h -#if defined(MAJOR_IN_MKDEV) -#include -#elif defined(MAJOR_IN_SYSMACROS) -#include -#else +fi +ac_fn_c_check_header_compile "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_wait_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/xattr.h" "ac_cv_header_sys_xattr_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_xattr_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_XATTR_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sysexits.h" "ac_cv_header_sysexits_h" "$ac_includes_default" +if test "x$ac_cv_header_sysexits_h" = xyes +then : + printf "%s\n" "#define HAVE_SYSEXITS_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "syslog.h" "ac_cv_header_syslog_h" "$ac_includes_default" +if test "x$ac_cv_header_syslog_h" = xyes +then : + printf "%s\n" "#define HAVE_SYSLOG_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "termios.h" "ac_cv_header_termios_h" "$ac_includes_default" +if test "x$ac_cv_header_termios_h" = xyes +then : + printf "%s\n" "#define HAVE_TERMIOS_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "util.h" "ac_cv_header_util_h" "$ac_includes_default" +if test "x$ac_cv_header_util_h" = xyes +then : + printf "%s\n" "#define HAVE_UTIL_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" "$ac_includes_default" +if test "x$ac_cv_header_utime_h" = xyes +then : + printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "utmp.h" "ac_cv_header_utmp_h" "$ac_includes_default" +if test "x$ac_cv_header_utmp_h" = xyes +then : + printf "%s\n" "#define HAVE_UTMP_H 1" >>confdefs.h + +fi + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 +printf %s "checking for $ac_hdr that defines DIR... " >&6; } +if eval test \${$as_ac_Header+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ #include -#endif +#include <$ac_hdr> int -main () +main (void) { - - makedev(0, 0) +if ((DIR *) 0) +return 0; ; return 0; } - _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_func_makedev=yes -else - ac_cv_func_makedev=no +if ac_fn_c_try_compile "$LINENO" +then : + eval "$as_ac_Header=yes" +else $as_nop + eval "$as_ac_Header=no" fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_makedev" >&5 -$as_echo "$ac_cv_func_makedev" >&6; } +eval ac_res=\$$as_ac_Header + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : + cat >>confdefs.h <<_ACEOF +#define `printf "%s\n" "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF -if test "x$ac_cv_func_makedev" = xyes; then : +ac_header_dirent=$ac_hdr; break +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +printf %s "checking for library containing opendir... " >&6; } +if test ${ac_cv_search_opendir+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ -$as_echo "#define HAVE_MAKEDEV 1" >>confdefs.h +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char opendir (); +int +main (void) +{ +return opendir (); + ; + return 0; +} +_ACEOF +for ac_lib in '' dir +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" +then : + ac_cv_search_opendir=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext + if test ${ac_cv_search_opendir+y} +then : + break +fi +done +if test ${ac_cv_search_opendir+y} +then : +else $as_nop + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +printf "%s\n" "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no +then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi -# byte swapping -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for le64toh" >&5 -$as_echo_n "checking for le64toh... " >&6; } -if ${ac_cv_func_le64toh+:} false; then : - $as_echo_n "(cached) " >&6 else - + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 +printf %s "checking for library containing opendir... " >&6; } +if test ${ac_cv_search_opendir+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef HAVE_ENDIAN_H -#include -#elif defined(HAVE_SYS_ENDIAN_H) -#include -#endif - +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char opendir (); int -main () +main (void) { - - le64toh(1) +return opendir (); ; return 0; } - _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_func_le64toh=yes -else - ac_cv_func_le64toh=no +for ac_lib in '' x +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" +then : + ac_cv_search_opendir=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext + if test ${ac_cv_search_opendir+y} +then : + break +fi +done +if test ${ac_cv_search_opendir+y} +then : + +else $as_nop + ac_cv_search_opendir=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 +printf "%s\n" "$ac_cv_search_opendir" >&6; } +ac_res=$ac_cv_search_opendir +if test "$ac_res" != no +then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_le64toh" >&5 -$as_echo "$ac_cv_func_le64toh" >&6; } -if test "x$ac_cv_func_le64toh" = xyes; then : +fi -$as_echo "#define HAVE_HTOLE64 1" >>confdefs.h +ac_fn_c_check_header_compile "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mkdev_h" = xyes +then : +printf "%s\n" "#define MAJOR_IN_MKDEV 1" >>confdefs.h fi -use_lfs=yes -# Don't use largefile support for GNU/Hurd -case $ac_sys_system in GNU*) - use_lfs=no -esac +if test $ac_cv_header_sys_mkdev_h = no; then + ac_fn_c_check_header_compile "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_sysmacros_h" = xyes +then : -if test "$use_lfs" = "yes"; then -# Two defines needed to enable largefile support on various platforms +printf "%s\n" "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h + +fi + +fi + + +# bluetooth/bluetooth.h has been known to not compile with -std=c99. +# http://permalink.gmane.org/gmane.linux.bluez.kernel/22294 +SAVE_CFLAGS=$CFLAGS +CFLAGS="-std=c99 $CFLAGS" +ac_fn_c_check_header_compile "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" +if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes +then : + printf "%s\n" "#define HAVE_BLUETOOTH_BLUETOOTH_H 1" >>confdefs.h + +fi + +CFLAGS=$SAVE_CFLAGS + +# On Darwin (OS X) net/if.h requires sys/socket.h to be imported first. +ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#include +#include +#include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +" +if test "x$ac_cv_header_net_if_h" = xyes +then : + printf "%s\n" "#define HAVE_NET_IF_H 1" >>confdefs.h + +fi + + +# On Linux, netlink.h requires asm/types.h +ac_fn_c_check_header_compile "$LINENO" "linux/netlink.h" "ac_cv_header_linux_netlink_h" " +#ifdef HAVE_ASM_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_linux_netlink_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_NETLINK_H 1" >>confdefs.h + +fi + + +# On Linux, qrtr.h requires asm/types.h +ac_fn_c_check_header_compile "$LINENO" "linux/qrtr.h" "ac_cv_header_linux_qrtr_h" " +#ifdef HAVE_ASM_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_linux_qrtr_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_QRTR_H 1" >>confdefs.h + +fi + + +ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" " +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_linux_vm_sockets_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_VM_SOCKETS_H 1" >>confdefs.h + +fi + + +# On Linux, can.h, can/bcm.h, can/j1939.h, can/raw.h require sys/socket.h +# On NetBSD, netcan/can.h requires sys/socket.h +ac_fn_c_check_header_compile "$LINENO" "linux/can.h" "ac_cv_header_linux_can_h" " +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_linux_can_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_CAN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/can/bcm.h" "ac_cv_header_linux_can_bcm_h" " +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_linux_can_bcm_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_CAN_BCM_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/can/j1939.h" "ac_cv_header_linux_can_j1939_h" " +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_linux_can_j1939_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_CAN_J1939_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/can/raw.h" "ac_cv_header_linux_can_raw_h" " +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_linux_can_raw_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_CAN_RAW_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netcan/can.h" "ac_cv_header_netcan_can_h" " +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +" +if test "x$ac_cv_header_netcan_can_h" = xyes +then : + printf "%s\n" "#define HAVE_NETCAN_CAN_H 1" >>confdefs.h + +fi + + +# checks for typedefs + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_t in time.h" >&5 +printf %s "checking for clock_t in time.h... " >&6; } +if test ${ac_cv_clock_t_time_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "clock_t" >/dev/null 2>&1 +then : + ac_cv_clock_t_time_h=yes +else $as_nop + ac_cv_clock_t_time_h=no +fi +rm -rf conftest* + + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_clock_t_time_h" >&5 +printf "%s\n" "$ac_cv_clock_t_time_h" >&6; } +if test "x$ac_cv_clock_t_time_h" = xno +then : + + +printf "%s\n" "#define clock_t long" >>confdefs.h + + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for makedev" >&5 +printf %s "checking for makedev... " >&6; } +if test ${ac_cv_func_makedev+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if defined(MAJOR_IN_MKDEV) +#include +#elif defined(MAJOR_IN_SYSMACROS) +#include +#else +#include +#endif + +int +main (void) +{ + + makedev(0, 0) + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_func_makedev=yes +else $as_nop + ac_cv_func_makedev=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_makedev" >&5 +printf "%s\n" "$ac_cv_func_makedev" >&6; } + +if test "x$ac_cv_func_makedev" = xyes +then : + + +printf "%s\n" "#define HAVE_MAKEDEV 1" >>confdefs.h + + +fi + +# byte swapping +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for le64toh" >&5 +printf %s "checking for le64toh... " >&6; } +if test ${ac_cv_func_le64toh+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_ENDIAN_H +#include +#elif defined(HAVE_SYS_ENDIAN_H) +#include +#endif + +int +main (void) +{ + + le64toh(1) + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_func_le64toh=yes +else $as_nop + ac_cv_func_le64toh=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_le64toh" >&5 +printf "%s\n" "$ac_cv_func_le64toh" >&6; } + +if test "x$ac_cv_func_le64toh" = xyes +then : + + +printf "%s\n" "#define HAVE_HTOLE64 1" >>confdefs.h + + +fi + +use_lfs=yes +# Don't use largefile support for GNU/Hurd +case $ac_sys_system in GNU*) + use_lfs=no +esac + +if test "$use_lfs" = "yes"; then +# Two defines needed to enable largefile support on various platforms # These may affect some typedefs case $ac_sys_system/$ac_sys_release in AIX*) -$as_echo "#define _LARGE_FILES 1" >>confdefs.h +printf "%s\n" "#define _LARGE_FILES 1" >>confdefs.h ;; esac -$as_echo "#define _LARGEFILE_SOURCE 1" >>confdefs.h +printf "%s\n" "#define _LARGEFILE_SOURCE 1" >>confdefs.h -$as_echo "#define _FILE_OFFSET_BITS 64" >>confdefs.h +printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h fi @@ -10145,96 +11429,121 @@ EOF # Type availability checks ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = xyes; then : +if test "x$ac_cv_type_mode_t" = xyes +then : -else +else $as_nop -cat >>confdefs.h <<_ACEOF -#define mode_t int -_ACEOF +printf "%s\n" "#define mode_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = xyes; then : +if test "x$ac_cv_type_off_t" = xyes +then : -else +else $as_nop -cat >>confdefs.h <<_ACEOF -#define off_t long int -_ACEOF +printf "%s\n" "#define off_t long int" >>confdefs.h fi -ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = xyes; then : -else + ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default +" +if test "x$ac_cv_type_pid_t" = xyes +then : + +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #if defined _WIN64 && !defined __CYGWIN__ + LLP64 + #endif + +int +main (void) +{ + + ; + return 0; +} -cat >>confdefs.h <<_ACEOF -#define pid_t int _ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_pid_type='int' +else $as_nop + ac_pid_type='__int64' +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + +printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h + fi -cat >>confdefs.h <<_ACEOF -#define RETSIGTYPE void -_ACEOF + +printf "%s\n" "#define RETSIGTYPE void" >>confdefs.h ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : +if test "x$ac_cv_type_size_t" = xyes +then : -else +else $as_nop -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF +printf "%s\n" "#define size_t unsigned int" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 -$as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if ${ac_cv_type_uid_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +printf %s "checking for uid_t in sys/types.h... " >&6; } +if test ${ac_cv_type_uid_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uid_t" >/dev/null 2>&1; then : + $EGREP "uid_t" >/dev/null 2>&1 +then : ac_cv_type_uid_t=yes -else +else $as_nop ac_cv_type_uid_t=no fi -rm -f conftest* +rm -rf conftest* fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 -$as_echo "$ac_cv_type_uid_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +printf "%s\n" "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then -$as_echo "#define uid_t int" >>confdefs.h +printf "%s\n" "#define uid_t int" >>confdefs.h -$as_echo "#define gid_t int" >>confdefs.h +printf "%s\n" "#define gid_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" -if test "x$ac_cv_type_ssize_t" = xyes; then : +if test "x$ac_cv_type_ssize_t" = xyes +then : -$as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h +printf "%s\n" "#define HAVE_SSIZE_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default" -if test "x$ac_cv_type___uint128_t" = xyes; then : +if test "x$ac_cv_type___uint128_t" = xyes +then : -$as_echo "#define HAVE_GCC_UINT128_T 1" >>confdefs.h +printf "%s\n" "#define HAVE_GCC_UINT128_T 1" >>confdefs.h fi @@ -10245,17 +11554,19 @@ fi # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +printf %s "checking size of int... " >&6; } +if test ${ac_cv_sizeof_int+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else @@ -10264,31 +11575,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +printf "%s\n" "$ac_cv_sizeof_int" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF +printf "%s\n" "#define SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +printf %s "checking size of long... " >&6; } +if test ${ac_cv_sizeof_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else @@ -10297,33 +11608,30 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG $ac_cv_sizeof_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler, # see AC_CHECK_SIZEOF for more information. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of long" >&5 -$as_echo_n "checking alignment of long... " >&6; } -if ${ac_cv_alignof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking alignment of long" >&5 +printf %s "checking alignment of long... " >&6; } +if test ${ac_cv_alignof_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_long" "$ac_includes_default -#ifndef offsetof -# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) -#endif -typedef struct { char x; long y; } ac__type_alignof_;"; then : +typedef struct { char x; long y; } ac__type_alignof_;" +then : -else +else $as_nop if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute alignment of long See \`config.log' for more details" "$LINENO" 5; } else @@ -10332,31 +11640,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_long" >&5 -$as_echo "$ac_cv_alignof_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_long" >&5 +printf "%s\n" "$ac_cv_alignof_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define ALIGNOF_LONG $ac_cv_alignof_long -_ACEOF +printf "%s\n" "#define ALIGNOF_LONG $ac_cv_alignof_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 -$as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 +printf %s "checking size of long long... " >&6; } +if test ${ac_cv_sizeof_long_long+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else @@ -10365,31 +11673,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 -$as_echo "$ac_cv_sizeof_long_long" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 +printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF +printf "%s\n" "#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +printf %s "checking size of void *... " >&6; } +if test ${ac_cv_sizeof_void_p+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else @@ -10398,31 +11706,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +printf "%s\n" "$ac_cv_sizeof_void_p" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF +printf "%s\n" "#define SIZEOF_VOID_P $ac_cv_sizeof_void_p" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 -$as_echo_n "checking size of short... " >&6; } -if ${ac_cv_sizeof_short+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 +printf %s "checking size of short... " >&6; } +if test ${ac_cv_sizeof_short+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_short" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) See \`config.log' for more details" "$LINENO" 5; } else @@ -10431,31 +11739,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 -$as_echo "$ac_cv_sizeof_short" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 +printf "%s\n" "$ac_cv_sizeof_short" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SHORT $ac_cv_sizeof_short -_ACEOF +printf "%s\n" "#define SIZEOF_SHORT $ac_cv_sizeof_short" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 -$as_echo_n "checking size of float... " >&6; } -if ${ac_cv_sizeof_float+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 +printf %s "checking size of float... " >&6; } +if test ${ac_cv_sizeof_float+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_float" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (float) See \`config.log' for more details" "$LINENO" 5; } else @@ -10464,31 +11772,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_float" >&5 -$as_echo "$ac_cv_sizeof_float" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_float" >&5 +printf "%s\n" "$ac_cv_sizeof_float" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_FLOAT $ac_cv_sizeof_float -_ACEOF +printf "%s\n" "#define SIZEOF_FLOAT $ac_cv_sizeof_float" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 -$as_echo_n "checking size of double... " >&6; } -if ${ac_cv_sizeof_double+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 +printf %s "checking size of double... " >&6; } +if test ${ac_cv_sizeof_double+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_double" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (double) See \`config.log' for more details" "$LINENO" 5; } else @@ -10497,31 +11805,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5 -$as_echo "$ac_cv_sizeof_double" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_double" >&5 +printf "%s\n" "$ac_cv_sizeof_double" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_DOUBLE $ac_cv_sizeof_double -_ACEOF +printf "%s\n" "#define SIZEOF_DOUBLE $ac_cv_sizeof_double" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 -$as_echo_n "checking size of fpos_t... " >&6; } -if ${ac_cv_sizeof_fpos_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 +printf %s "checking size of fpos_t... " >&6; } +if test ${ac_cv_sizeof_fpos_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_fpos_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (fpos_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -10530,31 +11838,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_fpos_t" >&5 -$as_echo "$ac_cv_sizeof_fpos_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_fpos_t" >&5 +printf "%s\n" "$ac_cv_sizeof_fpos_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_FPOS_T $ac_cv_sizeof_fpos_t -_ACEOF +printf "%s\n" "#define SIZEOF_FPOS_T $ac_cv_sizeof_fpos_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 -$as_echo_n "checking size of size_t... " >&6; } -if ${ac_cv_sizeof_size_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 +printf %s "checking size of size_t... " >&6; } +if test ${ac_cv_sizeof_size_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_size_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (size_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -10563,33 +11871,30 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 -$as_echo "$ac_cv_sizeof_size_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 +printf "%s\n" "$ac_cv_sizeof_size_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t -_ACEOF +printf "%s\n" "#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler, # see AC_CHECK_SIZEOF for more information. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of size_t" >&5 -$as_echo_n "checking alignment of size_t... " >&6; } -if ${ac_cv_alignof_size_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking alignment of size_t" >&5 +printf %s "checking alignment of size_t... " >&6; } +if test ${ac_cv_alignof_size_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_size_t" "$ac_includes_default -#ifndef offsetof -# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) -#endif -typedef struct { char x; size_t y; } ac__type_alignof_;"; then : +typedef struct { char x; size_t y; } ac__type_alignof_;" +then : -else +else $as_nop if test "$ac_cv_type_size_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute alignment of size_t See \`config.log' for more details" "$LINENO" 5; } else @@ -10598,31 +11903,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_size_t" >&5 -$as_echo "$ac_cv_alignof_size_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_size_t" >&5 +printf "%s\n" "$ac_cv_alignof_size_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define ALIGNOF_SIZE_T $ac_cv_alignof_size_t -_ACEOF +printf "%s\n" "#define ALIGNOF_SIZE_T $ac_cv_alignof_size_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 -$as_echo_n "checking size of pid_t... " >&6; } -if ${ac_cv_sizeof_pid_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 +printf %s "checking size of pid_t... " >&6; } +if test ${ac_cv_sizeof_pid_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_pid_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pid_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -10631,31 +11936,31 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pid_t" >&5 -$as_echo "$ac_cv_sizeof_pid_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pid_t" >&5 +printf "%s\n" "$ac_cv_sizeof_pid_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_PID_T $ac_cv_sizeof_pid_t -_ACEOF +printf "%s\n" "#define SIZEOF_PID_T $ac_cv_sizeof_pid_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 -$as_echo_n "checking size of uintptr_t... " >&6; } -if ${ac_cv_sizeof_uintptr_t+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 +printf %s "checking size of uintptr_t... " >&6; } +if test ${ac_cv_sizeof_uintptr_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_uintptr_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (uintptr_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -10664,33 +11969,30 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uintptr_t" >&5 -$as_echo "$ac_cv_sizeof_uintptr_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uintptr_t" >&5 +printf "%s\n" "$ac_cv_sizeof_uintptr_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_UINTPTR_T $ac_cv_sizeof_uintptr_t -_ACEOF +printf "%s\n" "#define SIZEOF_UINTPTR_T $ac_cv_sizeof_uintptr_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler, # see AC_CHECK_SIZEOF for more information. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of max_align_t" >&5 -$as_echo_n "checking alignment of max_align_t... " >&6; } -if ${ac_cv_alignof_max_align_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking alignment of max_align_t" >&5 +printf %s "checking alignment of max_align_t... " >&6; } +if test ${ac_cv_alignof_max_align_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_max_align_t" "$ac_includes_default -#ifndef offsetof -# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) -#endif -typedef struct { char x; max_align_t y; } ac__type_alignof_;"; then : +typedef struct { char x; max_align_t y; } ac__type_alignof_;" +then : -else +else $as_nop if test "$ac_cv_type_max_align_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute alignment of max_align_t See \`config.log' for more details" "$LINENO" 5; } else @@ -10699,23 +12001,22 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_max_align_t" >&5 -$as_echo "$ac_cv_alignof_max_align_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_max_align_t" >&5 +printf "%s\n" "$ac_cv_alignof_max_align_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define ALIGNOF_MAX_ALIGN_T $ac_cv_alignof_max_align_t -_ACEOF +printf "%s\n" "#define ALIGNOF_MAX_ALIGN_T $ac_cv_alignof_max_align_t" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double" >&5 -$as_echo_n "checking for long double... " >&6; } -if ${ac_cv_type_long_double+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for long double" >&5 +printf %s "checking for long double... " >&6; } +if test ${ac_cv_type_long_double+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "$GCC" = yes; then ac_cv_type_long_double=yes else @@ -10725,7 +12026,7 @@ else not support it. */ long double foo = 0.0L; int -main () +main (void) { static int test_array [1 - 2 * !(/* On Ultrix 4.3 cc, long double is 4 and double is 8. */ sizeof (double) <= sizeof (long double))]; @@ -10736,19 +12037,20 @@ return test_array [0]; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_type_long_double=yes -else +else $as_nop ac_cv_type_long_double=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double" >&5 -$as_echo "$ac_cv_type_long_double" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double" >&5 +printf "%s\n" "$ac_cv_type_long_double" >&6; } if test $ac_cv_type_long_double = yes; then -$as_echo "#define HAVE_LONG_DOUBLE 1" >>confdefs.h +printf "%s\n" "#define HAVE_LONG_DOUBLE 1" >>confdefs.h fi @@ -10756,17 +12058,19 @@ $as_echo "#define HAVE_LONG_DOUBLE 1" >>confdefs.h # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 -$as_echo_n "checking size of long double... " >&6; } -if ${ac_cv_sizeof_long_double+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 +printf %s "checking size of long double... " >&6; } +if test ${ac_cv_sizeof_long_double+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type_long_double" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long double) See \`config.log' for more details" "$LINENO" 5; } else @@ -10775,14 +12079,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 -$as_echo "$ac_cv_sizeof_long_double" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 +printf "%s\n" "$ac_cv_sizeof_long_double" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double -_ACEOF +printf "%s\n" "#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double" >>confdefs.h @@ -10790,17 +12092,19 @@ _ACEOF # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 -$as_echo_n "checking size of _Bool... " >&6; } -if ${ac_cv_sizeof__Bool+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default"; then : - -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 +printf %s "checking size of _Bool... " >&6; } +if test ${ac_cv_sizeof__Bool+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default" +then : + +else $as_nop if test "$ac_cv_type__Bool" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (_Bool) See \`config.log' for more details" "$LINENO" 5; } else @@ -10809,14 +12113,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof__Bool" >&5 -$as_echo "$ac_cv_sizeof__Bool" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof__Bool" >&5 +printf "%s\n" "$ac_cv_sizeof__Bool" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF__BOOL $ac_cv_sizeof__Bool -_ACEOF +printf "%s\n" "#define SIZEOF__BOOL $ac_cv_sizeof__Bool" >>confdefs.h @@ -10824,22 +12126,24 @@ _ACEOF # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 -$as_echo_n "checking size of off_t... " >&6; } -if ${ac_cv_sizeof_off_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 +printf %s "checking size of off_t... " >&6; } +if test ${ac_cv_sizeof_off_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " #ifdef HAVE_SYS_TYPES_H #include #endif -"; then : +" +then : -else +else $as_nop if test "$ac_cv_type_off_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -10848,19 +12152,17 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 -$as_echo "$ac_cv_sizeof_off_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 +printf "%s\n" "$ac_cv_sizeof_off_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_OFF_T $ac_cv_sizeof_off_t -_ACEOF +printf "%s\n" "#define SIZEOF_OFF_T $ac_cv_sizeof_off_t" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable large file support" >&5 -$as_echo_n "checking whether to enable large file support... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable large file support" >&5 +printf %s "checking whether to enable large file support... " >&6; } if test "$ac_cv_sizeof_off_t" -gt "$ac_cv_sizeof_long" -a \ "$ac_cv_sizeof_long_long" -ge "$ac_cv_sizeof_off_t"; then have_largefile_support="yes" @@ -10874,18 +12176,19 @@ case $ac_sys_system in #( *) : ;; esac -if test "x$have_largefile_support" = xyes; then : +if test "x$have_largefile_support" = xyes +then : -$as_echo "#define HAVE_LARGEFILE_SUPPORT 1" >>confdefs.h +printf "%s\n" "#define HAVE_LARGEFILE_SUPPORT 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -10893,11 +12196,12 @@ fi # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 -$as_echo_n "checking size of time_t... " >&6; } -if ${ac_cv_sizeof_time_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 +printf %s "checking size of time_t... " >&6; } +if test ${ac_cv_sizeof_time_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " #ifdef HAVE_SYS_TYPES_H #include @@ -10906,12 +12210,13 @@ else #include #endif -"; then : +" +then : -else +else $as_nop if test "$ac_cv_type_time_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (time_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -10920,14 +12225,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 -$as_echo "$ac_cv_sizeof_time_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 +printf "%s\n" "$ac_cv_sizeof_time_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_TIME_T $ac_cv_sizeof_time_t -_ACEOF +printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h @@ -10941,18 +12244,19 @@ elif test "$ac_cv_pthread" = "yes" then CC="$CC -pthread" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_t" >&5 -$as_echo_n "checking for pthread_t... " >&6; } -if ${ac_cv_have_pthread_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_t" >&5 +printf %s "checking for pthread_t... " >&6; } +if test ${ac_cv_have_pthread_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { pthread_t x; x = *(pthread_t*)0; ; @@ -10960,38 +12264,42 @@ pthread_t x; x = *(pthread_t*)0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_have_pthread_t=yes -else +else $as_nop ac_cv_have_pthread_t=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pthread_t" >&5 -$as_echo "$ac_cv_have_pthread_t" >&6; } -if test "x$ac_cv_have_pthread_t" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_pthread_t" >&5 +printf "%s\n" "$ac_cv_have_pthread_t" >&6; } +if test "x$ac_cv_have_pthread_t" = xyes +then : # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 -$as_echo_n "checking size of pthread_t... " >&6; } -if ${ac_cv_sizeof_pthread_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 +printf %s "checking size of pthread_t... " >&6; } +if test ${ac_cv_sizeof_pthread_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " #ifdef HAVE_PTHREAD_H #include #endif -"; then : +" +then : -else +else $as_nop if test "$ac_cv_type_pthread_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pthread_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -11000,14 +12308,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_t" >&5 -$as_echo "$ac_cv_sizeof_pthread_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_t" >&5 +printf "%s\n" "$ac_cv_sizeof_pthread_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_PTHREAD_T $ac_cv_sizeof_pthread_t -_ACEOF +printf "%s\n" "#define SIZEOF_PTHREAD_T $ac_cv_sizeof_pthread_t" >>confdefs.h @@ -11019,18 +12325,20 @@ fi # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_key_t" >&5 -$as_echo_n "checking size of pthread_key_t... " >&6; } -if ${ac_cv_sizeof_pthread_key_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_key_t" >&5 +printf %s "checking size of pthread_key_t... " >&6; } +if test ${ac_cv_sizeof_pthread_key_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_key_t))" "ac_cv_sizeof_pthread_key_t" "#include -"; then : +" +then : -else +else $as_nop if test "$ac_cv_type_pthread_key_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pthread_key_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -11039,77 +12347,78 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_key_t" >&5 -$as_echo "$ac_cv_sizeof_pthread_key_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_key_t" >&5 +printf "%s\n" "$ac_cv_sizeof_pthread_key_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_PTHREAD_KEY_T $ac_cv_sizeof_pthread_key_t -_ACEOF +printf "%s\n" "#define SIZEOF_PTHREAD_KEY_T $ac_cv_sizeof_pthread_key_t" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthread_key_t is compatible with int" >&5 -$as_echo_n "checking whether pthread_key_t is compatible with int... " >&6; } -if ${ac_cv_pthread_key_t_is_arithmetic_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_key_t is compatible with int" >&5 +printf %s "checking whether pthread_key_t is compatible with int... " >&6; } +if test ${ac_cv_pthread_key_t_is_arithmetic_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "$ac_cv_sizeof_pthread_key_t" -eq "$ac_cv_sizeof_int" ; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { pthread_key_t k; k * 1; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_pthread_key_t_is_arithmetic_type=yes -else +else $as_nop ac_cv_pthread_key_t_is_arithmetic_type=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext else ac_cv_pthread_key_t_is_arithmetic_type=no fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_key_t_is_arithmetic_type" >&5 -$as_echo "$ac_cv_pthread_key_t_is_arithmetic_type" >&6; } -if test "x$ac_cv_pthread_key_t_is_arithmetic_type" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_key_t_is_arithmetic_type" >&5 +printf "%s\n" "$ac_cv_pthread_key_t_is_arithmetic_type" >&6; } +if test "x$ac_cv_pthread_key_t_is_arithmetic_type" = xyes +then : -$as_echo "#define PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT 1" >>confdefs.h +printf "%s\n" "#define PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT 1" >>confdefs.h fi CC="$ac_save_cc" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-framework" >&5 -$as_echo_n "checking for --enable-framework... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-framework" >&5 +printf %s "checking for --enable-framework... " >&6; } if test "$enable_framework" then BASECFLAGS="$BASECFLAGS -fno-common -dynamic" # -F. is needed to allow linking to the framework while # in the build location. -$as_echo "#define WITH_NEXT_FRAMEWORK 1" >>confdefs.h +printf "%s\n" "#define WITH_NEXT_FRAMEWORK 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } if test $enable_shared = "yes" then as_fn_error $? "Specifying both --enable-shared and --enable-framework is not supported, use only --enable-framework instead" "$LINENO" 5 fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi # Check for --with-dsymutil @@ -11117,37 +12426,39 @@ fi DSYMUTIL= DSYMUTIL_PATH= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dsymutil" >&5 -$as_echo_n "checking for --with-dsymutil... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-dsymutil" >&5 +printf %s "checking for --with-dsymutil... " >&6; } # Check whether --with-dsymutil was given. -if test "${with_dsymutil+set}" = set; then : +if test ${with_dsymutil+y} +then : withval=$with_dsymutil; if test "$withval" != no then if test "$MACHDEP" != "darwin"; then as_fn_error $? "dsymutil debug linking is only available in macOS." "$LINENO" 5 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; }; DSYMUTIL='true' -else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; }; DSYMUTIL= +else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; }; DSYMUTIL= fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "$DSYMUTIL"; then # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_DSYMUTIL_PATH+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_DSYMUTIL_PATH+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $DSYMUTIL_PATH in [\\/]* | ?:[\\/]*) ac_cv_path_DSYMUTIL_PATH="$DSYMUTIL_PATH" # Let the user override the test with a path. @@ -11157,11 +12468,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_DSYMUTIL_PATH="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_DSYMUTIL_PATH="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -11174,11 +12489,11 @@ esac fi DSYMUTIL_PATH=$ac_cv_path_DSYMUTIL_PATH if test -n "$DSYMUTIL_PATH"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL_PATH" >&5 -$as_echo "$DSYMUTIL_PATH" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL_PATH" >&5 +printf "%s\n" "$DSYMUTIL_PATH" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -11187,54 +12502,57 @@ fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dyld" >&5 -$as_echo_n "checking for dyld... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dyld" >&5 +printf %s "checking for dyld... " >&6; } case $ac_sys_system/$ac_sys_release in Darwin/*) -$as_echo "#define WITH_DYLD 1" >>confdefs.h +printf "%s\n" "#define WITH_DYLD 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: always on for Darwin" >&5 -$as_echo "always on for Darwin" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: always on for Darwin" >&5 +printf "%s\n" "always on for Darwin" >&6; } ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-address-sanitizer" >&5 -$as_echo_n "checking for --with-address-sanitizer... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-address-sanitizer" >&5 +printf %s "checking for --with-address-sanitizer... " >&6; } # Check whether --with-address_sanitizer was given. -if test "${with_address_sanitizer+set}" = set; then : +if test ${with_address_sanitizer+y} +then : withval=$with_address_sanitizer; -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 -$as_echo "$withval" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +printf "%s\n" "$withval" >&6; } BASECFLAGS="-fsanitize=address -fno-omit-frame-pointer $BASECFLAGS" LDFLAGS="-fsanitize=address $LDFLAGS" # ASan works by controlling memory allocation, our own malloc interferes. with_pymalloc="no" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-memory-sanitizer" >&5 -$as_echo_n "checking for --with-memory-sanitizer... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-memory-sanitizer" >&5 +printf %s "checking for --with-memory-sanitizer... " >&6; } # Check whether --with-memory_sanitizer was given. -if test "${with_memory_sanitizer+set}" = set; then : +if test ${with_memory_sanitizer+y} +then : withval=$with_memory_sanitizer; -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 -$as_echo "$withval" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fsanitize=memory" >&5 -$as_echo_n "checking whether C compiler accepts -fsanitize=memory... " >&6; } -if ${ax_cv_check_cflags___fsanitize_memory+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +printf "%s\n" "$withval" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fsanitize=memory" >&5 +printf %s "checking whether C compiler accepts -fsanitize=memory... " >&6; } +if test ${ax_cv_check_cflags___fsanitize_memory+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fsanitize=memory" @@ -11242,57 +12560,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ax_cv_check_cflags___fsanitize_memory=yes -else +else $as_nop ax_cv_check_cflags___fsanitize_memory=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$ax_check_save_flags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fsanitize_memory" >&5 -$as_echo "$ax_cv_check_cflags___fsanitize_memory" >&6; } -if test "x$ax_cv_check_cflags___fsanitize_memory" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fsanitize_memory" >&5 +printf "%s\n" "$ax_cv_check_cflags___fsanitize_memory" >&6; } +if test "x$ax_cv_check_cflags___fsanitize_memory" = xyes +then : BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS" -else +else $as_nop as_fn_error $? "The selected compiler doesn't support memory sanitizer" "$LINENO" 5 fi # MSan works by controlling memory allocation, our own malloc interferes. with_pymalloc="no" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-undefined-behavior-sanitizer" >&5 -$as_echo_n "checking for --with-undefined-behavior-sanitizer... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-undefined-behavior-sanitizer" >&5 +printf %s "checking for --with-undefined-behavior-sanitizer... " >&6; } # Check whether --with-undefined_behavior_sanitizer was given. -if test "${with_undefined_behavior_sanitizer+set}" = set; then : +if test ${with_undefined_behavior_sanitizer+y} +then : withval=$with_undefined_behavior_sanitizer; -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 -$as_echo "$withval" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +printf "%s\n" "$withval" >&6; } BASECFLAGS="-fsanitize=undefined $BASECFLAGS" LDFLAGS="-fsanitize=undefined $LDFLAGS" with_ubsan="yes" -else +else $as_nop -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } with_ubsan="no" fi @@ -11308,8 +12629,8 @@ fi # SHLIB_SUFFIX is the extension of shared libraries `(including the dot!) # -- usually .so, .sl on HP-UX, .dll on Cygwin -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the extension of shared libraries" >&5 -$as_echo_n "checking the extension of shared libraries... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the extension of shared libraries" >&5 +printf %s "checking the extension of shared libraries... " >&6; } if test -z "$SHLIB_SUFFIX"; then case $ac_sys_system in hp*|HP*) @@ -11322,15 +12643,15 @@ if test -z "$SHLIB_SUFFIX"; then *) SHLIB_SUFFIX=.so;; esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHLIB_SUFFIX" >&5 -$as_echo "$SHLIB_SUFFIX" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SHLIB_SUFFIX" >&5 +printf "%s\n" "$SHLIB_SUFFIX" >&6; } # LDSHARED is the ld *command* used to create shared library # -- "cc -G" on SunOS 5.x. # (Shared libraries in this instance are shared modules to be loaded into # Python, as opposed to building Python itself as a shared library.) -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LDSHARED" >&5 -$as_echo_n "checking LDSHARED... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDSHARED" >&5 +printf %s "checking LDSHARED... " >&6; } if test -z "$LDSHARED" then case $ac_sys_system/$ac_sys_release in @@ -11446,7 +12767,8 @@ then LDSHARED='$(CC) -Wl,-G,-Bexport' LDCXXSHARED='$(CXX) -Wl,-G,-Bexport';; WASI*) - if test "x$enable_wasm_dynamic_linking" = xyes; then : + if test "x$enable_wasm_dynamic_linking" = xyes +then : fi;; @@ -11461,20 +12783,20 @@ if test "$enable_wasm_dynamic_linking" = "yes" -a "$ac_sys_system" = "Emscripten BLDSHARED='$(CC) -shared -sSIDE_MODULE=1' fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDSHARED" >&5 -$as_echo "$LDSHARED" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDSHARED" >&5 +printf "%s\n" "$LDSHARED" >&6; } LDCXXSHARED=${LDCXXSHARED-$LDSHARED} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking BLDSHARED flags" >&5 -$as_echo_n "checking BLDSHARED flags... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BLDSHARED flags" >&5 +printf %s "checking BLDSHARED flags... " >&6; } BLDSHARED=${BLDSHARED-$LDSHARED} -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BLDSHARED" >&5 -$as_echo "$BLDSHARED" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BLDSHARED" >&5 +printf "%s\n" "$BLDSHARED" >&6; } # CCSHARED are the C *flags* used to create objects to go into a shared # library (module) -- this is only needed for a few systems -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking CCSHARED" >&5 -$as_echo_n "checking CCSHARED... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CCSHARED" >&5 +printf %s "checking CCSHARED... " >&6; } if test -z "$CCSHARED" then case $ac_sys_system/$ac_sys_release in @@ -11491,7 +12813,8 @@ then Linux-android*) ;; Linux*|GNU*) CCSHARED="-fPIC";; Emscripten*|WASI*) - if test "x$enable_wasm_dynamic_linking" = xyes; then : + if test "x$enable_wasm_dynamic_linking" = xyes +then : CCSHARED="-fPIC" @@ -11512,12 +12835,12 @@ fi;; CCSHARED="-fpic -D__SO_PICABILINUX__ -ftls-model=global-dynamic" esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CCSHARED" >&5 -$as_echo "$CCSHARED" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CCSHARED" >&5 +printf "%s\n" "$CCSHARED" >&6; } # LINKFORSHARED are the flags passed to the $(CC) command that links # the python executable -- this is only needed for a few systems -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LINKFORSHARED" >&5 -$as_echo_n "checking LINKFORSHARED... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LINKFORSHARED" >&5 +printf %s "checking LINKFORSHARED... " >&6; } if test -z "$LINKFORSHARED" then case $ac_sys_system/$ac_sys_release in @@ -11544,9 +12867,7 @@ then LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED" -cat >>confdefs.h <<_ACEOF -#define THREAD_STACK_SIZE 0x$stack_size -_ACEOF +printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h if test "$enable_framework" @@ -11585,13 +12906,13 @@ _ACEOF LINKFORSHARED='-Wl,-export-dynamic';; esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINKFORSHARED" >&5 -$as_echo "$LINKFORSHARED" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LINKFORSHARED" >&5 +printf "%s\n" "$LINKFORSHARED" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking CFLAGSFORSHARED" >&5 -$as_echo_n "checking CFLAGSFORSHARED... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CFLAGSFORSHARED" >&5 +printf %s "checking CFLAGSFORSHARED... " >&6; } if test ! "$LIBRARY" = "$LDLIBRARY" then case $ac_sys_system in @@ -11604,14 +12925,15 @@ then esac fi -if test "x$enable_wasm_dynamic_linking" = xyes; then : +if test "x$enable_wasm_dynamic_linking" = xyes +then : CFLAGSFORSHARED='$(CCSHARED)' fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CFLAGSFORSHARED" >&5 -$as_echo "$CFLAGSFORSHARED" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CFLAGSFORSHARED" >&5 +printf "%s\n" "$CFLAGSFORSHARED" >&6; } # SHLIBS are libraries (except -lc and -lm) to link to the python shared # library (with --enable-shared). @@ -11622,17 +12944,17 @@ $as_echo "$CFLAGSFORSHARED" >&6; } # don't need to link LIBS explicitly. The default should be only changed # on systems where this approach causes problems. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SHLIBS" >&5 -$as_echo_n "checking SHLIBS... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SHLIBS" >&5 +printf %s "checking SHLIBS... " >&6; } case "$ac_sys_system" in *) SHLIBS='$(LIBS)';; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHLIBS" >&5 -$as_echo "$SHLIBS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SHLIBS" >&5 +printf "%s\n" "$SHLIBS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking perf trampoline" >&5 -$as_echo_n "checking perf trampoline... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking perf trampoline" >&5 +printf %s "checking perf trampoline... " >&6; } case $PLATFORM_TRIPLET in #( x86_64-linux-gnu) : perf_trampoline=yes ;; #( @@ -11642,17 +12964,19 @@ case $PLATFORM_TRIPLET in #( perf_trampoline=no ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $perf_trampoline" >&5 -$as_echo "$perf_trampoline" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $perf_trampoline" >&5 +printf "%s\n" "$perf_trampoline" >&6; } -if test "x$perf_trampoline" = xyes; then : +if test "x$perf_trampoline" = xyes +then : -$as_echo "#define PY_HAVE_PERF_TRAMPOLINE 1" >>confdefs.h +printf "%s\n" "#define PY_HAVE_PERF_TRAMPOLINE 1" >>confdefs.h PERF_TRAMPOLINE_OBJ=Python/asm_trampoline.o - if test "x$Py_DEBUG" = xtrue; then : + if test "x$Py_DEBUG" = xtrue +then : as_fn_append BASECFLAGS " -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer" @@ -11662,11 +12986,12 @@ fi # checks for libraries -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile in -lsendfile" >&5 -$as_echo_n "checking for sendfile in -lsendfile... " >&6; } -if ${ac_cv_lib_sendfile_sendfile+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sendfile in -lsendfile" >&5 +printf %s "checking for sendfile in -lsendfile... " >&6; } +if test ${ac_cv_lib_sendfile_sendfile+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsendfile $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11675,43 +13000,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sendfile (); int -main () +main (void) { return sendfile (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sendfile_sendfile=yes -else +else $as_nop ac_cv_lib_sendfile_sendfile=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sendfile_sendfile" >&5 -$as_echo "$ac_cv_lib_sendfile_sendfile" >&6; } -if test "x$ac_cv_lib_sendfile_sendfile" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSENDFILE 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sendfile_sendfile" >&5 +printf "%s\n" "$ac_cv_lib_sendfile_sendfile" >&6; } +if test "x$ac_cv_lib_sendfile_sendfile" = xyes +then : + printf "%s\n" "#define HAVE_LIBSENDFILE 1" >>confdefs.h LIBS="-lsendfile $LIBS" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +printf %s "checking for dlopen in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlopen+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11720,43 +13043,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char dlopen (); int -main () +main (void) { return dlopen (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_dl_dlopen=yes -else +else $as_nop ac_cv_lib_dl_dlopen=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBDL 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes +then : + printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h LIBS="-ldl $LIBS" fi # Dynamic linking for SunOS/Solaris and SYSV -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -$as_echo_n "checking for shl_load in -ldld... " >&6; } -if ${ac_cv_lib_dld_shl_load+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +printf %s "checking for shl_load in -ldld... " >&6; } +if test ${ac_cv_lib_dld_shl_load+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11765,33 +13086,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char shl_load (); int -main () +main (void) { return shl_load (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_dld_shl_load=yes -else +else $as_nop ac_cv_lib_dld_shl_load=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -$as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBDLD 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes +then : + printf "%s\n" "#define HAVE_LIBDLD 1" >>confdefs.h LIBS="-ldld $LIBS" @@ -11804,49 +13122,50 @@ fi have_uuid=missing -for ac_header in uuid.h + for ac_header in uuid.h do : - ac_fn_c_check_header_mongrel "$LINENO" "uuid.h" "ac_cv_header_uuid_h" "$ac_includes_default" -if test "x$ac_cv_header_uuid_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_UUID_H 1 -_ACEOF - for ac_func in uuid_create uuid_enc_be + ac_fn_c_check_header_compile "$LINENO" "uuid.h" "ac_cv_header_uuid_h" "$ac_includes_default" +if test "x$ac_cv_header_uuid_h" = xyes +then : + printf "%s\n" "#define HAVE_UUID_H 1" >>confdefs.h + + for ac_func in uuid_create uuid_enc_be do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` + as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF have_uuid=yes LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} LIBUUID_LIBS=${LIBUUID_LIBS-""} fi -done +done fi done - -if test "x$have_uuid" = xmissing; then : +if test "x$have_uuid" = xmissing +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBUUID" >&5 -$as_echo_n "checking for LIBUUID... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBUUID" >&5 +printf %s "checking for LIBUUID... " >&6; } if test -n "$LIBUUID_CFLAGS"; then pkg_cv_LIBUUID_CFLAGS="$LIBUUID_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid >= 2.20\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid >= 2.20\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid >= 2.20") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBUUID_CFLAGS=`$PKG_CONFIG --cflags "uuid >= 2.20" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -11860,10 +13179,10 @@ if test -n "$LIBUUID_LIBS"; then pkg_cv_LIBUUID_LIBS="$LIBUUID_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid >= 2.20\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid >= 2.20\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid >= 2.20") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBUUID_LIBS=`$PKG_CONFIG --libs "uuid >= 2.20" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -11877,8 +13196,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -11902,20 +13221,20 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" LDFLAGS="$LDFLAGS $LIBUUID_LIBS" - for ac_header in uuid/uuid.h + for ac_header in uuid/uuid.h do : - ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" -if test "x$ac_cv_header_uuid_uuid_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_UUID_UUID_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" +if test "x$ac_cv_header_uuid_uuid_h" = xyes +then : + printf "%s\n" "#define HAVE_UUID_UUID_H 1" >>confdefs.h py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time in -luuid" >&5 -$as_echo_n "checking for uuid_generate_time in -luuid... " >&6; } -if ${ac_cv_lib_uuid_uuid_generate_time+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time in -luuid" >&5 +printf %s "checking for uuid_generate_time in -luuid... " >&6; } +if test ${ac_cv_lib_uuid_uuid_generate_time+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11924,41 +13243,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char uuid_generate_time (); int -main () +main (void) { return uuid_generate_time (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_uuid_uuid_generate_time=yes -else +else $as_nop ac_cv_lib_uuid_uuid_generate_time=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 -$as_echo "$ac_cv_lib_uuid_uuid_generate_time" >&6; } -if test "x$ac_cv_lib_uuid_uuid_generate_time" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 +printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time" >&6; } +if test "x$ac_cv_lib_uuid_uuid_generate_time" = xyes +then : have_uuid=yes fi LIBS=$py_check_lib_save_LIBS py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time_safe in -luuid" >&5 -$as_echo_n "checking for uuid_generate_time_safe in -luuid... " >&6; } -if ${ac_cv_lib_uuid_uuid_generate_time_safe+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time_safe in -luuid" >&5 +printf %s "checking for uuid_generate_time_safe in -luuid... " >&6; } +if test ${ac_cv_lib_uuid_uuid_generate_time_safe+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11967,32 +13286,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char uuid_generate_time_safe (); int -main () +main (void) { return uuid_generate_time_safe (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_uuid_uuid_generate_time_safe=yes -else +else $as_nop ac_cv_lib_uuid_uuid_generate_time_safe=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 -$as_echo "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } -if test "x$ac_cv_lib_uuid_uuid_generate_time_safe" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 +printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } +if test "x$ac_cv_lib_uuid_uuid_generate_time_safe" = xyes +then : have_uuid=yes - $as_echo "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h + printf "%s\n" "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h fi @@ -12001,8 +13319,8 @@ LIBS=$py_check_lib_save_LIBS fi done - - if test "x$have_uuid" = xyes; then : + if test "x$have_uuid" = xyes +then : LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} LIBUUID_LIBS=${LIBUUID_LIBS-"-luuid"} @@ -12018,8 +13336,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -12029,20 +13347,20 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBUUID_CFLAGS" LDFLAGS="$LDFLAGS $LIBUUID_LIBS" - for ac_header in uuid/uuid.h + for ac_header in uuid/uuid.h do : - ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" -if test "x$ac_cv_header_uuid_uuid_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_UUID_UUID_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" +if test "x$ac_cv_header_uuid_uuid_h" = xyes +then : + printf "%s\n" "#define HAVE_UUID_UUID_H 1" >>confdefs.h py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time in -luuid" >&5 -$as_echo_n "checking for uuid_generate_time in -luuid... " >&6; } -if ${ac_cv_lib_uuid_uuid_generate_time+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time in -luuid" >&5 +printf %s "checking for uuid_generate_time in -luuid... " >&6; } +if test ${ac_cv_lib_uuid_uuid_generate_time+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12051,41 +13369,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char uuid_generate_time (); int -main () +main (void) { return uuid_generate_time (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_uuid_uuid_generate_time=yes -else +else $as_nop ac_cv_lib_uuid_uuid_generate_time=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 -$as_echo "$ac_cv_lib_uuid_uuid_generate_time" >&6; } -if test "x$ac_cv_lib_uuid_uuid_generate_time" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time" >&5 +printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time" >&6; } +if test "x$ac_cv_lib_uuid_uuid_generate_time" = xyes +then : have_uuid=yes fi LIBS=$py_check_lib_save_LIBS py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time_safe in -luuid" >&5 -$as_echo_n "checking for uuid_generate_time_safe in -luuid... " >&6; } -if ${ac_cv_lib_uuid_uuid_generate_time_safe+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uuid_generate_time_safe in -luuid" >&5 +printf %s "checking for uuid_generate_time_safe in -luuid... " >&6; } +if test ${ac_cv_lib_uuid_uuid_generate_time_safe+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12094,32 +13412,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char uuid_generate_time_safe (); int -main () +main (void) { return uuid_generate_time_safe (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_uuid_uuid_generate_time_safe=yes -else +else $as_nop ac_cv_lib_uuid_uuid_generate_time_safe=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 -$as_echo "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } -if test "x$ac_cv_lib_uuid_uuid_generate_time_safe" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate_time_safe" >&5 +printf "%s\n" "$ac_cv_lib_uuid_uuid_generate_time_safe" >&6; } +if test "x$ac_cv_lib_uuid_uuid_generate_time_safe" = xyes +then : have_uuid=yes - $as_echo "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h + printf "%s\n" "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h fi @@ -12128,8 +13445,8 @@ LIBS=$py_check_lib_save_LIBS fi done - - if test "x$have_uuid" = xyes; then : + if test "x$have_uuid" = xyes +then : LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} LIBUUID_LIBS=${LIBUUID_LIBS-"-luuid"} @@ -12147,30 +13464,31 @@ LIBS=$save_LIBS else LIBUUID_CFLAGS=$pkg_cv_LIBUUID_CFLAGS LIBUUID_LIBS=$pkg_cv_LIBUUID_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_uuid=yes - $as_echo "#define HAVE_UUID_H 1" >>confdefs.h + printf "%s\n" "#define HAVE_UUID_H 1" >>confdefs.h - $as_echo "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h + printf "%s\n" "#define HAVE_UUID_GENERATE_TIME_SAFE 1" >>confdefs.h fi fi -if test "x$have_uuid" = xmissing; then : +if test "x$have_uuid" = xmissing +then : - for ac_header in uuid/uuid.h + for ac_header in uuid/uuid.h do : - ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" -if test "x$ac_cv_header_uuid_uuid_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_UUID_UUID_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default" +if test "x$ac_cv_header_uuid_uuid_h" = xyes +then : + printf "%s\n" "#define HAVE_UUID_UUID_H 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "uuid_generate_time" "ac_cv_func_uuid_generate_time" -if test "x$ac_cv_func_uuid_generate_time" = xyes; then : +if test "x$ac_cv_func_uuid_generate_time" = xyes +then : have_uuid=yes LIBUUID_CFLAGS=${LIBUUID_CFLAGS-""} @@ -12183,21 +13501,22 @@ fi done - fi -if test "x$have_uuid" = xmissing; then : +if test "x$have_uuid" = xmissing +then : have_uuid=no fi # 'Real Time' functions on Solaris # posix4 on Solaris 2.6 # pthread (first!) on Linux -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 -$as_echo_n "checking for library containing sem_init... " >&6; } -if ${ac_cv_search_sem_init+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 +printf %s "checking for library containing sem_init... " >&6; } +if test ${ac_cv_search_sem_init+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -12205,57 +13524,60 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sem_init (); int -main () +main (void) { return sem_init (); ; return 0; } _ACEOF -for ac_lib in '' pthread rt posix4; do +for ac_lib in '' pthread rt posix4 +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_sem_init=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_sem_init+:} false; then : + if test ${ac_cv_search_sem_init+y} +then : break fi done -if ${ac_cv_search_sem_init+:} false; then : +if test ${ac_cv_search_sem_init+y} +then : -else +else $as_nop ac_cv_search_sem_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_init" >&5 -$as_echo "$ac_cv_search_sem_init" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_init" >&5 +printf "%s\n" "$ac_cv_search_sem_init" >&6; } ac_res=$ac_cv_search_sem_init -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # check if we need libintl for locale functions -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 -$as_echo_n "checking for textdomain in -lintl... " >&6; } -if ${ac_cv_lib_intl_textdomain+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 +printf %s "checking for textdomain in -lintl... " >&6; } +if test ${ac_cv_lib_intl_textdomain+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12264,32 +13586,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char textdomain (); int -main () +main (void) { return textdomain (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_intl_textdomain=yes -else +else $as_nop ac_cv_lib_intl_textdomain=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 -$as_echo "$ac_cv_lib_intl_textdomain" >&6; } -if test "x$ac_cv_lib_intl_textdomain" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 +printf "%s\n" "$ac_cv_lib_intl_textdomain" >&6; } +if test "x$ac_cv_lib_intl_textdomain" = xyes +then : -$as_echo "#define WITH_LIBINTL 1" >>confdefs.h +printf "%s\n" "#define WITH_LIBINTL 1" >>confdefs.h LIBS="-lintl $LIBS" fi @@ -12297,14 +13618,14 @@ fi # checks for system dependent C++ extensions support case "$ac_sys_system" in - AIX*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for genuine AIX C++ extensions support" >&5 -$as_echo_n "checking for genuine AIX C++ extensions support... " >&6; } + AIX*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for genuine AIX C++ extensions support" >&5 +printf %s "checking for genuine AIX C++ extensions support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { loadAndInit("", 0, "") ; @@ -12312,48 +13633,49 @@ loadAndInit("", 0, "") } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : -$as_echo "#define AIX_GENUINE_CPLUSPLUS 1" >>confdefs.h +printf "%s\n" "#define AIX_GENUINE_CPLUSPLUS 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext # BUILD_GNU_TYPE + AIX_BUILDDATE are used to construct the platform_tag # of the AIX system used to build/package Python executable. This tag serves # as a baseline for bdist module packages - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the system builddate" >&5 -$as_echo_n "checking for the system builddate... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the system builddate" >&5 +printf %s "checking for the system builddate... " >&6; } AIX_BUILDDATE=$(lslpp -Lcq bos.mp64 | awk -F: '{ print $NF }') -cat >>confdefs.h <<_ACEOF -#define AIX_BUILDDATE $AIX_BUILDDATE -_ACEOF +printf "%s\n" "#define AIX_BUILDDATE $AIX_BUILDDATE" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AIX_BUILDDATE" >&5 -$as_echo "$AIX_BUILDDATE" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AIX_BUILDDATE" >&5 +printf "%s\n" "$AIX_BUILDDATE" >&6; } ;; *) ;; esac # check for systems that require aligned memory access -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking aligned memory access is required" >&5 -$as_echo_n "checking aligned memory access is required... " >&6; } -if ${ac_cv_aligned_required+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking aligned memory access is required" >&5 +printf %s "checking aligned memory access is required... " >&6; } +if test ${ac_cv_aligned_required+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_aligned_required=yes -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -12370,9 +13692,10 @@ int main(void) return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_aligned_required=no -else +else $as_nop ac_cv_aligned_required=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -12381,36 +13704,37 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_aligned_required" >&5 -$as_echo "$ac_cv_aligned_required" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_aligned_required" >&5 +printf "%s\n" "$ac_cv_aligned_required" >&6; } if test "$ac_cv_aligned_required" = yes ; then -$as_echo "#define HAVE_ALIGNED_REQUIRED 1" >>confdefs.h +printf "%s\n" "#define HAVE_ALIGNED_REQUIRED 1" >>confdefs.h fi # str, bytes and memoryview hash algorithm -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-hash-algorithm" >&5 -$as_echo_n "checking for --with-hash-algorithm... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-hash-algorithm" >&5 +printf %s "checking for --with-hash-algorithm... " >&6; } # Check whether --with-hash_algorithm was given. -if test "${with_hash_algorithm+set}" = set; then : +if test ${with_hash_algorithm+y} +then : withval=$with_hash_algorithm; -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 -$as_echo "$withval" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +printf "%s\n" "$withval" >&6; } case "$withval" in siphash13) - $as_echo "#define Py_HASH_ALGORITHM 3" >>confdefs.h + printf "%s\n" "#define Py_HASH_ALGORITHM 3" >>confdefs.h ;; siphash24) - $as_echo "#define Py_HASH_ALGORITHM 1" >>confdefs.h + printf "%s\n" "#define Py_HASH_ALGORITHM 1" >>confdefs.h ;; fnv) - $as_echo "#define Py_HASH_ALGORITHM 2" >>confdefs.h + printf "%s\n" "#define Py_HASH_ALGORITHM 2" >>confdefs.h ;; *) @@ -12418,9 +13742,9 @@ case "$withval" in ;; esac -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default" >&5 -$as_echo "default" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default" >&5 +printf "%s\n" "default" >&6; } fi @@ -12439,11 +13763,12 @@ validate_tzpath() { } TZPATH="/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/etc/zoneinfo" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-tzpath" >&5 -$as_echo_n "checking for --with-tzpath... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-tzpath" >&5 +printf %s "checking for --with-tzpath... " >&6; } # Check whether --with-tzpath was given. -if test "${with_tzpath+set}" = set; then : +if test ${with_tzpath+y} +then : withval=$with_tzpath; case "$withval" in yes) @@ -12452,25 +13777,26 @@ case "$withval" in *) validate_tzpath "$withval" TZPATH="$withval" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$withval\"" >&5 -$as_echo "\"$withval\"" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$withval\"" >&5 +printf "%s\n" "\"$withval\"" >&6; } ;; esac -else +else $as_nop validate_tzpath "$TZPATH" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$TZPATH\"" >&5 -$as_echo "\"$TZPATH\"" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$TZPATH\"" >&5 +printf "%s\n" "\"$TZPATH\"" >&6; } fi # Most SVR4 platforms (e.g. Solaris) need -lsocket and -lnsl. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 -$as_echo_n "checking for t_open in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_t_open+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 +printf %s "checking for t_open in -lnsl... " >&6; } +if test ${ac_cv_lib_nsl_t_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12479,38 +13805,38 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char t_open (); int -main () +main (void) { return t_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_nsl_t_open=yes -else +else $as_nop ac_cv_lib_nsl_t_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 -$as_echo "$ac_cv_lib_nsl_t_open" >&6; } -if test "x$ac_cv_lib_nsl_t_open" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 +printf "%s\n" "$ac_cv_lib_nsl_t_open" >&6; } +if test "x$ac_cv_lib_nsl_t_open" = xyes +then : LIBS="-lnsl $LIBS" fi # SVR4 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 -$as_echo_n "checking for socket in -lsocket... " >&6; } -if ${ac_cv_lib_socket_socket+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 +printf %s "checking for socket in -lsocket... " >&6; } +if test ${ac_cv_lib_socket_socket+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12519,41 +13845,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char socket (); int -main () +main (void) { return socket (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_socket_socket=yes -else +else $as_nop ac_cv_lib_socket_socket=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 -$as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 +printf "%s\n" "$ac_cv_lib_socket_socket" >&6; } +if test "x$ac_cv_lib_socket_socket" = xyes +then : LIBS="-lsocket $LIBS" fi # SVR4 sockets case $ac_sys_system/$ac_sys_release in Haiku*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5 -$as_echo_n "checking for socket in -lnetwork... " >&6; } -if ${ac_cv_lib_network_socket+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5 +printf %s "checking for socket in -lnetwork... " >&6; } +if test ${ac_cv_lib_network_socket+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12562,74 +13888,76 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char socket (); int -main () +main (void) { return socket (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_network_socket=yes -else +else $as_nop ac_cv_lib_network_socket=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5 -$as_echo "$ac_cv_lib_network_socket" >&6; } -if test "x$ac_cv_lib_network_socket" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5 +printf "%s\n" "$ac_cv_lib_network_socket" >&6; } +if test "x$ac_cv_lib_network_socket" = xyes +then : LIBS="-lnetwork $LIBS" fi ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-libs" >&5 -$as_echo_n "checking for --with-libs... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-libs" >&5 +printf %s "checking for --with-libs... " >&6; } # Check whether --with-libs was given. -if test "${with_libs+set}" = set; then : +if test ${with_libs+y} +then : withval=$with_libs; -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 -$as_echo "$withval" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +printf "%s\n" "$withval" >&6; } LIBS="$withval $LIBS" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi # Check for use of the system expat library -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-system-expat" >&5 -$as_echo_n "checking for --with-system-expat... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-system-expat" >&5 +printf %s "checking for --with-system-expat... " >&6; } # Check whether --with-system_expat was given. -if test "${with_system_expat+set}" = set; then : +if test ${with_system_expat+y} +then : withval=$with_system_expat; -else +else $as_nop with_system_expat="no" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_system_expat" >&5 -$as_echo "$with_system_expat" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_system_expat" >&5 +printf "%s\n" "$with_system_expat" >&6; } -if test "x$with_system_expat" = xyes; then : +if test "x$with_system_expat" = xyes +then : LIBEXPAT_CFLAGS=${LIBEXPAT_CFLAGS-""} LIBEXPAT_LDFLAGS=${LIBEXPAT_LDFLAGS-"-lexpat"} LIBEXPAT_INTERNAL= -else +else $as_nop LIBEXPAT_CFLAGS="-I\$(srcdir)/Modules/expat" LIBEXPAT_LDFLAGS="-lm \$(LIBEXPAT_A)" @@ -12641,7 +13969,8 @@ fi have_libffi=missing -if test "x$ac_sys_system" = xDarwin; then : +if test "x$ac_sys_system" = xDarwin +then : save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -12650,14 +13979,16 @@ save_LIBS=$LIBS CFLAGS="-I${SDKROOT}/usr/include/ffi $CFLAGS" - ac_fn_c_check_header_mongrel "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" -if test "x$ac_cv_header_ffi_h" = xyes; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_call in -lffi" >&5 -$as_echo_n "checking for ffi_call in -lffi... " >&6; } -if ${ac_cv_lib_ffi_ffi_call+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" +if test "x$ac_cv_header_ffi_h" = xyes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ffi_call in -lffi" >&5 +printf %s "checking for ffi_call in -lffi... " >&6; } +if test ${ac_cv_lib_ffi_ffi_call+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lffi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12666,30 +13997,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char ffi_call (); int -main () +main (void) { return ffi_call (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ffi_ffi_call=yes -else +else $as_nop ac_cv_lib_ffi_ffi_call=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 -$as_echo "$ac_cv_lib_ffi_ffi_call" >&6; } -if test "x$ac_cv_lib_ffi_ffi_call" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 +printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } +if test "x$ac_cv_lib_ffi_ffi_call" = xyes +then : have_libffi=yes LIBFFI_CFLAGS="-I${SDKROOT}/usr/include/ffi -DUSING_APPLE_OS_LIBFFI=1" @@ -12701,7 +14031,6 @@ fi fi - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -12710,21 +14039,22 @@ LIBS=$save_LIBS fi -if test "x$have_libffi" = xmissing; then : +if test "x$have_libffi" = xmissing +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBFFI" >&5 -$as_echo_n "checking for LIBFFI... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBFFI" >&5 +printf %s "checking for LIBFFI... " >&6; } if test -n "$LIBFFI_CFLAGS"; then pkg_cv_LIBFFI_CFLAGS="$LIBFFI_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libffi\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libffi\""; } >&5 ($PKG_CONFIG --exists --print-errors "libffi") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBFFI_CFLAGS=`$PKG_CONFIG --cflags "libffi" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -12738,10 +14068,10 @@ if test -n "$LIBFFI_LIBS"; then pkg_cv_LIBFFI_LIBS="$LIBFFI_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libffi\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libffi\""; } >&5 ($PKG_CONFIG --exists --print-errors "libffi") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBFFI_LIBS=`$PKG_CONFIG --libs "libffi" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -12755,8 +14085,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -12780,14 +14110,16 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" LDFLAGS="$LDFLAGS $LIBFFI_LIBS" - ac_fn_c_check_header_mongrel "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" -if test "x$ac_cv_header_ffi_h" = xyes; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_call in -lffi" >&5 -$as_echo_n "checking for ffi_call in -lffi... " >&6; } -if ${ac_cv_lib_ffi_ffi_call+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" +if test "x$ac_cv_header_ffi_h" = xyes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ffi_call in -lffi" >&5 +printf %s "checking for ffi_call in -lffi... " >&6; } +if test ${ac_cv_lib_ffi_ffi_call+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lffi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12796,36 +14128,35 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char ffi_call (); int -main () +main (void) { return ffi_call (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ffi_ffi_call=yes -else +else $as_nop ac_cv_lib_ffi_ffi_call=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 -$as_echo "$ac_cv_lib_ffi_ffi_call" >&6; } -if test "x$ac_cv_lib_ffi_ffi_call" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 +printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } +if test "x$ac_cv_lib_ffi_ffi_call" = xyes +then : have_libffi=yes LIBFFI_CFLAGS=${LIBFFI_CFLAGS-""} LIBFFI_LIBS=${LIBFFI_LIBS-"-lffi"} -else +else $as_nop have_libffi=no fi @@ -12833,7 +14164,6 @@ fi fi - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -12842,8 +14172,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -12853,14 +14183,16 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBFFI_CFLAGS" LDFLAGS="$LDFLAGS $LIBFFI_LIBS" - ac_fn_c_check_header_mongrel "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" -if test "x$ac_cv_header_ffi_h" = xyes; then : - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_call in -lffi" >&5 -$as_echo_n "checking for ffi_call in -lffi... " >&6; } -if ${ac_cv_lib_ffi_ffi_call+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "ffi.h" "ac_cv_header_ffi_h" "$ac_includes_default" +if test "x$ac_cv_header_ffi_h" = xyes +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ffi_call in -lffi" >&5 +printf %s "checking for ffi_call in -lffi... " >&6; } +if test ${ac_cv_lib_ffi_ffi_call+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lffi $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12869,36 +14201,35 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char ffi_call (); int -main () +main (void) { return ffi_call (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ffi_ffi_call=yes -else +else $as_nop ac_cv_lib_ffi_ffi_call=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 -$as_echo "$ac_cv_lib_ffi_ffi_call" >&6; } -if test "x$ac_cv_lib_ffi_ffi_call" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 +printf "%s\n" "$ac_cv_lib_ffi_ffi_call" >&6; } +if test "x$ac_cv_lib_ffi_ffi_call" = xyes +then : have_libffi=yes LIBFFI_CFLAGS=${LIBFFI_CFLAGS-""} LIBFFI_LIBS=${LIBFFI_LIBS-"-lffi"} -else +else $as_nop have_libffi=no fi @@ -12906,7 +14237,6 @@ fi fi - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -12917,14 +14247,15 @@ LIBS=$save_LIBS else LIBFFI_CFLAGS=$pkg_cv_LIBFFI_CFLAGS LIBFFI_LIBS=$pkg_cv_LIBFFI_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_libffi=yes fi fi -if test "x$have_libffi" = xyes; then : +if test "x$have_libffi" = xyes +then : ctypes_malloc_closure=no case $ac_sys_system in #( @@ -12938,7 +14269,8 @@ if test "x$have_libffi" = xyes; then : *) : ;; esac - if test "x$ctypes_malloc_closure" = xyes; then : + if test "x$ctypes_malloc_closure" = xyes +then : MODULE__CTYPES_MALLOC_CLOSURE=_ctypes/malloc_closure.c as_fn_append LIBFFI_CFLAGS " -DUSING_MALLOC_CLOSURE_DOT_C=1" @@ -12946,7 +14278,8 @@ esac fi - if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + if test "x$ac_cv_lib_dl_dlopen" = xyes +then : as_fn_append LIBFFI_LIBS " -ldl" fi @@ -12961,35 +14294,38 @@ save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_prep_cif_var" >&5 -$as_echo_n "checking for ffi_prep_cif_var... " >&6; } -if ${ac_cv_func_ffi_prep_cif_var+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ffi_prep_cif_var" >&5 +printf %s "checking for ffi_prep_cif_var... " >&6; } +if test ${ac_cv_func_ffi_prep_cif_var+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=ffi_prep_cif_var ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_ffi_prep_cif_var=yes -else +else $as_nop ac_cv_func_ffi_prep_cif_var=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_cif_var" >&5 -$as_echo "$ac_cv_func_ffi_prep_cif_var" >&6; } - if test "x$ac_cv_func_ffi_prep_cif_var" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_cif_var" >&5 +printf "%s\n" "$ac_cv_func_ffi_prep_cif_var" >&6; } + if test "x$ac_cv_func_ffi_prep_cif_var" = xyes +then : -$as_echo "#define HAVE_FFI_PREP_CIF_VAR 1" >>confdefs.h +printf "%s\n" "#define HAVE_FFI_PREP_CIF_VAR 1" >>confdefs.h fi @@ -12997,35 +14333,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_prep_closure_loc" >&5 -$as_echo_n "checking for ffi_prep_closure_loc... " >&6; } -if ${ac_cv_func_ffi_prep_closure_loc+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ffi_prep_closure_loc" >&5 +printf %s "checking for ffi_prep_closure_loc... " >&6; } +if test ${ac_cv_func_ffi_prep_closure_loc+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=ffi_prep_closure_loc ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_ffi_prep_closure_loc=yes -else +else $as_nop ac_cv_func_ffi_prep_closure_loc=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_closure_loc" >&5 -$as_echo "$ac_cv_func_ffi_prep_closure_loc" >&6; } - if test "x$ac_cv_func_ffi_prep_closure_loc" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_prep_closure_loc" >&5 +printf "%s\n" "$ac_cv_func_ffi_prep_closure_loc" >&6; } + if test "x$ac_cv_func_ffi_prep_closure_loc" = xyes +then : -$as_echo "#define HAVE_FFI_PREP_CLOSURE_LOC 1" >>confdefs.h +printf "%s\n" "#define HAVE_FFI_PREP_CLOSURE_LOC 1" >>confdefs.h fi @@ -13033,35 +14372,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_closure_alloc" >&5 -$as_echo_n "checking for ffi_closure_alloc... " >&6; } -if ${ac_cv_func_ffi_closure_alloc+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ffi_closure_alloc" >&5 +printf %s "checking for ffi_closure_alloc... " >&6; } +if test ${ac_cv_func_ffi_closure_alloc+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=ffi_closure_alloc ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_ffi_closure_alloc=yes -else +else $as_nop ac_cv_func_ffi_closure_alloc=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_closure_alloc" >&5 -$as_echo "$ac_cv_func_ffi_closure_alloc" >&6; } - if test "x$ac_cv_func_ffi_closure_alloc" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ffi_closure_alloc" >&5 +printf "%s\n" "$ac_cv_func_ffi_closure_alloc" >&6; } + if test "x$ac_cv_func_ffi_closure_alloc" = xyes +then : -$as_echo "#define HAVE_FFI_CLOSURE_ALLOC 1" >>confdefs.h +printf "%s\n" "#define HAVE_FFI_CLOSURE_ALLOC 1" >>confdefs.h fi @@ -13078,32 +14420,35 @@ LIBS=$save_LIBS fi # Check for use of the system libmpdec library -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-system-libmpdec" >&5 -$as_echo_n "checking for --with-system-libmpdec... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-system-libmpdec" >&5 +printf %s "checking for --with-system-libmpdec... " >&6; } # Check whether --with-system_libmpdec was given. -if test "${with_system_libmpdec+set}" = set; then : +if test ${with_system_libmpdec+y} +then : withval=$with_system_libmpdec; -else +else $as_nop with_system_libmpdec="no" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_system_libmpdec" >&5 -$as_echo "$with_system_libmpdec" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_system_libmpdec" >&5 +printf "%s\n" "$with_system_libmpdec" >&6; } -if test "x$with_system_libmpdec" = xyes; then : +if test "x$with_system_libmpdec" = xyes +then : LIBMPDEC_CFLAGS=${LIBMPDEC_CFLAGS-""} LIBMPDEC_LDFLAGS=${LIBMPDEC_LDFLAGS-"-lmpdec"} LIBMPDEC_INTERNAL= -else +else $as_nop LIBMPDEC_CFLAGS="-I\$(srcdir)/Modules/_decimal/libmpdec" LIBMPDEC_LDFLAGS="-lm \$(LIBMPDEC_A)" LIBMPDEC_INTERNAL="\$(LIBMPDEC_HEADERS) \$(LIBMPDEC_A)" - if test "x$with_pydebug" = xyes; then : + if test "x$with_pydebug" = xyes +then : as_fn_append LIBMPDEC_CFLAGS " -DTEST_COVERAGE" @@ -13115,13 +14460,14 @@ fi # Check whether _decimal should use a coroutine-local or thread-local context -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-decimal-contextvar" >&5 -$as_echo_n "checking for --with-decimal-contextvar... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-decimal-contextvar" >&5 +printf %s "checking for --with-decimal-contextvar... " >&6; } # Check whether --with-decimal_contextvar was given. -if test "${with_decimal_contextvar+set}" = set; then : +if test ${with_decimal_contextvar+y} +then : withval=$with_decimal_contextvar; -else +else $as_nop with_decimal_contextvar="yes" fi @@ -13129,16 +14475,16 @@ fi if test "$with_decimal_contextvar" != "no" then -$as_echo "#define WITH_DECIMAL_CONTEXTVAR 1" >>confdefs.h +printf "%s\n" "#define WITH_DECIMAL_CONTEXTVAR 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_decimal_contextvar" >&5 -$as_echo "$with_decimal_contextvar" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_decimal_contextvar" >&5 +printf "%s\n" "$with_decimal_contextvar" >&6; } # Check for libmpdec machine flavor -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for decimal libmpdec machine" >&5 -$as_echo_n "checking for decimal libmpdec machine... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for decimal libmpdec machine" >&5 +printf %s "checking for decimal libmpdec machine... " >&6; } case $ac_sys_system in #( Darwin*) : libmpdec_system=Darwin ;; #( @@ -13177,8 +14523,8 @@ esac libmpdec_machine=ansi32 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libmpdec_machine" >&5 -$as_echo "$libmpdec_machine" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libmpdec_machine" >&5 +printf "%s\n" "$libmpdec_machine" >&6; } case $libmpdec_machine in #( x64) : @@ -13216,17 +14562,17 @@ fi pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBNSL" >&5 -$as_echo_n "checking for LIBNSL... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBNSL" >&5 +printf %s "checking for LIBNSL... " >&6; } if test -n "$LIBNSL_CFLAGS"; then pkg_cv_LIBNSL_CFLAGS="$LIBNSL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnsl\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnsl\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnsl") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNSL_CFLAGS=`$PKG_CONFIG --cflags "libnsl" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -13240,10 +14586,10 @@ if test -n "$LIBNSL_LIBS"; then pkg_cv_LIBNSL_LIBS="$LIBNSL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnsl\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnsl\""; } >&5 ($PKG_CONFIG --exists --print-errors "libnsl") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNSL_LIBS=`$PKG_CONFIG --libs "libnsl" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -13257,8 +14603,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -13281,11 +14627,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing yp_match" >&5 -$as_echo_n "checking for library containing yp_match... " >&6; } -if ${ac_cv_search_yp_match+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing yp_match" >&5 +printf %s "checking for library containing yp_match... " >&6; } +if test ${ac_cv_search_yp_match+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13293,49 +14640,51 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char yp_match (); int -main () +main (void) { return yp_match (); ; return 0; } _ACEOF -for ac_lib in '' nsl; do +for ac_lib in '' nsl +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_yp_match=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_yp_match+:} false; then : + if test ${ac_cv_search_yp_match+y} +then : break fi done -if ${ac_cv_search_yp_match+:} false; then : +if test ${ac_cv_search_yp_match+y} +then : -else +else $as_nop ac_cv_search_yp_match=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_yp_match" >&5 -$as_echo "$ac_cv_search_yp_match" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_yp_match" >&5 +printf "%s\n" "$ac_cv_search_yp_match" >&6; } ac_res=$ac_cv_search_yp_match -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" have_nis=yes -else +else $as_nop have_nis=no fi @@ -13358,8 +14707,8 @@ esac LIBNSL_LIBS=${LIBNSL_LIBS-$libnsl} elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } LIBNSL_CFLAGS=${LIBNSL_CFLAGS-""} save_CFLAGS=$CFLAGS @@ -13368,11 +14717,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing yp_match" >&5 -$as_echo_n "checking for library containing yp_match... " >&6; } -if ${ac_cv_search_yp_match+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing yp_match" >&5 +printf %s "checking for library containing yp_match... " >&6; } +if test ${ac_cv_search_yp_match+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13380,49 +14730,51 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char yp_match (); int -main () +main (void) { return yp_match (); ; return 0; } _ACEOF -for ac_lib in '' nsl; do +for ac_lib in '' nsl +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_yp_match=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_yp_match+:} false; then : + if test ${ac_cv_search_yp_match+y} +then : break fi done -if ${ac_cv_search_yp_match+:} false; then : +if test ${ac_cv_search_yp_match+y} +then : -else +else $as_nop ac_cv_search_yp_match=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_yp_match" >&5 -$as_echo "$ac_cv_search_yp_match" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_yp_match" >&5 +printf "%s\n" "$ac_cv_search_yp_match" >&6; } ac_res=$ac_cv_search_yp_match -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" have_nis=yes -else +else $as_nop have_nis=no fi @@ -13447,12 +14799,13 @@ esac else LIBNSL_CFLAGS=$pkg_cv_LIBNSL_CFLAGS LIBNSL_LIBS=$pkg_cv_LIBNSL_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_nis=yes fi -if test "x$have_nis" = xyes; then : +if test "x$have_nis" = xyes +then : save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -13461,18 +14814,13 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBNSL_CFLAGS" - for ac_header in rpc/rpc.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "rpc/rpc.h" "ac_cv_header_rpc_rpc_h" "$ac_includes_default" -if test "x$ac_cv_header_rpc_rpc_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_RPC_RPC_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "rpc/rpc.h" "ac_cv_header_rpc_rpc_h" "$ac_includes_default" +if test "x$ac_cv_header_rpc_rpc_h" = xyes +then : + printf "%s\n" "#define HAVE_RPC_RPC_H 1" >>confdefs.h fi -done - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS @@ -13494,7 +14842,8 @@ esac - if test "$ac_sys_system" = "Emscripten" -a -z "$LIBSQLITE3_CFLAGS" -a -z "$LIBSQLITE3_LIBS"; then : + if test "$ac_sys_system" = "Emscripten" -a -z "$LIBSQLITE3_CFLAGS" -a -z "$LIBSQLITE3_LIBS" +then : LIBSQLITE3_CFLAGS="-sUSE_SQLITE3" LIBSQLITE3_LIBS="-sUSE_SQLITE3" @@ -13506,17 +14855,17 @@ fi pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSQLITE3" >&5 -$as_echo_n "checking for LIBSQLITE3... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBSQLITE3" >&5 +printf %s "checking for LIBSQLITE3... " >&6; } if test -n "$LIBSQLITE3_CFLAGS"; then pkg_cv_LIBSQLITE3_CFLAGS="$LIBSQLITE3_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.7.15\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.7.15\""; } >&5 ($PKG_CONFIG --exists --print-errors "sqlite3 >= 3.7.15") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBSQLITE3_CFLAGS=`$PKG_CONFIG --cflags "sqlite3 >= 3.7.15" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -13530,10 +14879,10 @@ if test -n "$LIBSQLITE3_LIBS"; then pkg_cv_LIBSQLITE3_LIBS="$LIBSQLITE3_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.7.15\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.7.15\""; } >&5 ($PKG_CONFIG --exists --print-errors "sqlite3 >= 3.7.15") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBSQLITE3_LIBS=`$PKG_CONFIG --libs "sqlite3 >= 3.7.15" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -13547,8 +14896,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -13569,8 +14918,8 @@ fi elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } LIBSQLITE3_CFLAGS=${LIBSQLITE3_CFLAGS-""} LIBSQLITE3_LIBS=${LIBSQLITE3_LIBS-"-lsqlite3"} @@ -13579,8 +14928,8 @@ $as_echo "no" >&6; } else LIBSQLITE3_CFLAGS=$pkg_cv_LIBSQLITE3_CFLAGS LIBSQLITE3_LIBS=$pkg_cv_LIBSQLITE3_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi as_fn_append LIBSQLITE3_CFLAGS ' -I$(srcdir)/Modules/_sqlite' @@ -13596,8 +14945,9 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBSQLITE3_CFLAGS" LDFLAGS="$LIBSQLITE3_LIBS $LDFLAGS" - ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" -if test "x$ac_cv_header_sqlite3_h" = xyes; then : + ac_fn_c_check_header_compile "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" +if test "x$ac_cv_header_sqlite3_h" = xyes +then : have_sqlite3=yes @@ -13611,7 +14961,7 @@ if test "x$ac_cv_header_sqlite3_h" = xyes; then : #endif int -main () +main (void) { ; @@ -13619,15 +14969,17 @@ main () } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : have_supported_sqlite3=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_bind_double in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_bind_double in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_bind_double+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_bind_double in -lsqlite3" >&5 +printf %s "checking for sqlite3_bind_double in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_bind_double+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13636,37 +14988,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_bind_double (); int -main () +main (void) { return sqlite3_bind_double (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_bind_double=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_bind_double=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_bind_double" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_bind_double" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_bind_double" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_bind_double" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_bind_double" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_bind_double" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -13674,11 +15023,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_column_decltype in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_column_decltype in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_column_decltype+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_column_decltype in -lsqlite3" >&5 +printf %s "checking for sqlite3_column_decltype in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_column_decltype+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13687,37 +15037,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_column_decltype (); int -main () +main (void) { return sqlite3_column_decltype (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_column_decltype=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_column_decltype=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_decltype" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_column_decltype" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_column_decltype" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_decltype" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_column_decltype" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_column_decltype" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -13725,11 +15072,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_column_double in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_column_double in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_column_double+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_column_double in -lsqlite3" >&5 +printf %s "checking for sqlite3_column_double in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_column_double+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13738,37 +15086,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_column_double (); int -main () +main (void) { return sqlite3_column_double (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_column_double=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_column_double=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_double" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_column_double" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_column_double" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_column_double" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_column_double" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_column_double" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -13776,11 +15121,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_complete in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_complete in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_complete+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_complete in -lsqlite3" >&5 +printf %s "checking for sqlite3_complete in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_complete+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13789,37 +15135,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_complete (); int -main () +main (void) { return sqlite3_complete (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_complete=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_complete=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_complete" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_complete" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_complete" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_complete" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_complete" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_complete" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -13827,11 +15170,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_progress_handler in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_progress_handler in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_progress_handler+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_progress_handler in -lsqlite3" >&5 +printf %s "checking for sqlite3_progress_handler in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_progress_handler+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13840,37 +15184,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_progress_handler (); int -main () +main (void) { return sqlite3_progress_handler (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_progress_handler=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_progress_handler=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_progress_handler" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_progress_handler" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_progress_handler" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_progress_handler" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_progress_handler" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_progress_handler" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -13878,11 +15219,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_result_double in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_result_double in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_result_double+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_result_double in -lsqlite3" >&5 +printf %s "checking for sqlite3_result_double in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_result_double+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13891,37 +15233,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_result_double (); int -main () +main (void) { return sqlite3_result_double (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_result_double=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_result_double=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_result_double" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_result_double" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_result_double" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_result_double" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_result_double" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_result_double" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -13929,11 +15268,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_set_authorizer in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_set_authorizer in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_set_authorizer+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_set_authorizer in -lsqlite3" >&5 +printf %s "checking for sqlite3_set_authorizer in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_set_authorizer+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13942,37 +15282,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_set_authorizer (); int -main () +main (void) { return sqlite3_set_authorizer (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_set_authorizer=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_set_authorizer=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_set_authorizer" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_set_authorizer" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_set_authorizer" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -13980,11 +15317,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_trace_v2 in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_trace_v2 in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_trace_v2+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_trace_v2 in -lsqlite3" >&5 +printf %s "checking for sqlite3_trace_v2 in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_trace_v2+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13993,45 +15331,43 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_trace_v2 (); int -main () +main (void) { return sqlite3_trace_v2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_trace_v2=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_trace_v2=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace_v2" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_trace_v2" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_trace_v2" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace_v2" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_trace_v2" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_trace_v2" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_trace in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_trace in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_trace+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_trace in -lsqlite3" >&5 +printf %s "checking for sqlite3_trace in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_trace+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14040,37 +15376,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_trace (); int -main () +main (void) { return sqlite3_trace (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_trace=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_trace=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_trace" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_trace" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_trace" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_trace" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_trace" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no @@ -14083,11 +15416,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_value_double in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_value_double in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_value_double+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_value_double in -lsqlite3" >&5 +printf %s "checking for sqlite3_value_double in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_value_double+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14096,48 +15430,46 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_value_double (); int -main () +main (void) { return sqlite3_value_double (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_value_double=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_value_double=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_value_double" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_value_double" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_value_double" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_value_double" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_value_double" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_value_double" = xyes +then : + printf "%s\n" "#define HAVE_LIBSQLITE3 1" >>confdefs.h LIBS="-lsqlite3 $LIBS" -else +else $as_nop have_supported_sqlite3=no fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_load_extension in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_load_extension in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_load_extension+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_load_extension in -lsqlite3" >&5 +printf %s "checking for sqlite3_load_extension in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_load_extension+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14146,41 +15478,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_load_extension (); int -main () +main (void) { return sqlite3_load_extension (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_load_extension=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_load_extension=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_load_extension" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_load_extension" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_load_extension" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_load_extension" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_load_extension" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_load_extension" = xyes +then : have_sqlite3_load_extension=yes -else +else $as_nop have_sqlite3_load_extension=no fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_serialize in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_serialize in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_serialize+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3_serialize in -lsqlite3" >&5 +printf %s "checking for sqlite3_serialize in -lsqlite3... " >&6; } +if test ${ac_cv_lib_sqlite3_sqlite3_serialize+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14189,49 +15521,47 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char sqlite3_serialize (); int -main () +main (void) { return sqlite3_serialize (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_sqlite3_sqlite3_serialize=yes -else +else $as_nop ac_cv_lib_sqlite3_sqlite3_serialize=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_serialize" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_serialize" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_serialize" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_serialize" >&5 +printf "%s\n" "$ac_cv_lib_sqlite3_sqlite3_serialize" >&6; } +if test "x$ac_cv_lib_sqlite3_sqlite3_serialize" = xyes +then : -$as_echo "#define PY_SQLITE_HAVE_SERIALIZE 1" >>confdefs.h +printf "%s\n" "#define PY_SQLITE_HAVE_SERIALIZE 1" >>confdefs.h fi -else +else $as_nop have_supported_sqlite3=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -14239,32 +15569,34 @@ LIBS=$save_LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-loadable-sqlite-extensions" >&5 -$as_echo_n "checking for --enable-loadable-sqlite-extensions... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-loadable-sqlite-extensions" >&5 +printf %s "checking for --enable-loadable-sqlite-extensions... " >&6; } # Check whether --enable-loadable-sqlite-extensions was given. -if test "${enable_loadable_sqlite_extensions+set}" = set; then : +if test ${enable_loadable_sqlite_extensions+y} +then : enableval=$enable_loadable_sqlite_extensions; - if test "x$have_sqlite3_load_extension" = xno; then : + if test "x$have_sqlite3_load_extension" = xno +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: n/a" >&5 -$as_echo "n/a" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Your version of SQLite does not support loadable extensions" >&5 -$as_echo "$as_me: WARNING: Your version of SQLite does not support loadable extensions" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: n/a" >&5 +printf "%s\n" "n/a" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Your version of SQLite does not support loadable extensions" >&5 +printf "%s\n" "$as_me: WARNING: Your version of SQLite does not support loadable extensions" >&2;} -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -$as_echo "#define PY_SQLITE_ENABLE_LOAD_EXTENSION 1" >>confdefs.h +printf "%s\n" "#define PY_SQLITE_ENABLE_LOAD_EXTENSION 1" >>confdefs.h fi -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -14279,25 +15611,25 @@ for _QUERY in \ "tcl85 >= 8.5.12 tk85 >= 8.5.12" \ ; do if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5 ($PKG_CONFIG --exists --print-errors "$_QUERY") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TCLTK" >&5 -$as_echo_n "checking for TCLTK... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TCLTK" >&5 +printf %s "checking for TCLTK... " >&6; } if test -n "$TCLTK_CFLAGS"; then pkg_cv_TCLTK_CFLAGS="$TCLTK_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5 ($PKG_CONFIG --exists --print-errors "$_QUERY") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_TCLTK_CFLAGS=`$PKG_CONFIG --cflags "$_QUERY" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -14311,10 +15643,10 @@ if test -n "$TCLTK_LIBS"; then pkg_cv_TCLTK_LIBS="$TCLTK_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5 ($PKG_CONFIG --exists --print-errors "$_QUERY") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_TCLTK_LIBS=`$PKG_CONFIG --libs "$_QUERY" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -14328,8 +15660,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -14346,24 +15678,26 @@ fi found_tcltk=no elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } found_tcltk=no else TCLTK_CFLAGS=$pkg_cv_TCLTK_CFLAGS TCLTK_LIBS=$pkg_cv_TCLTK_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } found_tcltk=yes fi fi - if test "x$found_tcltk" = xyes; then : + if test "x$found_tcltk" = xyes +then : break fi done -if test "x$found_tcltk" = xno; then : +if test "x$found_tcltk" = xno +then : TCLTK_CFLAGS=${TCLTK_CFLAGS-""} TCLTK_LIBS=${TCLTK_LIBS-""} @@ -14374,25 +15708,25 @@ case $ac_sys_system in #( FreeBSD*) : if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5 ($PKG_CONFIG --exists --print-errors "x11") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11" >&5 -$as_echo_n "checking for X11... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for X11" >&5 +printf %s "checking for X11... " >&6; } if test -n "$X11_CFLAGS"; then pkg_cv_X11_CFLAGS="$X11_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5 ($PKG_CONFIG --exists --print-errors "x11") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_X11_CFLAGS=`$PKG_CONFIG --cflags "x11" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -14406,10 +15740,10 @@ if test -n "$X11_LIBS"; then pkg_cv_X11_LIBS="$X11_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5 ($PKG_CONFIG --exists --print-errors "x11") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_X11_LIBS=`$PKG_CONFIG --libs "x11" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -14423,8 +15757,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -14450,10 +15784,10 @@ Alternatively, you may set the environment variables X11_CFLAGS and X11_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. @@ -14467,8 +15801,8 @@ See \`config.log' for more details" "$LINENO" 5; } else X11_CFLAGS=$pkg_cv_X11_CFLAGS X11_LIBS=$pkg_cv_X11_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } TCLTK_CFLAGS="$TCLTK_CFLAGS $X11_CFLAGS" TCLTK_LIBS="$TCLTK_LIBS $X11_LIBS" @@ -14514,7 +15848,7 @@ save_LIBS=$LIBS #endif int -main () +main (void) { void *x1 = Tcl_Init; @@ -14525,17 +15859,18 @@ main () } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : have_tcltk=yes as_fn_append TCLTK_CFLAGS " -Wno-strict-prototypes -DWITH_APPINIT=1" -else +else $as_nop have_tcltk=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$save_CFLAGS @@ -14555,19 +15890,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $GDBM_CFLAGS" LDFLAGS="$GDBM_LIBS $LDFLAGS" - for ac_header in gdbm.h + for ac_header in gdbm.h do : - ac_fn_c_check_header_mongrel "$LINENO" "gdbm.h" "ac_cv_header_gdbm_h" "$ac_includes_default" -if test "x$ac_cv_header_gdbm_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GDBM_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gdbm_open in -lgdbm" >&5 -$as_echo_n "checking for gdbm_open in -lgdbm... " >&6; } -if ${ac_cv_lib_gdbm_gdbm_open+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "gdbm.h" "ac_cv_header_gdbm_h" "$ac_includes_default" +if test "x$ac_cv_header_gdbm_h" = xyes +then : + printf "%s\n" "#define HAVE_GDBM_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gdbm_open in -lgdbm" >&5 +printf %s "checking for gdbm_open in -lgdbm... " >&6; } +if test ${ac_cv_lib_gdbm_gdbm_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lgdbm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14576,46 +15911,44 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char gdbm_open (); int -main () +main (void) { return gdbm_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_gdbm_gdbm_open=yes -else +else $as_nop ac_cv_lib_gdbm_gdbm_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_gdbm_open" >&5 -$as_echo "$ac_cv_lib_gdbm_gdbm_open" >&6; } -if test "x$ac_cv_lib_gdbm_gdbm_open" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gdbm_gdbm_open" >&5 +printf "%s\n" "$ac_cv_lib_gdbm_gdbm_open" >&6; } +if test "x$ac_cv_lib_gdbm_gdbm_open" = xyes +then : have_gdbm=yes GDBM_LIBS=${GDBM_LIBS-"-lgdbm"} -else +else $as_nop have_gdbm=no fi -else +else $as_nop have_gdbm=no fi done - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -14623,13 +15956,12 @@ LIBS=$save_LIBS -for ac_header in ndbm.h + for ac_header in ndbm.h do : - ac_fn_c_check_header_mongrel "$LINENO" "ndbm.h" "ac_cv_header_ndbm_h" "$ac_includes_default" -if test "x$ac_cv_header_ndbm_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_NDBM_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "ndbm.h" "ac_cv_header_ndbm_h" "$ac_includes_default" +if test "x$ac_cv_header_ndbm_h" = xyes +then : + printf "%s\n" "#define HAVE_NDBM_H 1" >>confdefs.h save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -14637,11 +15969,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dbm_open" >&5 -$as_echo_n "checking for library containing dbm_open... " >&6; } -if ${ac_cv_search_dbm_open+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dbm_open" >&5 +printf %s "checking for library containing dbm_open... " >&6; } +if test ${ac_cv_search_dbm_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14649,46 +15982,48 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char dbm_open (); int -main () +main (void) { return dbm_open (); ; return 0; } _ACEOF -for ac_lib in '' ndbm gdbm_compat; do +for ac_lib in '' ndbm gdbm_compat +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_dbm_open=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_dbm_open+:} false; then : + if test ${ac_cv_search_dbm_open+y} +then : break fi done -if ${ac_cv_search_dbm_open+:} false; then : +if test ${ac_cv_search_dbm_open+y} +then : -else +else $as_nop ac_cv_search_dbm_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 -$as_echo "$ac_cv_search_dbm_open" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 +printf "%s\n" "$ac_cv_search_dbm_open" >&6; } ac_res=$ac_cv_search_dbm_open -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi @@ -14705,9 +16040,8 @@ fi done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ndbm presence and linker args" >&5 -$as_echo_n "checking for ndbm presence and linker args... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ndbm presence and linker args" >&5 +printf %s "checking for ndbm presence and linker args... " >&6; } case $ac_cv_search_dbm_open in #( *ndbm*|*gdbm_compat*) : @@ -14725,55 +16059,59 @@ case $ac_cv_search_dbm_open in #( *) : ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ndbm ($dbm_ndbm)" >&5 -$as_echo "$have_ndbm ($dbm_ndbm)" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_ndbm ($dbm_ndbm)" >&5 +printf "%s\n" "$have_ndbm ($dbm_ndbm)" >&6; } { ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} -if ${ac_cv_header_gdbm_slash_ndbm_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - - ac_fn_c_check_header_mongrel "$LINENO" "gdbm/ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" -if test "x$ac_cv_header_gdbm_ndbm_h" = xyes; then : +if test ${ac_cv_header_gdbm_slash_ndbm_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ac_fn_c_check_header_compile "$LINENO" "gdbm/ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" +if test "x$ac_cv_header_gdbm_ndbm_h" = xyes +then : ac_cv_header_gdbm_slash_ndbm_h=yes -else +else $as_nop ac_cv_header_gdbm_slash_ndbm_h=no fi - fi -if test "x$ac_cv_header_gdbm_slash_ndbm_h" = xyes; then : +if test "x$ac_cv_header_gdbm_slash_ndbm_h" = xyes +then : -$as_echo "#define HAVE_GDBM_NDBM_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_GDBM_NDBM_H 1" >>confdefs.h fi { ac_cv_header_gdbm_ndbm_h=; unset ac_cv_header_gdbm_ndbm_h;} -if ${ac_cv_header_gdbm_dash_ndbm_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - - ac_fn_c_check_header_mongrel "$LINENO" "gdbm-ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" -if test "x$ac_cv_header_gdbm_ndbm_h" = xyes; then : +if test ${ac_cv_header_gdbm_dash_ndbm_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + ac_fn_c_check_header_compile "$LINENO" "gdbm-ndbm.h" "ac_cv_header_gdbm_ndbm_h" "$ac_includes_default" +if test "x$ac_cv_header_gdbm_ndbm_h" = xyes +then : ac_cv_header_gdbm_dash_ndbm_h=yes -else +else $as_nop ac_cv_header_gdbm_dash_ndbm_h=no fi - fi -if test "x$ac_cv_header_gdbm_dash_ndbm_h" = xyes; then : +if test "x$ac_cv_header_gdbm_dash_ndbm_h" = xyes +then : -$as_echo "#define HAVE_GDBM_DASH_NDBM_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_GDBM_DASH_NDBM_H 1" >>confdefs.h fi @@ -14787,11 +16125,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dbm_open" >&5 -$as_echo_n "checking for library containing dbm_open... " >&6; } -if ${ac_cv_search_dbm_open+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dbm_open" >&5 +printf %s "checking for library containing dbm_open... " >&6; } +if test ${ac_cv_search_dbm_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14799,49 +16138,51 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char dbm_open (); int -main () +main (void) { return dbm_open (); ; return 0; } _ACEOF -for ac_lib in '' gdbm_compat; do +for ac_lib in '' gdbm_compat +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_dbm_open=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_dbm_open+:} false; then : + if test ${ac_cv_search_dbm_open+y} +then : break fi done -if ${ac_cv_search_dbm_open+:} false; then : +if test ${ac_cv_search_dbm_open+y} +then : -else +else $as_nop ac_cv_search_dbm_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 -$as_echo "$ac_cv_search_dbm_open" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dbm_open" >&5 +printf "%s\n" "$ac_cv_search_dbm_open" >&6; } ac_res=$ac_cv_search_dbm_open -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" have_gdbm_compat=yes -else +else $as_nop have_gdbm_compat=no fi @@ -14856,19 +16197,19 @@ fi # Check for libdb >= 5 with dbm_open() # db.h re-defines the name of the function -for ac_header in db.h + for ac_header in db.h do : - ac_fn_c_check_header_mongrel "$LINENO" "db.h" "ac_cv_header_db_h" "$ac_includes_default" -if test "x$ac_cv_header_db_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_DB_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdb" >&5 -$as_echo_n "checking for libdb... " >&6; } -if ${ac_cv_have_libdb+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "db.h" "ac_cv_header_db_h" "$ac_includes_default" +if test "x$ac_cv_header_db_h" = xyes +then : + printf "%s\n" "#define HAVE_DB_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libdb" >&5 +printf %s "checking for libdb... " >&6; } +if test ${ac_cv_have_libdb+y} +then : + printf %s "(cached) " >&6 +else $as_nop save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -14887,7 +16228,7 @@ save_LIBS=$LIBS #endif int -main () +main (void) { DBM *dbm = dbm_open(NULL, 0, 0) ; @@ -14895,12 +16236,13 @@ DBM *dbm = dbm_open(NULL, 0, 0) } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_have_libdb=yes -else +else $as_nop ac_cv_have_libdb=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$save_CFLAGS @@ -14911,12 +16253,13 @@ LIBS=$save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_libdb" >&5 -$as_echo "$ac_cv_have_libdb" >&6; } - if test "x$ac_cv_have_libdb" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_libdb" >&5 +printf "%s\n" "$ac_cv_have_libdb" >&6; } + if test "x$ac_cv_have_libdb" = xyes +then : -$as_echo "#define HAVE_LIBDB 1" >>confdefs.h +printf "%s\n" "#define HAVE_LIBDB 1" >>confdefs.h fi @@ -14925,15 +16268,15 @@ fi done - # Check for --with-dbmliborder -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dbmliborder" >&5 -$as_echo_n "checking for --with-dbmliborder... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-dbmliborder" >&5 +printf %s "checking for --with-dbmliborder... " >&6; } # Check whether --with-dbmliborder was given. -if test "${with_dbmliborder+set}" = set; then : +if test ${with_dbmliborder+y} +then : withval=$with_dbmliborder; -else +else $as_nop with_dbmliborder=gdbm:ndbm:bdb fi @@ -14955,16 +16298,17 @@ for db in $with_dbmliborder; do esac done IFS=$as_save_IFS -if test "x$with_dbmliborder" = xerror; then : +if test "x$with_dbmliborder" = xerror +then : as_fn_error $? "proper usage is --with-dbmliborder=db1:db2:... (gdbm:ndbm:bdb)" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_dbmliborder" >&5 -$as_echo "$with_dbmliborder" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_dbmliborder" >&5 +printf "%s\n" "$with_dbmliborder" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _dbm module CFLAGS and LIBS" >&5 -$as_echo_n "checking for _dbm module CFLAGS and LIBS... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _dbm module CFLAGS and LIBS" >&5 +printf %s "checking for _dbm module CFLAGS and LIBS... " >&6; } have_dbm=no as_save_IFS=$IFS IFS=: @@ -14997,8 +16341,8 @@ for db in $with_dbmliborder; do esac done IFS=$as_save_IFS -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DBM_CFLAGS $DBM_LIBS" >&5 -$as_echo "$DBM_CFLAGS $DBM_LIBS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DBM_CFLAGS $DBM_LIBS" >&5 +printf "%s\n" "$DBM_CFLAGS $DBM_LIBS" >&6; } # Templates for things AC_DEFINEd more than once. # For a single AC_DEFINE, no template is needed. @@ -15007,7 +16351,7 @@ $as_echo "$DBM_CFLAGS $DBM_LIBS" >&6; } if test "$ac_cv_pthread_is_default" = yes then # Defining _REENTRANT on system with POSIX threads should not hurt. - $as_echo "#define _REENTRANT 1" >>confdefs.h + printf "%s\n" "#define _REENTRANT 1" >>confdefs.h posix_threads=yes if test "$ac_sys_system" = "SunOS"; then @@ -15042,8 +16386,8 @@ else # According to the POSIX spec, a pthreads implementation must # define _POSIX_THREADS in unistd.h. Some apparently don't # (e.g. gnu pth with pthread emulation) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _POSIX_THREADS in unistd.h" >&5 -$as_echo_n "checking for _POSIX_THREADS in unistd.h... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _POSIX_THREADS in unistd.h" >&5 +printf %s "checking for _POSIX_THREADS in unistd.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15054,25 +16398,26 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : + $EGREP "yes" >/dev/null 2>&1 +then : unistd_defines_pthreads=yes -else +else $as_nop unistd_defines_pthreads=no fi -rm -f conftest* +rm -rf conftest* - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $unistd_defines_pthreads" >&5 -$as_echo "$unistd_defines_pthreads" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $unistd_defines_pthreads" >&5 +printf "%s\n" "$unistd_defines_pthreads" >&6; } - $as_echo "#define _REENTRANT 1" >>confdefs.h + printf "%s\n" "#define _REENTRANT 1" >>confdefs.h # Just looking for pthread_create in libpthread is not enough: # on HP/UX, pthread.h renames pthread_create to a different symbol name. # So we really have to include pthread.h, and then link. _libs=$LIBS LIBS="$LIBS -lpthread" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -$as_echo_n "checking for pthread_create in -lpthread... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15082,7 +16427,7 @@ $as_echo_n "checking for pthread_create in -lpthread... " >&6; } void * start_routine (void *arg) { exit (0); } int -main () +main (void) { pthread_create (NULL, NULL, start_routine, NULL) @@ -15090,27 +16435,30 @@ pthread_create (NULL, NULL, start_routine, NULL) return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } posix_threads=yes -else +else $as_nop LIBS=$_libs ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" -if test "x$ac_cv_func_pthread_detach" = xyes; then : +if test "x$ac_cv_func_pthread_detach" = xyes +then : posix_threads=yes -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 -$as_echo_n "checking for pthread_create in -lpthreads... " >&6; } -if ${ac_cv_lib_pthreads_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 +printf %s "checking for pthread_create in -lpthreads... " >&6; } +if test ${ac_cv_lib_pthreads_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15119,41 +16467,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pthreads_pthread_create=yes -else +else $as_nop ac_cv_lib_pthreads_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 -$as_echo "$ac_cv_lib_pthreads_pthread_create" >&6; } -if test "x$ac_cv_lib_pthreads_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthreads_pthread_create" >&6; } +if test "x$ac_cv_lib_pthreads_pthread_create" = xyes +then : posix_threads=yes LIBS="$LIBS -lpthreads" -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 -$as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if ${ac_cv_lib_c_r_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 +printf %s "checking for pthread_create in -lc_r... " >&6; } +if test ${ac_cv_lib_c_r_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15162,41 +16510,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_c_r_pthread_create=yes -else +else $as_nop ac_cv_lib_c_r_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 -$as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_c_r_pthread_create" >&6; } +if test "x$ac_cv_lib_c_r_pthread_create" = xyes +then : posix_threads=yes LIBS="$LIBS -lc_r" -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 -$as_echo_n "checking for __pthread_create_system in -lpthread... " >&6; } -if ${ac_cv_lib_pthread___pthread_create_system+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 +printf %s "checking for __pthread_create_system in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread___pthread_create_system+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15205,41 +16553,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char __pthread_create_system (); int -main () +main (void) { return __pthread_create_system (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pthread___pthread_create_system=yes -else +else $as_nop ac_cv_lib_pthread___pthread_create_system=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 -$as_echo "$ac_cv_lib_pthread___pthread_create_system" >&6; } -if test "x$ac_cv_lib_pthread___pthread_create_system" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 +printf "%s\n" "$ac_cv_lib_pthread___pthread_create_system" >&6; } +if test "x$ac_cv_lib_pthread___pthread_create_system" = xyes +then : posix_threads=yes LIBS="$LIBS -lpthread" -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 -$as_echo_n "checking for pthread_create in -lcma... " >&6; } -if ${ac_cv_lib_cma_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 +printf %s "checking for pthread_create in -lcma... " >&6; } +if test ${ac_cv_lib_cma_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lcma $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15248,35 +16596,34 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_create (); int -main () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_cma_pthread_create=yes -else +else $as_nop ac_cv_lib_cma_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 -$as_echo "$ac_cv_lib_cma_pthread_create" >&6; } -if test "x$ac_cv_lib_cma_pthread_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_cma_pthread_create" >&6; } +if test "x$ac_cv_lib_cma_pthread_create" = xyes +then : posix_threads=yes LIBS="$LIBS -lcma" -else +else $as_nop case $ac_sys_system in #( WASI) : @@ -15297,14 +16644,15 @@ fi fi fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usconfig in -lmpc" >&5 -$as_echo_n "checking for usconfig in -lmpc... " >&6; } -if ${ac_cv_lib_mpc_usconfig+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for usconfig in -lmpc" >&5 +printf %s "checking for usconfig in -lmpc... " >&6; } +if test ${ac_cv_lib_mpc_usconfig+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lmpc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15313,30 +16661,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char usconfig (); int -main () +main (void) { return usconfig (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_mpc_usconfig=yes -else +else $as_nop ac_cv_lib_mpc_usconfig=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 -$as_echo "$ac_cv_lib_mpc_usconfig" >&6; } -if test "x$ac_cv_lib_mpc_usconfig" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 +printf "%s\n" "$ac_cv_lib_mpc_usconfig" >&6; } +if test "x$ac_cv_lib_mpc_usconfig" = xyes +then : LIBS="$LIBS -lmpc" @@ -15348,38 +16695,40 @@ fi if test "$posix_threads" = "yes"; then if test "$unistd_defines_pthreads" = "no"; then -$as_echo "#define _POSIX_THREADS 1" >>confdefs.h +printf "%s\n" "#define _POSIX_THREADS 1" >>confdefs.h fi # Bug 662787: Using semaphores causes unexplicable hangs on Solaris 8. case $ac_sys_system/$ac_sys_release in SunOS/5.6) -$as_echo "#define HAVE_PTHREAD_DESTRUCTOR 1" >>confdefs.h +printf "%s\n" "#define HAVE_PTHREAD_DESTRUCTOR 1" >>confdefs.h ;; SunOS/5.8) -$as_echo "#define HAVE_BROKEN_POSIX_SEMAPHORES 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_POSIX_SEMAPHORES 1" >>confdefs.h ;; AIX/*) -$as_echo "#define HAVE_BROKEN_POSIX_SEMAPHORES 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_POSIX_SEMAPHORES 1" >>confdefs.h ;; NetBSD/*) -$as_echo "#define HAVE_BROKEN_POSIX_SEMAPHORES 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_POSIX_SEMAPHORES 1" >>confdefs.h ;; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5 -$as_echo_n "checking if PTHREAD_SCOPE_SYSTEM is supported... " >&6; } -if ${ac_cv_pthread_system_supported+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5 +printf %s "checking if PTHREAD_SCOPE_SYSTEM is supported... " >&6; } +if test ${ac_cv_pthread_system_supported+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_pthread_system_supported=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15397,9 +16746,10 @@ else return (0); } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_pthread_system_supported=yes -else +else $as_nop ac_cv_pthread_system_supported=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -15408,71 +16758,69 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_system_supported" >&5 -$as_echo "$ac_cv_pthread_system_supported" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pthread_system_supported" >&5 +printf "%s\n" "$ac_cv_pthread_system_supported" >&6; } if test "$ac_cv_pthread_system_supported" = "yes"; then -$as_echo "#define PTHREAD_SYSTEM_SCHED_SUPPORTED 1" >>confdefs.h +printf "%s\n" "#define PTHREAD_SYSTEM_SCHED_SUPPORTED 1" >>confdefs.h fi - for ac_func in pthread_sigmask + + for ac_func in pthread_sigmask do : ac_fn_c_check_func "$LINENO" "pthread_sigmask" "ac_cv_func_pthread_sigmask" -if test "x$ac_cv_func_pthread_sigmask" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_PTHREAD_SIGMASK 1 -_ACEOF +if test "x$ac_cv_func_pthread_sigmask" = xyes +then : + printf "%s\n" "#define HAVE_PTHREAD_SIGMASK 1" >>confdefs.h case $ac_sys_system in CYGWIN*) -$as_echo "#define HAVE_BROKEN_PTHREAD_SIGMASK 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_PTHREAD_SIGMASK 1" >>confdefs.h ;; esac fi -done - for ac_func in pthread_getcpuclockid -do : - ac_fn_c_check_func "$LINENO" "pthread_getcpuclockid" "ac_cv_func_pthread_getcpuclockid" -if test "x$ac_cv_func_pthread_getcpuclockid" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_PTHREAD_GETCPUCLOCKID 1 -_ACEOF +done + ac_fn_c_check_func "$LINENO" "pthread_getcpuclockid" "ac_cv_func_pthread_getcpuclockid" +if test "x$ac_cv_func_pthread_getcpuclockid" = xyes +then : + printf "%s\n" "#define HAVE_PTHREAD_GETCPUCLOCKID 1" >>confdefs.h fi -done fi -if test "x$posix_threads" = xstub; then : +if test "x$posix_threads" = xstub +then : -$as_echo "#define HAVE_PTHREAD_STUBS 1" >>confdefs.h +printf "%s\n" "#define HAVE_PTHREAD_STUBS 1" >>confdefs.h fi # Check for enable-ipv6 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if --enable-ipv6 is specified" >&5 -$as_echo_n "checking if --enable-ipv6 is specified... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if --enable-ipv6 is specified" >&5 +printf %s "checking if --enable-ipv6 is specified... " >&6; } # Check whether --enable-ipv6 was given. -if test "${enable_ipv6+set}" = set; then : +if test ${enable_ipv6+y} +then : enableval=$enable_ipv6; case "$enableval" in no) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ipv6=no ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - $as_echo "#define ENABLE_IPV6 1" >>confdefs.h + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + printf "%s\n" "#define ENABLE_IPV6 1" >>confdefs.h ipv6=yes ;; esac -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15480,23 +16828,24 @@ else #include #include int -main () +main (void) { int domain = AF_INET6; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ipv6=yes -else +else $as_nop ipv6=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext case $ac_sys_system in #( WASI) : @@ -15506,19 +16855,19 @@ case $ac_sys_system in #( ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ipv6" >&5 -$as_echo "$ipv6" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ipv6" >&5 +printf "%s\n" "$ipv6" >&6; } if test "$ipv6" = "yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if RFC2553 API is available" >&5 -$as_echo_n "checking if RFC2553 API is available... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if RFC2553 API is available" >&5 +printf %s "checking if RFC2553 API is available... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { struct sockaddr_in6 x; x.sin6_scope_id; @@ -15527,24 +16876,25 @@ struct sockaddr_in6 x; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ipv6=yes -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } ipv6=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$ipv6" = "yes"; then - $as_echo "#define ENABLE_IPV6 1" >>confdefs.h + printf "%s\n" "#define ENABLE_IPV6 1" >>confdefs.h fi @@ -15556,8 +16906,8 @@ ipv6lib=none ipv6trylibc=no if test "$ipv6" = "yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking ipv6 stack type" >&5 -$as_echo_n "checking ipv6 stack type... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ipv6 stack type" >&5 +printf %s "checking ipv6 stack type... " >&6; } for i in inria kame linux-glibc linux-inet6 solaris toshiba v6d zeta; do case $i in @@ -15571,10 +16921,11 @@ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : + $EGREP "yes" >/dev/null 2>&1 +then : ipv6type=$i fi -rm -f conftest* +rm -rf conftest* ;; kame) @@ -15587,13 +16938,14 @@ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : + $EGREP "yes" >/dev/null 2>&1 +then : ipv6type=$i; ipv6lib=inet6 ipv6libdir=/usr/local/v6/lib ipv6trylibc=yes fi -rm -f conftest* +rm -rf conftest* ;; linux-glibc) @@ -15606,11 +16958,12 @@ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : + $EGREP "yes" >/dev/null 2>&1 +then : ipv6type=$i; ipv6trylibc=yes fi -rm -f conftest* +rm -rf conftest* ;; linux-inet6) @@ -15639,12 +16992,13 @@ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : + $EGREP "yes" >/dev/null 2>&1 +then : ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib fi -rm -f conftest* +rm -rf conftest* ;; v6d) @@ -15657,13 +17011,14 @@ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : + $EGREP "yes" >/dev/null 2>&1 +then : ipv6type=$i; ipv6lib=v6; ipv6libdir=/usr/local/v6/lib; BASECFLAGS="-I/usr/local/v6/include $BASECFLAGS" fi -rm -f conftest* +rm -rf conftest* ;; zeta) @@ -15676,12 +17031,13 @@ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : + $EGREP "yes" >/dev/null 2>&1 +then : ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib fi -rm -f conftest* +rm -rf conftest* ;; esac @@ -15689,22 +17045,23 @@ rm -f conftest* break fi done - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ipv6type" >&5 -$as_echo "$ipv6type" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ipv6type" >&5 +printf "%s\n" "$ipv6type" >&6; } fi if test "$ipv6" = "yes" -a "$ipv6lib" != "none"; then if test -d $ipv6libdir -a -f $ipv6libdir/lib$ipv6lib.a; then LIBS="-L$ipv6libdir -l$ipv6lib $LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: using lib$ipv6lib" >&5 -$as_echo "$as_me: using lib$ipv6lib" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using lib$ipv6lib" >&5 +printf "%s\n" "$as_me: using lib$ipv6lib" >&6;} else - if test "x$ipv6trylibc" = xyes; then : + if test "x$ipv6trylibc" = xyes +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: using libc" >&5 -$as_echo "$as_me: using libc" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using libc" >&5 +printf "%s\n" "$as_me: using libc" >&6;} -else +else $as_nop as_fn_error $? "No $ipv6lib library found; cannot continue. You need to fetch lib$ipv6lib.a from appropriate ipv6 kit and compile beforehand." "$LINENO" 5 @@ -15713,84 +17070,91 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking CAN_RAW_FD_FRAMES" >&5 -$as_echo_n "checking CAN_RAW_FD_FRAMES... " >&6; } -if ${ac_cv_can_raw_fd_frames+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CAN_RAW_FD_FRAMES" >&5 +printf %s "checking CAN_RAW_FD_FRAMES... " >&6; } +if test ${ac_cv_can_raw_fd_frames+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* CAN_RAW_FD_FRAMES available check */ #include int -main () +main (void) { int can_raw_fd_frames = CAN_RAW_FD_FRAMES; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_can_raw_fd_frames=yes -else +else $as_nop ac_cv_can_raw_fd_frames=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_fd_frames" >&5 -$as_echo "$ac_cv_can_raw_fd_frames" >&6; } -if test "x$ac_cv_can_raw_fd_frames" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_fd_frames" >&5 +printf "%s\n" "$ac_cv_can_raw_fd_frames" >&6; } +if test "x$ac_cv_can_raw_fd_frames" = xyes +then : -$as_echo "#define HAVE_LINUX_CAN_RAW_FD_FRAMES 1" >>confdefs.h +printf "%s\n" "#define HAVE_LINUX_CAN_RAW_FD_FRAMES 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CAN_RAW_JOIN_FILTERS" >&5 -$as_echo_n "checking for CAN_RAW_JOIN_FILTERS... " >&6; } -if ${ac_cv_can_raw_join_filters+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CAN_RAW_JOIN_FILTERS" >&5 +printf %s "checking for CAN_RAW_JOIN_FILTERS... " >&6; } +if test ${ac_cv_can_raw_join_filters+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int can_raw_join_filters = CAN_RAW_JOIN_FILTERS; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_can_raw_join_filters=yes -else +else $as_nop ac_cv_can_raw_join_filters=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_join_filters" >&5 -$as_echo "$ac_cv_can_raw_join_filters" >&6; } -if test "x$ac_cv_can_raw_join_filters" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_can_raw_join_filters" >&5 +printf "%s\n" "$ac_cv_can_raw_join_filters" >&6; } +if test "x$ac_cv_can_raw_join_filters" = xyes +then : -$as_echo "#define HAVE_LINUX_CAN_RAW_JOIN_FILTERS 1" >>confdefs.h +printf "%s\n" "#define HAVE_LINUX_CAN_RAW_JOIN_FILTERS 1" >>confdefs.h fi # Check for --with-doc-strings -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-doc-strings" >&5 -$as_echo_n "checking for --with-doc-strings... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-doc-strings" >&5 +printf %s "checking for --with-doc-strings... " >&6; } # Check whether --with-doc-strings was given. -if test "${with_doc_strings+set}" = set; then : +if test ${with_doc_strings+y} +then : withval=$with_doc_strings; fi @@ -15801,18 +17165,19 @@ fi if test "$with_doc_strings" != "no" then -$as_echo "#define WITH_DOC_STRINGS 1" >>confdefs.h +printf "%s\n" "#define WITH_DOC_STRINGS 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_doc_strings" >&5 -$as_echo "$with_doc_strings" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_doc_strings" >&5 +printf "%s\n" "$with_doc_strings" >&6; } # Check for Python-specific malloc support -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pymalloc" >&5 -$as_echo_n "checking for --with-pymalloc... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-pymalloc" >&5 +printf %s "checking for --with-pymalloc... " >&6; } # Check whether --with-pymalloc was given. -if test "${with_pymalloc+set}" = set; then : +if test ${with_pymalloc+y} +then : withval=$with_pymalloc; fi @@ -15832,362 +17197,1515 @@ fi if test "$with_pymalloc" != "no" then -$as_echo "#define WITH_PYMALLOC 1" >>confdefs.h +printf "%s\n" "#define WITH_PYMALLOC 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_pymalloc" >&5 -$as_echo "$with_pymalloc" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_pymalloc" >&5 +printf "%s\n" "$with_pymalloc" >&6; } # Check whether objects such as float, tuple and dict are using # freelists to optimization memory allocation. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-freelists" >&5 -$as_echo_n "checking for --with-freelists... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-freelists" >&5 +printf %s "checking for --with-freelists... " >&6; } + +# Check whether --with-freelists was given. +if test ${with_freelists+y} +then : + withval=$with_freelists; +fi + + +if test -z "$with_freelists" +then + with_freelists="yes" +fi +if test "$with_freelists" != "no" +then + +printf "%s\n" "#define WITH_FREELISTS 1" >>confdefs.h + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_freelists" >&5 +printf "%s\n" "$with_freelists" >&6; } + +# Check for --with-c-locale-coercion +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-c-locale-coercion" >&5 +printf %s "checking for --with-c-locale-coercion... " >&6; } + +# Check whether --with-c-locale-coercion was given. +if test ${with_c_locale_coercion+y} +then : + withval=$with_c_locale_coercion; +fi + + +if test -z "$with_c_locale_coercion" +then + with_c_locale_coercion="yes" +fi +if test "$with_c_locale_coercion" != "no" +then + +printf "%s\n" "#define PY_COERCE_C_LOCALE 1" >>confdefs.h + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_c_locale_coercion" >&5 +printf "%s\n" "$with_c_locale_coercion" >&6; } + +# Check for Valgrind support +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-valgrind" >&5 +printf %s "checking for --with-valgrind... " >&6; } + +# Check whether --with-valgrind was given. +if test ${with_valgrind+y} +then : + withval=$with_valgrind; +else $as_nop + with_valgrind=no + +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_valgrind" >&5 +printf "%s\n" "$with_valgrind" >&6; } +if test "$with_valgrind" != no; then + ac_fn_c_check_header_compile "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" +if test "x$ac_cv_header_valgrind_valgrind_h" = xyes +then : + +printf "%s\n" "#define WITH_VALGRIND 1" >>confdefs.h + +else $as_nop + as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 + +fi + + OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" +fi + +# Check for DTrace support +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-dtrace" >&5 +printf %s "checking for --with-dtrace... " >&6; } + +# Check whether --with-dtrace was given. +if test ${with_dtrace+y} +then : + withval=$with_dtrace; +else $as_nop + with_dtrace=no +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5 +printf "%s\n" "$with_dtrace" >&6; } + + + + + +DTRACE= +DTRACE_HEADERS= +DTRACE_OBJS= + +if test "$with_dtrace" = "yes" +then + # Extract the first word of "dtrace", so it can be a program name with args. +set dummy dtrace; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_DTRACE+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $DTRACE in + [\\/]* | ?:[\\/]*) + ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_DTRACE="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_DTRACE" && ac_cv_path_DTRACE="not found" + ;; +esac +fi +DTRACE=$ac_cv_path_DTRACE +if test -n "$DTRACE"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 +printf "%s\n" "$DTRACE" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + if test "$DTRACE" = "not found"; then + as_fn_error $? "dtrace command not found on \$PATH" "$LINENO" 5 + fi + +printf "%s\n" "#define WITH_DTRACE 1" >>confdefs.h + + DTRACE_HEADERS="Include/pydtrace_probes.h" + + # On OS X, DTrace providers do not need to be explicitly compiled and + # linked into the binary. Correspondingly, dtrace(1) is missing the ELF + # generation flag '-G'. We check for presence of this flag, rather than + # hardcoding support by OS, in the interest of robustness. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether DTrace probes require linking" >&5 +printf %s "checking whether DTrace probes require linking... " >&6; } +if test ${ac_cv_dtrace_link+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_dtrace_link=no + echo 'BEGIN{}' > conftest.d + "$DTRACE" $DFLAGS -G -s conftest.d -o conftest.o > /dev/null 2>&1 && \ + ac_cv_dtrace_link=yes + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dtrace_link" >&5 +printf "%s\n" "$ac_cv_dtrace_link" >&6; } + if test "$ac_cv_dtrace_link" = "yes"; then + DTRACE_OBJS="Python/pydtrace.o" + fi +fi + +PLATFORM_HEADERS= +PLATFORM_OBJS= + +case $ac_sys_system in #( + Emscripten) : + + as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o' + as_fn_append PLATFORM_HEADERS ' $(srcdir)/Include/internal/pycore_emscripten_signal.h' + ;; #( + *) : + ;; +esac + + + +# -I${DLINCLDIR} is added to the compile rule for importdl.o + +DLINCLDIR=. + +# the dlopen() function means we might want to use dynload_shlib.o. some +# platforms have dlopen(), but don't want to use it. +ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes +then : + printf "%s\n" "#define HAVE_DLOPEN 1" >>confdefs.h + +fi + + +# DYNLOADFILE specifies which dynload_*.o file we will use for dynamic +# loading of modules. + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking DYNLOADFILE" >&5 +printf %s "checking DYNLOADFILE... " >&6; } +if test -z "$DYNLOADFILE" +then + case $ac_sys_system/$ac_sys_release in + hp*|HP*) DYNLOADFILE="dynload_hpux.o";; + *) + # use dynload_shlib.c and dlopen() if we have it; otherwise stub + # out any dynamic loading + if test "$ac_cv_func_dlopen" = yes + then DYNLOADFILE="dynload_shlib.o" + else DYNLOADFILE="dynload_stub.o" + fi + ;; + esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DYNLOADFILE" >&5 +printf "%s\n" "$DYNLOADFILE" >&6; } +if test "$DYNLOADFILE" != "dynload_stub.o" +then + +printf "%s\n" "#define HAVE_DYNAMIC_LOADING 1" >>confdefs.h + +fi + +# MACHDEP_OBJS can be set to platform-specific object files needed by Python + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP_OBJS" >&5 +printf %s "checking MACHDEP_OBJS... " >&6; } +if test -z "$MACHDEP_OBJS" +then + MACHDEP_OBJS=$extra_machdep_objs +else + MACHDEP_OBJS="$MACHDEP_OBJS $extra_machdep_objs" +fi +if test -z "$MACHDEP_OBJS"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 +printf "%s\n" "none" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MACHDEP_OBJS" >&5 +printf "%s\n" "$MACHDEP_OBJS" >&6; } +fi + +# checks for library functions +ac_fn_c_check_func "$LINENO" "accept4" "ac_cv_func_accept4" +if test "x$ac_cv_func_accept4" = xyes +then : + printf "%s\n" "#define HAVE_ACCEPT4 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "alarm" "ac_cv_func_alarm" +if test "x$ac_cv_func_alarm" = xyes +then : + printf "%s\n" "#define HAVE_ALARM 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "bind_textdomain_codeset" "ac_cv_func_bind_textdomain_codeset" +if test "x$ac_cv_func_bind_textdomain_codeset" = xyes +then : + printf "%s\n" "#define HAVE_BIND_TEXTDOMAIN_CODESET 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "chmod" "ac_cv_func_chmod" +if test "x$ac_cv_func_chmod" = xyes +then : + printf "%s\n" "#define HAVE_CHMOD 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "chown" "ac_cv_func_chown" +if test "x$ac_cv_func_chown" = xyes +then : + printf "%s\n" "#define HAVE_CHOWN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "clock" "ac_cv_func_clock" +if test "x$ac_cv_func_clock" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "close_range" "ac_cv_func_close_range" +if test "x$ac_cv_func_close_range" = xyes +then : + printf "%s\n" "#define HAVE_CLOSE_RANGE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "confstr" "ac_cv_func_confstr" +if test "x$ac_cv_func_confstr" = xyes +then : + printf "%s\n" "#define HAVE_CONFSTR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "copy_file_range" "ac_cv_func_copy_file_range" +if test "x$ac_cv_func_copy_file_range" = xyes +then : + printf "%s\n" "#define HAVE_COPY_FILE_RANGE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ctermid" "ac_cv_func_ctermid" +if test "x$ac_cv_func_ctermid" = xyes +then : + printf "%s\n" "#define HAVE_CTERMID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "dup" "ac_cv_func_dup" +if test "x$ac_cv_func_dup" = xyes +then : + printf "%s\n" "#define HAVE_DUP 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "dup3" "ac_cv_func_dup3" +if test "x$ac_cv_func_dup3" = xyes +then : + printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" +if test "x$ac_cv_func_execv" = xyes +then : + printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" +if test "x$ac_cv_func_explicit_bzero" = xyes +then : + printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "explicit_memset" "ac_cv_func_explicit_memset" +if test "x$ac_cv_func_explicit_memset" = xyes +then : + printf "%s\n" "#define HAVE_EXPLICIT_MEMSET 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "faccessat" "ac_cv_func_faccessat" +if test "x$ac_cv_func_faccessat" = xyes +then : + printf "%s\n" "#define HAVE_FACCESSAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fchmod" "ac_cv_func_fchmod" +if test "x$ac_cv_func_fchmod" = xyes +then : + printf "%s\n" "#define HAVE_FCHMOD 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fchmodat" "ac_cv_func_fchmodat" +if test "x$ac_cv_func_fchmodat" = xyes +then : + printf "%s\n" "#define HAVE_FCHMODAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fchown" "ac_cv_func_fchown" +if test "x$ac_cv_func_fchown" = xyes +then : + printf "%s\n" "#define HAVE_FCHOWN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fchownat" "ac_cv_func_fchownat" +if test "x$ac_cv_func_fchownat" = xyes +then : + printf "%s\n" "#define HAVE_FCHOWNAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fdopendir" "ac_cv_func_fdopendir" +if test "x$ac_cv_func_fdopendir" = xyes +then : + printf "%s\n" "#define HAVE_FDOPENDIR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fdwalk" "ac_cv_func_fdwalk" +if test "x$ac_cv_func_fdwalk" = xyes +then : + printf "%s\n" "#define HAVE_FDWALK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fexecve" "ac_cv_func_fexecve" +if test "x$ac_cv_func_fexecve" = xyes +then : + printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" +if test "x$ac_cv_func_fork" = xyes +then : + printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" +if test "x$ac_cv_func_fork1" = xyes +then : + printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" +if test "x$ac_cv_func_fpathconf" = xyes +then : + printf "%s\n" "#define HAVE_FPATHCONF 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fstatat" "ac_cv_func_fstatat" +if test "x$ac_cv_func_fstatat" = xyes +then : + printf "%s\n" "#define HAVE_FSTATAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ftime" "ac_cv_func_ftime" +if test "x$ac_cv_func_ftime" = xyes +then : + printf "%s\n" "#define HAVE_FTIME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ftruncate" "ac_cv_func_ftruncate" +if test "x$ac_cv_func_ftruncate" = xyes +then : + printf "%s\n" "#define HAVE_FTRUNCATE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "futimens" "ac_cv_func_futimens" +if test "x$ac_cv_func_futimens" = xyes +then : + printf "%s\n" "#define HAVE_FUTIMENS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "futimes" "ac_cv_func_futimes" +if test "x$ac_cv_func_futimes" = xyes +then : + printf "%s\n" "#define HAVE_FUTIMES 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "futimesat" "ac_cv_func_futimesat" +if test "x$ac_cv_func_futimesat" = xyes +then : + printf "%s\n" "#define HAVE_FUTIMESAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gai_strerror" "ac_cv_func_gai_strerror" +if test "x$ac_cv_func_gai_strerror" = xyes +then : + printf "%s\n" "#define HAVE_GAI_STRERROR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getegid" "ac_cv_func_getegid" +if test "x$ac_cv_func_getegid" = xyes +then : + printf "%s\n" "#define HAVE_GETEGID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" +if test "x$ac_cv_func_getentropy" = xyes +then : + printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "geteuid" "ac_cv_func_geteuid" +if test "x$ac_cv_func_geteuid" = xyes +then : + printf "%s\n" "#define HAVE_GETEUID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getgid" "ac_cv_func_getgid" +if test "x$ac_cv_func_getgid" = xyes +then : + printf "%s\n" "#define HAVE_GETGID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getgrgid" "ac_cv_func_getgrgid" +if test "x$ac_cv_func_getgrgid" = xyes +then : + printf "%s\n" "#define HAVE_GETGRGID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getgrgid_r" "ac_cv_func_getgrgid_r" +if test "x$ac_cv_func_getgrgid_r" = xyes +then : + printf "%s\n" "#define HAVE_GETGRGID_R 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getgrnam_r" "ac_cv_func_getgrnam_r" +if test "x$ac_cv_func_getgrnam_r" = xyes +then : + printf "%s\n" "#define HAVE_GETGRNAM_R 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist" +if test "x$ac_cv_func_getgrouplist" = xyes +then : + printf "%s\n" "#define HAVE_GETGROUPLIST 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups" +if test "x$ac_cv_func_getgroups" = xyes +then : + printf "%s\n" "#define HAVE_GETGROUPS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "gethostname" "ac_cv_func_gethostname" +if test "x$ac_cv_func_gethostname" = xyes +then : + printf "%s\n" "#define HAVE_GETHOSTNAME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getitimer" "ac_cv_func_getitimer" +if test "x$ac_cv_func_getitimer" = xyes +then : + printf "%s\n" "#define HAVE_GETITIMER 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getloadavg" "ac_cv_func_getloadavg" +if test "x$ac_cv_func_getloadavg" = xyes +then : + printf "%s\n" "#define HAVE_GETLOADAVG 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getlogin" "ac_cv_func_getlogin" +if test "x$ac_cv_func_getlogin" = xyes +then : + printf "%s\n" "#define HAVE_GETLOGIN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpeername" "ac_cv_func_getpeername" +if test "x$ac_cv_func_getpeername" = xyes +then : + printf "%s\n" "#define HAVE_GETPEERNAME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpgid" "ac_cv_func_getpgid" +if test "x$ac_cv_func_getpgid" = xyes +then : + printf "%s\n" "#define HAVE_GETPGID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpid" "ac_cv_func_getpid" +if test "x$ac_cv_func_getpid" = xyes +then : + printf "%s\n" "#define HAVE_GETPID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getppid" "ac_cv_func_getppid" +if test "x$ac_cv_func_getppid" = xyes +then : + printf "%s\n" "#define HAVE_GETPPID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpriority" "ac_cv_func_getpriority" +if test "x$ac_cv_func_getpriority" = xyes +then : + printf "%s\n" "#define HAVE_GETPRIORITY 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "_getpty" "ac_cv_func__getpty" +if test "x$ac_cv_func__getpty" = xyes +then : + printf "%s\n" "#define HAVE__GETPTY 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpwent" "ac_cv_func_getpwent" +if test "x$ac_cv_func_getpwent" = xyes +then : + printf "%s\n" "#define HAVE_GETPWENT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpwnam_r" "ac_cv_func_getpwnam_r" +if test "x$ac_cv_func_getpwnam_r" = xyes +then : + printf "%s\n" "#define HAVE_GETPWNAM_R 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpwuid" "ac_cv_func_getpwuid" +if test "x$ac_cv_func_getpwuid" = xyes +then : + printf "%s\n" "#define HAVE_GETPWUID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getpwuid_r" "ac_cv_func_getpwuid_r" +if test "x$ac_cv_func_getpwuid_r" = xyes +then : + printf "%s\n" "#define HAVE_GETPWUID_R 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getresgid" "ac_cv_func_getresgid" +if test "x$ac_cv_func_getresgid" = xyes +then : + printf "%s\n" "#define HAVE_GETRESGID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getresuid" "ac_cv_func_getresuid" +if test "x$ac_cv_func_getresuid" = xyes +then : + printf "%s\n" "#define HAVE_GETRESUID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getrusage" "ac_cv_func_getrusage" +if test "x$ac_cv_func_getrusage" = xyes +then : + printf "%s\n" "#define HAVE_GETRUSAGE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getsid" "ac_cv_func_getsid" +if test "x$ac_cv_func_getsid" = xyes +then : + printf "%s\n" "#define HAVE_GETSID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getspent" "ac_cv_func_getspent" +if test "x$ac_cv_func_getspent" = xyes +then : + printf "%s\n" "#define HAVE_GETSPENT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getspnam" "ac_cv_func_getspnam" +if test "x$ac_cv_func_getspnam" = xyes +then : + printf "%s\n" "#define HAVE_GETSPNAM 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getuid" "ac_cv_func_getuid" +if test "x$ac_cv_func_getuid" = xyes +then : + printf "%s\n" "#define HAVE_GETUID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getwd" "ac_cv_func_getwd" +if test "x$ac_cv_func_getwd" = xyes +then : + printf "%s\n" "#define HAVE_GETWD 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "if_nameindex" "ac_cv_func_if_nameindex" +if test "x$ac_cv_func_if_nameindex" = xyes +then : + printf "%s\n" "#define HAVE_IF_NAMEINDEX 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups" +if test "x$ac_cv_func_initgroups" = xyes +then : + printf "%s\n" "#define HAVE_INITGROUPS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "kill" "ac_cv_func_kill" +if test "x$ac_cv_func_kill" = xyes +then : + printf "%s\n" "#define HAVE_KILL 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "killpg" "ac_cv_func_killpg" +if test "x$ac_cv_func_killpg" = xyes +then : + printf "%s\n" "#define HAVE_KILLPG 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "lchown" "ac_cv_func_lchown" +if test "x$ac_cv_func_lchown" = xyes +then : + printf "%s\n" "#define HAVE_LCHOWN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "linkat" "ac_cv_func_linkat" +if test "x$ac_cv_func_linkat" = xyes +then : + printf "%s\n" "#define HAVE_LINKAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "lockf" "ac_cv_func_lockf" +if test "x$ac_cv_func_lockf" = xyes +then : + printf "%s\n" "#define HAVE_LOCKF 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "lstat" "ac_cv_func_lstat" +if test "x$ac_cv_func_lstat" = xyes +then : + printf "%s\n" "#define HAVE_LSTAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "lutimes" "ac_cv_func_lutimes" +if test "x$ac_cv_func_lutimes" = xyes +then : + printf "%s\n" "#define HAVE_LUTIMES 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "madvise" "ac_cv_func_madvise" +if test "x$ac_cv_func_madvise" = xyes +then : + printf "%s\n" "#define HAVE_MADVISE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mbrtowc" "ac_cv_func_mbrtowc" +if test "x$ac_cv_func_mbrtowc" = xyes +then : + printf "%s\n" "#define HAVE_MBRTOWC 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "memrchr" "ac_cv_func_memrchr" +if test "x$ac_cv_func_memrchr" = xyes +then : + printf "%s\n" "#define HAVE_MEMRCHR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mkdirat" "ac_cv_func_mkdirat" +if test "x$ac_cv_func_mkdirat" = xyes +then : + printf "%s\n" "#define HAVE_MKDIRAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mkfifo" "ac_cv_func_mkfifo" +if test "x$ac_cv_func_mkfifo" = xyes +then : + printf "%s\n" "#define HAVE_MKFIFO 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mkfifoat" "ac_cv_func_mkfifoat" +if test "x$ac_cv_func_mkfifoat" = xyes +then : + printf "%s\n" "#define HAVE_MKFIFOAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mknod" "ac_cv_func_mknod" +if test "x$ac_cv_func_mknod" = xyes +then : + printf "%s\n" "#define HAVE_MKNOD 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mknodat" "ac_cv_func_mknodat" +if test "x$ac_cv_func_mknodat" = xyes +then : + printf "%s\n" "#define HAVE_MKNODAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mktime" "ac_cv_func_mktime" +if test "x$ac_cv_func_mktime" = xyes +then : + printf "%s\n" "#define HAVE_MKTIME 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" +if test "x$ac_cv_func_mmap" = xyes +then : + printf "%s\n" "#define HAVE_MMAP 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "mremap" "ac_cv_func_mremap" +if test "x$ac_cv_func_mremap" = xyes +then : + printf "%s\n" "#define HAVE_MREMAP 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "nice" "ac_cv_func_nice" +if test "x$ac_cv_func_nice" = xyes +then : + printf "%s\n" "#define HAVE_NICE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "openat" "ac_cv_func_openat" +if test "x$ac_cv_func_openat" = xyes +then : + printf "%s\n" "#define HAVE_OPENAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "opendir" "ac_cv_func_opendir" +if test "x$ac_cv_func_opendir" = xyes +then : + printf "%s\n" "#define HAVE_OPENDIR 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pathconf" "ac_cv_func_pathconf" +if test "x$ac_cv_func_pathconf" = xyes +then : + printf "%s\n" "#define HAVE_PATHCONF 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pause" "ac_cv_func_pause" +if test "x$ac_cv_func_pause" = xyes +then : + printf "%s\n" "#define HAVE_PAUSE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pipe" "ac_cv_func_pipe" +if test "x$ac_cv_func_pipe" = xyes +then : + printf "%s\n" "#define HAVE_PIPE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" +if test "x$ac_cv_func_pipe2" = xyes +then : + printf "%s\n" "#define HAVE_PIPE2 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "plock" "ac_cv_func_plock" +if test "x$ac_cv_func_plock" = xyes +then : + printf "%s\n" "#define HAVE_PLOCK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll" +if test "x$ac_cv_func_poll" = xyes +then : + printf "%s\n" "#define HAVE_POLL 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" +if test "x$ac_cv_func_posix_fadvise" = xyes +then : + printf "%s\n" "#define HAVE_POSIX_FADVISE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "posix_fallocate" "ac_cv_func_posix_fallocate" +if test "x$ac_cv_func_posix_fallocate" = xyes +then : + printf "%s\n" "#define HAVE_POSIX_FALLOCATE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" +if test "x$ac_cv_func_posix_spawn" = xyes +then : + printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" +if test "x$ac_cv_func_posix_spawnp" = xyes +then : + printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" +if test "x$ac_cv_func_pread" = xyes +then : + printf "%s\n" "#define HAVE_PREAD 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "preadv" "ac_cv_func_preadv" +if test "x$ac_cv_func_preadv" = xyes +then : + printf "%s\n" "#define HAVE_PREADV 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "preadv2" "ac_cv_func_preadv2" +if test "x$ac_cv_func_preadv2" = xyes +then : + printf "%s\n" "#define HAVE_PREADV2 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pthread_condattr_setclock" "ac_cv_func_pthread_condattr_setclock" +if test "x$ac_cv_func_pthread_condattr_setclock" = xyes +then : + printf "%s\n" "#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pthread_init" "ac_cv_func_pthread_init" +if test "x$ac_cv_func_pthread_init" = xyes +then : + printf "%s\n" "#define HAVE_PTHREAD_INIT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pthread_kill" "ac_cv_func_pthread_kill" +if test "x$ac_cv_func_pthread_kill" = xyes +then : + printf "%s\n" "#define HAVE_PTHREAD_KILL 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite" +if test "x$ac_cv_func_pwrite" = xyes +then : + printf "%s\n" "#define HAVE_PWRITE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pwritev" "ac_cv_func_pwritev" +if test "x$ac_cv_func_pwritev" = xyes +then : + printf "%s\n" "#define HAVE_PWRITEV 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "pwritev2" "ac_cv_func_pwritev2" +if test "x$ac_cv_func_pwritev2" = xyes +then : + printf "%s\n" "#define HAVE_PWRITEV2 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "readlink" "ac_cv_func_readlink" +if test "x$ac_cv_func_readlink" = xyes +then : + printf "%s\n" "#define HAVE_READLINK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "readlinkat" "ac_cv_func_readlinkat" +if test "x$ac_cv_func_readlinkat" = xyes +then : + printf "%s\n" "#define HAVE_READLINKAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "readv" "ac_cv_func_readv" +if test "x$ac_cv_func_readv" = xyes +then : + printf "%s\n" "#define HAVE_READV 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath" +if test "x$ac_cv_func_realpath" = xyes +then : + printf "%s\n" "#define HAVE_REALPATH 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "renameat" "ac_cv_func_renameat" +if test "x$ac_cv_func_renameat" = xyes +then : + printf "%s\n" "#define HAVE_RENAMEAT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "rtpSpawn" "ac_cv_func_rtpSpawn" +if test "x$ac_cv_func_rtpSpawn" = xyes +then : + printf "%s\n" "#define HAVE_RTPSPAWN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sched_get_priority_max" "ac_cv_func_sched_get_priority_max" +if test "x$ac_cv_func_sched_get_priority_max" = xyes +then : + printf "%s\n" "#define HAVE_SCHED_GET_PRIORITY_MAX 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sched_rr_get_interval" "ac_cv_func_sched_rr_get_interval" +if test "x$ac_cv_func_sched_rr_get_interval" = xyes +then : + printf "%s\n" "#define HAVE_SCHED_RR_GET_INTERVAL 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sched_setaffinity" "ac_cv_func_sched_setaffinity" +if test "x$ac_cv_func_sched_setaffinity" = xyes +then : + printf "%s\n" "#define HAVE_SCHED_SETAFFINITY 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sched_setparam" "ac_cv_func_sched_setparam" +if test "x$ac_cv_func_sched_setparam" = xyes +then : + printf "%s\n" "#define HAVE_SCHED_SETPARAM 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sched_setscheduler" "ac_cv_func_sched_setscheduler" +if test "x$ac_cv_func_sched_setscheduler" = xyes +then : + printf "%s\n" "#define HAVE_SCHED_SETSCHEDULER 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sem_clockwait" "ac_cv_func_sem_clockwait" +if test "x$ac_cv_func_sem_clockwait" = xyes +then : + printf "%s\n" "#define HAVE_SEM_CLOCKWAIT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sem_getvalue" "ac_cv_func_sem_getvalue" +if test "x$ac_cv_func_sem_getvalue" = xyes +then : + printf "%s\n" "#define HAVE_SEM_GETVALUE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sem_open" "ac_cv_func_sem_open" +if test "x$ac_cv_func_sem_open" = xyes +then : + printf "%s\n" "#define HAVE_SEM_OPEN 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sem_timedwait" "ac_cv_func_sem_timedwait" +if test "x$ac_cv_func_sem_timedwait" = xyes +then : + printf "%s\n" "#define HAVE_SEM_TIMEDWAIT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sem_unlink" "ac_cv_func_sem_unlink" +if test "x$ac_cv_func_sem_unlink" = xyes +then : + printf "%s\n" "#define HAVE_SEM_UNLINK 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "sendfile" "ac_cv_func_sendfile" +if test "x$ac_cv_func_sendfile" = xyes +then : + printf "%s\n" "#define HAVE_SENDFILE 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "setegid" "ac_cv_func_setegid" +if test "x$ac_cv_func_setegid" = xyes +then : + printf "%s\n" "#define HAVE_SETEGID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "seteuid" "ac_cv_func_seteuid" +if test "x$ac_cv_func_seteuid" = xyes +then : + printf "%s\n" "#define HAVE_SETEUID 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "setgid" "ac_cv_func_setgid" +if test "x$ac_cv_func_setgid" = xyes +then : + printf "%s\n" "#define HAVE_SETGID 1" >>confdefs.h -# Check whether --with-freelists was given. -if test "${with_freelists+set}" = set; then : - withval=$with_freelists; fi +ac_fn_c_check_func "$LINENO" "sethostname" "ac_cv_func_sethostname" +if test "x$ac_cv_func_sethostname" = xyes +then : + printf "%s\n" "#define HAVE_SETHOSTNAME 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "setitimer" "ac_cv_func_setitimer" +if test "x$ac_cv_func_setitimer" = xyes +then : + printf "%s\n" "#define HAVE_SETITIMER 1" >>confdefs.h -if test -z "$with_freelists" -then - with_freelists="yes" fi -if test "$with_freelists" != "no" -then +ac_fn_c_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale" +if test "x$ac_cv_func_setlocale" = xyes +then : + printf "%s\n" "#define HAVE_SETLOCALE 1" >>confdefs.h -$as_echo "#define WITH_FREELISTS 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "setpgid" "ac_cv_func_setpgid" +if test "x$ac_cv_func_setpgid" = xyes +then : + printf "%s\n" "#define HAVE_SETPGID 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_freelists" >&5 -$as_echo "$with_freelists" >&6; } +ac_fn_c_check_func "$LINENO" "setpgrp" "ac_cv_func_setpgrp" +if test "x$ac_cv_func_setpgrp" = xyes +then : + printf "%s\n" "#define HAVE_SETPGRP 1" >>confdefs.h -# Check for --with-c-locale-coercion -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-c-locale-coercion" >&5 -$as_echo_n "checking for --with-c-locale-coercion... " >&6; } +fi +ac_fn_c_check_func "$LINENO" "setpriority" "ac_cv_func_setpriority" +if test "x$ac_cv_func_setpriority" = xyes +then : + printf "%s\n" "#define HAVE_SETPRIORITY 1" >>confdefs.h -# Check whether --with-c-locale-coercion was given. -if test "${with_c_locale_coercion+set}" = set; then : - withval=$with_c_locale_coercion; fi +ac_fn_c_check_func "$LINENO" "setregid" "ac_cv_func_setregid" +if test "x$ac_cv_func_setregid" = xyes +then : + printf "%s\n" "#define HAVE_SETREGID 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "setresgid" "ac_cv_func_setresgid" +if test "x$ac_cv_func_setresgid" = xyes +then : + printf "%s\n" "#define HAVE_SETRESGID 1" >>confdefs.h -if test -z "$with_c_locale_coercion" -then - with_c_locale_coercion="yes" fi -if test "$with_c_locale_coercion" != "no" -then +ac_fn_c_check_func "$LINENO" "setresuid" "ac_cv_func_setresuid" +if test "x$ac_cv_func_setresuid" = xyes +then : + printf "%s\n" "#define HAVE_SETRESUID 1" >>confdefs.h -$as_echo "#define PY_COERCE_C_LOCALE 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "setreuid" "ac_cv_func_setreuid" +if test "x$ac_cv_func_setreuid" = xyes +then : + printf "%s\n" "#define HAVE_SETREUID 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_c_locale_coercion" >&5 -$as_echo "$with_c_locale_coercion" >&6; } +ac_fn_c_check_func "$LINENO" "setsid" "ac_cv_func_setsid" +if test "x$ac_cv_func_setsid" = xyes +then : + printf "%s\n" "#define HAVE_SETSID 1" >>confdefs.h -# Check for Valgrind support -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-valgrind" >&5 -$as_echo_n "checking for --with-valgrind... " >&6; } +fi +ac_fn_c_check_func "$LINENO" "setuid" "ac_cv_func_setuid" +if test "x$ac_cv_func_setuid" = xyes +then : + printf "%s\n" "#define HAVE_SETUID 1" >>confdefs.h -# Check whether --with-valgrind was given. -if test "${with_valgrind+set}" = set; then : - withval=$with_valgrind; -else - with_valgrind=no +fi +ac_fn_c_check_func "$LINENO" "setvbuf" "ac_cv_func_setvbuf" +if test "x$ac_cv_func_setvbuf" = xyes +then : + printf "%s\n" "#define HAVE_SETVBUF 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "shutdown" "ac_cv_func_shutdown" +if test "x$ac_cv_func_shutdown" = xyes +then : + printf "%s\n" "#define HAVE_SHUTDOWN 1" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_valgrind" >&5 -$as_echo "$with_valgrind" >&6; } -if test "$with_valgrind" != no; then - ac_fn_c_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : +fi +ac_fn_c_check_func "$LINENO" "sigaction" "ac_cv_func_sigaction" +if test "x$ac_cv_func_sigaction" = xyes +then : + printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h -$as_echo "#define WITH_VALGRIND 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" +if test "x$ac_cv_func_sigaltstack" = xyes +then : + printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h -else - as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 +fi +ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" +if test "x$ac_cv_func_sigfillset" = xyes +then : + printf "%s\n" "#define HAVE_SIGFILLSET 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "siginterrupt" "ac_cv_func_siginterrupt" +if test "x$ac_cv_func_siginterrupt" = xyes +then : + printf "%s\n" "#define HAVE_SIGINTERRUPT 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "sigpending" "ac_cv_func_sigpending" +if test "x$ac_cv_func_sigpending" = xyes +then : + printf "%s\n" "#define HAVE_SIGPENDING 1" >>confdefs.h - OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" fi +ac_fn_c_check_func "$LINENO" "sigrelse" "ac_cv_func_sigrelse" +if test "x$ac_cv_func_sigrelse" = xyes +then : + printf "%s\n" "#define HAVE_SIGRELSE 1" >>confdefs.h -# Check for DTrace support -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dtrace" >&5 -$as_echo_n "checking for --with-dtrace... " >&6; } +fi +ac_fn_c_check_func "$LINENO" "sigtimedwait" "ac_cv_func_sigtimedwait" +if test "x$ac_cv_func_sigtimedwait" = xyes +then : + printf "%s\n" "#define HAVE_SIGTIMEDWAIT 1" >>confdefs.h -# Check whether --with-dtrace was given. -if test "${with_dtrace+set}" = set; then : - withval=$with_dtrace; -else - with_dtrace=no fi +ac_fn_c_check_func "$LINENO" "sigwait" "ac_cv_func_sigwait" +if test "x$ac_cv_func_sigwait" = xyes +then : + printf "%s\n" "#define HAVE_SIGWAIT 1" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5 -$as_echo "$with_dtrace" >&6; } +fi +ac_fn_c_check_func "$LINENO" "sigwaitinfo" "ac_cv_func_sigwaitinfo" +if test "x$ac_cv_func_sigwaitinfo" = xyes +then : + printf "%s\n" "#define HAVE_SIGWAITINFO 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" +if test "x$ac_cv_func_snprintf" = xyes +then : + printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "splice" "ac_cv_func_splice" +if test "x$ac_cv_func_splice" = xyes +then : + printf "%s\n" "#define HAVE_SPLICE 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" +if test "x$ac_cv_func_strftime" = xyes +then : + printf "%s\n" "#define HAVE_STRFTIME 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" +if test "x$ac_cv_func_strlcpy" = xyes +then : + printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h -DTRACE= -DTRACE_HEADERS= -DTRACE_OBJS= +fi +ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal" +if test "x$ac_cv_func_strsignal" = xyes +then : + printf "%s\n" "#define HAVE_STRSIGNAL 1" >>confdefs.h -if test "$with_dtrace" = "yes" -then - # Extract the first word of "dtrace", so it can be a program name with args. -set dummy dtrace; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_DTRACE+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $DTRACE in - [\\/]* | ?:[\\/]*) - ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_DTRACE="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS +fi +ac_fn_c_check_func "$LINENO" "symlinkat" "ac_cv_func_symlinkat" +if test "x$ac_cv_func_symlinkat" = xyes +then : + printf "%s\n" "#define HAVE_SYMLINKAT 1" >>confdefs.h - test -z "$ac_cv_path_DTRACE" && ac_cv_path_DTRACE="not found" - ;; -esac fi -DTRACE=$ac_cv_path_DTRACE -if test -n "$DTRACE"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DTRACE" >&5 -$as_echo "$DTRACE" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +ac_fn_c_check_func "$LINENO" "sync" "ac_cv_func_sync" +if test "x$ac_cv_func_sync" = xyes +then : + printf "%s\n" "#define HAVE_SYNC 1" >>confdefs.h + fi +ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" +if test "x$ac_cv_func_sysconf" = xyes +then : + printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "system" "ac_cv_func_system" +if test "x$ac_cv_func_system" = xyes +then : + printf "%s\n" "#define HAVE_SYSTEM 1" >>confdefs.h - if test "$DTRACE" = "not found"; then - as_fn_error $? "dtrace command not found on \$PATH" "$LINENO" 5 - fi +fi +ac_fn_c_check_func "$LINENO" "tcgetpgrp" "ac_cv_func_tcgetpgrp" +if test "x$ac_cv_func_tcgetpgrp" = xyes +then : + printf "%s\n" "#define HAVE_TCGETPGRP 1" >>confdefs.h -$as_echo "#define WITH_DTRACE 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "tcsetpgrp" "ac_cv_func_tcsetpgrp" +if test "x$ac_cv_func_tcsetpgrp" = xyes +then : + printf "%s\n" "#define HAVE_TCSETPGRP 1" >>confdefs.h - DTRACE_HEADERS="Include/pydtrace_probes.h" +fi +ac_fn_c_check_func "$LINENO" "tempnam" "ac_cv_func_tempnam" +if test "x$ac_cv_func_tempnam" = xyes +then : + printf "%s\n" "#define HAVE_TEMPNAM 1" >>confdefs.h - # On OS X, DTrace providers do not need to be explicitly compiled and - # linked into the binary. Correspondingly, dtrace(1) is missing the ELF - # generation flag '-G'. We check for presence of this flag, rather than - # hardcoding support by OS, in the interest of robustness. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether DTrace probes require linking" >&5 -$as_echo_n "checking whether DTrace probes require linking... " >&6; } -if ${ac_cv_dtrace_link+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_dtrace_link=no - echo 'BEGIN{}' > conftest.d - "$DTRACE" $DFLAGS -G -s conftest.d -o conftest.o > /dev/null 2>&1 && \ - ac_cv_dtrace_link=yes +fi +ac_fn_c_check_func "$LINENO" "timegm" "ac_cv_func_timegm" +if test "x$ac_cv_func_timegm" = xyes +then : + printf "%s\n" "#define HAVE_TIMEGM 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dtrace_link" >&5 -$as_echo "$ac_cv_dtrace_link" >&6; } - if test "$ac_cv_dtrace_link" = "yes"; then - DTRACE_OBJS="Python/pydtrace.o" - fi +ac_fn_c_check_func "$LINENO" "times" "ac_cv_func_times" +if test "x$ac_cv_func_times" = xyes +then : + printf "%s\n" "#define HAVE_TIMES 1" >>confdefs.h + fi +ac_fn_c_check_func "$LINENO" "tmpfile" "ac_cv_func_tmpfile" +if test "x$ac_cv_func_tmpfile" = xyes +then : + printf "%s\n" "#define HAVE_TMPFILE 1" >>confdefs.h -PLATFORM_HEADERS= -PLATFORM_OBJS= +fi +ac_fn_c_check_func "$LINENO" "tmpnam" "ac_cv_func_tmpnam" +if test "x$ac_cv_func_tmpnam" = xyes +then : + printf "%s\n" "#define HAVE_TMPNAM 1" >>confdefs.h -case $ac_sys_system in #( - Emscripten) : +fi +ac_fn_c_check_func "$LINENO" "tmpnam_r" "ac_cv_func_tmpnam_r" +if test "x$ac_cv_func_tmpnam_r" = xyes +then : + printf "%s\n" "#define HAVE_TMPNAM_R 1" >>confdefs.h - as_fn_append PLATFORM_OBJS ' Python/emscripten_signal.o' - as_fn_append PLATFORM_HEADERS ' $(srcdir)/Include/internal/pycore_emscripten_signal.h' - ;; #( - *) : - ;; -esac +fi +ac_fn_c_check_func "$LINENO" "truncate" "ac_cv_func_truncate" +if test "x$ac_cv_func_truncate" = xyes +then : + printf "%s\n" "#define HAVE_TRUNCATE 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "ttyname" "ac_cv_func_ttyname" +if test "x$ac_cv_func_ttyname" = xyes +then : + printf "%s\n" "#define HAVE_TTYNAME 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "umask" "ac_cv_func_umask" +if test "x$ac_cv_func_umask" = xyes +then : + printf "%s\n" "#define HAVE_UMASK 1" >>confdefs.h -# -I${DLINCLDIR} is added to the compile rule for importdl.o +fi +ac_fn_c_check_func "$LINENO" "uname" "ac_cv_func_uname" +if test "x$ac_cv_func_uname" = xyes +then : + printf "%s\n" "#define HAVE_UNAME 1" >>confdefs.h -DLINCLDIR=. +fi +ac_fn_c_check_func "$LINENO" "unlinkat" "ac_cv_func_unlinkat" +if test "x$ac_cv_func_unlinkat" = xyes +then : + printf "%s\n" "#define HAVE_UNLINKAT 1" >>confdefs.h -# the dlopen() function means we might want to use dynload_shlib.o. some -# platforms have dlopen(), but don't want to use it. -for ac_func in dlopen -do : - ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_DLOPEN 1 -_ACEOF +fi +ac_fn_c_check_func "$LINENO" "utimensat" "ac_cv_func_utimensat" +if test "x$ac_cv_func_utimensat" = xyes +then : + printf "%s\n" "#define HAVE_UTIMENSAT 1" >>confdefs.h fi -done +ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes" +if test "x$ac_cv_func_utimes" = xyes +then : + printf "%s\n" "#define HAVE_UTIMES 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "vfork" "ac_cv_func_vfork" +if test "x$ac_cv_func_vfork" = xyes +then : + printf "%s\n" "#define HAVE_VFORK 1" >>confdefs.h -# DYNLOADFILE specifies which dynload_*.o file we will use for dynamic -# loading of modules. +fi +ac_fn_c_check_func "$LINENO" "wait" "ac_cv_func_wait" +if test "x$ac_cv_func_wait" = xyes +then : + printf "%s\n" "#define HAVE_WAIT 1" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking DYNLOADFILE" >&5 -$as_echo_n "checking DYNLOADFILE... " >&6; } -if test -z "$DYNLOADFILE" -then - case $ac_sys_system/$ac_sys_release in - hp*|HP*) DYNLOADFILE="dynload_hpux.o";; - *) - # use dynload_shlib.c and dlopen() if we have it; otherwise stub - # out any dynamic loading - if test "$ac_cv_func_dlopen" = yes - then DYNLOADFILE="dynload_shlib.o" - else DYNLOADFILE="dynload_stub.o" - fi - ;; - esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DYNLOADFILE" >&5 -$as_echo "$DYNLOADFILE" >&6; } -if test "$DYNLOADFILE" != "dynload_stub.o" -then +ac_fn_c_check_func "$LINENO" "wait3" "ac_cv_func_wait3" +if test "x$ac_cv_func_wait3" = xyes +then : + printf "%s\n" "#define HAVE_WAIT3 1" >>confdefs.h -$as_echo "#define HAVE_DYNAMIC_LOADING 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "wait4" "ac_cv_func_wait4" +if test "x$ac_cv_func_wait4" = xyes +then : + printf "%s\n" "#define HAVE_WAIT4 1" >>confdefs.h fi +ac_fn_c_check_func "$LINENO" "waitid" "ac_cv_func_waitid" +if test "x$ac_cv_func_waitid" = xyes +then : + printf "%s\n" "#define HAVE_WAITID 1" >>confdefs.h -# MACHDEP_OBJS can be set to platform-specific object files needed by Python +fi +ac_fn_c_check_func "$LINENO" "waitpid" "ac_cv_func_waitpid" +if test "x$ac_cv_func_waitpid" = xyes +then : + printf "%s\n" "#define HAVE_WAITPID 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "wcscoll" "ac_cv_func_wcscoll" +if test "x$ac_cv_func_wcscoll" = xyes +then : + printf "%s\n" "#define HAVE_WCSCOLL 1" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking MACHDEP_OBJS" >&5 -$as_echo_n "checking MACHDEP_OBJS... " >&6; } -if test -z "$MACHDEP_OBJS" -then - MACHDEP_OBJS=$extra_machdep_objs -else - MACHDEP_OBJS="$MACHDEP_OBJS $extra_machdep_objs" fi -if test -z "$MACHDEP_OBJS"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 -$as_echo "none" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MACHDEP_OBJS" >&5 -$as_echo "$MACHDEP_OBJS" >&6; } +ac_fn_c_check_func "$LINENO" "wcsftime" "ac_cv_func_wcsftime" +if test "x$ac_cv_func_wcsftime" = xyes +then : + printf "%s\n" "#define HAVE_WCSFTIME 1" >>confdefs.h + fi +ac_fn_c_check_func "$LINENO" "wcsxfrm" "ac_cv_func_wcsxfrm" +if test "x$ac_cv_func_wcsxfrm" = xyes +then : + printf "%s\n" "#define HAVE_WCSXFRM 1" >>confdefs.h -# checks for library functions -for ac_func in \ - accept4 alarm bind_textdomain_codeset chmod chown clock close_range confstr \ - copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \ - faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ - fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ - gai_strerror getegid getentropy geteuid getgid getgrgid getgrgid_r \ - getgrnam_r getgrouplist getgroups gethostname getitimer getloadavg getlogin \ - getpeername getpgid getpid getppid getpriority _getpty \ - getpwent getpwnam_r getpwuid getpwuid_r getresgid getresuid getrusage getsid getspent \ - getspnam getuid getwd if_nameindex initgroups kill killpg lchown linkat \ - lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ - mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ - pipe2 plock poll posix_fadvise posix_fallocate posix_spawn posix_spawnp \ - pread preadv preadv2 pthread_condattr_setclock pthread_init pthread_kill \ - pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \ - rtpSpawn sched_get_priority_max sched_rr_get_interval sched_setaffinity \ - sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ - sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ - setitimer setlocale setpgid setpgrp setpriority setregid setresgid \ - setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \ - sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ - sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ - sysconf system tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ - tmpnam tmpnam_r truncate ttyname umask uname unlinkat utimensat utimes vfork \ - wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \ +fi +ac_fn_c_check_func "$LINENO" "wmemcmp" "ac_cv_func_wmemcmp" +if test "x$ac_cv_func_wmemcmp" = xyes +then : + printf "%s\n" "#define HAVE_WMEMCMP 1" >>confdefs.h -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi +ac_fn_c_check_func "$LINENO" "writev" "ac_cv_func_writev" +if test "x$ac_cv_func_writev" = xyes +then : + printf "%s\n" "#define HAVE_WRITEV 1" >>confdefs.h fi -done # Force lchmod off for Linux. Linux disallows changing the mode of symbolic # links. Some libc implementations have a stub lchmod implementation that always # returns an error. if test "$MACHDEP" != linux; then - for ac_func in lchmod -do : ac_fn_c_check_func "$LINENO" "lchmod" "ac_cv_func_lchmod" -if test "x$ac_cv_func_lchmod" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LCHMOD 1 -_ACEOF +if test "x$ac_cv_func_lchmod" = xyes +then : + printf "%s\n" "#define HAVE_LCHMOD 1" >>confdefs.h fi -done fi -ac_fn_c_check_decl "$LINENO" "dirfd" "ac_cv_have_decl_dirfd" "#include - #include -" -if test "x$ac_cv_have_decl_dirfd" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 +printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } +if test ${ac_cv_c_undeclared_builtin_options+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_CFLAGS=$CFLAGS + ac_cv_c_undeclared_builtin_options='cannot detect' + for ac_arg in '' -fno-builtin; do + CFLAGS="$ac_save_CFLAGS $ac_arg" + # This test program should *not* compile successfully. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +(void) strchr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else $as_nop + # This test program should compile successfully. + # No library function is consistently available on + # freestanding implementations, so test against a dummy + # declaration. Include always-available headers on the + # off chance that they somehow elicit warnings. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +extern void ac_decl (int, char *); -$as_echo "#define HAVE_DIRFD 1" >>confdefs.h +int +main (void) +{ +(void) ac_decl (0, (char *) 0); + (void) ac_decl; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + if test x"$ac_arg" = x +then : + ac_cv_c_undeclared_builtin_options='none needed' +else $as_nop + ac_cv_c_undeclared_builtin_options=$ac_arg fi + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done + CFLAGS=$ac_save_CFLAGS + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 +printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } + case $ac_cv_c_undeclared_builtin_options in #( + 'cannot detect') : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot make $CC report undeclared builtins +See \`config.log' for more details" "$LINENO" 5; } ;; #( + 'none needed') : + ac_c_undeclared_builtin_options='' ;; #( + *) : + ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; +esac + +ac_fn_check_decl "$LINENO" "dirfd" "ac_cv_have_decl_dirfd" "#include + #include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_dirfd" = xyes +then : + +printf "%s\n" "#define HAVE_DIRFD 1" >>confdefs.h +fi # For some functions, having a definition is not sufficient, since # we want to take their address. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chroot" >&5 -$as_echo_n "checking for chroot... " >&6; } -if ${ac_cv_func_chroot+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for chroot" >&5 +printf %s "checking for chroot... " >&6; } +if test ${ac_cv_func_chroot+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=chroot ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_chroot=yes -else +else $as_nop ac_cv_func_chroot=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chroot" >&5 -$as_echo "$ac_cv_func_chroot" >&6; } - if test "x$ac_cv_func_chroot" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chroot" >&5 +printf "%s\n" "$ac_cv_func_chroot" >&6; } + if test "x$ac_cv_func_chroot" = xyes +then : -$as_echo "#define HAVE_CHROOT 1" >>confdefs.h +printf "%s\n" "#define HAVE_CHROOT 1" >>confdefs.h fi @@ -16195,35 +18713,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for link" >&5 -$as_echo_n "checking for link... " >&6; } -if ${ac_cv_func_link+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for link" >&5 +printf %s "checking for link... " >&6; } +if test ${ac_cv_func_link+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=link ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_link=yes -else +else $as_nop ac_cv_func_link=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_link" >&5 -$as_echo "$ac_cv_func_link" >&6; } - if test "x$ac_cv_func_link" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_link" >&5 +printf "%s\n" "$ac_cv_func_link" >&6; } + if test "x$ac_cv_func_link" = xyes +then : -$as_echo "#define HAVE_LINK 1" >>confdefs.h +printf "%s\n" "#define HAVE_LINK 1" >>confdefs.h fi @@ -16231,35 +18752,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for symlink" >&5 -$as_echo_n "checking for symlink... " >&6; } -if ${ac_cv_func_symlink+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for symlink" >&5 +printf %s "checking for symlink... " >&6; } +if test ${ac_cv_func_symlink+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=symlink ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_symlink=yes -else +else $as_nop ac_cv_func_symlink=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_symlink" >&5 -$as_echo "$ac_cv_func_symlink" >&6; } - if test "x$ac_cv_func_symlink" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_symlink" >&5 +printf "%s\n" "$ac_cv_func_symlink" >&6; } + if test "x$ac_cv_func_symlink" = xyes +then : -$as_echo "#define HAVE_SYMLINK 1" >>confdefs.h +printf "%s\n" "#define HAVE_SYMLINK 1" >>confdefs.h fi @@ -16267,35 +18791,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fchdir" >&5 -$as_echo_n "checking for fchdir... " >&6; } -if ${ac_cv_func_fchdir+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fchdir" >&5 +printf %s "checking for fchdir... " >&6; } +if test ${ac_cv_func_fchdir+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=fchdir ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_fchdir=yes -else +else $as_nop ac_cv_func_fchdir=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fchdir" >&5 -$as_echo "$ac_cv_func_fchdir" >&6; } - if test "x$ac_cv_func_fchdir" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fchdir" >&5 +printf "%s\n" "$ac_cv_func_fchdir" >&6; } + if test "x$ac_cv_func_fchdir" = xyes +then : -$as_echo "#define HAVE_FCHDIR 1" >>confdefs.h +printf "%s\n" "#define HAVE_FCHDIR 1" >>confdefs.h fi @@ -16303,35 +18830,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fsync" >&5 -$as_echo_n "checking for fsync... " >&6; } -if ${ac_cv_func_fsync+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fsync" >&5 +printf %s "checking for fsync... " >&6; } +if test ${ac_cv_func_fsync+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=fsync ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_fsync=yes -else +else $as_nop ac_cv_func_fsync=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fsync" >&5 -$as_echo "$ac_cv_func_fsync" >&6; } - if test "x$ac_cv_func_fsync" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fsync" >&5 +printf "%s\n" "$ac_cv_func_fsync" >&6; } + if test "x$ac_cv_func_fsync" = xyes +then : -$as_echo "#define HAVE_FSYNC 1" >>confdefs.h +printf "%s\n" "#define HAVE_FSYNC 1" >>confdefs.h fi @@ -16339,35 +18869,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fdatasync" >&5 -$as_echo_n "checking for fdatasync... " >&6; } -if ${ac_cv_func_fdatasync+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fdatasync" >&5 +printf %s "checking for fdatasync... " >&6; } +if test ${ac_cv_func_fdatasync+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=fdatasync ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_fdatasync=yes -else +else $as_nop ac_cv_func_fdatasync=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fdatasync" >&5 -$as_echo "$ac_cv_func_fdatasync" >&6; } - if test "x$ac_cv_func_fdatasync" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fdatasync" >&5 +printf "%s\n" "$ac_cv_func_fdatasync" >&6; } + if test "x$ac_cv_func_fdatasync" = xyes +then : -$as_echo "#define HAVE_FDATASYNC 1" >>confdefs.h +printf "%s\n" "#define HAVE_FDATASYNC 1" >>confdefs.h fi @@ -16375,35 +18908,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for epoll_create" >&5 -$as_echo_n "checking for epoll_create... " >&6; } -if ${ac_cv_func_epoll_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for epoll_create" >&5 +printf %s "checking for epoll_create... " >&6; } +if test ${ac_cv_func_epoll_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=epoll_create ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_epoll_create=yes -else +else $as_nop ac_cv_func_epoll_create=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create" >&5 -$as_echo "$ac_cv_func_epoll_create" >&6; } - if test "x$ac_cv_func_epoll_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create" >&5 +printf "%s\n" "$ac_cv_func_epoll_create" >&6; } + if test "x$ac_cv_func_epoll_create" = xyes +then : -$as_echo "#define HAVE_EPOLL 1" >>confdefs.h +printf "%s\n" "#define HAVE_EPOLL 1" >>confdefs.h fi @@ -16411,35 +18947,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for epoll_create1" >&5 -$as_echo_n "checking for epoll_create1... " >&6; } -if ${ac_cv_func_epoll_create1+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for epoll_create1" >&5 +printf %s "checking for epoll_create1... " >&6; } +if test ${ac_cv_func_epoll_create1+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=epoll_create1 ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_epoll_create1=yes -else +else $as_nop ac_cv_func_epoll_create1=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create1" >&5 -$as_echo "$ac_cv_func_epoll_create1" >&6; } - if test "x$ac_cv_func_epoll_create1" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_epoll_create1" >&5 +printf "%s\n" "$ac_cv_func_epoll_create1" >&6; } + if test "x$ac_cv_func_epoll_create1" = xyes +then : -$as_echo "#define HAVE_EPOLL_CREATE1 1" >>confdefs.h +printf "%s\n" "#define HAVE_EPOLL_CREATE1 1" >>confdefs.h fi @@ -16447,11 +18986,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for kqueue" >&5 -$as_echo_n "checking for kqueue... " >&6; } -if ${ac_cv_func_kqueue+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for kqueue" >&5 +printf %s "checking for kqueue... " >&6; } +if test ${ac_cv_func_kqueue+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16459,26 +18999,28 @@ else #include int -main () +main (void) { void *x=kqueue ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_kqueue=yes -else +else $as_nop ac_cv_func_kqueue=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_kqueue" >&5 -$as_echo "$ac_cv_func_kqueue" >&6; } - if test "x$ac_cv_func_kqueue" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_kqueue" >&5 +printf "%s\n" "$ac_cv_func_kqueue" >&6; } + if test "x$ac_cv_func_kqueue" = xyes +then : -$as_echo "#define HAVE_KQUEUE 1" >>confdefs.h +printf "%s\n" "#define HAVE_KQUEUE 1" >>confdefs.h fi @@ -16486,11 +19028,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prlimit" >&5 -$as_echo_n "checking for prlimit... " >&6; } -if ${ac_cv_func_prlimit+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for prlimit" >&5 +printf %s "checking for prlimit... " >&6; } +if test ${ac_cv_func_prlimit+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16498,26 +19041,28 @@ else #include int -main () +main (void) { void *x=prlimit ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_prlimit=yes -else +else $as_nop ac_cv_func_prlimit=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_prlimit" >&5 -$as_echo "$ac_cv_func_prlimit" >&6; } - if test "x$ac_cv_func_prlimit" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_prlimit" >&5 +printf "%s\n" "$ac_cv_func_prlimit" >&6; } + if test "x$ac_cv_func_prlimit" = xyes +then : -$as_echo "#define HAVE_PRLIMIT 1" >>confdefs.h +printf "%s\n" "#define HAVE_PRLIMIT 1" >>confdefs.h fi @@ -16526,35 +19071,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _dyld_shared_cache_contains_path" >&5 -$as_echo_n "checking for _dyld_shared_cache_contains_path... " >&6; } -if ${ac_cv_func__dyld_shared_cache_contains_path+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _dyld_shared_cache_contains_path" >&5 +printf %s "checking for _dyld_shared_cache_contains_path... " >&6; } +if test ${ac_cv_func__dyld_shared_cache_contains_path+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=_dyld_shared_cache_contains_path ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func__dyld_shared_cache_contains_path=yes -else +else $as_nop ac_cv_func__dyld_shared_cache_contains_path=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func__dyld_shared_cache_contains_path" >&5 -$as_echo "$ac_cv_func__dyld_shared_cache_contains_path" >&6; } - if test "x$ac_cv_func__dyld_shared_cache_contains_path" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func__dyld_shared_cache_contains_path" >&5 +printf "%s\n" "$ac_cv_func__dyld_shared_cache_contains_path" >&6; } + if test "x$ac_cv_func__dyld_shared_cache_contains_path" = xyes +then : -$as_echo "#define HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH 1" >>confdefs.h +printf "%s\n" "#define HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH 1" >>confdefs.h fi @@ -16563,11 +19111,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for memfd_create" >&5 -$as_echo_n "checking for memfd_create... " >&6; } -if ${ac_cv_func_memfd_create+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for memfd_create" >&5 +printf %s "checking for memfd_create... " >&6; } +if test ${ac_cv_func_memfd_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16579,26 +19128,28 @@ else #endif int -main () +main (void) { void *x=memfd_create ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_memfd_create=yes -else +else $as_nop ac_cv_func_memfd_create=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memfd_create" >&5 -$as_echo "$ac_cv_func_memfd_create" >&6; } - if test "x$ac_cv_func_memfd_create" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memfd_create" >&5 +printf "%s\n" "$ac_cv_func_memfd_create" >&6; } + if test "x$ac_cv_func_memfd_create" = xyes +then : -$as_echo "#define HAVE_MEMFD_CREATE 1" >>confdefs.h +printf "%s\n" "#define HAVE_MEMFD_CREATE 1" >>confdefs.h fi @@ -16607,11 +19158,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for eventfd" >&5 -$as_echo_n "checking for eventfd... " >&6; } -if ${ac_cv_func_eventfd+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for eventfd" >&5 +printf %s "checking for eventfd... " >&6; } +if test ${ac_cv_func_eventfd+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16620,26 +19172,28 @@ else #endif int -main () +main (void) { void *x=eventfd ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_eventfd=yes -else +else $as_nop ac_cv_func_eventfd=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_eventfd" >&5 -$as_echo "$ac_cv_func_eventfd" >&6; } - if test "x$ac_cv_func_eventfd" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_eventfd" >&5 +printf "%s\n" "$ac_cv_func_eventfd" >&6; } + if test "x$ac_cv_func_eventfd" = xyes +then : -$as_echo "#define HAVE_EVENTFD 1" >>confdefs.h +printf "%s\n" "#define HAVE_EVENTFD 1" >>confdefs.h fi @@ -16654,51 +19208,55 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ctermid_r" >&5 -$as_echo_n "checking for ctermid_r... " >&6; } -if ${ac_cv_func_ctermid_r+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ctermid_r" >&5 +printf %s "checking for ctermid_r... " >&6; } +if test ${ac_cv_func_ctermid_r+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=ctermid_r ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_ctermid_r=yes -else +else $as_nop ac_cv_func_ctermid_r=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ctermid_r" >&5 -$as_echo "$ac_cv_func_ctermid_r" >&6; } - if test "x$ac_cv_func_ctermid_r" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_ctermid_r" >&5 +printf "%s\n" "$ac_cv_func_ctermid_r" >&6; } + if test "x$ac_cv_func_ctermid_r" = xyes +then : -$as_echo "#define HAVE_CTERMID_R 1" >>confdefs.h +printf "%s\n" "#define HAVE_CTERMID_R 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock declaration" >&5 -$as_echo_n "checking for flock declaration... " >&6; } -if ${ac_cv_flock_decl+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flock declaration" >&5 +printf %s "checking for flock declaration... " >&6; } +if test ${ac_cv_flock_decl+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void* p = flock @@ -16706,34 +19264,33 @@ void* p = flock return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_flock_decl=yes -else +else $as_nop ac_cv_flock_decl=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_flock_decl" >&5 -$as_echo "$ac_cv_flock_decl" >&6; } -if test "x$ac_cv_flock_decl" = xyes; then : - for ac_func in flock -do : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_flock_decl" >&5 +printf "%s\n" "$ac_cv_flock_decl" >&6; } +if test "x$ac_cv_flock_decl" = xyes +then : ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" -if test "x$ac_cv_func_flock" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_FLOCK 1 -_ACEOF +if test "x$ac_cv_func_flock" = xyes +then : + printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h fi -done - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 -$as_echo_n "checking for flock in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_flock+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 +printf %s "checking for flock in -lbsd... " >&6; } +if test ${ac_cv_lib_bsd_flock+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16742,30 +19299,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char flock (); int -main () +main (void) { return flock (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_bsd_flock=yes -else +else $as_nop ac_cv_lib_bsd_flock=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 -$as_echo "$ac_cv_lib_bsd_flock" >&6; } -if test "x$ac_cv_lib_bsd_flock" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 +printf "%s\n" "$ac_cv_lib_bsd_flock" >&6; } +if test "x$ac_cv_lib_bsd_flock" = xyes +then : FCNTL_LIBS="-lbsd" fi @@ -16774,72 +19330,78 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpagesize" >&5 -$as_echo_n "checking for getpagesize... " >&6; } -if ${ac_cv_func_getpagesize+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getpagesize" >&5 +printf %s "checking for getpagesize... " >&6; } +if test ${ac_cv_func_getpagesize+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=getpagesize ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_getpagesize=yes -else +else $as_nop ac_cv_func_getpagesize=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpagesize" >&5 -$as_echo "$ac_cv_func_getpagesize" >&6; } - if test "x$ac_cv_func_getpagesize" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpagesize" >&5 +printf "%s\n" "$ac_cv_func_getpagesize" >&6; } + if test "x$ac_cv_func_getpagesize" = xyes +then : -$as_echo "#define HAVE_GETPAGESIZE 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETPAGESIZE 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken unsetenv" >&5 -$as_echo_n "checking for broken unsetenv... " >&6; } -if ${ac_cv_broken_unsetenv+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken unsetenv" >&5 +printf %s "checking for broken unsetenv... " >&6; } +if test ${ac_cv_broken_unsetenv+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int res = unsetenv("DUMMY") ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_broken_unsetenv=no -else +else $as_nop ac_cv_broken_unsetenv=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_unsetenv" >&5 -$as_echo "$ac_cv_broken_unsetenv" >&6; } -if test "x$ac_cv_broken_unsetenv" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_unsetenv" >&5 +printf "%s\n" "$ac_cv_broken_unsetenv" >&6; } +if test "x$ac_cv_broken_unsetenv" = xyes +then : -$as_echo "#define HAVE_BROKEN_UNSETENV 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_UNSETENV 1" >>confdefs.h fi @@ -16848,11 +19410,12 @@ for ac_prog in true do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_TRUE+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_TRUE+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$TRUE"; then ac_cv_prog_TRUE="$TRUE" # Let the user override the test. else @@ -16860,11 +19423,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_TRUE="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -16875,11 +19442,11 @@ fi fi TRUE=$ac_cv_prog_TRUE if test -n "$TRUE"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TRUE" >&5 -$as_echo "$TRUE" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TRUE" >&5 +printf "%s\n" "$TRUE" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -16888,11 +19455,12 @@ done test -n "$TRUE" || TRUE="/bin/true" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lc" >&5 -$as_echo_n "checking for inet_aton in -lc... " >&6; } -if ${ac_cv_lib_c_inet_aton+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lc" >&5 +printf %s "checking for inet_aton in -lc... " >&6; } +if test ${ac_cv_lib_c_inet_aton+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16901,37 +19469,37 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char inet_aton (); int -main () +main (void) { return inet_aton (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_c_inet_aton=yes -else +else $as_nop ac_cv_lib_c_inet_aton=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 -$as_echo "$ac_cv_lib_c_inet_aton" >&6; } -if test "x$ac_cv_lib_c_inet_aton" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 +printf "%s\n" "$ac_cv_lib_c_inet_aton" >&6; } +if test "x$ac_cv_lib_c_inet_aton" = xyes +then : $ac_cv_prog_TRUE -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 -$as_echo_n "checking for inet_aton in -lresolv... " >&6; } -if ${ac_cv_lib_resolv_inet_aton+:} false; then : - $as_echo_n "(cached) " >&6 -else +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 +printf %s "checking for inet_aton in -lresolv... " >&6; } +if test ${ac_cv_lib_resolv_inet_aton+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16940,33 +19508,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char inet_aton (); int -main () +main (void) { return inet_aton (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_resolv_inet_aton=yes -else +else $as_nop ac_cv_lib_resolv_inet_aton=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 -$as_echo "$ac_cv_lib_resolv_inet_aton" >&6; } -if test "x$ac_cv_lib_resolv_inet_aton" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBRESOLV 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 +printf "%s\n" "$ac_cv_lib_resolv_inet_aton" >&6; } +if test "x$ac_cv_lib_resolv_inet_aton" = xyes +then : + printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h LIBS="-lresolv $LIBS" @@ -16978,14 +19543,16 @@ fi # On Tru64, chflags seems to be present, but calling it will # exit Python -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for chflags" >&5 -$as_echo_n "checking for chflags... " >&6; } -if ${ac_cv_have_chflags+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for chflags" >&5 +printf %s "checking for chflags... " >&6; } +if test ${ac_cv_have_chflags+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_have_chflags=cross -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16999,9 +19566,10 @@ int main(int argc, char *argv[]) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_have_chflags=yes -else +else $as_nop ac_cv_have_chflags=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -17010,31 +19578,34 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_chflags" >&5 -$as_echo "$ac_cv_have_chflags" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_chflags" >&5 +printf "%s\n" "$ac_cv_have_chflags" >&6; } if test "$ac_cv_have_chflags" = cross ; then ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" -if test "x$ac_cv_func_chflags" = xyes; then : +if test "x$ac_cv_func_chflags" = xyes +then : ac_cv_have_chflags="yes" -else +else $as_nop ac_cv_have_chflags="no" fi fi if test "$ac_cv_have_chflags" = yes ; then -$as_echo "#define HAVE_CHFLAGS 1" >>confdefs.h +printf "%s\n" "#define HAVE_CHFLAGS 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lchflags" >&5 -$as_echo_n "checking for lchflags... " >&6; } -if ${ac_cv_have_lchflags+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lchflags" >&5 +printf %s "checking for lchflags... " >&6; } +if test ${ac_cv_have_lchflags+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_have_lchflags=cross -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17048,9 +19619,10 @@ int main(int argc, char *argv[]) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_have_lchflags=yes -else +else $as_nop ac_cv_have_lchflags=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -17059,20 +19631,21 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_lchflags" >&5 -$as_echo "$ac_cv_have_lchflags" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_lchflags" >&5 +printf "%s\n" "$ac_cv_have_lchflags" >&6; } if test "$ac_cv_have_lchflags" = cross ; then ac_fn_c_check_func "$LINENO" "lchflags" "ac_cv_func_lchflags" -if test "x$ac_cv_func_lchflags" = xyes; then : +if test "x$ac_cv_func_lchflags" = xyes +then : ac_cv_have_lchflags="yes" -else +else $as_nop ac_cv_have_lchflags="no" fi fi if test "$ac_cv_have_lchflags" = yes ; then -$as_echo "#define HAVE_LCHFLAGS 1" >>confdefs.h +printf "%s\n" "#define HAVE_LCHFLAGS 1" >>confdefs.h fi @@ -17081,7 +19654,8 @@ fi - if test "$ac_sys_system" = "Emscripten" -a -z "$ZLIB_CFLAGS" -a -z "$ZLIB_LIBS"; then : + if test "$ac_sys_system" = "Emscripten" -a -z "$ZLIB_CFLAGS" -a -z "$ZLIB_LIBS" +then : ZLIB_CFLAGS="-sUSE_ZLIB" ZLIB_LIBS="-sUSE_ZLIB" @@ -17093,17 +19667,17 @@ fi pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZLIB" >&5 -$as_echo_n "checking for ZLIB... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ZLIB" >&5 +printf %s "checking for ZLIB... " >&6; } if test -n "$ZLIB_CFLAGS"; then pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.0\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib >= 1.2.0") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib >= 1.2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -17117,10 +19691,10 @@ if test -n "$ZLIB_LIBS"; then pkg_cv_ZLIB_LIBS="$ZLIB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.0\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib >= 1.2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib >= 1.2.0") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib >= 1.2.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -17134,8 +19708,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -17159,20 +19733,20 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" LDFLAGS="$LDFLAGS $ZLIB_LIBS" - for ac_header in zlib.h + for ac_header in zlib.h do : - ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" -if test "x$ac_cv_header_zlib_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_ZLIB_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = xyes +then : + printf "%s\n" "#define HAVE_ZLIB_H 1" >>confdefs.h py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzread in -lz" >&5 -$as_echo_n "checking for gzread in -lz... " >&6; } -if ${ac_cv_lib_z_gzread+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gzread in -lz" >&5 +printf %s "checking for gzread in -lz... " >&6; } +if test ${ac_cv_lib_z_gzread+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17181,54 +19755,54 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char gzread (); int -main () +main (void) { return gzread (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_z_gzread=yes -else +else $as_nop ac_cv_lib_z_gzread=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 -$as_echo "$ac_cv_lib_z_gzread" >&6; } -if test "x$ac_cv_lib_z_gzread" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 +printf "%s\n" "$ac_cv_lib_z_gzread" >&6; } +if test "x$ac_cv_lib_z_gzread" = xyes +then : have_zlib=yes -else +else $as_nop have_zlib=no fi LIBS=$py_check_lib_save_LIBS -else +else $as_nop have_zlib=no fi done - - if test "x$have_zlib" = xyes; then : + if test "x$have_zlib" = xyes +then : ZLIB_CFLAGS=${ZLIB_CFLAGS-""} ZLIB_LIBS=${ZLIB_LIBS-"-lz"} py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 -$as_echo_n "checking for inflateCopy in -lz... " >&6; } -if ${ac_cv_lib_z_inflateCopy+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 +printf %s "checking for inflateCopy in -lz... " >&6; } +if test ${ac_cv_lib_z_inflateCopy+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17237,31 +19811,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char inflateCopy (); int -main () +main (void) { return inflateCopy (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_z_inflateCopy=yes -else +else $as_nop ac_cv_lib_z_inflateCopy=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 -$as_echo "$ac_cv_lib_z_inflateCopy" >&6; } -if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : - $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 +printf "%s\n" "$ac_cv_lib_z_inflateCopy" >&6; } +if test "x$ac_cv_lib_z_inflateCopy" = xyes +then : + printf "%s\n" "#define HAVE_ZLIB_COPY 1" >>confdefs.h fi @@ -17278,8 +19851,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -17289,20 +19862,20 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" LDFLAGS="$LDFLAGS $ZLIB_LIBS" - for ac_header in zlib.h + for ac_header in zlib.h do : - ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" -if test "x$ac_cv_header_zlib_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_ZLIB_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = xyes +then : + printf "%s\n" "#define HAVE_ZLIB_H 1" >>confdefs.h py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzread in -lz" >&5 -$as_echo_n "checking for gzread in -lz... " >&6; } -if ${ac_cv_lib_z_gzread+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gzread in -lz" >&5 +printf %s "checking for gzread in -lz... " >&6; } +if test ${ac_cv_lib_z_gzread+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17311,54 +19884,54 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char gzread (); int -main () +main (void) { return gzread (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_z_gzread=yes -else +else $as_nop ac_cv_lib_z_gzread=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 -$as_echo "$ac_cv_lib_z_gzread" >&6; } -if test "x$ac_cv_lib_z_gzread" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzread" >&5 +printf "%s\n" "$ac_cv_lib_z_gzread" >&6; } +if test "x$ac_cv_lib_z_gzread" = xyes +then : have_zlib=yes -else +else $as_nop have_zlib=no fi LIBS=$py_check_lib_save_LIBS -else +else $as_nop have_zlib=no fi done - - if test "x$have_zlib" = xyes; then : + if test "x$have_zlib" = xyes +then : ZLIB_CFLAGS=${ZLIB_CFLAGS-""} ZLIB_LIBS=${ZLIB_LIBS-"-lz"} py_check_lib_save_LIBS=$LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 -$as_echo_n "checking for inflateCopy in -lz... " >&6; } -if ${ac_cv_lib_z_inflateCopy+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 +printf %s "checking for inflateCopy in -lz... " >&6; } +if test ${ac_cv_lib_z_inflateCopy+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17367,31 +19940,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char inflateCopy (); int -main () +main (void) { return inflateCopy (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_z_inflateCopy=yes -else +else $as_nop ac_cv_lib_z_inflateCopy=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 -$as_echo "$ac_cv_lib_z_inflateCopy" >&6; } -if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : - $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 +printf "%s\n" "$ac_cv_lib_z_inflateCopy" >&6; } +if test "x$ac_cv_lib_z_inflateCopy" = xyes +then : + printf "%s\n" "#define HAVE_ZLIB_COPY 1" >>confdefs.h fi @@ -17410,16 +19982,17 @@ LIBS=$save_LIBS else ZLIB_CFLAGS=$pkg_cv_ZLIB_CFLAGS ZLIB_LIBS=$pkg_cv_ZLIB_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_zlib=yes - $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h + printf "%s\n" "#define HAVE_ZLIB_COPY 1" >>confdefs.h fi -if test "x$have_zlib" = xyes; then : +if test "x$have_zlib" = xyes +then : BINASCII_CFLAGS="-DUSE_ZLIB_CRC32 $ZLIB_CFLAGS" BINASCII_LIBS="$ZLIB_LIBS" @@ -17429,7 +20002,8 @@ fi - if test "$ac_sys_system" = "Emscripten" -a -z "$BZIP2_CFLAGS" -a -z "$BZIP2_LIBS"; then : + if test "$ac_sys_system" = "Emscripten" -a -z "$BZIP2_CFLAGS" -a -z "$BZIP2_LIBS" +then : BZIP2_CFLAGS="-sUSE_BZIP2" BZIP2_LIBS="-sUSE_BZIP2" @@ -17441,17 +20015,17 @@ fi pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BZIP2" >&5 -$as_echo_n "checking for BZIP2... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BZIP2" >&5 +printf %s "checking for BZIP2... " >&6; } if test -n "$BZIP2_CFLAGS"; then pkg_cv_BZIP2_CFLAGS="$BZIP2_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bzip2\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bzip2\""; } >&5 ($PKG_CONFIG --exists --print-errors "bzip2") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_BZIP2_CFLAGS=`$PKG_CONFIG --cflags "bzip2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -17465,10 +20039,10 @@ if test -n "$BZIP2_LIBS"; then pkg_cv_BZIP2_LIBS="$BZIP2_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bzip2\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bzip2\""; } >&5 ($PKG_CONFIG --exists --print-errors "bzip2") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_BZIP2_LIBS=`$PKG_CONFIG --libs "bzip2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -17482,8 +20056,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -17507,19 +20081,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" LDFLAGS="$LDFLAGS $BZIP2_LIBS" - for ac_header in bzlib.h + for ac_header in bzlib.h do : - ac_fn_c_check_header_mongrel "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" -if test "x$ac_cv_header_bzlib_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_BZLIB_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BZ2_bzCompress in -lbz2" >&5 -$as_echo_n "checking for BZ2_bzCompress in -lbz2... " >&6; } -if ${ac_cv_lib_bz2_BZ2_bzCompress+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" +if test "x$ac_cv_header_bzlib_h" = xyes +then : + printf "%s\n" "#define HAVE_BZLIB_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BZ2_bzCompress in -lbz2" >&5 +printf %s "checking for BZ2_bzCompress in -lbz2... " >&6; } +if test ${ac_cv_lib_bz2_BZ2_bzCompress+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lbz2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17528,43 +20102,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char BZ2_bzCompress (); int -main () +main (void) { return BZ2_bzCompress (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_bz2_BZ2_bzCompress=yes -else +else $as_nop ac_cv_lib_bz2_BZ2_bzCompress=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 -$as_echo "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } -if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 +printf "%s\n" "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } +if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes +then : have_bzip2=yes -else +else $as_nop have_bzip2=no fi -else +else $as_nop have_bzip2=no fi done - - if test "x$have_bzip2" = xyes; then : + if test "x$have_bzip2" = xyes +then : BZIP2_CFLAGS=${BZIP2_CFLAGS-""} BZIP2_LIBS=${BZIP2_LIBS-"-lbz2"} @@ -17579,8 +20152,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -17590,19 +20163,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $BZIP2_CFLAGS" LDFLAGS="$LDFLAGS $BZIP2_LIBS" - for ac_header in bzlib.h + for ac_header in bzlib.h do : - ac_fn_c_check_header_mongrel "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" -if test "x$ac_cv_header_bzlib_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_BZLIB_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BZ2_bzCompress in -lbz2" >&5 -$as_echo_n "checking for BZ2_bzCompress in -lbz2... " >&6; } -if ${ac_cv_lib_bz2_BZ2_bzCompress+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" +if test "x$ac_cv_header_bzlib_h" = xyes +then : + printf "%s\n" "#define HAVE_BZLIB_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BZ2_bzCompress in -lbz2" >&5 +printf %s "checking for BZ2_bzCompress in -lbz2... " >&6; } +if test ${ac_cv_lib_bz2_BZ2_bzCompress+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lbz2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17611,43 +20184,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char BZ2_bzCompress (); int -main () +main (void) { return BZ2_bzCompress (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_bz2_BZ2_bzCompress=yes -else +else $as_nop ac_cv_lib_bz2_BZ2_bzCompress=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 -$as_echo "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } -if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzCompress" >&5 +printf "%s\n" "$ac_cv_lib_bz2_BZ2_bzCompress" >&6; } +if test "x$ac_cv_lib_bz2_BZ2_bzCompress" = xyes +then : have_bzip2=yes -else +else $as_nop have_bzip2=no fi -else +else $as_nop have_bzip2=no fi done - - if test "x$have_bzip2" = xyes; then : + if test "x$have_bzip2" = xyes +then : BZIP2_CFLAGS=${BZIP2_CFLAGS-""} BZIP2_LIBS=${BZIP2_LIBS-"-lbz2"} @@ -17664,24 +20236,24 @@ LIBS=$save_LIBS else BZIP2_CFLAGS=$pkg_cv_BZIP2_CFLAGS BZIP2_LIBS=$pkg_cv_BZIP2_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_bzip2=yes fi pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBLZMA" >&5 -$as_echo_n "checking for LIBLZMA... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBLZMA" >&5 +printf %s "checking for LIBLZMA... " >&6; } if test -n "$LIBLZMA_CFLAGS"; then pkg_cv_LIBLZMA_CFLAGS="$LIBLZMA_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"liblzma\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"liblzma\""; } >&5 ($PKG_CONFIG --exists --print-errors "liblzma") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBLZMA_CFLAGS=`$PKG_CONFIG --cflags "liblzma" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -17695,10 +20267,10 @@ if test -n "$LIBLZMA_LIBS"; then pkg_cv_LIBLZMA_LIBS="$LIBLZMA_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"liblzma\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"liblzma\""; } >&5 ($PKG_CONFIG --exists --print-errors "liblzma") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBLZMA_LIBS=`$PKG_CONFIG --libs "liblzma" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -17712,8 +20284,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -17737,19 +20309,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" - for ac_header in lzma.h + for ac_header in lzma.h do : - ac_fn_c_check_header_mongrel "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" -if test "x$ac_cv_header_lzma_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LZMA_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzma_easy_encoder in -llzma" >&5 -$as_echo_n "checking for lzma_easy_encoder in -llzma... " >&6; } -if ${ac_cv_lib_lzma_lzma_easy_encoder+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" +if test "x$ac_cv_header_lzma_h" = xyes +then : + printf "%s\n" "#define HAVE_LZMA_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lzma_easy_encoder in -llzma" >&5 +printf %s "checking for lzma_easy_encoder in -llzma... " >&6; } +if test ${ac_cv_lib_lzma_lzma_easy_encoder+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-llzma $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17758,43 +20330,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char lzma_easy_encoder (); int -main () +main (void) { return lzma_easy_encoder (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_lzma_lzma_easy_encoder=yes -else +else $as_nop ac_cv_lib_lzma_lzma_easy_encoder=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 -$as_echo "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } -if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 +printf "%s\n" "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } +if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes +then : have_liblzma=yes -else +else $as_nop have_liblzma=no fi -else +else $as_nop have_liblzma=no fi done - - if test "x$have_liblzma" = xyes; then : + if test "x$have_liblzma" = xyes +then : LIBLZMA_CFLAGS=${LIBLZMA_CFLAGS-""} LIBLZMA_LIBS=${LIBLZMA_LIBS-"-llzma"} @@ -17809,8 +20380,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -17820,19 +20391,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBLZMA_CFLAGS" LDFLAGS="$LDFLAGS $LIBLZMA_LIBS" - for ac_header in lzma.h + for ac_header in lzma.h do : - ac_fn_c_check_header_mongrel "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" -if test "x$ac_cv_header_lzma_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LZMA_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzma_easy_encoder in -llzma" >&5 -$as_echo_n "checking for lzma_easy_encoder in -llzma... " >&6; } -if ${ac_cv_lib_lzma_lzma_easy_encoder+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" +if test "x$ac_cv_header_lzma_h" = xyes +then : + printf "%s\n" "#define HAVE_LZMA_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for lzma_easy_encoder in -llzma" >&5 +printf %s "checking for lzma_easy_encoder in -llzma... " >&6; } +if test ${ac_cv_lib_lzma_lzma_easy_encoder+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-llzma $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -17841,43 +20412,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char lzma_easy_encoder (); int -main () +main (void) { return lzma_easy_encoder (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_lzma_lzma_easy_encoder=yes -else +else $as_nop ac_cv_lib_lzma_lzma_easy_encoder=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 -$as_echo "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } -if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_easy_encoder" >&5 +printf "%s\n" "$ac_cv_lib_lzma_lzma_easy_encoder" >&6; } +if test "x$ac_cv_lib_lzma_lzma_easy_encoder" = xyes +then : have_liblzma=yes -else +else $as_nop have_liblzma=no fi -else +else $as_nop have_liblzma=no fi done - - if test "x$have_liblzma" = xyes; then : + if test "x$have_liblzma" = xyes +then : LIBLZMA_CFLAGS=${LIBLZMA_CFLAGS-""} LIBLZMA_LIBS=${LIBLZMA_LIBS-"-llzma"} @@ -17894,8 +20464,8 @@ LIBS=$save_LIBS else LIBLZMA_CFLAGS=$pkg_cv_LIBLZMA_CFLAGS LIBLZMA_LIBS=$pkg_cv_LIBLZMA_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_liblzma=yes fi @@ -17903,35 +20473,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hstrerror" >&5 -$as_echo_n "checking for hstrerror... " >&6; } -if ${ac_cv_func_hstrerror+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for hstrerror" >&5 +printf %s "checking for hstrerror... " >&6; } +if test ${ac_cv_func_hstrerror+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=hstrerror ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_hstrerror=yes -else +else $as_nop ac_cv_func_hstrerror=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_hstrerror" >&5 -$as_echo "$ac_cv_func_hstrerror" >&6; } - if test "x$ac_cv_func_hstrerror" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_hstrerror" >&5 +printf "%s\n" "$ac_cv_func_hstrerror" >&6; } + if test "x$ac_cv_func_hstrerror" = xyes +then : -$as_echo "#define HAVE_HSTRERROR 1" >>confdefs.h +printf "%s\n" "#define HAVE_HSTRERROR 1" >>confdefs.h fi @@ -17939,35 +20512,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getservbyname" >&5 -$as_echo_n "checking for getservbyname... " >&6; } -if ${ac_cv_func_getservbyname+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getservbyname" >&5 +printf %s "checking for getservbyname... " >&6; } +if test ${ac_cv_func_getservbyname+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=getservbyname ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_getservbyname=yes -else +else $as_nop ac_cv_func_getservbyname=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyname" >&5 -$as_echo "$ac_cv_func_getservbyname" >&6; } - if test "x$ac_cv_func_getservbyname" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyname" >&5 +printf "%s\n" "$ac_cv_func_getservbyname" >&6; } + if test "x$ac_cv_func_getservbyname" = xyes +then : -$as_echo "#define HAVE_GETSERVBYNAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETSERVBYNAME 1" >>confdefs.h fi @@ -17975,35 +20551,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getservbyport" >&5 -$as_echo_n "checking for getservbyport... " >&6; } -if ${ac_cv_func_getservbyport+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getservbyport" >&5 +printf %s "checking for getservbyport... " >&6; } +if test ${ac_cv_func_getservbyport+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=getservbyport ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_getservbyport=yes -else +else $as_nop ac_cv_func_getservbyport=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyport" >&5 -$as_echo "$ac_cv_func_getservbyport" >&6; } - if test "x$ac_cv_func_getservbyport" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getservbyport" >&5 +printf "%s\n" "$ac_cv_func_getservbyport" >&6; } + if test "x$ac_cv_func_getservbyport" = xyes +then : -$as_echo "#define HAVE_GETSERVBYPORT 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETSERVBYPORT 1" >>confdefs.h fi @@ -18011,35 +20590,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname" >&5 -$as_echo_n "checking for gethostbyname... " >&6; } -if ${ac_cv_func_gethostbyname+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname" >&5 +printf %s "checking for gethostbyname... " >&6; } +if test ${ac_cv_func_gethostbyname+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=gethostbyname ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_gethostbyname=yes -else +else $as_nop ac_cv_func_gethostbyname=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyname" >&5 -$as_echo "$ac_cv_func_gethostbyname" >&6; } - if test "x$ac_cv_func_gethostbyname" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyname" >&5 +printf "%s\n" "$ac_cv_func_gethostbyname" >&6; } + if test "x$ac_cv_func_gethostbyname" = xyes +then : -$as_echo "#define HAVE_GETHOSTBYNAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTBYNAME 1" >>confdefs.h fi @@ -18047,35 +20629,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyaddr" >&5 -$as_echo_n "checking for gethostbyaddr... " >&6; } -if ${ac_cv_func_gethostbyaddr+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyaddr" >&5 +printf %s "checking for gethostbyaddr... " >&6; } +if test ${ac_cv_func_gethostbyaddr+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=gethostbyaddr ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_gethostbyaddr=yes -else +else $as_nop ac_cv_func_gethostbyaddr=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyaddr" >&5 -$as_echo "$ac_cv_func_gethostbyaddr" >&6; } - if test "x$ac_cv_func_gethostbyaddr" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_gethostbyaddr" >&5 +printf "%s\n" "$ac_cv_func_gethostbyaddr" >&6; } + if test "x$ac_cv_func_gethostbyaddr" = xyes +then : -$as_echo "#define HAVE_GETHOSTBYADDR 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTBYADDR 1" >>confdefs.h fi @@ -18083,35 +20668,38 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getprotobyname" >&5 -$as_echo_n "checking for getprotobyname... " >&6; } -if ${ac_cv_func_getprotobyname+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getprotobyname" >&5 +printf %s "checking for getprotobyname... " >&6; } +if test ${ac_cv_func_getprotobyname+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { void *x=getprotobyname ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_getprotobyname=yes -else +else $as_nop ac_cv_func_getprotobyname=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getprotobyname" >&5 -$as_echo "$ac_cv_func_getprotobyname" >&6; } - if test "x$ac_cv_func_getprotobyname" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getprotobyname" >&5 +printf "%s\n" "$ac_cv_func_getprotobyname" >&6; } + if test "x$ac_cv_func_getprotobyname" = xyes +then : -$as_echo "#define HAVE_GETPROTOBYNAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETPROTOBYNAME 1" >>confdefs.h fi @@ -18122,11 +20710,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton" >&5 -$as_echo_n "checking for inet_aton... " >&6; } -if ${ac_cv_func_inet_aton+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_aton" >&5 +printf %s "checking for inet_aton... " >&6; } +if test ${ac_cv_func_inet_aton+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18136,26 +20725,28 @@ else #include int -main () +main (void) { void *x=inet_aton ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_inet_aton=yes -else +else $as_nop ac_cv_func_inet_aton=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_aton" >&5 -$as_echo "$ac_cv_func_inet_aton" >&6; } - if test "x$ac_cv_func_inet_aton" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_aton" >&5 +printf "%s\n" "$ac_cv_func_inet_aton" >&6; } + if test "x$ac_cv_func_inet_aton" = xyes +then : -$as_echo "#define HAVE_INET_ATON 1" >>confdefs.h +printf "%s\n" "#define HAVE_INET_ATON 1" >>confdefs.h fi @@ -18163,11 +20754,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa" >&5 -$as_echo_n "checking for inet_ntoa... " >&6; } -if ${ac_cv_func_inet_ntoa+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa" >&5 +printf %s "checking for inet_ntoa... " >&6; } +if test ${ac_cv_func_inet_ntoa+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18177,26 +20769,28 @@ else #include int -main () +main (void) { void *x=inet_ntoa ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_inet_ntoa=yes -else +else $as_nop ac_cv_func_inet_ntoa=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_ntoa" >&5 -$as_echo "$ac_cv_func_inet_ntoa" >&6; } - if test "x$ac_cv_func_inet_ntoa" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_ntoa" >&5 +printf "%s\n" "$ac_cv_func_inet_ntoa" >&6; } + if test "x$ac_cv_func_inet_ntoa" = xyes +then : -$as_echo "#define HAVE_INET_NTOA 1" >>confdefs.h +printf "%s\n" "#define HAVE_INET_NTOA 1" >>confdefs.h fi @@ -18204,11 +20798,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_pton" >&5 -$as_echo_n "checking for inet_pton... " >&6; } -if ${ac_cv_func_inet_pton+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_pton" >&5 +printf %s "checking for inet_pton... " >&6; } +if test ${ac_cv_func_inet_pton+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18218,26 +20813,28 @@ else #include int -main () +main (void) { void *x=inet_pton ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_inet_pton=yes -else +else $as_nop ac_cv_func_inet_pton=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_pton" >&5 -$as_echo "$ac_cv_func_inet_pton" >&6; } - if test "x$ac_cv_func_inet_pton" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_inet_pton" >&5 +printf "%s\n" "$ac_cv_func_inet_pton" >&6; } + if test "x$ac_cv_func_inet_pton" = xyes +then : -$as_echo "#define HAVE_INET_PTON 1" >>confdefs.h +printf "%s\n" "#define HAVE_INET_PTON 1" >>confdefs.h fi @@ -18245,11 +20842,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpeername" >&5 -$as_echo_n "checking for getpeername... " >&6; } -if ${ac_cv_func_getpeername+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getpeername" >&5 +printf %s "checking for getpeername... " >&6; } +if test ${ac_cv_func_getpeername+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18259,26 +20857,28 @@ else #include int -main () +main (void) { void *x=getpeername ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_getpeername=yes -else +else $as_nop ac_cv_func_getpeername=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpeername" >&5 -$as_echo "$ac_cv_func_getpeername" >&6; } - if test "x$ac_cv_func_getpeername" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpeername" >&5 +printf "%s\n" "$ac_cv_func_getpeername" >&6; } + if test "x$ac_cv_func_getpeername" = xyes +then : -$as_echo "#define HAVE_GETPEERNAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETPEERNAME 1" >>confdefs.h fi @@ -18286,11 +20886,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getsockname" >&5 -$as_echo_n "checking for getsockname... " >&6; } -if ${ac_cv_func_getsockname+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getsockname" >&5 +printf %s "checking for getsockname... " >&6; } +if test ${ac_cv_func_getsockname+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18300,26 +20901,28 @@ else #include int -main () +main (void) { void *x=getsockname ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_getsockname=yes -else +else $as_nop ac_cv_func_getsockname=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getsockname" >&5 -$as_echo "$ac_cv_func_getsockname" >&6; } - if test "x$ac_cv_func_getsockname" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getsockname" >&5 +printf "%s\n" "$ac_cv_func_getsockname" >&6; } + if test "x$ac_cv_func_getsockname" = xyes +then : -$as_echo "#define HAVE_GETSOCKNAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETSOCKNAME 1" >>confdefs.h fi @@ -18327,11 +20930,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for accept" >&5 -$as_echo_n "checking for accept... " >&6; } -if ${ac_cv_func_accept+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for accept" >&5 +printf %s "checking for accept... " >&6; } +if test ${ac_cv_func_accept+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18341,26 +20945,28 @@ else #include int -main () +main (void) { void *x=accept ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_accept=yes -else +else $as_nop ac_cv_func_accept=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_accept" >&5 -$as_echo "$ac_cv_func_accept" >&6; } - if test "x$ac_cv_func_accept" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_accept" >&5 +printf "%s\n" "$ac_cv_func_accept" >&6; } + if test "x$ac_cv_func_accept" = xyes +then : -$as_echo "#define HAVE_ACCEPT 1" >>confdefs.h +printf "%s\n" "#define HAVE_ACCEPT 1" >>confdefs.h fi @@ -18368,11 +20974,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for bind" >&5 -$as_echo_n "checking for bind... " >&6; } -if ${ac_cv_func_bind+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for bind" >&5 +printf %s "checking for bind... " >&6; } +if test ${ac_cv_func_bind+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18382,26 +20989,28 @@ else #include int -main () +main (void) { void *x=bind ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_bind=yes -else +else $as_nop ac_cv_func_bind=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_bind" >&5 -$as_echo "$ac_cv_func_bind" >&6; } - if test "x$ac_cv_func_bind" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_bind" >&5 +printf "%s\n" "$ac_cv_func_bind" >&6; } + if test "x$ac_cv_func_bind" = xyes +then : -$as_echo "#define HAVE_BIND 1" >>confdefs.h +printf "%s\n" "#define HAVE_BIND 1" >>confdefs.h fi @@ -18409,11 +21018,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect" >&5 -$as_echo_n "checking for connect... " >&6; } -if ${ac_cv_func_connect+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect" >&5 +printf %s "checking for connect... " >&6; } +if test ${ac_cv_func_connect+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18423,26 +21033,28 @@ else #include int -main () +main (void) { void *x=connect ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_connect=yes -else +else $as_nop ac_cv_func_connect=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_connect" >&5 -$as_echo "$ac_cv_func_connect" >&6; } - if test "x$ac_cv_func_connect" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_connect" >&5 +printf "%s\n" "$ac_cv_func_connect" >&6; } + if test "x$ac_cv_func_connect" = xyes +then : -$as_echo "#define HAVE_CONNECT 1" >>confdefs.h +printf "%s\n" "#define HAVE_CONNECT 1" >>confdefs.h fi @@ -18450,11 +21062,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for listen" >&5 -$as_echo_n "checking for listen... " >&6; } -if ${ac_cv_func_listen+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for listen" >&5 +printf %s "checking for listen... " >&6; } +if test ${ac_cv_func_listen+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18464,26 +21077,28 @@ else #include int -main () +main (void) { void *x=listen ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_listen=yes -else +else $as_nop ac_cv_func_listen=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_listen" >&5 -$as_echo "$ac_cv_func_listen" >&6; } - if test "x$ac_cv_func_listen" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_listen" >&5 +printf "%s\n" "$ac_cv_func_listen" >&6; } + if test "x$ac_cv_func_listen" = xyes +then : -$as_echo "#define HAVE_LISTEN 1" >>confdefs.h +printf "%s\n" "#define HAVE_LISTEN 1" >>confdefs.h fi @@ -18491,11 +21106,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for recvfrom" >&5 -$as_echo_n "checking for recvfrom... " >&6; } -if ${ac_cv_func_recvfrom+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for recvfrom" >&5 +printf %s "checking for recvfrom... " >&6; } +if test ${ac_cv_func_recvfrom+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18505,26 +21121,28 @@ else #include int -main () +main (void) { void *x=recvfrom ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_recvfrom=yes -else +else $as_nop ac_cv_func_recvfrom=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_recvfrom" >&5 -$as_echo "$ac_cv_func_recvfrom" >&6; } - if test "x$ac_cv_func_recvfrom" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_recvfrom" >&5 +printf "%s\n" "$ac_cv_func_recvfrom" >&6; } + if test "x$ac_cv_func_recvfrom" = xyes +then : -$as_echo "#define HAVE_RECVFROM 1" >>confdefs.h +printf "%s\n" "#define HAVE_RECVFROM 1" >>confdefs.h fi @@ -18532,11 +21150,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendto" >&5 -$as_echo_n "checking for sendto... " >&6; } -if ${ac_cv_func_sendto+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sendto" >&5 +printf %s "checking for sendto... " >&6; } +if test ${ac_cv_func_sendto+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18546,26 +21165,28 @@ else #include int -main () +main (void) { void *x=sendto ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_sendto=yes -else +else $as_nop ac_cv_func_sendto=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_sendto" >&5 -$as_echo "$ac_cv_func_sendto" >&6; } - if test "x$ac_cv_func_sendto" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_sendto" >&5 +printf "%s\n" "$ac_cv_func_sendto" >&6; } + if test "x$ac_cv_func_sendto" = xyes +then : -$as_echo "#define HAVE_SENDTO 1" >>confdefs.h +printf "%s\n" "#define HAVE_SENDTO 1" >>confdefs.h fi @@ -18573,11 +21194,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt" >&5 -$as_echo_n "checking for setsockopt... " >&6; } -if ${ac_cv_func_setsockopt+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setsockopt" >&5 +printf %s "checking for setsockopt... " >&6; } +if test ${ac_cv_func_setsockopt+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18587,26 +21209,28 @@ else #include int -main () +main (void) { void *x=setsockopt ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_setsockopt=yes -else +else $as_nop ac_cv_func_setsockopt=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setsockopt" >&5 -$as_echo "$ac_cv_func_setsockopt" >&6; } - if test "x$ac_cv_func_setsockopt" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setsockopt" >&5 +printf "%s\n" "$ac_cv_func_setsockopt" >&6; } + if test "x$ac_cv_func_setsockopt" = xyes +then : -$as_echo "#define HAVE_SETSOCKOPT 1" >>confdefs.h +printf "%s\n" "#define HAVE_SETSOCKOPT 1" >>confdefs.h fi @@ -18614,11 +21238,12 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket" >&5 -$as_echo_n "checking for socket... " >&6; } -if ${ac_cv_func_socket+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socket" >&5 +printf %s "checking for socket... " >&6; } +if test ${ac_cv_func_socket+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18628,26 +21253,28 @@ else #include int -main () +main (void) { void *x=socket ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_socket=yes -else +else $as_nop ac_cv_func_socket=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socket" >&5 -$as_echo "$ac_cv_func_socket" >&6; } - if test "x$ac_cv_func_socket" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socket" >&5 +printf "%s\n" "$ac_cv_func_socket" >&6; } + if test "x$ac_cv_func_socket" = xyes +then : -$as_echo "#define HAVE_SOCKET 1" >>confdefs.h +printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h fi @@ -18657,11 +21284,12 @@ fi # On some systems, setgroups is in unistd.h, on others, in grp.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setgroups" >&5 -$as_echo_n "checking for setgroups... " >&6; } -if ${ac_cv_func_setgroups+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setgroups" >&5 +printf %s "checking for setgroups... " >&6; } +if test ${ac_cv_func_setgroups+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18671,26 +21299,28 @@ else #endif int -main () +main (void) { void *x=setgroups ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_setgroups=yes -else +else $as_nop ac_cv_func_setgroups=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setgroups" >&5 -$as_echo "$ac_cv_func_setgroups" >&6; } - if test "x$ac_cv_func_setgroups" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setgroups" >&5 +printf "%s\n" "$ac_cv_func_setgroups" >&6; } + if test "x$ac_cv_func_setgroups" = xyes +then : -$as_echo "#define HAVE_SETGROUPS 1" >>confdefs.h +printf "%s\n" "#define HAVE_SETGROUPS 1" >>confdefs.h fi @@ -18699,20 +21329,21 @@ fi # check for openpty, login_tty, and forkpty -for ac_func in openpty + + for ac_func in openpty do : ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_OPENPTY 1 -_ACEOF - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 -$as_echo_n "checking for openpty in -lutil... " >&6; } -if ${ac_cv_lib_util_openpty+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_openpty" = xyes +then : + printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 +printf %s "checking for openpty in -lutil... " >&6; } +if test ${ac_cv_lib_util_openpty+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lutil $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -18721,38 +21352,38 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char openpty (); int -main () +main (void) { return openpty (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_util_openpty=yes -else +else $as_nop ac_cv_lib_util_openpty=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 -$as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = xyes; then : - $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 +printf "%s\n" "$ac_cv_lib_util_openpty" >&6; } +if test "x$ac_cv_lib_util_openpty" = xyes +then : + printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lutil" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 -$as_echo_n "checking for openpty in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_openpty+:} false; then : - $as_echo_n "(cached) " >&6 -else +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 +printf %s "checking for openpty in -lbsd... " >&6; } +if test ${ac_cv_lib_bsd_openpty+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -18761,44 +21392,44 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char openpty (); int -main () +main (void) { return openpty (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_bsd_openpty=yes -else +else $as_nop ac_cv_lib_bsd_openpty=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 -$as_echo "$ac_cv_lib_bsd_openpty" >&6; } -if test "x$ac_cv_lib_bsd_openpty" = xyes; then : - $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 +printf "%s\n" "$ac_cv_lib_bsd_openpty" >&6; } +if test "x$ac_cv_lib_bsd_openpty" = xyes +then : + printf "%s\n" "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi fi fi -done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 -$as_echo_n "checking for library containing login_tty... " >&6; } -if ${ac_cv_search_login_tty+:} false; then : - $as_echo_n "(cached) " >&6 -else +done +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 +printf %s "checking for library containing login_tty... " >&6; } +if test ${ac_cv_search_login_tty+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18806,67 +21437,70 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char login_tty (); int -main () +main (void) { return login_tty (); ; return 0; } _ACEOF -for ac_lib in '' util; do +for ac_lib in '' util +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_login_tty=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_login_tty+:} false; then : + if test ${ac_cv_search_login_tty+y} +then : break fi done -if ${ac_cv_search_login_tty+:} false; then : +if test ${ac_cv_search_login_tty+y} +then : -else +else $as_nop ac_cv_search_login_tty=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_login_tty" >&5 -$as_echo "$ac_cv_search_login_tty" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_login_tty" >&5 +printf "%s\n" "$ac_cv_search_login_tty" >&6; } ac_res=$ac_cv_search_login_tty -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -$as_echo "#define HAVE_LOGIN_TTY 1" >>confdefs.h +printf "%s\n" "#define HAVE_LOGIN_TTY 1" >>confdefs.h fi -for ac_func in forkpty + + for ac_func in forkpty do : ac_fn_c_check_func "$LINENO" "forkpty" "ac_cv_func_forkpty" -if test "x$ac_cv_func_forkpty" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_FORKPTY 1 -_ACEOF - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 -$as_echo_n "checking for forkpty in -lutil... " >&6; } -if ${ac_cv_lib_util_forkpty+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_forkpty" = xyes +then : + printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 +printf %s "checking for forkpty in -lutil... " >&6; } +if test ${ac_cv_lib_util_forkpty+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lutil $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -18875,38 +21509,38 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char forkpty (); int -main () +main (void) { return forkpty (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_util_forkpty=yes -else +else $as_nop ac_cv_lib_util_forkpty=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 -$as_echo "$ac_cv_lib_util_forkpty" >&6; } -if test "x$ac_cv_lib_util_forkpty" = xyes; then : - $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 +printf "%s\n" "$ac_cv_lib_util_forkpty" >&6; } +if test "x$ac_cv_lib_util_forkpty" = xyes +then : + printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lutil" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 -$as_echo_n "checking for forkpty in -lbsd... " >&6; } -if ${ac_cv_lib_bsd_forkpty+:} false; then : - $as_echo_n "(cached) " >&6 -else +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 +printf %s "checking for forkpty in -lbsd... " >&6; } +if test ${ac_cv_lib_bsd_forkpty+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -18915,59 +21549,84 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char forkpty (); int -main () +main (void) { return forkpty (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_bsd_forkpty=yes -else +else $as_nop ac_cv_lib_bsd_forkpty=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 -$as_echo "$ac_cv_lib_bsd_forkpty" >&6; } -if test "x$ac_cv_lib_bsd_forkpty" = xyes; then : - $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 +printf "%s\n" "$ac_cv_lib_bsd_forkpty" >&6; } +if test "x$ac_cv_lib_bsd_forkpty" = xyes +then : + printf "%s\n" "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi fi fi -done +done # check for long file support functions -for ac_func in fseek64 fseeko fstatvfs ftell64 ftello statvfs -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" +if test "x$ac_cv_func_fseek64" = xyes +then : + printf "%s\n" "#define HAVE_FSEEK64 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fseeko" "ac_cv_func_fseeko" +if test "x$ac_cv_func_fseeko" = xyes +then : + printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "fstatvfs" "ac_cv_func_fstatvfs" +if test "x$ac_cv_func_fstatvfs" = xyes +then : + printf "%s\n" "#define HAVE_FSTATVFS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ftell64" "ac_cv_func_ftell64" +if test "x$ac_cv_func_ftell64" = xyes +then : + printf "%s\n" "#define HAVE_FTELL64 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "ftello" "ac_cv_func_ftello" +if test "x$ac_cv_func_ftello" = xyes +then : + printf "%s\n" "#define HAVE_FTELLO 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "statvfs" "ac_cv_func_statvfs" +if test "x$ac_cv_func_statvfs" = xyes +then : + printf "%s\n" "#define HAVE_STATVFS 1" >>confdefs.h fi -done ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" -if test "x$ac_cv_func_dup2" = xyes; then : - $as_echo "#define HAVE_DUP2 1" >>confdefs.h +if test "x$ac_cv_func_dup2" = xyes +then : + printf "%s\n" "#define HAVE_DUP2 1" >>confdefs.h -else +else $as_nop case " $LIBOBJS " in *" dup2.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS dup2.$ac_objext" @@ -18977,90 +21636,92 @@ esac fi -for ac_func in getpgrp + for ac_func in getpgrp do : ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp" -if test "x$ac_cv_func_getpgrp" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETPGRP 1 -_ACEOF +if test "x$ac_cv_func_getpgrp" = xyes +then : + printf "%s\n" "#define HAVE_GETPGRP 1" >>confdefs.h cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { getpgrp(0); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -$as_echo "#define GETPGRP_HAVE_ARG 1" >>confdefs.h +printf "%s\n" "#define GETPGRP_HAVE_ARG 1" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi + done -for ac_func in setpgrp + for ac_func in setpgrp do : ac_fn_c_check_func "$LINENO" "setpgrp" "ac_cv_func_setpgrp" -if test "x$ac_cv_func_setpgrp" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SETPGRP 1 -_ACEOF +if test "x$ac_cv_func_setpgrp" = xyes +then : + printf "%s\n" "#define HAVE_SETPGRP 1" >>confdefs.h cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { setpgrp(0,0); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -$as_echo "#define SETPGRP_HAVE_ARG 1" >>confdefs.h +printf "%s\n" "#define SETPGRP_HAVE_ARG 1" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -done +done # check for namespace functions -for ac_func in setns unshare -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "setns" "ac_cv_func_setns" +if test "x$ac_cv_func_setns" = xyes +then : + printf "%s\n" "#define HAVE_SETNS 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "unshare" "ac_cv_func_unshare" +if test "x$ac_cv_func_unshare" = xyes +then : + printf "%s\n" "#define HAVE_UNSHARE 1" >>confdefs.h fi -done pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBCRYPT" >&5 -$as_echo_n "checking for LIBCRYPT... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBCRYPT" >&5 +printf %s "checking for LIBCRYPT... " >&6; } if test -n "$LIBCRYPT_CFLAGS"; then pkg_cv_LIBCRYPT_CFLAGS="$LIBCRYPT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxcrypt >= 3.1.1\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxcrypt >= 3.1.1\""; } >&5 ($PKG_CONFIG --exists --print-errors "libxcrypt >= 3.1.1") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBCRYPT_CFLAGS=`$PKG_CONFIG --cflags "libxcrypt >= 3.1.1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -19074,10 +21735,10 @@ if test -n "$LIBCRYPT_LIBS"; then pkg_cv_LIBCRYPT_LIBS="$LIBCRYPT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxcrypt >= 3.1.1\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libxcrypt >= 3.1.1\""; } >&5 ($PKG_CONFIG --exists --print-errors "libxcrypt >= 3.1.1") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBCRYPT_LIBS=`$PKG_CONFIG --libs "libxcrypt >= 3.1.1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -19091,8 +21752,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -19114,11 +21775,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt_r" >&5 -$as_echo_n "checking for library containing crypt_r... " >&6; } -if ${ac_cv_search_crypt_r+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing crypt_r" >&5 +printf %s "checking for library containing crypt_r... " >&6; } +if test ${ac_cv_search_crypt_r+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19126,49 +21788,51 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char crypt_r (); int -main () +main (void) { return crypt_r (); ; return 0; } _ACEOF -for ac_lib in '' crypt; do +for ac_lib in '' crypt +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_crypt_r=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_crypt_r+:} false; then : + if test ${ac_cv_search_crypt_r+y} +then : break fi done -if ${ac_cv_search_crypt_r+:} false; then : +if test ${ac_cv_search_crypt_r+y} +then : -else +else $as_nop ac_cv_search_crypt_r=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt_r" >&5 -$as_echo "$ac_cv_search_crypt_r" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt_r" >&5 +printf "%s\n" "$ac_cv_search_crypt_r" >&6; } ac_res=$ac_cv_search_crypt_r -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - $as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h + printf "%s\n" "#define HAVE_CRYPT_R 1" >>confdefs.h if test "$ac_cv_search_crypt_r" = "none required"; then libcrypt= @@ -19188,8 +21852,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -19197,11 +21861,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt_r" >&5 -$as_echo_n "checking for library containing crypt_r... " >&6; } -if ${ac_cv_search_crypt_r+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing crypt_r" >&5 +printf %s "checking for library containing crypt_r... " >&6; } +if test ${ac_cv_search_crypt_r+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19209,49 +21874,51 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char crypt_r (); int -main () +main (void) { return crypt_r (); ; return 0; } _ACEOF -for ac_lib in '' crypt; do +for ac_lib in '' crypt +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_crypt_r=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_crypt_r+:} false; then : + if test ${ac_cv_search_crypt_r+y} +then : break fi done -if ${ac_cv_search_crypt_r+:} false; then : +if test ${ac_cv_search_crypt_r+y} +then : -else +else $as_nop ac_cv_search_crypt_r=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt_r" >&5 -$as_echo "$ac_cv_search_crypt_r" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt_r" >&5 +printf "%s\n" "$ac_cv_search_crypt_r" >&6; } ac_res=$ac_cv_search_crypt_r -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - $as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h + printf "%s\n" "#define HAVE_CRYPT_R 1" >>confdefs.h if test "$ac_cv_search_crypt_r" = "none required"; then libcrypt= @@ -19273,10 +21940,10 @@ LIBS=$save_LIBS else LIBCRYPT_CFLAGS=$pkg_cv_LIBCRYPT_CFLAGS LIBCRYPT_LIBS=$pkg_cv_LIBCRYPT_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } - $as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h + printf "%s\n" "#define HAVE_CRYPT_R 1" >>confdefs.h fi @@ -19289,11 +21956,12 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBCRYPT_CFLAGS" LIBS="$LIBCRYPT_LIBS $LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt or crypt_r" >&5 -$as_echo_n "checking for crypt or crypt_r... " >&6; } -if ${ac_cv_crypt_crypt+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for crypt or crypt_r" >&5 +printf %s "checking for crypt or crypt_r... " >&6; } +if test ${ac_cv_crypt_crypt+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19304,7 +21972,7 @@ else #include int -main () +main (void) { #ifdef HAVE_CRYPT_R @@ -19318,17 +21986,18 @@ main () } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_crypt_crypt=yes -else +else $as_nop ac_cv_crypt_crypt=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_crypt_crypt" >&5 -$as_echo "$ac_cv_crypt_crypt" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_crypt_crypt" >&5 +printf "%s\n" "$ac_cv_crypt_crypt" >&6; } CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS @@ -19337,21 +22006,22 @@ LIBS=$save_LIBS -for ac_func in clock_gettime + + for ac_func in clock_gettime do : ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" -if test "x$ac_cv_func_clock_gettime" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_CLOCK_GETTIME 1 -_ACEOF - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 -$as_echo_n "checking for clock_gettime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_gettime+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_clock_gettime" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19360,60 +22030,60 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_gettime (); int -main () +main (void) { return clock_gettime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_gettime=yes -else +else $as_nop ac_cv_lib_rt_clock_gettime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 -$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } -if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : LIBS="$LIBS -lrt" - $as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h + printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h -$as_echo "#define TIMEMODULE_LIB rt" >>confdefs.h +printf "%s\n" "#define TIMEMODULE_LIB rt" >>confdefs.h fi fi + done -for ac_func in clock_getres + for ac_func in clock_getres do : ac_fn_c_check_func "$LINENO" "clock_getres" "ac_cv_func_clock_getres" -if test "x$ac_cv_func_clock_getres" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_CLOCK_GETRES 1 -_ACEOF - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_getres in -lrt" >&5 -$as_echo_n "checking for clock_getres in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_getres+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_clock_getres" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_getres in -lrt" >&5 +printf %s "checking for clock_getres in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_getres+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19422,56 +22092,56 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_getres (); int -main () +main (void) { return clock_getres (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_getres=yes -else +else $as_nop ac_cv_lib_rt_clock_getres=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_getres" >&5 -$as_echo "$ac_cv_lib_rt_clock_getres" >&6; } -if test "x$ac_cv_lib_rt_clock_getres" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_getres" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_getres" >&6; } +if test "x$ac_cv_lib_rt_clock_getres" = xyes +then : - $as_echo "#define HAVE_CLOCK_GETRES 1" >>confdefs.h + printf "%s\n" "#define HAVE_CLOCK_GETRES 1" >>confdefs.h fi fi + done -for ac_func in clock_settime + for ac_func in clock_settime do : ac_fn_c_check_func "$LINENO" "clock_settime" "ac_cv_func_clock_settime" -if test "x$ac_cv_func_clock_settime" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_CLOCK_SETTIME 1 -_ACEOF - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5 -$as_echo_n "checking for clock_settime in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_settime+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_clock_settime" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5 +printf %s "checking for clock_settime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_settime+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19480,114 +22150,114 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char clock_settime (); int -main () +main (void) { return clock_settime (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_settime=yes -else +else $as_nop ac_cv_lib_rt_clock_settime=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_settime" >&5 -$as_echo "$ac_cv_lib_rt_clock_settime" >&6; } -if test "x$ac_cv_lib_rt_clock_settime" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_settime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_settime" >&6; } +if test "x$ac_cv_lib_rt_clock_settime" = xyes +then : - $as_echo "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h + printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h fi fi + done -for ac_func in clock_nanosleep + for ac_func in clock_nanosleep do : ac_fn_c_check_func "$LINENO" "clock_nanosleep" "ac_cv_func_clock_nanosleep" -if test "x$ac_cv_func_clock_nanosleep" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_CLOCK_NANOSLEEP 1 -_ACEOF - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_nanosleep in -lrt" >&5 -$as_echo_n "checking for clock_nanosleep in -lrt... " >&6; } -if ${ac_cv_lib_rt_clock_nanosleep+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_clock_nanosleep" = xyes +then : + printf "%s\n" "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_nanosleep in -lrt" >&5 +printf %s "checking for clock_nanosleep in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_nanosleep+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ char clock_nanosleep (); int -main () +main (void) { return clock_nanosleep (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_clock_nanosleep=yes -else +else $as_nop ac_cv_lib_rt_clock_nanosleep=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_nanosleep" >&5 -$as_echo "$ac_cv_lib_rt_clock_nanosleep" >&6; } -if test "x$ac_cv_lib_rt_clock_nanosleep" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_nanosleep" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_nanosleep" >&6; } +if test "x$ac_cv_lib_rt_clock_nanosleep" = xyes +then : - $as_echo "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h + printf "%s\n" "#define HAVE_CLOCK_NANOSLEEP 1" >>confdefs.h fi fi + done -for ac_func in nanosleep + for ac_func in nanosleep do : ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep" -if test "x$ac_cv_func_nanosleep" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_NANOSLEEP 1 -_ACEOF - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5 -$as_echo_n "checking for nanosleep in -lrt... " >&6; } -if ${ac_cv_lib_rt_nanosleep+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func_nanosleep" = xyes +then : + printf "%s\n" "#define HAVE_NANOSLEEP 1" >>confdefs.h + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5 +printf %s "checking for nanosleep in -lrt... " >&6; } +if test ${ac_cv_lib_rt_nanosleep+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -19596,46 +22266,46 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char nanosleep (); int -main () +main (void) { return nanosleep (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_rt_nanosleep=yes -else +else $as_nop ac_cv_lib_rt_nanosleep=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5 -$as_echo "$ac_cv_lib_rt_nanosleep" >&6; } -if test "x$ac_cv_lib_rt_nanosleep" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5 +printf "%s\n" "$ac_cv_lib_rt_nanosleep" >&6; } +if test "x$ac_cv_lib_rt_nanosleep" = xyes +then : - $as_echo "#define HAVE_NANOSLEEP 1" >>confdefs.h + printf "%s\n" "#define HAVE_NANOSLEEP 1" >>confdefs.h fi fi -done +done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for major, minor, and makedev" >&5 -$as_echo_n "checking for major, minor, and makedev... " >&6; } -if ${ac_cv_device_macros+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for major, minor, and makedev" >&5 +printf %s "checking for major, minor, and makedev... " >&6; } +if test ${ac_cv_device_macros+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19649,7 +22319,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #endif int -main () +main (void) { makedev(major(0),minor(0)); @@ -19658,36 +22328,39 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_device_macros=yes -else +else $as_nop ac_cv_device_macros=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_device_macros" >&5 -$as_echo "$ac_cv_device_macros" >&6; } -if test "x$ac_cv_device_macros" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_device_macros" >&5 +printf "%s\n" "$ac_cv_device_macros" >&6; } +if test "x$ac_cv_device_macros" = xyes +then : -$as_echo "#define HAVE_DEVICE_MACROS 1" >>confdefs.h +printf "%s\n" "#define HAVE_DEVICE_MACROS 1" >>confdefs.h fi -$as_echo "#define SYS_SELECT_WITH_SYS_TIME 1" >>confdefs.h +printf "%s\n" "#define SYS_SELECT_WITH_SYS_TIME 1" >>confdefs.h # On OSF/1 V5.1, getaddrinfo is available, but a define # for [no]getaddrinfo in netdb.h. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5 -$as_echo_n "checking for getaddrinfo... " >&6; } -if ${ac_cv_func_getaddrinfo+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5 +printf %s "checking for getaddrinfo... " >&6; } +if test ${ac_cv_func_getaddrinfo+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19698,40 +22371,44 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include int -main () +main (void) { getaddrinfo(NULL, NULL, NULL, NULL); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_func_getaddrinfo=yes -else +else $as_nop ac_cv_func_getaddrinfo=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getaddrinfo" >&5 -$as_echo "$ac_cv_func_getaddrinfo" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getaddrinfo" >&5 +printf "%s\n" "$ac_cv_func_getaddrinfo" >&6; } -if test "x$ac_cv_func_getaddrinfo" = xyes; then : +if test "x$ac_cv_func_getaddrinfo" = xyes +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking getaddrinfo bug" >&5 -$as_echo_n "checking getaddrinfo bug... " >&6; } -if ${ac_cv_buggy_getaddrinfo+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking getaddrinfo bug" >&5 +printf %s "checking getaddrinfo bug... " >&6; } +if test ${ac_cv_buggy_getaddrinfo+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : if test "${enable_ipv6+set}" = set; then ac_cv_buggy_getaddrinfo="no -- configured with --(en|dis)able-ipv6" else ac_cv_buggy_getaddrinfo=yes fi -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19825,9 +22502,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_buggy_getaddrinfo=no -else +else $as_nop ac_cv_buggy_getaddrinfo=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -19835,50 +22513,48 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_buggy_getaddrinfo" >&5 -$as_echo "$ac_cv_buggy_getaddrinfo" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_buggy_getaddrinfo" >&5 +printf "%s\n" "$ac_cv_buggy_getaddrinfo" >&6; } fi if test "$ac_cv_func_getaddrinfo" = no -o "$ac_cv_buggy_getaddrinfo" = yes then - if test "x$ipv6" = xyes; then : + if test "x$ipv6" = xyes +then : as_fn_error $? "You must get working getaddrinfo() function or pass the \"--disable-ipv6\" option to configure." "$LINENO" 5 fi else -$as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h fi -for ac_func in getnameinfo -do : - ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" -if test "x$ac_cv_func_getnameinfo" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETNAMEINFO 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" +if test "x$ac_cv_func_getnameinfo" = xyes +then : + printf "%s\n" "#define HAVE_GETNAMEINFO 1" >>confdefs.h fi -done # checks for structures -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 -$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if ${ac_cv_struct_tm+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +printf %s "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if test ${ac_cv_struct_tm+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { struct tm tm; int *p = &tm.tm_sec; @@ -19887,18 +22563,19 @@ struct tm tm; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_struct_tm=time.h -else +else $as_nop ac_cv_struct_tm=sys/time.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 -$as_echo "$ac_cv_struct_tm" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +printf "%s\n" "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then -$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h +printf "%s\n" "#define TM_IN_SYS_TIME 1" >>confdefs.h fi @@ -19906,37 +22583,35 @@ ac_fn_c_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_TM_TM_ZONE 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_TM_TM_ZONE 1" >>confdefs.h fi if test "$ac_cv_member_struct_tm_tm_zone" = yes; then -$as_echo "#define HAVE_TM_ZONE 1" >>confdefs.h +printf "%s\n" "#define HAVE_TM_ZONE 1" >>confdefs.h else - ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include -" -if test "x$ac_cv_have_decl_tzname" = xyes; then : + ac_fn_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_tzname" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi +printf "%s\n" "#define HAVE_DECL_TZNAME $ac_have_decl" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_TZNAME $ac_have_decl -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 -$as_echo_n "checking for tzname... " >&6; } -if ${ac_cv_var_tzname+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 +printf %s "checking for tzname... " >&6; } +if test ${ac_cv_var_tzname+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -19945,86 +22620,81 @@ extern char *tzname[]; #endif int -main () +main (void) { return tzname[0][0]; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_var_tzname=yes -else +else $as_nop ac_cv_var_tzname=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 -$as_echo "$ac_cv_var_tzname" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 +printf "%s\n" "$ac_cv_var_tzname" >&6; } if test $ac_cv_var_tzname = yes; then -$as_echo "#define HAVE_TZNAME 1" >>confdefs.h +printf "%s\n" "#define HAVE_TZNAME 1" >>confdefs.h fi fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_rdev" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_RDEV 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_RDEV 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_blksize" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BLKSIZE 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_flags" "ac_cv_member_struct_stat_st_flags" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_flags" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_flags" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_FLAGS 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_FLAGS 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_gen" "ac_cv_member_struct_stat_st_gen" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_gen" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_gen" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_GEN 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_GEN 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : +if test "x$ac_cv_member_struct_stat_st_blocks" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STAT_ST_BLOCKS 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BLOCKS 1" >>confdefs.h fi @@ -20034,11 +22704,10 @@ ac_fn_c_check_member "$LINENO" "struct passwd" "pw_gecos" "ac_cv_member_struct_p #include " -if test "x$ac_cv_member_struct_passwd_pw_gecos" = xyes; then : +if test "x$ac_cv_member_struct_passwd_pw_gecos" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_PASSWD_PW_GECOS 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_PASSWD_PW_GECOS 1" >>confdefs.h fi @@ -20047,11 +22716,10 @@ ac_fn_c_check_member "$LINENO" "struct passwd" "pw_passwd" "ac_cv_member_struct_ #include " -if test "x$ac_cv_member_struct_passwd_pw_passwd" = xyes; then : +if test "x$ac_cv_member_struct_passwd_pw_passwd" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_PASSWD_PW_PASSWD 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_PASSWD_PW_PASSWD 1" >>confdefs.h fi @@ -20059,118 +22727,124 @@ fi # Issue #21085: In Cygwin, siginfo_t does not have si_band field. ac_fn_c_check_member "$LINENO" "siginfo_t" "si_band" "ac_cv_member_siginfo_t_si_band" "#include " -if test "x$ac_cv_member_siginfo_t_si_band" = xyes; then : +if test "x$ac_cv_member_siginfo_t_si_band" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_SIGINFO_T_SI_BAND 1 -_ACEOF +printf "%s\n" "#define HAVE_SIGINFO_T_SI_BAND 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 -$as_echo_n "checking for time.h that defines altzone... " >&6; } -if ${ac_cv_header_time_altzone+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 +printf %s "checking for time.h that defines altzone... " >&6; } +if test ${ac_cv_header_time_altzone+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { return altzone; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_header_time_altzone=yes -else +else $as_nop ac_cv_header_time_altzone=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time_altzone" >&5 -$as_echo "$ac_cv_header_time_altzone" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time_altzone" >&5 +printf "%s\n" "$ac_cv_header_time_altzone" >&6; } if test $ac_cv_header_time_altzone = yes; then -$as_echo "#define HAVE_ALTZONE 1" >>confdefs.h +printf "%s\n" "#define HAVE_ALTZONE 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for addrinfo" >&5 -$as_echo_n "checking for addrinfo... " >&6; } -if ${ac_cv_struct_addrinfo+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for addrinfo" >&5 +printf %s "checking for addrinfo... " >&6; } +if test ${ac_cv_struct_addrinfo+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { struct addrinfo a ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_struct_addrinfo=yes -else +else $as_nop ac_cv_struct_addrinfo=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_addrinfo" >&5 -$as_echo "$ac_cv_struct_addrinfo" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_addrinfo" >&5 +printf "%s\n" "$ac_cv_struct_addrinfo" >&6; } if test $ac_cv_struct_addrinfo = yes; then -$as_echo "#define HAVE_ADDRINFO 1" >>confdefs.h +printf "%s\n" "#define HAVE_ADDRINFO 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_storage" >&5 -$as_echo_n "checking for sockaddr_storage... " >&6; } -if ${ac_cv_struct_sockaddr_storage+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sockaddr_storage" >&5 +printf %s "checking for sockaddr_storage... " >&6; } +if test ${ac_cv_struct_sockaddr_storage+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include # include int -main () +main (void) { struct sockaddr_storage s ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_struct_sockaddr_storage=yes -else +else $as_nop ac_cv_struct_sockaddr_storage=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_storage" >&5 -$as_echo "$ac_cv_struct_sockaddr_storage" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_storage" >&5 +printf "%s\n" "$ac_cv_struct_sockaddr_storage" >&6; } if test $ac_cv_struct_sockaddr_storage = yes; then -$as_echo "#define HAVE_SOCKADDR_STORAGE 1" >>confdefs.h +printf "%s\n" "#define HAVE_SOCKADDR_STORAGE 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_alg" >&5 -$as_echo_n "checking for sockaddr_alg... " >&6; } -if ${ac_cv_struct_sockaddr_alg+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sockaddr_alg" >&5 +printf %s "checking for sockaddr_alg... " >&6; } +if test ${ac_cv_struct_sockaddr_alg+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20178,40 +22852,42 @@ else # include # include int -main () +main (void) { struct sockaddr_alg s ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_struct_sockaddr_alg=yes -else +else $as_nop ac_cv_struct_sockaddr_alg=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_alg" >&5 -$as_echo "$ac_cv_struct_sockaddr_alg" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_alg" >&5 +printf "%s\n" "$ac_cv_struct_sockaddr_alg" >&6; } if test $ac_cv_struct_sockaddr_alg = yes; then -$as_echo "#define HAVE_SOCKADDR_ALG 1" >>confdefs.h +printf "%s\n" "#define HAVE_SOCKADDR_ALG 1" >>confdefs.h fi # checks for compiler characteristics -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 -$as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +printf %s "checking for an ANSI C-conforming const... " >&6; } +if test ${ac_cv_c_const+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __cplusplus @@ -20224,7 +22900,7 @@ main () /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. + /* IBM XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ @@ -20252,7 +22928,7 @@ main () iptr p = 0; ++p; } - { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; @@ -20268,88 +22944,95 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_const=yes -else +else $as_nop ac_cv_c_const=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 -$as_echo "$ac_cv_c_const" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +printf "%s\n" "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then -$as_echo "#define const /**/" >>confdefs.h +printf "%s\n" "#define const /**/" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working signed char" >&5 -$as_echo_n "checking for working signed char... " >&6; } -if ${ac_cv_working_signed_char_c+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working signed char" >&5 +printf %s "checking for working signed char... " >&6; } +if test ${ac_cv_working_signed_char_c+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { signed char c; ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_working_signed_char_c=yes -else +else $as_nop ac_cv_working_signed_char_c=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_signed_char_c" >&5 -$as_echo "$ac_cv_working_signed_char_c" >&6; } -if test "x$ac_cv_working_signed_char_c" = xno; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_signed_char_c" >&5 +printf "%s\n" "$ac_cv_working_signed_char_c" >&6; } +if test "x$ac_cv_working_signed_char_c" = xno +then : -$as_echo "#define signed /**/" >>confdefs.h +printf "%s\n" "#define signed /**/" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for prototypes" >&5 -$as_echo_n "checking for prototypes... " >&6; } -if ${ac_cv_function_prototypes+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for prototypes" >&5 +printf %s "checking for prototypes... " >&6; } +if test ${ac_cv_function_prototypes+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo(int x) { return 0; } int -main () +main (void) { return foo(10); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_function_prototypes=yes -else +else $as_nop ac_cv_function_prototypes=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_function_prototypes" >&5 -$as_echo "$ac_cv_function_prototypes" >&6; } -if test "x$ac_cv_function_prototypes" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_function_prototypes" >&5 +printf "%s\n" "$ac_cv_function_prototypes" >&6; } +if test "x$ac_cv_function_prototypes" = xyes +then : -$as_echo "#define HAVE_PROTOTYPES 1" >>confdefs.h +printf "%s\n" "#define HAVE_PROTOTYPES 1" >>confdefs.h fi @@ -20358,11 +23041,12 @@ fi # check for socketpair - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socketpair" >&5 -$as_echo_n "checking for socketpair... " >&6; } -if ${ac_cv_func_socketpair+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socketpair" >&5 +printf %s "checking for socketpair... " >&6; } +if test ${ac_cv_func_socketpair+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20370,26 +23054,28 @@ else #include int -main () +main (void) { void *x=socketpair ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_func_socketpair=yes -else +else $as_nop ac_cv_func_socketpair=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socketpair" >&5 -$as_echo "$ac_cv_func_socketpair" >&6; } - if test "x$ac_cv_func_socketpair" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_socketpair" >&5 +printf "%s\n" "$ac_cv_func_socketpair" >&6; } + if test "x$ac_cv_func_socketpair" = xyes +then : -$as_echo "#define HAVE_SOCKETPAIR 1" >>confdefs.h +printf "%s\n" "#define HAVE_SOCKETPAIR 1" >>confdefs.h fi @@ -20397,18 +23083,19 @@ fi # check if sockaddr has sa_len member -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if sockaddr has sa_len member" >&5 -$as_echo_n "checking if sockaddr has sa_len member... " >&6; } -if ${ac_cv_struct_sockaddr_sa_len+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if sockaddr has sa_len member" >&5 +printf %s "checking if sockaddr has sa_len member... " >&6; } +if test ${ac_cv_struct_sockaddr_sa_len+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int -main () +main (void) { struct sockaddr x; x.sa_len = 0; @@ -20416,20 +23103,22 @@ x.sa_len = 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_struct_sockaddr_sa_len=yes -else +else $as_nop ac_cv_struct_sockaddr_sa_len=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_sa_len" >&5 -$as_echo "$ac_cv_struct_sockaddr_sa_len" >&6; } -if test "x$ac_cv_struct_sockaddr_sa_len" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_sockaddr_sa_len" >&5 +printf "%s\n" "$ac_cv_struct_sockaddr_sa_len" >&6; } +if test "x$ac_cv_struct_sockaddr_sa_len" = xyes +then : -$as_echo "#define HAVE_SOCKADDR_SA_LEN 1" >>confdefs.h +printf "%s\n" "#define HAVE_SOCKADDR_SA_LEN 1" >>confdefs.h fi @@ -20438,11 +23127,12 @@ fi ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" -if test "x$ac_cv_func_gethostbyname_r" = xyes; then : - $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h +if test "x$ac_cv_func_gethostbyname_r" = xyes +then : + printf "%s\n" "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 6 args" >&5 -$as_echo_n "checking gethostbyname_r with 6 args... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 6 args" >&5 +printf %s "checking gethostbyname_r with 6 args... " >&6; } OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20451,7 +23141,7 @@ $as_echo_n "checking gethostbyname_r with 6 args... " >&6; } # include int -main () +main (void) { char *name; @@ -20466,29 +23156,30 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : - $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h + printf "%s\n" "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h -$as_echo "#define HAVE_GETHOSTBYNAME_R_6_ARG 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R_6_ARG 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 5 args" >&5 -$as_echo_n "checking gethostbyname_r with 5 args... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 5 args" >&5 +printf %s "checking gethostbyname_r with 5 args... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include int -main () +main (void) { char *name; @@ -20503,29 +23194,30 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : - $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h + printf "%s\n" "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h -$as_echo "#define HAVE_GETHOSTBYNAME_R_5_ARG 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R_5_ARG 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 3 args" >&5 -$as_echo_n "checking gethostbyname_r with 3 args... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking gethostbyname_r with 3 args" >&5 +printf %s "checking gethostbyname_r with 3 args... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include int -main () +main (void) { char *name; @@ -20538,43 +23230,40 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : - $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h + printf "%s\n" "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h -$as_echo "#define HAVE_GETHOSTBYNAME_R_3_ARG 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETHOSTBYNAME_R_3_ARG 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$OLD_CFLAGS -else +else $as_nop - for ac_func in gethostbyname -do : ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETHOSTBYNAME 1 -_ACEOF +if test "x$ac_cv_func_gethostbyname" = xyes +then : + printf "%s\n" "#define HAVE_GETHOSTBYNAME 1" >>confdefs.h fi -done fi @@ -20590,14 +23279,16 @@ fi # Linux requires this for correct f.p. operations ac_fn_c_check_func "$LINENO" "__fpu_control" "ac_cv_func___fpu_control" -if test "x$ac_cv_func___fpu_control" = xyes; then : - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 -$as_echo_n "checking for __fpu_control in -lieee... " >&6; } -if ${ac_cv_lib_ieee___fpu_control+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test "x$ac_cv_func___fpu_control" = xyes +then : + +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 +printf %s "checking for __fpu_control in -lieee... " >&6; } +if test ${ac_cv_lib_ieee___fpu_control+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lieee $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20606,33 +23297,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char __fpu_control (); int -main () +main (void) { return __fpu_control (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ieee___fpu_control=yes -else +else $as_nop ac_cv_lib_ieee___fpu_control=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 -$as_echo "$ac_cv_lib_ieee___fpu_control" >&6; } -if test "x$ac_cv_lib_ieee___fpu_control" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBIEEE 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 +printf "%s\n" "$ac_cv_lib_ieee___fpu_control" >&6; } +if test "x$ac_cv_lib_ieee___fpu_control" = xyes +then : + printf "%s\n" "#define HAVE_LIBIEEE 1" >>confdefs.h LIBS="-lieee $LIBS" @@ -20648,49 +23336,51 @@ case $ac_sys_system in Darwin) ;; *) LIBM=-lm esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-libm=STRING" >&5 -$as_echo_n "checking for --with-libm=STRING... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-libm=STRING" >&5 +printf %s "checking for --with-libm=STRING... " >&6; } # Check whether --with-libm was given. -if test "${with_libm+set}" = set; then : +if test ${with_libm+y} +then : withval=$with_libm; if test "$withval" = no then LIBM= - { $as_echo "$as_me:${as_lineno-$LINENO}: result: force LIBM empty" >&5 -$as_echo "force LIBM empty" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: force LIBM empty" >&5 +printf "%s\n" "force LIBM empty" >&6; } elif test "$withval" != yes then LIBM=$withval - { $as_echo "$as_me:${as_lineno-$LINENO}: result: set LIBM=\"$withval\"" >&5 -$as_echo "set LIBM=\"$withval\"" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: set LIBM=\"$withval\"" >&5 +printf "%s\n" "set LIBM=\"$withval\"" >&6; } else as_fn_error $? "proper usage is --with-libm=STRING" "$LINENO" 5 fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 -$as_echo "default LIBM=\"$LIBM\"" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 +printf "%s\n" "default LIBM=\"$LIBM\"" >&6; } fi # check for --with-libc=... -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-libc=STRING" >&5 -$as_echo_n "checking for --with-libc=STRING... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-libc=STRING" >&5 +printf %s "checking for --with-libc=STRING... " >&6; } # Check whether --with-libc was given. -if test "${with_libc+set}" = set; then : +if test ${with_libc+y} +then : withval=$with_libc; if test "$withval" = no then LIBC= - { $as_echo "$as_me:${as_lineno-$LINENO}: result: force LIBC empty" >&5 -$as_echo "force LIBC empty" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: force LIBC empty" >&5 +printf "%s\n" "force LIBC empty" >&6; } elif test "$withval" != yes then LIBC=$withval - { $as_echo "$as_me:${as_lineno-$LINENO}: result: set LIBC=\"$withval\"" >&5 -$as_echo "set LIBC=\"$withval\"" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: set LIBC=\"$withval\"" >&5 +printf "%s\n" "set LIBC=\"$withval\"" >&6; } else as_fn_error $? "proper usage is --with-libc=STRING" "$LINENO" 5 fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 -$as_echo "default LIBC=\"$LIBC\"" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 +printf "%s\n" "default LIBC=\"$LIBC\"" >&6; } fi @@ -20699,17 +23389,18 @@ fi # ************************************** -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x64 gcc inline assembler" >&5 -$as_echo_n "checking for x64 gcc inline assembler... " >&6; } -if ${ac_cv_gcc_asm_for_x64+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for x64 gcc inline assembler" >&5 +printf %s "checking for x64 gcc inline assembler... " >&6; } +if test ${ac_cv_gcc_asm_for_x64+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { __asm__ __volatile__ ("movq %rcx, %rax"); @@ -20718,22 +23409,24 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_gcc_asm_for_x64=yes -else +else $as_nop ac_cv_gcc_asm_for_x64=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x64" >&5 -$as_echo "$ac_cv_gcc_asm_for_x64" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x64" >&5 +printf "%s\n" "$ac_cv_gcc_asm_for_x64" >&6; } -if test "x$ac_cv_gcc_asm_for_x64" = xyes; then : +if test "x$ac_cv_gcc_asm_for_x64" = xyes +then : -$as_echo "#define HAVE_GCC_ASM_FOR_X64 1" >>confdefs.h +printf "%s\n" "#define HAVE_GCC_ASM_FOR_X64 1" >>confdefs.h fi @@ -20742,11 +23435,12 @@ fi # * Check for various properties of floating point * # ************************************************** -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether float word ordering is bigendian" >&5 -$as_echo_n "checking whether float word ordering is bigendian... " >&6; } -if ${ax_cv_c_float_words_bigendian+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether float word ordering is bigendian" >&5 +printf %s "checking whether float word ordering is bigendian... " >&6; } +if test ${ax_cv_c_float_words_bigendian+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_cv_c_float_words_bigendian=unknown @@ -20758,7 +23452,8 @@ double d = 909042349670368103374704789055050114762116927356156320147971208440534 _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : if grep noonsees conftest.$ac_objext >/dev/null ; then @@ -20774,15 +23469,15 @@ fi fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_float_words_bigendian" >&5 -$as_echo "$ax_cv_c_float_words_bigendian" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_float_words_bigendian" >&5 +printf "%s\n" "$ax_cv_c_float_words_bigendian" >&6; } case $ax_cv_c_float_words_bigendian in yes) -$as_echo "#define FLOAT_WORDS_BIGENDIAN 1" >>confdefs.h +printf "%s\n" "#define FLOAT_WORDS_BIGENDIAN 1" >>confdefs.h ;; no) ;; @@ -20799,12 +23494,12 @@ esac if test "$ax_cv_c_float_words_bigendian" = "yes" then -$as_echo "#define DOUBLE_IS_BIG_ENDIAN_IEEE754 1" >>confdefs.h +printf "%s\n" "#define DOUBLE_IS_BIG_ENDIAN_IEEE754 1" >>confdefs.h elif test "$ax_cv_c_float_words_bigendian" = "no" then -$as_echo "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h +printf "%s\n" "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h else # Some ARM platforms use a mixed-endian representation for doubles. @@ -20814,7 +23509,7 @@ else # FLOAT_WORDS_BIGENDIAN doesnt actually detect this case, but if it's not big # or little, then it must be this? -$as_echo "#define DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 1" >>confdefs.h +printf "%s\n" "#define DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 1" >>confdefs.h fi @@ -20828,17 +23523,18 @@ fi # This inline assembler syntax may also work for suncc and icc, # so we try it on all platforms. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can use gcc inline assembler to get and set x87 control word" >&5 -$as_echo_n "checking whether we can use gcc inline assembler to get and set x87 control word... " >&6; } -if ${ac_cv_gcc_asm_for_x87+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we can use gcc inline assembler to get and set x87 control word" >&5 +printf %s "checking whether we can use gcc inline assembler to get and set x87 control word... " >&6; } +if test ${ac_cv_gcc_asm_for_x87+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { unsigned short cw; @@ -20849,36 +23545,39 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_gcc_asm_for_x87=yes -else +else $as_nop ac_cv_gcc_asm_for_x87=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x87" >&5 -$as_echo "$ac_cv_gcc_asm_for_x87" >&6; } -if test "x$ac_cv_gcc_asm_for_x87" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_x87" >&5 +printf "%s\n" "$ac_cv_gcc_asm_for_x87" >&6; } +if test "x$ac_cv_gcc_asm_for_x87" = xyes +then : -$as_echo "#define HAVE_GCC_ASM_FOR_X87 1" >>confdefs.h +printf "%s\n" "#define HAVE_GCC_ASM_FOR_X87 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can use gcc inline assembler to get and set mc68881 fpcr" >&5 -$as_echo_n "checking whether we can use gcc inline assembler to get and set mc68881 fpcr... " >&6; } -if ${ac_cv_gcc_asm_for_mc68881+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we can use gcc inline assembler to get and set mc68881 fpcr" >&5 +printf %s "checking whether we can use gcc inline assembler to get and set mc68881 fpcr... " >&6; } +if test ${ac_cv_gcc_asm_for_mc68881+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { unsigned int fpcr; @@ -20889,21 +23588,23 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_gcc_asm_for_mc68881=yes -else +else $as_nop ac_cv_gcc_asm_for_mc68881=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_mc68881" >&5 -$as_echo "$ac_cv_gcc_asm_for_mc68881" >&6; } -if test "x$ac_cv_gcc_asm_for_mc68881" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gcc_asm_for_mc68881" >&5 +printf "%s\n" "$ac_cv_gcc_asm_for_mc68881" >&6; } +if test "x$ac_cv_gcc_asm_for_mc68881" = xyes +then : -$as_echo "#define HAVE_GCC_ASM_FOR_MC68881 1" >>confdefs.h +printf "%s\n" "#define HAVE_GCC_ASM_FOR_MC68881 1" >>confdefs.h fi @@ -20913,18 +23614,20 @@ fi # IEEE 754 platforms. On IEEE 754, test should return 1 if rounding # mode is round-to-nearest and double rounding issues are present, and # 0 otherwise. See https://github.com/python/cpython/issues/47186 for more info. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x87-style double rounding" >&5 -$as_echo_n "checking for x87-style double rounding... " >&6; } -if ${ac_cv_x87_double_rounding+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for x87-style double rounding" >&5 +printf %s "checking for x87-style double rounding... " >&6; } +if test ${ac_cv_x87_double_rounding+y} +then : + printf %s "(cached) " >&6 +else $as_nop # $BASECFLAGS may affect the result ac_save_cc="$CC" CC="$CC $BASECFLAGS" -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : ac_cv_x87_double_rounding=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20948,9 +23651,10 @@ int main(void) { } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_x87_double_rounding=no -else +else $as_nop ac_cv_x87_double_rounding=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -20960,13 +23664,14 @@ fi CC="$ac_save_cc" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x87_double_rounding" >&5 -$as_echo "$ac_cv_x87_double_rounding" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x87_double_rounding" >&5 +printf "%s\n" "$ac_cv_x87_double_rounding" >&6; } -if test "x$ac_cv_x87_double_rounding" = xyes; then : +if test "x$ac_cv_x87_double_rounding" = xyes +then : -$as_echo "#define X87_DOUBLE_ROUNDING 1" >>confdefs.h +printf "%s\n" "#define X87_DOUBLE_ROUNDING 1" >>confdefs.h fi @@ -20978,31 +23683,35 @@ fi LIBS_SAVE=$LIBS LIBS="$LIBS $LIBM" -for ac_func in acosh asinh atanh erf erfc expm1 log1p log2 + + for ac_func in acosh asinh atanh erf erfc expm1 log1p log2 do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` + as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF -else +else $as_nop as_fn_error $? "Python requires C99 compatible libm" "$LINENO" 5 fi -done +done LIBS=$LIBS_SAVE -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX semaphores are enabled" >&5 -$as_echo_n "checking whether POSIX semaphores are enabled... " >&6; } -if ${ac_cv_posix_semaphores_enabled+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX semaphores are enabled" >&5 +printf %s "checking whether POSIX semaphores are enabled... " >&6; } +if test ${ac_cv_posix_semaphores_enabled+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_posix_semaphores_enabled=yes -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21026,9 +23735,10 @@ else _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_posix_semaphores_enabled=yes -else +else $as_nop ac_cv_posix_semaphores_enabled=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -21037,24 +23747,27 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_posix_semaphores_enabled" >&5 -$as_echo "$ac_cv_posix_semaphores_enabled" >&6; } -if test "x$ac_cv_posix_semaphores_enabled" = xno; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_posix_semaphores_enabled" >&5 +printf "%s\n" "$ac_cv_posix_semaphores_enabled" >&6; } +if test "x$ac_cv_posix_semaphores_enabled" = xno +then : -$as_echo "#define POSIX_SEMAPHORES_NOT_ENABLED 1" >>confdefs.h +printf "%s\n" "#define POSIX_SEMAPHORES_NOT_ENABLED 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken sem_getvalue" >&5 -$as_echo_n "checking for broken sem_getvalue... " >&6; } -if ${ac_cv_broken_sem_getvalue+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken sem_getvalue" >&5 +printf %s "checking for broken sem_getvalue... " >&6; } +if test ${ac_cv_broken_sem_getvalue+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_broken_sem_getvalue=yes -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21082,9 +23795,10 @@ else _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_broken_sem_getvalue=no -else +else $as_nop ac_cv_broken_sem_getvalue=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -21093,111 +23807,97 @@ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_sem_getvalue" >&5 -$as_echo "$ac_cv_broken_sem_getvalue" >&6; } -if test "x$ac_cv_broken_sem_getvalue" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_sem_getvalue" >&5 +printf "%s\n" "$ac_cv_broken_sem_getvalue" >&6; } +if test "x$ac_cv_broken_sem_getvalue" = xyes +then : -$as_echo "#define HAVE_BROKEN_SEM_GETVALUE 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_SEM_GETVALUE 1" >>confdefs.h fi -ac_fn_c_check_decl "$LINENO" "RTLD_LAZY" "ac_cv_have_decl_RTLD_LAZY" "#include -" -if test "x$ac_cv_have_decl_RTLD_LAZY" = xyes; then : +ac_fn_check_decl "$LINENO" "RTLD_LAZY" "ac_cv_have_decl_RTLD_LAZY" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_LAZY" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_LAZY $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RTLD_NOW" "ac_cv_have_decl_RTLD_NOW" "#include -" -if test "x$ac_cv_have_decl_RTLD_NOW" = xyes; then : +printf "%s\n" "#define HAVE_DECL_RTLD_LAZY $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RTLD_NOW" "ac_cv_have_decl_RTLD_NOW" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_NOW" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_NOW $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RTLD_GLOBAL" "ac_cv_have_decl_RTLD_GLOBAL" "#include -" -if test "x$ac_cv_have_decl_RTLD_GLOBAL" = xyes; then : +printf "%s\n" "#define HAVE_DECL_RTLD_NOW $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RTLD_GLOBAL" "ac_cv_have_decl_RTLD_GLOBAL" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_GLOBAL" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_GLOBAL $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RTLD_LOCAL" "ac_cv_have_decl_RTLD_LOCAL" "#include -" -if test "x$ac_cv_have_decl_RTLD_LOCAL" = xyes; then : +printf "%s\n" "#define HAVE_DECL_RTLD_GLOBAL $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RTLD_LOCAL" "ac_cv_have_decl_RTLD_LOCAL" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_LOCAL" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_LOCAL $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RTLD_NODELETE" "ac_cv_have_decl_RTLD_NODELETE" "#include -" -if test "x$ac_cv_have_decl_RTLD_NODELETE" = xyes; then : +printf "%s\n" "#define HAVE_DECL_RTLD_LOCAL $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RTLD_NODELETE" "ac_cv_have_decl_RTLD_NODELETE" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_NODELETE" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_NODELETE $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RTLD_NOLOAD" "ac_cv_have_decl_RTLD_NOLOAD" "#include -" -if test "x$ac_cv_have_decl_RTLD_NOLOAD" = xyes; then : +printf "%s\n" "#define HAVE_DECL_RTLD_NODELETE $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RTLD_NOLOAD" "ac_cv_have_decl_RTLD_NOLOAD" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_NOLOAD" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_NOLOAD $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RTLD_DEEPBIND" "ac_cv_have_decl_RTLD_DEEPBIND" "#include -" -if test "x$ac_cv_have_decl_RTLD_DEEPBIND" = xyes; then : +printf "%s\n" "#define HAVE_DECL_RTLD_NOLOAD $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RTLD_DEEPBIND" "ac_cv_have_decl_RTLD_DEEPBIND" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_DEEPBIND" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_DEEPBIND $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "RTLD_MEMBER" "ac_cv_have_decl_RTLD_MEMBER" "#include -" -if test "x$ac_cv_have_decl_RTLD_MEMBER" = xyes; then : +printf "%s\n" "#define HAVE_DECL_RTLD_DEEPBIND $ac_have_decl" >>confdefs.h +ac_fn_check_decl "$LINENO" "RTLD_MEMBER" "ac_cv_have_decl_RTLD_MEMBER" "#include +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_RTLD_MEMBER" = xyes +then : ac_have_decl=1 -else +else $as_nop ac_have_decl=0 fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_RTLD_MEMBER $ac_have_decl -_ACEOF +printf "%s\n" "#define HAVE_DECL_RTLD_MEMBER $ac_have_decl" >>confdefs.h # determine what size digit to use for Python's longs -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking digit size for Python's longs" >&5 -$as_echo_n "checking digit size for Python's longs... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking digit size for Python's longs" >&5 +printf %s "checking digit size for Python's longs... " >&6; } # Check whether --enable-big-digits was given. -if test "${enable_big_digits+set}" = set; then : +if test ${enable_big_digits+y} +then : enableval=$enable_big_digits; case $enable_big_digits in yes) enable_big_digits=30 ;; @@ -21208,36 +23908,34 @@ no) *) as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_big_digits" >&5 -$as_echo "$enable_big_digits" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_big_digits" >&5 +printf "%s\n" "$enable_big_digits" >&6; } -cat >>confdefs.h <<_ACEOF -#define PYLONG_BITS_IN_DIGIT $enable_big_digits -_ACEOF +printf "%s\n" "#define PYLONG_BITS_IN_DIGIT $enable_big_digits" >>confdefs.h -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 -$as_echo "no value specified" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 +printf "%s\n" "no value specified" >&6; } fi # check for wchar.h -ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" -if test "x$ac_cv_header_wchar_h" = xyes; then : +ac_fn_c_check_header_compile "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" +if test "x$ac_cv_header_wchar_h" = xyes +then : -$as_echo "#define HAVE_WCHAR_H 1" >>confdefs.h +printf "%s\n" "#define HAVE_WCHAR_H 1" >>confdefs.h wchar_h="yes" -else +else $as_nop wchar_h="no" fi - # determine wchar_t size if test "$wchar_h" = yes then @@ -21245,18 +23943,20 @@ then # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 -$as_echo_n "checking size of wchar_t... " >&6; } -if ${ac_cv_sizeof_wchar_t+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 +printf %s "checking size of wchar_t... " >&6; } +if test ${ac_cv_sizeof_wchar_t+y} +then : + printf %s "(cached) " >&6 +else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include -"; then : +" +then : -else +else $as_nop if test "$ac_cv_type_wchar_t" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (wchar_t) See \`config.log' for more details" "$LINENO" 5; } else @@ -21265,14 +23965,12 @@ See \`config.log' for more details" "$LINENO" 5; } fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_wchar_t" >&5 -$as_echo "$ac_cv_sizeof_wchar_t" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_wchar_t" >&5 +printf "%s\n" "$ac_cv_sizeof_wchar_t" >&6; } -cat >>confdefs.h <<_ACEOF -#define SIZEOF_WCHAR_T $ac_cv_sizeof_wchar_t -_ACEOF +printf "%s\n" "#define SIZEOF_WCHAR_T $ac_cv_sizeof_wchar_t" >>confdefs.h fi @@ -21281,15 +23979,17 @@ fi if test "$wchar_h" = yes then # check whether wchar_t is signed or not - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is signed" >&5 -$as_echo_n "checking whether wchar_t is signed... " >&6; } -if ${ac_cv_wchar_t_signed+:} false; then : - $as_echo_n "(cached) " >&6 -else - - if test "$cross_compiling" = yes; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is signed" >&5 +printf %s "checking whether wchar_t is signed... " >&6; } +if test ${ac_cv_wchar_t_signed+y} +then : + printf %s "(cached) " >&6 +else $as_nop + + if test "$cross_compiling" = yes +then : ac_cv_wchar_t_signed=yes -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21301,9 +24001,10 @@ else } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_wchar_t_signed=yes -else +else $as_nop ac_cv_wchar_t_signed=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -21311,24 +24012,24 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wchar_t_signed" >&5 -$as_echo "$ac_cv_wchar_t_signed" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wchar_t_signed" >&5 +printf "%s\n" "$ac_cv_wchar_t_signed" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is usable" >&5 -$as_echo_n "checking whether wchar_t is usable... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is usable" >&5 +printf %s "checking whether wchar_t is usable... " >&6; } # wchar_t is only usable if it maps to an unsigned type if test "$ac_cv_sizeof_wchar_t" -ge 2 \ -a "$ac_cv_wchar_t_signed" = "no" then -$as_echo "#define HAVE_USABLE_WCHAR_T 1" >>confdefs.h +printf "%s\n" "#define HAVE_USABLE_WCHAR_T 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi case $ac_sys_system/$ac_sys_release in @@ -21340,7 +24041,7 @@ SunOS/*) # non-Unicode locales is not Unicode and hence cannot be used directly. # https://docs.oracle.com/cd/E37838_01/html/E61053/gmwke.html -$as_echo "#define HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION 1" >>confdefs.h +printf "%s\n" "#define HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION 1" >>confdefs.h fi fi @@ -21348,11 +24049,12 @@ $as_echo "#define HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION 1" >>confdefs.h esac # check for endianness - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 -$as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +printf %s "checking whether byte ordering is bigendian... " >&6; } +if test ${ac_cv_c_bigendian+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21363,7 +24065,8 @@ else typedef int dummy; _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. @@ -21387,7 +24090,7 @@ if ac_fn_c_try_compile "$LINENO"; then : fi done fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21396,7 +24099,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ @@ -21408,7 +24111,8 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21416,7 +24120,7 @@ if ac_fn_c_try_compile "$LINENO"; then : #include int -main () +main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian @@ -21426,14 +24130,15 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_bigendian=yes -else +else $as_nop ac_cv_c_bigendian=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). @@ -21442,7 +24147,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros @@ -21452,14 +24157,15 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef _BIG_ENDIAN not big endian @@ -21469,31 +24175,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_c_bigendian=yes -else +else $as_nop ac_cv_c_bigendian=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. - if test "$cross_compiling" = yes; then : + if test "$cross_compiling" = yes +then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -short int ascii_mm[] = +unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; - short int ascii_ii[] = + unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } - short int ebcdic_ii[] = + unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; - short int ebcdic_mm[] = + unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; @@ -21501,14 +24209,15 @@ short int ascii_mm[] = extern int foo; int -main () +main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi @@ -21521,13 +24230,13 @@ if ac_fn_c_try_compile "$LINENO"; then : fi fi fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int -main () +main (void) { /* Are we little or big endian? From Harbison&Steele. */ @@ -21543,9 +24252,10 @@ main () return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_c_bigendian=no -else +else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -21554,17 +24264,17 @@ fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 -$as_echo "$ac_cv_c_bigendian" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) - $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h + printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) -$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h +printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) @@ -21589,15 +24299,15 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h # In Python 3.2 and older, --with-wide-unicode added a 'u' flag. # In Python 3.7 and older, --with-pymalloc added a 'm' flag. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking ABIFLAGS" >&5 -$as_echo_n "checking ABIFLAGS... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ABIFLAGS" >&5 -$as_echo "$ABIFLAGS" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking SOABI" >&5 -$as_echo_n "checking SOABI... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ABIFLAGS" >&5 +printf %s "checking ABIFLAGS... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ABIFLAGS" >&5 +printf "%s\n" "$ABIFLAGS" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SOABI" >&5 +printf %s "checking SOABI... " >&6; } SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SOABI" >&5 -$as_echo "$SOABI" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SOABI" >&5 +printf "%s\n" "$SOABI" >&6; } # Release and debug (Py_DEBUG) ABI are compatible, but not Py_TRACE_REFS ABI if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then @@ -21605,20 +24315,18 @@ if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} -cat >>confdefs.h <<_ACEOF -#define ALT_SOABI "${ALT_SOABI}" -_ACEOF +printf "%s\n" "#define ALT_SOABI \"${ALT_SOABI}\"" >>confdefs.h fi EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LDVERSION" >&5 -$as_echo_n "checking LDVERSION... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDVERSION" >&5 +printf %s "checking LDVERSION... " >&6; } LDVERSION='$(VERSION)$(ABIFLAGS)' -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDVERSION" >&5 -$as_echo "$LDVERSION" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDVERSION" >&5 +printf "%s\n" "$LDVERSION" >&6; } # On Android and Cygwin the shared libraries must be linked with libpython. @@ -21637,11 +24345,12 @@ BINLIBDEST='$(LIBDIR)/python$(VERSION)' # /usr/$LIDIRNAME/python$VERSION PLATLIBDIR="lib" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-platlibdir" >&5 -$as_echo_n "checking for --with-platlibdir... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-platlibdir" >&5 +printf %s "checking for --with-platlibdir... " >&6; } # Check whether --with-platlibdir was given. -if test "${with_platlibdir+set}" = set; then : +if test ${with_platlibdir+y} +then : withval=$with_platlibdir; # ignore 3 options: # --with-platlibdir @@ -21649,17 +24358,17 @@ if test "${with_platlibdir+set}" = set; then : # --without-platlibdir if test -n "$withval" -a "$withval" != yes -a "$withval" != no then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } PLATLIBDIR="$withval" BINLIBDEST='${exec_prefix}/${PLATLIBDIR}/python$(VERSION)' else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -21675,37 +24384,40 @@ fi # Check for --with-wheel-pkg-dir=PATH WHEEL_PKG_DIR="" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-wheel-pkg-dir" >&5 -$as_echo_n "checking for --with-wheel-pkg-dir... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-wheel-pkg-dir" >&5 +printf %s "checking for --with-wheel-pkg-dir... " >&6; } # Check whether --with-wheel-pkg-dir was given. -if test "${with_wheel_pkg_dir+set}" = set; then : +if test ${with_wheel_pkg_dir+y} +then : withval=$with_wheel_pkg_dir; if test -n "$withval"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } WHEEL_PKG_DIR="$withval" else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi # Check whether right shifting a negative integer extends the sign bit # or fills with zeros (like the Cray J90, according to Tim Peters). -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether right shift extends the sign bit" >&5 -$as_echo_n "checking whether right shift extends the sign bit... " >&6; } -if ${ac_cv_rshift_extends_sign+:} false; then : - $as_echo_n "(cached) " >&6 -else - -if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether right shift extends the sign bit" >&5 +printf %s "checking whether right shift extends the sign bit... " >&6; } +if test ${ac_cv_rshift_extends_sign+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +if test "$cross_compiling" = yes +then : ac_cv_rshift_extends_sign=yes -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21715,9 +24427,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_rshift_extends_sign=yes -else +else $as_nop ac_cv_rshift_extends_sign=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -21725,27 +24438,28 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_rshift_extends_sign" >&5 -$as_echo "$ac_cv_rshift_extends_sign" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_rshift_extends_sign" >&5 +printf "%s\n" "$ac_cv_rshift_extends_sign" >&6; } if test "$ac_cv_rshift_extends_sign" = no then -$as_echo "#define SIGNED_RIGHT_SHIFT_ZERO_FILLS 1" >>confdefs.h +printf "%s\n" "#define SIGNED_RIGHT_SHIFT_ZERO_FILLS 1" >>confdefs.h fi # check for getc_unlocked and related locking functions -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getc_unlocked() and friends" >&5 -$as_echo_n "checking for getc_unlocked() and friends... " >&6; } -if ${ac_cv_have_getc_unlocked+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getc_unlocked() and friends" >&5 +printf %s "checking for getc_unlocked() and friends... " >&6; } +if test ${ac_cv_have_getc_unlocked+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen("/dev/null", "r"); @@ -21757,20 +24471,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_have_getc_unlocked=yes -else +else $as_nop ac_cv_have_getc_unlocked=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getc_unlocked" >&5 -$as_echo "$ac_cv_have_getc_unlocked" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getc_unlocked" >&5 +printf "%s\n" "$ac_cv_have_getc_unlocked" >&6; } if test "$ac_cv_have_getc_unlocked" = yes then -$as_echo "#define HAVE_GETC_UNLOCKED 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETC_UNLOCKED 1" >>confdefs.h fi @@ -21779,7 +24494,8 @@ fi # Check whether --with-readline was given. -if test "${with_readline+set}" = set; then : +if test ${with_readline+y} +then : withval=$with_readline; case $with_readline in #( editline|edit) : @@ -21793,27 +24509,28 @@ if test "${with_readline+set}" = set; then : ;; esac -else +else $as_nop with_readline=readline fi -if test "x$with_readline" = xreadline; then : +if test "x$with_readline" = xreadline +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBREADLINE" >&5 -$as_echo_n "checking for LIBREADLINE... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBREADLINE" >&5 +printf %s "checking for LIBREADLINE... " >&6; } if test -n "$LIBREADLINE_CFLAGS"; then pkg_cv_LIBREADLINE_CFLAGS="$LIBREADLINE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"readline\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"readline\""; } >&5 ($PKG_CONFIG --exists --print-errors "readline") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBREADLINE_CFLAGS=`$PKG_CONFIG --cflags "readline" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -21827,10 +24544,10 @@ if test -n "$LIBREADLINE_LIBS"; then pkg_cv_LIBREADLINE_LIBS="$LIBREADLINE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"readline\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"readline\""; } >&5 ($PKG_CONFIG --exists --print-errors "readline") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBREADLINE_LIBS=`$PKG_CONFIG --libs "readline" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -21844,8 +24561,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -21869,19 +24586,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" - for ac_header in readline/readline.h + for ac_header in readline/readline.h do : - ac_fn_c_check_header_mongrel "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" -if test "x$ac_cv_header_readline_readline_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_READLINE_READLINE_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5 -$as_echo_n "checking for readline in -lreadline... " >&6; } -if ${ac_cv_lib_readline_readline+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" +if test "x$ac_cv_header_readline_readline_h" = xyes +then : + printf "%s\n" "#define HAVE_READLINE_READLINE_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5 +printf %s "checking for readline in -lreadline... " >&6; } +if test ${ac_cv_lib_readline_readline+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21890,47 +24607,45 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char readline (); int -main () +main (void) { return readline (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_readline_readline=yes -else +else $as_nop ac_cv_lib_readline_readline=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 -$as_echo "$ac_cv_lib_readline_readline" >&6; } -if test "x$ac_cv_lib_readline_readline" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 +printf "%s\n" "$ac_cv_lib_readline_readline" >&6; } +if test "x$ac_cv_lib_readline_readline" = xyes +then : LIBREADLINE=readline READLINE_CFLAGS=${LIBREADLINE_CFLAGS-""} READLINE_LIBS=${LIBREADLINE_LIBS-"-lreadline"} -else +else $as_nop with_readline=no fi -else +else $as_nop with_readline=no fi done - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -21939,8 +24654,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -21950,19 +24665,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBREADLINE_CFLAGS" LDFLAGS="$LDFLAGS $LIBREADLINE_LIBS" - for ac_header in readline/readline.h + for ac_header in readline/readline.h do : - ac_fn_c_check_header_mongrel "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" -if test "x$ac_cv_header_readline_readline_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_READLINE_READLINE_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5 -$as_echo_n "checking for readline in -lreadline... " >&6; } -if ${ac_cv_lib_readline_readline+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" +if test "x$ac_cv_header_readline_readline_h" = xyes +then : + printf "%s\n" "#define HAVE_READLINE_READLINE_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5 +printf %s "checking for readline in -lreadline... " >&6; } +if test ${ac_cv_lib_readline_readline+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21971,47 +24686,45 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char readline (); int -main () +main (void) { return readline (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_readline_readline=yes -else +else $as_nop ac_cv_lib_readline_readline=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 -$as_echo "$ac_cv_lib_readline_readline" >&6; } -if test "x$ac_cv_lib_readline_readline" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5 +printf "%s\n" "$ac_cv_lib_readline_readline" >&6; } +if test "x$ac_cv_lib_readline_readline" = xyes +then : LIBREADLINE=readline READLINE_CFLAGS=${LIBREADLINE_CFLAGS-""} READLINE_LIBS=${LIBREADLINE_LIBS-"-lreadline"} -else +else $as_nop with_readline=no fi -else +else $as_nop with_readline=no fi done - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -22022,8 +24735,8 @@ LIBS=$save_LIBS else LIBREADLINE_CFLAGS=$pkg_cv_LIBREADLINE_CFLAGS LIBREADLINE_LIBS=$pkg_cv_LIBREADLINE_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } LIBREADLINE=readline READLINE_CFLAGS=$LIBREADLINE_CFLAGS @@ -22033,21 +24746,22 @@ fi fi -if test "x$with_readline" = xedit; then : +if test "x$with_readline" = xedit +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBEDIT" >&5 -$as_echo_n "checking for LIBEDIT... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBEDIT" >&5 +printf %s "checking for LIBEDIT... " >&6; } if test -n "$LIBEDIT_CFLAGS"; then pkg_cv_LIBEDIT_CFLAGS="$LIBEDIT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5 ($PKG_CONFIG --exists --print-errors "libedit") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEDIT_CFLAGS=`$PKG_CONFIG --cflags "libedit" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -22061,10 +24775,10 @@ if test -n "$LIBEDIT_LIBS"; then pkg_cv_LIBEDIT_LIBS="$LIBEDIT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5 ($PKG_CONFIG --exists --print-errors "libedit") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEDIT_LIBS=`$PKG_CONFIG --libs "libedit" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -22078,8 +24792,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -22103,19 +24817,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" - for ac_header in editline/readline.h + for ac_header in editline/readline.h do : - ac_fn_c_check_header_mongrel "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" -if test "x$ac_cv_header_editline_readline_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_EDITLINE_READLINE_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -ledit" >&5 -$as_echo_n "checking for readline in -ledit... " >&6; } -if ${ac_cv_lib_edit_readline+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" +if test "x$ac_cv_header_editline_readline_h" = xyes +then : + printf "%s\n" "#define HAVE_EDITLINE_READLINE_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for readline in -ledit" >&5 +printf %s "checking for readline in -ledit... " >&6; } +if test ${ac_cv_lib_edit_readline+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ledit $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -22124,49 +24838,47 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char readline (); int -main () +main (void) { return readline (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_edit_readline=yes -else +else $as_nop ac_cv_lib_edit_readline=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 -$as_echo "$ac_cv_lib_edit_readline" >&6; } -if test "x$ac_cv_lib_edit_readline" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 +printf "%s\n" "$ac_cv_lib_edit_readline" >&6; } +if test "x$ac_cv_lib_edit_readline" = xyes +then : LIBREADLINE=edit - $as_echo "#define WITH_EDITLINE 1" >>confdefs.h + printf "%s\n" "#define WITH_EDITLINE 1" >>confdefs.h READLINE_CFLAGS=${LIBEDIT_CFLAGS-""} READLINE_LIBS=${LIBEDIT_LIBS-"-ledit"} -else +else $as_nop with_readline=no fi -else +else $as_nop with_readline=no fi done - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -22175,8 +24887,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -22186,19 +24898,19 @@ save_LIBS=$LIBS CPPFLAGS="$CPPFLAGS $LIBEDIT_CFLAGS" LDFLAGS="$LDFLAGS $LIBEDIT_LIBS" - for ac_header in editline/readline.h + for ac_header in editline/readline.h do : - ac_fn_c_check_header_mongrel "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" -if test "x$ac_cv_header_editline_readline_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_EDITLINE_READLINE_H 1 -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -ledit" >&5 -$as_echo_n "checking for readline in -ledit... " >&6; } -if ${ac_cv_lib_edit_readline+:} false; then : - $as_echo_n "(cached) " >&6 -else + ac_fn_c_check_header_compile "$LINENO" "editline/readline.h" "ac_cv_header_editline_readline_h" "$ac_includes_default" +if test "x$ac_cv_header_editline_readline_h" = xyes +then : + printf "%s\n" "#define HAVE_EDITLINE_READLINE_H 1" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for readline in -ledit" >&5 +printf %s "checking for readline in -ledit... " >&6; } +if test ${ac_cv_lib_edit_readline+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ledit $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -22207,49 +24919,47 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char readline (); int -main () +main (void) { return readline (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_edit_readline=yes -else +else $as_nop ac_cv_lib_edit_readline=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 -$as_echo "$ac_cv_lib_edit_readline" >&6; } -if test "x$ac_cv_lib_edit_readline" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5 +printf "%s\n" "$ac_cv_lib_edit_readline" >&6; } +if test "x$ac_cv_lib_edit_readline" = xyes +then : LIBREADLINE=edit - $as_echo "#define WITH_EDITLINE 1" >>confdefs.h + printf "%s\n" "#define WITH_EDITLINE 1" >>confdefs.h READLINE_CFLAGS=${LIBEDIT_CFLAGS-""} READLINE_LIBS=${LIBEDIT_LIBS-"-ledit"} -else +else $as_nop with_readline=no fi -else +else $as_nop with_readline=no fi done - CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS @@ -22260,10 +24970,10 @@ LIBS=$save_LIBS else LIBEDIT_CFLAGS=$pkg_cv_LIBEDIT_CFLAGS LIBEDIT_LIBS=$pkg_cv_LIBEDIT_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } - $as_echo "#define WITH_EDITLINE 1" >>confdefs.h + printf "%s\n" "#define WITH_EDITLINE 1" >>confdefs.h LIBREADLINE=edit READLINE_CFLAGS=$LIBEDIT_CFLAGS @@ -22275,17 +24985,18 @@ fi READLINE_CFLAGS=$(echo $READLINE_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link readline" >&5 -$as_echo_n "checking how to link readline... " >&6; } -if test "x$with_readline" = xno; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to link readline" >&5 +printf %s "checking how to link readline... " >&6; } +if test "x$with_readline" = xno +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&5 -$as_echo "$with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&5 +printf "%s\n" "$with_readline (CFLAGS: $READLINE_CFLAGS, LIBS: $READLINE_LIBS)" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -22300,7 +25011,7 @@ save_LIBS=$LIBS # check for readline 2.2 - ac_fn_c_check_decl "$LINENO" "rl_completion_append_character" "ac_cv_have_decl_rl_completion_append_character" " + ac_fn_check_decl "$LINENO" "rl_completion_append_character" "ac_cv_have_decl_rl_completion_append_character" " #include /* Must be first for Gnu Readline */ #ifdef WITH_EDITLINE # include @@ -22309,17 +25020,17 @@ save_LIBS=$LIBS # include #endif -" -if test "x$ac_cv_have_decl_rl_completion_append_character" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_rl_completion_append_character" = xyes +then : -$as_echo "#define HAVE_RL_COMPLETION_APPEND_CHARACTER 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_COMPLETION_APPEND_CHARACTER 1" >>confdefs.h fi - - ac_fn_c_check_decl "$LINENO" "rl_completion_suppress_append" "ac_cv_have_decl_rl_completion_suppress_append" " + ac_fn_check_decl "$LINENO" "rl_completion_suppress_append" "ac_cv_have_decl_rl_completion_suppress_append" " #include /* Must be first for Gnu Readline */ #ifdef WITH_EDITLINE # include @@ -22328,22 +25039,23 @@ fi # include #endif -" -if test "x$ac_cv_have_decl_rl_completion_suppress_append" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_rl_completion_suppress_append" = xyes +then : -$as_echo "#define HAVE_RL_COMPLETION_SUPPRESS_APPEND 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_COMPLETION_SUPPRESS_APPEND 1" >>confdefs.h fi - # check for readline 4.0 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_pre_input_hook in -l$LIBREADLINE" >&5 -$as_echo_n "checking for rl_pre_input_hook in -l$LIBREADLINE... " >&6; } -if ${ac_cv_readline_rl_pre_input_hook+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_pre_input_hook in -l$LIBREADLINE" >&5 +printf %s "checking for rl_pre_input_hook in -l$LIBREADLINE... " >&6; } +if test ${ac_cv_readline_rl_pre_input_hook+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22357,39 +25069,42 @@ else #endif int -main () +main (void) { void *x = rl_pre_input_hook ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_readline_rl_pre_input_hook=yes -else +else $as_nop ac_cv_readline_rl_pre_input_hook=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_pre_input_hook" >&5 -$as_echo "$ac_cv_readline_rl_pre_input_hook" >&6; } - if test "x$ac_cv_readline_rl_pre_input_hook" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_pre_input_hook" >&5 +printf "%s\n" "$ac_cv_readline_rl_pre_input_hook" >&6; } + if test "x$ac_cv_readline_rl_pre_input_hook" = xyes +then : -$as_echo "#define HAVE_RL_PRE_INPUT_HOOK 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_PRE_INPUT_HOOK 1" >>confdefs.h fi # also in 4.0 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_display_matches_hook in -l$LIBREADLINE" >&5 -$as_echo_n "checking for rl_completion_display_matches_hook in -l$LIBREADLINE... " >&6; } -if ${ac_cv_readline_rl_completion_display_matches_hook+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_completion_display_matches_hook in -l$LIBREADLINE" >&5 +printf %s "checking for rl_completion_display_matches_hook in -l$LIBREADLINE... " >&6; } +if test ${ac_cv_readline_rl_completion_display_matches_hook+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22403,39 +25118,42 @@ else #endif int -main () +main (void) { void *x = rl_completion_display_matches_hook ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_readline_rl_completion_display_matches_hook=yes -else +else $as_nop ac_cv_readline_rl_completion_display_matches_hook=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_display_matches_hook" >&5 -$as_echo "$ac_cv_readline_rl_completion_display_matches_hook" >&6; } - if test "x$ac_cv_readline_rl_completion_display_matches_hook" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_display_matches_hook" >&5 +printf "%s\n" "$ac_cv_readline_rl_completion_display_matches_hook" >&6; } + if test "x$ac_cv_readline_rl_completion_display_matches_hook" = xyes +then : -$as_echo "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h fi # also in 4.0, but not in editline - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_resize_terminal in -l$LIBREADLINE" >&5 -$as_echo_n "checking for rl_resize_terminal in -l$LIBREADLINE... " >&6; } -if ${ac_cv_readline_rl_resize_terminal+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_resize_terminal in -l$LIBREADLINE" >&5 +printf %s "checking for rl_resize_terminal in -l$LIBREADLINE... " >&6; } +if test ${ac_cv_readline_rl_resize_terminal+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22449,39 +25167,42 @@ else #endif int -main () +main (void) { void *x = rl_resize_terminal ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_readline_rl_resize_terminal=yes -else +else $as_nop ac_cv_readline_rl_resize_terminal=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_resize_terminal" >&5 -$as_echo "$ac_cv_readline_rl_resize_terminal" >&6; } - if test "x$ac_cv_readline_rl_resize_terminal" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_resize_terminal" >&5 +printf "%s\n" "$ac_cv_readline_rl_resize_terminal" >&6; } + if test "x$ac_cv_readline_rl_resize_terminal" = xyes +then : -$as_echo "#define HAVE_RL_RESIZE_TERMINAL 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_RESIZE_TERMINAL 1" >>confdefs.h fi # check for readline 4.2 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -l$LIBREADLINE" >&5 -$as_echo_n "checking for rl_completion_matches in -l$LIBREADLINE... " >&6; } -if ${ac_cv_readline_rl_completion_matches+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -l$LIBREADLINE" >&5 +printf %s "checking for rl_completion_matches in -l$LIBREADLINE... " >&6; } +if test ${ac_cv_readline_rl_completion_matches+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22495,35 +25216,37 @@ else #endif int -main () +main (void) { void *x = rl_completion_matches ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_readline_rl_completion_matches=yes -else +else $as_nop ac_cv_readline_rl_completion_matches=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_matches" >&5 -$as_echo "$ac_cv_readline_rl_completion_matches" >&6; } - if test "x$ac_cv_readline_rl_completion_matches" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_rl_completion_matches" >&5 +printf "%s\n" "$ac_cv_readline_rl_completion_matches" >&6; } + if test "x$ac_cv_readline_rl_completion_matches" = xyes +then : -$as_echo "#define HAVE_RL_COMPLETION_MATCHES 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_COMPLETION_MATCHES 1" >>confdefs.h fi # also in readline 4.2 - ac_fn_c_check_decl "$LINENO" "rl_catch_signals" "ac_cv_have_decl_rl_catch_signals" " + ac_fn_check_decl "$LINENO" "rl_catch_signals" "ac_cv_have_decl_rl_catch_signals" " #include /* Must be first for Gnu Readline */ #ifdef WITH_EDITLINE # include @@ -22532,21 +25255,22 @@ fi # include #endif -" -if test "x$ac_cv_have_decl_rl_catch_signals" = xyes; then : +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_rl_catch_signals" = xyes +then : -$as_echo "#define HAVE_RL_CATCH_SIGNAL 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_CATCH_SIGNAL 1" >>confdefs.h fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for append_history in -l$LIBREADLINE" >&5 -$as_echo_n "checking for append_history in -l$LIBREADLINE... " >&6; } -if ${ac_cv_readline_append_history+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for append_history in -l$LIBREADLINE" >&5 +printf %s "checking for append_history in -l$LIBREADLINE... " >&6; } +if test ${ac_cv_readline_append_history+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22560,29 +25284,31 @@ else #endif int -main () +main (void) { void *x = append_history ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_readline_append_history=yes -else +else $as_nop ac_cv_readline_append_history=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_append_history" >&5 -$as_echo "$ac_cv_readline_append_history" >&6; } - if test "x$ac_cv_readline_append_history" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readline_append_history" >&5 +printf "%s\n" "$ac_cv_readline_append_history" >&6; } + if test "x$ac_cv_readline_append_history" = xyes +then : -$as_echo "#define HAVE_RL_APPEND_HISTORY 1" >>confdefs.h +printf "%s\n" "#define HAVE_RL_APPEND_HISTORY 1" >>confdefs.h fi @@ -22597,15 +25323,17 @@ LIBS=$save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 -$as_echo_n "checking for broken nice()... " >&6; } -if ${ac_cv_broken_nice+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 +printf %s "checking for broken nice()... " >&6; } +if test ${ac_cv_broken_nice+y} +then : + printf %s "(cached) " >&6 +else $as_nop -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : ac_cv_broken_nice=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22620,9 +25348,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_broken_nice=yes -else +else $as_nop ac_cv_broken_nice=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -22630,23 +25359,25 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_nice" >&5 -$as_echo "$ac_cv_broken_nice" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_nice" >&5 +printf "%s\n" "$ac_cv_broken_nice" >&6; } if test "$ac_cv_broken_nice" = yes then -$as_echo "#define HAVE_BROKEN_NICE 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_NICE 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken poll()" >&5 -$as_echo_n "checking for broken poll()... " >&6; } -if ${ac_cv_broken_poll+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken poll()" >&5 +printf %s "checking for broken poll()... " >&6; } +if test ${ac_cv_broken_poll+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_broken_poll=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22670,9 +25401,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_broken_poll=yes -else +else $as_nop ac_cv_broken_poll=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -22680,25 +25412,27 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_poll" >&5 -$as_echo "$ac_cv_broken_poll" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_poll" >&5 +printf "%s\n" "$ac_cv_broken_poll" >&6; } if test "$ac_cv_broken_poll" = yes then -$as_echo "#define HAVE_BROKEN_POLL 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_POLL 1" >>confdefs.h fi # check tzset(3) exists and works like we expect it to -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5 -$as_echo_n "checking for working tzset()... " >&6; } -if ${ac_cv_working_tzset+:} false; then : - $as_echo_n "(cached) " >&6 -else - -if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5 +printf %s "checking for working tzset()... " >&6; } +if test ${ac_cv_working_tzset+y} +then : + printf %s "(cached) " >&6 +else $as_nop + +if test "$cross_compiling" = yes +then : ac_cv_working_tzset=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22766,9 +25500,10 @@ int main(void) } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_working_tzset=yes -else +else $as_nop ac_cv_working_tzset=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -22776,26 +25511,27 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_tzset" >&5 -$as_echo "$ac_cv_working_tzset" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_tzset" >&5 +printf "%s\n" "$ac_cv_working_tzset" >&6; } if test "$ac_cv_working_tzset" = yes then -$as_echo "#define HAVE_WORKING_TZSET 1" >>confdefs.h +printf "%s\n" "#define HAVE_WORKING_TZSET 1" >>confdefs.h fi # Look for subsecond timestamps in struct stat -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec in struct stat" >&5 -$as_echo_n "checking for tv_nsec in struct stat... " >&6; } -if ${ac_cv_stat_tv_nsec+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tv_nsec in struct stat" >&5 +printf %s "checking for tv_nsec in struct stat... " >&6; } +if test ${ac_cv_stat_tv_nsec+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { struct stat st; @@ -22805,33 +25541,35 @@ st.st_mtim.tv_nsec = 1; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_stat_tv_nsec=yes -else +else $as_nop ac_cv_stat_tv_nsec=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec" >&5 -$as_echo "$ac_cv_stat_tv_nsec" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec" >&5 +printf "%s\n" "$ac_cv_stat_tv_nsec" >&6; } if test "$ac_cv_stat_tv_nsec" = yes then -$as_echo "#define HAVE_STAT_TV_NSEC 1" >>confdefs.h +printf "%s\n" "#define HAVE_STAT_TV_NSEC 1" >>confdefs.h fi # Look for BSD style subsecond timestamps in struct stat -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec2 in struct stat" >&5 -$as_echo_n "checking for tv_nsec2 in struct stat... " >&6; } -if ${ac_cv_stat_tv_nsec2+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tv_nsec2 in struct stat" >&5 +printf %s "checking for tv_nsec2 in struct stat... " >&6; } +if test ${ac_cv_stat_tv_nsec2+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { struct stat st; @@ -22841,19 +25579,20 @@ st.st_mtimespec.tv_nsec = 1; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_stat_tv_nsec2=yes -else +else $as_nop ac_cv_stat_tv_nsec2=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec2" >&5 -$as_echo "$ac_cv_stat_tv_nsec2" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_tv_nsec2" >&5 +printf "%s\n" "$ac_cv_stat_tv_nsec2" >&6; } if test "$ac_cv_stat_tv_nsec2" = yes then -$as_echo "#define HAVE_STAT_TV_NSEC2 1" >>confdefs.h +printf "%s\n" "#define HAVE_STAT_TV_NSEC2 1" >>confdefs.h fi @@ -22861,36 +25600,37 @@ have_curses=no have_panel=no -for ac_header in curses.h ncurses.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default" +if test "x$ac_cv_header_curses_h" = xyes +then : + printf "%s\n" "#define HAVE_CURSES_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "ncurses.h" "ac_cv_header_ncurses_h" "$ac_includes_default" +if test "x$ac_cv_header_ncurses_h" = xyes +then : + printf "%s\n" "#define HAVE_NCURSES_H 1" >>confdefs.h -done +fi -if test "x$ac_cv_header_ncurses_h" = xyes; then : +if test "x$ac_cv_header_ncurses_h" = xyes +then : if test "$ac_sys_system" != "Darwin"; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CURSES" >&5 -$as_echo_n "checking for CURSES... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CURSES" >&5 +printf %s "checking for CURSES... " >&6; } if test -n "$CURSES_CFLAGS"; then pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CURSES_CFLAGS=`$PKG_CONFIG --cflags "ncursesw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -22904,10 +25644,10 @@ if test -n "$CURSES_LIBS"; then pkg_cv_CURSES_LIBS="$CURSES_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CURSES_LIBS=`$PKG_CONFIG --libs "ncursesw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -22921,8 +25661,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -22944,11 +25684,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncursesw" >&5 -$as_echo_n "checking for initscr in -lncursesw... " >&6; } -if ${ac_cv_lib_ncursesw_initscr+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncursesw" >&5 +printf %s "checking for initscr in -lncursesw... " >&6; } +if test ${ac_cv_lib_ncursesw_initscr+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lncursesw $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -22957,32 +25698,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char initscr (); int -main () +main (void) { return initscr (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ncursesw_initscr=yes -else +else $as_nop ac_cv_lib_ncursesw_initscr=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_initscr" >&5 -$as_echo "$ac_cv_lib_ncursesw_initscr" >&6; } -if test "x$ac_cv_lib_ncursesw_initscr" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_initscr" >&5 +printf "%s\n" "$ac_cv_lib_ncursesw_initscr" >&6; } +if test "x$ac_cv_lib_ncursesw_initscr" = xyes +then : - $as_echo "#define HAVE_NCURSESW 1" >>confdefs.h + printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h have_curses=ncursesw CURSES_CFLAGS=${CURSES_CFLAGS-""} @@ -22999,8 +25739,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -23008,11 +25748,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncursesw" >&5 -$as_echo_n "checking for initscr in -lncursesw... " >&6; } -if ${ac_cv_lib_ncursesw_initscr+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncursesw" >&5 +printf %s "checking for initscr in -lncursesw... " >&6; } +if test ${ac_cv_lib_ncursesw_initscr+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lncursesw $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23021,32 +25762,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char initscr (); int -main () +main (void) { return initscr (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ncursesw_initscr=yes -else +else $as_nop ac_cv_lib_ncursesw_initscr=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_initscr" >&5 -$as_echo "$ac_cv_lib_ncursesw_initscr" >&6; } -if test "x$ac_cv_lib_ncursesw_initscr" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_initscr" >&5 +printf "%s\n" "$ac_cv_lib_ncursesw_initscr" >&6; } +if test "x$ac_cv_lib_ncursesw_initscr" = xyes +then : - $as_echo "#define HAVE_NCURSESW 1" >>confdefs.h + printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h have_curses=ncursesw CURSES_CFLAGS=${CURSES_CFLAGS-""} @@ -23065,31 +25805,32 @@ LIBS=$save_LIBS else CURSES_CFLAGS=$pkg_cv_CURSES_CFLAGS CURSES_LIBS=$pkg_cv_CURSES_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } - $as_echo "#define HAVE_NCURSESW 1" >>confdefs.h + printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h have_curses=ncursesw fi fi - if test "x$have_curses" = xno; then : + if test "x$have_curses" = xno +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CURSES" >&5 -$as_echo_n "checking for CURSES... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CURSES" >&5 +printf %s "checking for CURSES... " >&6; } if test -n "$CURSES_CFLAGS"; then pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncurses\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncurses\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncurses") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CURSES_CFLAGS=`$PKG_CONFIG --cflags "ncurses" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -23103,10 +25844,10 @@ if test -n "$CURSES_LIBS"; then pkg_cv_CURSES_LIBS="$CURSES_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncurses\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncurses\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncurses") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CURSES_LIBS=`$PKG_CONFIG --libs "ncurses" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -23120,8 +25861,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -23143,11 +25884,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncurses" >&5 -$as_echo_n "checking for initscr in -lncurses... " >&6; } -if ${ac_cv_lib_ncurses_initscr+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncurses" >&5 +printf %s "checking for initscr in -lncurses... " >&6; } +if test ${ac_cv_lib_ncurses_initscr+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lncurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23156,30 +25898,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char initscr (); int -main () +main (void) { return initscr (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ncurses_initscr=yes -else +else $as_nop ac_cv_lib_ncurses_initscr=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_initscr" >&5 -$as_echo "$ac_cv_lib_ncurses_initscr" >&6; } -if test "x$ac_cv_lib_ncurses_initscr" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_initscr" >&5 +printf "%s\n" "$ac_cv_lib_ncurses_initscr" >&6; } +if test "x$ac_cv_lib_ncurses_initscr" = xyes +then : have_curses=ncurses CURSES_CFLAGS=${CURSES_CFLAGS-""} @@ -23196,8 +25937,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -23205,11 +25946,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncurses" >&5 -$as_echo_n "checking for initscr in -lncurses... " >&6; } -if ${ac_cv_lib_ncurses_initscr+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncurses" >&5 +printf %s "checking for initscr in -lncurses... " >&6; } +if test ${ac_cv_lib_ncurses_initscr+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lncurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23218,30 +25960,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char initscr (); int -main () +main (void) { return initscr (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ncurses_initscr=yes -else +else $as_nop ac_cv_lib_ncurses_initscr=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_initscr" >&5 -$as_echo "$ac_cv_lib_ncurses_initscr" >&6; } -if test "x$ac_cv_lib_ncurses_initscr" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_initscr" >&5 +printf "%s\n" "$ac_cv_lib_ncurses_initscr" >&6; } +if test "x$ac_cv_lib_ncurses_initscr" = xyes +then : have_curses=ncurses CURSES_CFLAGS=${CURSES_CFLAGS-""} @@ -23260,8 +26001,8 @@ LIBS=$save_LIBS else CURSES_CFLAGS=$pkg_cv_CURSES_CFLAGS CURSES_LIBS=$pkg_cv_CURSES_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_curses=ncurses @@ -23276,57 +26017,55 @@ CURSES_CFLAGS=$(echo $CURSES_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') if test "$have_curses" = no -a "$ac_sys_system" = "Darwin"; then as_fn_append CURSES_CFLAGS " -D_XOPEN_SOURCE_EXTENDED=1" - $as_echo "#define HAVE_NCURSESW 1" >>confdefs.h + printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking curses module flags" >&5 -$as_echo_n "checking curses module flags... " >&6; } -if test "x$have_curses" = xno; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking curses module flags" >&5 +printf %s "checking curses module flags... " >&6; } +if test "x$have_curses" = xno +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_curses (CFLAGS: $CURSES_CFLAGS, LIBS: $CURSES_LIBS)" >&5 -$as_echo "$have_curses (CFLAGS: $CURSES_CFLAGS, LIBS: $CURSES_LIBS)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_curses (CFLAGS: $CURSES_CFLAGS, LIBS: $CURSES_LIBS)" >&5 +printf "%s\n" "$have_curses (CFLAGS: $CURSES_CFLAGS, LIBS: $CURSES_LIBS)" >&6; } fi -for ac_header in panel.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "panel.h" "ac_cv_header_panel_h" "$ac_includes_default" -if test "x$ac_cv_header_panel_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_PANEL_H 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "panel.h" "ac_cv_header_panel_h" "$ac_includes_default" +if test "x$ac_cv_header_panel_h" = xyes +then : + printf "%s\n" "#define HAVE_PANEL_H 1" >>confdefs.h fi -done - -if test "x$ac_cv_header_panel_h" = xyes; then : +if test "x$ac_cv_header_panel_h" = xyes +then : if test "$ac_sys_system" != "Darwin"; then - if test "x$have_curses" = xncursesw; then : + if test "x$have_curses" = xncursesw +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PANEL" >&5 -$as_echo_n "checking for PANEL... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PANEL" >&5 +printf %s "checking for PANEL... " >&6; } if test -n "$PANEL_CFLAGS"; then pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "panelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -23340,10 +26079,10 @@ if test -n "$PANEL_LIBS"; then pkg_cv_PANEL_LIBS="$PANEL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "panelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -23357,8 +26096,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -23380,11 +26119,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanelw" >&5 -$as_echo_n "checking for update_panels in -lpanelw... " >&6; } -if ${ac_cv_lib_panelw_update_panels+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanelw" >&5 +printf %s "checking for update_panels in -lpanelw... " >&6; } +if test ${ac_cv_lib_panelw_update_panels+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpanelw $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23393,30 +26133,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char update_panels (); int -main () +main (void) { return update_panels (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_panelw_update_panels=yes -else +else $as_nop ac_cv_lib_panelw_update_panels=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panelw_update_panels" >&5 -$as_echo "$ac_cv_lib_panelw_update_panels" >&6; } -if test "x$ac_cv_lib_panelw_update_panels" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panelw_update_panels" >&5 +printf "%s\n" "$ac_cv_lib_panelw_update_panels" >&6; } +if test "x$ac_cv_lib_panelw_update_panels" = xyes +then : have_panel=panelw PANEL_CFLAGS=${PANEL_CFLAGS-""} @@ -23433,8 +26172,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -23442,11 +26181,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanelw" >&5 -$as_echo_n "checking for update_panels in -lpanelw... " >&6; } -if ${ac_cv_lib_panelw_update_panels+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanelw" >&5 +printf %s "checking for update_panels in -lpanelw... " >&6; } +if test ${ac_cv_lib_panelw_update_panels+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpanelw $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23455,30 +26195,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char update_panels (); int -main () +main (void) { return update_panels (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_panelw_update_panels=yes -else +else $as_nop ac_cv_lib_panelw_update_panels=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panelw_update_panels" >&5 -$as_echo "$ac_cv_lib_panelw_update_panels" >&6; } -if test "x$ac_cv_lib_panelw_update_panels" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panelw_update_panels" >&5 +printf "%s\n" "$ac_cv_lib_panelw_update_panels" >&6; } +if test "x$ac_cv_lib_panelw_update_panels" = xyes +then : have_panel=panelw PANEL_CFLAGS=${PANEL_CFLAGS-""} @@ -23497,8 +26236,8 @@ LIBS=$save_LIBS else PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS PANEL_LIBS=$pkg_cv_PANEL_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_panel=panelw @@ -23507,21 +26246,22 @@ fi fi fi - if test "x$have_curses" = xncurses; then : + if test "x$have_curses" = xncurses +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PANEL" >&5 -$as_echo_n "checking for PANEL... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PANEL" >&5 +printf %s "checking for PANEL... " >&6; } if test -n "$PANEL_CFLAGS"; then pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 ($PKG_CONFIG --exists --print-errors "panel") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "panel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -23535,10 +26275,10 @@ if test -n "$PANEL_LIBS"; then pkg_cv_PANEL_LIBS="$PANEL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 ($PKG_CONFIG --exists --print-errors "panel") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "panel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -23552,8 +26292,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -23575,11 +26315,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanel" >&5 -$as_echo_n "checking for update_panels in -lpanel... " >&6; } -if ${ac_cv_lib_panel_update_panels+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanel" >&5 +printf %s "checking for update_panels in -lpanel... " >&6; } +if test ${ac_cv_lib_panel_update_panels+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpanel $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23588,30 +26329,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char update_panels (); int -main () +main (void) { return update_panels (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_panel_update_panels=yes -else +else $as_nop ac_cv_lib_panel_update_panels=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panel_update_panels" >&5 -$as_echo "$ac_cv_lib_panel_update_panels" >&6; } -if test "x$ac_cv_lib_panel_update_panels" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panel_update_panels" >&5 +printf "%s\n" "$ac_cv_lib_panel_update_panels" >&6; } +if test "x$ac_cv_lib_panel_update_panels" = xyes +then : have_panel=panel PANEL_CFLAGS=${PANEL_CFLAGS-""} @@ -23628,8 +26368,8 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -23637,11 +26377,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanel" >&5 -$as_echo_n "checking for update_panels in -lpanel... " >&6; } -if ${ac_cv_lib_panel_update_panels+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanel" >&5 +printf %s "checking for update_panels in -lpanel... " >&6; } +if test ${ac_cv_lib_panel_update_panels+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpanel $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23650,30 +26391,29 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char update_panels (); int -main () +main (void) { return update_panels (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_panel_update_panels=yes -else +else $as_nop ac_cv_lib_panel_update_panels=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panel_update_panels" >&5 -$as_echo "$ac_cv_lib_panel_update_panels" >&6; } -if test "x$ac_cv_lib_panel_update_panels" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panel_update_panels" >&5 +printf "%s\n" "$ac_cv_lib_panel_update_panels" >&6; } +if test "x$ac_cv_lib_panel_update_panels" = xyes +then : have_panel=panel PANEL_CFLAGS=${PANEL_CFLAGS-""} @@ -23692,8 +26432,8 @@ LIBS=$save_LIBS else PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS PANEL_LIBS=$pkg_cv_PANEL_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_panel=panel @@ -23705,17 +26445,18 @@ fi fi PANEL_CFLAGS=$(echo $PANEL_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking panel flags" >&5 -$as_echo_n "checking panel flags... " >&6; } -if test "x$have_panel" = xno; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking panel flags" >&5 +printf %s "checking panel flags... " >&6; } +if test "x$have_panel" = xno +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_panel (CFLAGS: $PANEL_CFLAGS, LIBS: $PANEL_LIBS)" >&5 -$as_echo "$have_panel (CFLAGS: $PANEL_CFLAGS, LIBS: $PANEL_LIBS)" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_panel (CFLAGS: $PANEL_CFLAGS, LIBS: $PANEL_LIBS)" >&5 +printf "%s\n" "$have_panel (CFLAGS: $PANEL_CFLAGS, LIBS: $PANEL_LIBS)" >&6; } fi @@ -23726,35 +26467,31 @@ if test "$cross_compiling" = no; then fi # On Solaris, term.h requires curses.h -for ac_header in term.h -do : - ac_fn_c_check_header_compile "$LINENO" "term.h" "ac_cv_header_term_h" " +ac_fn_c_check_header_compile "$LINENO" "term.h" "ac_cv_header_term_h" " #ifdef HAVE_CURSES_H #include #endif " -if test "x$ac_cv_header_term_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_TERM_H 1 -_ACEOF +if test "x$ac_cv_header_term_h" = xyes +then : + printf "%s\n" "#define HAVE_TERM_H 1" >>confdefs.h fi -done - # On HP/UX 11.0, mvwdelch is a block with a return statement -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 -$as_echo_n "checking whether mvwdelch is an expression... " >&6; } -if ${ac_cv_mvwdelch_is_expression+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 +printf %s "checking whether mvwdelch is an expression... " >&6; } +if test ${ac_cv_mvwdelch_is_expression+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int rtn; @@ -23764,20 +26501,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_mvwdelch_is_expression=yes -else +else $as_nop ac_cv_mvwdelch_is_expression=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mvwdelch_is_expression" >&5 -$as_echo "$ac_cv_mvwdelch_is_expression" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mvwdelch_is_expression" >&5 +printf "%s\n" "$ac_cv_mvwdelch_is_expression" >&6; } if test "$ac_cv_mvwdelch_is_expression" = yes then -$as_echo "#define MVWDELCH_IS_EXPRESSION 1" >>confdefs.h +printf "%s\n" "#define MVWDELCH_IS_EXPRESSION 1" >>confdefs.h fi @@ -23785,11 +26523,12 @@ fi # structs since version 5.7. If the macro is defined as zero before including # [n]curses.h, ncurses will expose fields of the structs regardless of the # configuration. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether WINDOW has _flags" >&5 -$as_echo_n "checking whether WINDOW has _flags... " >&6; } -if ${ac_cv_window_has_flags+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether WINDOW has _flags" >&5 +printf %s "checking whether WINDOW has _flags... " >&6; } +if test ${ac_cv_window_has_flags+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23797,7 +26536,7 @@ else #include int -main () +main (void) { WINDOW *w; @@ -23807,21 +26546,22 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_window_has_flags=yes -else +else $as_nop ac_cv_window_has_flags=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_window_has_flags" >&5 -$as_echo "$ac_cv_window_has_flags" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_window_has_flags" >&5 +printf "%s\n" "$ac_cv_window_has_flags" >&6; } if test "$ac_cv_window_has_flags" = yes then -$as_echo "#define WINDOW_HAS_FLAGS 1" >>confdefs.h +printf "%s\n" "#define WINDOW_HAS_FLAGS 1" >>confdefs.h fi @@ -23829,16 +26569,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function is_pad" >&5 -$as_echo_n "checking for curses function is_pad... " >&6; } -if ${ac_cv_lib_curses_is_pad+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function is_pad" >&5 +printf %s "checking for curses function is_pad... " >&6; } +if test ${ac_cv_lib_curses_is_pad+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef is_pad @@ -23849,19 +26590,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_is_pad=yes -else +else $as_nop ac_cv_lib_curses_is_pad=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_pad" >&5 -$as_echo "$ac_cv_lib_curses_is_pad" >&6; } - if test "x$ac_cv_lib_curses_is_pad" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_pad" >&5 +printf "%s\n" "$ac_cv_lib_curses_is_pad" >&6; } + if test "x$ac_cv_lib_curses_is_pad" = xyes +then : -$as_echo "#define HAVE_CURSES_IS_PAD 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_IS_PAD 1" >>confdefs.h fi @@ -23869,16 +26612,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function is_term_resized" >&5 -$as_echo_n "checking for curses function is_term_resized... " >&6; } -if ${ac_cv_lib_curses_is_term_resized+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function is_term_resized" >&5 +printf %s "checking for curses function is_term_resized... " >&6; } +if test ${ac_cv_lib_curses_is_term_resized+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef is_term_resized @@ -23889,19 +26633,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_is_term_resized=yes -else +else $as_nop ac_cv_lib_curses_is_term_resized=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_term_resized" >&5 -$as_echo "$ac_cv_lib_curses_is_term_resized" >&6; } - if test "x$ac_cv_lib_curses_is_term_resized" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_is_term_resized" >&5 +printf "%s\n" "$ac_cv_lib_curses_is_term_resized" >&6; } + if test "x$ac_cv_lib_curses_is_term_resized" = xyes +then : -$as_echo "#define HAVE_CURSES_IS_TERM_RESIZED 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_IS_TERM_RESIZED 1" >>confdefs.h fi @@ -23909,16 +26655,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function resize_term" >&5 -$as_echo_n "checking for curses function resize_term... " >&6; } -if ${ac_cv_lib_curses_resize_term+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function resize_term" >&5 +printf %s "checking for curses function resize_term... " >&6; } +if test ${ac_cv_lib_curses_resize_term+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef resize_term @@ -23929,19 +26676,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_resize_term=yes -else +else $as_nop ac_cv_lib_curses_resize_term=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resize_term" >&5 -$as_echo "$ac_cv_lib_curses_resize_term" >&6; } - if test "x$ac_cv_lib_curses_resize_term" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resize_term" >&5 +printf "%s\n" "$ac_cv_lib_curses_resize_term" >&6; } + if test "x$ac_cv_lib_curses_resize_term" = xyes +then : -$as_echo "#define HAVE_CURSES_RESIZE_TERM 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_RESIZE_TERM 1" >>confdefs.h fi @@ -23949,16 +26698,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function resizeterm" >&5 -$as_echo_n "checking for curses function resizeterm... " >&6; } -if ${ac_cv_lib_curses_resizeterm+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function resizeterm" >&5 +printf %s "checking for curses function resizeterm... " >&6; } +if test ${ac_cv_lib_curses_resizeterm+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef resizeterm @@ -23969,19 +26719,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_resizeterm=yes -else +else $as_nop ac_cv_lib_curses_resizeterm=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resizeterm" >&5 -$as_echo "$ac_cv_lib_curses_resizeterm" >&6; } - if test "x$ac_cv_lib_curses_resizeterm" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_resizeterm" >&5 +printf "%s\n" "$ac_cv_lib_curses_resizeterm" >&6; } + if test "x$ac_cv_lib_curses_resizeterm" = xyes +then : -$as_echo "#define HAVE_CURSES_RESIZETERM 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_RESIZETERM 1" >>confdefs.h fi @@ -23989,16 +26741,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function immedok" >&5 -$as_echo_n "checking for curses function immedok... " >&6; } -if ${ac_cv_lib_curses_immedok+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function immedok" >&5 +printf %s "checking for curses function immedok... " >&6; } +if test ${ac_cv_lib_curses_immedok+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef immedok @@ -24009,19 +26762,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_immedok=yes -else +else $as_nop ac_cv_lib_curses_immedok=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_immedok" >&5 -$as_echo "$ac_cv_lib_curses_immedok" >&6; } - if test "x$ac_cv_lib_curses_immedok" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_immedok" >&5 +printf "%s\n" "$ac_cv_lib_curses_immedok" >&6; } + if test "x$ac_cv_lib_curses_immedok" = xyes +then : -$as_echo "#define HAVE_CURSES_IMMEDOK 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_IMMEDOK 1" >>confdefs.h fi @@ -24029,16 +26784,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function syncok" >&5 -$as_echo_n "checking for curses function syncok... " >&6; } -if ${ac_cv_lib_curses_syncok+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function syncok" >&5 +printf %s "checking for curses function syncok... " >&6; } +if test ${ac_cv_lib_curses_syncok+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef syncok @@ -24049,19 +26805,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_syncok=yes -else +else $as_nop ac_cv_lib_curses_syncok=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_syncok" >&5 -$as_echo "$ac_cv_lib_curses_syncok" >&6; } - if test "x$ac_cv_lib_curses_syncok" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_syncok" >&5 +printf "%s\n" "$ac_cv_lib_curses_syncok" >&6; } + if test "x$ac_cv_lib_curses_syncok" = xyes +then : -$as_echo "#define HAVE_CURSES_SYNCOK 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_SYNCOK 1" >>confdefs.h fi @@ -24069,16 +26827,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function wchgat" >&5 -$as_echo_n "checking for curses function wchgat... " >&6; } -if ${ac_cv_lib_curses_wchgat+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function wchgat" >&5 +printf %s "checking for curses function wchgat... " >&6; } +if test ${ac_cv_lib_curses_wchgat+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef wchgat @@ -24089,19 +26848,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_wchgat=yes -else +else $as_nop ac_cv_lib_curses_wchgat=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wchgat" >&5 -$as_echo "$ac_cv_lib_curses_wchgat" >&6; } - if test "x$ac_cv_lib_curses_wchgat" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_wchgat" >&5 +printf "%s\n" "$ac_cv_lib_curses_wchgat" >&6; } + if test "x$ac_cv_lib_curses_wchgat" = xyes +then : -$as_echo "#define HAVE_CURSES_WCHGAT 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_WCHGAT 1" >>confdefs.h fi @@ -24109,16 +26870,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function filter" >&5 -$as_echo_n "checking for curses function filter... " >&6; } -if ${ac_cv_lib_curses_filter+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function filter" >&5 +printf %s "checking for curses function filter... " >&6; } +if test ${ac_cv_lib_curses_filter+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef filter @@ -24129,19 +26891,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_filter=yes -else +else $as_nop ac_cv_lib_curses_filter=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_filter" >&5 -$as_echo "$ac_cv_lib_curses_filter" >&6; } - if test "x$ac_cv_lib_curses_filter" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_filter" >&5 +printf "%s\n" "$ac_cv_lib_curses_filter" >&6; } + if test "x$ac_cv_lib_curses_filter" = xyes +then : -$as_echo "#define HAVE_CURSES_FILTER 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_FILTER 1" >>confdefs.h fi @@ -24149,16 +26913,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function has_key" >&5 -$as_echo_n "checking for curses function has_key... " >&6; } -if ${ac_cv_lib_curses_has_key+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function has_key" >&5 +printf %s "checking for curses function has_key... " >&6; } +if test ${ac_cv_lib_curses_has_key+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef has_key @@ -24169,19 +26934,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_has_key=yes -else +else $as_nop ac_cv_lib_curses_has_key=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_has_key" >&5 -$as_echo "$ac_cv_lib_curses_has_key" >&6; } - if test "x$ac_cv_lib_curses_has_key" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_has_key" >&5 +printf "%s\n" "$ac_cv_lib_curses_has_key" >&6; } + if test "x$ac_cv_lib_curses_has_key" = xyes +then : -$as_echo "#define HAVE_CURSES_HAS_KEY 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_HAS_KEY 1" >>confdefs.h fi @@ -24189,16 +26956,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function typeahead" >&5 -$as_echo_n "checking for curses function typeahead... " >&6; } -if ${ac_cv_lib_curses_typeahead+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function typeahead" >&5 +printf %s "checking for curses function typeahead... " >&6; } +if test ${ac_cv_lib_curses_typeahead+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef typeahead @@ -24209,19 +26977,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_typeahead=yes -else +else $as_nop ac_cv_lib_curses_typeahead=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_typeahead" >&5 -$as_echo "$ac_cv_lib_curses_typeahead" >&6; } - if test "x$ac_cv_lib_curses_typeahead" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_typeahead" >&5 +printf "%s\n" "$ac_cv_lib_curses_typeahead" >&6; } + if test "x$ac_cv_lib_curses_typeahead" = xyes +then : -$as_echo "#define HAVE_CURSES_TYPEAHEAD 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_TYPEAHEAD 1" >>confdefs.h fi @@ -24229,16 +26999,17 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curses function use_env" >&5 -$as_echo_n "checking for curses function use_env... " >&6; } -if ${ac_cv_lib_curses_use_env+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for curses function use_env" >&5 +printf %s "checking for curses function use_env... " >&6; } +if test ${ac_cv_lib_curses_use_env+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifndef use_env @@ -24249,19 +27020,21 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_lib_curses_use_env=yes -else +else $as_nop ac_cv_lib_curses_use_env=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_use_env" >&5 -$as_echo "$ac_cv_lib_curses_use_env" >&6; } - if test "x$ac_cv_lib_curses_use_env" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_use_env" >&5 +printf "%s\n" "$ac_cv_lib_curses_use_env" >&6; } + if test "x$ac_cv_lib_curses_use_env" = xyes +then : -$as_echo "#define HAVE_CURSES_USE_ENV 1" >>confdefs.h +printf "%s\n" "#define HAVE_CURSES_USE_ENV 1" >>confdefs.h fi @@ -24269,31 +27042,32 @@ fi CPPFLAGS=$ac_save_cppflags -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 -$as_echo "$as_me: checking for device files" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 +printf "%s\n" "$as_me: checking for device files" >&6;} if test "x$cross_compiling" = xyes; then if test "${ac_cv_file__dev_ptmx+set}" != set; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5 -$as_echo_n "checking for /dev/ptmx... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5 -$as_echo "not set" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5 +printf %s "checking for /dev/ptmx... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5 +printf "%s\n" "not set" >&6; } as_fn_error $? "set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5 fi if test "${ac_cv_file__dev_ptc+set}" != set; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5 -$as_echo_n "checking for /dev/ptc... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not set" >&5 -$as_echo "not set" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5 +printf %s "checking for /dev/ptc... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5 +printf "%s\n" "not set" >&6; } as_fn_error $? "set ac_cv_file__dev_ptc to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5 -$as_echo_n "checking for /dev/ptmx... " >&6; } -if ${ac_cv_file__dev_ptmx+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5 +printf %s "checking for /dev/ptmx... " >&6; } +if test ${ac_cv_file__dev_ptmx+y} +then : + printf %s "(cached) " >&6 +else $as_nop test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/dev/ptmx"; then @@ -24302,22 +27076,24 @@ else ac_cv_file__dev_ptmx=no fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptmx" >&5 -$as_echo "$ac_cv_file__dev_ptmx" >&6; } -if test "x$ac_cv_file__dev_ptmx" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptmx" >&5 +printf "%s\n" "$ac_cv_file__dev_ptmx" >&6; } +if test "x$ac_cv_file__dev_ptmx" = xyes +then : fi if test "x$ac_cv_file__dev_ptmx" = xyes; then -$as_echo "#define HAVE_DEV_PTMX 1" >>confdefs.h +printf "%s\n" "#define HAVE_DEV_PTMX 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5 -$as_echo_n "checking for /dev/ptc... " >&6; } -if ${ac_cv_file__dev_ptc+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5 +printf %s "checking for /dev/ptc... " >&6; } +if test ${ac_cv_file__dev_ptc+y} +then : + printf %s "(cached) " >&6 +else $as_nop test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "/dev/ptc"; then @@ -24326,15 +27102,16 @@ else ac_cv_file__dev_ptc=no fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptc" >&5 -$as_echo "$ac_cv_file__dev_ptc" >&6; } -if test "x$ac_cv_file__dev_ptc" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__dev_ptc" >&5 +printf "%s\n" "$ac_cv_file__dev_ptc" >&6; } +if test "x$ac_cv_file__dev_ptc" = xyes +then : fi if test "x$ac_cv_file__dev_ptc" = xyes; then -$as_echo "#define HAVE_DEV_PTC 1" >>confdefs.h +printf "%s\n" "#define HAVE_DEV_PTC 1" >>confdefs.h fi @@ -24352,23 +27129,26 @@ ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" " #endif " -if test "x$ac_cv_type_socklen_t" = xyes; then : +if test "x$ac_cv_type_socklen_t" = xyes +then : -else +else $as_nop -$as_echo "#define socklen_t int" >>confdefs.h +printf "%s\n" "#define socklen_t int" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken mbstowcs" >&5 -$as_echo_n "checking for broken mbstowcs... " >&6; } -if ${ac_cv_broken_mbstowcs+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken mbstowcs" >&5 +printf %s "checking for broken mbstowcs... " >&6; } +if test ${ac_cv_broken_mbstowcs+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : ac_cv_broken_mbstowcs=no -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24383,9 +27163,10 @@ int main(void) { } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_broken_mbstowcs=no -else +else $as_nop ac_cv_broken_mbstowcs=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -24393,57 +27174,60 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_mbstowcs" >&5 -$as_echo "$ac_cv_broken_mbstowcs" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_broken_mbstowcs" >&5 +printf "%s\n" "$ac_cv_broken_mbstowcs" >&6; } if test "$ac_cv_broken_mbstowcs" = yes then -$as_echo "#define HAVE_BROKEN_MBSTOWCS 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_MBSTOWCS 1" >>confdefs.h fi # Check for --with-computed-gotos -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-computed-gotos" >&5 -$as_echo_n "checking for --with-computed-gotos... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-computed-gotos" >&5 +printf %s "checking for --with-computed-gotos... " >&6; } # Check whether --with-computed-gotos was given. -if test "${with_computed_gotos+set}" = set; then : +if test ${with_computed_gotos+y} +then : withval=$with_computed_gotos; if test "$withval" = yes then -$as_echo "#define USE_COMPUTED_GOTOS 1" >>confdefs.h +printf "%s\n" "#define USE_COMPUTED_GOTOS 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } fi if test "$withval" = no then -$as_echo "#define USE_COMPUTED_GOTOS 0" >>confdefs.h +printf "%s\n" "#define USE_COMPUTED_GOTOS 0" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 -$as_echo "no value specified" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 +printf "%s\n" "no value specified" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 -$as_echo_n "checking whether $CC supports computed gotos... " >&6; } -if ${ac_cv_computed_gotos+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 +printf %s "checking whether $CC supports computed gotos... " >&6; } +if test ${ac_cv_computed_gotos+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test "$cross_compiling" = yes +then : if test "${with_computed_gotos+set}" = set; then ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" else ac_cv_computed_gotos=no fi -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24459,9 +27243,10 @@ LABEL2: } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : ac_cv_computed_gotos=yes -else +else $as_nop ac_cv_computed_gotos=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -24469,18 +27254,18 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_computed_gotos" >&5 -$as_echo "$ac_cv_computed_gotos" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_computed_gotos" >&5 +printf "%s\n" "$ac_cv_computed_gotos" >&6; } case "$ac_cv_computed_gotos" in yes*) -$as_echo "#define HAVE_COMPUTED_GOTOS 1" >>confdefs.h +printf "%s\n" "#define HAVE_COMPUTED_GOTOS 1" >>confdefs.h esac case $ac_sys_system in AIX*) -$as_echo "#define HAVE_BROKEN_PIPE_BUF 1" >>confdefs.h +printf "%s\n" "#define HAVE_BROKEN_PIPE_BUF 1" >>confdefs.h ;; esac @@ -24515,22 +27300,23 @@ SRCDIRS="\ Python \ Python/frozen_modules \ Python/deepfreeze" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for build directories" >&5 -$as_echo_n "checking for build directories... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build directories" >&5 +printf %s "checking for build directories... " >&6; } for dir in $SRCDIRS; do if test ! -d $dir; then mkdir $dir fi done -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 -$as_echo "done" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 +printf "%s\n" "done" >&6; } # Availability of -O2: -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -O2" >&5 -$as_echo_n "checking for -O2... " >&6; } -if ${ac_cv_compile_o2+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -O2" >&5 +printf %s "checking for -O2... " >&6; } +if test ${ac_cv_compile_o2+y} +then : + printf %s "(cached) " >&6 +else $as_nop saved_cflags="$CFLAGS" CFLAGS="-O2" @@ -24538,37 +27324,39 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_compile_o2=yes -else +else $as_nop ac_cv_compile_o2=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$saved_cflags" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_compile_o2" >&5 -$as_echo "$ac_cv_compile_o2" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_compile_o2" >&5 +printf "%s\n" "$ac_cv_compile_o2" >&6; } # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5 -$as_echo_n "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5 +printf %s "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; } saved_cflags="$CFLAGS" CFLAGS="-O2 -D_FORTIFY_SOURCE=2" if test "$ac_cv_compile_o2" = no; then CFLAGS="" fi -if test "$cross_compiling" = yes; then : +if test "$cross_compiling" = yes +then : have_glibc_memmove_bug=undefined -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24588,9 +27376,10 @@ int main(void) { } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : have_glibc_memmove_bug=no -else +else $as_nop have_glibc_memmove_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -24598,11 +27387,11 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi CFLAGS="$saved_cflags" -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5 -$as_echo "$have_glibc_memmove_bug" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5 +printf "%s\n" "$have_glibc_memmove_bug" >&6; } if test "$have_glibc_memmove_bug" = yes; then -$as_echo "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h +printf "%s\n" "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h fi @@ -24612,13 +27401,14 @@ if test "$ac_cv_gcc_asm_for_x87" = yes; then # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html case $CC in *gcc*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5 -$as_echo_n "checking for gcc ipa-pure-const bug... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5 +printf %s "checking for gcc ipa-pure-const bug... " >&6; } saved_cflags="$CFLAGS" CFLAGS="-O2" - if test "$cross_compiling" = yes; then : + if test "$cross_compiling" = yes +then : have_ipa_pure_const_bug=undefined -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24639,9 +27429,10 @@ else } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : +if ac_fn_c_try_run "$LINENO" +then : have_ipa_pure_const_bug=no -else +else $as_nop have_ipa_pure_const_bug=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ @@ -24649,11 +27440,11 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ fi CFLAGS="$saved_cflags" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5 -$as_echo "$have_ipa_pure_const_bug" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5 +printf "%s\n" "$have_ipa_pure_const_bug" >&6; } if test "$have_ipa_pure_const_bug" = yes; then -$as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h +printf "%s\n" "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h fi ;; @@ -24661,11 +27452,12 @@ $as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h fi # Check for stdatomic.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdatomic.h" >&5 -$as_echo_n "checking for stdatomic.h... " >&6; } -if ${ac_cv_header_stdatomic_h+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdatomic.h" >&5 +printf %s "checking for stdatomic.h... " >&6; } +if test ${ac_cv_header_stdatomic_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24683,32 +27475,35 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_header_stdatomic_h=yes -else +else $as_nop ac_cv_header_stdatomic_h=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdatomic_h" >&5 -$as_echo "$ac_cv_header_stdatomic_h" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdatomic_h" >&5 +printf "%s\n" "$ac_cv_header_stdatomic_h" >&6; } -if test "x$ac_cv_header_stdatomic_h" = xyes; then : +if test "x$ac_cv_header_stdatomic_h" = xyes +then : -$as_echo "#define HAVE_STD_ATOMIC 1" >>confdefs.h +printf "%s\n" "#define HAVE_STD_ATOMIC 1" >>confdefs.h fi # Check for GCC >= 4.7 and clang __atomic builtin functions -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __atomic_load_n and __atomic_store_n functions" >&5 -$as_echo_n "checking for builtin __atomic_load_n and __atomic_store_n functions... " >&6; } -if ${ac_cv_builtin_atomic+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for builtin __atomic_load_n and __atomic_store_n functions" >&5 +printf %s "checking for builtin __atomic_load_n and __atomic_store_n functions... " >&6; } +if test ${ac_cv_builtin_atomic+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24723,34 +27518,37 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_builtin_atomic=yes -else +else $as_nop ac_cv_builtin_atomic=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_builtin_atomic" >&5 -$as_echo "$ac_cv_builtin_atomic" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_builtin_atomic" >&5 +printf "%s\n" "$ac_cv_builtin_atomic" >&6; } -if test "x$ac_cv_builtin_atomic" = xyes; then : +if test "x$ac_cv_builtin_atomic" = xyes +then : -$as_echo "#define HAVE_BUILTIN_ATOMIC 1" >>confdefs.h +printf "%s\n" "#define HAVE_BUILTIN_ATOMIC 1" >>confdefs.h fi # ensurepip option -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5 -$as_echo_n "checking for ensurepip... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5 +printf %s "checking for ensurepip... " >&6; } # Check whether --with-ensurepip was given. -if test "${with_ensurepip+set}" = set; then : +if test ${with_ensurepip+y} +then : withval=$with_ensurepip; -else +else $as_nop case $ac_sys_system in #( Emscripten) : @@ -24774,16 +27572,17 @@ case $with_ensurepip in #( *) : as_fn_error $? "--with-ensurepip=upgrade|install|no" "$LINENO" 5 ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENSUREPIP" >&5 -$as_echo "$ENSUREPIP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ENSUREPIP" >&5 +printf "%s\n" "$ENSUREPIP" >&6; } # check if the dirent structure of a d_type field and DT_UNKNOWN is defined -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the dirent structure of a d_type field" >&5 -$as_echo_n "checking if the dirent structure of a d_type field... " >&6; } -if ${ac_cv_dirent_d_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the dirent structure of a d_type field" >&5 +printf %s "checking if the dirent structure of a d_type field... " >&6; } +if test ${ac_cv_dirent_d_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24798,32 +27597,35 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_dirent_d_type=yes -else +else $as_nop ac_cv_dirent_d_type=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dirent_d_type" >&5 -$as_echo "$ac_cv_dirent_d_type" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_dirent_d_type" >&5 +printf "%s\n" "$ac_cv_dirent_d_type" >&6; } -if test "x$ac_cv_dirent_d_type" = xyes; then : +if test "x$ac_cv_dirent_d_type" = xyes +then : -$as_echo "#define HAVE_DIRENT_D_TYPE 1" >>confdefs.h +printf "%s\n" "#define HAVE_DIRENT_D_TYPE 1" >>confdefs.h fi # check if the Linux getrandom() syscall is available -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Linux getrandom() syscall" >&5 -$as_echo_n "checking for the Linux getrandom() syscall... " >&6; } -if ${ac_cv_getrandom_syscall+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the Linux getrandom() syscall" >&5 +printf %s "checking for the Linux getrandom() syscall... " >&6; } +if test ${ac_cv_getrandom_syscall+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24845,33 +27647,36 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_getrandom_syscall=yes -else +else $as_nop ac_cv_getrandom_syscall=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_getrandom_syscall" >&5 -$as_echo "$ac_cv_getrandom_syscall" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_getrandom_syscall" >&5 +printf "%s\n" "$ac_cv_getrandom_syscall" >&6; } -if test "x$ac_cv_getrandom_syscall" = xyes; then : +if test "x$ac_cv_getrandom_syscall" = xyes +then : -$as_echo "#define HAVE_GETRANDOM_SYSCALL 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETRANDOM_SYSCALL 1" >>confdefs.h fi # check if the getrandom() function is available # the test was written for the Solaris function of -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the getrandom() function" >&5 -$as_echo_n "checking for the getrandom() function... " >&6; } -if ${ac_cv_func_getrandom+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the getrandom() function" >&5 +printf %s "checking for the getrandom() function... " >&6; } +if test ${ac_cv_func_getrandom+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24891,22 +27696,24 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_func_getrandom=yes -else +else $as_nop ac_cv_func_getrandom=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getrandom" >&5 -$as_echo "$ac_cv_func_getrandom" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getrandom" >&5 +printf "%s\n" "$ac_cv_func_getrandom" >&6; } -if test "x$ac_cv_func_getrandom" = xyes; then : +if test "x$ac_cv_func_getrandom" = xyes +then : -$as_echo "#define HAVE_GETRANDOM 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h fi @@ -24920,11 +27727,12 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing shm_open" >&5 -$as_echo_n "checking for library containing shm_open... " >&6; } -if ${ac_cv_search_shm_open+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing shm_open" >&5 +printf %s "checking for library containing shm_open... " >&6; } +if test ${ac_cv_search_shm_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24932,51 +27740,54 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char shm_open (); int -main () +main (void) { return shm_open (); ; return 0; } _ACEOF -for ac_lib in '' rt; do +for ac_lib in '' rt +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_shm_open=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_shm_open+:} false; then : + if test ${ac_cv_search_shm_open+y} +then : break fi done -if ${ac_cv_search_shm_open+:} false; then : +if test ${ac_cv_search_shm_open+y} +then : -else +else $as_nop ac_cv_search_shm_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_shm_open" >&5 -$as_echo "$ac_cv_search_shm_open" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_shm_open" >&5 +printf "%s\n" "$ac_cv_search_shm_open" >&6; } ac_res=$ac_cv_search_shm_open -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi - if test "x$ac_cv_search_shm_open" = x-lrt; then : + if test "x$ac_cv_search_shm_open" = x-lrt +then : POSIXSHMEM_LIBS="-lrt" fi @@ -24989,20 +27800,22 @@ fi # endif #endif " + for ac_func in shm_open shm_unlink do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` + as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : +if eval test \"x\$"$as_ac_var"\" = x"yes" +then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF have_posix_shmem=yes -else +else $as_nop have_posix_shmem=no fi -done +done ac_includes_default=$save_ac_includes_default CFLAGS=$save_CFLAGS @@ -25017,7 +27830,8 @@ LIBS=$save_LIBS found=false # Check whether --with-openssl was given. -if test "${with_openssl+set}" = set; then : +if test ${with_openssl+y} +then : withval=$with_openssl; case "$withval" in "" | y | ye | yes | n | no) @@ -25027,18 +27841,19 @@ if test "${with_openssl+set}" = set; then : ;; esac -else +else $as_nop # if pkg-config is installed and openssl has installed a .pc file, # then use that information and don't search ssldirs if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$PKG_CONFIG"; then ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. else @@ -25046,11 +27861,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -25061,11 +27880,11 @@ fi fi PKG_CONFIG=$ac_cv_prog_PKG_CONFIG if test -n "$PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -$as_echo "$PKG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -25074,11 +27893,12 @@ if test -z "$ac_cv_prog_PKG_CONFIG"; then ac_ct_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_PKG_CONFIG"; then ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test. else @@ -25086,11 +27906,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -25101,11 +27925,11 @@ fi fi ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG if test -n "$ac_ct_PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5 -$as_echo "$ac_ct_PKG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5 +printf "%s\n" "$ac_ct_PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_PKG_CONFIG" = x; then @@ -25113,8 +27937,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_ct_PKG_CONFIG @@ -25148,19 +27972,19 @@ fi if ! $found; then OPENSSL_INCLUDES= for ssldir in $ssldirs; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 -$as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for include/openssl/ssl.h in $ssldir" >&5 +printf %s "checking for include/openssl/ssl.h in $ssldir... " >&6; } if test -f "$ssldir/include/openssl/ssl.h"; then OPENSSL_INCLUDES="-I$ssldir/include" OPENSSL_LDFLAGS="-L$ssldir/lib" OPENSSL_LIBS="-lssl -lcrypto" found=true - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } break else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi done @@ -25171,8 +27995,8 @@ $as_echo "no" >&6; } # try the preprocessor and linker with our new flags, # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 -$as_echo_n "checking whether compiling and linking against OpenSSL works... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL works" >&5 +printf %s "checking whether compiling and linking against OpenSSL works... " >&6; } echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&5 @@ -25186,27 +28010,28 @@ $as_echo_n "checking whether compiling and linking against OpenSSL works... " >& /* end confdefs.h. */ #include int -main () +main (void) { SSL_new(NULL) ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_openssl=yes -else +else $as_nop - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } have_openssl=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" @@ -25218,23 +28043,25 @@ rm -f core conftest.err conftest.$ac_objext \ # rpath to libssl and libcrypto -if test "x$GNULD" = xyes; then : +if test "x$GNULD" = xyes +then : rpath_arg="-Wl,--enable-new-dtags,-rpath=" -else +else $as_nop rpath_arg="-Wl,-rpath=" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-openssl-rpath" >&5 -$as_echo_n "checking for --with-openssl-rpath... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-openssl-rpath" >&5 +printf %s "checking for --with-openssl-rpath... " >&6; } # Check whether --with-openssl-rpath was given. -if test "${with_openssl_rpath+set}" = set; then : +if test ${with_openssl_rpath+y} +then : withval=$with_openssl_rpath; -else +else $as_nop with_openssl_rpath=no fi @@ -25256,28 +28083,30 @@ esac no) : OPENSSL_RPATH= ;; #( *) : - if test -d "$with_openssl_rpath"; then : + if test -d "$with_openssl_rpath" +then : OPENSSL_RPATH="$with_openssl_rpath" OPENSSL_LDFLAGS_RPATH="${rpath_arg}$with_openssl_rpath" -else +else $as_nop as_fn_error $? "--with-openssl-rpath \"$with_openssl_rpath\" is not a directory" "$LINENO" 5 fi ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENSSL_RPATH" >&5 -$as_echo "$OPENSSL_RPATH" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OPENSSL_RPATH" >&5 +printf "%s\n" "$OPENSSL_RPATH" >&6; } # This static linking is NOT OFFICIALLY SUPPORTED and not advertised. # Requires static OpenSSL build with position-independent code. Some features # like DSO engines or external OSSL providers don't work. Only tested with GCC # and clang on X86_64. -if test "x$PY_UNSUPPORTED_OPENSSL_BUILD" = xstatic; then : +if test "x$PY_UNSUPPORTED_OPENSSL_BUILD" = xstatic +then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsupported static openssl build" >&5 -$as_echo_n "checking for unsupported static openssl build... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unsupported static openssl build" >&5 +printf %s "checking for unsupported static openssl build... " >&6; } new_OPENSSL_LIBS= for arg in $OPENSSL_LIBS; do case $arg in #( @@ -25292,8 +28121,8 @@ $as_echo_n "checking for unsupported static openssl build... " >&6; } esac done OPENSSL_LIBS="$new_OPENSSL_LIBS $ZLIB_LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENSSL_LIBS" >&5 -$as_echo "$OPENSSL_LIBS" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OPENSSL_LIBS" >&5 +printf "%s\n" "$OPENSSL_LIBS" >&6; } fi @@ -25319,11 +28148,12 @@ save_LIBS=$LIBS CFLAGS="$CFLAGS $OPENSSL_INCLUDES" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS $OPENSSL_LDFLAGS_RPATH" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL provides required ssl module APIs" >&5 -$as_echo_n "checking whether OpenSSL provides required ssl module APIs... " >&6; } -if ${ac_cv_working_openssl_ssl+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL provides required ssl module APIs" >&5 +printf %s "checking whether OpenSSL provides required ssl module APIs... " >&6; } +if test ${ac_cv_working_openssl_ssl+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -25336,7 +28166,7 @@ else static void keylog_cb(const SSL *ssl, const char *line) {} int -main () +main (void) { SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); @@ -25351,17 +28181,18 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_working_openssl_ssl=yes -else +else $as_nop ac_cv_working_openssl_ssl=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_ssl" >&5 -$as_echo "$ac_cv_working_openssl_ssl" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_ssl" >&5 +printf "%s\n" "$ac_cv_working_openssl_ssl" >&6; } CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS @@ -25380,11 +28211,12 @@ save_LIBS=$LIBS CFLAGS="$CFLAGS $OPENSSL_INCLUDES" LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS $OPENSSL_LDFLAGS_RPATH" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL provides required hashlib module APIs" >&5 -$as_echo_n "checking whether OpenSSL provides required hashlib module APIs... " >&6; } -if ${ac_cv_working_openssl_hashlib+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether OpenSSL provides required hashlib module APIs" >&5 +printf %s "checking whether OpenSSL provides required hashlib module APIs... " >&6; } +if test ${ac_cv_working_openssl_hashlib+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -25396,7 +28228,7 @@ else #endif int -main () +main (void) { OBJ_nid2sn(NID_md5); @@ -25409,17 +28241,18 @@ main () return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_working_openssl_hashlib=yes -else +else $as_nop ac_cv_working_openssl_hashlib=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_hashlib" >&5 -$as_echo "$ac_cv_working_openssl_hashlib" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_openssl_hashlib" >&5 +printf "%s\n" "$ac_cv_working_openssl_hashlib" >&6; } CFLAGS=$save_CFLAGS CPPFLAGS=$save_CPPFLAGS @@ -25432,38 +28265,37 @@ LIBS=$save_LIBS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-ssl-default-suites" >&5 -$as_echo_n "checking for --with-ssl-default-suites... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-ssl-default-suites" >&5 +printf %s "checking for --with-ssl-default-suites... " >&6; } # Check whether --with-ssl-default-suites was given. -if test "${with_ssl_default_suites+set}" = set; then : +if test ${with_ssl_default_suites+y} +then : withval=$with_ssl_default_suites; -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 -$as_echo "$withval" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 +printf "%s\n" "$withval" >&6; } case "$withval" in python) - $as_echo "#define PY_SSL_DEFAULT_CIPHERS 1" >>confdefs.h + printf "%s\n" "#define PY_SSL_DEFAULT_CIPHERS 1" >>confdefs.h ;; openssl) - $as_echo "#define PY_SSL_DEFAULT_CIPHERS 2" >>confdefs.h + printf "%s\n" "#define PY_SSL_DEFAULT_CIPHERS 2" >>confdefs.h ;; *) - $as_echo "#define PY_SSL_DEFAULT_CIPHERS 0" >>confdefs.h + printf "%s\n" "#define PY_SSL_DEFAULT_CIPHERS 0" >>confdefs.h - cat >>confdefs.h <<_ACEOF -#define PY_SSL_DEFAULT_CIPHER_STRING "$withval" -_ACEOF + printf "%s\n" "#define PY_SSL_DEFAULT_CIPHER_STRING \"$withval\"" >>confdefs.h ;; esac -else +else $as_nop -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: python" >&5 -$as_echo "python" >&6; } -$as_echo "#define PY_SSL_DEFAULT_CIPHERS 1" >>confdefs.h +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: python" >&5 +printf "%s\n" "python" >&6; } +printf "%s\n" "#define PY_SSL_DEFAULT_CIPHERS 1" >>confdefs.h fi @@ -25472,13 +28304,14 @@ fi # builtin hash modules default_hashlib_hashes="md5,sha1,sha2,sha3,blake2" -$as_echo "#define PY_BUILTIN_HASHLIB_HASHES /**/" >>confdefs.h +printf "%s\n" "#define PY_BUILTIN_HASHLIB_HASHES /**/" >>confdefs.h -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-builtin-hashlib-hashes" >&5 -$as_echo_n "checking for --with-builtin-hashlib-hashes... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-builtin-hashlib-hashes" >&5 +printf %s "checking for --with-builtin-hashlib-hashes... " >&6; } # Check whether --with-builtin-hashlib-hashes was given. -if test "${with_builtin_hashlib_hashes+set}" = set; then : +if test ${with_builtin_hashlib_hashes+y} +then : withval=$with_builtin_hashlib_hashes; case $with_builtin_hashlib_hashes in #( yes) : @@ -25490,16 +28323,14 @@ if test "${with_builtin_hashlib_hashes+set}" = set; then : ;; esac -else +else $as_nop with_builtin_hashlib_hashes=$default_hashlib_hashes fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_builtin_hashlib_hashes" >&5 -$as_echo "$with_builtin_hashlib_hashes" >&6; } -cat >>confdefs.h <<_ACEOF -#define PY_BUILTIN_HASHLIB_HASHES "$with_builtin_hashlib_hashes" -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_builtin_hashlib_hashes" >&5 +printf "%s\n" "$with_builtin_hashlib_hashes" >&6; } +printf "%s\n" "#define PY_BUILTIN_HASHLIB_HASHES \"$with_builtin_hashlib_hashes\"" >>confdefs.h as_save_IFS=$IFS @@ -25523,21 +28354,22 @@ esac done IFS=$as_save_IFS -if test "x$with_builtin_blake2" = xyes; then : +if test "x$with_builtin_blake2" = xyes +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBB2" >&5 -$as_echo_n "checking for LIBB2... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBB2" >&5 +printf %s "checking for LIBB2... " >&6; } if test -n "$LIBB2_CFLAGS"; then pkg_cv_LIBB2_CFLAGS="$LIBB2_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libb2\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libb2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libb2") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBB2_CFLAGS=`$PKG_CONFIG --cflags "libb2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -25551,10 +28383,10 @@ if test -n "$LIBB2_LIBS"; then pkg_cv_LIBB2_LIBS="$LIBB2_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libb2\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libb2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libb2") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBB2_LIBS=`$PKG_CONFIG --libs "libb2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -25568,8 +28400,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -25586,18 +28418,18 @@ fi have_libb2=no elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } have_libb2=no else LIBB2_CFLAGS=$pkg_cv_LIBB2_CFLAGS LIBB2_LIBS=$pkg_cv_LIBB2_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } have_libb2=yes -$as_echo "#define HAVE_LIBB2 1" >>confdefs.h +printf "%s\n" "#define HAVE_LIBB2 1" >>confdefs.h fi @@ -25606,18 +28438,20 @@ fi # Check whether to disable test modules. Once set, setup.py will not build # test extension modules and "make install" will not install test suites. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --disable-test-modules" >&5 -$as_echo_n "checking for --disable-test-modules... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --disable-test-modules" >&5 +printf %s "checking for --disable-test-modules... " >&6; } # Check whether --enable-test-modules was given. -if test "${enable_test_modules+set}" = set; then : +if test ${enable_test_modules+y} +then : enableval=$enable_test_modules; - if test "x$enable_test_modules" = xyes; then : + if test "x$enable_test_modules" = xyes +then : TEST_MODULES=yes -else +else $as_nop TEST_MODULES=no fi -else +else $as_nop case $ac_sys_system/$ac_sys_emscripten_target in #( Emscripten/browser*) : @@ -25629,8 +28463,8 @@ esac fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TEST_MODULES" >&5 -$as_echo "$TEST_MODULES" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEST_MODULES" >&5 +printf "%s\n" "$TEST_MODULES" >&6; } @@ -25754,7 +28588,8 @@ MODULE_BLOCK= - if test "$py_cv_module__io" != "n/a"; then : + if test "$py_cv_module__io" != "n/a" +then : py_cv_module__io=yes fi if test "$py_cv_module__io" = yes; then @@ -25766,7 +28601,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__IO_STATE=$py_cv_module__io$as_nl" - if test "x$py_cv_module__io" = xyes; then : + if test "x$py_cv_module__io" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__IO_CFLAGS=-I\$(srcdir)/Modules/_io$as_nl" @@ -25774,7 +28610,8 @@ fi fi - if test "$py_cv_module_time" != "n/a"; then : + if test "$py_cv_module_time" != "n/a" +then : py_cv_module_time=yes fi if test "$py_cv_module_time" = yes; then @@ -25786,7 +28623,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_TIME_STATE=$py_cv_module_time$as_nl" - if test "x$py_cv_module_time" = xyes; then : + if test "x$py_cv_module_time" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_TIME_LDFLAGS=$TIMEMODULE_LIB$as_nl" @@ -25795,7 +28633,8 @@ fi - if test "$py_cv_module_array" != "n/a"; then : + if test "$py_cv_module_array" != "n/a" +then : py_cv_module_array=yes fi if test "$py_cv_module_array" = yes; then @@ -25807,7 +28646,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_ARRAY_STATE=$py_cv_module_array$as_nl" - if test "x$py_cv_module_array" = xyes; then : + if test "x$py_cv_module_array" = xyes +then : @@ -25815,7 +28655,8 @@ fi fi - if test "$py_cv_module__asyncio" != "n/a"; then : + if test "$py_cv_module__asyncio" != "n/a" +then : py_cv_module__asyncio=yes fi if test "$py_cv_module__asyncio" = yes; then @@ -25827,7 +28668,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__ASYNCIO_STATE=$py_cv_module__asyncio$as_nl" - if test "x$py_cv_module__asyncio" = xyes; then : + if test "x$py_cv_module__asyncio" = xyes +then : @@ -25835,7 +28677,8 @@ fi fi - if test "$py_cv_module__bisect" != "n/a"; then : + if test "$py_cv_module__bisect" != "n/a" +then : py_cv_module__bisect=yes fi if test "$py_cv_module__bisect" = yes; then @@ -25847,7 +28690,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__BISECT_STATE=$py_cv_module__bisect$as_nl" - if test "x$py_cv_module__bisect" = xyes; then : + if test "x$py_cv_module__bisect" = xyes +then : @@ -25855,7 +28699,8 @@ fi fi - if test "$py_cv_module__contextvars" != "n/a"; then : + if test "$py_cv_module__contextvars" != "n/a" +then : py_cv_module__contextvars=yes fi if test "$py_cv_module__contextvars" = yes; then @@ -25867,7 +28712,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CONTEXTVARS_STATE=$py_cv_module__contextvars$as_nl" - if test "x$py_cv_module__contextvars" = xyes; then : + if test "x$py_cv_module__contextvars" = xyes +then : @@ -25875,7 +28721,8 @@ fi fi - if test "$py_cv_module__csv" != "n/a"; then : + if test "$py_cv_module__csv" != "n/a" +then : py_cv_module__csv=yes fi if test "$py_cv_module__csv" = yes; then @@ -25887,7 +28734,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CSV_STATE=$py_cv_module__csv$as_nl" - if test "x$py_cv_module__csv" = xyes; then : + if test "x$py_cv_module__csv" = xyes +then : @@ -25895,7 +28743,8 @@ fi fi - if test "$py_cv_module__heapq" != "n/a"; then : + if test "$py_cv_module__heapq" != "n/a" +then : py_cv_module__heapq=yes fi if test "$py_cv_module__heapq" = yes; then @@ -25907,7 +28756,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__HEAPQ_STATE=$py_cv_module__heapq$as_nl" - if test "x$py_cv_module__heapq" = xyes; then : + if test "x$py_cv_module__heapq" = xyes +then : @@ -25915,7 +28765,8 @@ fi fi - if test "$py_cv_module__json" != "n/a"; then : + if test "$py_cv_module__json" != "n/a" +then : py_cv_module__json=yes fi if test "$py_cv_module__json" = yes; then @@ -25927,7 +28778,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__JSON_STATE=$py_cv_module__json$as_nl" - if test "x$py_cv_module__json" = xyes; then : + if test "x$py_cv_module__json" = xyes +then : @@ -25935,7 +28787,8 @@ fi fi - if test "$py_cv_module__lsprof" != "n/a"; then : + if test "$py_cv_module__lsprof" != "n/a" +then : py_cv_module__lsprof=yes fi if test "$py_cv_module__lsprof" = yes; then @@ -25947,7 +28800,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__LSPROF_STATE=$py_cv_module__lsprof$as_nl" - if test "x$py_cv_module__lsprof" = xyes; then : + if test "x$py_cv_module__lsprof" = xyes +then : @@ -25955,7 +28809,8 @@ fi fi - if test "$py_cv_module__opcode" != "n/a"; then : + if test "$py_cv_module__opcode" != "n/a" +then : py_cv_module__opcode=yes fi if test "$py_cv_module__opcode" = yes; then @@ -25967,7 +28822,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__OPCODE_STATE=$py_cv_module__opcode$as_nl" - if test "x$py_cv_module__opcode" = xyes; then : + if test "x$py_cv_module__opcode" = xyes +then : @@ -25975,7 +28831,8 @@ fi fi - if test "$py_cv_module__pickle" != "n/a"; then : + if test "$py_cv_module__pickle" != "n/a" +then : py_cv_module__pickle=yes fi if test "$py_cv_module__pickle" = yes; then @@ -25987,7 +28844,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__PICKLE_STATE=$py_cv_module__pickle$as_nl" - if test "x$py_cv_module__pickle" = xyes; then : + if test "x$py_cv_module__pickle" = xyes +then : @@ -25995,7 +28853,8 @@ fi fi - if test "$py_cv_module__posixsubprocess" != "n/a"; then : + if test "$py_cv_module__posixsubprocess" != "n/a" +then : py_cv_module__posixsubprocess=yes fi if test "$py_cv_module__posixsubprocess" = yes; then @@ -26007,7 +28866,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__POSIXSUBPROCESS_STATE=$py_cv_module__posixsubprocess$as_nl" - if test "x$py_cv_module__posixsubprocess" = xyes; then : + if test "x$py_cv_module__posixsubprocess" = xyes +then : @@ -26015,7 +28875,8 @@ fi fi - if test "$py_cv_module__queue" != "n/a"; then : + if test "$py_cv_module__queue" != "n/a" +then : py_cv_module__queue=yes fi if test "$py_cv_module__queue" = yes; then @@ -26027,7 +28888,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__QUEUE_STATE=$py_cv_module__queue$as_nl" - if test "x$py_cv_module__queue" = xyes; then : + if test "x$py_cv_module__queue" = xyes +then : @@ -26035,7 +28897,8 @@ fi fi - if test "$py_cv_module__random" != "n/a"; then : + if test "$py_cv_module__random" != "n/a" +then : py_cv_module__random=yes fi if test "$py_cv_module__random" = yes; then @@ -26047,7 +28910,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__RANDOM_STATE=$py_cv_module__random$as_nl" - if test "x$py_cv_module__random" = xyes; then : + if test "x$py_cv_module__random" = xyes +then : @@ -26055,7 +28919,8 @@ fi fi - if test "$py_cv_module_select" != "n/a"; then : + if test "$py_cv_module_select" != "n/a" +then : py_cv_module_select=yes fi if test "$py_cv_module_select" = yes; then @@ -26067,7 +28932,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_SELECT_STATE=$py_cv_module_select$as_nl" - if test "x$py_cv_module_select" = xyes; then : + if test "x$py_cv_module_select" = xyes +then : @@ -26075,7 +28941,8 @@ fi fi - if test "$py_cv_module__struct" != "n/a"; then : + if test "$py_cv_module__struct" != "n/a" +then : py_cv_module__struct=yes fi if test "$py_cv_module__struct" = yes; then @@ -26087,7 +28954,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__STRUCT_STATE=$py_cv_module__struct$as_nl" - if test "x$py_cv_module__struct" = xyes; then : + if test "x$py_cv_module__struct" = xyes +then : @@ -26095,7 +28963,8 @@ fi fi - if test "$py_cv_module__typing" != "n/a"; then : + if test "$py_cv_module__typing" != "n/a" +then : py_cv_module__typing=yes fi if test "$py_cv_module__typing" = yes; then @@ -26107,7 +28976,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__TYPING_STATE=$py_cv_module__typing$as_nl" - if test "x$py_cv_module__typing" = xyes; then : + if test "x$py_cv_module__typing" = xyes +then : @@ -26115,7 +28985,8 @@ fi fi - if test "$py_cv_module__xxsubinterpreters" != "n/a"; then : + if test "$py_cv_module__xxsubinterpreters" != "n/a" +then : py_cv_module__xxsubinterpreters=yes fi if test "$py_cv_module__xxsubinterpreters" = yes; then @@ -26127,7 +28998,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__XXSUBINTERPRETERS_STATE=$py_cv_module__xxsubinterpreters$as_nl" - if test "x$py_cv_module__xxsubinterpreters" = xyes; then : + if test "x$py_cv_module__xxsubinterpreters" = xyes +then : @@ -26135,7 +29007,8 @@ fi fi - if test "$py_cv_module__xxinterpchannels" != "n/a"; then : + if test "$py_cv_module__xxinterpchannels" != "n/a" +then : py_cv_module__xxinterpchannels=yes fi if test "$py_cv_module__xxinterpchannels" = yes; then @@ -26147,7 +29020,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__XXINTERPCHANNELS_STATE=$py_cv_module__xxinterpchannels$as_nl" - if test "x$py_cv_module__xxinterpchannels" = xyes; then : + if test "x$py_cv_module__xxinterpchannels" = xyes +then : @@ -26155,7 +29029,8 @@ fi fi - if test "$py_cv_module__zoneinfo" != "n/a"; then : + if test "$py_cv_module__zoneinfo" != "n/a" +then : py_cv_module__zoneinfo=yes fi if test "$py_cv_module__zoneinfo" = yes; then @@ -26167,7 +29042,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__ZONEINFO_STATE=$py_cv_module__zoneinfo$as_nl" - if test "x$py_cv_module__zoneinfo" = xyes; then : + if test "x$py_cv_module__zoneinfo" = xyes +then : @@ -26176,23 +29052,27 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _multiprocessing" >&5 -$as_echo_n "checking for stdlib extension module _multiprocessing... " >&6; } - if test "$py_cv_module__multiprocessing" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _multiprocessing" >&5 +printf %s "checking for stdlib extension module _multiprocessing... " >&6; } + if test "$py_cv_module__multiprocessing" != "n/a" +then : - if true; then : - if test "$ac_cv_func_sem_unlink" = "yes"; then : + if true +then : + if test "$ac_cv_func_sem_unlink" = "yes" +then : py_cv_module__multiprocessing=yes -else +else $as_nop py_cv_module__multiprocessing=missing fi -else +else $as_nop py_cv_module__multiprocessing=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__MULTIPROCESSING_STATE=$py_cv_module__multiprocessing$as_nl" - if test "x$py_cv_module__multiprocessing" = xyes; then : + if test "x$py_cv_module__multiprocessing" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__MULTIPROCESSING_CFLAGS=-I\$(srcdir)/Modules/_multiprocessing$as_nl" @@ -26206,27 +29086,31 @@ else MODULE__MULTIPROCESSING_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__multiprocessing" >&5 -$as_echo "$py_cv_module__multiprocessing" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__multiprocessing" >&5 +printf "%s\n" "$py_cv_module__multiprocessing" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _posixshmem" >&5 -$as_echo_n "checking for stdlib extension module _posixshmem... " >&6; } - if test "$py_cv_module__posixshmem" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _posixshmem" >&5 +printf %s "checking for stdlib extension module _posixshmem... " >&6; } + if test "$py_cv_module__posixshmem" != "n/a" +then : - if true; then : - if test "$have_posix_shmem" = "yes"; then : + if true +then : + if test "$have_posix_shmem" = "yes" +then : py_cv_module__posixshmem=yes -else +else $as_nop py_cv_module__posixshmem=missing fi -else +else $as_nop py_cv_module__posixshmem=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__POSIXSHMEM_STATE=$py_cv_module__posixshmem$as_nl" - if test "x$py_cv_module__posixshmem" = xyes; then : + if test "x$py_cv_module__posixshmem" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__POSIXSHMEM_CFLAGS=$POSIXSHMEM_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__POSIXSHMEM_LDFLAGS=$POSIXSHMEM_LIBS$as_nl" @@ -26240,12 +29124,13 @@ else MODULE__POSIXSHMEM_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__posixshmem" >&5 -$as_echo "$py_cv_module__posixshmem" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__posixshmem" >&5 +printf "%s\n" "$py_cv_module__posixshmem" >&6; } - if test "$py_cv_module_audioop" != "n/a"; then : + if test "$py_cv_module_audioop" != "n/a" +then : py_cv_module_audioop=yes fi if test "$py_cv_module_audioop" = yes; then @@ -26257,7 +29142,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_AUDIOOP_STATE=$py_cv_module_audioop$as_nl" - if test "x$py_cv_module_audioop" = xyes; then : + if test "x$py_cv_module_audioop" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_AUDIOOP_LDFLAGS=$LIBM$as_nl" @@ -26265,7 +29151,8 @@ fi fi - if test "$py_cv_module__statistics" != "n/a"; then : + if test "$py_cv_module__statistics" != "n/a" +then : py_cv_module__statistics=yes fi if test "$py_cv_module__statistics" = yes; then @@ -26277,7 +29164,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__STATISTICS_STATE=$py_cv_module__statistics$as_nl" - if test "x$py_cv_module__statistics" = xyes; then : + if test "x$py_cv_module__statistics" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__STATISTICS_LDFLAGS=$LIBM$as_nl" @@ -26285,7 +29173,8 @@ fi fi - if test "$py_cv_module_cmath" != "n/a"; then : + if test "$py_cv_module_cmath" != "n/a" +then : py_cv_module_cmath=yes fi if test "$py_cv_module_cmath" = yes; then @@ -26297,7 +29186,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_CMATH_STATE=$py_cv_module_cmath$as_nl" - if test "x$py_cv_module_cmath" = xyes; then : + if test "x$py_cv_module_cmath" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_CMATH_LDFLAGS=$LIBM$as_nl" @@ -26305,7 +29195,8 @@ fi fi - if test "$py_cv_module_math" != "n/a"; then : + if test "$py_cv_module_math" != "n/a" +then : py_cv_module_math=yes fi if test "$py_cv_module_math" = yes; then @@ -26317,7 +29208,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_MATH_STATE=$py_cv_module_math$as_nl" - if test "x$py_cv_module_math" = xyes; then : + if test "x$py_cv_module_math" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_MATH_LDFLAGS=$LIBM$as_nl" @@ -26326,7 +29218,8 @@ fi - if test "$py_cv_module__datetime" != "n/a"; then : + if test "$py_cv_module__datetime" != "n/a" +then : py_cv_module__datetime=yes fi if test "$py_cv_module__datetime" = yes; then @@ -26338,7 +29231,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__DATETIME_STATE=$py_cv_module__datetime$as_nl" - if test "x$py_cv_module__datetime" = xyes; then : + if test "x$py_cv_module__datetime" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__DATETIME_LDFLAGS=$TIMEMODULE_LIB $LIBM$as_nl" @@ -26347,23 +29241,27 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module fcntl" >&5 -$as_echo_n "checking for stdlib extension module fcntl... " >&6; } - if test "$py_cv_module_fcntl" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module fcntl" >&5 +printf %s "checking for stdlib extension module fcntl... " >&6; } + if test "$py_cv_module_fcntl" != "n/a" +then : - if true; then : - if test "$ac_cv_header_sys_ioctl_h" = "yes" -a "$ac_cv_header_fcntl_h" = "yes"; then : + if true +then : + if test "$ac_cv_header_sys_ioctl_h" = "yes" -a "$ac_cv_header_fcntl_h" = "yes" +then : py_cv_module_fcntl=yes -else +else $as_nop py_cv_module_fcntl=missing fi -else +else $as_nop py_cv_module_fcntl=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_FCNTL_STATE=$py_cv_module_fcntl$as_nl" - if test "x$py_cv_module_fcntl" = xyes; then : + if test "x$py_cv_module_fcntl" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_FCNTL_LDFLAGS=$FCNTL_LIBS$as_nl" @@ -26377,27 +29275,31 @@ else MODULE_FCNTL_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_fcntl" >&5 -$as_echo "$py_cv_module_fcntl" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_fcntl" >&5 +printf "%s\n" "$py_cv_module_fcntl" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module mmap" >&5 -$as_echo_n "checking for stdlib extension module mmap... " >&6; } - if test "$py_cv_module_mmap" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module mmap" >&5 +printf %s "checking for stdlib extension module mmap... " >&6; } + if test "$py_cv_module_mmap" != "n/a" +then : - if true; then : - if test "$ac_cv_header_sys_mman_h" = "yes" -a "$ac_cv_header_sys_stat_h" = "yes"; then : + if true +then : + if test "$ac_cv_header_sys_mman_h" = "yes" -a "$ac_cv_header_sys_stat_h" = "yes" +then : py_cv_module_mmap=yes -else +else $as_nop py_cv_module_mmap=missing fi -else +else $as_nop py_cv_module_mmap=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_MMAP_STATE=$py_cv_module_mmap$as_nl" - if test "x$py_cv_module_mmap" = xyes; then : + if test "x$py_cv_module_mmap" = xyes +then : @@ -26411,27 +29313,31 @@ else MODULE_MMAP_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_mmap" >&5 -$as_echo "$py_cv_module_mmap" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_mmap" >&5 +printf "%s\n" "$py_cv_module_mmap" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _socket" >&5 -$as_echo_n "checking for stdlib extension module _socket... " >&6; } - if test "$py_cv_module__socket" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _socket" >&5 +printf %s "checking for stdlib extension module _socket... " >&6; } + if test "$py_cv_module__socket" != "n/a" +then : - if true; then : - if test "$ac_cv_header_sys_socket_h" = "yes" -a "$ac_cv_header_sys_types_h" = "yes" -a "$ac_cv_header_netinet_in_h" = "yes"; then : + if true +then : + if test "$ac_cv_header_sys_socket_h" = "yes" -a "$ac_cv_header_sys_types_h" = "yes" -a "$ac_cv_header_netinet_in_h" = "yes" +then : py_cv_module__socket=yes -else +else $as_nop py_cv_module__socket=missing fi -else +else $as_nop py_cv_module__socket=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__SOCKET_STATE=$py_cv_module__socket$as_nl" - if test "x$py_cv_module__socket" = xyes; then : + if test "x$py_cv_module__socket" = xyes +then : @@ -26445,28 +29351,32 @@ else MODULE__SOCKET_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__socket" >&5 -$as_echo "$py_cv_module__socket" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__socket" >&5 +printf "%s\n" "$py_cv_module__socket" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module grp" >&5 -$as_echo_n "checking for stdlib extension module grp... " >&6; } - if test "$py_cv_module_grp" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module grp" >&5 +printf %s "checking for stdlib extension module grp... " >&6; } + if test "$py_cv_module_grp" != "n/a" +then : - if true; then : - if test "$ac_cv_func_getgrgid" = yes -o "$ac_cv_func_getgrgid_r" = yes; then : + if true +then : + if test "$ac_cv_func_getgrgid" = yes -o "$ac_cv_func_getgrgid_r" = yes +then : py_cv_module_grp=yes -else +else $as_nop py_cv_module_grp=missing fi -else +else $as_nop py_cv_module_grp=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_GRP_STATE=$py_cv_module_grp$as_nl" - if test "x$py_cv_module_grp" = xyes; then : + if test "x$py_cv_module_grp" = xyes +then : @@ -26480,27 +29390,31 @@ else MODULE_GRP_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_grp" >&5 -$as_echo "$py_cv_module_grp" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_grp" >&5 +printf "%s\n" "$py_cv_module_grp" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module ossaudiodev" >&5 -$as_echo_n "checking for stdlib extension module ossaudiodev... " >&6; } - if test "$py_cv_module_ossaudiodev" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module ossaudiodev" >&5 +printf %s "checking for stdlib extension module ossaudiodev... " >&6; } + if test "$py_cv_module_ossaudiodev" != "n/a" +then : - if true; then : - if test "$ac_cv_header_linux_soundcard_h" = yes -o "$ac_cv_header_sys_soundcard_h" = yes; then : + if true +then : + if test "$ac_cv_header_linux_soundcard_h" = yes -o "$ac_cv_header_sys_soundcard_h" = yes +then : py_cv_module_ossaudiodev=yes -else +else $as_nop py_cv_module_ossaudiodev=missing fi -else +else $as_nop py_cv_module_ossaudiodev=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_OSSAUDIODEV_STATE=$py_cv_module_ossaudiodev$as_nl" - if test "x$py_cv_module_ossaudiodev" = xyes; then : + if test "x$py_cv_module_ossaudiodev" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_OSSAUDIODEV_LDFLAGS=$OSSAUDIODEV_LIBS$as_nl" @@ -26514,27 +29428,31 @@ else MODULE_OSSAUDIODEV_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_ossaudiodev" >&5 -$as_echo "$py_cv_module_ossaudiodev" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_ossaudiodev" >&5 +printf "%s\n" "$py_cv_module_ossaudiodev" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module pwd" >&5 -$as_echo_n "checking for stdlib extension module pwd... " >&6; } - if test "$py_cv_module_pwd" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module pwd" >&5 +printf %s "checking for stdlib extension module pwd... " >&6; } + if test "$py_cv_module_pwd" != "n/a" +then : - if true; then : - if test "$ac_cv_func_getpwuid" = yes -o "$ac_cv_func_getpwuid_r" = yes; then : + if true +then : + if test "$ac_cv_func_getpwuid" = yes -o "$ac_cv_func_getpwuid_r" = yes +then : py_cv_module_pwd=yes -else +else $as_nop py_cv_module_pwd=missing fi -else +else $as_nop py_cv_module_pwd=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_PWD_STATE=$py_cv_module_pwd$as_nl" - if test "x$py_cv_module_pwd" = xyes; then : + if test "x$py_cv_module_pwd" = xyes +then : @@ -26548,27 +29466,31 @@ else MODULE_PWD_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_pwd" >&5 -$as_echo "$py_cv_module_pwd" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_pwd" >&5 +printf "%s\n" "$py_cv_module_pwd" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module resource" >&5 -$as_echo_n "checking for stdlib extension module resource... " >&6; } - if test "$py_cv_module_resource" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module resource" >&5 +printf %s "checking for stdlib extension module resource... " >&6; } + if test "$py_cv_module_resource" != "n/a" +then : - if true; then : - if test "$ac_cv_header_sys_resource_h" = yes; then : + if true +then : + if test "$ac_cv_header_sys_resource_h" = yes +then : py_cv_module_resource=yes -else +else $as_nop py_cv_module_resource=missing fi -else +else $as_nop py_cv_module_resource=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_RESOURCE_STATE=$py_cv_module_resource$as_nl" - if test "x$py_cv_module_resource" = xyes; then : + if test "x$py_cv_module_resource" = xyes +then : @@ -26582,27 +29504,31 @@ else MODULE_RESOURCE_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_resource" >&5 -$as_echo "$py_cv_module_resource" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_resource" >&5 +printf "%s\n" "$py_cv_module_resource" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _scproxy" >&5 -$as_echo_n "checking for stdlib extension module _scproxy... " >&6; } - if test "$py_cv_module__scproxy" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _scproxy" >&5 +printf %s "checking for stdlib extension module _scproxy... " >&6; } + if test "$py_cv_module__scproxy" != "n/a" +then : - if test "$ac_sys_system" = "Darwin"; then : - if true; then : + if test "$ac_sys_system" = "Darwin" +then : + if true +then : py_cv_module__scproxy=yes -else +else $as_nop py_cv_module__scproxy=missing fi -else +else $as_nop py_cv_module__scproxy=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__SCPROXY_STATE=$py_cv_module__scproxy$as_nl" - if test "x$py_cv_module__scproxy" = xyes; then : + if test "x$py_cv_module__scproxy" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__SCPROXY_LDFLAGS=-framework SystemConfiguration -framework CoreFoundation$as_nl" @@ -26616,27 +29542,31 @@ else MODULE__SCPROXY_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__scproxy" >&5 -$as_echo "$py_cv_module__scproxy" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__scproxy" >&5 +printf "%s\n" "$py_cv_module__scproxy" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module spwd" >&5 -$as_echo_n "checking for stdlib extension module spwd... " >&6; } - if test "$py_cv_module_spwd" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module spwd" >&5 +printf %s "checking for stdlib extension module spwd... " >&6; } + if test "$py_cv_module_spwd" != "n/a" +then : - if true; then : - if test "$ac_cv_func_getspent" = yes -o "$ac_cv_func_getspnam" = yes; then : + if true +then : + if test "$ac_cv_func_getspent" = yes -o "$ac_cv_func_getspnam" = yes +then : py_cv_module_spwd=yes -else +else $as_nop py_cv_module_spwd=missing fi -else +else $as_nop py_cv_module_spwd=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_SPWD_STATE=$py_cv_module_spwd$as_nl" - if test "x$py_cv_module_spwd" = xyes; then : + if test "x$py_cv_module_spwd" = xyes +then : @@ -26650,27 +29580,31 @@ else MODULE_SPWD_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_spwd" >&5 -$as_echo "$py_cv_module_spwd" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_spwd" >&5 +printf "%s\n" "$py_cv_module_spwd" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module syslog" >&5 -$as_echo_n "checking for stdlib extension module syslog... " >&6; } - if test "$py_cv_module_syslog" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module syslog" >&5 +printf %s "checking for stdlib extension module syslog... " >&6; } + if test "$py_cv_module_syslog" != "n/a" +then : - if true; then : - if test "$ac_cv_header_syslog_h" = yes; then : + if true +then : + if test "$ac_cv_header_syslog_h" = yes +then : py_cv_module_syslog=yes -else +else $as_nop py_cv_module_syslog=missing fi -else +else $as_nop py_cv_module_syslog=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_SYSLOG_STATE=$py_cv_module_syslog$as_nl" - if test "x$py_cv_module_syslog" = xyes; then : + if test "x$py_cv_module_syslog" = xyes +then : @@ -26684,27 +29618,31 @@ else MODULE_SYSLOG_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_syslog" >&5 -$as_echo "$py_cv_module_syslog" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_syslog" >&5 +printf "%s\n" "$py_cv_module_syslog" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module termios" >&5 -$as_echo_n "checking for stdlib extension module termios... " >&6; } - if test "$py_cv_module_termios" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module termios" >&5 +printf %s "checking for stdlib extension module termios... " >&6; } + if test "$py_cv_module_termios" != "n/a" +then : - if true; then : - if test "$ac_cv_header_termios_h" = yes; then : + if true +then : + if test "$ac_cv_header_termios_h" = yes +then : py_cv_module_termios=yes -else +else $as_nop py_cv_module_termios=missing fi -else +else $as_nop py_cv_module_termios=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_TERMIOS_STATE=$py_cv_module_termios$as_nl" - if test "x$py_cv_module_termios" = xyes; then : + if test "x$py_cv_module_termios" = xyes +then : @@ -26718,28 +29656,32 @@ else MODULE_TERMIOS_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_termios" >&5 -$as_echo "$py_cv_module_termios" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_termios" >&5 +printf "%s\n" "$py_cv_module_termios" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module pyexpat" >&5 -$as_echo_n "checking for stdlib extension module pyexpat... " >&6; } - if test "$py_cv_module_pyexpat" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module pyexpat" >&5 +printf %s "checking for stdlib extension module pyexpat... " >&6; } + if test "$py_cv_module_pyexpat" != "n/a" +then : - if true; then : - if test "$ac_cv_header_sys_time_h" = "yes"; then : + if true +then : + if test "$ac_cv_header_sys_time_h" = "yes" +then : py_cv_module_pyexpat=yes -else +else $as_nop py_cv_module_pyexpat=missing fi -else +else $as_nop py_cv_module_pyexpat=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_PYEXPAT_STATE=$py_cv_module_pyexpat$as_nl" - if test "x$py_cv_module_pyexpat" = xyes; then : + if test "x$py_cv_module_pyexpat" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_PYEXPAT_CFLAGS=$LIBEXPAT_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE_PYEXPAT_LDFLAGS=$LIBEXPAT_LDFLAGS$as_nl" @@ -26753,27 +29695,31 @@ else MODULE_PYEXPAT_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_pyexpat" >&5 -$as_echo "$py_cv_module_pyexpat" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_pyexpat" >&5 +printf "%s\n" "$py_cv_module_pyexpat" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _elementtree" >&5 -$as_echo_n "checking for stdlib extension module _elementtree... " >&6; } - if test "$py_cv_module__elementtree" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _elementtree" >&5 +printf %s "checking for stdlib extension module _elementtree... " >&6; } + if test "$py_cv_module__elementtree" != "n/a" +then : - if true; then : - if true; then : + if true +then : + if true +then : py_cv_module__elementtree=yes -else +else $as_nop py_cv_module__elementtree=missing fi -else +else $as_nop py_cv_module__elementtree=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__ELEMENTTREE_STATE=$py_cv_module__elementtree$as_nl" - if test "x$py_cv_module__elementtree" = xyes; then : + if test "x$py_cv_module__elementtree" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__ELEMENTTREE_CFLAGS=$LIBEXPAT_CFLAGS$as_nl" @@ -26787,11 +29733,12 @@ else MODULE__ELEMENTTREE_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__elementtree" >&5 -$as_echo "$py_cv_module__elementtree" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__elementtree" >&5 +printf "%s\n" "$py_cv_module__elementtree" >&6; } - if test "$py_cv_module__codecs_cn" != "n/a"; then : + if test "$py_cv_module__codecs_cn" != "n/a" +then : py_cv_module__codecs_cn=yes fi if test "$py_cv_module__codecs_cn" = yes; then @@ -26803,7 +29750,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CODECS_CN_STATE=$py_cv_module__codecs_cn$as_nl" - if test "x$py_cv_module__codecs_cn" = xyes; then : + if test "x$py_cv_module__codecs_cn" = xyes +then : @@ -26811,7 +29759,8 @@ fi fi - if test "$py_cv_module__codecs_hk" != "n/a"; then : + if test "$py_cv_module__codecs_hk" != "n/a" +then : py_cv_module__codecs_hk=yes fi if test "$py_cv_module__codecs_hk" = yes; then @@ -26823,7 +29772,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CODECS_HK_STATE=$py_cv_module__codecs_hk$as_nl" - if test "x$py_cv_module__codecs_hk" = xyes; then : + if test "x$py_cv_module__codecs_hk" = xyes +then : @@ -26831,7 +29781,8 @@ fi fi - if test "$py_cv_module__codecs_iso2022" != "n/a"; then : + if test "$py_cv_module__codecs_iso2022" != "n/a" +then : py_cv_module__codecs_iso2022=yes fi if test "$py_cv_module__codecs_iso2022" = yes; then @@ -26843,7 +29794,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CODECS_ISO2022_STATE=$py_cv_module__codecs_iso2022$as_nl" - if test "x$py_cv_module__codecs_iso2022" = xyes; then : + if test "x$py_cv_module__codecs_iso2022" = xyes +then : @@ -26851,7 +29803,8 @@ fi fi - if test "$py_cv_module__codecs_jp" != "n/a"; then : + if test "$py_cv_module__codecs_jp" != "n/a" +then : py_cv_module__codecs_jp=yes fi if test "$py_cv_module__codecs_jp" = yes; then @@ -26863,7 +29816,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CODECS_JP_STATE=$py_cv_module__codecs_jp$as_nl" - if test "x$py_cv_module__codecs_jp" = xyes; then : + if test "x$py_cv_module__codecs_jp" = xyes +then : @@ -26871,7 +29825,8 @@ fi fi - if test "$py_cv_module__codecs_kr" != "n/a"; then : + if test "$py_cv_module__codecs_kr" != "n/a" +then : py_cv_module__codecs_kr=yes fi if test "$py_cv_module__codecs_kr" = yes; then @@ -26883,7 +29838,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CODECS_KR_STATE=$py_cv_module__codecs_kr$as_nl" - if test "x$py_cv_module__codecs_kr" = xyes; then : + if test "x$py_cv_module__codecs_kr" = xyes +then : @@ -26891,7 +29847,8 @@ fi fi - if test "$py_cv_module__codecs_tw" != "n/a"; then : + if test "$py_cv_module__codecs_tw" != "n/a" +then : py_cv_module__codecs_tw=yes fi if test "$py_cv_module__codecs_tw" = yes; then @@ -26903,7 +29860,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__CODECS_TW_STATE=$py_cv_module__codecs_tw$as_nl" - if test "x$py_cv_module__codecs_tw" = xyes; then : + if test "x$py_cv_module__codecs_tw" = xyes +then : @@ -26911,7 +29869,8 @@ fi fi - if test "$py_cv_module__multibytecodec" != "n/a"; then : + if test "$py_cv_module__multibytecodec" != "n/a" +then : py_cv_module__multibytecodec=yes fi if test "$py_cv_module__multibytecodec" = yes; then @@ -26923,7 +29882,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE__MULTIBYTECODEC_STATE=$py_cv_module__multibytecodec$as_nl" - if test "x$py_cv_module__multibytecodec" = xyes; then : + if test "x$py_cv_module__multibytecodec" = xyes +then : @@ -26931,7 +29891,8 @@ fi fi - if test "$py_cv_module_unicodedata" != "n/a"; then : + if test "$py_cv_module_unicodedata" != "n/a" +then : py_cv_module_unicodedata=yes fi if test "$py_cv_module_unicodedata" = yes; then @@ -26943,7 +29904,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_UNICODEDATA_STATE=$py_cv_module_unicodedata$as_nl" - if test "x$py_cv_module_unicodedata" = xyes; then : + if test "x$py_cv_module_unicodedata" = xyes +then : @@ -26952,23 +29914,27 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _md5" >&5 -$as_echo_n "checking for stdlib extension module _md5... " >&6; } - if test "$py_cv_module__md5" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _md5" >&5 +printf %s "checking for stdlib extension module _md5... " >&6; } + if test "$py_cv_module__md5" != "n/a" +then : - if test "$with_builtin_md5" = yes; then : - if true; then : + if test "$with_builtin_md5" = yes +then : + if true +then : py_cv_module__md5=yes -else +else $as_nop py_cv_module__md5=missing fi -else +else $as_nop py_cv_module__md5=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__MD5_STATE=$py_cv_module__md5$as_nl" - if test "x$py_cv_module__md5" = xyes; then : + if test "x$py_cv_module__md5" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__MD5_CFLAGS=-I\$(srcdir)/Modules/_hacl/include -I\$(srcdir)/Modules/_hacl/internal -D_BSD_SOURCE -D_DEFAULT_SOURCE$as_nl" @@ -26982,27 +29948,31 @@ else MODULE__MD5_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__md5" >&5 -$as_echo "$py_cv_module__md5" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__md5" >&5 +printf "%s\n" "$py_cv_module__md5" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sha1" >&5 -$as_echo_n "checking for stdlib extension module _sha1... " >&6; } - if test "$py_cv_module__sha1" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sha1" >&5 +printf %s "checking for stdlib extension module _sha1... " >&6; } + if test "$py_cv_module__sha1" != "n/a" +then : - if test "$with_builtin_sha1" = yes; then : - if true; then : + if test "$with_builtin_sha1" = yes +then : + if true +then : py_cv_module__sha1=yes -else +else $as_nop py_cv_module__sha1=missing fi -else +else $as_nop py_cv_module__sha1=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__SHA1_STATE=$py_cv_module__sha1$as_nl" - if test "x$py_cv_module__sha1" = xyes; then : + if test "x$py_cv_module__sha1" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__SHA1_CFLAGS=-I\$(srcdir)/Modules/_hacl/include -I\$(srcdir)/Modules/_hacl/internal -D_BSD_SOURCE -D_DEFAULT_SOURCE$as_nl" @@ -27016,27 +29986,31 @@ else MODULE__SHA1_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sha1" >&5 -$as_echo "$py_cv_module__sha1" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sha1" >&5 +printf "%s\n" "$py_cv_module__sha1" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sha2" >&5 -$as_echo_n "checking for stdlib extension module _sha2... " >&6; } - if test "$py_cv_module__sha2" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sha2" >&5 +printf %s "checking for stdlib extension module _sha2... " >&6; } + if test "$py_cv_module__sha2" != "n/a" +then : - if test "$with_builtin_sha2" = yes; then : - if true; then : + if test "$with_builtin_sha2" = yes +then : + if true +then : py_cv_module__sha2=yes -else +else $as_nop py_cv_module__sha2=missing fi -else +else $as_nop py_cv_module__sha2=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__SHA2_STATE=$py_cv_module__sha2$as_nl" - if test "x$py_cv_module__sha2" = xyes; then : + if test "x$py_cv_module__sha2" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__SHA2_CFLAGS=-I\$(srcdir)/Modules/_hacl/include -I\$(srcdir)/Modules/_hacl/internal -D_BSD_SOURCE -D_DEFAULT_SOURCE$as_nl" @@ -27050,27 +30024,31 @@ else MODULE__SHA2_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sha2" >&5 -$as_echo "$py_cv_module__sha2" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sha2" >&5 +printf "%s\n" "$py_cv_module__sha2" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sha3" >&5 -$as_echo_n "checking for stdlib extension module _sha3... " >&6; } - if test "$py_cv_module__sha3" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sha3" >&5 +printf %s "checking for stdlib extension module _sha3... " >&6; } + if test "$py_cv_module__sha3" != "n/a" +then : - if test "$with_builtin_sha3" = yes; then : - if true; then : + if test "$with_builtin_sha3" = yes +then : + if true +then : py_cv_module__sha3=yes -else +else $as_nop py_cv_module__sha3=missing fi -else +else $as_nop py_cv_module__sha3=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__SHA3_STATE=$py_cv_module__sha3$as_nl" - if test "x$py_cv_module__sha3" = xyes; then : + if test "x$py_cv_module__sha3" = xyes +then : @@ -27084,27 +30062,31 @@ else MODULE__SHA3_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sha3" >&5 -$as_echo "$py_cv_module__sha3" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sha3" >&5 +printf "%s\n" "$py_cv_module__sha3" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _blake2" >&5 -$as_echo_n "checking for stdlib extension module _blake2... " >&6; } - if test "$py_cv_module__blake2" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _blake2" >&5 +printf %s "checking for stdlib extension module _blake2... " >&6; } + if test "$py_cv_module__blake2" != "n/a" +then : - if test "$with_builtin_blake2" = yes; then : - if true; then : + if test "$with_builtin_blake2" = yes +then : + if true +then : py_cv_module__blake2=yes -else +else $as_nop py_cv_module__blake2=missing fi -else +else $as_nop py_cv_module__blake2=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__BLAKE2_STATE=$py_cv_module__blake2$as_nl" - if test "x$py_cv_module__blake2" = xyes; then : + if test "x$py_cv_module__blake2" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__BLAKE2_CFLAGS=$LIBB2_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__BLAKE2_LDFLAGS=$LIBB2_LIBS$as_nl" @@ -27118,28 +30100,32 @@ else MODULE__BLAKE2_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__blake2" >&5 -$as_echo "$py_cv_module__blake2" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__blake2" >&5 +printf "%s\n" "$py_cv_module__blake2" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _crypt" >&5 -$as_echo_n "checking for stdlib extension module _crypt... " >&6; } - if test "$py_cv_module__crypt" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _crypt" >&5 +printf %s "checking for stdlib extension module _crypt... " >&6; } + if test "$py_cv_module__crypt" != "n/a" +then : - if true; then : - if test "$ac_cv_crypt_crypt" = yes; then : + if true +then : + if test "$ac_cv_crypt_crypt" = yes +then : py_cv_module__crypt=yes -else +else $as_nop py_cv_module__crypt=missing fi -else +else $as_nop py_cv_module__crypt=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__CRYPT_STATE=$py_cv_module__crypt$as_nl" - if test "x$py_cv_module__crypt" = xyes; then : + if test "x$py_cv_module__crypt" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__CRYPT_CFLAGS=$LIBCRYPT_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__CRYPT_LDFLAGS=$LIBCRYPT_LIBS$as_nl" @@ -27153,27 +30139,31 @@ else MODULE__CRYPT_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__crypt" >&5 -$as_echo "$py_cv_module__crypt" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__crypt" >&5 +printf "%s\n" "$py_cv_module__crypt" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _ctypes" >&5 -$as_echo_n "checking for stdlib extension module _ctypes... " >&6; } - if test "$py_cv_module__ctypes" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _ctypes" >&5 +printf %s "checking for stdlib extension module _ctypes... " >&6; } + if test "$py_cv_module__ctypes" != "n/a" +then : - if true; then : - if test "$have_libffi" = yes; then : + if true +then : + if test "$have_libffi" = yes +then : py_cv_module__ctypes=yes -else +else $as_nop py_cv_module__ctypes=missing fi -else +else $as_nop py_cv_module__ctypes=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__CTYPES_STATE=$py_cv_module__ctypes$as_nl" - if test "x$py_cv_module__ctypes" = xyes; then : + if test "x$py_cv_module__ctypes" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__CTYPES_CFLAGS=$NO_STRICT_OVERFLOW_CFLAGS $LIBFFI_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__CTYPES_LDFLAGS=$LIBFFI_LIBS$as_nl" @@ -27187,27 +30177,31 @@ else MODULE__CTYPES_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__ctypes" >&5 -$as_echo "$py_cv_module__ctypes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__ctypes" >&5 +printf "%s\n" "$py_cv_module__ctypes" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _curses" >&5 -$as_echo_n "checking for stdlib extension module _curses... " >&6; } - if test "$py_cv_module__curses" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _curses" >&5 +printf %s "checking for stdlib extension module _curses... " >&6; } + if test "$py_cv_module__curses" != "n/a" +then : - if true; then : - if test "$have_curses" != "no"; then : + if true +then : + if test "$have_curses" != "no" +then : py_cv_module__curses=yes -else +else $as_nop py_cv_module__curses=missing fi -else +else $as_nop py_cv_module__curses=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__CURSES_STATE=$py_cv_module__curses$as_nl" - if test "x$py_cv_module__curses" = xyes; then : + if test "x$py_cv_module__curses" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__CURSES_CFLAGS=$CURSES_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__CURSES_LDFLAGS=$CURSES_LIBS @@ -27222,27 +30216,31 @@ else MODULE__CURSES_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__curses" >&5 -$as_echo "$py_cv_module__curses" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__curses" >&5 +printf "%s\n" "$py_cv_module__curses" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _curses_panel" >&5 -$as_echo_n "checking for stdlib extension module _curses_panel... " >&6; } - if test "$py_cv_module__curses_panel" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _curses_panel" >&5 +printf %s "checking for stdlib extension module _curses_panel... " >&6; } + if test "$py_cv_module__curses_panel" != "n/a" +then : - if true; then : - if test "$have_panel" != "no"; then : + if true +then : + if test "$have_panel" != "no" +then : py_cv_module__curses_panel=yes -else +else $as_nop py_cv_module__curses_panel=missing fi -else +else $as_nop py_cv_module__curses_panel=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__CURSES_PANEL_STATE=$py_cv_module__curses_panel$as_nl" - if test "x$py_cv_module__curses_panel" = xyes; then : + if test "x$py_cv_module__curses_panel" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__CURSES_PANEL_CFLAGS=$PANEL_CFLAGS $CURSES_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__CURSES_PANEL_LDFLAGS=$PANEL_LIBS $CURSES_LIBS @@ -27257,27 +30255,31 @@ else MODULE__CURSES_PANEL_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__curses_panel" >&5 -$as_echo "$py_cv_module__curses_panel" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__curses_panel" >&5 +printf "%s\n" "$py_cv_module__curses_panel" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _decimal" >&5 -$as_echo_n "checking for stdlib extension module _decimal... " >&6; } - if test "$py_cv_module__decimal" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _decimal" >&5 +printf %s "checking for stdlib extension module _decimal... " >&6; } + if test "$py_cv_module__decimal" != "n/a" +then : - if true; then : - if true; then : + if true +then : + if true +then : py_cv_module__decimal=yes -else +else $as_nop py_cv_module__decimal=missing fi -else +else $as_nop py_cv_module__decimal=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__DECIMAL_STATE=$py_cv_module__decimal$as_nl" - if test "x$py_cv_module__decimal" = xyes; then : + if test "x$py_cv_module__decimal" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__DECIMAL_CFLAGS=$LIBMPDEC_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__DECIMAL_LDFLAGS=$LIBMPDEC_LDFLAGS$as_nl" @@ -27291,27 +30293,31 @@ else MODULE__DECIMAL_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__decimal" >&5 -$as_echo "$py_cv_module__decimal" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__decimal" >&5 +printf "%s\n" "$py_cv_module__decimal" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _dbm" >&5 -$as_echo_n "checking for stdlib extension module _dbm... " >&6; } - if test "$py_cv_module__dbm" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _dbm" >&5 +printf %s "checking for stdlib extension module _dbm... " >&6; } + if test "$py_cv_module__dbm" != "n/a" +then : - if test -n "$with_dbmliborder"; then : - if test "$have_dbm" != "no"; then : + if test -n "$with_dbmliborder" +then : + if test "$have_dbm" != "no" +then : py_cv_module__dbm=yes -else +else $as_nop py_cv_module__dbm=missing fi -else +else $as_nop py_cv_module__dbm=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__DBM_STATE=$py_cv_module__dbm$as_nl" - if test "x$py_cv_module__dbm" = xyes; then : + if test "x$py_cv_module__dbm" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__DBM_CFLAGS=$DBM_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__DBM_LDFLAGS=$DBM_LIBS$as_nl" @@ -27325,27 +30331,31 @@ else MODULE__DBM_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__dbm" >&5 -$as_echo "$py_cv_module__dbm" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__dbm" >&5 +printf "%s\n" "$py_cv_module__dbm" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _gdbm" >&5 -$as_echo_n "checking for stdlib extension module _gdbm... " >&6; } - if test "$py_cv_module__gdbm" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _gdbm" >&5 +printf %s "checking for stdlib extension module _gdbm... " >&6; } + if test "$py_cv_module__gdbm" != "n/a" +then : - if test "$have_gdbm_dbmliborder" = yes; then : - if test "$have_gdbm" = yes; then : + if test "$have_gdbm_dbmliborder" = yes +then : + if test "$have_gdbm" = yes +then : py_cv_module__gdbm=yes -else +else $as_nop py_cv_module__gdbm=missing fi -else +else $as_nop py_cv_module__gdbm=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__GDBM_STATE=$py_cv_module__gdbm$as_nl" - if test "x$py_cv_module__gdbm" = xyes; then : + if test "x$py_cv_module__gdbm" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__GDBM_CFLAGS=$GDBM_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__GDBM_LDFLAGS=$GDBM_LIBS$as_nl" @@ -27359,27 +30369,31 @@ else MODULE__GDBM_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__gdbm" >&5 -$as_echo "$py_cv_module__gdbm" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__gdbm" >&5 +printf "%s\n" "$py_cv_module__gdbm" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module nis" >&5 -$as_echo_n "checking for stdlib extension module nis... " >&6; } - if test "$py_cv_module_nis" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module nis" >&5 +printf %s "checking for stdlib extension module nis... " >&6; } + if test "$py_cv_module_nis" != "n/a" +then : - if true; then : - if test "$have_nis" = yes -a "$ac_cv_header_rpc_rpc_h" = yes; then : + if true +then : + if test "$have_nis" = yes -a "$ac_cv_header_rpc_rpc_h" = yes +then : py_cv_module_nis=yes -else +else $as_nop py_cv_module_nis=missing fi -else +else $as_nop py_cv_module_nis=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_NIS_STATE=$py_cv_module_nis$as_nl" - if test "x$py_cv_module_nis" = xyes; then : + if test "x$py_cv_module_nis" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_NIS_CFLAGS=$LIBNSL_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE_NIS_LDFLAGS=$LIBNSL_LIBS$as_nl" @@ -27393,27 +30407,31 @@ else MODULE_NIS_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_nis" >&5 -$as_echo "$py_cv_module_nis" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_nis" >&5 +printf "%s\n" "$py_cv_module_nis" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module readline" >&5 -$as_echo_n "checking for stdlib extension module readline... " >&6; } - if test "$py_cv_module_readline" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module readline" >&5 +printf %s "checking for stdlib extension module readline... " >&6; } + if test "$py_cv_module_readline" != "n/a" +then : - if true; then : - if test "$with_readline" != "no"; then : + if true +then : + if test "$with_readline" != "no" +then : py_cv_module_readline=yes -else +else $as_nop py_cv_module_readline=missing fi -else +else $as_nop py_cv_module_readline=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_READLINE_STATE=$py_cv_module_readline$as_nl" - if test "x$py_cv_module_readline" = xyes; then : + if test "x$py_cv_module_readline" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_READLINE_CFLAGS=$READLINE_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE_READLINE_LDFLAGS=$READLINE_LIBS$as_nl" @@ -27427,27 +30445,31 @@ else MODULE_READLINE_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_readline" >&5 -$as_echo "$py_cv_module_readline" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_readline" >&5 +printf "%s\n" "$py_cv_module_readline" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sqlite3" >&5 -$as_echo_n "checking for stdlib extension module _sqlite3... " >&6; } - if test "$py_cv_module__sqlite3" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _sqlite3" >&5 +printf %s "checking for stdlib extension module _sqlite3... " >&6; } + if test "$py_cv_module__sqlite3" != "n/a" +then : - if test "$have_sqlite3" = "yes"; then : - if test "$have_supported_sqlite3" = "yes"; then : + if test "$have_sqlite3" = "yes" +then : + if test "$have_supported_sqlite3" = "yes" +then : py_cv_module__sqlite3=yes -else +else $as_nop py_cv_module__sqlite3=missing fi -else +else $as_nop py_cv_module__sqlite3=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__SQLITE3_STATE=$py_cv_module__sqlite3$as_nl" - if test "x$py_cv_module__sqlite3" = xyes; then : + if test "x$py_cv_module__sqlite3" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__SQLITE3_CFLAGS=$LIBSQLITE3_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__SQLITE3_LDFLAGS=$LIBSQLITE3_LIBS$as_nl" @@ -27461,27 +30483,31 @@ else MODULE__SQLITE3_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sqlite3" >&5 -$as_echo "$py_cv_module__sqlite3" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__sqlite3" >&5 +printf "%s\n" "$py_cv_module__sqlite3" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _tkinter" >&5 -$as_echo_n "checking for stdlib extension module _tkinter... " >&6; } - if test "$py_cv_module__tkinter" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _tkinter" >&5 +printf %s "checking for stdlib extension module _tkinter... " >&6; } + if test "$py_cv_module__tkinter" != "n/a" +then : - if true; then : - if test "$have_tcltk" = "yes"; then : + if true +then : + if test "$have_tcltk" = "yes" +then : py_cv_module__tkinter=yes -else +else $as_nop py_cv_module__tkinter=missing fi -else +else $as_nop py_cv_module__tkinter=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__TKINTER_STATE=$py_cv_module__tkinter$as_nl" - if test "x$py_cv_module__tkinter" = xyes; then : + if test "x$py_cv_module__tkinter" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__TKINTER_CFLAGS=$TCLTK_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__TKINTER_LDFLAGS=$TCLTK_LIBS$as_nl" @@ -27495,27 +30521,31 @@ else MODULE__TKINTER_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__tkinter" >&5 -$as_echo "$py_cv_module__tkinter" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__tkinter" >&5 +printf "%s\n" "$py_cv_module__tkinter" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _uuid" >&5 -$as_echo_n "checking for stdlib extension module _uuid... " >&6; } - if test "$py_cv_module__uuid" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _uuid" >&5 +printf %s "checking for stdlib extension module _uuid... " >&6; } + if test "$py_cv_module__uuid" != "n/a" +then : - if true; then : - if test "$have_uuid" = "yes"; then : + if true +then : + if test "$have_uuid" = "yes" +then : py_cv_module__uuid=yes -else +else $as_nop py_cv_module__uuid=missing fi -else +else $as_nop py_cv_module__uuid=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__UUID_STATE=$py_cv_module__uuid$as_nl" - if test "x$py_cv_module__uuid" = xyes; then : + if test "x$py_cv_module__uuid" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__UUID_CFLAGS=$LIBUUID_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__UUID_LDFLAGS=$LIBUUID_LIBS$as_nl" @@ -27529,28 +30559,32 @@ else MODULE__UUID_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__uuid" >&5 -$as_echo "$py_cv_module__uuid" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__uuid" >&5 +printf "%s\n" "$py_cv_module__uuid" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module zlib" >&5 -$as_echo_n "checking for stdlib extension module zlib... " >&6; } - if test "$py_cv_module_zlib" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module zlib" >&5 +printf %s "checking for stdlib extension module zlib... " >&6; } + if test "$py_cv_module_zlib" != "n/a" +then : - if true; then : - if test "$have_zlib" = yes; then : + if true +then : + if test "$have_zlib" = yes +then : py_cv_module_zlib=yes -else +else $as_nop py_cv_module_zlib=missing fi -else +else $as_nop py_cv_module_zlib=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_ZLIB_STATE=$py_cv_module_zlib$as_nl" - if test "x$py_cv_module_zlib" = xyes; then : + if test "x$py_cv_module_zlib" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_ZLIB_CFLAGS=$ZLIB_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE_ZLIB_LDFLAGS=$ZLIB_LIBS$as_nl" @@ -27564,11 +30598,12 @@ else MODULE_ZLIB_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_zlib" >&5 -$as_echo "$py_cv_module_zlib" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_zlib" >&5 +printf "%s\n" "$py_cv_module_zlib" >&6; } - if test "$py_cv_module_binascii" != "n/a"; then : + if test "$py_cv_module_binascii" != "n/a" +then : py_cv_module_binascii=yes fi if test "$py_cv_module_binascii" = yes; then @@ -27580,7 +30615,8 @@ else fi as_fn_append MODULE_BLOCK "MODULE_BINASCII_STATE=$py_cv_module_binascii$as_nl" - if test "x$py_cv_module_binascii" = xyes; then : + if test "x$py_cv_module_binascii" = xyes +then : as_fn_append MODULE_BLOCK "MODULE_BINASCII_CFLAGS=$BINASCII_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE_BINASCII_LDFLAGS=$BINASCII_LIBS$as_nl" @@ -27588,23 +30624,27 @@ fi fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _bz2" >&5 -$as_echo_n "checking for stdlib extension module _bz2... " >&6; } - if test "$py_cv_module__bz2" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _bz2" >&5 +printf %s "checking for stdlib extension module _bz2... " >&6; } + if test "$py_cv_module__bz2" != "n/a" +then : - if true; then : - if test "$have_bzip2" = yes; then : + if true +then : + if test "$have_bzip2" = yes +then : py_cv_module__bz2=yes -else +else $as_nop py_cv_module__bz2=missing fi -else +else $as_nop py_cv_module__bz2=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__BZ2_STATE=$py_cv_module__bz2$as_nl" - if test "x$py_cv_module__bz2" = xyes; then : + if test "x$py_cv_module__bz2" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__BZ2_CFLAGS=$BZIP2_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__BZ2_LDFLAGS=$BZIP2_LIBS$as_nl" @@ -27618,27 +30658,31 @@ else MODULE__BZ2_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__bz2" >&5 -$as_echo "$py_cv_module__bz2" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__bz2" >&5 +printf "%s\n" "$py_cv_module__bz2" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _lzma" >&5 -$as_echo_n "checking for stdlib extension module _lzma... " >&6; } - if test "$py_cv_module__lzma" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _lzma" >&5 +printf %s "checking for stdlib extension module _lzma... " >&6; } + if test "$py_cv_module__lzma" != "n/a" +then : - if true; then : - if test "$have_liblzma" = yes; then : + if true +then : + if test "$have_liblzma" = yes +then : py_cv_module__lzma=yes -else +else $as_nop py_cv_module__lzma=missing fi -else +else $as_nop py_cv_module__lzma=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__LZMA_STATE=$py_cv_module__lzma$as_nl" - if test "x$py_cv_module__lzma" = xyes; then : + if test "x$py_cv_module__lzma" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__LZMA_CFLAGS=$LIBLZMA_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__LZMA_LDFLAGS=$LIBLZMA_LIBS$as_nl" @@ -27652,28 +30696,32 @@ else MODULE__LZMA_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__lzma" >&5 -$as_echo "$py_cv_module__lzma" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__lzma" >&5 +printf "%s\n" "$py_cv_module__lzma" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _ssl" >&5 -$as_echo_n "checking for stdlib extension module _ssl... " >&6; } - if test "$py_cv_module__ssl" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _ssl" >&5 +printf %s "checking for stdlib extension module _ssl... " >&6; } + if test "$py_cv_module__ssl" != "n/a" +then : - if true; then : - if test "$ac_cv_working_openssl_ssl" = yes; then : + if true +then : + if test "$ac_cv_working_openssl_ssl" = yes +then : py_cv_module__ssl=yes -else +else $as_nop py_cv_module__ssl=missing fi -else +else $as_nop py_cv_module__ssl=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__SSL_STATE=$py_cv_module__ssl$as_nl" - if test "x$py_cv_module__ssl" = xyes; then : + if test "x$py_cv_module__ssl" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__SSL_CFLAGS=$OPENSSL_INCLUDES$as_nl" as_fn_append MODULE_BLOCK "MODULE__SSL_LDFLAGS=$OPENSSL_LDFLAGS $OPENSSL_LDFLAGS_RPATH $OPENSSL_LIBS$as_nl" @@ -27687,27 +30735,31 @@ else MODULE__SSL_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__ssl" >&5 -$as_echo "$py_cv_module__ssl" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__ssl" >&5 +printf "%s\n" "$py_cv_module__ssl" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _hashlib" >&5 -$as_echo_n "checking for stdlib extension module _hashlib... " >&6; } - if test "$py_cv_module__hashlib" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _hashlib" >&5 +printf %s "checking for stdlib extension module _hashlib... " >&6; } + if test "$py_cv_module__hashlib" != "n/a" +then : - if true; then : - if test "$ac_cv_working_openssl_hashlib" = yes; then : + if true +then : + if test "$ac_cv_working_openssl_hashlib" = yes +then : py_cv_module__hashlib=yes -else +else $as_nop py_cv_module__hashlib=missing fi -else +else $as_nop py_cv_module__hashlib=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__HASHLIB_STATE=$py_cv_module__hashlib$as_nl" - if test "x$py_cv_module__hashlib" = xyes; then : + if test "x$py_cv_module__hashlib" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__HASHLIB_CFLAGS=$OPENSSL_INCLUDES$as_nl" as_fn_append MODULE_BLOCK "MODULE__HASHLIB_LDFLAGS=$OPENSSL_LDFLAGS $OPENSSL_LDFLAGS_RPATH $LIBCRYPTO_LIBS$as_nl" @@ -27721,28 +30773,32 @@ else MODULE__HASHLIB_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__hashlib" >&5 -$as_echo "$py_cv_module__hashlib" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__hashlib" >&5 +printf "%s\n" "$py_cv_module__hashlib" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testcapi" >&5 -$as_echo_n "checking for stdlib extension module _testcapi... " >&6; } - if test "$py_cv_module__testcapi" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testcapi" >&5 +printf %s "checking for stdlib extension module _testcapi... " >&6; } + if test "$py_cv_module__testcapi" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if true; then : + if test "$TEST_MODULES" = yes +then : + if true +then : py_cv_module__testcapi=yes -else +else $as_nop py_cv_module__testcapi=missing fi -else +else $as_nop py_cv_module__testcapi=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__TESTCAPI_STATE=$py_cv_module__testcapi$as_nl" - if test "x$py_cv_module__testcapi" = xyes; then : + if test "x$py_cv_module__testcapi" = xyes +then : @@ -27756,27 +30812,31 @@ else MODULE__TESTCAPI_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testcapi" >&5 -$as_echo "$py_cv_module__testcapi" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testcapi" >&5 +printf "%s\n" "$py_cv_module__testcapi" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testclinic" >&5 -$as_echo_n "checking for stdlib extension module _testclinic... " >&6; } - if test "$py_cv_module__testclinic" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testclinic" >&5 +printf %s "checking for stdlib extension module _testclinic... " >&6; } + if test "$py_cv_module__testclinic" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if true; then : + if test "$TEST_MODULES" = yes +then : + if true +then : py_cv_module__testclinic=yes -else +else $as_nop py_cv_module__testclinic=missing fi -else +else $as_nop py_cv_module__testclinic=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__TESTCLINIC_STATE=$py_cv_module__testclinic$as_nl" - if test "x$py_cv_module__testclinic" = xyes; then : + if test "x$py_cv_module__testclinic" = xyes +then : @@ -27790,27 +30850,31 @@ else MODULE__TESTCLINIC_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testclinic" >&5 -$as_echo "$py_cv_module__testclinic" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testclinic" >&5 +printf "%s\n" "$py_cv_module__testclinic" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testinternalcapi" >&5 -$as_echo_n "checking for stdlib extension module _testinternalcapi... " >&6; } - if test "$py_cv_module__testinternalcapi" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testinternalcapi" >&5 +printf %s "checking for stdlib extension module _testinternalcapi... " >&6; } + if test "$py_cv_module__testinternalcapi" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if true; then : + if test "$TEST_MODULES" = yes +then : + if true +then : py_cv_module__testinternalcapi=yes -else +else $as_nop py_cv_module__testinternalcapi=missing fi -else +else $as_nop py_cv_module__testinternalcapi=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__TESTINTERNALCAPI_STATE=$py_cv_module__testinternalcapi$as_nl" - if test "x$py_cv_module__testinternalcapi" = xyes; then : + if test "x$py_cv_module__testinternalcapi" = xyes +then : @@ -27824,27 +30888,31 @@ else MODULE__TESTINTERNALCAPI_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testinternalcapi" >&5 -$as_echo "$py_cv_module__testinternalcapi" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testinternalcapi" >&5 +printf "%s\n" "$py_cv_module__testinternalcapi" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testbuffer" >&5 -$as_echo_n "checking for stdlib extension module _testbuffer... " >&6; } - if test "$py_cv_module__testbuffer" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testbuffer" >&5 +printf %s "checking for stdlib extension module _testbuffer... " >&6; } + if test "$py_cv_module__testbuffer" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if true; then : + if test "$TEST_MODULES" = yes +then : + if true +then : py_cv_module__testbuffer=yes -else +else $as_nop py_cv_module__testbuffer=missing fi -else +else $as_nop py_cv_module__testbuffer=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__TESTBUFFER_STATE=$py_cv_module__testbuffer$as_nl" - if test "x$py_cv_module__testbuffer" = xyes; then : + if test "x$py_cv_module__testbuffer" = xyes +then : @@ -27858,27 +30926,31 @@ else MODULE__TESTBUFFER_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testbuffer" >&5 -$as_echo "$py_cv_module__testbuffer" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testbuffer" >&5 +printf "%s\n" "$py_cv_module__testbuffer" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testimportmultiple" >&5 -$as_echo_n "checking for stdlib extension module _testimportmultiple... " >&6; } - if test "$py_cv_module__testimportmultiple" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testimportmultiple" >&5 +printf %s "checking for stdlib extension module _testimportmultiple... " >&6; } + if test "$py_cv_module__testimportmultiple" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if test "$ac_cv_func_dlopen" = yes; then : + if test "$TEST_MODULES" = yes +then : + if test "$ac_cv_func_dlopen" = yes +then : py_cv_module__testimportmultiple=yes -else +else $as_nop py_cv_module__testimportmultiple=missing fi -else +else $as_nop py_cv_module__testimportmultiple=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__TESTIMPORTMULTIPLE_STATE=$py_cv_module__testimportmultiple$as_nl" - if test "x$py_cv_module__testimportmultiple" = xyes; then : + if test "x$py_cv_module__testimportmultiple" = xyes +then : @@ -27892,27 +30964,31 @@ else MODULE__TESTIMPORTMULTIPLE_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testimportmultiple" >&5 -$as_echo "$py_cv_module__testimportmultiple" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testimportmultiple" >&5 +printf "%s\n" "$py_cv_module__testimportmultiple" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testmultiphase" >&5 -$as_echo_n "checking for stdlib extension module _testmultiphase... " >&6; } - if test "$py_cv_module__testmultiphase" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _testmultiphase" >&5 +printf %s "checking for stdlib extension module _testmultiphase... " >&6; } + if test "$py_cv_module__testmultiphase" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if test "$ac_cv_func_dlopen" = yes; then : + if test "$TEST_MODULES" = yes +then : + if test "$ac_cv_func_dlopen" = yes +then : py_cv_module__testmultiphase=yes -else +else $as_nop py_cv_module__testmultiphase=missing fi -else +else $as_nop py_cv_module__testmultiphase=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__TESTMULTIPHASE_STATE=$py_cv_module__testmultiphase$as_nl" - if test "x$py_cv_module__testmultiphase" = xyes; then : + if test "x$py_cv_module__testmultiphase" = xyes +then : @@ -27926,27 +31002,31 @@ else MODULE__TESTMULTIPHASE_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testmultiphase" >&5 -$as_echo "$py_cv_module__testmultiphase" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__testmultiphase" >&5 +printf "%s\n" "$py_cv_module__testmultiphase" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module xxsubtype" >&5 -$as_echo_n "checking for stdlib extension module xxsubtype... " >&6; } - if test "$py_cv_module_xxsubtype" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module xxsubtype" >&5 +printf %s "checking for stdlib extension module xxsubtype... " >&6; } + if test "$py_cv_module_xxsubtype" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if true; then : + if test "$TEST_MODULES" = yes +then : + if true +then : py_cv_module_xxsubtype=yes -else +else $as_nop py_cv_module_xxsubtype=missing fi -else +else $as_nop py_cv_module_xxsubtype=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_XXSUBTYPE_STATE=$py_cv_module_xxsubtype$as_nl" - if test "x$py_cv_module_xxsubtype" = xyes; then : + if test "x$py_cv_module_xxsubtype" = xyes +then : @@ -27960,27 +31040,31 @@ else MODULE_XXSUBTYPE_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_xxsubtype" >&5 -$as_echo "$py_cv_module_xxsubtype" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_xxsubtype" >&5 +printf "%s\n" "$py_cv_module_xxsubtype" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _xxtestfuzz" >&5 -$as_echo_n "checking for stdlib extension module _xxtestfuzz... " >&6; } - if test "$py_cv_module__xxtestfuzz" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _xxtestfuzz" >&5 +printf %s "checking for stdlib extension module _xxtestfuzz... " >&6; } + if test "$py_cv_module__xxtestfuzz" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if true; then : + if test "$TEST_MODULES" = yes +then : + if true +then : py_cv_module__xxtestfuzz=yes -else +else $as_nop py_cv_module__xxtestfuzz=missing fi -else +else $as_nop py_cv_module__xxtestfuzz=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__XXTESTFUZZ_STATE=$py_cv_module__xxtestfuzz$as_nl" - if test "x$py_cv_module__xxtestfuzz" = xyes; then : + if test "x$py_cv_module__xxtestfuzz" = xyes +then : @@ -27994,27 +31078,31 @@ else MODULE__XXTESTFUZZ_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__xxtestfuzz" >&5 -$as_echo "$py_cv_module__xxtestfuzz" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__xxtestfuzz" >&5 +printf "%s\n" "$py_cv_module__xxtestfuzz" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _ctypes_test" >&5 -$as_echo_n "checking for stdlib extension module _ctypes_test... " >&6; } - if test "$py_cv_module__ctypes_test" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _ctypes_test" >&5 +printf %s "checking for stdlib extension module _ctypes_test... " >&6; } + if test "$py_cv_module__ctypes_test" != "n/a" +then : - if test "$TEST_MODULES" = yes; then : - if test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes; then : + if test "$TEST_MODULES" = yes +then : + if test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes +then : py_cv_module__ctypes_test=yes -else +else $as_nop py_cv_module__ctypes_test=missing fi -else +else $as_nop py_cv_module__ctypes_test=disabled fi fi as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_STATE=$py_cv_module__ctypes_test$as_nl" - if test "x$py_cv_module__ctypes_test" = xyes; then : + if test "x$py_cv_module__ctypes_test" = xyes +then : as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_LDFLAGS=$LIBM$as_nl" @@ -28028,28 +31116,32 @@ else MODULE__CTYPES_TEST_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__ctypes_test" >&5 -$as_echo "$py_cv_module__ctypes_test" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__ctypes_test" >&5 +printf "%s\n" "$py_cv_module__ctypes_test" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module xxlimited" >&5 -$as_echo_n "checking for stdlib extension module xxlimited... " >&6; } - if test "$py_cv_module_xxlimited" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module xxlimited" >&5 +printf %s "checking for stdlib extension module xxlimited... " >&6; } + if test "$py_cv_module_xxlimited" != "n/a" +then : - if test "$with_trace_refs" = "no"; then : - if test "$ac_cv_func_dlopen" = yes; then : + if test "$with_trace_refs" = "no" +then : + if test "$ac_cv_func_dlopen" = yes +then : py_cv_module_xxlimited=yes -else +else $as_nop py_cv_module_xxlimited=missing fi -else +else $as_nop py_cv_module_xxlimited=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_XXLIMITED_STATE=$py_cv_module_xxlimited$as_nl" - if test "x$py_cv_module_xxlimited" = xyes; then : + if test "x$py_cv_module_xxlimited" = xyes +then : @@ -28063,27 +31155,31 @@ else MODULE_XXLIMITED_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_xxlimited" >&5 -$as_echo "$py_cv_module_xxlimited" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_xxlimited" >&5 +printf "%s\n" "$py_cv_module_xxlimited" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module xxlimited_35" >&5 -$as_echo_n "checking for stdlib extension module xxlimited_35... " >&6; } - if test "$py_cv_module_xxlimited_35" != "n/a"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module xxlimited_35" >&5 +printf %s "checking for stdlib extension module xxlimited_35... " >&6; } + if test "$py_cv_module_xxlimited_35" != "n/a" +then : - if test "$with_trace_refs" = "no"; then : - if test "$ac_cv_func_dlopen" = yes; then : + if test "$with_trace_refs" = "no" +then : + if test "$ac_cv_func_dlopen" = yes +then : py_cv_module_xxlimited_35=yes -else +else $as_nop py_cv_module_xxlimited_35=missing fi -else +else $as_nop py_cv_module_xxlimited_35=disabled fi fi as_fn_append MODULE_BLOCK "MODULE_XXLIMITED_35_STATE=$py_cv_module_xxlimited_35$as_nl" - if test "x$py_cv_module_xxlimited_35" = xyes; then : + if test "x$py_cv_module_xxlimited_35" = xyes +then : @@ -28097,8 +31193,8 @@ else MODULE_XXLIMITED_35_FALSE= fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_xxlimited_35" >&5 -$as_echo "$py_cv_module_xxlimited_35" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $py_cv_module_xxlimited_35" >&5 +printf "%s\n" "$py_cv_module_xxlimited_35" >&6; } # substitute multiline block, must come after last PY_STDLIB_MOD() @@ -28138,8 +31234,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -28169,15 +31265,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -28191,8 +31287,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -28209,7 +31305,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -28558,8 +31654,8 @@ fi ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -28582,14 +31678,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -28599,46 +31697,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -28647,13 +31745,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -28662,8 +31753,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -28675,30 +31770,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -28711,13 +31786,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -28744,18 +31820,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -28767,12 +31845,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -28803,7 +31882,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -28825,6 +31904,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -28838,6 +31921,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -28879,7 +31968,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -28888,7 +31977,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -28951,7 +32040,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by python $as_me 3.12, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -29009,14 +32098,16 @@ $config_headers Report bugs to ." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ python config.status 3.12 -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -29055,15 +32146,15 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" @@ -29071,7 +32162,7 @@ do --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; @@ -29080,7 +32171,7 @@ do as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -29108,7 +32199,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -29122,7 +32213,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -29158,8 +32249,8 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree @@ -29495,7 +32586,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -29503,17 +32594,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -29530,7 +32621,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -29554,9 +32645,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -29618,8 +32709,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -29663,9 +32754,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -29681,20 +32772,20 @@ which seems to be undefined. Please make sure it is defined" >&2;} # if test x"$ac_file" != x-; then { - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi @@ -29740,20 +32831,20 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating Modules/Setup.local" >&5 -$as_echo "$as_me: creating Modules/Setup.local" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating Modules/Setup.local" >&5 +printf "%s\n" "$as_me: creating Modules/Setup.local" >&6;} if test ! -f Modules/Setup.local then echo "# Edit this file for local setup changes" >Modules/Setup.local fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating Makefile" >&5 -$as_echo "$as_me: creating Makefile" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating Makefile" >&5 +printf "%s\n" "$as_me: creating Makefile" >&6;} $SHELL $srcdir/Modules/makesetup -c $srcdir/Modules/config.c.in \ -s Modules \ Modules/Setup.local Modules/Setup.stdlib Modules/Setup.bootstrap $srcdir/Modules/Setup @@ -29764,32 +32855,34 @@ fi mv config.c Modules if test -z "$PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pkg-config is missing. Some dependencies may not be detected correctly." >&5 -$as_echo "$as_me: WARNING: pkg-config is missing. Some dependencies may not be detected correctly." >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: pkg-config is missing. Some dependencies may not be detected correctly." >&5 +printf "%s\n" "$as_me: WARNING: pkg-config is missing. Some dependencies may not be detected correctly." >&2;} fi if test "$Py_OPT" = 'false' -a "$Py_DEBUG" != 'true'; then - { $as_echo "$as_me:${as_lineno-$LINENO}: + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: If you want a release build with all stable optimizations active (PGO, etc), please run ./configure --enable-optimizations " >&5 -$as_echo "$as_me: +printf "%s\n" "$as_me: If you want a release build with all stable optimizations active (PGO, etc), please run ./configure --enable-optimizations " >&6;} fi -if test "x$PY_SUPPORT_TIER" = x0; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +if test "x$PY_SUPPORT_TIER" = x0 +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Platform \"$host\" with compiler \"$ac_cv_cc_name\" is not supported by the CPython core team, see https://peps.python.org/pep-0011/ for more information. " >&5 -$as_echo "$as_me: WARNING: +printf "%s\n" "$as_me: WARNING: Platform \"$host\" with compiler \"$ac_cv_cc_name\" is not supported by the CPython core team, see https://peps.python.org/pep-0011/ for more information. " >&2;} fi + diff --git a/configure.ac b/configure.ac index c30fb2a08d104e..e0a69583ca834a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,13 +2,20 @@ dnl *************************************************** dnl * Please run autoreconf -if to test your changes! * dnl *************************************************** dnl -dnl Python's configure.ac file requires autoconf 2.69 and autoconf-archive. +dnl Python's configure script requires autoconf 2.71, autoconf-archive, +dnl pkgconf's m4 macros. +dnl +dnl It is recommended to use a cpython_autoconf container to regenerate the +dnl configure script: +dnl +dnl podman run --rm --pull=always -v $(pwd):/src:Z quay.io/tiran/cpython_autoconf:271 +dnl docker run --rm --pull=always -v $(pwd):/src quay.io/tiran/cpython_autoconf:271 dnl # Set VERSION so we only need to edit in one place (i.e., here) m4_define([PYTHON_VERSION], [3.12]) -AC_PREREQ([2.69]) +AC_PREREQ([2.71]) AC_INIT([python],[PYTHON_VERSION],[https://github.com/python/cpython/issues/]) diff --git a/pyconfig.h.in b/pyconfig.h.in index b33e82c3609c18..7c87cd7d5ddd1f 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -790,12 +790,12 @@ /* Define if you have the 'memfd_create' function. */ #undef HAVE_MEMFD_CREATE -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - /* Define to 1 if you have the `memrchr' function. */ #undef HAVE_MEMRCHR +/* Define to 1 if you have the header file. */ +#undef HAVE_MINIX_CONFIG_H + /* Define to 1 if you have the `mkdirat' function. */ #undef HAVE_MKDIRAT @@ -1193,6 +1193,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H @@ -1701,21 +1704,87 @@ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# undef _DARWIN_C_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif -/* Enable threading extensions on Solaris. */ +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# undef _HPUX_ALT_XOPEN_SOCKET_API +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +# undef _MINIX +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# undef _NETBSD_SOURCE +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# undef _OPENBSD_SOURCE +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +# undef _POSIX_SOURCE +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +# undef _POSIX_1_SOURCE +#endif +/* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# undef __STDC_WANT_IEC_60559_BFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# undef __STDC_WANT_IEC_60559_DFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# undef __STDC_WANT_IEC_60559_TYPES_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# undef __STDC_WANT_LIB_EXT2__ +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# undef __STDC_WANT_MATH_SPEC_FUNCS__ +#endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +# undef _XOPEN_SOURCE #endif @@ -1789,22 +1858,12 @@ /* This must be defined on AIX systems to enable large file support. */ #undef _LARGE_FILES -/* Define to 1 if on MINIX. */ -#undef _MINIX - /* Define on NetBSD to activate all library features */ #undef _NETBSD_SOURCE -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -#undef _POSIX_1_SOURCE - /* Define to activate features from IEEE Stds 1003.1-2008 */ #undef _POSIX_C_SOURCE -/* Define to 1 if you need to in order for `stat' and other things to work. */ -#undef _POSIX_SOURCE - /* Define if you have POSIX threads, and your system does not define that. */ #undef _POSIX_THREADS @@ -1847,7 +1906,7 @@ /* Define to `long int' if does not define. */ #undef off_t -/* Define to `int' if does not define. */ +/* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to empty if the keyword does not work. */ From c38ceb032d59d6c8f2006ab9a347d7e207f9f84e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:24:55 -0700 Subject: [PATCH 0103/1206] [3.12] gh-105020: Share tp_bases and tp_mro Between Interpreters For All Static Builtin Types (gh-105115) (gh-105124) In gh-103912 we added tp_bases and tp_mro to each PyInterpreterState.types.builtins entry. However, doing so ignored the fact that both PyTypeObject fields are public API, and not documented as internal (as opposed to tp_subclasses). We address that here by reverting back to shared objects, making them immortal in the process. (cherry picked from commit 7be667d) Co-authored-by: Eric Snow ericsnowcurrently@gmail.com --- Doc/data/python3.12.abi | 52850 ++++++++-------- Include/internal/pycore_object.h | 15 + Include/internal/pycore_typeobject.h | 6 +- Lib/test/test_capi/test_misc.py | 33 + ...-05-30-17-45-32.gh-issue-105115.iRho1K.rst | 3 + Modules/_testcapimodule.c | 23 + Objects/typeobject.c | 76 +- 7 files changed, 26544 insertions(+), 26462 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 94b09516b511e1..55d8468d57c05a 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1,26428 +1,26422 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 500b3eece68055..0981d1122fec54 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -76,6 +76,21 @@ static inline void _Py_SetImmortal(PyObject *op) } #define _Py_SetImmortal(op) _Py_SetImmortal(_PyObject_CAST(op)) +/* _Py_ClearImmortal() should only be used during runtime finalization. */ +static inline void _Py_ClearImmortal(PyObject *op) +{ + if (op) { + assert(op->ob_refcnt == _Py_IMMORTAL_REFCNT); + op->ob_refcnt = 1; + Py_DECREF(op); + } +} +#define _Py_ClearImmortal(op) \ + do { \ + _Py_ClearImmortal(_PyObject_CAST(op)); \ + op = NULL; \ + } while (0) + static inline void _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index c7d00002fbc63c..8f3fbbcdb5ffcd 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -46,11 +46,9 @@ typedef struct { PyTypeObject *type; int readying; int ready; - // XXX tp_dict, tp_bases, and tp_mro can probably be statically - // allocated, instead of dynamically and stored on the interpreter. + // XXX tp_dict can probably be statically allocated, + // instead of dynamically and stored on the interpreter. PyObject *tp_dict; - PyObject *tp_bases; - PyObject *tp_mro; PyObject *tp_subclasses; /* We never clean up weakrefs for static builtin types since they will effectively never get triggered. However, there diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index dc3441e4496a5d..037c8112d53e7a 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1593,6 +1593,39 @@ def test_module_state_shared_in_global(self): self.assertEqual(main_attr_id, subinterp_attr_id) +class BuiltinStaticTypesTests(unittest.TestCase): + + TYPES = [ + object, + type, + int, + str, + dict, + type(None), + bool, + BaseException, + Exception, + Warning, + DeprecationWarning, # Warning subclass + ] + + def test_tp_bases_is_set(self): + # PyTypeObject.tp_bases is documented as public API. + # See https://github.com/python/cpython/issues/105020. + for typeobj in self.TYPES: + with self.subTest(typeobj): + bases = _testcapi.type_get_tp_bases(typeobj) + self.assertIsNot(bases, None) + + def test_tp_mro_is_set(self): + # PyTypeObject.tp_bases is documented as public API. + # See https://github.com/python/cpython/issues/105020. + for typeobj in self.TYPES: + with self.subTest(typeobj): + mro = _testcapi.type_get_tp_mro(typeobj) + self.assertIsNot(mro, None) + + class TestThreadState(unittest.TestCase): @threading_helper.reap_threads diff --git a/Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst b/Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst new file mode 100644 index 00000000000000..595cc0e2013d96 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst @@ -0,0 +1,3 @@ +``PyTypeObject.tp_bases`` (and ``tp_mro``) for builtin static types are now +shared by all interpreters, whereas in 3.12-beta1 they were stored on +``PyInterpreterState``. Also note that now the tuples are immortal objects. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index aff09aac80c610..66c1cbabe0f8c4 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2606,6 +2606,27 @@ type_assign_version(PyObject *self, PyObject *type) } +static PyObject * +type_get_tp_bases(PyObject *self, PyObject *type) +{ + PyObject *bases = ((PyTypeObject *)type)->tp_bases; + if (bases == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(bases); +} + +static PyObject * +type_get_tp_mro(PyObject *self, PyObject *type) +{ + PyObject *mro = ((PyTypeObject *)type)->tp_mro; + if (mro == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(mro); +} + + // Test PyThreadState C API static PyObject * test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) @@ -3361,6 +3382,8 @@ static PyMethodDef TestMethods[] = { {"test_py_is_funcs", test_py_is_funcs, METH_NOARGS}, {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")}, {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, + {"type_get_tp_bases", type_get_tp_bases, METH_O}, + {"type_get_tp_mro", type_get_tp_mro, METH_O}, {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, {"frame_getlocals", frame_getlocals, METH_O, NULL}, {"frame_getglobals", frame_getglobals, METH_O, NULL}, diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0a2e1b1d3c1f78..6540d4ef7fc482 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -268,12 +268,6 @@ clear_tp_dict(PyTypeObject *self) static inline PyObject * lookup_tp_bases(PyTypeObject *self) { - if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - assert(state != NULL); - return state->tp_bases; - } return self->tp_bases; } @@ -287,12 +281,22 @@ _PyType_GetBases(PyTypeObject *self) static inline void set_tp_bases(PyTypeObject *self, PyObject *bases) { + assert(PyTuple_CheckExact(bases)); if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - assert(state != NULL); - state->tp_bases = bases; - return; + // XXX tp_bases can probably be statically allocated for each + // static builtin type. + assert(_Py_IsMainInterpreter(_PyInterpreterState_GET())); + assert(self->tp_bases == NULL); + if (PyTuple_GET_SIZE(bases) == 0) { + assert(self->tp_base == NULL); + } + else { + assert(PyTuple_GET_SIZE(bases) == 1); + assert(PyTuple_GET_ITEM(bases, 0) == (PyObject *)self->tp_base); + assert(self->tp_base->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); + assert(_Py_IsImmortal(self->tp_base)); + } + _Py_SetImmortal(bases); } self->tp_bases = bases; } @@ -301,10 +305,14 @@ static inline void clear_tp_bases(PyTypeObject *self) { if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - assert(state != NULL); - Py_CLEAR(state->tp_bases); + if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) { + if (self->tp_bases != NULL + && PyTuple_GET_SIZE(self->tp_bases) > 0) + { + assert(_Py_IsImmortal(self->tp_bases)); + _Py_ClearImmortal(self->tp_bases); + } + } return; } Py_CLEAR(self->tp_bases); @@ -314,12 +322,6 @@ clear_tp_bases(PyTypeObject *self) static inline PyObject * lookup_tp_mro(PyTypeObject *self) { - if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - assert(state != NULL); - return state->tp_mro; - } return self->tp_mro; } @@ -333,12 +335,14 @@ _PyType_GetMRO(PyTypeObject *self) static inline void set_tp_mro(PyTypeObject *self, PyObject *mro) { + assert(PyTuple_CheckExact(mro)); if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - assert(state != NULL); - state->tp_mro = mro; - return; + // XXX tp_mro can probably be statically allocated for each + // static builtin type. + assert(_Py_IsMainInterpreter(_PyInterpreterState_GET())); + assert(self->tp_mro == NULL); + /* Other checks are done via set_tp_bases. */ + _Py_SetImmortal(mro); } self->tp_mro = mro; } @@ -347,10 +351,14 @@ static inline void clear_tp_mro(PyTypeObject *self) { if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - assert(state != NULL); - Py_CLEAR(state->tp_mro); + if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) { + if (self->tp_mro != NULL + && PyTuple_GET_SIZE(self->tp_mro) > 0) + { + assert(_Py_IsImmortal(self->tp_mro)); + _Py_ClearImmortal(self->tp_mro); + } + } return; } Py_CLEAR(self->tp_mro); @@ -7153,6 +7161,14 @@ type_ready_preheader(PyTypeObject *type) static int type_ready_mro(PyTypeObject *type) { + if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) { + assert(lookup_tp_mro(type) != NULL); + return 0; + } + assert(lookup_tp_mro(type) == NULL); + } + /* Calculate method resolution order */ if (mro_internal(type, NULL) < 0) { return -1; From d2be5c73ed520fb9d82a395f001eb9001711ed8f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:50:28 -0700 Subject: [PATCH 0104/1206] [3.12] gh-104341: Call _PyEval_ReleaseLock() with NULL When Finalizing the Current Thread (gh-105109) (gh-105209) This avoids the problematic race in drop_gil() by skipping the FORCE_SWITCHING code there for finalizing threads. (The idea for this approach came out of discussions with @markshannon.) (cherry picked from commit 3698fda) Co-authored-by: Eric Snow ericsnowcurrently@gmail.com --- Include/internal/pycore_ceval.h | 2 +- Python/ceval_gil.c | 30 ++++++++++++++++++++++++++---- Python/pylifecycle.c | 2 +- Python/pystate.c | 21 ++++++++++++++++++--- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 3c8b368bd2af4e..ca2703781de4b0 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -100,7 +100,7 @@ extern PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil); extern void _PyEval_FiniGIL(PyInterpreterState *interp); extern void _PyEval_AcquireLock(PyThreadState *tstate); -extern void _PyEval_ReleaseLock(PyThreadState *tstate); +extern void _PyEval_ReleaseLock(PyInterpreterState *, PyThreadState *); extern PyThreadState * _PyThreadState_SwapNoGIL(PyThreadState *); extern void _PyEval_DeactivateOpCache(void); diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index b9bdb74fcedf32..764278ac130dfa 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -278,6 +278,15 @@ static void recreate_gil(struct _gil_runtime_state *gil) static void drop_gil(struct _ceval_state *ceval, PyThreadState *tstate) { + /* If tstate is NULL, the caller is indicating that we're releasing + the GIL for the last time in this thread. This is particularly + relevant when the current thread state is finalizing or its + interpreter is finalizing (either may be in an inconsistent + state). In that case the current thread will definitely + never try to acquire the GIL again. */ + // XXX It may be more correct to check tstate->_status.finalizing. + // XXX assert(tstate == NULL || !tstate->_status.cleared); + struct _gil_runtime_state *gil = ceval->gil; if (!_Py_atomic_load_relaxed(&gil->locked)) { Py_FatalError("drop_gil: GIL is not locked"); @@ -298,7 +307,15 @@ drop_gil(struct _ceval_state *ceval, PyThreadState *tstate) MUTEX_UNLOCK(gil->mutex); #ifdef FORCE_SWITCHING - if (_Py_atomic_load_relaxed(&ceval->gil_drop_request) && tstate != NULL) { + /* We check tstate first in case we might be releasing the GIL for + the last time in this thread. In that case there's a possible + race with tstate->interp getting deleted after gil->mutex is + unlocked and before the following code runs, leading to a crash. + We can use (tstate == NULL) to indicate the thread is done with + the GIL, and that's the only time we might delete the + interpreter, so checking tstate first prevents the crash. + See https://github.com/python/cpython/issues/104341. */ + if (tstate != NULL && _Py_atomic_load_relaxed(&ceval->gil_drop_request)) { MUTEX_LOCK(gil->switch_mutex); /* Not switched yet => wait */ if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate) @@ -350,6 +367,9 @@ take_gil(PyThreadState *tstate) int err = errno; assert(tstate != NULL); + /* We shouldn't be using a thread state that isn't viable any more. */ + // XXX It may be more correct to check tstate->_status.finalizing. + // XXX assert(!tstate->_status.cleared); if (tstate_must_exit(tstate)) { /* bpo-39877: If Py_Finalize() has been called and tstate is not the @@ -625,10 +645,12 @@ _PyEval_AcquireLock(PyThreadState *tstate) } void -_PyEval_ReleaseLock(PyThreadState *tstate) +_PyEval_ReleaseLock(PyInterpreterState *interp, PyThreadState *tstate) { - _Py_EnsureTstateNotNULL(tstate); - struct _ceval_state *ceval = &tstate->interp->ceval; + /* If tstate is NULL then we do not expect the current thread + to acquire the GIL ever again. */ + assert(tstate == NULL || tstate->interp == interp); + struct _ceval_state *ceval = &interp->ceval; drop_gil(ceval, tstate); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 06c43459624c67..8b846443ce8f6a 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2035,7 +2035,7 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) const PyConfig *src_config; if (save_tstate != NULL) { // XXX Might new_interpreter() have been called without the GIL held? - _PyEval_ReleaseLock(save_tstate); + _PyEval_ReleaseLock(save_tstate->interp, save_tstate); src_config = _PyInterpreterState_GetConfig(save_tstate->interp); } else diff --git a/Python/pystate.c b/Python/pystate.c index 25e655a2027918..39fe5473ed46b3 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -822,6 +822,12 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) p = p->next; HEAD_UNLOCK(runtime); } + if (tstate->interp == interp) { + /* We fix tstate->_status below when we for sure aren't using it + (e.g. no longer need the GIL). */ + // XXX Eliminate the need to do this. + tstate->_status.cleared = 0; + } /* It is possible that any of the objects below have a finalizer that runs Python code or otherwise relies on a thread state @@ -886,6 +892,12 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) Py_CLEAR(interp->builtins); Py_CLEAR(interp->interpreter_trampoline); + if (tstate->interp == interp) { + /* We are now safe to fix tstate->_status.cleared. */ + // XXX Do this (much) earlier? + tstate->_status.cleared = 1; + } + for (int i=0; i < DICT_MAX_WATCHERS; i++) { interp->dict_state.watchers[i] = NULL; } @@ -930,6 +942,7 @@ _PyInterpreterState_Clear(PyThreadState *tstate) } +static inline void tstate_deactivate(PyThreadState *tstate); static void zapthreads(PyInterpreterState *interp); void @@ -943,7 +956,9 @@ PyInterpreterState_Delete(PyInterpreterState *interp) PyThreadState *tcur = current_fast_get(runtime); if (tcur != NULL && interp == tcur->interp) { /* Unset current thread. After this, many C API calls become crashy. */ - _PyThreadState_Swap(runtime, NULL); + current_fast_clear(runtime); + tstate_deactivate(tcur); + _PyEval_ReleaseLock(interp, NULL); } zapthreads(interp); @@ -1567,7 +1582,7 @@ _PyThreadState_DeleteCurrent(PyThreadState *tstate) _Py_EnsureTstateNotNULL(tstate); tstate_delete_common(tstate); current_fast_clear(tstate->interp->runtime); - _PyEval_ReleaseLock(tstate); + _PyEval_ReleaseLock(tstate->interp, NULL); free_threadstate(tstate); } @@ -1907,7 +1922,7 @@ _PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts) { PyThreadState *oldts = current_fast_get(runtime); if (oldts != NULL) { - _PyEval_ReleaseLock(oldts); + _PyEval_ReleaseLock(oldts->interp, oldts); } _swap_thread_states(runtime, oldts, newts); if (newts != NULL) { From d57ee813ebd496a3fd8118d7dc057d54c4af847e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 1 Jun 2023 16:06:38 -0700 Subject: [PATCH 0105/1206] [3.12] gh-104614: Make Sure ob_type is Always Set Correctly by PyType_Ready() (gh-105122) (gh-105211) When I added the relevant condition to type_ready_set_bases() in gh-103912, I had missed that the function also sets tp_base and ob_type (if necessary). That led to problems for third-party static types. We fix that here, by making those extra operations distinct and by adjusting the condition to be more specific. (cherry picked from commit 1469393) Co-authored-by: Eric Snow ericsnowcurrently@gmail.com --- Lib/test/test_capi/test_misc.py | 38 +++++++++++++++++- Modules/_testcapimodule.c | 45 +++++++++++++++++++++ Objects/typeobject.c | 60 ++++++++++++++++++++-------- Tools/c-analyzer/cpython/ignored.tsv | 2 + 4 files changed, 128 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 037c8112d53e7a..e1b55cffe8ff52 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1,8 +1,9 @@ # Run the _testcapi module tests (tests for the Python/C API): by defn, # these are all functions _testcapi exports whose name begins with 'test_'. -from collections import OrderedDict import _thread +from collections import OrderedDict +import contextlib import importlib.machinery import importlib.util import os @@ -1626,6 +1627,41 @@ def test_tp_mro_is_set(self): self.assertIsNot(mro, None) +class TestStaticTypes(unittest.TestCase): + + _has_run = False + + @classmethod + def setUpClass(cls): + # The tests here don't play nice with our approach to refleak + # detection, so we bail out in that case. + if cls._has_run: + raise unittest.SkipTest('these tests do not support re-running') + cls._has_run = True + + @contextlib.contextmanager + def basic_static_type(self, *args): + cls = _testcapi.get_basic_static_type(*args) + yield cls + + def test_pytype_ready_always_sets_tp_type(self): + # The point of this test is to prevent something like + # https://github.com/python/cpython/issues/104614 + # from happening again. + + # First check when tp_base/tp_bases is *not* set before PyType_Ready(). + with self.basic_static_type() as cls: + self.assertIs(cls.__base__, object); + self.assertEqual(cls.__bases__, (object,)); + self.assertIs(type(cls), type(object)); + + # Then check when we *do* set tp_base/tp_bases first. + with self.basic_static_type(object) as cls: + self.assertIs(cls.__base__, object); + self.assertEqual(cls.__bases__, (object,)); + self.assertIs(type(cls), type(object)); + + class TestThreadState(unittest.TestCase): @threading_helper.reap_threads diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 66c1cbabe0f8c4..3caaca35cd742d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2627,6 +2627,50 @@ type_get_tp_mro(PyObject *self, PyObject *type) } +/* We only use 2 in test_capi/test_misc.py. */ +#define NUM_BASIC_STATIC_TYPES 2 +static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = { +#define INIT_BASIC_STATIC_TYPE \ + { \ + PyVarObject_HEAD_INIT(NULL, 0) \ + .tp_name = "BasicStaticType", \ + .tp_basicsize = sizeof(PyObject), \ + } + INIT_BASIC_STATIC_TYPE, + INIT_BASIC_STATIC_TYPE, +#undef INIT_BASIC_STATIC_TYPE +}; +static int num_basic_static_types_used = 0; + +static PyObject * +get_basic_static_type(PyObject *self, PyObject *args) +{ + PyObject *base = NULL; + if (!PyArg_ParseTuple(args, "|O", &base)) { + return NULL; + } + assert(base == NULL || PyType_Check(base)); + + if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) { + PyErr_SetString(PyExc_RuntimeError, "no more available basic static types"); + return NULL; + } + PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++]; + + if (base != NULL) { + cls->tp_base = (PyTypeObject *)Py_NewRef(base); + cls->tp_bases = Py_BuildValue("(O)", base); + if (cls->tp_bases == NULL) { + return NULL; + } + } + if (PyType_Ready(cls) < 0) { + return NULL; + } + return (PyObject *)cls; +} + + // Test PyThreadState C API static PyObject * test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) @@ -3384,6 +3428,7 @@ static PyMethodDef TestMethods[] = { {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")}, {"type_get_tp_bases", type_get_tp_bases, METH_O}, {"type_get_tp_mro", type_get_tp_mro, METH_O}, + {"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL}, {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, {"frame_getlocals", frame_getlocals, METH_O, NULL}, {"frame_getglobals", frame_getglobals, METH_O, NULL}, diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6540d4ef7fc482..b6771d3004df91 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -306,11 +306,14 @@ clear_tp_bases(PyTypeObject *self) { if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) { - if (self->tp_bases != NULL - && PyTuple_GET_SIZE(self->tp_bases) > 0) - { - assert(_Py_IsImmortal(self->tp_bases)); - _Py_ClearImmortal(self->tp_bases); + if (self->tp_bases != NULL) { + if (PyTuple_GET_SIZE(self->tp_bases) == 0) { + Py_CLEAR(self->tp_bases); + } + else { + assert(_Py_IsImmortal(self->tp_bases)); + _Py_ClearImmortal(self->tp_bases); + } } } return; @@ -352,11 +355,14 @@ clear_tp_mro(PyTypeObject *self) { if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) { - if (self->tp_mro != NULL - && PyTuple_GET_SIZE(self->tp_mro) > 0) - { - assert(_Py_IsImmortal(self->tp_mro)); - _Py_ClearImmortal(self->tp_mro); + if (self->tp_mro != NULL) { + if (PyTuple_GET_SIZE(self->tp_mro) == 0) { + Py_CLEAR(self->tp_mro); + } + else { + assert(_Py_IsImmortal(self->tp_mro)); + _Py_ClearImmortal(self->tp_mro); + } } } return; @@ -6996,12 +7002,8 @@ type_ready_pre_checks(PyTypeObject *type) static int -type_ready_set_bases(PyTypeObject *type) +type_ready_set_base(PyTypeObject *type) { - if (lookup_tp_bases(type) != NULL) { - return 0; - } - /* Initialize tp_base (defaults to BaseObject unless that's us) */ PyTypeObject *base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { @@ -7025,6 +7027,12 @@ type_ready_set_bases(PyTypeObject *type) } } + return 0; +} + +static int +type_ready_set_type(PyTypeObject *type) +{ /* Initialize ob_type if NULL. This means extensions that want to be compilable separately on Windows can call PyType_Ready() instead of initializing the ob_type field of their type objects. */ @@ -7032,11 +7040,25 @@ type_ready_set_bases(PyTypeObject *type) NULL when type is &PyBaseObject_Type, and we know its ob_type is not NULL (it's initialized to &PyType_Type). But coverity doesn't know that. */ + PyTypeObject *base = type->tp_base; if (Py_IS_TYPE(type, NULL) && base != NULL) { Py_SET_TYPE(type, Py_TYPE(base)); } - /* Initialize tp_bases */ + return 0; +} + +static int +type_ready_set_bases(PyTypeObject *type) +{ + if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) { + assert(lookup_tp_bases(type) != NULL); + return 0; + } + assert(lookup_tp_bases(type) == NULL); + } + PyObject *bases = lookup_tp_bases(type); if (bases == NULL) { PyTypeObject *base = type->tp_base; @@ -7446,6 +7468,12 @@ type_ready(PyTypeObject *type, int rerunbuiltin) if (type_ready_set_dict(type) < 0) { goto error; } + if (type_ready_set_base(type) < 0) { + goto error; + } + if (type_ready_set_type(type) < 0) { + goto error; + } if (type_ready_set_bases(type) < 0) { goto error; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index e9056aed5dc0b2..4c40a04a6854bf 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -424,6 +424,8 @@ Modules/_testcapi/watchers.c - num_code_object_destroyed_events - Modules/_testcapi/watchers.c - pyfunc_watchers - Modules/_testcapi/watchers.c - func_watcher_ids - Modules/_testcapi/watchers.c - func_watcher_callbacks - +Modules/_testcapimodule.c - BasicStaticTypes - +Modules/_testcapimodule.c - num_basic_static_types_used - Modules/_testcapimodule.c - ContainerNoGC_members - Modules/_testcapimodule.c - ContainerNoGC_type - Modules/_testcapimodule.c - FmData - From e6d5e63614684025d4aa09f77a759eb3fc0bd77f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:06:07 -0700 Subject: [PATCH 0106/1206] [3.12] gh-104799: Default missing lists in AST to the empty list (GH-104834) (#105213) (cherry picked from commit 77d25795862f19c6e3d647b76cfb10d5ce1f149c) Co-authored-by: Jelle Zijlstra Co-authored-by: Alex Waygood --- Lib/test/test_ast.py | 2 + ...-05-31-08-10-59.gh-issue-104799.8kDWti.rst | 4 + Parser/asdl_c.py | 49 +- Python/Python-ast.c | 584 +++++++++++------- 4 files changed, 400 insertions(+), 239 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 76edbf5121c806..ffd082ec11806a 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1591,6 +1591,8 @@ def test_funcdef(self): f = ast.FunctionDef("x", a, [ast.Pass()], [], ast.Name("x", ast.Store()), None, []) self.stmt(f, "must have Load context") + f = ast.FunctionDef("x", ast.arguments(), [ast.Pass()]) + self.stmt(f) def fac(args): return ast.FunctionDef("x", args, [ast.Pass()], [], None, None, []) self._check_arguments(fac, self.stmt) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst new file mode 100644 index 00000000000000..e1fe47f862529c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst @@ -0,0 +1,4 @@ +Attributes of :mod:`ast` nodes that are lists now default to the empty list +if omitted. This means that some code that previously raised +:exc:`TypeError` when the AST node was used will now proceed with the empty +list instead. Patch by Jelle Zijlstra. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index 5d5a05a70ca7ec..cb312796f89e04 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -632,29 +632,38 @@ def visitField(self, field, name, sum=None, prod=None, depth=0): self.emit(line % field.name, depth) self.emit("return 1;", depth+1) self.emit("}", depth) - if not field.opt: + if field.seq: self.emit("if (tmp == NULL) {", depth) - message = "required field \\\"%s\\\" missing from %s" % (field.name, name) - format = "PyErr_SetString(PyExc_TypeError, \"%s\");" - self.emit(format % message, depth+1, reflow=False) - self.emit("return 1;", depth+1) + self.emit("tmp = PyList_New(0);", depth+1) + self.emit("if (tmp == NULL) {", depth+1) + self.emit("return 1;", depth+2) + self.emit("}", depth+1) + self.emit("}", depth) + self.emit("{", depth) else: - self.emit("if (tmp == NULL || tmp == Py_None) {", depth) - self.emit("Py_CLEAR(tmp);", depth+1) - if self.isNumeric(field): - if field.name in self.attribute_special_defaults: - self.emit( - "%s = %s;" % (field.name, self.attribute_special_defaults[field.name]), - depth+1, - ) - else: - self.emit("%s = 0;" % field.name, depth+1) - elif not self.isSimpleType(field): - self.emit("%s = NULL;" % field.name, depth+1) + if not field.opt: + self.emit("if (tmp == NULL) {", depth) + message = "required field \\\"%s\\\" missing from %s" % (field.name, name) + format = "PyErr_SetString(PyExc_TypeError, \"%s\");" + self.emit(format % message, depth+1, reflow=False) + self.emit("return 1;", depth+1) else: - raise TypeError("could not determine the default value for %s" % field.name) - self.emit("}", depth) - self.emit("else {", depth) + self.emit("if (tmp == NULL || tmp == Py_None) {", depth) + self.emit("Py_CLEAR(tmp);", depth+1) + if self.isNumeric(field): + if field.name in self.attribute_special_defaults: + self.emit( + "%s = %s;" % (field.name, self.attribute_special_defaults[field.name]), + depth+1, + ) + else: + self.emit("%s = 0;" % field.name, depth+1) + elif not self.isSimpleType(field): + self.emit("%s = NULL;" % field.name, depth+1) + else: + raise TypeError("could not determine the default value for %s" % field.name) + self.emit("}", depth) + self.emit("else {", depth) self.emit("int res;", depth+1) if field.seq: diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 030c082a4a6b14..84bce59e271471 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -5760,10 +5760,12 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -5796,10 +5798,12 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_ignores\" missing from Module"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -5844,10 +5848,12 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -5922,10 +5928,12 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"argtypes\" missing from FunctionType"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6119,10 +6127,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6155,10 +6165,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6225,10 +6237,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from FunctionDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6316,10 +6330,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFunctionDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6352,10 +6368,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from AsyncFunctionDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6422,10 +6440,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from AsyncFunctionDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6495,10 +6515,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6531,10 +6553,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6567,10 +6591,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6603,10 +6629,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6639,10 +6667,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from ClassDef"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6719,10 +6749,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6770,10 +6802,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -6872,10 +6906,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from TypeAlias"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7126,10 +7162,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7162,10 +7200,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7266,10 +7306,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFor"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7302,10 +7344,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from AsyncFor"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7388,10 +7432,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7424,10 +7470,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7492,10 +7540,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7528,10 +7578,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7579,10 +7631,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7615,10 +7669,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7683,10 +7739,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from AsyncWith"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7719,10 +7777,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncWith"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7803,10 +7863,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"cases\" missing from Match"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7903,10 +7965,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7939,10 +8003,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -7975,10 +8041,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8011,10 +8079,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8063,10 +8133,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from TryStar"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8099,10 +8171,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from TryStar"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8135,10 +8209,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from TryStar"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8171,10 +8247,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from TryStar"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8268,10 +8346,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8336,10 +8416,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8402,10 +8484,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8451,10 +8535,12 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -8676,10 +8762,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9002,10 +9090,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9038,10 +9128,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9087,10 +9179,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9154,10 +9248,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9221,10 +9317,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9306,10 +9404,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9373,10 +9473,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9531,10 +9633,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9567,10 +9671,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9635,10 +9741,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9671,10 +9779,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -9787,10 +9897,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from JoinedStr"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -10113,10 +10225,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -10180,10 +10294,12 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -10666,10 +10782,12 @@ obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -10855,10 +10973,12 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -10916,10 +11036,12 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"posonlyargs\" missing from arguments"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -10952,10 +11074,12 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11005,10 +11129,12 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11041,10 +11167,12 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11094,10 +11222,12 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11613,10 +11743,12 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from match_case"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11809,10 +11941,12 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchSequence"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11860,10 +11994,12 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from MatchMapping"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11896,10 +12032,12 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchMapping"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -11982,10 +12120,12 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchClass"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -12018,10 +12158,12 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"kwd_attrs\" missing from MatchClass"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -12054,10 +12196,12 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"kwd_patterns\" missing from MatchClass"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; @@ -12182,10 +12326,12 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchOr"); - return 1; + tmp = PyList_New(0); + if (tmp == NULL) { + return 1; + } } - else { + { int res; Py_ssize_t len; Py_ssize_t i; From 46cc4f0f76a9f6966aee76d74f8db9a2f43fa8a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 2 Jun 2023 01:24:25 -0700 Subject: [PATCH 0107/1206] [3.12] gh-105184: document that marshal functions can fail and need to be checked with PyErr_Occurred (GH-105185) (#105218) gh-105184: document that marshal functions can fail and need to be checked with PyErr_Occurred (GH-105185) (cherry picked from commit ee26ca13a129da8cf549409d0a1b2e892ff2b4ec) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/c-api/marshal.rst | 4 ++++ Python/marshal.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst index 8e25968c6909fd..489f1580a414b2 100644 --- a/Doc/c-api/marshal.rst +++ b/Doc/c-api/marshal.rst @@ -25,12 +25,16 @@ unmarshalling. Version 2 uses a binary format for floating point numbers. the least-significant 32 bits of *value*; regardless of the size of the native :c:expr:`long` type. *version* indicates the file format. + This function can fail, in which case it sets the error indicator. + Use :c:func:`PyErr_Occurred` to check for that. .. c:function:: void PyMarshal_WriteObjectToFile(PyObject *value, FILE *file, int version) Marshal a Python object, *value*, to *file*. *version* indicates the file format. + This function can fail, in which case it sets the error indicator. + Use :c:func:`PyErr_Occurred` to check for that. .. c:function:: PyObject* PyMarshal_WriteObjectToString(PyObject *value, int version) diff --git a/Python/marshal.c b/Python/marshal.c index 208996b05fc484..6439503d2c6879 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -625,6 +625,10 @@ w_clear_refs(WFILE *wf) } /* version currently has no effect for writing ints. */ +/* Note that while the documentation states that this function + * can error, currently it never does. Setting an exception in + * this function should be regarded as an API-breaking change. + */ void PyMarshal_WriteLongToFile(long x, FILE *fp, int version) { From 103ae4e36e965b2d693c90bb6cb699f845903950 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 2 Jun 2023 05:53:27 -0700 Subject: [PATCH 0108/1206] [3.12] gh-105194: Fix format specifier escaped characters in f-strings (GH-105231) (#105234) --- Grammar/python.gram | 2 +- Lib/test/test_fstring.py | 10 ++++++++++ ...-06-02-11-37-12.gh-issue-105194.4eu56B.rst | 2 ++ Parser/action_helpers.c | 19 +++++++++++++++++++ Parser/parser.c | 2 +- Parser/pegen.h | 1 + 6 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 9131835f7421bc..6b2a46aff0dcf0 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -923,7 +923,7 @@ fstring_conversion[ResultTokenWithMetadata*]: fstring_full_format_spec[ResultTokenWithMetadata*]: | colon=':' spec=fstring_format_spec* { _PyPegen_setup_full_format_spec(p, colon, (asdl_expr_seq *) spec, EXTRA) } fstring_format_spec[expr_ty]: - | t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) } + | t=FSTRING_MIDDLE { _PyPegen_decoded_constant_from_token(p, t) } | fstring_replacement_field fstring[expr_ty]: | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 3ba2f943e6e968..031b94d8d58a39 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -764,6 +764,16 @@ def test_format_specifier_expressions(self): """f'{"s"!{"r"}}'""", ]) + def test_custom_format_specifier(self): + class CustomFormat: + def __format__(self, format_spec): + return format_spec + + self.assertEqual(f'{CustomFormat():\n}', '\n') + self.assertEqual(f'{CustomFormat():\u2603}', '☃') + with self.assertWarns(SyntaxWarning): + exec('f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat}) + def test_side_effect_order(self): class X: def __init__(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst new file mode 100644 index 00000000000000..adee74f5894b54 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst @@ -0,0 +1,2 @@ +Do not escape with backslashes f-string format specifiers. Patch by Pablo +Galindo diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index c4d8f75e542805..9f5135380db1b2 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1356,6 +1356,25 @@ _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b p->arena); } +expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok) { + Py_ssize_t bsize; + char* bstr; + if (PyBytes_AsStringAndSize(tok->bytes, &bstr, &bsize) == -1) { + return NULL; + } + PyObject* str = _PyPegen_decode_string(p, 0, bstr, bsize, tok); + if (str == NULL) { + return NULL; + } + if (_PyArena_AddPyObject(p->arena, str) < 0) { + Py_DECREF(str); + return NULL; + } + return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset, + tok->end_lineno, tok->end_col_offset, + p->arena); +} + expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) { char* bstr = PyBytes_AsString(tok->bytes); if (bstr == NULL) { diff --git a/Parser/parser.c b/Parser/parser.c index 1705ebd456b5ff..006ee297974a61 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -16323,7 +16323,7 @@ fstring_format_spec_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ fstring_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); - _res = _PyPegen_constant_from_token ( p , t ); + _res = _PyPegen_decoded_constant_from_token ( p , t ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; diff --git a/Parser/pegen.h b/Parser/pegen.h index 8800e9f97f5e04..fe13d10e6b83e3 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -328,6 +328,7 @@ expr_ty _PyPegen_collect_call_seqs(Parser *, asdl_expr_seq *, asdl_seq *, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok); +expr_ty _PyPegen_decoded_constant_from_token(Parser* p, Token* tok); expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok); expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *, int, int, int, int, PyArena *); expr_ty _PyPegen_FetchRawForm(Parser *p, int, int, int, int); From 00fe6186cb8bb5de9ab1604521dfd2584a487545 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 2 Jun 2023 09:04:22 -0700 Subject: [PATCH 0109/1206] [3.12] gh-102778: update documentation of PyErr_PrintEx and traceback.print_last() regarding sys.last_exc (GH-105190) (#105246) gh-102778: update documentation of PyErr_PrintEx and traceback.print_last() regarding sys.last_exc (GH-105190) (cherry picked from commit 0dafc785ee6629dbcb9bec6f7aee43a56cd0b26e) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/c-api/exceptions.rst | 11 ++++++++--- Doc/library/traceback.rst | 7 +++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index dc73ad8157961b..1694aa2db9c9da 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -60,9 +60,14 @@ Printing and clearing Call this function **only** when the error indicator is set. Otherwise it will cause a fatal error! - If *set_sys_last_vars* is nonzero, the variables :data:`sys.last_type`, - :data:`sys.last_value` and :data:`sys.last_traceback` will be set to the - type, value and traceback of the printed exception, respectively. + If *set_sys_last_vars* is nonzero, the variable :data:`sys.last_exc` is + set to the printed exception. For backwards compatibility, the + deprecated variables :data:`sys.last_type`, :data:`sys.last_value` and + :data:`sys.last_traceback` are also set to the type, value and traceback + of this exception, respectively. + + .. versionchanged:: 3.12 + The setting of :data:`sys.last_exc` was added. .. c:function:: void PyErr_Print() diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 9a04b56947a1bb..58f47818fcecab 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -86,10 +86,9 @@ The module defines the following functions: .. function:: print_last(limit=None, file=None, chain=True) - This is a shorthand for ``print_exception(sys.last_type, sys.last_value, - sys.last_traceback, limit, file, chain)``. In general it will work only - after an exception has reached an interactive prompt (see - :data:`sys.last_type`). + This is a shorthand for ``print_exception(sys.last_exc, limit, file, + chain)``. In general it will work only after an exception has reached + an interactive prompt (see :data:`sys.last_exc`). .. function:: print_stack(f=None, limit=None, file=None) From 72d5dfaa8f475498644035839f5a6469db486407 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 2 Jun 2023 10:09:51 -0700 Subject: [PATCH 0110/1206] [3.12] gh-104614: Fix potential ref. leak in _testcapimodule/get_basic_static_type() (GH-105225) (#105248) (cherry picked from commit e01b04c9075c6468ed57bc883693ec2a06a6dd8e) Co-authored-by: Erlend E. Aasland --- Modules/_testcapimodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3caaca35cd742d..b8ad00a0197421 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2658,13 +2658,15 @@ get_basic_static_type(PyObject *self, PyObject *args) PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++]; if (base != NULL) { - cls->tp_base = (PyTypeObject *)Py_NewRef(base); cls->tp_bases = Py_BuildValue("(O)", base); if (cls->tp_bases == NULL) { return NULL; } + cls->tp_base = (PyTypeObject *)Py_NewRef(base); } if (PyType_Ready(cls) < 0) { + Py_DECREF(cls->tp_bases); + Py_DECREF(cls->tp_base); return NULL; } return (PyObject *)cls; From d3922c4688172c6865caaee69ed1afb439907919 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:05:49 -0700 Subject: [PATCH 0111/1206] [3.12] gh-105080: Fixed inconsistent signature on derived classes (GH-105217) (#105257) gh-105080: Fixed inconsistent signature on derived classes (GH-105217) (cherry picked from commit 9ad199ba36791711f596393ca9a20dbf118ef858) Co-authored-by: Tian Gao --- Lib/inspect.py | 23 ++++++++++--------- Lib/test/test_inspect.py | 18 +++++++++++++++ ...-06-02-02-38-26.gh-issue-105080.2imGMg.rst | 1 + 3 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index 15eefdb6570be4..a550202bb0d49b 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2581,17 +2581,18 @@ def _signature_from_callable(obj, *, factory_method = None new = _signature_get_user_defined_method(obj, '__new__') init = _signature_get_user_defined_method(obj, '__init__') - # Now we check if the 'obj' class has an own '__new__' method - if '__new__' in obj.__dict__: - factory_method = new - # or an own '__init__' method - elif '__init__' in obj.__dict__: - factory_method = init - # If not, we take inherited '__new__' or '__init__', if present - elif new is not None: - factory_method = new - elif init is not None: - factory_method = init + + # Go through the MRO and see if any class has user-defined + # pure Python __new__ or __init__ method + for base in obj.__mro__: + # Now we check if the 'obj' class has an own '__new__' method + if new is not None and '__new__' in base.__dict__: + factory_method = new + break + # or an own '__init__' method + elif init is not None and '__init__' in base.__dict__: + factory_method = init + break if factory_method is not None: sig = _get_signature_of(factory_method) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 6a49e3b5530e16..d89953ab60f022 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -3927,6 +3927,24 @@ def __signature__(): ('b', 2, ..., 'positional_or_keyword')), ...)) + def test_signature_on_derived_classes(self): + # gh-105080: Make sure that signatures are consistent on derived classes + + class B: + def __new__(self, *args, **kwargs): + return super().__new__(self) + def __init__(self, value): + self.value = value + + class D1(B): + def __init__(self, value): + super().__init__(value) + + class D2(D1): + pass + + self.assertEqual(inspect.signature(D2), inspect.signature(D1)) + class TestParameterObject(unittest.TestCase): def test_signature_parameter_kinds(self): diff --git a/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst b/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst new file mode 100644 index 00000000000000..efe8365a7644be --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst @@ -0,0 +1 @@ +Fixed inconsistent signature on derived classes for :func:`inspect.signature` From f629d5fc240e674652e6d183ada7a4e2dbdf3e18 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 3 Jun 2023 08:29:18 -0700 Subject: [PATCH 0112/1206] [3.12] gh-89415: Mention new `IP_*` constants in `socket` module in the docs (GH-105266) (#105270) gh-89415: Mention new `IP_*` constants in `socket` module in the docs (GH-105266) (cherry picked from commit eaff9c39aa1a70d401521847cc35bec883ae9772) Co-authored-by: Nikita Sobolev --- Doc/library/socket.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 13a82cf82d5908..21453b40478231 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -436,7 +436,8 @@ Constants ``TCP_FASTOPEN_CONNECT``, ``TCP_ULP``, ``TCP_MD5SIG_EXT``, ``TCP_FASTOPEN_KEY``, ``TCP_FASTOPEN_NO_COOKIE``, ``TCP_ZEROCOPY_RECEIVE``, ``TCP_INQ``, ``TCP_TX_DELAY``. - Added ``IP_PKTINFO``. + Added ``IP_PKTINFO``, ``IP_UNBLOCK_SOURCE``, ``IP_BLOCK_SOURCE``, + ``IP_ADD_SOURCE_MEMBERSHIP``, ``IP_DROP_SOURCE_MEMBERSHIP``. .. data:: AF_CAN PF_CAN From c7a9d96a25a646d37cb97506019e82ee7493d1b3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 3 Jun 2023 21:32:00 -0700 Subject: [PATCH 0113/1206] [3.12] gh-104690 Disallow thread creation and fork at interpreter finalization (GH-104826) (#105277) gh-104690 Disallow thread creation and fork at interpreter finalization (GH-104826) Disallow thread creation and fork at interpreter finalization. in the following functions, check if interpreter is finalizing and raise `RuntimeError` with appropriate message: * `_thread.start_new_thread` and thus `threading` * `posix.fork` * `posix.fork1` * `posix.forkpty` * `_posixsubprocess.fork_exec` when a `preexec_fn=` is supplied. --------- (cherry picked from commit ce558e69d4087dd3653207de78345fbb8a2c7835) Co-authored-by: chgnrdv <52372310+chgnrdv@users.noreply.github.com> Co-authored-by: Gregory P. Smith --- Doc/library/atexit.rst | 10 +++++ Lib/test/test_os.py | 16 +++++++ Lib/test/test_subprocess.py | 19 ++++++++ Lib/test/test_threading.py | 44 +++++++------------ ...-05-24-12-10-54.gh-issue-104690.HX3Jou.rst | 6 +++ Modules/_posixsubprocess.c | 6 +++ Modules/_threadmodule.c | 5 +++ Modules/posixmodule.c | 21 ++++++++- 8 files changed, 97 insertions(+), 30 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst diff --git a/Doc/library/atexit.rst b/Doc/library/atexit.rst index a2bd85b31c9a8d..3dbef69580d9b3 100644 --- a/Doc/library/atexit.rst +++ b/Doc/library/atexit.rst @@ -48,6 +48,16 @@ a cleanup function is undefined. This function returns *func*, which makes it possible to use it as a decorator. + .. warning:: + Starting new threads or calling :func:`os.fork` from a registered + function can lead to race condition between the main Python + runtime thread freeing thread states while internal :mod:`threading` + routines or the new process try to use that state. This can lead to + crashes rather than clean shutdown. + + .. versionchanged:: 3.12 + Attempts to start a new thread or :func:`os.fork` a new process + in a registered function now leads to :exc:`RuntimeError`. .. function:: unregister(func) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 584cc05ca82a55..9453742132667d 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -4700,6 +4700,22 @@ def test_fork_warns_when_non_python_thread_exists(self): self.assertEqual(err.decode("utf-8"), "") self.assertEqual(out.decode("utf-8"), "") + def test_fork_at_exit(self): + code = """if 1: + import atexit + import os + + def exit_handler(): + pid = os.fork() + if pid != 0: + print("shouldn't be printed") + + atexit.register(exit_handler) + """ + _, out, err = assert_python_ok("-c", code) + self.assertEqual(b"", out) + self.assertIn(b"can't fork at interpreter shutdown", err) + # Only test if the C version is provided, otherwise TestPEP519 already tested # the pure Python implementation. diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 92f81eaafb1c93..51ba423a0f1c92 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -5,6 +5,7 @@ from test.support import import_helper from test.support import os_helper from test.support import warnings_helper +from test.support.script_helper import assert_python_ok import subprocess import sys import signal @@ -3329,6 +3330,24 @@ def test_communicate_repeated_call_after_stdout_close(self): except subprocess.TimeoutExpired: pass + def test_preexec_at_exit(self): + code = f"""if 1: + import atexit + import subprocess + + def dummy(): + pass + + def exit_handler(): + subprocess.Popen({ZERO_RETURN_CMD}, preexec_fn=dummy) + print("shouldn't be printed") + + atexit.register(exit_handler) + """ + _, out, err = assert_python_ok("-c", code) + self.assertEqual(out, b'') + self.assertIn(b"preexec_fn not supported at interpreter shutdown", err) + @unittest.skipUnless(mswindows, "Windows specific tests") class Win32ProcessTestCase(BaseTestCase): diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 97165264b34bbe..9e4972ecb640df 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -531,34 +531,6 @@ def test_daemon_param(self): t = threading.Thread(daemon=True) self.assertTrue(t.daemon) - @support.requires_fork() - def test_fork_at_exit(self): - # bpo-42350: Calling os.fork() after threading._shutdown() must - # not log an error. - code = textwrap.dedent(""" - import atexit - import os - import sys - from test.support import wait_process - - # Import the threading module to register its "at fork" callback - import threading - - def exit_handler(): - pid = os.fork() - if not pid: - print("child process ok", file=sys.stderr, flush=True) - # child process - else: - wait_process(pid, exitcode=0) - - # exit_handler() will be called after threading._shutdown() - atexit.register(exit_handler) - """) - _, out, err = assert_python_ok("-c", code) - self.assertEqual(out, b'') - self.assertEqual(err.rstrip(), b'child process ok') - @support.requires_fork() def test_dummy_thread_after_fork(self): # Issue #14308: a dummy thread in the active list doesn't mess up @@ -1048,6 +1020,22 @@ def import_threading(): self.assertEqual(out, b'') self.assertEqual(err, b'') + def test_start_new_thread_at_exit(self): + code = """if 1: + import atexit + import _thread + + def f(): + print("shouldn't be printed") + + def exit_handler(): + _thread.start_new_thread(f, ()) + + atexit.register(exit_handler) + """ + _, out, err = assert_python_ok("-c", code) + self.assertEqual(out, b'') + self.assertIn(b"can't create new thread at interpreter shutdown", err) class ThreadJoinOnShutdown(BaseTestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst new file mode 100644 index 00000000000000..7934dd23b10691 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst @@ -0,0 +1,6 @@ +Starting new threads and process creation through :func:`os.fork` during interpreter +shutdown (such as from :mod:`atexit` handlers) is no longer supported. It can lead +to race condition between the main Python runtime thread freeing thread states while +internal :mod:`threading` routines are trying to allocate and use the state of just +created threads. Or forked children trying to use the mid-shutdown runtime and thread +state in the child process. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 36470804c6a165..2d88f5e9ba1601 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -5,6 +5,7 @@ #include "Python.h" #include "pycore_fileutils.h" +#include "pycore_pystate.h" #if defined(HAVE_PIPE2) && !defined(_GNU_SOURCE) # define _GNU_SOURCE #endif @@ -943,6 +944,11 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE(py_fds_to_keep); PyInterpreterState *interp = PyInterpreterState_Get(); + if ((preexec_fn != Py_None) && interp->finalizing) { + PyErr_SetString(PyExc_RuntimeError, + "preexec_fn not supported at interpreter shutdown"); + return NULL; + } if ((preexec_fn != Py_None) && (interp != PyInterpreterState_Main())) { PyErr_SetString(PyExc_RuntimeError, "preexec_fn not supported within subinterpreters"); diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 5d753b4a0ebc5e..b6f878e07526db 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1155,6 +1155,11 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) "thread is not supported for isolated subinterpreters"); return NULL; } + if (interp->finalizing) { + PyErr_SetString(PyExc_RuntimeError, + "can't create new thread at interpreter shutdown"); + return NULL; + } struct bootstate *boot = PyMem_NEW(struct bootstate, 1); if (boot == NULL) { diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index abc50b4d335bd2..f5e653dd023aef 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7620,7 +7620,13 @@ os_fork1_impl(PyObject *module) { pid_t pid; - if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->finalizing) { + PyErr_SetString(PyExc_RuntimeError, + "can't fork at interpreter shutdown"); + return NULL; + } + if (!_Py_IsMainInterpreter(interp)) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters"); return NULL; } @@ -7656,6 +7662,11 @@ os_fork_impl(PyObject *module) { pid_t pid; PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->finalizing) { + PyErr_SetString(PyExc_RuntimeError, + "can't fork at interpreter shutdown"); + return NULL; + } if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_FORK)) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for isolated subinterpreters"); @@ -8327,7 +8338,13 @@ os_forkpty_impl(PyObject *module) int master_fd = -1; pid_t pid; - if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->finalizing) { + PyErr_SetString(PyExc_RuntimeError, + "can't fork at interpreter shutdown"); + return NULL; + } + if (!_Py_IsMainInterpreter(interp)) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters"); return NULL; } From 6b61fe90975b3693f51e257723716fe9c3090911 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 4 Jun 2023 08:50:27 -0700 Subject: [PATCH 0114/1206] [3.12] Fix typo in Python 3.12 What's New (GH-105278) (#105282) Fix typo in Python 3.12 What's New (GH-105278) (cherry picked from commit 9a90c9ace2ed878715107bf4ae39e5967d7c931f) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 2966abe7eea544..3e8b866e6bfb5f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1337,8 +1337,8 @@ Removed * Support for ``find_loader()`` and ``find_module()`` APIs have been removed. (Contributed by Barry Warsaw in :gh:`98040`.) - * ``importlib.abc.Finder``, ``pkg.ImpImporter``, and ``pkg.ImpLoader`` have - been removed. (Contributed by Barry Warsaw in :gh:`98040`.) + * ``importlib.abc.Finder``, ``pkgutil.ImpImporter``, and ``pkgutil.ImpLoader`` + have been removed. (Contributed by Barry Warsaw in :gh:`98040`.) * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in :gh:`98040`.) From 9ce3312cdba865b57547377d4e99877fe811a92f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 4 Jun 2023 09:07:59 -0700 Subject: [PATCH 0115/1206] [3.12] gh-104882: Docs: fix description of relationship between `socket.getblocking()` and `socket.gettimeout()` (GH-105026) (#105283) gh-104882: Docs: fix description of relationship between `socket.getblocking()` and `socket.gettimeout()` (GH-105026) (cherry picked from commit 5a5ed7a3e616a372f054a1dd2e9a31ba32a87a67) Co-authored-by: Joe Geisbauer --- Doc/library/socket.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 21453b40478231..5f795af42b812e 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1527,7 +1527,7 @@ to sockets. Return ``True`` if socket is in blocking mode, ``False`` if in non-blocking. - This is equivalent to checking ``socket.gettimeout() == 0``. + This is equivalent to checking ``socket.gettimeout() != 0``. .. versionadded:: 3.7 From 3e7ddc29a3f33b638c5d51d9372763fbc688b06b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 4 Jun 2023 20:45:12 -0700 Subject: [PATCH 0116/1206] [3.12] gh-98963: Restore the ability to have a dict-less property. (GH-105262) (#105297) gh-98963: Restore the ability to have a dict-less property. (GH-105262) Ignore doc string assignment failures in `property` as has been the behavior of all past Python releases. (the docstring is discarded) (cherry picked from commit 418befd75d4d0d1cba83d8b81e1a7bcc9a65be8e) This fixes a behavior regression in 3.12beta1 where an AttributeError was being raised in a situation it has never been in the past. It keeps the existing unusual single situation where AttributeError does get raised. Existing widely deployed projects depend on this not raising an exception. Co-authored-by: Gregory P. Smith --- Lib/test/test_property.py | 61 +++++++++++++++++-- ...3-06-02-17-39-19.gh-issue-98963.J4wJgk.rst | 4 ++ Objects/descrobject.c | 45 +++++++++++--- 3 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index d4bdf50c0192ae..45aa9e51c06de0 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -246,16 +246,67 @@ class PropertySubSlots(property): class PropertySubclassTests(unittest.TestCase): def test_slots_docstring_copy_exception(self): - try: + # A special case error that we preserve despite the GH-98963 behavior + # that would otherwise silently ignore this error. + # This came from commit b18500d39d791c879e9904ebac293402b4a7cd34 + # as part of https://bugs.python.org/issue5890 which allowed docs to + # be set via property subclasses in the first place. + with self.assertRaises(AttributeError): class Foo(object): @PropertySubSlots def spam(self): """Trying to copy this docstring will raise an exception""" return 1 - except AttributeError: - pass - else: - raise Exception("AttributeError not raised") + + def test_property_with_slots_no_docstring(self): + # https://github.com/python/cpython/issues/98963#issuecomment-1574413319 + class slotted_prop(property): + __slots__ = ("foo",) + + p = slotted_prop() # no AttributeError + self.assertIsNone(getattr(p, "__doc__", None)) + + def undocumented_getter(): + return 4 + + p = slotted_prop(undocumented_getter) # New in 3.12: no AttributeError + self.assertIsNone(getattr(p, "__doc__", None)) + + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def test_property_with_slots_docstring_silently_dropped(self): + # https://github.com/python/cpython/issues/98963#issuecomment-1574413319 + class slotted_prop(property): + __slots__ = ("foo",) + + p = slotted_prop(doc="what's up") # no AttributeError + self.assertIsNone(p.__doc__) + + def documented_getter(): + """getter doc.""" + return 4 + + # Historical behavior: A docstring from a getter always raises. + # (matches test_slots_docstring_copy_exception above). + with self.assertRaises(AttributeError): + p = slotted_prop(documented_getter) + + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def test_property_with_slots_and_doc_slot_docstring_present(self): + # https://github.com/python/cpython/issues/98963#issuecomment-1574413319 + class slotted_prop(property): + __slots__ = ("foo", "__doc__") + + p = slotted_prop(doc="what's up") + self.assertEqual("what's up", p.__doc__) # new in 3.12: This gets set. + + def documented_getter(): + """what's up getter doc?""" + return 4 + + p = slotted_prop(documented_getter) + self.assertEqual("what's up getter doc?", p.__doc__) @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst new file mode 100644 index 00000000000000..4caadb0875a188 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst @@ -0,0 +1,4 @@ +Restore the ability for a subclass of :class:`property` to define ``__slots__`` +or otherwise be dict-less by ignoring failures to set a docstring on such a +class. This behavior had regressed in 3.12beta1. An :exc:`AttributeError` +where there had not previously been one was disruptive to existing code. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 17c0c85a06c4b8..72ac4703949262 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1485,7 +1485,10 @@ class property(object): self.__get = fget self.__set = fset self.__del = fdel - self.__doc__ = doc + try: + self.__doc__ = doc + except AttributeError: # read-only or dict-less class + pass def __get__(self, inst, type=None): if inst is None: @@ -1791,6 +1794,19 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset, if (rc <= 0) { return rc; } + if (!Py_IS_TYPE(self, &PyProperty_Type) && + prop_doc != NULL && prop_doc != Py_None) { + // This oddity preserves the long existing behavior of surfacing + // an AttributeError when using a dict-less (__slots__) property + // subclass as a decorator on a getter method with a docstring. + // See PropertySubclassTest.test_slots_docstring_copy_exception. + int err = PyObject_SetAttr( + (PyObject *)self, &_Py_ID(__doc__), prop_doc); + if (err < 0) { + Py_DECREF(prop_doc); // release our new reference. + return -1; + } + } if (prop_doc == Py_None) { prop_doc = NULL; Py_DECREF(Py_None); @@ -1806,19 +1822,32 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset, if (Py_IS_TYPE(self, &PyProperty_Type)) { Py_XSETREF(self->prop_doc, prop_doc); } else { - /* If this is a property subclass, put __doc__ - in dict of the subclass instance instead, - otherwise it gets shadowed by __doc__ in the - class's dict. */ + /* If this is a property subclass, put __doc__ in the dict + or designated slot of the subclass instance instead, otherwise + it gets shadowed by __doc__ in the class's dict. */ if (prop_doc == NULL) { prop_doc = Py_NewRef(Py_None); } int err = PyObject_SetAttr( (PyObject *)self, &_Py_ID(__doc__), prop_doc); - Py_XDECREF(prop_doc); - if (err < 0) - return -1; + Py_DECREF(prop_doc); + if (err < 0) { + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + // https://github.com/python/cpython/issues/98963#issuecomment-1574413319 + // Python silently dropped this doc assignment through 3.11. + // We preserve that behavior for backwards compatibility. + // + // If we ever want to deprecate this behavior, only raise a + // warning or error when proc_doc is not None so that + // property without a specific doc= still works. + return 0; + } else { + return -1; + } + } } return 0; From 6d0354167f8093183ae5f12205fd0cf991dbbd6a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 5 Jun 2023 06:42:31 -0700 Subject: [PATCH 0117/1206] [3.12] gh-105164: Detect annotations inside match blocks (GH-105177) (#105313) (cherry picked from commit 69d1245685cf95ddc678633e978a56673da64865) Co-authored-by: Jelle Zijlstra --- Lib/test/test_type_annotations.py | 111 ++++++++++++++++++ ...-05-31-19-35-22.gh-issue-105164.6Wajph.rst | 2 + Python/compile.c | 10 ++ 3 files changed, 123 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index 87f46c2ce8ce61..3dbb35afcb620f 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -1,4 +1,6 @@ +import textwrap import unittest +from test.support import run_code class TypeAnnotationTests(unittest.TestCase): @@ -101,3 +103,112 @@ class D(metaclass=C): with self.assertRaises(AttributeError): del D.__annotations__ self.assertEqual(D.__annotations__, {}) + + +class TestSetupAnnotations(unittest.TestCase): + def check(self, code: str): + code = textwrap.dedent(code) + for scope in ("module", "class"): + with self.subTest(scope=scope): + if scope == "class": + code = f"class C:\n{textwrap.indent(code, ' ')}" + ns = run_code(code) + if scope == "class": + annotations = ns["C"].__annotations__ + else: + annotations = ns["__annotations__"] + self.assertEqual(annotations, {"x": int}) + + def test_top_level(self): + self.check("x: int = 1") + + def test_blocks(self): + self.check("if True:\n x: int = 1") + self.check(""" + while True: + x: int = 1 + break + """) + self.check(""" + while False: + pass + else: + x: int = 1 + """) + self.check(""" + for i in range(1): + x: int = 1 + """) + self.check(""" + for i in range(1): + pass + else: + x: int = 1 + """) + + def test_try(self): + self.check(""" + try: + x: int = 1 + except: + pass + """) + self.check(""" + try: + pass + except: + pass + else: + x: int = 1 + """) + self.check(""" + try: + pass + except: + pass + finally: + x: int = 1 + """) + self.check(""" + try: + 1/0 + except: + x: int = 1 + """) + + def test_try_star(self): + self.check(""" + try: + x: int = 1 + except* Exception: + pass + """) + self.check(""" + try: + pass + except* Exception: + pass + else: + x: int = 1 + """) + self.check(""" + try: + pass + except* Exception: + pass + finally: + x: int = 1 + """) + self.check(""" + try: + 1/0 + except* Exception: + x: int = 1 + """) + + def test_match(self): + self.check(""" + match 0: + case 0: + x: int = 1 + """) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst new file mode 100644 index 00000000000000..7d3486c3b6e98a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst @@ -0,0 +1,2 @@ +Ensure annotations are set up correctly if the only annotation in a block is +within a :keyword:`match` block. Patch by Jelle Zijlstra. diff --git a/Python/compile.c b/Python/compile.c index f2314ae11c417b..32eda4d407ea12 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1422,8 +1422,18 @@ find_ann(asdl_stmt_seq *stmts) find_ann(st->v.TryStar.finalbody) || find_ann(st->v.TryStar.orelse); break; + case Match_kind: + for (j = 0; j < asdl_seq_LEN(st->v.Match.cases); j++) { + match_case_ty match_case = (match_case_ty)asdl_seq_GET( + st->v.Match.cases, j); + if (find_ann(match_case->body)) { + return true; + } + } + break; default: res = false; + break; } if (res) { break; From 51750269cf36901e83a70a1fff9ab93a2e2855fb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 5 Jun 2023 07:06:25 -0700 Subject: [PATCH 0118/1206] [3.12] gh-105237: Allow calling `issubclass(X, typing.Protocol)` again (GH-105239) (#105316) gh-105237: Allow calling `issubclass(X, typing.Protocol)` again (GH-105239) (cherry picked from commit cdfb201bfa35b7c50de5099c6d9078c806851d98) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 59 +++++++++++++++++++ Lib/typing.py | 4 ++ ...-06-02-14-57-11.gh-issue-105239.SAmuuj.rst | 2 + 3 files changed, 65 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 5480a981ad5647..3a2f7393eb46c5 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2758,6 +2758,65 @@ def x(self): ... with self.assertRaisesRegex(TypeError, only_classes_allowed): issubclass(1, BadPG) + def test_issubclass_and_isinstance_on_Protocol_itself(self): + class C: + def x(self): pass + + self.assertNotIsSubclass(object, Protocol) + self.assertNotIsInstance(object(), Protocol) + + self.assertNotIsSubclass(str, Protocol) + self.assertNotIsInstance('foo', Protocol) + + self.assertNotIsSubclass(C, Protocol) + self.assertNotIsInstance(C(), Protocol) + + only_classes_allowed = r"issubclass\(\) arg 1 must be a class" + + with self.assertRaisesRegex(TypeError, only_classes_allowed): + issubclass(1, Protocol) + with self.assertRaisesRegex(TypeError, only_classes_allowed): + issubclass('foo', Protocol) + with self.assertRaisesRegex(TypeError, only_classes_allowed): + issubclass(C(), Protocol) + + T = TypeVar('T') + + @runtime_checkable + class EmptyProtocol(Protocol): pass + + @runtime_checkable + class SupportsStartsWith(Protocol): + def startswith(self, x: str) -> bool: ... + + @runtime_checkable + class SupportsX(Protocol[T]): + def x(self): ... + + for proto in EmptyProtocol, SupportsStartsWith, SupportsX: + with self.subTest(proto=proto.__name__): + self.assertIsSubclass(proto, Protocol) + + # gh-105237 / PR #105239: + # check that the presence of Protocol subclasses + # where `issubclass(X, )` evaluates to True + # doesn't influence the result of `issubclass(X, Protocol)` + + self.assertIsSubclass(object, EmptyProtocol) + self.assertIsInstance(object(), EmptyProtocol) + self.assertNotIsSubclass(object, Protocol) + self.assertNotIsInstance(object(), Protocol) + + self.assertIsSubclass(str, SupportsStartsWith) + self.assertIsInstance('foo', SupportsStartsWith) + self.assertNotIsSubclass(str, Protocol) + self.assertNotIsInstance('foo', Protocol) + + self.assertIsSubclass(C, SupportsX) + self.assertIsInstance(C(), SupportsX) + self.assertNotIsSubclass(C, Protocol) + self.assertNotIsInstance(C(), Protocol) + def test_protocols_issubclass_non_callable(self): class C: x = 1 diff --git a/Lib/typing.py b/Lib/typing.py index 2383d807ec58d1..06d50306c4754e 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1788,6 +1788,8 @@ def __init__(cls, *args, **kwargs): ) def __subclasscheck__(cls, other): + if cls is Protocol: + return type.__subclasscheck__(cls, other) if not isinstance(other, type): # Same error message as for issubclass(1, int). raise TypeError('issubclass() arg 1 must be a class') @@ -1809,6 +1811,8 @@ def __subclasscheck__(cls, other): def __instancecheck__(cls, instance): # We need this method for situations where attributes are # assigned in __init__. + if cls is Protocol: + return type.__instancecheck__(cls, instance) if not getattr(cls, "_is_protocol", False): # i.e., it's a concrete subclass of a protocol return super().__instancecheck__(instance) diff --git a/Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst b/Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst new file mode 100644 index 00000000000000..35e1b1a217b3a4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst @@ -0,0 +1,2 @@ +Fix longstanding bug where ``issubclass(object, typing.Protocol)`` would +evaluate to ``True`` in some edge cases. Patch by Alex Waygood. From 2031238eb64150053117e214ca40dc774b95b933 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 5 Jun 2023 07:51:26 -0700 Subject: [PATCH 0119/1206] [3.12] gh-105280: Ensure `isinstance([], collections.abc.Mapping)` always evaluates to `False` (GH-105281) (#105318) gh-105280: Ensure `isinstance([], collections.abc.Mapping)` always evaluates to `False` (GH-105281) (cherry picked from commit 08756dbba647440803d2ba4545ba0ab2f0cdfe1c) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 14 ++++++++++ Lib/typing.py | 28 +++++++++++++------ ...-06-04-12-16-47.gh-issue-105280.srRbCe.rst | 4 +++ 3 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3a2f7393eb46c5..ef1db06109eca3 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3,6 +3,7 @@ import collections.abc from collections import defaultdict from functools import lru_cache, wraps +import gc import inspect import itertools import pickle @@ -2758,6 +2759,19 @@ def x(self): ... with self.assertRaisesRegex(TypeError, only_classes_allowed): issubclass(1, BadPG) + def test_isinstance_checks_not_at_whim_of_gc(self): + self.addCleanup(gc.enable) + gc.disable() + + with self.assertRaisesRegex( + TypeError, + "Protocols can only inherit from other protocols" + ): + class Foo(collections.abc.Mapping, Protocol): + pass + + self.assertNotIsInstance([], collections.abc.Mapping) + def test_issubclass_and_isinstance_on_Protocol_itself(self): class C: def x(self): pass diff --git a/Lib/typing.py b/Lib/typing.py index 06d50306c4754e..2acb9f052f2af5 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1777,6 +1777,25 @@ def _pickle_pskwargs(pskwargs): class _ProtocolMeta(ABCMeta): # This metaclass is somewhat unfortunate, # but is necessary for several reasons... + def __new__(mcls, name, bases, namespace, /, **kwargs): + if name == "Protocol" and bases == (Generic,): + pass + elif Protocol in bases: + for base in bases: + if not ( + base in {object, Generic} + or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) + or ( + issubclass(base, Generic) + and getattr(base, "_is_protocol", False) + ) + ): + raise TypeError( + f"Protocols can only inherit from other protocols, " + f"got {base!r}" + ) + return super().__new__(mcls, name, bases, namespace, **kwargs) + def __init__(cls, *args, **kwargs): super().__init__(*args, **kwargs) if getattr(cls, "_is_protocol", False): @@ -1912,14 +1931,7 @@ def _proto_hook(other): if not cls._is_protocol: return - # ... otherwise check consistency of bases, and prohibit instantiation. - for base in cls.__bases__: - if not (base in (object, Generic) or - base.__module__ in _PROTO_ALLOWLIST and - base.__name__ in _PROTO_ALLOWLIST[base.__module__] or - issubclass(base, Generic) and getattr(base, '_is_protocol', False)): - raise TypeError('Protocols can only inherit from other' - ' protocols, got %r' % base) + # ... otherwise prohibit instantiation. if cls.__init__ is Protocol.__init__: cls.__init__ = _no_init_or_replace_init diff --git a/Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst b/Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst new file mode 100644 index 00000000000000..8e469646604316 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst @@ -0,0 +1,4 @@ +Fix bug where ``isinstance([], collections.abc.Mapping)`` could evaluate to +``True`` if garbage collection happened at the wrong time. The bug was +caused by changes to the implementation of :class:`typing.Protocol` in +Python 3.12. From 83fc562ea5ff1d731cd1066016c16f9f75a12de4 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 5 Jun 2023 16:05:21 +0100 Subject: [PATCH 0120/1206] [3.12] gh-105286: Improve `typing.py` docstrings (#105287) (#105319) gh-105286: Improve `typing.py` docstrings (#105287) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Co-authored-by: Nikita Sobolev --- Lib/typing.py | 473 +++++++++++++++++++++++++++----------------------- 1 file changed, 253 insertions(+), 220 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index 2acb9f052f2af5..f9a8ea601e793e 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1,22 +1,22 @@ """ -The typing module: Support for gradual typing as defined by PEP 484. - -At large scale, the structure of the module is following: -* Imports and exports, all public names should be explicitly added to __all__. -* Internal helper functions: these should never be used in code outside this module. -* _SpecialForm and its instances (special forms): - Any, NoReturn, Never, ClassVar, Union, Optional, Concatenate, Unpack -* Classes whose instances can be type arguments in addition to types: - ForwardRef, TypeVar and ParamSpec -* The core of internal generics API: _GenericAlias and _VariadicGenericAlias, the latter is - currently only used by Tuple and Callable. All subscripted types like X[int], Union[int, str], - etc., are instances of either of these classes. -* The public counterpart of the generics API consists of two classes: Generic and Protocol. -* Public helper functions: get_type_hints, overload, cast, no_type_check, - no_type_check_decorator. -* Generic aliases for collections.abc ABCs and few additional protocols. +The typing module: Support for gradual typing as defined by PEP 484 and subsequent PEPs. + +Any name not present in __all__ is an implementation detail +that may be changed without notice. Use at your own risk! + +Among other things, the module includes the following: +* Generic, Protocol, and internal machinery to support generic aliases. + All subscripted types like X[int], Union[int, str] are generic aliases. +* Various "special forms" that have unique meanings in type annotations: + NoReturn, Never, ClassVar, Self, Concatenate, Unpack, and others. +* Classes whose instances can be type arguments to generic classes and functions: + TypeVar, ParamSpec, TypeVarTuple. +* Public helper functions: get_type_hints, overload, cast, final, and others. +* Several protocols to support duck-typing: + SupportsFloat, SupportsIndex, SupportsAbs, and others. * Special types: NewType, NamedTuple, TypedDict. -* Wrapper submodules for re and io related types. +* Deprecated wrapper submodules for re and io related types. +* Deprecated aliases for builtin types and collections.abc ABCs. """ from abc import abstractmethod, ABCMeta @@ -178,7 +178,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms= As a special case, accept None and return type(None) instead. Also wrap strings into ForwardRef instances. Consider several corner cases, for example plain special forms like Union are not valid, while Union[int, str] is OK, etc. - The msg argument is a human-readable error message, e.g:: + The msg argument is a human-readable error message, e.g.:: "Union[arg, ...]: arg should be a type." @@ -214,7 +214,7 @@ def _should_unflatten_callable_args(typ, args): """Internal helper for munging collections.abc.Callable's __args__. The canonical representation for a Callable's __args__ flattens the - argument types, see https://bugs.python.org/issue42195. For example: + argument types, see https://bugs.python.org/issue42195. For example:: collections.abc.Callable[[int, int], str].__args__ == (int, int, str) collections.abc.Callable[ParamSpec, str].__args__ == (ParamSpec, str) @@ -255,9 +255,11 @@ def _type_repr(obj): def _collect_parameters(args): """Collect all type variables and parameter specifications in args - in order of first appearance (lexicographic order). For example:: + in order of first appearance (lexicographic order). - _collect_parameters((T, Callable[P, T])) == (T, P) + For example:: + + assert _collect_parameters((T, Callable[P, T])) == (T, P) """ parameters = [] for t in args: @@ -283,6 +285,7 @@ def _collect_parameters(args): def _check_generic(cls, parameters, elen): """Check correct count for parameters of a generic cls (internal helper). + This gives a nice error message in case of count mismatch. """ if not elen: @@ -317,8 +320,9 @@ def _deduplicate(params): def _remove_dups_flatten(parameters): - """An internal helper for Union creation and substitution: flatten Unions - among parameters, then remove duplicates. + """Internal helper for Union creation and substitution. + + Flatten Unions among parameters, then remove duplicates. """ # Flatten out Union[Union[...], ...]. params = [] @@ -332,7 +336,7 @@ def _remove_dups_flatten(parameters): def _flatten_literal_params(parameters): - """An internal helper for Literal creation: flatten Literals among parameters""" + """Internal helper for Literal creation: flatten Literals among parameters.""" params = [] for p in parameters: if isinstance(p, _LiteralGenericAlias): @@ -377,6 +381,7 @@ def inner(*args, **kwds): def _eval_type(t, globalns, localns, recursive_guard=frozenset()): """Evaluate all forward references in the given type t. + For use of globalns and localns see the docstring for get_type_hints(). recursive_guard is used to prevent infinite recursion with a recursive ForwardRef. @@ -409,7 +414,7 @@ def _eval_type(t, globalns, localns, recursive_guard=frozenset()): class _Final: - """Mixin to prohibit subclassing""" + """Mixin to prohibit subclassing.""" __slots__ = ('__weakref__',) @@ -419,6 +424,7 @@ def __init_subclass__(cls, /, *args, **kwds): class _Immutable: """Mixin to indicate that object should not be copied.""" + __slots__ = () def __copy__(self): @@ -431,8 +437,10 @@ def __deepcopy__(self, memo): class _NotIterable: """Mixin to prevent iteration, without being compatible with Iterable. - That is, we could do: + That is, we could do:: + def __iter__(self): raise TypeError() + But this would make users of this mixin duck type-compatible with collections.abc.Iterable - isinstance(foo, Iterable) would be True. @@ -519,6 +527,7 @@ class Any(metaclass=_AnyMeta): static type checkers. At runtime, Any should not be used with instance checks. """ + def __new__(cls, *args, **kwargs): if cls is Any: raise TypeError("Any cannot be instantiated") @@ -528,18 +537,18 @@ def __new__(cls, *args, **kwargs): @_SpecialForm def NoReturn(self, parameters): """Special type indicating functions that never return. + Example:: - from typing import NoReturn + from typing import NoReturn - def stop() -> NoReturn: - raise Exception('no way') + def stop() -> NoReturn: + raise Exception('no way') NoReturn can also be used as a bottom type, a type that has no values. Starting in Python 3.11, the Never type should be used for this concept instead. Type checkers should treat the two equivalently. - """ raise TypeError(f"{self} is not subscriptable") @@ -567,7 +576,6 @@ def int_or_str(arg: int | str) -> None: print("It's a str") case _: never_call_me(arg) # ok, arg is of type Never - """ raise TypeError(f"{self} is not subscriptable") @@ -578,12 +586,12 @@ def Self(self, parameters): Example:: - from typing import Self + from typing import Self - class Foo: - def return_self(self) -> Self: - ... - return self + class Foo: + def return_self(self) -> Self: + ... + return self This is especially useful for: - classmethods that are used as alternative constructors @@ -615,7 +623,6 @@ def caller(arbitrary_string: str, literal_string: LiteralString) -> None: Only string literals and other LiteralStrings are compatible with LiteralString. This provides a tool to help prevent security issues such as SQL injection. - """ raise TypeError(f"{self} is not subscriptable") @@ -628,9 +635,9 @@ def ClassVar(self, parameters): attribute is intended to be used as a class variable and should not be set on instances of that class. Usage:: - class Starship: - stats: ClassVar[Dict[str, int]] = {} # class variable - damage: int = 10 # instance variable + class Starship: + stats: ClassVar[Dict[str, int]] = {} # class variable + damage: int = 10 # instance variable ClassVar accepts only types and cannot be further subscribed. @@ -645,16 +652,17 @@ def Final(self, parameters): """Special typing construct to indicate final names to type checkers. A final name cannot be re-assigned or overridden in a subclass. - For example: - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker + For example:: - class Connection: - TIMEOUT: Final[int] = 10 + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker + class Connection: + TIMEOUT: Final[int] = 10 + + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker There is no runtime checking of these properties. """ @@ -665,25 +673,29 @@ class FastConnector(Connection): def Union(self, parameters): """Union type; Union[X, Y] means either X or Y. - To define a union, use e.g. Union[int, str]. Details: + On Python 3.10 and higher, the | operator + can also be used to denote unions; + X | Y means the same thing to the type checker as Union[X, Y]. + + To define a union, use e.g. Union[int, str]. Details: - The arguments must be types and there must be at least one. - None as an argument is a special case and is replaced by type(None). - Unions of unions are flattened, e.g.:: - Union[Union[int, str], float] == Union[int, str, float] + assert Union[Union[int, str], float] == Union[int, str, float] - Unions of a single argument vanish, e.g.:: - Union[int] == int # The constructor actually returns int + assert Union[int] == int # The constructor actually returns int - Redundant arguments are skipped, e.g.:: - Union[int, str, int] == Union[int, str] + assert Union[int, str, int] == Union[int, str] - When comparing unions, the argument order is ignored, e.g.:: - Union[int, str] == Union[str, int] + assert Union[int, str] == Union[str, int] - You cannot subclass or instantiate a union. - You can use Optional[X] as a shorthand for Union[X, None]. @@ -706,16 +718,13 @@ def _make_union(left, right): TypeVar.__or__ calls this instead of returning types.UnionType because we want to allow unions between TypeVars and strings - (forward references.) + (forward references). """ return Union[left, right] @_SpecialForm def Optional(self, parameters): - """Optional type. - - Optional[X] is equivalent to Union[X, None]. - """ + """Optional[X] is equivalent to Union[X, None].""" arg = _type_check(parameters, f"{self} requires a single type.") return Union[arg, type(None)] @@ -726,17 +735,17 @@ def Literal(self, *parameters): This form can be used to indicate to type checkers that the corresponding variable or function parameter has a value equivalent to the provided - literal (or one of several literals): + literal (or one of several literals):: - def validate_simple(data: Any) -> Literal[True]: # always returns True - ... + def validate_simple(data: Any) -> Literal[True]: # always returns True + ... - MODE = Literal['r', 'rb', 'w', 'wb'] - def open_helper(file: str, mode: MODE) -> str: - ... + MODE = Literal['r', 'rb', 'w', 'wb'] + def open_helper(file: str, mode: MODE) -> str: + ... - open_helper('/some/path', 'r') # Passes type check - open_helper('/other/path', 'typo') # Error in type checker + open_helper('/some/path', 'r') # Passes type check + open_helper('/other/path', 'typo') # Error in type checker Literal[...] cannot be subclassed. At runtime, an arbitrary value is allowed as type argument to Literal[...], but type checkers may @@ -756,11 +765,11 @@ def open_helper(file: str, mode: MODE) -> str: @_SpecialForm def TypeAlias(self, parameters): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. + """Special form for marking type aliases. - For example:: + Use TypeAlias to indicate that an assignment should + be recognized as a proper type alias definition by type + checkers. For example:: Predicate: TypeAlias = Callable[..., bool] @@ -771,13 +780,15 @@ def TypeAlias(self, parameters): @_SpecialForm def Concatenate(self, parameters): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. + """Special form for annotating higher-order functions. + + ``Concatenate`` can be sed in conjunction with ``ParamSpec`` and + ``Callable`` to represent a higher order function which adds, removes or + transforms the parameters of a callable. For example:: - Callable[Concatenate[int, P], int] + Callable[Concatenate[int, P], int] See PEP 612 for detailed information. """ @@ -795,7 +806,9 @@ def Concatenate(self, parameters): @_SpecialForm def TypeGuard(self, parameters): - """Special typing form used to annotate the return type of a user-defined + """Special typing construct for marking user-defined type guard functions. + + ``TypeGuard`` can be used to annotate the return type of a user-defined type guard function. ``TypeGuard`` only accepts a single type argument. At runtime, functions marked this way should return a boolean. @@ -818,14 +831,14 @@ def TypeGuard(self, parameters): For example:: - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower form of ``TypeA`` (it can even be a wider form) and this may lead to @@ -1102,14 +1115,15 @@ def _is_dunder(attr): return attr.startswith('__') and attr.endswith('__') class _BaseGenericAlias(_Final, _root=True): - """The central part of internal API. + """The central part of the internal API. This represents a generic version of type 'origin' with type arguments 'params'. There are two kind of these aliases: user defined and special. The special ones are wrappers around builtin collections and ABCs in collections.abc. These must - have 'name' always set. If 'inst' is False, then the alias can't be instantiated, + have 'name' always set. If 'inst' is False, then the alias can't be instantiated; this is used by e.g. typing.List and typing.Dict. """ + def __init__(self, origin, *, inst=True, name=None): self._inst = inst self._name = name @@ -1188,8 +1202,7 @@ class _GenericAlias(_BaseGenericAlias, _root=True): # * Note that native container types, e.g. `tuple`, `list`, use # `types.GenericAlias` instead. # * Parameterized classes: - # T = TypeVar('T') - # class C(Generic[T]): pass + # class C[T]: pass # # C[int] is a _GenericAlias # * `Callable` aliases, generic `Callable` aliases, and # parameterized `Callable` aliases: @@ -1562,7 +1575,6 @@ def _value_and_type_iter(parameters): class _LiteralGenericAlias(_GenericAlias, _root=True): - def __eq__(self, other): if not isinstance(other, _LiteralGenericAlias): return NotImplemented @@ -1588,35 +1600,40 @@ def Unpack(self, parameters): The type unpack operator takes the child types from some container type, such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For - example: + example:: - # For some generic class `Foo`: - Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] + # For some generic class `Foo`: + Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] - Ts = TypeVarTuple('Ts') - # Specifies that `Bar` is generic in an arbitrary number of types. - # (Think of `Ts` as a tuple of an arbitrary number of individual - # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the - # `Generic[]`.) - class Bar(Generic[Unpack[Ts]]): ... - Bar[int] # Valid - Bar[int, str] # Also valid + Ts = TypeVarTuple('Ts') + # Specifies that `Bar` is generic in an arbitrary number of types. + # (Think of `Ts` as a tuple of an arbitrary number of individual + # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the + # `Generic[]`.) + class Bar(Generic[Unpack[Ts]]): ... + Bar[int] # Valid + Bar[int, str] # Also valid - From Python 3.11, this can also be done using the `*` operator: + From Python 3.11, this can also be done using the `*` operator:: Foo[*tuple[int, str]] class Bar(Generic[*Ts]): ... + And from Python 3.12, it can be done using built-in syntax for generics:: + + Foo[*tuple[int, str]] + class Bar[*Ts]: ... + The operator can also be used along with a `TypedDict` to annotate - `**kwargs` in a function signature. For instance: + `**kwargs` in a function signature. For instance:: - class Movie(TypedDict): - name: str - year: int + class Movie(TypedDict): + name: str + year: int - # This function expects two keyword arguments - *name* of type `str` and - # *year* of type `int`. - def foo(**kwargs: Unpack[Movie]): ... + # This function expects two keyword arguments - *name* of type `str` and + # *year* of type `int`. + def foo(**kwargs: Unpack[Movie]): ... Note that there is only some runtime checking of this operator. Not everything the runtime allows may be accepted by static type checkers. @@ -1628,7 +1645,6 @@ def foo(**kwargs: Unpack[Movie]): ... class _UnpackGenericAlias(_GenericAlias, _root=True): - def __repr__(self): # `Unpack` only takes one argument, so __args__ should contain only # a single item. @@ -1886,10 +1902,11 @@ def func(x: Proto) -> int: only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:: - class GenProto(Protocol[T]): + class GenProto[T](Protocol): def meth(self) -> T: ... """ + __slots__ = () _is_protocol = True _is_runtime_protocol = False @@ -1940,12 +1957,13 @@ class _AnnotatedAlias(_NotIterable, _GenericAlias, _root=True): """Runtime representation of an annotated type. At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' - with extra annotations. The alias behaves like a normal typing alias, - instantiating is the same as instantiating the underlying type, binding + with extra annotations. The alias behaves like a normal typing alias. + Instantiating is the same as instantiating the underlying type; binding it to types is also the same. The metadata itself is stored in a '__metadata__' attribute as a tuple. """ + def __init__(self, origin, metadata): if isinstance(origin, _AnnotatedAlias): metadata = origin.__metadata__ + metadata @@ -1988,7 +2006,7 @@ def __mro_entries__(self, bases): class Annotated: - """Add context specific metadata to a type. + """Add context-specific metadata to a type. Example: Annotated[int, runtime_check.Unsigned] indicates to the hypothetical runtime_check module that this type is an unsigned int. @@ -2002,24 +2020,24 @@ class Annotated: - It's an error to call `Annotated` with less than two arguments. - Access the metadata via the ``__metadata__`` attribute:: - Annotated[int, '$'].__metadata__ == ('$',) + assert Annotated[int, '$'].__metadata__ == ('$',) - Nested Annotated are flattened:: - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + assert Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - Instantiating an annotated type is equivalent to instantiating the underlying type:: - Annotated[C, Ann1](5) == C(5) + assert Annotated[C, Ann1](5) == C(5) - Annotated can be used as a generic type alias:: Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] + assert Optimized[int] == Annotated[int, runtime.Optimize()] OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + assert OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - Annotated cannot be used with an unpacked TypeVarTuple:: @@ -2065,6 +2083,7 @@ def runtime_checkable(cls): Raise TypeError if applied to a non-protocol class. This allows a simple-minded structural check very similar to one trick ponies in collections.abc such as Iterable. + For example:: @runtime_checkable @@ -2106,7 +2125,6 @@ def assert_type(val, typ, /): def greet(name: str) -> None: assert_type(name, str) # ok assert_type(name, int) # type checker error - """ return val @@ -2147,7 +2165,6 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): - If two dict arguments are passed, they specify globals and locals, respectively. """ - if getattr(obj, '__no_type_check__', None): return {} # Classes require a special treatment. @@ -2217,8 +2234,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False): def _strip_annotations(t): - """Strips the annotations from a given type. - """ + """Strip the annotations from a given type.""" if isinstance(t, _AnnotatedAlias): return _strip_annotations(t.__origin__) if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): @@ -2246,16 +2262,16 @@ def get_origin(tp): """Get the unsubscripted version of a type. This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar - and Annotated. Return None for unsupported types. Examples:: - - get_origin(Literal[42]) is Literal - get_origin(int) is None - get_origin(ClassVar[int]) is ClassVar - get_origin(Generic) is Generic - get_origin(Generic[T]) is Generic - get_origin(Union[T, int]) is Union - get_origin(List[Tuple[T, T]][int]) == list - get_origin(P.args) is P + Annotated, and others. Return None for unsupported types. Examples:: + + assert get_origin(Literal[42]) is Literal + assert get_origin(int) is None + assert get_origin(ClassVar[int]) is ClassVar + assert get_origin(Generic) is Generic + assert get_origin(Generic[T]) is Generic + assert get_origin(Union[T, int]) is Union + assert get_origin(List[Tuple[T, T]][int]) is list + assert get_origin(P.args) is P """ if isinstance(tp, _AnnotatedAlias): return Annotated @@ -2273,12 +2289,14 @@ def get_args(tp): """Get type arguments with all substitutions performed. For unions, basic simplifications used by Union constructor are performed. + Examples:: - get_args(Dict[str, int]) == (str, int) - get_args(int) == () - get_args(Union[int, Union[T, int], str][int]) == (int, str) - get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) - get_args(Callable[[], T][int]) == ([], int) + + assert get_args(Dict[str, int]) == (str, int) + assert get_args(int) == () + assert get_args(Union[int, Union[T, int], str][int]) == (int, str) + assert get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + assert get_args(Callable[[], T][int]) == ([], int) """ if isinstance(tp, _AnnotatedAlias): return (tp.__origin__,) + tp.__metadata__ @@ -2293,14 +2311,15 @@ def get_args(tp): def is_typeddict(tp): - """Check if an annotation is a TypedDict class + """Check if an annotation is a TypedDict class. For example:: + class Film(TypedDict): title: str year: int - is_typeddict(Film) # => True + is_typeddict(Film) # => True is_typeddict(Union[list, str]) # => False """ return isinstance(tp, _TypedDictMeta) @@ -2327,7 +2346,6 @@ def int_or_str(arg: int | str) -> None: reachable, it will emit an error. At runtime, this throws an exception when called. - """ value = repr(arg) if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH: @@ -2377,7 +2395,6 @@ def no_type_check_decorator(decorator): This wraps the decorator with something that wraps the decorated function in @no_type_check. """ - @functools.wraps(decorator) def wrapped_decorator(*args, **kwds): func = decorator(*args, **kwds) @@ -2404,27 +2421,27 @@ def overload(func): """Decorator for overloaded functions/methods. In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. For example: + function in a row, each decorated with @overload. For example:: - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... In a non-stub file (i.e. a regular .py file), do the same but follow it with an implementation. The implementation should *not* - be decorated with @overload. For example: + be decorated with @overload. For example:: - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - def utf8(value): - # implementation goes here + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + ... # implementation goes here The overloads for a function can be retrieved at runtime using the get_overloads() function. @@ -2457,29 +2474,30 @@ def clear_overloads(): def final(f): - """A decorator to indicate final methods and final classes. + """Decorator to indicate final methods and final classes. Use this decorator to indicate to type checkers that the decorated method cannot be overridden, and decorated class cannot be subclassed. - For example: - - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker + + For example:: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker ... - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... There is no runtime checking of these properties. The decorator - sets the ``__final__`` attribute to ``True`` on the decorated object - to allow runtime introspection. + attempts to set the ``__final__`` attribute to ``True`` on the decorated + object to allow runtime introspection. """ try: f.__final__ = True @@ -2526,13 +2544,15 @@ class Other(Leaf): # Error reported by type checker Collection = _alias(collections.abc.Collection, 1) Callable = _CallableType(collections.abc.Callable, 2) Callable.__doc__ = \ - """Callable type; Callable[[int], str] is a function of (int) -> str. + """Deprecated alias to collections.abc.Callable. + Callable[[int], str] signifies a function of (int) -> str. The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types or ellipsis; the return type must be a single type. + values: the argument list and the return type. + The argument list must be a list of types, a ParamSpec or ellipsis. + The return type must be a single type. - There is no syntax to indicate optional or keyword arguments, + There is no syntax to indicate optional or keyword arguments; such function types are rarely used as callback types. """ AbstractSet = _alias(collections.abc.Set, 1, name='AbstractSet') @@ -2548,7 +2568,9 @@ class Other(Leaf): # Error reported by type checker # Tuple accepts variable number of parameters. Tuple = _TupleType(tuple, -1, inst=False, name='Tuple') Tuple.__doc__ = \ - """Tuple type; Tuple[X, Y] is the cross-product type of X and Y. + """Deprecated alias to builtins.tuple. + + Tuple[X, Y] is the cross-product type of X and Y. Example: Tuple[T1, T2] is a tuple of two elements corresponding to type variables T1 and T2. Tuple[int, float, str] is a tuple @@ -2575,25 +2597,25 @@ class Other(Leaf): # Error reported by type checker AsyncGenerator = _alias(collections.abc.AsyncGenerator, 2) Type = _alias(type, 1, inst=False, name='Type') Type.__doc__ = \ - """A special construct usable to annotate class objects. + """Deprecated alias to builtins.type. + builtins.type or typing.Type can be used to annotate class objects. For example, suppose we have the following classes:: - class User: ... # Abstract base for User classes - class BasicUser(User): ... - class ProUser(User): ... - class TeamUser(User): ... + class User: ... # Abstract base for User classes + class BasicUser(User): ... + class ProUser(User): ... + class TeamUser(User): ... And a function that takes a class argument that's a subclass of User and returns an instance of the corresponding class:: - U = TypeVar('U', bound=User) - def new_user(user_class: Type[U]) -> U: - user = user_class() - # (Here we could write the user object to a database) - return user + def new_user[U](user_class: Type[U]) -> U: + user = user_class() + # (Here we could write the user object to a database) + return user - joe = new_user(BasicUser) + joe = new_user(BasicUser) At this point the type checker knows that joe has type BasicUser. """ @@ -2602,6 +2624,7 @@ def new_user(user_class: Type[U]) -> U: @runtime_checkable class SupportsInt(Protocol): """An ABC with one abstract method __int__.""" + __slots__ = () @abstractmethod @@ -2612,6 +2635,7 @@ def __int__(self) -> int: @runtime_checkable class SupportsFloat(Protocol): """An ABC with one abstract method __float__.""" + __slots__ = () @abstractmethod @@ -2622,6 +2646,7 @@ def __float__(self) -> float: @runtime_checkable class SupportsComplex(Protocol): """An ABC with one abstract method __complex__.""" + __slots__ = () @abstractmethod @@ -2632,6 +2657,7 @@ def __complex__(self) -> complex: @runtime_checkable class SupportsBytes(Protocol): """An ABC with one abstract method __bytes__.""" + __slots__ = () @abstractmethod @@ -2642,6 +2668,7 @@ def __bytes__(self) -> bytes: @runtime_checkable class SupportsIndex(Protocol): """An ABC with one abstract method __index__.""" + __slots__ = () @abstractmethod @@ -2652,6 +2679,7 @@ def __index__(self) -> int: @runtime_checkable class SupportsAbs[T](Protocol): """An ABC with one abstract method __abs__ that is covariant in its return type.""" + __slots__ = () @abstractmethod @@ -2662,6 +2690,7 @@ def __abs__(self) -> T: @runtime_checkable class SupportsRound[T](Protocol): """An ABC with one abstract method __round__ that is covariant in its return type.""" + __slots__ = () @abstractmethod @@ -2688,7 +2717,6 @@ def _make_nmtuple(name, types, module, defaults = ()): class NamedTupleMeta(type): - def __new__(cls, typename, bases, ns): assert _NamedTuple in bases for base in bases: @@ -2740,10 +2768,9 @@ class Employee(NamedTuple): The resulting class has an extra __annotations__ attribute, giving a dict that maps field names to types. (The field names are also in the _fields attribute, which is part of the namedtuple API.) - Alternative equivalent keyword syntax is also accepted:: - - Employee = NamedTuple('Employee', name=str, id=int) + An alternative equivalent functional syntax is also accepted:: + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) """ if fields is None: fields = kwargs.items() @@ -2765,7 +2792,7 @@ def _namedtuple_mro_entries(bases): class _TypedDictMeta(type): def __new__(cls, name, bases, ns, total=True): - """Create new typed dict class object. + """Create a new typed dict class object. This method is called when TypedDict is subclassed, or when TypedDict is instantiated. This way @@ -2839,10 +2866,11 @@ def __subclasscheck__(cls, other): def TypedDict(typename, fields=None, /, *, total=True, **kwargs): """A simple typed namespace. At runtime it is equivalent to a plain dict. - TypedDict creates a dictionary type that expects all of its + TypedDict creates a dictionary type such that a type checker will expect all instances to have a certain set of keys, where each key is associated with a value of a consistent type. This expectation - is not checked at runtime but is only enforced by type checkers. + is not checked at runtime. + Usage:: class Point2D(TypedDict): @@ -2862,20 +2890,25 @@ class Point2D(TypedDict): Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) By default, all keys must be present in a TypedDict. It is possible - to override this by specifying totality. - Usage:: + to override this by specifying totality:: - class point2D(TypedDict, total=False): + class Point2D(TypedDict, total=False): x: int y: int - This means that a point2D TypedDict can have any of the keys omitted.A type + This means that a Point2D TypedDict can have any of the keys omitted. A type checker is only expected to support a literal False or True as the value of the total argument. True is the default, and makes all items defined in the class body be required. - The class syntax is only supported in Python 3.6+, while the other - syntax form works for Python 2.7 and 3.2+ + The Required and NotRequired special forms can also be used to mark + individual keys as being required or not required:: + + class Point2D(TypedDict): + x: int # the "x" key must always be present (Required is the default) + y: NotRequired[int] # the "y" key can be omitted + + See PEP 655 for more details on Required and NotRequired. """ if fields is None: fields = kwargs @@ -2907,8 +2940,9 @@ class body be required. @_SpecialForm def Required(self, parameters): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: + """Special typing construct to mark a TypedDict key as required. + + This is mainly useful for total=False TypedDicts. For example:: class Movie(TypedDict, total=False): title: Required[str] @@ -2928,8 +2962,9 @@ class Movie(TypedDict, total=False): @_SpecialForm def NotRequired(self, parameters): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: + """Special typing construct to mark a TypedDict key as potentially missing. + + For example:: class Movie(TypedDict): title: str @@ -2945,8 +2980,9 @@ class Movie(TypedDict): class NewType: - """NewType creates simple unique types with almost zero - runtime overhead. NewType(name, tp) is considered a subtype of tp + """NewType creates simple unique types with almost zero runtime overhead. + + NewType(name, tp) is considered a subtype of tp by static type checkers. At runtime, NewType(name, tp) returns a dummy callable that simply returns its argument. Usage:: @@ -3208,12 +3244,11 @@ def reveal_type[T](obj: T, /) -> T: x: int = 1 reveal_type(x) - Running a static type checker (e.g., ``mypy``) on this example + Running a static type checker (e.g., mypy) on this example will produce output similar to 'Revealed type is "builtins.int"'. At runtime, the function prints the runtime type of the argument and returns it unchanged. - """ print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr) return obj @@ -3233,15 +3268,14 @@ def dataclass_transform( field_specifiers: tuple[type[Any] | Callable[..., Any], ...] = (), **kwargs: Any, ) -> _IdentityCallable: - """Decorator that marks a function, class, or metaclass as providing - dataclass-like behavior. + """Decorator to mark an object as providing dataclass-like behaviour. - Example usage with a decorator function: + The decorator can be applied to a function, class, or metaclass. - T = TypeVar("T") + Example usage with a decorator function:: @dataclass_transform() - def create_model(cls: type[T]) -> type[T]: + def create_model[T](cls: type[T]) -> type[T]: ... return cls @@ -3250,7 +3284,7 @@ class CustomerModel: id: int name: str - On a base class: + On a base class:: @dataclass_transform() class ModelBase: ... @@ -3259,7 +3293,7 @@ class CustomerModel(ModelBase): id: int name: str - On a metaclass: + On a metaclass:: @dataclass_transform() class ModelMeta(type): ... @@ -3315,7 +3349,7 @@ def decorator(cls_or_fn): def override[F: _Func](method: F, /) -> F: """Indicate that a method is intended to override a method in a base class. - Usage: + Usage:: class Base: def method(self) -> None: ... @@ -3331,12 +3365,11 @@ def method(self) -> None: base class. This helps prevent bugs that may occur when a base class is changed without an equivalent change to a child class. - There is no runtime checking of this property. The decorator sets the - ``__override__`` attribute to ``True`` on the decorated object to allow - runtime introspection. + There is no runtime checking of this property. The decorator attempts to + set the ``__override__`` attribute to ``True`` on the decorated object to + allow runtime introspection. See PEP 698 for details. - """ try: method.__override__ = True From dbc179e7c3c668537e7a61f36b8522545af08b56 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 5 Jun 2023 08:09:11 -0700 Subject: [PATCH 0121/1206] [3.12] Clarify that error messages are better with PEP 701 (GH-105150) (#105169) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Pablo Galindo Salgado Co-authored-by: Marta Gómez Macías --- Doc/whatsnew/3.12.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3e8b866e6bfb5f..a4c571e563687d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -203,6 +203,31 @@ same quote as the containing f-string. Let's cover these in detail: See :pep:`701` for more details. +As a positive side-effect of how this feature has been implemented (by parsing f-strings +with the PEG parser (see :pep:`617`), now error messages for f-strings are more precise +and include the exact location of the error. For example, in Python 3.11, the following +f-string raises a :exc:`SyntaxError`: + +.. code-block:: python + + >>> my_string = f"{x z y}" + f"{1 + 1}" + File "", line 1 + (x z y) + ^^^ + SyntaxError: f-string: invalid syntax. Perhaps you forgot a comma? + +but the error message doesn't include the exact location of the error withing the line and +also has the expression artificially surrounded by parentheses. In Python 3.12, as f-strings +are parsed with the PEG parser, error messages can be more precise and show the entire line: + +.. code-block:: python + + >>> my_string = f"{x z y}" + f"{1 + 1}" + File "", line 1 + my_string = f"{x z y}" + f"{1 + 1}" + ^^^ + SyntaxError: invalid syntax. Perhaps you forgot a comma? + (Contributed by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou, Cristián Maureira-Fredes and Marta Gómez in :gh:`102856`. PEP written by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou and Marta Gómez). From 0c51318c5863060195facc69bcaa90e574b7f899 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 5 Jun 2023 18:28:03 +0300 Subject: [PATCH 0122/1206] [3.12] What's New in 3.12: List 'Improved Modules' alphabetically (GH-105315) (#105321) --- Doc/whatsnew/3.12.rst | 214 +++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a4c571e563687d..18c4ae049ab7f8 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -74,10 +74,10 @@ New typing features: * :pep:`688`: Making the buffer protocol accessible in Python -* :ref:`whatsnew312-pep695` - * :ref:`whatsnew312-pep692` +* :ref:`whatsnew312-pep695` + * :pep:`698`: Override Decorator for Static Typing Important deprecations, removals or restrictions: @@ -179,7 +179,7 @@ same quote as the containing f-string. Let's cover these in detail: must be defined in a single line even if outside f-strings expressions could span multiple lines (like literal lists being defined over multiple lines), making them harder to read. In Python 3.12 you can now define expressions - spaning multiple lines and include comments on them: + spanning multiple lines and include comments on them: >>> f"This is the playlist: {", ".join([ ... 'Take me back to Eden', # My, my, those eyes like fire @@ -216,7 +216,7 @@ f-string raises a :exc:`SyntaxError`: ^^^ SyntaxError: f-string: invalid syntax. Perhaps you forgot a comma? -but the error message doesn't include the exact location of the error withing the line and +but the error message doesn't include the exact location of the error within the line and also has the expression artificially surrounded by parentheses. In Python 3.12, as f-strings are parsed with the PEG parser, error messages can be more precise and show the entire line: @@ -553,46 +553,6 @@ csv provide finer grained control of ``None`` and empty strings by :class:`~csv.writer` objects. -inspect -------- - -* Add :func:`inspect.markcoroutinefunction` to mark sync functions that return - a :term:`coroutine` for use with :func:`inspect.iscoroutinefunction`. - (Contributed Carlton Gibson in :gh:`99247`.) - -* Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals` - for determining the current state of asynchronous generators. - (Contributed by Thomas Krennwallner in :issue:`35759`.) - -* The performance of :func:`inspect.getattr_static` has been considerably - improved. Most calls to the function should be at least 2x faster than they - were in Python 3.11, and some may be 6x faster or more. (Contributed by Alex - Waygood in :gh:`103193`.) - -pathlib -------- - -* Add support for subclassing :class:`pathlib.PurePath` and - :class:`~pathlib.Path`, plus their Posix- and Windows-specific variants. - Subclasses may override the :meth:`~pathlib.PurePath.with_segments` method - to pass information between path instances. - -* Add :meth:`~pathlib.Path.walk` for walking the directory trees and generating - all file or directory names within them, similar to :func:`os.walk`. - (Contributed by Stanislav Zmiev in :gh:`90385`.) - -* Add *walk_up* optional parameter to :meth:`pathlib.PurePath.relative_to` - to allow the insertion of ``..`` entries in the result; this behavior is - more consistent with :func:`os.path.relpath`. - (Contributed by Domenico Ragusa in :issue:`40358`.) - -* Add :meth:`pathlib.Path.is_junction` as a proxy to :func:`os.path.isjunction`. - (Contributed by Charles Machalow in :gh:`99547`.) - -* Add *case_sensitive* optional parameter to :meth:`pathlib.Path.glob`, - :meth:`pathlib.Path.rglob` and :meth:`pathlib.PurePath.match` for matching - the path's case sensitivity, allowing for more precise control over the matching process. - dis --- @@ -610,6 +570,22 @@ fractions * Objects of type :class:`fractions.Fraction` now support float-style formatting. (Contributed by Mark Dickinson in :gh:`100161`.) +inspect +------- + +* Add :func:`inspect.markcoroutinefunction` to mark sync functions that return + a :term:`coroutine` for use with :func:`inspect.iscoroutinefunction`. + (Contributed Carlton Gibson in :gh:`99247`.) + +* Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals` + for determining the current state of asynchronous generators. + (Contributed by Thomas Krennwallner in :issue:`35759`.) + +* The performance of :func:`inspect.getattr_static` has been considerably + improved. Most calls to the function should be at least 2x faster than they + were in Python 3.11, and some may be 6x faster or more. (Contributed by Alex + Waygood in :gh:`103193`.) + itertools --------- @@ -669,6 +645,30 @@ os.path * Add :func:`os.path.splitroot` to split a path into a triad ``(drive, root, tail)``. (Contributed by Barney Gale in :gh:`101000`.) +pathlib +------- + +* Add support for subclassing :class:`pathlib.PurePath` and + :class:`~pathlib.Path`, plus their Posix- and Windows-specific variants. + Subclasses may override the :meth:`~pathlib.PurePath.with_segments` method + to pass information between path instances. + +* Add :meth:`~pathlib.Path.walk` for walking the directory trees and generating + all file or directory names within them, similar to :func:`os.walk`. + (Contributed by Stanislav Zmiev in :gh:`90385`.) + +* Add *walk_up* optional parameter to :meth:`pathlib.PurePath.relative_to` + to allow the insertion of ``..`` entries in the result; this behavior is + more consistent with :func:`os.path.relpath`. + (Contributed by Domenico Ragusa in :issue:`40358`.) + +* Add :meth:`pathlib.Path.is_junction` as a proxy to :func:`os.path.isjunction`. + (Contributed by Charles Machalow in :gh:`99547`.) + +* Add *case_sensitive* optional parameter to :meth:`pathlib.Path.glob`, + :meth:`pathlib.Path.rglob` and :meth:`pathlib.PurePath.match` for matching + the path's case sensitivity, allowing for more precise control over the matching process. + pdb --- @@ -746,6 +746,38 @@ statistics for computing the Spearman correlation of ranked data. (Contributed by Raymond Hettinger in :gh:`95861`.) +sys +--- + +* Add :func:`sys.activate_stack_trampoline` and + :func:`sys.deactivate_stack_trampoline` for activating and deactivating + stack profiler trampolines, + and :func:`sys.is_stack_trampoline_active` for querying if stack profiler + trampolines are active. + (Contributed by Pablo Galindo and Christian Heimes + with contributions from Gregory P. Smith [Google] and Mark Shannon + in :gh:`96123`.) + +* Add :data:`sys.last_exc` which holds the last unhandled exception that + was raised (for post-mortem debugging use cases). Deprecate the + three fields that have the same information in its legacy form: + :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`. + (Contributed by Irit Katriel in :gh:`102778`.) + +* :func:`sys._current_exceptions` now returns a mapping from thread-id to an + exception instance, rather than to a ``(typ, exc, tb)`` tuple. + (Contributed by Irit Katriel in :gh:`103176`.) + +tempfile +-------- + +* The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter + *delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.) +* :func:`tempfile.mkdtemp` now always returns an absolute path, even if the + argument provided to the *dir* parameter is a relative path. + +.. _whatsnew-typing-py312: + threading --------- @@ -780,49 +812,6 @@ types :ref:`user-defined-generics` when subclassed. (Contributed by James Hilton-Balfe and Alex Waygood in :gh:`101827`.) -unicodedata ------------ - -* The Unicode database has been updated to version 15.0.0. (Contributed by - Benjamin Peterson in :gh:`96734`). - -unittest --------- - -Added ``--durations`` command line option, showing the N slowest test cases:: - - python3 -m unittest --durations=3 lib.tests.test_threading - ..... - Slowest test durations - ---------------------------------------------------------------------- - 1.210s test_timeout (Lib.test.test_threading.BarrierTests) - 1.003s test_default_timeout (Lib.test.test_threading.BarrierTests) - 0.518s test_timeout (Lib.test.test_threading.EventTests) - - (0.000 durations hidden. Use -v to show these durations.) - ---------------------------------------------------------------------- - Ran 158 tests in 9.869s - - OK (skipped=3) - -(Contributed by Giampaolo Rodola in :issue:`4080`) - -uuid ----- - -* Add a :ref:`command-line interface `. - (Contributed by Adam Chhina in :gh:`88597`.) - -tempfile --------- - -* The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter - *delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.) -* :func:`tempfile.mkdtemp` now always returns an absolute path, even if the - argument provided to the *dir* parameter is a relative path. - -.. _whatsnew-typing-py312: - typing ------ @@ -877,27 +866,38 @@ typing * Add ``frozen_default`` parameter to :func:`typing.dataclass_transform`. (Contributed by Erik De Bonte in :gh:`99957`.) -sys ---- +unicodedata +----------- -* Add :func:`sys.activate_stack_trampoline` and - :func:`sys.deactivate_stack_trampoline` for activating and deactivating - stack profiler trampolines, - and :func:`sys.is_stack_trampoline_active` for querying if stack profiler - trampolines are active. - (Contributed by Pablo Galindo and Christian Heimes - with contributions from Gregory P. Smith [Google] and Mark Shannon - in :gh:`96123`.) +* The Unicode database has been updated to version 15.0.0. (Contributed by + Benjamin Peterson in :gh:`96734`). -* Add :data:`sys.last_exc` which holds the last unhandled exception that - was raised (for post-mortem debugging use cases). Deprecate the - three fields that have the same information in its legacy form: - :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`. - (Contributed by Irit Katriel in :gh:`102778`.) +unittest +-------- -* :func:`sys._current_exceptions` now returns a mapping from thread-id to an - exception instance, rather than to a ``(typ, exc, tb)`` tuple. - (Contributed by Irit Katriel in :gh:`103176`.) +Added ``--durations`` command line option, showing the N slowest test cases:: + + python3 -m unittest --durations=3 lib.tests.test_threading + ..... + Slowest test durations + ---------------------------------------------------------------------- + 1.210s test_timeout (Lib.test.test_threading.BarrierTests) + 1.003s test_default_timeout (Lib.test.test_threading.BarrierTests) + 0.518s test_timeout (Lib.test.test_threading.EventTests) + + (0.000 durations hidden. Use -v to show these durations.) + ---------------------------------------------------------------------- + Ran 158 tests in 9.869s + + OK (skipped=3) + +(Contributed by Giampaolo Rodola in :issue:`4080`) + +uuid +---- + +* Add a :ref:`command-line interface `. + (Contributed by Adam Chhina in :gh:`88597`.) Optimizations @@ -1486,7 +1486,7 @@ Changes in the Python API 1,13-1,17: FSTRING_MIDDLE ' end' 1,17-1,18: FSTRING_END '"' - Aditionally, there may be some minor behavioral changes as a consecuence of the + Additionally, there may be some minor behavioral changes as a consecuence of the changes required to support :pep:`701`. Some of these changes include: * Some final ``DEDENT`` tokens are now emitted within the bounds of the @@ -1757,7 +1757,7 @@ Porting to Python 3.12 before storing it. (Contributed by Mark Shannon in :gh:`101578`.) * ``_Py_RefTotal`` is no longer authoritative and only kept around - for ABI compabitility. Note that it is an internal global and only + for ABI compatibility. Note that it is an internal global and only available on debug builds. If you happen to be using it then you'll need to start using ``_Py_GetGlobalRefTotal()``. From 05b615345699c9d0dcff0b638b8eb9bd596c0cb7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 5 Jun 2023 09:24:12 -0700 Subject: [PATCH 0123/1206] [3.12] gh-97908: CAPI docs: Remove repeated struct names from member docs (GH-100054) (#105057) And add raw HTML fragments to keep old links working. (cherry picked from commit 1668b41dc477bc9562e4c50ab36a232839b4621b) Co-authored-by: Petr Viktorin --- Doc/c-api/structures.rst | 12 ++++++------ Doc/c-api/type.rst | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index aae1b951804491..7ce3578f250792 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -395,7 +395,7 @@ Accessing attributes of extension types The string should be static, no copy is made of it. - .. c:member:: Py_ssize_t PyMemberDef.offset + .. c:member:: Py_ssize_t offset The offset in bytes that the member is located on the type’s object struct. @@ -625,23 +625,23 @@ Defining Getters and Setters Structure to define property-like access for a type. See also description of the :c:member:`PyTypeObject.tp_getset` slot. - .. c:member:: const char* PyGetSetDef.name + .. c:member:: const char* name attribute name - .. c:member:: getter PyGetSetDef.get + .. c:member:: getter get C function to get the attribute. - .. c:member:: setter PyGetSetDef.set + .. c:member:: setter set Optional C function to set or delete the attribute, if omitted the attribute is readonly. - .. c:member:: const char* PyGetSetDef.doc + .. c:member:: const char* doc optional docstring - .. c:member:: void* PyGetSetDef.closure + .. c:member:: void* closure Optional function pointer, providing additional data for getter and setter. diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index fb38935e003336..89cd74335fd770 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -349,6 +349,15 @@ The following functions and structs are used to create :c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it will be no longer allowed. +.. raw:: html + + + + + + + + .. c:type:: PyType_Spec Structure defining a type's behavior. @@ -410,12 +419,18 @@ The following functions and structs are used to create Each slot ID should be specified at most once. +.. raw:: html + + + + + .. c:type:: PyType_Slot Structure defining optional functionality of a type, containing a slot ID and a value pointer. - .. c:member:: int PyType_Slot.slot + .. c:member:: int slot A slot ID. @@ -459,7 +474,7 @@ The following functions and structs are used to create :c:member:`~PyBufferProcs.bf_releasebuffer` are now available under the limited API. - .. c:member:: void *PyType_Slot.pfunc + .. c:member:: void *pfunc The desired value of the slot. In most cases, this is a pointer to a function. From ab660e9a53090f6b00b33ff0633b0388355f4c4a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 5 Jun 2023 10:02:14 -0700 Subject: [PATCH 0124/1206] [3.12] gh-89412: Add missing attributes (added in 3.10) to traceback module docs (GH-105046) (#105327) (cherry picked from commit a4f72fa39a9d391c7b931ba1906d81da4ae01949) Co-authored-by: Jakub Kuczys --- Doc/library/traceback.rst | 14 ++++++++++++++ Lib/traceback.py | 4 ++-- .../2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 58f47818fcecab..36171a3b5a610d 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -279,6 +279,13 @@ capture data for later printing in a lightweight fashion. For syntax errors - the line number where the error occurred. + .. attribute:: end_lineno + + For syntax errors - the end line number where the error occurred. + Can be ``None`` if not present. + + .. versionadded:: 3.10 + .. attribute:: text For syntax errors - the text where the error occurred. @@ -287,6 +294,13 @@ capture data for later printing in a lightweight fashion. For syntax errors - the offset into the text where the error occurred. + .. attribute:: end_offset + + For syntax errors - the end offset into the text where the error occurred. + Can be ``None`` if not present. + + .. versionadded:: 3.10 + .. attribute:: msg For syntax errors - the compiler error message. diff --git a/Lib/traceback.py b/Lib/traceback.py index 0ea77bfb94612e..21e32040ee9872 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -674,8 +674,8 @@ class TracebackException: occurred. - :attr:`offset` For syntax errors - the offset into the text where the error occurred. - - :attr:`end_offset` For syntax errors - the offset into the text where the - error occurred. Can be `None` if not present. + - :attr:`end_offset` For syntax errors - the end offset into the text where + the error occurred. Can be `None` if not present. - :attr:`msg` For syntax errors - the compiler error message. """ diff --git a/Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst b/Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst new file mode 100644 index 00000000000000..00937e58c98595 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst @@ -0,0 +1,2 @@ +Add missing documentation for the ``end_lineno`` and ``end_offset`` attributes +of the :class:`traceback.TracebackException` class. From 3aa3be4fe3f64ccaf2b6235bd3addeb5c1313002 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 5 Jun 2023 12:44:20 -0700 Subject: [PATCH 0125/1206] [3.12] gh-105324: Fix tokenize module main function for stdin (GH-105325) (#105330) --- Lib/tokenize.py | 3 +-- .../2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 380dc2ab468b57..a07a8bf45891ac 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -490,8 +490,7 @@ def error(message, filename=None, location=None): else: filename = "" tokens = _generate_tokens_from_c_tokenizer( - (x.encode('utf-8') for x in iter(sys.stdin.readline, "") - ), "utf-8", extra_tokens=True) + sys.stdin.readline, extra_tokens=True) # Output the tokenization diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst new file mode 100644 index 00000000000000..17275aed338d0d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst @@ -0,0 +1,2 @@ +Fix the main function of the :mod:`tokenize` module when reading from +``sys.stdin``. Patch by Pablo Galindo From 6f3a4fd4f23f8013cca5abdf03bcc7dd4adf8637 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 6 Jun 2023 12:58:13 +0200 Subject: [PATCH 0126/1206] [3.12] gh-90005: Don't link with libbsd if not needed (#105236) (#105360) The regression was introduced with commit 5b946cada. Restore pre gh-29696 behaviour. --- .../Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst | 1 + configure | 8 ++++++-- configure.ac | 5 ++--- 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst diff --git a/Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst b/Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst new file mode 100644 index 00000000000000..0a23fbf0c0fbdd --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst @@ -0,0 +1 @@ +Fix a regression in :file:`configure` where we could end up unintentionally linking with ``libbsd``. diff --git a/configure b/configure index a4d4996b065798..e89155b5bbef94 100755 --- a/configure +++ b/configure @@ -19278,13 +19278,15 @@ fi printf "%s\n" "$ac_cv_flock_decl" >&6; } if test "x$ac_cv_flock_decl" = xyes then : + + for ac_func in flock +do : ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" if test "x$ac_cv_func_flock" = xyes then : printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h -fi - +else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 printf %s "checking for flock in -lbsd... " >&6; } if test ${ac_cv_lib_bsd_flock+y} @@ -19325,7 +19327,9 @@ then : FCNTL_LIBS="-lbsd" fi +fi +done fi diff --git a/configure.ac b/configure.ac index e0a69583ca834a..dc9359e7c7bdee 100644 --- a/configure.ac +++ b/configure.ac @@ -4936,9 +4936,8 @@ AC_CACHE_CHECK([for flock declaration], [ac_cv_flock_decl], ]) dnl Linking with libbsd may be necessary on AIX for flock function. AS_VAR_IF([ac_cv_flock_decl], [yes], - AC_CHECK_FUNCS([flock]) - AC_CHECK_LIB([bsd], [flock], [FCNTL_LIBS="-lbsd"]) -) + [AC_CHECK_FUNCS([flock], [], + [AC_CHECK_LIB([bsd], [flock], [FCNTL_LIBS="-lbsd"])])]) PY_CHECK_FUNC([getpagesize], [#include ]) From 67b288f8be4989176ffab04c72794e5faf5797a5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 05:47:45 -0700 Subject: [PATCH 0127/1206] [3.12] gh-105259: Ensure we don't show newline characters for trailing NEWLINE tokens (GH-105364) (#105367) --- Lib/test/test_tokenize.py | 2 +- .../2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst | 2 ++ Parser/tokenizer.c | 7 +++++++ Parser/tokenizer.h | 1 + Python/Python-tokenize.c | 10 ++++++---- 5 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index a9a2b7673887c9..5ac17095b185f5 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1870,7 +1870,7 @@ def readline(encoding): TokenInfo(type=NUMBER, string='1', start=(1, 0), end=(1, 1), line='1+1\n'), TokenInfo(type=OP, string='+', start=(1, 1), end=(1, 2), line='1+1\n'), TokenInfo(type=NUMBER, string='1', start=(1, 2), end=(1, 3), line='1+1\n'), - TokenInfo(type=NEWLINE, string='\n', start=(1, 3), end=(1, 4), line='1+1\n'), + TokenInfo(type=NEWLINE, string='', start=(1, 3), end=(1, 4), line='1+1\n'), TokenInfo(type=ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') ] for encoding in ["utf-8", "latin-1", "utf-16"]: diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst new file mode 100644 index 00000000000000..75a63033750826 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst @@ -0,0 +1,2 @@ +Don't include newline character for trailing ``NEWLINE`` tokens emitted in +the :mod:`tokenize` module. Patch by Pablo Galindo diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index fae613e3a18c1d..89594e6974fe04 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -114,6 +114,7 @@ tok_new(void) tok->report_warnings = 1; tok->tok_extra_tokens = 0; tok->comment_newline = 0; + tok->implicit_newline = 0; tok->tok_mode_stack[0] = (tokenizer_mode){.kind =TOK_REGULAR_MODE, .f_string_quote='\0', .f_string_quote_size = 0, .f_string_debug=0}; tok->tok_mode_stack_index = 0; tok->tok_report_warnings = 1; @@ -355,10 +356,12 @@ tok_concatenate_interactive_new_line(struct tok_state *tok, const char *line) { return -1; } strcpy(new_str + current_size, line); + tok->implicit_newline = 0; if (last_char != '\n') { /* Last line does not end in \n, fake one */ new_str[current_size + line_size - 1] = '\n'; new_str[current_size + line_size] = '\0'; + tok->implicit_newline = 1; } tok->interactive_src_start = new_str; tok->interactive_src_end = new_str + current_size + line_size; @@ -1262,11 +1265,13 @@ tok_underflow_file(struct tok_state *tok) { tok->done = E_EOF; return 0; } + tok->implicit_newline = 0; if (tok->inp[-1] != '\n') { assert(tok->inp + 1 < tok->end); /* Last line does not end in \n, fake one */ *tok->inp++ = '\n'; *tok->inp = '\0'; + tok->implicit_newline = 1; } ADVANCE_LINENO(); @@ -1304,11 +1309,13 @@ tok_underflow_readline(struct tok_state* tok) { tok->done = E_EOF; return 0; } + tok->implicit_newline = 0; if (tok->inp[-1] != '\n') { assert(tok->inp + 1 < tok->end); /* Last line does not end in \n, fake one */ *tok->inp++ = '\n'; *tok->inp = '\0'; + tok->implicit_newline = 1; } ADVANCE_LINENO(); diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 600d4297b6865a..16e919a8931edd 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -131,6 +131,7 @@ struct tok_state { int tok_report_warnings; int tok_extra_tokens; int comment_newline; + int implicit_newline; #ifdef Py_DEBUG int debug; #endif diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index a7933b2d6b0187..223de54d658507 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -243,10 +243,12 @@ tokenizeriter_next(tokenizeriterobject *it) } else if (type == NEWLINE) { Py_DECREF(str); - if (it->tok->start[0] == '\r') { - str = PyUnicode_FromString("\r\n"); - } else { - str = PyUnicode_FromString("\n"); + if (!it->tok->implicit_newline) { + if (it->tok->start[0] == '\r') { + str = PyUnicode_FromString("\r\n"); + } else { + str = PyUnicode_FromString("\n"); + } } end_col_offset++; } From 82ab13c49a77b0d73e6cd5c7ecfe0de1b1036819 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Jun 2023 15:11:28 +0200 Subject: [PATCH 0128/1206] [3.12] gh-102304: doc: Add links to Stable ABI and Limited C API (#105345) (#105371) * gh-102304: doc: Add links to Stable ABI and Limited C API (#105345) * Add "limited-c-api" and "stable-api" references. * Rename "stable-abi-list" reference to "limited-api-list". * Makefile: Document files regenerated by "make regen-limited-abi" * Remove first empty line in generated files: - Lib/test/test_stable_abi_ctypes.py - PC/python3dll.c (cherry picked from commit bae415ad02c79cf3a2eec4aa6969221a12e6716f) * gh-102304: Fix up Simple ABI doc (GH-105351) (cherry picked from commit 0202aa002e06acef9aa55ace0d939103df19cadd) --- Doc/c-api/exceptions.rst | 4 +- Doc/c-api/stable.rst | 55 +++++++++++++++++----------- Doc/c-api/structures.rst | 2 +- Doc/c-api/type.rst | 4 +- Doc/c-api/typeobj.rst | 2 +- Doc/c-api/unicode.rst | 2 +- Doc/howto/isolating-extensions.rst | 2 +- Doc/library/test.rst | 2 +- Doc/whatsnew/3.11.rst | 2 +- Doc/whatsnew/3.12.rst | 2 +- Lib/test/test_stable_abi_ctypes.py | 3 +- Misc/NEWS.d/3.11.0a1.rst | 2 +- Misc/NEWS.d/3.11.0a2.rst | 2 +- Modules/_testcapi_feature_macros.inc | 2 +- PC/python3dll.c | 1 - Tools/build/stable_abi.py | 8 ++-- 16 files changed, 53 insertions(+), 42 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 1694aa2db9c9da..a24ecac861e76b 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -887,7 +887,7 @@ because the :ref:`call protocol ` takes care of recursion handling. depth limit. .. versionchanged:: 3.9 - This function is now also available in the limited API. + This function is now also available in the :ref:`limited API `. .. c:function:: void Py_LeaveRecursiveCall(void) @@ -895,7 +895,7 @@ because the :ref:`call protocol ` takes care of recursion handling. *successful* invocation of :c:func:`Py_EnterRecursiveCall`. .. versionchanged:: 3.9 - This function is now also available in the limited API. + This function is now also available in the :ref:`limited API `. Properly implementing :c:member:`~PyTypeObject.tp_repr` for container types requires special recursion handling. In addition to protecting the stack, diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst index 3721fc0697f5cd..149d4d6bac3ee4 100644 --- a/Doc/c-api/stable.rst +++ b/Doc/c-api/stable.rst @@ -20,9 +20,9 @@ but will need to be compiled separately for 3.9.x and 3.10.x. There are two tiers of C API with different stability exepectations: -- *Unstable API*, may change in minor versions without a deprecation period. - It is marked by the ``PyUnstable`` prefix in names. -- *Limited API*, is compatible across several minor releases. +- :ref:`Unstable API `, may change in minor versions without + a deprecation period. It is marked by the ``PyUnstable`` prefix in names. +- :ref:`Limited API `, is compatible across several minor releases. When :c:macro:`Py_LIMITED_API` is defined, only this subset is exposed from ``Python.h``. @@ -55,19 +55,19 @@ CPython development and spend extra effort adjusting to changes. Stable Application Binary Interface =================================== +For simplicity, this document talks about *extensions*, but the Limited API +and Stable ABI work the same way for all uses of the API – for example, +embedding Python. + +.. _limited-c-api: + +Limited C API +------------- + Python 3.2 introduced the *Limited API*, a subset of Python's C API. Extensions that only use the Limited API can be compiled once and work with multiple versions of Python. -Contents of the Limited API are :ref:`listed below `. - -To enable this, Python provides a *Stable ABI*: a set of symbols that will -remain compatible across Python 3.x versions. The Stable ABI contains symbols -exposed in the Limited API, but also other ones – for example, functions -necessary to support older versions of the Limited API. - -(For simplicity, this document talks about *extensions*, but the Limited API -and Stable ABI work the same way for all uses of the API – for example, -embedding Python.) +Contents of the Limited API are :ref:`listed below `. .. c:macro:: Py_LIMITED_API @@ -87,6 +87,19 @@ embedding Python.) You can also define ``Py_LIMITED_API`` to ``3``. This works the same as ``0x03020000`` (Python 3.2, the version that introduced Limited API). + +.. _stable-abi: + +Stable ABI +---------- + +To enable this, Python provides a *Stable ABI*: a set of symbols that will +remain compatible across Python 3.x versions. + +The Stable ABI contains symbols exposed in the :ref:`Limited API +`, but also other ones – for example, functions necessary to +support older versions of the Limited API. + On Windows, extensions that use the Stable ABI should be linked against ``python3.dll`` rather than a version-specific library such as ``python39.dll``. @@ -131,9 +144,9 @@ Limited API Caveats ------------------- Note that compiling with ``Py_LIMITED_API`` is *not* a complete guarantee that -code conforms to the Limited API or the Stable ABI. ``Py_LIMITED_API`` only -covers definitions, but an API also includes other issues, such as expected -semantics. +code conforms to the :ref:`Limited API ` or the :ref:`Stable ABI +`. ``Py_LIMITED_API`` only covers definitions, but an API also +includes other issues, such as expected semantics. One issue that ``Py_LIMITED_API`` does not guard against is calling a function with arguments that are invalid in a lower Python version. @@ -166,9 +179,9 @@ Platform Considerations ======================= ABI stability depends not only on Python, but also on the compiler used, -lower-level libraries and compiler options. For the purposes of the Stable ABI, -these details define a “platformâ€. They usually depend on the OS -type and processor architecture +lower-level libraries and compiler options. For the purposes of +the :ref:`Stable ABI `, these details define a “platformâ€. They +usually depend on the OS type and processor architecture It is the responsibility of each particular distributor of Python to ensure that all Python versions on a particular platform are built @@ -177,12 +190,12 @@ This is the case with Windows and macOS releases from ``python.org`` and many third-party distributors. -.. _stable-abi-list: +.. _limited-api-list: Contents of Limited API ======================= -Currently, the Limited API includes the following items: +Currently, the :ref:`Limited API ` includes the following items: .. limited-api-list:: diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 7ce3578f250792..766f881463c00f 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -288,7 +288,7 @@ There are these calling conventions: .. versionchanged:: 3.10 - ``METH_FASTCALL`` is now part of the stable ABI. + ``METH_FASTCALL`` is now part of the :ref:`stable ABI `. .. data:: METH_FASTCALL | METH_KEYWORDS diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 89cd74335fd770..bf261b9814456e 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -42,7 +42,7 @@ Type Objects Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily meant for use with ``Py_LIMITED_API``; the individual flag bits are guaranteed to be stable across Python releases, but access to - :c:member:`~PyTypeObject.tp_flags` itself is not part of the limited API. + :c:member:`~PyTypeObject.tp_flags` itself is not part of the :ref:`limited API `. .. versionadded:: 3.2 @@ -472,7 +472,7 @@ The following functions and structs are used to create .. versionchanged:: 3.11 :c:member:`~PyBufferProcs.bf_getbuffer` and :c:member:`~PyBufferProcs.bf_releasebuffer` are now available - under the limited API. + under the :ref:`limited API `. .. c:member:: void *pfunc diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 0584989233de3f..c6e783acdf0654 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2150,7 +2150,7 @@ This results in types that are limited relative to types defined in Python: include any subinterpreter-specific state. Also, since :c:type:`PyTypeObject` is only part of the :ref:`Limited API -` as an opaque struct, any extension modules using static types must be +` as an opaque struct, any extension modules using static types must be compiled for a specific Python minor version. diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 6771f378bfbc31..33437b6193919a 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -992,7 +992,7 @@ These are the UTF-8 codec APIs: The return type is now ``const char *`` rather of ``char *``. .. versionchanged:: 3.10 - This function is a part of the :ref:`limited API `. + This function is a part of the :ref:`limited API `. .. c:function:: const char* PyUnicode_AsUTF8(PyObject *unicode) diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 0262054ae2b4a0..8adb85f3a87401 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -461,7 +461,7 @@ Module State Access from Slot Methods, Getters and Setters .. After adding to limited API: - If you use the :ref:`limited API , + If you use the :ref:`limited API `, you must update ``Py_LIMITED_API`` to ``0x030b0000``, losing ABI compatibility with earlier versions. diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 20f633b8f569be..1b045c7de83a80 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -803,7 +803,7 @@ The :mod:`test.support` module defines the following functions: .. decorator:: requires_limited_api - Decorator for only running the test if :ref:`Limited C API ` + Decorator for only running the test if :ref:`Limited C API ` is available. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 48606f3be42e3c..c06ce783689857 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2650,7 +2650,7 @@ Removed * :c:func:`PyMarshal_WriteObjectToString` * the ``Py_MARSHAL_VERSION`` macro - These are not part of the :ref:`limited API `. + These are not part of the :ref:`limited API `. (Contributed by Victor Stinner in :issue:`45474`.) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 18c4ae049ab7f8..287549fe30ec1a 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1580,7 +1580,7 @@ New Features (Contributed by Petr Viktorin in :gh:`103509`.) -* Added the new limited C API function :c:func:`PyType_FromMetaclass`, +* Added the new :ref:`limited C API ` function :c:func:`PyType_FromMetaclass`, which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using an additional metaclass argument. (Contributed by Wenzel Jakob in :gh:`93012`.) diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 60ad3603ae9223..68983675488389 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -1,5 +1,4 @@ - -# Generated by Tools/scripts/stable_abi.py +# Generated by Tools/build/stable_abi.py """Test that all symbols of the Stable ABI are accessible using ctypes """ diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index 7670e482ede5b6..447d5c0e7d9032 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -4980,7 +4980,7 @@ Removed documentation for the removed ``PyParser_*`` C API. .. nonce: fy0AXK .. section: C API -The list in :ref:`stable-abi-list` now shows the public name +The list in :ref:`limited-api-list` now shows the public name :c:struct:`PyFrameObject` rather than ``_frame``. The non-existing entry ``_node`` no longer appears in the list. diff --git a/Misc/NEWS.d/3.11.0a2.rst b/Misc/NEWS.d/3.11.0a2.rst index 225bd61e90d4a8..cf26137dff19ef 100644 --- a/Misc/NEWS.d/3.11.0a2.rst +++ b/Misc/NEWS.d/3.11.0a2.rst @@ -1234,7 +1234,7 @@ defined: * :c:func:`PyMarshal_WriteObjectToString` * the ``Py_MARSHAL_VERSION`` macro -These are not part of the :ref:`limited API `. +These are not part of the :ref:`limited API `. Patch by Victor Stinner. diff --git a/Modules/_testcapi_feature_macros.inc b/Modules/_testcapi_feature_macros.inc index b1763b57d913c2..a076e714980074 100644 --- a/Modules/_testcapi_feature_macros.inc +++ b/Modules/_testcapi_feature_macros.inc @@ -1,4 +1,4 @@ -// Generated by Tools/scripts/stable_abi.py +// Generated by Tools/build/stable_abi.py // Add an entry in dict `result` for each Stable ABI feature macro. diff --git a/PC/python3dll.c b/PC/python3dll.c index f2c0d9dee883d9..5665d5530e2360 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -1,4 +1,3 @@ - /* Re-export stable Python ABI */ /* Generated by Tools/build/stable_abi.py */ diff --git a/Tools/build/stable_abi.py b/Tools/build/stable_abi.py index 42b2dd92307bbf..4cd1cd953d0d29 100644 --- a/Tools/build/stable_abi.py +++ b/Tools/build/stable_abi.py @@ -183,7 +183,7 @@ def _decorator(func): def gen_python3dll(manifest, args, outfile): """Generate/check the source for the Windows stable ABI library""" write = partial(print, file=outfile) - content = f""" + content = f"""\ /* Re-export stable Python ABI */ /* Generated by {SCRIPT_NAME} */ @@ -267,8 +267,8 @@ def gen_doc_annotations(manifest, args, outfile): def gen_ctypes_test(manifest, args, outfile): """Generate/check the ctypes-based test for exported symbols""" write = partial(print, file=outfile) - write(textwrap.dedent(''' - # Generated by Tools/scripts/stable_abi.py + write(textwrap.dedent(f'''\ + # Generated by {SCRIPT_NAME} """Test that all symbols of the Stable ABI are accessible using ctypes """ @@ -341,7 +341,7 @@ def test_windows_feature_macros(self): def gen_testcapi_feature_macros(manifest, args, outfile): """Generate/check the stable ABI list for documentation annotations""" write = partial(print, file=outfile) - write('// Generated by Tools/scripts/stable_abi.py') + write(f'// Generated by {SCRIPT_NAME}') write() write('// Add an entry in dict `result` for each Stable ABI feature macro.') write() From 27cbeb08b80138d093b9b08eb41744d249c386e6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 07:01:28 -0700 Subject: [PATCH 0129/1206] [3.12] gh-104399: Use newer libtommath APIs when necessary (GH-104407) (#105343) gh-104399: Use newer libtommath APIs when necessary (GH-104407) (cherry picked from commit 00d73caf804c0474980e471347d6385757af975f) Co-authored-by: Christopher Chavez --- ...-05-11-23-03-00.gh-issue-104399.MMatTP.rst | 4 ++++ Modules/_tkinter.c | 23 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst diff --git a/Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst b/Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst new file mode 100644 index 00000000000000..84cc888635b415 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst @@ -0,0 +1,4 @@ +Prepare the ``_tkinter`` module for building with Tcl 9.0 and future +libtommath by replacing usage of deprecated functions +:c:func:`mp_to_unsigned_bin_n` and :c:func:`mp_unsigned_bin_size` +when necessary. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 49c94447c7237c..15f9c0465fb043 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -65,6 +65,12 @@ Copyright (C) 1994 Steen Lumholt. #endif #include +#if defined(TCL_WITH_EXTERNAL_TOMMATH) || (TK_HEX_VERSION >= 0x08070000) +#define USE_DEPRECATED_TOMMATH_API 0 +#else +#define USE_DEPRECATED_TOMMATH_API 1 +#endif + #if !(defined(MS_WINDOWS) || defined(__CYGWIN__)) #define HAVE_CREATEFILEHANDLER #endif @@ -1053,20 +1059,33 @@ static PyObject* fromBignumObj(TkappObject *tkapp, Tcl_Obj *value) { mp_int bigValue; + mp_err err; +#if USE_DEPRECATED_TOMMATH_API unsigned long numBytes; +#else + size_t numBytes; +#endif unsigned char *bytes; PyObject *res; if (Tcl_GetBignumFromObj(Tkapp_Interp(tkapp), value, &bigValue) != TCL_OK) return Tkinter_Error(tkapp); +#if USE_DEPRECATED_TOMMATH_API numBytes = mp_unsigned_bin_size(&bigValue); +#else + numBytes = mp_ubin_size(&bigValue); +#endif bytes = PyMem_Malloc(numBytes); if (bytes == NULL) { mp_clear(&bigValue); return PyErr_NoMemory(); } - if (mp_to_unsigned_bin_n(&bigValue, bytes, - &numBytes) != MP_OKAY) { +#if USE_DEPRECATED_TOMMATH_API + err = mp_to_unsigned_bin_n(&bigValue, bytes, &numBytes); +#else + err = mp_to_ubin(&bigValue, bytes, numBytes, NULL); +#endif + if (err != MP_OKAY) { mp_clear(&bigValue); PyMem_Free(bytes); return PyErr_NoMemory(); From 260ba1fcdba860ab298c530af8c5340eb8b2c021 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 07:04:07 -0700 Subject: [PATCH 0130/1206] [3.12] gh-104411: Update test_getint for Tcl 9.0 (GH-104412) (#105356) gh-104411: Update test_getint for Tcl 9.0 (GH-104412) (cherry picked from commit 2c49c759e880a32539f50c31dbd35d2bc4b4e030) Co-authored-by: Christopher Chavez --- Lib/test/test_tcl.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index cd79024ab2c8e3..d07b83acb1b505 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -142,7 +142,10 @@ def test_getint(self): for i in self.get_integers(): self.assertEqual(tcl.getint(' %d ' % i), i) self.assertEqual(tcl.getint(' %#o ' % i), i) - self.assertEqual(tcl.getint((' %#o ' % i).replace('o', '')), i) + # Numbers starting with 0 are parsed as decimal in Tcl 9.0 + # and as octal in older versions. + self.assertEqual(tcl.getint((' %#o ' % i).replace('o', '')), + i if tcl_version < (9, 0) else int('%o' % i)) self.assertEqual(tcl.getint(' %#x ' % i), i) self.assertEqual(tcl.getint(42), 42) self.assertRaises(TypeError, tcl.getint) From 2d9ead219e940d3fd717cdb0841cfe8a97efe554 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 07:06:44 -0700 Subject: [PATCH 0131/1206] [3.12] GH-105162: Account for `INSTRUMENTED_RESUME` in gen.close/throw. (GH-105187) (#105378) GH-105162: Account for `INSTRUMENTED_RESUME` in gen.close/throw. (GH-105187) (cherry picked from commit 601ae09f0c8eda213b9050892f5ce9b91f0aa522) Co-authored-by: Mark Shannon --- Lib/test/test_monitoring.py | 35 +++++++++++++++++++ ...-06-01-11-37-03.gh-issue-105162.r8VCXk.rst | 2 ++ Objects/genobject.c | 18 ++++++++-- 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 46b817d74f092f..ef4a79aefd646b 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1425,3 +1425,38 @@ def f(): def test_get_local_events_uninitialized(self): self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, self.f.__code__), 0) + +class TestRegressions(MonitoringTestBase, unittest.TestCase): + + def test_105162(self): + caught = None + + def inner(): + nonlocal caught + try: + yield + except Exception: + caught = "inner" + yield + + def outer(): + nonlocal caught + try: + yield from inner() + except Exception: + caught = "outer" + yield + + def run(): + gen = outer() + gen.send(None) + gen.throw(Exception) + run() + self.assertEqual(caught, "inner") + caught = None + try: + sys.monitoring.set_events(TEST_TOOL, E.PY_RESUME) + run() + self.assertEqual(caught, "inner") + finally: + sys.monitoring.set_events(TEST_TOOL, 0) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst new file mode 100644 index 00000000000000..adb4e8478d9c55 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst @@ -0,0 +1,2 @@ +Fixed bug in generator.close()/throw() where an inner iterator would be +ignored when the outer iterator was instrumented. diff --git a/Objects/genobject.c b/Objects/genobject.c index 9252c654934565..b13b52edf5c52d 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -331,6 +331,18 @@ gen_close_iter(PyObject *yf) return 0; } +static inline bool +is_resume(_Py_CODEUNIT *instr) +{ + return instr->op.code == RESUME || instr->op.code == INSTRUMENTED_RESUME; +} + +static inline bool +is_yield(_Py_CODEUNIT *instr) +{ + return instr->op.code == YIELD_VALUE || instr->op.code == INSTRUMENTED_YIELD_VALUE; +} + PyObject * _PyGen_yf(PyGenObject *gen) { @@ -347,7 +359,7 @@ _PyGen_yf(PyGenObject *gen) return NULL; } _Py_CODEUNIT next = frame->prev_instr[1]; - if (next.op.code != RESUME || next.op.arg < 2) + if (!is_resume(&next) || next.op.arg < 2) { /* Not in a yield from */ return NULL; @@ -382,8 +394,8 @@ gen_close(PyGenObject *gen, PyObject *args) _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; /* It is possible for the previous instruction to not be a * YIELD_VALUE if the debugger has changed the lineno. */ - if (err == 0 && frame->prev_instr[0].op.code == YIELD_VALUE) { - assert(frame->prev_instr[1].op.code == RESUME); + if (err == 0 && is_yield(frame->prev_instr)) { + assert(is_resume(frame->prev_instr + 1)); int exception_handler_depth = frame->prev_instr[0].op.code; assert(exception_handler_depth > 0); /* We can safely ignore the outermost try block From e6c0efa25a47488f400093fc556c03e83567aed8 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 6 Jun 2023 16:12:06 +0200 Subject: [PATCH 0132/1206] Python 3.12.0b2 --- Include/patchlevel.h | 4 +- Lib/pydoc_data/topics.py | 781 +++++++++++++++--- Misc/NEWS.d/3.12.0b2.rst | 530 ++++++++++++ ...3-05-26-15-44-20.gh-issue-89886._iSW-p.rst | 2 - ...3-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst | 1 - ...-05-19-10-22-34.gh-issue-104668.MLX1g9.rst | 5 - ...-05-30-10-15-13.gh-issue-105071.dPtp7c.rst | 1 - ...-05-30-17-45-32.gh-issue-105115.iRho1K.rst | 3 - ...-05-24-09-59-56.gh-issue-104825.mQesie.rst | 2 - ...-05-24-10-19-35.gh-issue-104879.v-29NL.rst | 2 - ...-05-24-12-10-54.gh-issue-104690.HX3Jou.rst | 6 - ...-05-25-21-40-39.gh-issue-104955.LZx7jf.rst | 2 - ...-05-26-14-09-47.gh-issue-104972.El2UjE.rst | 2 - ...-05-26-15-16-11.gh-issue-104976.6dLitD.rst | 3 - ...-05-27-16-23-16.gh-issue-105017.KQrsC0.rst | 1 - ...-05-27-16-57-11.gh-issue-105013.IsDgDY.rst | 2 - ...-05-27-21-50-48.gh-issue-105017.4sDyDV.rst | 1 - ...-05-30-08-09-43.gh-issue-105035.OWUlHy.rst | 2 - ...-05-31-08-10-59.gh-issue-104799.8kDWti.rst | 4 - ...-05-31-19-35-22.gh-issue-105164.6Wajph.rst | 2 - ...-06-01-11-37-03.gh-issue-105162.r8VCXk.rst | 2 - ...-06-02-11-37-12.gh-issue-105194.4eu56B.rst | 2 - ...3-06-02-17-39-19.gh-issue-98963.J4wJgk.rst | 4 - ...-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst | 2 - ...-06-06-11-37-53.gh-issue-105259.E2BGKL.rst | 2 - ...-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst | 1 - ...3-05-28-19-08-42.gh-issue-89412.j4cg7K.rst | 2 - ...3-05-28-21-01-00.gh-issue-89455.qAKRrA.rst | 3 - ...-05-23-17-19-49.gh-issue-104719.rvYXH-.rst | 2 - ...-02-18-22-55-48.gh-issue-102024.RUmg_D.rst | 1 - ...-05-11-23-03-00.gh-issue-104399.MMatTP.rst | 4 - ...3-05-19-19-46-22.gh-issue-99108.wqCg0t.rst | 3 - ...-05-22-18-39-53.gh-issue-104372.7tDRaK.rst | 5 - ...-05-23-17-43-52.gh-issue-104797.NR7KzF.rst | 2 - ...-05-23-18-31-49.gh-issue-104799.MJYOw6.rst | 4 - ...-05-24-09-34-23.gh-issue-104874.oqyJSy.rst | 2 - ...-05-25-08-50-47.gh-issue-104935.-rm1BR.rst | 3 - ...-05-25-22-54-20.gh-issue-104947.hi6TUr.rst | 2 - ...-05-25-23-34-54.gh-issue-103631.x5Urye.rst | 2 - ...-05-26-01-31-30.gh-issue-101588.RaqxFy.rst | 1 - ...-05-30-21-27-41.gh-issue-105113.bDUPl_.rst | 2 - ...-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst | 5 - ...-06-02-02-38-26.gh-issue-105080.2imGMg.rst | 1 - ...-06-02-14-57-11.gh-issue-105239.SAmuuj.rst | 2 - ...-06-04-12-16-47.gh-issue-105280.srRbCe.rst | 4 - ...3-05-24-09-29-08.gh-issue-99108.hwS2cr.rst | 2 - ...-06-01-03-24-58.gh-issue-103142.GLWDMX.rst | 2 - ...-05-23-19-26-28.gh-issue-104803.gqxYml.rst | 3 - ...-05-24-21-00-57.gh-issue-104820.ibyrpp.rst | 2 - ...3-05-29-11-38-53.gh-issue-88745.cldf9G.rst | 3 - ...-05-29-17-09-31.gh-issue-103646.U8oGQx.rst | 5 - ...-05-31-16-14-31.gh-issue-105146.gNjqq8.rst | 2 - ...-05-30-23-30-46.gh-issue-103142.55lMXQ.rst | 1 - README.rst | 2 +- 54 files changed, 1207 insertions(+), 234 deletions(-) create mode 100644 Misc/NEWS.d/3.12.0b2.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst delete mode 100644 Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst delete mode 100644 Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst delete mode 100644 Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst delete mode 100644 Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index d71bef922e5b2a..2d1cfc43d699f2 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.12.0b1+" +#define PY_VERSION "3.12.0b2" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index cb742992a48e8f..d70bf9e86b2de2 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon May 22 14:02:15 2023 +# Autogenerated by Sphinx on Tue Jun 6 16:12:51 2023 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -538,77 +538,7 @@ ' **PEP 492** - Coroutines with async and await syntax\n' ' The proposal that made coroutines a proper standalone concept ' 'in\n' - ' Python, and added supporting syntax.\n' - '\n' - '-[ Footnotes ]-\n' - '\n' - '[1] The exception is propagated to the invocation stack unless ' - 'there\n' - ' is a "finally" clause which happens to raise another ' - 'exception.\n' - ' That new exception causes the old one to be lost.\n' - '\n' - '[2] In pattern matching, a sequence is defined as one of the\n' - ' following:\n' - '\n' - ' * a class that inherits from "collections.abc.Sequence"\n' - '\n' - ' * a Python class that has been registered as\n' - ' "collections.abc.Sequence"\n' - '\n' - ' * a builtin class that has its (CPython) ' - '"Py_TPFLAGS_SEQUENCE"\n' - ' bit set\n' - '\n' - ' * a class that inherits from any of the above\n' - '\n' - ' The following standard library classes are sequences:\n' - '\n' - ' * "array.array"\n' - '\n' - ' * "collections.deque"\n' - '\n' - ' * "list"\n' - '\n' - ' * "memoryview"\n' - '\n' - ' * "range"\n' - '\n' - ' * "tuple"\n' - '\n' - ' Note:\n' - '\n' - ' Subject values of type "str", "bytes", and "bytearray" do ' - 'not\n' - ' match sequence patterns.\n' - '\n' - '[3] In pattern matching, a mapping is defined as one of the ' - 'following:\n' - '\n' - ' * a class that inherits from "collections.abc.Mapping"\n' - '\n' - ' * a Python class that has been registered as\n' - ' "collections.abc.Mapping"\n' - '\n' - ' * a builtin class that has its (CPython) ' - '"Py_TPFLAGS_MAPPING"\n' - ' bit set\n' - '\n' - ' * a class that inherits from any of the above\n' - '\n' - ' The standard library classes "dict" and ' - '"types.MappingProxyType"\n' - ' are mappings.\n' - '\n' - '[4] A string literal appearing as the first statement in the ' - 'function\n' - ' body is transformed into the function’s "__doc__" attribute ' - 'and\n' - ' therefore the function’s *docstring*.\n' - '\n' - '[5] A string literal appearing as the first statement in the class\n' - ' body is transformed into the namespace’s "__doc__" item and\n' - ' therefore the class’s *docstring*.\n', + ' Python, and added supporting syntax.\n', 'atom-identifiers': 'Identifiers (Names)\n' '*******************\n' '\n' @@ -1748,8 +1678,8 @@ 'standard\n' 'type hierarchy):\n' '\n' - ' classdef ::= [decorators] "class" classname [inheritance] ":" ' - 'suite\n' + ' classdef ::= [decorators] "class" classname [type_params] ' + '[inheritance] ":" suite\n' ' inheritance ::= "(" [argument_list] ")"\n' ' classname ::= identifier\n' '\n' @@ -1813,6 +1743,19 @@ '"assignment_expression". Previously, the grammar was much more\n' 'restrictive; see **PEP 614** for details.\n' '\n' + 'A list of type parameters may be given in square brackets ' + 'immediately\n' + 'after the class’s name. This indicates to static type checkers ' + 'that\n' + 'the class is generic. At runtime, the type parameters can be ' + 'retrieved\n' + 'from the class’s "__type_params__" attribute. See Generic classes ' + 'for\n' + 'more.\n' + '\n' + 'Changed in version 3.12: Type parameter lists are new in Python ' + '3.12.\n' + '\n' '**Programmer’s note:** Variables defined in the class definition ' 'are\n' 'class attributes; they are shared by instances. Instance ' @@ -3554,8 +3497,8 @@ '(see\n' 'section The standard type hierarchy):\n' '\n' - ' funcdef ::= [decorators] "def" funcname "(" ' - '[parameter_list] ")"\n' + ' funcdef ::= [decorators] "def" funcname ' + '[type_params] "(" [parameter_list] ")"\n' ' ["->" expression] ":" suite\n' ' decorators ::= decorator+\n' ' decorator ::= "@" assignment_expression ' @@ -3617,6 +3560,19 @@ '"assignment_expression". Previously, the grammar was much more\n' 'restrictive; see **PEP 614** for details.\n' '\n' + 'A list of type parameters may be given in square brackets ' + 'between the\n' + 'function’s name and the opening parenthesis for its parameter ' + 'list.\n' + 'This indicates to static type checkers that the function is ' + 'generic.\n' + 'At runtime, the type parameters can be retrieved from the ' + 'function’s\n' + '"__type_params__" attribute. See Generic functions for more.\n' + '\n' + 'Changed in version 3.12: Type parameter lists are new in Python ' + '3.12.\n' + '\n' 'When one or more *parameters* have the form *parameter* "="\n' '*expression*, the function is said to have “default parameter ' 'values.â€\n' @@ -3759,8 +3715,8 @@ 'standard\n' 'type hierarchy):\n' '\n' - ' classdef ::= [decorators] "class" classname [inheritance] ' - '":" suite\n' + ' classdef ::= [decorators] "class" classname [type_params] ' + '[inheritance] ":" suite\n' ' inheritance ::= "(" [argument_list] ")"\n' ' classname ::= identifier\n' '\n' @@ -3828,6 +3784,19 @@ '"assignment_expression". Previously, the grammar was much more\n' 'restrictive; see **PEP 614** for details.\n' '\n' + 'A list of type parameters may be given in square brackets ' + 'immediately\n' + 'after the class’s name. This indicates to static type checkers ' + 'that\n' + 'the class is generic. At runtime, the type parameters can be ' + 'retrieved\n' + 'from the class’s "__type_params__" attribute. See Generic ' + 'classes for\n' + 'more.\n' + '\n' + 'Changed in version 3.12: Type parameter lists are new in Python ' + '3.12.\n' + '\n' '**Programmer’s note:** Variables defined in the class definition ' 'are\n' 'class attributes; they are shared by instances. Instance ' @@ -3985,6 +3954,272 @@ 'concept in\n' ' Python, and added supporting syntax.\n' '\n' + '\n' + 'Type parameter lists\n' + '====================\n' + '\n' + 'New in version 3.12.\n' + '\n' + ' type_params ::= "[" type_param ("," type_param)* "]"\n' + ' type_param ::= typevar | typevartuple | paramspec\n' + ' typevar ::= identifier (":" expression)?\n' + ' typevartuple ::= "*" identifier\n' + ' paramspec ::= "**" identifier\n' + '\n' + 'Functions (including coroutines), classes and type aliases may ' + 'contain\n' + 'a type parameter list:\n' + '\n' + ' def max[T](args: list[T]) -> T:\n' + ' ...\n' + '\n' + ' async def amax[T](args: list[T]) -> T:\n' + ' ...\n' + '\n' + ' class Bag[T]:\n' + ' def __iter__(self) -> Iterator[T]:\n' + ' ...\n' + '\n' + ' def add(self, arg: T) -> None:\n' + ' ...\n' + '\n' + ' type ListOrSet[T] = list[T] | set[T]\n' + '\n' + 'Semantically, this indicates that the function, class, or type ' + 'alias\n' + 'is generic over a type variable. This information is primarily ' + 'used by\n' + 'static type checkers, and at runtime, generic objects behave ' + 'much like\n' + 'their non-generic counterparts.\n' + '\n' + 'Type parameters are declared in square brackets ("[]") ' + 'immediately\n' + 'after the name of the function, class, or type alias. The type\n' + 'parameters are accessible within the scope of the generic ' + 'object, but\n' + 'not elsewhere. Thus, after a declaration "def func[T](): pass", ' + 'the\n' + 'name "T" is not available in the module scope. Below, the ' + 'semantics of\n' + 'generic objects are described with more precision. The scope of ' + 'type\n' + 'parameters is modeled with a special function (technically, an\n' + 'annotation scope) that wraps the creation of the generic ' + 'object.\n' + '\n' + 'Generic functions, classes, and type aliases have a ' + '"__type_params__"\n' + 'attribute listing their type parameters.\n' + '\n' + 'Type parameters come in three kinds:\n' + '\n' + '* "typing.TypeVar", introduced by a plain name (e.g., "T").\n' + ' Semantically, this represents a single type to a type ' + 'checker.\n' + '\n' + '* "typing.TypeVarTuple", introduced by a name prefixed with a ' + 'single\n' + ' asterisk (e.g., "*Ts"). Semantically, this stands for a tuple ' + 'of any\n' + ' number of types.\n' + '\n' + '* "typing.ParamSpec", introduced by a name prefixed with two ' + 'asterisks\n' + ' (e.g., "**P"). Semantically, this stands for the parameters of ' + 'a\n' + ' callable.\n' + '\n' + '"typing.TypeVar" declarations can define *bounds* and ' + '*constraints*\n' + 'with a colon (":") followed by an expression. A single ' + 'expression\n' + 'after the colon indicates a bound (e.g. "T: int"). Semantically, ' + 'this\n' + 'means that the "typing.TypeVar" can only represent types that ' + 'are a\n' + 'subtype of this bound. A parenthesized tuple of expressions ' + 'after the\n' + 'colon indicates a set of constraints (e.g. "T: (str, bytes)"). ' + 'Each\n' + 'member of the tuple should be a type (again, this is not ' + 'enforced at\n' + 'runtime). Constrained type variables can only take on one of the ' + 'types\n' + 'in the list of constraints.\n' + '\n' + 'For "typing.TypeVar"s declared using the type parameter list ' + 'syntax,\n' + 'the bound and constraints are not evaluated when the generic ' + 'object is\n' + 'created, but only when the value is explicitly accessed through ' + 'the\n' + 'attributes "__bound__" and "__constraints__". To accomplish ' + 'this, the\n' + 'bounds or constraints are evaluated in a separate annotation ' + 'scope.\n' + '\n' + '"typing.TypeVarTuple"s and "typing.ParamSpec"s cannot have ' + 'bounds or\n' + 'constraints.\n' + '\n' + 'The following example indicates the full set of allowed type ' + 'parameter\n' + 'declarations:\n' + '\n' + ' def overly_generic[\n' + ' SimpleTypeVar,\n' + ' TypeVarWithBound: int,\n' + ' TypeVarWithConstraints: (str, bytes),\n' + ' *SimpleTypeVarTuple,\n' + ' **SimpleParamSpec,\n' + ' ](\n' + ' a: SimpleTypeVar,\n' + ' b: TypeVarWithBound,\n' + ' c: Callable[SimpleParamSpec, TypeVarWithConstraints],\n' + ' *d: SimpleTypeVarTuple,\n' + ' ): ...\n' + '\n' + '\n' + 'Generic functions\n' + '-----------------\n' + '\n' + 'Generic functions are declared as follows:\n' + '\n' + ' def func[T](arg: T): ...\n' + '\n' + 'This syntax is equivalent to:\n' + '\n' + ' annotation-def TYPE_PARAMS_OF_func():\n' + ' T = typing.TypeVar("T")\n' + ' def func(arg: T): ...\n' + ' func.__type_params__ = (T,)\n' + ' return func\n' + ' func = TYPE_PARAMS_OF_func()\n' + '\n' + 'Here "annotation-def" indicates an annotation scope, which is ' + 'not\n' + 'actually bound to any name at runtime. (One other liberty is ' + 'taken in\n' + 'the translation: the syntax does not go through attribute access ' + 'on\n' + 'the "typing" module, but creates an instance of ' + '"typing.TypeVar"\n' + 'directly.)\n' + '\n' + 'The annotations of generic functions are evaluated within the\n' + 'annotation scope used for declaring the type parameters, but ' + 'the\n' + 'function’s defaults and decorators are not.\n' + '\n' + 'The following example illustrates the scoping rules for these ' + 'cases,\n' + 'as well as for additional flavors of type parameters:\n' + '\n' + ' @decorator\n' + ' def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = ' + 'some_default):\n' + ' ...\n' + '\n' + 'Except for the lazy evaluation of the "TypeVar" bound, this is\n' + 'equivalent to:\n' + '\n' + ' DEFAULT_OF_arg = some_default\n' + '\n' + ' annotation-def TYPE_PARAMS_OF_func():\n' + '\n' + ' annotation-def BOUND_OF_T():\n' + ' return int\n' + ' # In reality, BOUND_OF_T() is evaluated only on demand.\n' + ' T = typing.TypeVar("T", bound=BOUND_OF_T())\n' + '\n' + ' Ts = typing.TypeVarTuple("Ts")\n' + ' P = typing.ParamSpec("P")\n' + '\n' + ' def func(*args: *Ts, arg: Callable[P, T] = ' + 'DEFAULT_OF_arg):\n' + ' ...\n' + '\n' + ' func.__type_params__ = (T, Ts, P)\n' + ' return func\n' + ' func = decorator(TYPE_PARAMS_OF_func())\n' + '\n' + 'The capitalized names like "DEFAULT_OF_arg" are not actually ' + 'bound at\n' + 'runtime.\n' + '\n' + '\n' + 'Generic classes\n' + '---------------\n' + '\n' + 'Generic classes are declared as follows:\n' + '\n' + ' class Bag[T]: ...\n' + '\n' + 'This syntax is equivalent to:\n' + '\n' + ' annotation-def TYPE_PARAMS_OF_Bag():\n' + ' T = typing.TypeVar("T")\n' + ' class Bag(typing.Generic[T]):\n' + ' __type_params__ = (T,)\n' + ' ...\n' + ' return Bag\n' + ' Bag = TYPE_PARAMS_OF_Bag()\n' + '\n' + 'Here again "annotation-def" (not a real keyword) indicates an\n' + 'annotation scope, and the name "TYPE_PARAMS_OF_Bag" is not ' + 'actually\n' + 'bound at runtime.\n' + '\n' + 'Generic classes implicitly inherit from "typing.Generic". The ' + 'base\n' + 'classes and keyword arguments of generic classes are evaluated ' + 'within\n' + 'the type scope for the type parameters, and decorators are ' + 'evaluated\n' + 'outside that scope. This is illustrated by this example:\n' + '\n' + ' @decorator\n' + ' class Bag(Base[T], arg=T): ...\n' + '\n' + 'This is equivalent to:\n' + '\n' + ' annotation-def TYPE_PARAMS_OF_Bag():\n' + ' T = typing.TypeVar("T")\n' + ' class Bag(Base[T], typing.Generic[T], arg=T):\n' + ' __type_params__ = (T,)\n' + ' ...\n' + ' return Bag\n' + ' Bag = decorator(TYPE_PARAMS_OF_Bag())\n' + '\n' + '\n' + 'Generic type aliases\n' + '--------------------\n' + '\n' + 'The "type" statement can also be used to create a generic type ' + 'alias:\n' + '\n' + ' type ListOrSet[T] = list[T] | set[T]\n' + '\n' + 'Except for the lazy evaluation of the value, this is equivalent ' + 'to:\n' + '\n' + ' annotation-def TYPE_PARAMS_OF_ListOrSet():\n' + ' T = typing.TypeVar("T")\n' + '\n' + ' annotation-def VALUE_OF_ListOrSet():\n' + ' return list[T] | set[T]\n' + ' # In reality, the value is lazily evaluated\n' + ' return typing.TypeAliasType("ListOrSet", ' + 'VALUE_OF_ListOrSet(), type_params=(T,))\n' + ' ListOrSet = TYPE_PARAMS_OF_ListOrSet()\n' + '\n' + 'Here, "annotation-def" (not a real keyword) indicates an ' + 'annotation\n' + 'scope. The capitalized names like "TYPE_PARAMS_OF_ListOrSet" are ' + 'not\n' + 'actually bound at runtime.\n' + '\n' '-[ Footnotes ]-\n' '\n' '[1] The exception is propagated to the invocation stack unless ' @@ -5692,6 +5927,10 @@ '\n' '* "import" statements.\n' '\n' + '* "type" statements.\n' + '\n' + '* type parameter lists.\n' + '\n' 'The "import" statement of the form "from ... import *" binds ' 'all names\n' 'defined in the imported module, except those beginning with an\n' @@ -5798,7 +6037,9 @@ 'scope.\n' '"SyntaxError" is raised at compile time if the given name does ' 'not\n' - 'exist in any enclosing function scope.\n' + 'exist in any enclosing function scope. Type parameters cannot ' + 'be\n' + 'rebound with the "nonlocal" statement.\n' '\n' 'The namespace for a module is automatically created the first ' 'time a\n' @@ -5821,17 +6062,162 @@ 'the class. The scope of names defined in a class block is ' 'limited to\n' 'the class block; it does not extend to the code blocks of ' - 'methods –\n' - 'this includes comprehensions and generator expressions since ' - 'they are\n' - 'implemented using a function scope. This means that the ' - 'following\n' - 'will fail:\n' + 'methods.\n' + 'This includes comprehensions and generator expressions, but it ' + 'does\n' + 'not include annotation scopes, which have access to their ' + 'enclosing\n' + 'class scopes. This means that the following will fail:\n' '\n' ' class A:\n' ' a = 42\n' ' b = list(a + i for i in range(10))\n' '\n' + 'However, the following will succeed:\n' + '\n' + ' class A:\n' + ' type Alias = Nested\n' + ' class Nested: pass\n' + '\n' + " print(A.Alias.__value__) # \n" + '\n' + '\n' + 'Annotation scopes\n' + '-----------------\n' + '\n' + 'Type parameter lists and "type" statements introduce ' + '*annotation\n' + 'scopes*, which behave mostly like function scopes, but with ' + 'some\n' + 'exceptions discussed below. *Annotations* currently do not use\n' + 'annotation scopes, but they are expected to use annotation ' + 'scopes in\n' + 'Python 3.13 when **PEP 649** is implemented.\n' + '\n' + 'Annotation scopes are used in the following contexts:\n' + '\n' + '* Type parameter lists for generic type aliases.\n' + '\n' + '* Type parameter lists for generic functions. A generic ' + 'function’s\n' + ' annotations are executed within the annotation scope, but ' + 'its\n' + ' defaults and decorators are not.\n' + '\n' + '* Type parameter lists for generic classes. A generic class’s ' + 'base\n' + ' classes and keyword arguments are executed within the ' + 'annotation\n' + ' scope, but its decorators are not.\n' + '\n' + '* The bounds and constraints for type variables (lazily ' + 'evaluated).\n' + '\n' + '* The value of type aliases (lazily evaluated).\n' + '\n' + 'Annotation scopes differ from function scopes in the following ' + 'ways:\n' + '\n' + '* Annotation scopes have access to their enclosing class ' + 'namespace. If\n' + ' an annotation scope is immediately within a class scope, or ' + 'within\n' + ' another annotation scope that is immediately within a class ' + 'scope,\n' + ' the code in the annotation scope can use names defined in the ' + 'class\n' + ' scope as if it were executed directly within the class body. ' + 'This\n' + ' contrasts with regular functions defined within classes, ' + 'which\n' + ' cannot access names defined in the class scope.\n' + '\n' + '* Expressions in annotation scopes cannot contain "yield", ' + '"yield\n' + ' from", "await", or ":=" expressions. (These expressions are ' + 'allowed\n' + ' in other scopes contained within the annotation scope.)\n' + '\n' + '* Names defined in annotation scopes cannot be rebound with ' + '"nonlocal"\n' + ' statements in inner scopes. This includes only type ' + 'parameters, as\n' + ' no other syntactic elements that can appear within annotation ' + 'scopes\n' + ' can introduce new names.\n' + '\n' + '* While annotation scopes have an internal name, that name is ' + 'not\n' + ' reflected in the *__qualname__* of objects defined within the ' + 'scope.\n' + ' Instead, the "__qualname__" of such objects is as if the ' + 'object were\n' + ' defined in the enclosing scope.\n' + '\n' + 'New in version 3.12: Annotation scopes were introduced in ' + 'Python 3.12\n' + 'as part of **PEP 695**.\n' + '\n' + '\n' + 'Lazy evaluation\n' + '---------------\n' + '\n' + 'The values of type aliases created through the "type" statement ' + 'are\n' + '*lazily evaluated*. The same applies to the bounds and ' + 'constraints of\n' + 'type variables created through the type parameter syntax. This ' + 'means\n' + 'that they are not evaluated when the type alias or type ' + 'variable is\n' + 'created. Instead, they are only evaluated when doing so is ' + 'necessary\n' + 'to resolve an attribute access.\n' + '\n' + 'Example:\n' + '\n' + ' >>> type Alias = 1/0\n' + ' >>> Alias.__value__\n' + ' Traceback (most recent call last):\n' + ' ...\n' + ' ZeroDivisionError: division by zero\n' + ' >>> def func[T: 1/0](): pass\n' + ' >>> T = func.__type_params__[0]\n' + ' >>> T.__bound__\n' + ' Traceback (most recent call last):\n' + ' ...\n' + ' ZeroDivisionError: division by zero\n' + '\n' + 'Here the exception is raised only when the "__value__" ' + 'attribute of\n' + 'the type alias or the "__bound__" attribute of the type ' + 'variable is\n' + 'accessed.\n' + '\n' + 'This behavior is primarily useful for references to types that ' + 'have\n' + 'not yet been defined when the type alias or type variable is ' + 'created.\n' + 'For example, lazy evaluation enables creation of mutually ' + 'recursive\n' + 'type aliases:\n' + '\n' + ' from typing import Literal\n' + '\n' + ' type SimpleExpr = int | Parenthesized\n' + ' type Parenthesized = tuple[Literal["("], Expr, ' + 'Literal[")"]]\n' + ' type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", ' + '"-"], Expr]\n' + '\n' + 'Lazily evaluated values are evaluated in annotation scope, ' + 'which means\n' + 'that names that appear inside the lazily evaluated value are ' + 'looked up\n' + 'as if they were used in the immediately enclosing scope.\n' + '\n' + 'New in version 3.12.\n' + '\n' '\n' 'Builtins and restricted execution\n' '---------------------------------\n' @@ -6872,8 +7258,8 @@ '(see\n' 'section The standard type hierarchy):\n' '\n' - ' funcdef ::= [decorators] "def" funcname "(" ' - '[parameter_list] ")"\n' + ' funcdef ::= [decorators] "def" funcname ' + '[type_params] "(" [parameter_list] ")"\n' ' ["->" expression] ":" suite\n' ' decorators ::= decorator+\n' ' decorator ::= "@" assignment_expression ' @@ -6935,6 +7321,19 @@ '"assignment_expression". Previously, the grammar was much more\n' 'restrictive; see **PEP 614** for details.\n' '\n' + 'A list of type parameters may be given in square brackets ' + 'between the\n' + 'function’s name and the opening parenthesis for its parameter ' + 'list.\n' + 'This indicates to static type checkers that the function is ' + 'generic.\n' + 'At runtime, the type parameters can be retrieved from the ' + 'function’s\n' + '"__type_params__" attribute. See Generic functions for more.\n' + '\n' + 'Changed in version 3.12: Type parameter lists are new in Python ' + '3.12.\n' + '\n' 'When one or more *parameters* have the form *parameter* "="\n' '*expression*, the function is said to have “default parameter ' 'values.â€\n' @@ -7277,19 +7676,24 @@ '\n' 'Some identifiers are only reserved under specific contexts. ' 'These are\n' - 'known as *soft keywords*. The identifiers "match", "case" ' - 'and "_" can\n' - 'syntactically act as keywords in contexts related to the ' - 'pattern\n' - 'matching statement, but this distinction is done at the ' - 'parser level,\n' - 'not when tokenizing.\n' + 'known as *soft keywords*. The identifiers "match", "case", ' + '"type" and\n' + '"_" can syntactically act as keywords in certain contexts, ' + 'but this\n' + 'distinction is done at the parser level, not when ' + 'tokenizing.\n' + '\n' + 'As soft keywords, their use in the grammar is possible while ' + 'still\n' + 'preserving compatibility with existing code that uses these ' + 'names as\n' + 'identifier names.\n' + '\n' + '"match", "case", and "_" are used in the "match" statement. ' + '"type" is\n' + 'used in the "type" statement.\n' '\n' - 'As soft keywords, their use with pattern matching is possible ' - 'while\n' - 'still preserving compatibility with existing code that uses ' - '"match",\n' - '"case" and "_" as identifier names.\n' + 'Changed in version 3.12: "type" is now a soft keyword.\n' '\n' '\n' 'Reserved classes of identifiers\n' @@ -7809,6 +8213,10 @@ '\n' '* "import" statements.\n' '\n' + '* "type" statements.\n' + '\n' + '* type parameter lists.\n' + '\n' 'The "import" statement of the form "from ... import *" binds all ' 'names\n' 'defined in the imported module, except those beginning with an\n' @@ -7908,7 +8316,8 @@ 'scope.\n' '"SyntaxError" is raised at compile time if the given name does ' 'not\n' - 'exist in any enclosing function scope.\n' + 'exist in any enclosing function scope. Type parameters cannot be\n' + 'rebound with the "nonlocal" statement.\n' '\n' 'The namespace for a module is automatically created the first time ' 'a\n' @@ -7930,18 +8339,156 @@ 'of\n' 'the class. The scope of names defined in a class block is limited ' 'to\n' - 'the class block; it does not extend to the code blocks of methods ' - '–\n' - 'this includes comprehensions and generator expressions since they ' - 'are\n' - 'implemented using a function scope. This means that the ' - 'following\n' - 'will fail:\n' + 'the class block; it does not extend to the code blocks of ' + 'methods.\n' + 'This includes comprehensions and generator expressions, but it ' + 'does\n' + 'not include annotation scopes, which have access to their ' + 'enclosing\n' + 'class scopes. This means that the following will fail:\n' '\n' ' class A:\n' ' a = 42\n' ' b = list(a + i for i in range(10))\n' '\n' + 'However, the following will succeed:\n' + '\n' + ' class A:\n' + ' type Alias = Nested\n' + ' class Nested: pass\n' + '\n' + " print(A.Alias.__value__) # \n" + '\n' + '\n' + 'Annotation scopes\n' + '=================\n' + '\n' + 'Type parameter lists and "type" statements introduce *annotation\n' + 'scopes*, which behave mostly like function scopes, but with some\n' + 'exceptions discussed below. *Annotations* currently do not use\n' + 'annotation scopes, but they are expected to use annotation scopes ' + 'in\n' + 'Python 3.13 when **PEP 649** is implemented.\n' + '\n' + 'Annotation scopes are used in the following contexts:\n' + '\n' + '* Type parameter lists for generic type aliases.\n' + '\n' + '* Type parameter lists for generic functions. A generic ' + 'function’s\n' + ' annotations are executed within the annotation scope, but its\n' + ' defaults and decorators are not.\n' + '\n' + '* Type parameter lists for generic classes. A generic class’s ' + 'base\n' + ' classes and keyword arguments are executed within the ' + 'annotation\n' + ' scope, but its decorators are not.\n' + '\n' + '* The bounds and constraints for type variables (lazily ' + 'evaluated).\n' + '\n' + '* The value of type aliases (lazily evaluated).\n' + '\n' + 'Annotation scopes differ from function scopes in the following ' + 'ways:\n' + '\n' + '* Annotation scopes have access to their enclosing class ' + 'namespace. If\n' + ' an annotation scope is immediately within a class scope, or ' + 'within\n' + ' another annotation scope that is immediately within a class ' + 'scope,\n' + ' the code in the annotation scope can use names defined in the ' + 'class\n' + ' scope as if it were executed directly within the class body. ' + 'This\n' + ' contrasts with regular functions defined within classes, which\n' + ' cannot access names defined in the class scope.\n' + '\n' + '* Expressions in annotation scopes cannot contain "yield", "yield\n' + ' from", "await", or ":=" expressions. (These expressions are ' + 'allowed\n' + ' in other scopes contained within the annotation scope.)\n' + '\n' + '* Names defined in annotation scopes cannot be rebound with ' + '"nonlocal"\n' + ' statements in inner scopes. This includes only type parameters, ' + 'as\n' + ' no other syntactic elements that can appear within annotation ' + 'scopes\n' + ' can introduce new names.\n' + '\n' + '* While annotation scopes have an internal name, that name is not\n' + ' reflected in the *__qualname__* of objects defined within the ' + 'scope.\n' + ' Instead, the "__qualname__" of such objects is as if the object ' + 'were\n' + ' defined in the enclosing scope.\n' + '\n' + 'New in version 3.12: Annotation scopes were introduced in Python ' + '3.12\n' + 'as part of **PEP 695**.\n' + '\n' + '\n' + 'Lazy evaluation\n' + '===============\n' + '\n' + 'The values of type aliases created through the "type" statement ' + 'are\n' + '*lazily evaluated*. The same applies to the bounds and constraints ' + 'of\n' + 'type variables created through the type parameter syntax. This ' + 'means\n' + 'that they are not evaluated when the type alias or type variable ' + 'is\n' + 'created. Instead, they are only evaluated when doing so is ' + 'necessary\n' + 'to resolve an attribute access.\n' + '\n' + 'Example:\n' + '\n' + ' >>> type Alias = 1/0\n' + ' >>> Alias.__value__\n' + ' Traceback (most recent call last):\n' + ' ...\n' + ' ZeroDivisionError: division by zero\n' + ' >>> def func[T: 1/0](): pass\n' + ' >>> T = func.__type_params__[0]\n' + ' >>> T.__bound__\n' + ' Traceback (most recent call last):\n' + ' ...\n' + ' ZeroDivisionError: division by zero\n' + '\n' + 'Here the exception is raised only when the "__value__" attribute ' + 'of\n' + 'the type alias or the "__bound__" attribute of the type variable ' + 'is\n' + 'accessed.\n' + '\n' + 'This behavior is primarily useful for references to types that ' + 'have\n' + 'not yet been defined when the type alias or type variable is ' + 'created.\n' + 'For example, lazy evaluation enables creation of mutually ' + 'recursive\n' + 'type aliases:\n' + '\n' + ' from typing import Literal\n' + '\n' + ' type SimpleExpr = int | Parenthesized\n' + ' type Parenthesized = tuple[Literal["("], Expr, Literal[")"]]\n' + ' type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], ' + 'Expr]\n' + '\n' + 'Lazily evaluated values are evaluated in annotation scope, which ' + 'means\n' + 'that names that appear inside the lazily evaluated value are ' + 'looked up\n' + 'as if they were used in the immediately enclosing scope.\n' + '\n' + 'New in version 3.12.\n' + '\n' '\n' 'Builtins and restricted execution\n' '=================================\n' @@ -9105,6 +9652,14 @@ '\n' ' New in version 3.3.\n' '\n' + 'definition.__type_params__\n' + '\n' + ' The type parameters of generic classes, functions, and ' + 'type\n' + ' aliases.\n' + '\n' + ' New in version 3.12.\n' + '\n' 'class.__mro__\n' '\n' ' This attribute is a tuple of classes that are considered ' @@ -13430,6 +13985,14 @@ '| |\n' ' ' '+---------------------------+---------------------------------+-------------+\n' + ' | "__type_params__" | A tuple containing the type ' + '| Writable |\n' + ' | | parameters of a generic ' + '| |\n' + ' | | function. ' + '| |\n' + ' ' + '+---------------------------+---------------------------------+-------------+\n' '\n' ' Most of the attributes labelled “Writable†check the type of ' 'the\n' @@ -13754,6 +14317,10 @@ ' with "__annotations__", please see Annotations Best\n' ' Practices.\n' '\n' + ' "__type_params__"\n' + ' A tuple containing the type parameters of a generic ' + 'class.\n' + '\n' 'Class instances\n' ' A class instance is created by calling a class object (see ' 'above).\n' diff --git a/Misc/NEWS.d/3.12.0b2.rst b/Misc/NEWS.d/3.12.0b2.rst new file mode 100644 index 00000000000000..482ea8753032d3 --- /dev/null +++ b/Misc/NEWS.d/3.12.0b2.rst @@ -0,0 +1,530 @@ +.. date: 2023-06-01-03-24-58 +.. gh-issue: 103142 +.. nonce: GLWDMX +.. release date: 2023-06-06 +.. section: Security + +The version of OpenSSL used in our binary builds has been upgraded to 1.1.1u +to address several CVEs. + +.. + +.. date: 2023-05-24-09-29-08 +.. gh-issue: 99108 +.. nonce: hwS2cr +.. section: Security + +Refresh our new HACL* built-in :mod:`hashlib` code from upstream. Built-in +SHA2 should be faster and an issue with SHA3 on 32-bit platforms is fixed. + +.. + +.. date: 2023-06-06-11-37-53 +.. gh-issue: 105259 +.. nonce: E2BGKL +.. section: Core and Builtins + +Don't include newline character for trailing ``NEWLINE`` tokens emitted in +the :mod:`tokenize` module. Patch by Pablo Galindo + +.. + +.. date: 2023-06-05-17-35-50 +.. gh-issue: 105324 +.. nonce: BqhiJJ +.. section: Core and Builtins + +Fix the main function of the :mod:`tokenize` module when reading from +``sys.stdin``. Patch by Pablo Galindo + +.. + +.. date: 2023-06-02-17-39-19 +.. gh-issue: 98963 +.. nonce: J4wJgk +.. section: Core and Builtins + +Restore the ability for a subclass of :class:`property` to define +``__slots__`` or otherwise be dict-less by ignoring failures to set a +docstring on such a class. This behavior had regressed in 3.12beta1. An +:exc:`AttributeError` where there had not previously been one was disruptive +to existing code. + +.. + +.. date: 2023-06-02-11-37-12 +.. gh-issue: 105194 +.. nonce: 4eu56B +.. section: Core and Builtins + +Do not escape with backslashes f-string format specifiers. Patch by Pablo +Galindo + +.. + +.. date: 2023-06-01-11-37-03 +.. gh-issue: 105162 +.. nonce: r8VCXk +.. section: Core and Builtins + +Fixed bug in generator.close()/throw() where an inner iterator would be +ignored when the outer iterator was instrumented. + +.. + +.. date: 2023-05-31-19-35-22 +.. gh-issue: 105164 +.. nonce: 6Wajph +.. section: Core and Builtins + +Ensure annotations are set up correctly if the only annotation in a block is +within a :keyword:`match` block. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-05-31-08-10-59 +.. gh-issue: 104799 +.. nonce: 8kDWti +.. section: Core and Builtins + +Attributes of :mod:`ast` nodes that are lists now default to the empty list +if omitted. This means that some code that previously raised +:exc:`TypeError` when the AST node was used will now proceed with the empty +list instead. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-05-30-08-09-43 +.. gh-issue: 105035 +.. nonce: OWUlHy +.. section: Core and Builtins + +Fix :func:`super` calls on types with custom :attr:`tp_getattro` +implementation (e.g. meta-types.) + +.. + +.. date: 2023-05-27-21-50-48 +.. gh-issue: 105017 +.. nonce: 4sDyDV +.. section: Core and Builtins + +Show CRLF lines in the tokenize string attribute in both NL and NEWLINE +tokens. Patch by Marta Gómez. + +.. + +.. date: 2023-05-27-16-57-11 +.. gh-issue: 105013 +.. nonce: IsDgDY +.. section: Core and Builtins + +Fix handling of multiline parenthesized lambdas in +:func:`inspect.getsource`. Patch by Pablo Galindo + +.. + +.. date: 2023-05-27-16-23-16 +.. gh-issue: 105017 +.. nonce: KQrsC0 +.. section: Core and Builtins + +Do not include an additional final ``NL`` token when parsing files having +CRLF lines. Patch by Marta Gómez. + +.. + +.. date: 2023-05-26-15-16-11 +.. gh-issue: 104976 +.. nonce: 6dLitD +.. section: Core and Builtins + +Ensure that trailing ``DEDENT`` :class:`tokenize.TokenInfo` objects emitted +by the :mod:`tokenize` module are reported as in Python 3.11. Patch by Pablo +Galindo + +.. + +.. date: 2023-05-26-14-09-47 +.. gh-issue: 104972 +.. nonce: El2UjE +.. section: Core and Builtins + +Ensure that the ``line`` attribute in :class:`tokenize.TokenInfo` objects in +the :mod:`tokenize` module are always correct. Patch by Pablo Galindo + +.. + +.. date: 2023-05-25-21-40-39 +.. gh-issue: 104955 +.. nonce: LZx7jf +.. section: Core and Builtins + +Fix signature for the new :meth:`~object.__release_buffer__` slot. Patch by +Jelle Zijlstra. + +.. + +.. date: 2023-05-24-12-10-54 +.. gh-issue: 104690 +.. nonce: HX3Jou +.. section: Core and Builtins + +Starting new threads and process creation through :func:`os.fork` during +interpreter shutdown (such as from :mod:`atexit` handlers) is no longer +supported. It can lead to race condition between the main Python runtime +thread freeing thread states while internal :mod:`threading` routines are +trying to allocate and use the state of just created threads. Or forked +children trying to use the mid-shutdown runtime and thread state in the +child process. + +.. + +.. date: 2023-05-24-10-19-35 +.. gh-issue: 104879 +.. nonce: v-29NL +.. section: Core and Builtins + +Fix crash when accessing the ``__module__`` attribute of type aliases +defined outside a module. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-05-24-09-59-56 +.. gh-issue: 104825 +.. nonce: mQesie +.. section: Core and Builtins + +Tokens emitted by the :mod:`tokenize` module do not include an implicit +``\n`` character in the ``line`` attribute anymore. Patch by Pablo Galindo + +.. + +.. date: 2023-06-04-12-16-47 +.. gh-issue: 105280 +.. nonce: srRbCe +.. section: Library + +Fix bug where ``isinstance([], collections.abc.Mapping)`` could evaluate to +``True`` if garbage collection happened at the wrong time. The bug was +caused by changes to the implementation of :class:`typing.Protocol` in +Python 3.12. + +.. + +.. date: 2023-06-02-14-57-11 +.. gh-issue: 105239 +.. nonce: SAmuuj +.. section: Library + +Fix longstanding bug where ``issubclass(object, typing.Protocol)`` would +evaluate to ``True`` in some edge cases. Patch by Alex Waygood. + +.. + +.. date: 2023-06-02-02-38-26 +.. gh-issue: 105080 +.. nonce: 2imGMg +.. section: Library + +Fixed inconsistent signature on derived classes for +:func:`inspect.signature` + +.. + +.. date: 2023-05-31-16-58-42 +.. gh-issue: 105144 +.. nonce: Oqfn0V +.. section: Library + +Fix a recent regression in the :mod:`typing` module. The regression meant +that doing ``class Foo(X, typing.Protocol)``, where ``X`` was a class that +had :class:`abc.ABCMeta` as its metaclass, would then cause subsequent +``isinstance(1, X)`` calls to erroneously raise :exc:`TypeError`. Patch by +Alex Waygood. + +.. + +.. date: 2023-05-30-21-27-41 +.. gh-issue: 105113 +.. nonce: bDUPl_ +.. section: Library + +Improve performance of :meth:`pathlib.PurePath.match` by compiling an +:class:`re.Pattern` object for the entire pattern. + +.. + +.. date: 2023-05-26-01-31-30 +.. gh-issue: 101588 +.. nonce: RaqxFy +.. section: Library + +Deprecate undocumented copy/deepcopy/pickle support for itertools. + +.. + +.. date: 2023-05-25-23-34-54 +.. gh-issue: 103631 +.. nonce: x5Urye +.. section: Library + +Fix ``pathlib.PurePosixPath(pathlib.PureWindowsPath(...))`` not converting +path separators to restore 3.11 compatible behavior. + +.. + +.. date: 2023-05-25-22-54-20 +.. gh-issue: 104947 +.. nonce: hi6TUr +.. section: Library + +Make comparisons between :class:`pathlib.PureWindowsPath` objects consistent +across Windows and Posix to match 3.11 behavior. + +.. + +.. date: 2023-05-25-08-50-47 +.. gh-issue: 104935 +.. nonce: -rm1BR +.. section: Library + +Fix bugs with the interaction between :func:`typing.runtime_checkable` and +:class:`typing.Generic` that were introduced by the :pep:`695` +implementation. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-05-24-09-34-23 +.. gh-issue: 104874 +.. nonce: oqyJSy +.. section: Library + +Document the ``__name__`` and ``__supertype__`` attributes of +:class:`typing.NewType`. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-05-23-18-31-49 +.. gh-issue: 104799 +.. nonce: MJYOw6 +.. section: Library + +Adjust the location of the (see :pep:`695`) ``type_params`` field on +:class:`ast.ClassDef`, :class:`ast.AsyncFunctionDef`, and +:class:`ast.FunctionDef` to better preserve backward compatibility. Patch by +Jelle Zijlstra + +.. + +.. date: 2023-05-23-17-43-52 +.. gh-issue: 104797 +.. nonce: NR7KzF +.. section: Library + +Allow :class:`typing.Protocol` classes to inherit from +:class:`collections.abc.Buffer`. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-05-22-18-39-53 +.. gh-issue: 104372 +.. nonce: 7tDRaK +.. section: Library + +On Linux where :mod:`subprocess` can use the ``vfork()`` syscall for faster +spawning, prevent the parent process from blocking other threads by dropping +the GIL while it waits for the vfork'ed child process ``exec()`` outcome. +This prevents spawning a binary from a slow filesystem from blocking the +rest of the application. + +.. + +.. date: 2023-05-19-19-46-22 +.. gh-issue: 99108 +.. nonce: wqCg0t +.. section: Library + +We now release the GIL around built-in :mod:`hashlib` computations of +reasonable size for the SHA families and MD5 hash functions, matching what +our OpenSSL backed hash computations already does. + +.. + +.. date: 2023-05-11-23-03-00 +.. gh-issue: 104399 +.. nonce: MMatTP +.. section: Library + +Prepare the ``_tkinter`` module for building with Tcl 9.0 and future +libtommath by replacing usage of deprecated functions +:c:func:`mp_to_unsigned_bin_n` and :c:func:`mp_unsigned_bin_size` when +necessary. + +.. + +.. date: 2023-02-18-22-55-48 +.. gh-issue: 102024 +.. nonce: RUmg_D +.. section: Library + +Reduce calls of ``_idle_semaphore.release()`` in +:func:`concurrent.futures.thread._worker`. + +.. + +.. date: 2023-05-28-21-01-00 +.. gh-issue: 89455 +.. nonce: qAKRrA +.. section: Documentation + +Add missing documentation for the ``max_group_depth`` and +``max_group_width`` parameters and the ``exceptions`` attribute of the +:class:`traceback.TracebackException` class. + +.. + +.. date: 2023-05-28-19-08-42 +.. gh-issue: 89412 +.. nonce: j4cg7K +.. section: Documentation + +Add missing documentation for the ``end_lineno`` and ``end_offset`` +attributes of the :class:`traceback.TracebackException` class. + +.. + +.. date: 2023-05-25-22-34-31 +.. gh-issue: 104943 +.. nonce: J2v1Pc +.. section: Documentation + +Remove mentions of old Python versions in :class:`typing.NamedTuple`. + +.. + +.. date: 2023-06-06-09-08-10 +.. gh-issue: 90005 +.. nonce: 8mmeJQ +.. section: Build + +Fix a regression in :file:`configure` where we could end up unintentionally +linking with ``libbsd``. + +.. + +.. date: 2023-05-26-15-44-20 +.. gh-issue: 89886 +.. nonce: _iSW-p +.. section: Build + +Autoconf 2.71 and aclocal 1.16.4 is now required to regenerate +:file:`!configure`. + +.. + +.. date: 2023-05-31-16-14-31 +.. gh-issue: 105146 +.. nonce: gNjqq8 +.. section: Windows + +Updated the links at the end of the installer to point to Discourse rather +than the mailing lists. + +.. + +.. date: 2023-05-29-17-09-31 +.. gh-issue: 103646 +.. nonce: U8oGQx +.. section: Windows + +When installed from the Microsoft Store, ``pip`` no longer defaults to +per-user installs. However, as the install directory is unwritable, it +should automatically decide to do a per-user install anyway. This should +resolve issues when ``pip`` is passed an option that conflicts with +``--user``. + +.. + +.. date: 2023-05-29-11-38-53 +.. gh-issue: 88745 +.. nonce: cldf9G +.. section: Windows + +Improve performance of :func:`shutil.copy2` by using the operating system's +``CopyFile2`` function. This may result in subtle changes to metadata copied +along with some files, bringing them in line with normal OS behavior. + +.. + +.. date: 2023-05-24-21-00-57 +.. gh-issue: 104820 +.. nonce: ibyrpp +.. section: Windows + +Fixes :func:`~os.stat` and related functions on file systems that do not +support file ID requests. This includes FAT32 and exFAT. + +.. + +.. date: 2023-05-23-19-26-28 +.. gh-issue: 104803 +.. nonce: gqxYml +.. section: Windows + +Add :func:`os.path.isdevdrive` to detect whether a path is on a Windows Dev +Drive. Returns ``False`` on platforms that do not support Dev Drive, and is +absent on non-Windows platforms. + +.. + +.. date: 2023-05-30-23-30-46 +.. gh-issue: 103142 +.. nonce: 55lMXQ +.. section: macOS + +Update macOS installer to use OpenSSL 1.1.1u. + +.. + +.. date: 2023-05-23-17-19-49 +.. gh-issue: 104719 +.. nonce: rvYXH- +.. section: IDLE + +Remove IDLE's modification of tokenize.tabsize and test other uses of +tokenize data and methods. + +.. + +.. date: 2023-05-30-17-45-32 +.. gh-issue: 105115 +.. nonce: iRho1K +.. section: C API + +``PyTypeObject.tp_bases`` (and ``tp_mro``) for builtin static types are now +shared by all interpreters, whereas in 3.12-beta1 they were stored on +``PyInterpreterState``. Also note that now the tuples are immortal objects. + +.. + +.. date: 2023-05-30-10-15-13 +.. gh-issue: 105071 +.. nonce: dPtp7c +.. section: C API + +Add ``PyUnstable_Exc_PrepReraiseStar`` to the unstable C api to expose the +implementation of :keyword:`except* `. + +.. + +.. date: 2023-05-19-10-22-34 +.. gh-issue: 104668 +.. nonce: MLX1g9 +.. section: C API + +Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer` +in subinterpreters, since it's generally difficult to avoid using global +state in their registered callbacks. This also avoids situations where +extensions may find themselves running in a subinterpreter they don't +support (or haven't yet been loaded in). diff --git a/Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst b/Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst deleted file mode 100644 index 83559545e86141..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-05-26-15-44-20.gh-issue-89886._iSW-p.rst +++ /dev/null @@ -1,2 +0,0 @@ -Autoconf 2.71 and aclocal 1.16.4 is now required to regenerate -:file:`!configure`. diff --git a/Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst b/Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst deleted file mode 100644 index 0a23fbf0c0fbdd..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-06-06-09-08-10.gh-issue-90005.8mmeJQ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a regression in :file:`configure` where we could end up unintentionally linking with ``libbsd``. diff --git a/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst b/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst deleted file mode 100644 index 7b882afd7f81a0..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst +++ /dev/null @@ -1,5 +0,0 @@ -Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer` -in subinterpreters, since it's generally difficult to avoid using global -state in their registered callbacks. This also avoids situations where -extensions may find themselves running in a subinterpreter they don't -support (or haven't yet been loaded in). diff --git a/Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst b/Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst deleted file mode 100644 index 3d916fcb961f62..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-05-30-10-15-13.gh-issue-105071.dPtp7c.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``PyUnstable_Exc_PrepReraiseStar`` to the unstable C api to expose the implementation of :keyword:`except* `. diff --git a/Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst b/Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst deleted file mode 100644 index 595cc0e2013d96..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-05-30-17-45-32.gh-issue-105115.iRho1K.rst +++ /dev/null @@ -1,3 +0,0 @@ -``PyTypeObject.tp_bases`` (and ``tp_mro``) for builtin static types are now -shared by all interpreters, whereas in 3.12-beta1 they were stored on -``PyInterpreterState``. Also note that now the tuples are immortal objects. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst deleted file mode 100644 index caf5d3527085f3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst +++ /dev/null @@ -1,2 +0,0 @@ -Tokens emitted by the :mod:`tokenize` module do not include an implicit -``\n`` character in the ``line`` attribute anymore. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst deleted file mode 100644 index 235f4180642be6..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-10-19-35.gh-issue-104879.v-29NL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash when accessing the ``__module__`` attribute of type aliases -defined outside a module. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst deleted file mode 100644 index 7934dd23b10691..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-12-10-54.gh-issue-104690.HX3Jou.rst +++ /dev/null @@ -1,6 +0,0 @@ -Starting new threads and process creation through :func:`os.fork` during interpreter -shutdown (such as from :mod:`atexit` handlers) is no longer supported. It can lead -to race condition between the main Python runtime thread freeing thread states while -internal :mod:`threading` routines are trying to allocate and use the state of just -created threads. Or forked children trying to use the mid-shutdown runtime and thread -state in the child process. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst deleted file mode 100644 index 9fccf2a41ffb6f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-25-21-40-39.gh-issue-104955.LZx7jf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix signature for the new :meth:`~object.__release_buffer__` slot. Patch by Jelle -Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst deleted file mode 100644 index 05d50c108c7b77..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-26-14-09-47.gh-issue-104972.El2UjE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure that the ``line`` attribute in :class:`tokenize.TokenInfo` objects in -the :mod:`tokenize` module are always correct. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst deleted file mode 100644 index 377e8e76362687..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-26-15-16-11.gh-issue-104976.6dLitD.rst +++ /dev/null @@ -1,3 +0,0 @@ -Ensure that trailing ``DEDENT`` :class:`tokenize.TokenInfo` objects emitted -by the :mod:`tokenize` module are reported as in Python 3.11. Patch by Pablo -Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst deleted file mode 100644 index d41a2169ccb3de..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-23-16.gh-issue-105017.KQrsC0.rst +++ /dev/null @@ -1 +0,0 @@ -Do not include an additional final ``NL`` token when parsing files having CRLF lines. Patch by Marta Gómez. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst deleted file mode 100644 index a9917c2849982a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-16-57-11.gh-issue-105013.IsDgDY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix handling of multiline parenthesized lambdas in -:func:`inspect.getsource`. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst deleted file mode 100644 index 02d653c2d658eb..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-27-21-50-48.gh-issue-105017.4sDyDV.rst +++ /dev/null @@ -1 +0,0 @@ -Show CRLF lines in the tokenize string attribute in both NL and NEWLINE tokens. Patch by Marta Gómez. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst deleted file mode 100644 index c0ee2da9d45037..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-30-08-09-43.gh-issue-105035.OWUlHy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`super` calls on types with custom :attr:`tp_getattro` -implementation (e.g. meta-types.) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst deleted file mode 100644 index e1fe47f862529c..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-31-08-10-59.gh-issue-104799.8kDWti.rst +++ /dev/null @@ -1,4 +0,0 @@ -Attributes of :mod:`ast` nodes that are lists now default to the empty list -if omitted. This means that some code that previously raised -:exc:`TypeError` when the AST node was used will now proceed with the empty -list instead. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst deleted file mode 100644 index 7d3486c3b6e98a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure annotations are set up correctly if the only annotation in a block is -within a :keyword:`match` block. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst deleted file mode 100644 index adb4e8478d9c55..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-01-11-37-03.gh-issue-105162.r8VCXk.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed bug in generator.close()/throw() where an inner iterator would be -ignored when the outer iterator was instrumented. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst deleted file mode 100644 index adee74f5894b54..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-11-37-12.gh-issue-105194.4eu56B.rst +++ /dev/null @@ -1,2 +0,0 @@ -Do not escape with backslashes f-string format specifiers. Patch by Pablo -Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst deleted file mode 100644 index 4caadb0875a188..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-17-39-19.gh-issue-98963.J4wJgk.rst +++ /dev/null @@ -1,4 +0,0 @@ -Restore the ability for a subclass of :class:`property` to define ``__slots__`` -or otherwise be dict-less by ignoring failures to set a docstring on such a -class. This behavior had regressed in 3.12beta1. An :exc:`AttributeError` -where there had not previously been one was disruptive to existing code. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst deleted file mode 100644 index 17275aed338d0d..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-05-17-35-50.gh-issue-105324.BqhiJJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the main function of the :mod:`tokenize` module when reading from -``sys.stdin``. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst deleted file mode 100644 index 75a63033750826..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-11-37-53.gh-issue-105259.E2BGKL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Don't include newline character for trailing ``NEWLINE`` tokens emitted in -the :mod:`tokenize` module. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst b/Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst deleted file mode 100644 index bc4d03b8e95f86..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-05-25-22-34-31.gh-issue-104943.J2v1Pc.rst +++ /dev/null @@ -1 +0,0 @@ -Remove mentions of old Python versions in :class:`typing.NamedTuple`. diff --git a/Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst b/Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst deleted file mode 100644 index 00937e58c98595..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-05-28-19-08-42.gh-issue-89412.j4cg7K.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add missing documentation for the ``end_lineno`` and ``end_offset`` attributes -of the :class:`traceback.TracebackException` class. diff --git a/Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst b/Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst deleted file mode 100644 index fdfa4357f001b5..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-05-28-21-01-00.gh-issue-89455.qAKRrA.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add missing documentation for the ``max_group_depth`` and ``max_group_width`` -parameters and the ``exceptions`` attribute of the -:class:`traceback.TracebackException` class. diff --git a/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst b/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst deleted file mode 100644 index 3fbe04ba4f6844..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove IDLE's modification of tokenize.tabsize and test other uses of -tokenize data and methods. diff --git a/Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst b/Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst deleted file mode 100644 index bb9e28e06c5554..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-18-22-55-48.gh-issue-102024.RUmg_D.rst +++ /dev/null @@ -1 +0,0 @@ -Reduce calls of ``_idle_semaphore.release()`` in :func:`concurrent.futures.thread._worker`. diff --git a/Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst b/Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst deleted file mode 100644 index 84cc888635b415..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-11-23-03-00.gh-issue-104399.MMatTP.rst +++ /dev/null @@ -1,4 +0,0 @@ -Prepare the ``_tkinter`` module for building with Tcl 9.0 and future -libtommath by replacing usage of deprecated functions -:c:func:`mp_to_unsigned_bin_n` and :c:func:`mp_unsigned_bin_size` -when necessary. diff --git a/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst b/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst deleted file mode 100644 index b595f1893609cc..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst +++ /dev/null @@ -1,3 +0,0 @@ -We now release the GIL around built-in :mod:`hashlib` computations of -reasonable size for the SHA families and MD5 hash functions, matching -what our OpenSSL backed hash computations already does. diff --git a/Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst b/Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst deleted file mode 100644 index ea13ec85543ca2..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-22-18-39-53.gh-issue-104372.7tDRaK.rst +++ /dev/null @@ -1,5 +0,0 @@ -On Linux where :mod:`subprocess` can use the ``vfork()`` syscall for faster -spawning, prevent the parent process from blocking other threads by dropping -the GIL while it waits for the vfork'ed child process ``exec()`` outcome. -This prevents spawning a binary from a slow filesystem from blocking the -rest of the application. diff --git a/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst b/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst deleted file mode 100644 index 60c9a0601cdc9a..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Allow :class:`typing.Protocol` classes to inherit from -:class:`collections.abc.Buffer`. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst b/Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst deleted file mode 100644 index 614918d7572969..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-23-18-31-49.gh-issue-104799.MJYOw6.rst +++ /dev/null @@ -1,4 +0,0 @@ -Adjust the location of the (see :pep:`695`) ``type_params`` field on -:class:`ast.ClassDef`, :class:`ast.AsyncFunctionDef`, and -:class:`ast.FunctionDef` to better preserve backward compatibility. Patch by -Jelle Zijlstra diff --git a/Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst b/Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst deleted file mode 100644 index 9d5904bc146421..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-24-09-34-23.gh-issue-104874.oqyJSy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document the ``__name__`` and ``__supertype__`` attributes of -:class:`typing.NewType`. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst b/Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst deleted file mode 100644 index 7af52bce2c9185..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-25-08-50-47.gh-issue-104935.-rm1BR.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix bugs with the interaction between :func:`typing.runtime_checkable` and -:class:`typing.Generic` that were introduced by the :pep:`695` -implementation. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst b/Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst deleted file mode 100644 index 4af73d73d2a717..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-25-22-54-20.gh-issue-104947.hi6TUr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make comparisons between :class:`pathlib.PureWindowsPath` objects consistent -across Windows and Posix to match 3.11 behavior. diff --git a/Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst b/Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst deleted file mode 100644 index d1eb2d3ed6191f..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-25-23-34-54.gh-issue-103631.x5Urye.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``pathlib.PurePosixPath(pathlib.PureWindowsPath(...))`` not converting -path separators to restore 3.11 compatible behavior. diff --git a/Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst b/Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst deleted file mode 100644 index 07e3dc468f7d9a..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-26-01-31-30.gh-issue-101588.RaqxFy.rst +++ /dev/null @@ -1 +0,0 @@ -Deprecate undocumented copy/deepcopy/pickle support for itertools. diff --git a/Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst b/Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst deleted file mode 100644 index 59164ae4734e51..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-30-21-27-41.gh-issue-105113.bDUPl_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :meth:`pathlib.PurePath.match` by compiling an -:class:`re.Pattern` object for the entire pattern. diff --git a/Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst b/Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst deleted file mode 100644 index 7e4d6fbc4911ba..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-31-16-58-42.gh-issue-105144.Oqfn0V.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix a recent regression in the :mod:`typing` module. The regression meant -that doing ``class Foo(X, typing.Protocol)``, where ``X`` was a class that -had :class:`abc.ABCMeta` as its metaclass, would then cause subsequent -``isinstance(1, X)`` calls to erroneously raise :exc:`TypeError`. Patch by -Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst b/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst deleted file mode 100644 index efe8365a7644be..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed inconsistent signature on derived classes for :func:`inspect.signature` diff --git a/Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst b/Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst deleted file mode 100644 index 35e1b1a217b3a4..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-02-14-57-11.gh-issue-105239.SAmuuj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix longstanding bug where ``issubclass(object, typing.Protocol)`` would -evaluate to ``True`` in some edge cases. Patch by Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst b/Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst deleted file mode 100644 index 8e469646604316..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-04-12-16-47.gh-issue-105280.srRbCe.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix bug where ``isinstance([], collections.abc.Mapping)`` could evaluate to -``True`` if garbage collection happened at the wrong time. The bug was -caused by changes to the implementation of :class:`typing.Protocol` in -Python 3.12. diff --git a/Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst b/Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst deleted file mode 100644 index 312ba89454b5b8..00000000000000 --- a/Misc/NEWS.d/next/Security/2023-05-24-09-29-08.gh-issue-99108.hwS2cr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Refresh our new HACL* built-in :mod:`hashlib` code from upstream. Built-in -SHA2 should be faster and an issue with SHA3 on 32-bit platforms is fixed. diff --git a/Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst b/Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst deleted file mode 100644 index 7e0836879e4f81..00000000000000 --- a/Misc/NEWS.d/next/Security/2023-06-01-03-24-58.gh-issue-103142.GLWDMX.rst +++ /dev/null @@ -1,2 +0,0 @@ -The version of OpenSSL used in our binary builds has been upgraded to 1.1.1u -to address several CVEs. diff --git a/Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst b/Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst deleted file mode 100644 index d2242c76189970..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-05-23-19-26-28.gh-issue-104803.gqxYml.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add :func:`os.path.isdevdrive` to detect whether a path is on a Windows Dev -Drive. Returns ``False`` on platforms that do not support Dev Drive, and is -absent on non-Windows platforms. diff --git a/Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst b/Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst deleted file mode 100644 index 5bdfbabfaf28e1..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-05-24-21-00-57.gh-issue-104820.ibyrpp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixes :func:`~os.stat` and related functions on file systems that do not -support file ID requests. This includes FAT32 and exFAT. diff --git a/Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst b/Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst deleted file mode 100644 index 258eb89d50d9f5..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-05-29-11-38-53.gh-issue-88745.cldf9G.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improve performance of :func:`shutil.copy2` by using the operating system's -``CopyFile2`` function. This may result in subtle changes to metadata copied -along with some files, bringing them in line with normal OS behavior. diff --git a/Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst b/Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst deleted file mode 100644 index 71c1e7c6594cbf..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-05-29-17-09-31.gh-issue-103646.U8oGQx.rst +++ /dev/null @@ -1,5 +0,0 @@ -When installed from the Microsoft Store, ``pip`` no longer defaults to -per-user installs. However, as the install directory is unwritable, it -should automatically decide to do a per-user install anyway. This should -resolve issues when ``pip`` is passed an option that conflicts with -``--user``. diff --git a/Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst b/Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst deleted file mode 100644 index 1a5208bc898207..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-05-31-16-14-31.gh-issue-105146.gNjqq8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Updated the links at the end of the installer to point to Discourse rather -than the mailing lists. diff --git a/Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst b/Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst deleted file mode 100644 index 1afd949d6a9f03..00000000000000 --- a/Misc/NEWS.d/next/macOS/2023-05-30-23-30-46.gh-issue-103142.55lMXQ.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use OpenSSL 1.1.1u. diff --git a/README.rst b/README.rst index 596a62108cf1f1..bd1c1b06667aa8 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 beta 1 +This is Python version 3.12.0 beta 2 ===================================== .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From 2bbb557b0f077f8c8b571148e0368472bbbbf5ea Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Jun 2023 16:22:04 +0200 Subject: [PATCH 0133/1206] [3.12] gh-102304: Fix Py_INCREF() stable ABI in debug mode (#104763) (#105352) gh-102304: Fix Py_INCREF() stable ABI in debug mode (#104763) When Python is built in debug mode (if the Py_REF_DEBUG macro is defined), the Py_INCREF() and Py_DECREF() function are now always implemented as opaque functions to avoid leaking implementation details like the "_Py_RefTotal" variable or the _Py_DecRefTotal_DO_NOT_USE_THIS() function. * Remove _Py_IncRefTotal_DO_NOT_USE_THIS() and _Py_DecRefTotal_DO_NOT_USE_THIS() from the stable ABI. * Remove _Py_NegativeRefcount() from limited C API. (cherry picked from commit 92022d8416d9e175800b65c4d71d4e4fb47adcb0) --- Doc/whatsnew/3.12.rst | 9 +++++++++ Include/object.h | 22 ++++++++-------------- Lib/test/test_stable_abi_ctypes.py | 2 -- Misc/stable_abi.toml | 9 --------- PC/python3dll.c | 2 -- 5 files changed, 17 insertions(+), 27 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 287549fe30ec1a..4a755975b788b6 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1535,6 +1535,15 @@ Build Changes :file:`!configure`. (Contributed by Christian Heimes in :gh:`89886`.) +* C extensions built with the :ref:`limited C API ` + on :ref:`Python build in debug mode ` no longer support Python + 3.9 and older. In this configuration, :c:func:`Py_INCREF` and + :c:func:`Py_DECREF` are now always implemented as opaque function calls, + but the called functions were added to Python 3.10. Build C extensions + with a release build of Python or with Python 3.12 and older, to keep support + for Python 3.9 and older. + (Contributed by Victor Stinner in :gh:`102304`.) + C API Changes ============= diff --git a/Include/object.h b/Include/object.h index c2fee85a2c38f6..dc5b087db2f467 100644 --- a/Include/object.h +++ b/Include/object.h @@ -585,20 +585,14 @@ decision that's up to the implementer of each new type so if you want, you can count such references to the type object.) */ -#ifdef Py_REF_DEBUG -# if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030A0000 -extern Py_ssize_t _Py_RefTotal; -# define _Py_INC_REFTOTAL() _Py_RefTotal++ -# define _Py_DEC_REFTOTAL() _Py_RefTotal-- -# elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 +#if defined(Py_REF_DEBUG) && !defined(Py_LIMITED_API) +PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, + PyObject *op); PyAPI_FUNC(void) _Py_IncRefTotal_DO_NOT_USE_THIS(void); PyAPI_FUNC(void) _Py_DecRefTotal_DO_NOT_USE_THIS(void); # define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() # define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS() -# endif -PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, - PyObject *op); -#endif /* Py_REF_DEBUG */ +#endif // Py_REF_DEBUG && !Py_LIMITED_API PyAPI_FUNC(void) _Py_Dealloc(PyObject *); @@ -616,8 +610,8 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *); static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) { -#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030A0000 - // Stable ABI for Python 3.10 built in debug mode. +#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) + // Stable ABI for Python built in debug mode _Py_IncRef(op); #else // Non-limited C API and limited C API for Python 3.9 and older access @@ -647,8 +641,8 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) # define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op)) #endif -#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030A0000 -// Stable ABI for limited C API version 3.10 of Python debug build +#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) +// Stable ABI for Python built in debug mode static inline void Py_DECREF(PyObject *op) { _Py_DecRef(op); } diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 68983675488389..8cad71c7c34545 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -917,8 +917,6 @@ def test_windows_feature_macros(self): ) if feature_macros['Py_REF_DEBUG']: SYMBOL_NAMES += ( - '_Py_DecRefTotal_DO_NOT_USE_THIS', - '_Py_IncRefTotal_DO_NOT_USE_THIS', '_Py_NegativeRefcount', '_Py_RefTotal', ) diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 1db98483f09f77..48299e9b35ff97 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2406,12 +2406,3 @@ added = '3.12' [const.Py_TPFLAGS_ITEMS_AT_END] added = '3.12' - -[function._Py_IncRefTotal_DO_NOT_USE_THIS] - added = '3.12' - ifdef = 'Py_REF_DEBUG' - abi_only = true -[function._Py_DecRefTotal_DO_NOT_USE_THIS] - added = '3.12' - ifdef = 'Py_REF_DEBUG' - abi_only = true diff --git a/PC/python3dll.c b/PC/python3dll.c index 5665d5530e2360..505feef4b986c4 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -17,9 +17,7 @@ EXPORT_FUNC(_Py_BuildValue_SizeT) EXPORT_FUNC(_Py_CheckRecursiveCall) EXPORT_FUNC(_Py_Dealloc) EXPORT_FUNC(_Py_DecRef) -EXPORT_FUNC(_Py_DecRefTotal_DO_NOT_USE_THIS) EXPORT_FUNC(_Py_IncRef) -EXPORT_FUNC(_Py_IncRefTotal_DO_NOT_USE_THIS) EXPORT_FUNC(_Py_NegativeRefcount) EXPORT_FUNC(_Py_VaBuildValue_SizeT) EXPORT_FUNC(_PyArg_Parse_SizeT) From bf62e06e597ddc8179b9b2bf5c9304f81606e104 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:14:55 -0700 Subject: [PATCH 0134/1206] [3.12] gh-94172: Update keyfile removal documentation (GH-105392) (#105402) gh-94172: Update keyfile removal documentation (GH-105392) Remove the "deprecated:: 3.6" markup, since the parameters (like keyfile and certfile) got removed in Python 3.12. (cherry picked from commit 2b8e6e5712a83657333948bc387c81db02549b13) Co-authored-by: Victor Stinner --- Doc/library/ftplib.rst | 8 +------- Doc/library/http.client.rst | 14 ++------------ Doc/library/imaplib.rst | 9 +-------- Doc/library/poplib.rst | 9 +-------- Doc/library/smtplib.rst | 18 ++---------------- 5 files changed, 7 insertions(+), 51 deletions(-) diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index 47054812f9f514..e7fb5b1ae26960 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -107,12 +107,6 @@ The module defines the following items: :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :data:`ssl.HAS_SNI`). - .. deprecated:: 3.6 - *keyfile* and *certfile* are deprecated in favor of *context*. - Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let - :func:`ssl.create_default_context` select the system's trusted CA - certificates for you. - .. versionchanged:: 3.9 If the *timeout* parameter is set to be zero, it will raise a :class:`ValueError` to prevent the creation of a non-blocking socket. @@ -120,7 +114,7 @@ The module defines the following items: Latin-1 to UTF-8 to follow :rfc:`2640`. .. versionchanged:: 3.12 - The deprecated *keyfile* and *certfile* parameters have been removed. + The deprecated *keyfile* and *certfile* parameters have been removed. Here's a sample session using the :class:`FTP_TLS` class:: diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 46d616aae95c96..45291933d635b9 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -95,16 +95,6 @@ The module provides the following classes: :func:`ssl._create_unverified_context` can be passed to the *context* parameter. - .. deprecated:: 3.6 - *key_file* and *cert_file* are deprecated in favor of *context*. - Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let - :func:`ssl.create_default_context` select the system's trusted CA - certificates for you. - - The *check_hostname* parameter is also deprecated; the - :attr:`ssl.SSLContext.check_hostname` attribute of *context* should - be used instead. - .. versionchanged:: 3.8 This class now enables TLS 1.3 :attr:`ssl.SSLContext.post_handshake_auth` for the default *context* or @@ -116,8 +106,8 @@ The module provides the following classes: ALPN protocols with :meth:`~ssl.SSLContext.set_alpn_protocol`. .. versionchanged:: 3.12 - The deprecated *key_file*, *cert_file* and *check_hostname* parameters - have been removed. + The deprecated *key_file*, *cert_file* and *check_hostname* parameters + have been removed. .. class:: HTTPResponse(sock, debuglevel=0, method=None, url=None) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index f1344ae9bb0a49..59d7711f9cbd3c 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -108,18 +108,11 @@ There's also a subclass for secure connections: :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :data:`ssl.HAS_SNI`). - .. deprecated:: 3.6 - - *keyfile* and *certfile* are deprecated in favor of *ssl_context*. - Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let - :func:`ssl.create_default_context` select the system's trusted CA - certificates for you. - .. versionchanged:: 3.9 The optional *timeout* parameter was added. .. versionchanged:: 3.12 - The deprecated *keyfile* and *certfile* parameters have been removed. + The deprecated *keyfile* and *certfile* parameters have been removed. The second subclass allows for connections created by a child process: diff --git a/Doc/library/poplib.rst b/Doc/library/poplib.rst index d8618ce9b60bba..260c4a63d12031 100644 --- a/Doc/library/poplib.rst +++ b/Doc/library/poplib.rst @@ -79,19 +79,12 @@ The :mod:`poplib` module provides two classes: :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :data:`ssl.HAS_SNI`). - .. deprecated:: 3.6 - - *keyfile* and *certfile* are deprecated in favor of *context*. - Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let - :func:`ssl.create_default_context` select the system's trusted CA - certificates for you. - .. versionchanged:: 3.9 If the *timeout* parameter is set to be zero, it will raise a :class:`ValueError` to prevent the creation of a non-blocking socket. .. versionchanged:: 3.12 - The deprecated *keyfile* and *certfile* parameters have been removed. + The deprecated *keyfile* and *certfile* parameters have been removed. One exception is defined as an attribute of the :mod:`poplib` module: diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index 4686232b09ac47..f90274feb6bf9a 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -100,19 +100,12 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :data:`ssl.HAS_SNI`). - .. deprecated:: 3.6 - - *keyfile* and *certfile* are deprecated in favor of *context*. - Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let - :func:`ssl.create_default_context` select the system's trusted CA - certificates for you. - .. versionchanged:: 3.9 If the *timeout* parameter is set to be zero, it will raise a :class:`ValueError` to prevent the creation of a non-blocking socket .. versionchanged:: 3.12 - The deprecated *keyfile* and *certfile* parameters have been removed. + The deprecated *keyfile* and *certfile* parameters have been removed. .. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, \ source_address=None[, timeout]) @@ -407,15 +400,8 @@ An :class:`SMTP` instance has the following methods: If there has been no previous ``EHLO`` or ``HELO`` command this session, this method tries ESMTP ``EHLO`` first. - .. deprecated:: 3.6 - - *keyfile* and *certfile* are deprecated in favor of *context*. - Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let - :func:`ssl.create_default_context` select the system's trusted CA - certificates for you. - .. versionchanged:: 3.12 - The deprecated *keyfile* and *certfile* parameters have been removed. + The deprecated *keyfile* and *certfile* parameters have been removed. :exc:`SMTPHeloError` The server didn't reply properly to the ``HELO`` greeting. From 6fe0a6ba73adb4bc4060ddd0a132072339758c6b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 12:00:17 -0700 Subject: [PATCH 0135/1206] [3.12] sliding_window() recipe: Raise ValueError for non-positive window sizes. Add more tests. (GH-105403) (GH-105405) --- Doc/library/itertools.rst | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index b3decaef9c49d1..56d6599798af20 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -929,9 +929,7 @@ which incur interpreter overhead. def sliding_window(iterable, n): # sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG it = iter(iterable) - window = collections.deque(islice(it, n), maxlen=n) - if len(window) == n: - yield tuple(window) + window = collections.deque(islice(it, n-1), maxlen=n) for x in it: window.append(x) yield tuple(window) @@ -1420,8 +1418,34 @@ The following recipes have a more mathematical flavor: >>> list(grouper('abcdefg', n=3, incomplete='ignore')) [('a', 'b', 'c'), ('d', 'e', 'f')] + >>> list(sliding_window('ABCDEFG', 1)) + [('A',), ('B',), ('C',), ('D',), ('E',), ('F',), ('G',)] + >>> list(sliding_window('ABCDEFG', 2)) + [('A', 'B'), ('B', 'C'), ('C', 'D'), ('D', 'E'), ('E', 'F'), ('F', 'G')] + >>> list(sliding_window('ABCDEFG', 3)) + [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')] >>> list(sliding_window('ABCDEFG', 4)) [('A', 'B', 'C', 'D'), ('B', 'C', 'D', 'E'), ('C', 'D', 'E', 'F'), ('D', 'E', 'F', 'G')] + >>> list(sliding_window('ABCDEFG', 5)) + [('A', 'B', 'C', 'D', 'E'), ('B', 'C', 'D', 'E', 'F'), ('C', 'D', 'E', 'F', 'G')] + >>> list(sliding_window('ABCDEFG', 6)) + [('A', 'B', 'C', 'D', 'E', 'F'), ('B', 'C', 'D', 'E', 'F', 'G')] + >>> list(sliding_window('ABCDEFG', 7)) + [('A', 'B', 'C', 'D', 'E', 'F', 'G')] + >>> list(sliding_window('ABCDEFG', 8)) + [] + >>> try: + ... list(sliding_window('ABCDEFG', -1)) + ... except ValueError: + ... 'zero or negative n not supported' + ... + 'zero or negative n not supported' + >>> try: + ... list(sliding_window('ABCDEFG', 0)) + ... except ValueError: + ... 'zero or negative n not supported' + ... + 'zero or negative n not supported' >>> list(roundrobin('abc', 'd', 'ef')) ['a', 'd', 'e', 'b', 'f', 'c'] From e33add429f8f16340b4c186501bb1e436e66b4cc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 12:27:10 -0700 Subject: [PATCH 0136/1206] gh-92658: Fix typo in docs and tests for `HV_GUID_PARENT` (GH-105267) (cherry picked from commit 3907de12b57b14f674cdcc80ae64350a23af53a0) Co-authored-by: Nikita Sobolev --- Doc/library/socket.rst | 2 +- Lib/test/test_socket.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 5f795af42b812e..f2408cb95ff314 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -666,7 +666,7 @@ Constants HV_GUID_BROADCAST HV_GUID_CHILDREN HV_GUID_LOOPBACK - HV_GUID_LOOPBACK + HV_GUID_PARENT Constants for Windows Hyper-V sockets for host/guest communications. diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 68cdc6eaa91375..0eaf64257c3b81 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -2566,7 +2566,7 @@ def testHyperVConstants(self): socket.HV_GUID_BROADCAST socket.HV_GUID_CHILDREN socket.HV_GUID_LOOPBACK - socket.HV_GUID_LOOPBACK + socket.HV_GUID_PARENT def testCreateHyperVSocketWithUnknownProtoFailure(self): expected = r"\[WinError 10041\]" From 9824a28a76af4e17496443a87f341d108eb0ebbe Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 6 Jun 2023 21:46:44 +0200 Subject: [PATCH 0137/1206] Post 3.12.0b2 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 2d1cfc43d699f2..a6d20e4d03cf58 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.12.0b2" +#define PY_VERSION "3.12.0b2+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 84133c56f334dca2a1d9fe640fdbafc584d44839 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 17:51:16 -0700 Subject: [PATCH 0138/1206] [3.12] gh-105286: Further improvements to `typing.py` docstrings (GH-105363) (#105416) gh-105286: Further improvements to `typing.py` docstrings (GH-105363) (cherry picked from commit 9a89f1bf1e7bb819fe7240be779c99a84f47ea46) Co-authored-by: Alex Waygood --- Lib/typing.py | 68 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index f9a8ea601e793e..3dda940b07accb 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1,9 +1,6 @@ """ The typing module: Support for gradual typing as defined by PEP 484 and subsequent PEPs. -Any name not present in __all__ is an implementation detail -that may be changed without notice. Use at your own risk! - Among other things, the module includes the following: * Generic, Protocol, and internal machinery to support generic aliases. All subscripted types like X[int], Union[int, str] are generic aliases. @@ -17,6 +14,9 @@ * Special types: NewType, NamedTuple, TypedDict. * Deprecated wrapper submodules for re and io related types. * Deprecated aliases for builtin types and collections.abc ABCs. + +Any name not present in __all__ is an implementation detail +that may be changed without notice. Use at your own risk! """ from abc import abstractmethod, ABCMeta @@ -214,10 +214,12 @@ def _should_unflatten_callable_args(typ, args): """Internal helper for munging collections.abc.Callable's __args__. The canonical representation for a Callable's __args__ flattens the - argument types, see https://bugs.python.org/issue42195. For example:: + argument types, see https://github.com/python/cpython/issues/86361. - collections.abc.Callable[[int, int], str].__args__ == (int, int, str) - collections.abc.Callable[ParamSpec, str].__args__ == (ParamSpec, str) + For example:: + + assert collections.abc.Callable[[int, int], str].__args__ == (int, int, str) + assert collections.abc.Callable[ParamSpec, str].__args__ == (ParamSpec, str) As a result, if we need to reconstruct the Callable from its __args__, we need to unflatten it. @@ -351,8 +353,9 @@ def _flatten_literal_params(parameters): def _tp_cache(func=None, /, *, typed=False): - """Internal wrapper caching __getitem__ of generic types with a fallback to - original function for non-hashable arguments. + """Internal wrapper caching __getitem__ of generic types. + + For non-hashable arguments, the original function is used as a fallback. """ def decorator(func): # The callback 'inner' references the newly created lru_cache @@ -633,10 +636,12 @@ def ClassVar(self, parameters): An annotation wrapped in ClassVar indicates that a given attribute is intended to be used as a class variable and - should not be set on instances of that class. Usage:: + should not be set on instances of that class. + + Usage:: class Starship: - stats: ClassVar[Dict[str, int]] = {} # class variable + stats: ClassVar[dict[str, int]] = {} # class variable damage: int = 10 # instance variable ClassVar accepts only types and cannot be further subscribed. @@ -769,7 +774,9 @@ def TypeAlias(self, parameters): Use TypeAlias to indicate that an assignment should be recognized as a proper type alias definition by type - checkers. For example:: + checkers. + + For example:: Predicate: TypeAlias = Callable[..., bool] @@ -782,8 +789,8 @@ def TypeAlias(self, parameters): def Concatenate(self, parameters): """Special form for annotating higher-order functions. - ``Concatenate`` can be sed in conjunction with ``ParamSpec`` and - ``Callable`` to represent a higher order function which adds, removes or + ``Concatenate`` can be used in conjunction with ``ParamSpec`` and + ``Callable`` to represent a higher-order function which adds, removes or transforms the parameters of a callable. For example:: @@ -1599,8 +1606,9 @@ def Unpack(self, parameters): """Type unpack operator. The type unpack operator takes the child types from some container type, - such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For - example:: + such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. + + For example:: # For some generic class `Foo`: Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] @@ -1625,7 +1633,7 @@ class Bar(Generic[*Ts]): ... class Bar[*Ts]: ... The operator can also be used along with a `TypedDict` to annotate - `**kwargs` in a function signature. For instance:: + `**kwargs` in a function signature:: class Movie(TypedDict): name: str @@ -1638,7 +1646,7 @@ def foo(**kwargs: Unpack[Movie]): ... Note that there is only some runtime checking of this operator. Not everything the runtime allows may be accepted by static type checkers. - For more information, see PEP 646. + For more information, see PEPs 646 and 692. """ item = _type_check(parameters, f'{self} accepts only single type.') return _UnpackGenericAlias(origin=self, args=(item,)) @@ -1886,7 +1894,9 @@ def meth(self) -> int: ... Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: + structural subtyping (static duck-typing). + + For example:: class C: def meth(self) -> int: @@ -2043,7 +2053,7 @@ class Annotated: Annotated[*Ts, Ann1] # NOT valid - This would be equivalent to + This would be equivalent to:: Annotated[T1, T2, T3, ..., Ann1] @@ -2261,8 +2271,10 @@ def _strip_annotations(t): def get_origin(tp): """Get the unsubscripted version of a type. - This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar - Annotated, and others. Return None for unsupported types. Examples:: + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar, + Annotated, and others. Return None for unsupported types. + + Examples:: assert get_origin(Literal[42]) is Literal assert get_origin(int) is None @@ -2421,7 +2433,9 @@ def overload(func): """Decorator for overloaded functions/methods. In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. For example:: + function in a row, each decorated with @overload. + + For example:: @overload def utf8(value: None) -> None: ... @@ -2432,7 +2446,7 @@ def utf8(value: str) -> bytes: ... In a non-stub file (i.e. a regular .py file), do the same but follow it with an implementation. The implementation should *not* - be decorated with @overload. For example:: + be decorated with @overload:: @overload def utf8(value: None) -> None: ... @@ -2942,7 +2956,9 @@ class Point2D(TypedDict): def Required(self, parameters): """Special typing construct to mark a TypedDict key as required. - This is mainly useful for total=False TypedDicts. For example:: + This is mainly useful for total=False TypedDicts. + + For example:: class Movie(TypedDict, total=False): title: Required[str] @@ -2984,7 +3000,9 @@ class NewType: NewType(name, tp) is considered a subtype of tp by static type checkers. At runtime, NewType(name, tp) returns - a dummy callable that simply returns its argument. Usage:: + a dummy callable that simply returns its argument. + + Usage:: UserId = NewType('UserId', int) From f4969eb315fbbb80c476afbcdeacd0695ac7fb9b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 20:55:37 -0700 Subject: [PATCH 0139/1206] [3.12] `typing.NewType` docs: the future performance improvements are now in the past (GH-105354) (#105414) `typing.NewType` docs: the future performance improvements are now in the past (GH-105354) (cherry picked from commit 5f65ff0370e1123084ff300a5ff02cd57623b575) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a4bba7b5ad630b..a0aee8a601563e 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -236,9 +236,13 @@ See :pep:`484` for more details. .. versionadded:: 3.5.2 .. versionchanged:: 3.10 - ``NewType`` is now a class rather than a function. There is some additional - runtime cost when calling ``NewType`` over a regular function. However, this - cost will be reduced in 3.11.0. + ``NewType`` is now a class rather than a function. As a result, there is + some additional runtime cost when calling ``NewType`` over a regular + function. + +.. versionchanged:: 3.11 + The performance of calling ``NewType`` has been restored to its level in + Python 3.9. Callable From ca4649a764badc2c5c7004ed23a8f80eb1ec8dc1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 20:56:16 -0700 Subject: [PATCH 0140/1206] [3.12] GH-95088: Clarify rules for parsing an item key for format strings (GH-103779) (#105419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GH-95088: Clarify rules for parsing an item key for format strings (GH-103779) (cherry picked from commit 3e7316d7e8969febb56fbc7416d483b073bd1702) Co-authored-by: achhina Co-authored-by: Åukasz Langa Co-authored-by: Jelle Zijlstra --- Doc/library/string.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 26b3f5000634f5..9b28f99536a3ae 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -227,7 +227,9 @@ See also the :ref:`formatspec` section. The *field_name* itself begins with an *arg_name* that is either a number or a keyword. If it's a number, it refers to a positional argument, and if it's a keyword, -it refers to a named keyword argument. If the numerical arg_names in a format string +it refers to a named keyword argument. An *arg_name* is treated as a number if +a call to :meth:`str.isdecimal` on the string would return true. +If the numerical arg_names in a format string are 0, 1, 2, ... in sequence, they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be automatically inserted in that order. Because *arg_name* is not quote-delimited, it is not possible to specify arbitrary From a36fb691ac81748f8106544306aa1a31db7886e4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 6 Jun 2023 23:48:44 -0700 Subject: [PATCH 0141/1206] [3.12] typing docs: Make the PEPs list an expandable section, hidden by default (GH-105353) (#105420) typing docs: Make the PEPs list an expandable section, hidden by default (GH-105353) (cherry picked from commit d7645124f56c8832a7630a7f76c99e2630e685d7) Co-authored-by: Alex Waygood Co-authored-by: Hugo van Kemenade --- Doc/library/typing.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a0aee8a601563e..cfc46979232ff2 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -59,7 +59,12 @@ Relevant PEPs Since the initial introduction of type hints in :pep:`484` and :pep:`483`, a number of PEPs have modified and enhanced Python's framework for type -annotations. These include: +annotations: + +.. raw:: html + +
+ The full list of PEPs * :pep:`526`: Syntax for Variable Annotations *Introducing* syntax for annotating variables outside of function @@ -106,6 +111,11 @@ annotations. These include: * :pep:`698`: Adding an override decorator to typing *Introducing* the :func:`@override` decorator +.. raw:: html + +
+
+ .. _type-aliases: Type aliases From 2cfe778d7ff5872cce048d5745f8f23b6d45728c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 00:00:22 -0700 Subject: [PATCH 0142/1206] [3.12] Improve code examples in `typing.rst` (GH-105346) (#105422) Improve code examples in `typing.rst` (GH-105346) (cherry picked from commit 81c81328a4fa13fead6f8cc9053a1a32a62a0279) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 105 +++++++++++++++++++++++++++++------------ 1 file changed, 75 insertions(+), 30 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index cfc46979232ff2..05eebcf4b2e6c3 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2,6 +2,11 @@ :mod:`typing` --- Support for type hints ======================================== +.. testsetup:: * + + import typing + from typing import * + .. module:: typing :synopsis: Support for type hints (see :pep:`484`). @@ -261,19 +266,22 @@ Callable Frameworks expecting callback functions of specific signatures might be type hinted using ``Callable[[Arg1Type, Arg2Type], ReturnType]``. -For example:: +For example: + +.. testcode:: from collections.abc import Callable def feeder(get_next_item: Callable[[], str]) -> None: - # Body + ... # Body def async_query(on_success: Callable[[int], None], on_error: Callable[[int, Exception], None]) -> None: - # Body + ... # Body async def on_update(value: str) -> None: - # Body + ... # Body + callback: Callable[[str], Awaitable[None]] = on_update It is possible to declare the return type of a callable without specifying @@ -431,11 +439,14 @@ In this case ``MyDict`` has a single parameter, ``T``. Using a generic class without specifying type parameters assumes :data:`Any` for each position. In the following example, ``MyIterable`` is -not generic but implicitly inherits from ``Iterable[Any]``:: +not generic but implicitly inherits from ``Iterable[Any]``: + +.. testcode:: from collections.abc import Iterable class MyIterable(Iterable): # Same as Iterable[Any] + ... User-defined generic type aliases are also supported. Examples:: @@ -701,9 +712,11 @@ These can be used as types in annotations and do not support ``[]``. A string created by composing ``LiteralString``-typed objects is also acceptable as a ``LiteralString``. - Example:: + Example: + + .. testcode:: - def run_query(sql: LiteralString) -> ... + def run_query(sql: LiteralString) -> None: ... def caller(arbitrary_string: str, literal_string: LiteralString) -> None: @@ -1596,9 +1609,9 @@ without the dedicated syntax, as documented below. def __abs__(self) -> "Array[*Shape]": ... def get_shape(self) -> tuple[*Shape]: ... - Type variable tuples can be happily combined with normal type variables:: + Type variable tuples can be happily combined with normal type variables: - DType = TypeVar('DType') + .. testcode:: class Array[DType, *Shape]: # This is fine pass @@ -1606,6 +1619,9 @@ without the dedicated syntax, as documented below. class Array2[*Shape, DType]: # This would also be fine pass + class Height: ... + class Width: ... + float_array_1d: Array[float, Height] = Array() # Totally fine int_array_2d: Array[int, Height, Width] = Array() # Yup, fine too @@ -1759,7 +1775,9 @@ without the dedicated syntax, as documented below. The type of type aliases created through the :keyword:`type` statement. - Example:: + Example: + + .. doctest:: >>> type Alias = int >>> type(Alias) @@ -1769,7 +1787,9 @@ without the dedicated syntax, as documented below. .. attribute:: __name__ - The name of the type alias:: + The name of the type alias: + + .. doctest:: >>> type Alias = int >>> Alias.__name__ @@ -2158,7 +2178,11 @@ These are not used in annotations. They are building blocks for declaring types. group: list[T] To create a generic ``TypedDict`` that is compatible with Python 3.11 - or lower, inherit from :class:`Generic` explicitly:: + or lower, inherit from :class:`Generic` explicitly: + + .. testcode:: + + T = TypeVar("T") class Group(TypedDict, Generic[T]): key: T @@ -2171,7 +2195,9 @@ These are not used in annotations. They are building blocks for declaring types. .. attribute:: __total__ ``Point2D.__total__`` gives the value of the ``total`` argument. - Example:: + Example: + + .. doctest:: >>> from typing import TypedDict >>> class Point2D(TypedDict): pass @@ -2201,7 +2227,9 @@ These are not used in annotations. They are building blocks for declaring types. non-required keys in the same ``TypedDict`` . This is done by declaring a ``TypedDict`` with one value for the ``total`` argument and then inheriting from it in another ``TypedDict`` with a different value for - ``total``:: + ``total``: + + .. doctest:: >>> class Point2D(TypedDict, total=False): ... x: int @@ -2860,12 +2888,12 @@ Functions and decorators decorated object performs runtime "magic" that transforms a class, giving it :func:`dataclasses.dataclass`-like behaviors. - Example usage with a decorator function:: + Example usage with a decorator function: - T = TypeVar("T") + .. testcode:: @dataclass_transform() - def create_model(cls: type[T]) -> type[T]: + def create_model[T](cls: type[T]) -> type[T]: ... return cls @@ -2969,7 +2997,9 @@ Functions and decorators runtime but should be ignored by a type checker. At runtime, calling a ``@overload``-decorated function directly will raise :exc:`NotImplementedError`. An example of overload that gives a more - precise type than can be expressed using a union or a type variable:: + precise type than can be expressed using a union or a type variable: + + .. testcode:: @overload def process(response: None) -> None: @@ -2981,7 +3011,7 @@ Functions and decorators def process(response: bytes) -> str: ... def process(response): - + ... # actual implementation goes here See :pep:`484` for more details and comparison with other typing semantics. @@ -3073,10 +3103,13 @@ Functions and decorators This helps prevent bugs that may occur when a base class is changed without an equivalent change to a child class. - For example:: + For example: + + .. testcode:: class Base: - def log_status(self) + def log_status(self) -> None: + ... class Sub(Base): @override @@ -3135,14 +3168,16 @@ Introspection helpers The function recursively replaces all ``Annotated[T, ...]`` with ``T``, unless ``include_extras`` is set to ``True`` (see :class:`Annotated` for - more information). For example:: + more information). For example: + + .. testcode:: class Student(NamedTuple): name: Annotated[str, 'some marker'] - get_type_hints(Student) == {'name': str} - get_type_hints(Student, include_extras=False) == {'name': str} - get_type_hints(Student, include_extras=True) == { + assert get_type_hints(Student) == {'name': str} + assert get_type_hints(Student, include_extras=False) == {'name': str} + assert get_type_hints(Student, include_extras=True) == { 'name': Annotated[str, 'some marker'] } @@ -3169,7 +3204,9 @@ Introspection helpers If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, return the underlying :class:`ParamSpec`. Return ``None`` for unsupported objects. - Examples:: + Examples: + + .. testcode:: assert get_origin(str) is None assert get_origin(Dict[str, int]) is dict @@ -3188,7 +3225,9 @@ Introspection helpers generic type, the order of ``(Y, Z, ...)`` may be different from the order of the original arguments ``[Y, Z, ...]`` due to type caching. Return ``()`` for unsupported objects. - Examples:: + Examples: + + .. testcode:: assert get_args(int) == () assert get_args(Dict[int, str]) == (int, str) @@ -3200,14 +3239,20 @@ Introspection helpers Check if a type is a :class:`TypedDict`. - For example:: + For example: + + .. testcode:: class Film(TypedDict): title: str year: int - is_typeddict(Film) # => True - is_typeddict(list | str) # => False + assert is_typeddict(Film) + assert not is_typeddict(list | str) + + # TypedDict is a factory for creating typed dicts, + # not a typed dict itself + assert not is_typeddict(TypedDict) .. versionadded:: 3.10 From c607551baf62d7201b147f20095160eee0140684 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 7 Jun 2023 09:41:17 +0200 Subject: [PATCH 0143/1206] [3.12] gh-89886: Use Autoconf quadrigraphs where appropriate (#105226) (#105423) --- configure.ac | 88 ++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/configure.ac b/configure.ac index dc9359e7c7bdee..14354a07ab5073 100644 --- a/configure.ac +++ b/configure.ac @@ -2616,7 +2616,7 @@ yes) AC_MSG_RESULT([$MACOSX_DEPLOYMENT_TARGET]) AC_MSG_CHECKING([if specified universal architectures work]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("%d", 42);]])], + AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[printf("%d", 42);]])], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_ERROR([check config.log and use the '--with-universal-archs' option]) @@ -3057,7 +3057,7 @@ fi AC_CACHE_CHECK([for pthread_t], [ac_cv_have_pthread_t], [ AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([[#include ]], [[pthread_t x; x = *(pthread_t*)0;]]) + AC_LANG_PROGRAM([[@%:@include ]], [[pthread_t x; x = *(pthread_t*)0;]]) ], [ac_cv_have_pthread_t=yes], [ac_cv_have_pthread_t=no]) ]) AS_VAR_IF([ac_cv_have_pthread_t], [yes], [ @@ -3070,11 +3070,11 @@ AS_VAR_IF([ac_cv_have_pthread_t], [yes], [ # Issue #25658: POSIX hasn't defined that pthread_key_t is compatible with int. # This checking will be unnecessary after removing deprecated TLS API. -AC_CHECK_SIZEOF([pthread_key_t], [], [[#include ]]) +AC_CHECK_SIZEOF([pthread_key_t], [], [[@%:@include ]]) AC_CACHE_CHECK([whether pthread_key_t is compatible with int], [ac_cv_pthread_key_t_is_arithmetic_type], [ if test "$ac_cv_sizeof_pthread_key_t" -eq "$ac_cv_sizeof_int" ; then AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([[#include ]], [[pthread_key_t k; k * 1;]])], + [AC_LANG_PROGRAM([[@%:@include ]], [[pthread_key_t k; k * 1;]])], [ac_cv_pthread_key_t_is_arithmetic_type=yes], [ac_cv_pthread_key_t_is_arithmetic_type=no] ) @@ -3615,7 +3615,7 @@ AC_CHECK_LIB([intl], [textdomain], case "$ac_sys_system" in AIX*) AC_MSG_CHECKING([for genuine AIX C++ extensions support]) AC_LINK_IFELSE([ - AC_LANG_PROGRAM([[#include ]], + AC_LANG_PROGRAM([[@%:@include ]], [[loadAndInit("", 0, "")]]) ],[ AC_DEFINE([AIX_GENUINE_CPLUSPLUS], [1], @@ -3833,9 +3833,9 @@ AS_VAR_IF([have_libffi], [yes], [ CFLAGS="$LIBFFI_CFLAGS $CFLAGS" LDFLAGS="$LIBFFI_LIBS $LDFLAGS" - PY_CHECK_FUNC([ffi_prep_cif_var], [#include ]) - PY_CHECK_FUNC([ffi_prep_closure_loc], [#include ]) - PY_CHECK_FUNC([ffi_closure_alloc], [#include ]) + PY_CHECK_FUNC([ffi_prep_cif_var], [@%:@include ]) + PY_CHECK_FUNC([ffi_prep_closure_loc], [@%:@include ]) + PY_CHECK_FUNC([ffi_closure_alloc], [@%:@include ]) ]) ]) @@ -4473,7 +4473,7 @@ AC_ARG_ENABLE([ipv6], dnl the check does not work on cross compilation case... AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ /* AF_INET6 available check */ #include -#include ]], +@%:@include ]], [[int domain = AF_INET6;]])],[ ipv6=yes ],[ @@ -4490,7 +4490,7 @@ if test "$ipv6" = "yes"; then AC_MSG_CHECKING([if RFC2553 API is available]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[#include -#include ]], +@%:@include ]], [[struct sockaddr_in6 x; x.sin6_scope_id;]]) ],[ @@ -4522,7 +4522,7 @@ if test "$ipv6" = "yes"; then #include #ifdef IPV6_INRIA_VERSION yes -#endif], +@%:@endif], [ipv6type=$i]) ;; kame) @@ -4531,7 +4531,7 @@ yes #include #ifdef __KAME__ yes -#endif], +@%:@endif], [ipv6type=$i; ipv6lib=inet6 ipv6libdir=/usr/local/v6/lib @@ -4543,7 +4543,7 @@ yes #include #if defined(__GLIBC__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2)) yes -#endif], +@%:@endif], [ipv6type=$i; ipv6trylibc=yes]) ;; @@ -4569,7 +4569,7 @@ yes #include #ifdef _TOSHIBA_INET6 yes -#endif], +@%:@endif], [ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib]) @@ -4579,7 +4579,7 @@ yes #include #ifdef __V6D__ yes -#endif], +@%:@endif], [ipv6type=$i; ipv6lib=v6; ipv6libdir=/usr/local/v6/lib; @@ -4590,7 +4590,7 @@ yes #include #ifdef _ZETA_MINAMI_INET6 yes -#endif], +@%:@endif], [ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib]) @@ -4623,7 +4623,7 @@ fi AC_CACHE_CHECK([CAN_RAW_FD_FRAMES], [ac_cv_can_raw_fd_frames], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ /* CAN_RAW_FD_FRAMES available check */ -#include ]], +@%:@include ]], [[int can_raw_fd_frames = CAN_RAW_FD_FRAMES;]])], [ac_cv_can_raw_fd_frames=yes], [ac_cv_can_raw_fd_frames=no]) @@ -4635,7 +4635,7 @@ AS_VAR_IF([ac_cv_can_raw_fd_frames], [yes], [ AC_CACHE_CHECK([for CAN_RAW_JOIN_FILTERS], [ac_cv_can_raw_join_filters], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#include ]], +@%:@include ]], [[int can_raw_join_filters = CAN_RAW_JOIN_FILTERS;]])], [ac_cv_can_raw_join_filters=yes], [ac_cv_can_raw_join_filters=no]) @@ -4882,14 +4882,14 @@ AC_CHECK_DECL([dirfd], # For some functions, having a definition is not sufficient, since # we want to take their address. -PY_CHECK_FUNC([chroot], [#include ]) -PY_CHECK_FUNC([link], [#include ]) -PY_CHECK_FUNC([symlink], [#include ]) -PY_CHECK_FUNC([fchdir], [#include ]) -PY_CHECK_FUNC([fsync], [#include ]) -PY_CHECK_FUNC([fdatasync], [#include ]) -PY_CHECK_FUNC([epoll_create], [#include ], [HAVE_EPOLL]) -PY_CHECK_FUNC([epoll_create1], [#include ]) +PY_CHECK_FUNC([chroot], [@%:@include ]) +PY_CHECK_FUNC([link], [@%:@include ]) +PY_CHECK_FUNC([symlink], [@%:@include ]) +PY_CHECK_FUNC([fchdir], [@%:@include ]) +PY_CHECK_FUNC([fsync], [@%:@include ]) +PY_CHECK_FUNC([fdatasync], [@%:@include ]) +PY_CHECK_FUNC([epoll_create], [@%:@include ], [HAVE_EPOLL]) +PY_CHECK_FUNC([epoll_create1], [@%:@include ]) PY_CHECK_FUNC([kqueue],[ #include #include @@ -4899,7 +4899,7 @@ PY_CHECK_FUNC([prlimit], [ #include ]) -PY_CHECK_FUNC([_dyld_shared_cache_contains_path], [#include ], [HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH]) +PY_CHECK_FUNC([_dyld_shared_cache_contains_path], [@%:@include ], [HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH]) PY_CHECK_FUNC([memfd_create], [ #ifdef HAVE_SYS_MMAN_H @@ -4922,12 +4922,12 @@ PY_CHECK_FUNC([eventfd], [ # address to avoid compiler warnings and potential miscompilations # because of the missing prototypes. -PY_CHECK_FUNC([ctermid_r], [#include ]) +PY_CHECK_FUNC([ctermid_r], [@%:@include ]) AC_CACHE_CHECK([for flock declaration], [ac_cv_flock_decl], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include ], + [@%:@include ], [void* p = flock] )], [ac_cv_flock_decl=yes], @@ -4939,12 +4939,12 @@ AS_VAR_IF([ac_cv_flock_decl], [yes], [AC_CHECK_FUNCS([flock], [], [AC_CHECK_LIB([bsd], [flock], [FCNTL_LIBS="-lbsd"])])]) -PY_CHECK_FUNC([getpagesize], [#include ]) +PY_CHECK_FUNC([getpagesize], [@%:@include ]) AC_CACHE_CHECK([for broken unsetenv], [ac_cv_broken_unsetenv], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include ], + [@%:@include ], [int res = unsetenv("DUMMY")])], [ac_cv_broken_unsetenv=no], [ac_cv_broken_unsetenv=yes] @@ -5072,7 +5072,7 @@ PKG_CHECK_MODULES([LIBLZMA], [liblzma], [have_liblzma=yes], [ ]) dnl PY_CHECK_NETDB_FUNC(FUNCTION) -AC_DEFUN([PY_CHECK_NETDB_FUNC], [PY_CHECK_FUNC([$1], [#include ])]) +AC_DEFUN([PY_CHECK_NETDB_FUNC], [PY_CHECK_FUNC([$1], [@%:@include ])]) PY_CHECK_NETDB_FUNC([hstrerror]) dnl not available in WASI yet @@ -5395,10 +5395,10 @@ AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_passwd], [], [], [[ #include ]]) # Issue #21085: In Cygwin, siginfo_t does not have si_band field. -AC_CHECK_MEMBERS([siginfo_t.si_band], [], [], [[#include ]]) +AC_CHECK_MEMBERS([siginfo_t.si_band], [], [], [[@%:@include ]]) AC_CACHE_CHECK([for time.h that defines altzone], [ac_cv_header_time_altzone], [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[return altzone;]])], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[return altzone;]])], [ac_cv_header_time_altzone=yes], [ac_cv_header_time_altzone=no]) ]) @@ -5408,7 +5408,7 @@ if test $ac_cv_header_time_altzone = yes; then fi AC_CACHE_CHECK([for addrinfo], [ac_cv_struct_addrinfo], -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct addrinfo a]])], +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[struct addrinfo a]])], [ac_cv_struct_addrinfo=yes], [ac_cv_struct_addrinfo=no])) if test $ac_cv_struct_addrinfo = yes; then @@ -5418,7 +5418,7 @@ fi AC_CACHE_CHECK([for sockaddr_storage], [ac_cv_struct_sockaddr_storage], AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ # include -# include ]], [[struct sockaddr_storage s]])], +@%:@ include ]], [[struct sockaddr_storage s]])], [ac_cv_struct_sockaddr_storage=yes], [ac_cv_struct_sockaddr_storage=no])) if test $ac_cv_struct_sockaddr_storage = yes; then @@ -5430,7 +5430,7 @@ AC_CACHE_CHECK([for sockaddr_alg], [ac_cv_struct_sockaddr_alg], AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ # include # include -# include ]], [[struct sockaddr_alg s]])], +@%:@ include ]], [[struct sockaddr_alg s]])], [ac_cv_struct_sockaddr_alg=yes], [ac_cv_struct_sockaddr_alg=no])) if test $ac_cv_struct_sockaddr_alg = yes; then @@ -5469,7 +5469,7 @@ PY_CHECK_FUNC([socketpair], [ # check if sockaddr has sa_len member AC_CACHE_CHECK([if sockaddr has sa_len member], [ac_cv_struct_sockaddr_sa_len], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], [[struct sockaddr x; +@%:@include ]], [[struct sockaddr x; x.sa_len = 0;]])], [ac_cv_struct_sockaddr_sa_len=yes], [ac_cv_struct_sockaddr_sa_len=no]) ]) @@ -5803,7 +5803,7 @@ AS_VAR_IF([ac_cv_broken_sem_getvalue], [yes], [ ) ]) -AC_CHECK_DECLS([RTLD_LAZY, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL, RTLD_NODELETE, RTLD_NOLOAD, RTLD_DEEPBIND, RTLD_MEMBER], [], [], [[#include ]]) +AC_CHECK_DECLS([RTLD_LAZY, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL, RTLD_NODELETE, RTLD_NOLOAD, RTLD_DEEPBIND, RTLD_MEMBER], [], [], [[@%:@include ]]) # determine what size digit to use for Python's longs AC_MSG_CHECKING([digit size for Python's longs]) @@ -6020,7 +6020,7 @@ fi # check for getc_unlocked and related locking functions AC_CACHE_CHECK([for getc_unlocked() and friends], [ac_cv_have_getc_unlocked], [ -AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[ FILE *f = fopen("/dev/null", "r"); flockfile(f); getc_unlocked(f); @@ -6326,7 +6326,7 @@ fi # Look for subsecond timestamps in struct stat AC_CACHE_CHECK([for tv_nsec in struct stat], [ac_cv_stat_tv_nsec], -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[ struct stat st; st.st_mtim.tv_nsec = 1; ]])], @@ -6340,7 +6340,7 @@ fi # Look for BSD style subsecond timestamps in struct stat AC_CACHE_CHECK([for tv_nsec2 in struct stat], [ac_cv_stat_tv_nsec2], -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[ struct stat st; st.st_mtimespec.tv_nsec = 1; ]])], @@ -6483,7 +6483,7 @@ AC_CHECK_HEADERS([term.h], [], [], [ # On HP/UX 11.0, mvwdelch is a block with a return statement AC_CACHE_CHECK([whether mvwdelch is an expression], [ac_cv_mvwdelch_is_expression], -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[ int rtn; rtn = mvwdelch(0,0,0); ]])], @@ -6527,7 +6527,7 @@ AC_DEFUN([PY_CHECK_CURSES_FUNC], [py_var], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include ], [ + [@%:@include ], [ #ifndef $1 void *x=$1 #endif From c84d4d165dd92e41d6d8661e71b9fd9ac03bfd9e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 04:38:36 -0700 Subject: [PATCH 0144/1206] [3.12] gh-105390: Correctly raise TokenError instead of SyntaxError for tokenize errors (GH-105399) (#105439) --- Doc/library/tokenize.rst | 5 ----- Doc/whatsnew/3.12.rst | 11 +++++----- Lib/test/test_tokenize.py | 11 +++++----- Lib/tokenize.py | 20 +++++++++++++++++-- ...-06-06-17-10-42.gh-issue-105390.DvqI-e.rst | 3 +++ Python/Python-tokenize.c | 9 ++------- 6 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst diff --git a/Doc/library/tokenize.rst b/Doc/library/tokenize.rst index 11f569df2e7cde..41222a771d1b47 100644 --- a/Doc/library/tokenize.rst +++ b/Doc/library/tokenize.rst @@ -139,11 +139,6 @@ function it uses to do this is available: 2, 3 -Note that unclosed single-quoted strings do not cause an error to be -raised. They are tokenized as :data:`~token.ERRORTOKEN`, followed by the -tokenization of their contents. - - .. _tokenize-cli: Command-Line Usage diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4a755975b788b6..18516cb9563f8b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1489,14 +1489,15 @@ Changes in the Python API Additionally, there may be some minor behavioral changes as a consecuence of the changes required to support :pep:`701`. Some of these changes include: - * Some final ``DEDENT`` tokens are now emitted within the bounds of the - input. This means that for a file containing 3 lines, the old version of the - tokenizer returned a ``DEDENT`` token in line 4 whilst the new version returns - the token in line 3. - * The ``type`` attribute of the tokens emitted when tokenizing some invalid Python characters such as ``!`` has changed from ``ERRORTOKEN`` to ``OP``. + * Incomplete single-line strings now also raise :exc:`tokenize.TokenError` as incomplete + multiline strings do. + + * Some incomplete or invalid Python code now raises :exc:`tokenize.TokenError` instead of + returning arbitrary ``ERRORTOKEN`` tokens when tokenizing it. + Build Changes ============= diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 5ac17095b185f5..f2847b2fb327f8 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -3,7 +3,8 @@ from tokenize import (tokenize, untokenize, NUMBER, NAME, OP, STRING, ENDMARKER, ENCODING, tok_name, detect_encoding, open as tokenize_open, Untokenizer, generate_tokens, - NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT, TokenInfo) + NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT, TokenInfo, + TokenError) from io import BytesIO, StringIO import unittest from textwrap import dedent @@ -286,7 +287,7 @@ def number_token(s): for lit in INVALID_UNDERSCORE_LITERALS: try: number_token(lit) - except SyntaxError: + except TokenError: continue self.assertNotEqual(number_token(lit), lit) @@ -1379,7 +1380,7 @@ def test_latin1_normalization(self): self.assertEqual(found, "iso-8859-1") def test_syntaxerror_latin1(self): - # Issue 14629: need to raise SyntaxError if the first + # Issue 14629: need to raise TokenError if the first # line(s) have non-UTF-8 characters lines = ( b'print("\xdf")', # Latin-1: LATIN SMALL LETTER SHARP S @@ -2754,7 +2755,7 @@ def get_tokens(string): "]", ]: with self.subTest(case=case): - self.assertRaises(SyntaxError, get_tokens, case) + self.assertRaises(TokenError, get_tokens, case) def test_max_indent(self): MAXINDENT = 100 @@ -2773,7 +2774,7 @@ def generate_source(indents): invalid = generate_source(MAXINDENT) the_input = StringIO(invalid) - self.assertRaises(SyntaxError, lambda: list(_generate_tokens_from_c_tokenizer(the_input.readline))) + self.assertRaises(IndentationError, lambda: list(_generate_tokens_from_c_tokenizer(the_input.readline))) self.assertRaises( IndentationError, compile, invalid, "", "exec" ) diff --git a/Lib/tokenize.py b/Lib/tokenize.py index a07a8bf45891ac..49e8144edddab7 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -517,14 +517,30 @@ def error(message, filename=None, location=None): perror("unexpected error: %s" % err) raise +def _transform_msg(msg): + """Transform error messages from the C tokenizer into the Python tokenize + + The C tokenizer is more picky than the Python one, so we need to massage + the error messages a bit for backwards compatibility. + """ + if "unterminated triple-quoted string literal" in msg: + return "EOF in multi-line string" + return msg + def _generate_tokens_from_c_tokenizer(source, encoding=None, extra_tokens=False): """Tokenize a source reading Python code as unicode strings using the internal C tokenizer""" if encoding is None: it = _tokenize.TokenizerIter(source, extra_tokens=extra_tokens) else: it = _tokenize.TokenizerIter(source, encoding=encoding, extra_tokens=extra_tokens) - for info in it: - yield TokenInfo._make(info) + try: + for info in it: + yield TokenInfo._make(info) + except SyntaxError as e: + if type(e) != SyntaxError: + raise e from None + msg = _transform_msg(e.msg) + raise TokenError(msg, (e.lineno, e.offset)) from None if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst new file mode 100644 index 00000000000000..de59b54d8f6053 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst @@ -0,0 +1,3 @@ +Correctly raise :exc:`tokenize.TokenError` exceptions instead of +:exc:`SyntaxError` for tokenize errors such as incomplete input. Patch by +Pablo Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 223de54d658507..4d2179348eed20 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -84,13 +84,8 @@ _tokenizer_error(struct tok_state *tok) msg = "invalid token"; break; case E_EOF: - if (tok->level > 0) { - PyErr_Format(PyExc_SyntaxError, - "parenthesis '%c' was never closed", - tok->parenstack[tok->level-1]); - } else { - PyErr_SetString(PyExc_SyntaxError, "unexpected EOF while parsing"); - } + PyErr_SetString(PyExc_SyntaxError, "unexpected EOF in multi-line statement"); + PyErr_SyntaxLocationObject(tok->filename, tok->lineno, tok->inp - tok->buf < 0 ? 0 : tok->inp - tok->buf); return -1; case E_DEDENT: msg = "unindent does not match any outer indentation level"; From bb6ea7200397d2a9650c5d8c7d08acef11edd39b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 04:43:18 -0700 Subject: [PATCH 0145/1206] [3.12] gh-105375: Improve error handling in sqlite3 collation callback (GH-105412) (#105440) Check for error after each call to PyUnicode_FromStringAndSize(). (cherry picked from commit a24a780d937109a0982d807473ae410cc75b0e3b) Co-authored-by: Erlend E. Aasland --- .../2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst | 2 ++ Modules/_sqlite/connection.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst b/Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst new file mode 100644 index 00000000000000..ec10d63822c203 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst @@ -0,0 +1,2 @@ +Fix a bug in :mod:`sqlite3` where an exception could be overwritten in the +:meth:`collation ` callback. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 5c57a4101c4a69..82d23c2c30b798 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -1868,10 +1868,12 @@ collation_callback(void *context, int text1_length, const void *text1_data, } string1 = PyUnicode_FromStringAndSize((const char*)text1_data, text1_length); + if (string1 == NULL) { + goto finally; + } string2 = PyUnicode_FromStringAndSize((const char*)text2_data, text2_length); - - if (!string1 || !string2) { - goto finally; /* failed to allocate strings */ + if (string2 == NULL) { + goto finally; } callback_context *ctx = (callback_context *)context; From 117c153d9fda7553a7fb5d342552e48c4b5c1260 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 06:07:57 -0700 Subject: [PATCH 0146/1206] [3.12] gh-105435: Fix spurious NEWLINE token if file ends with comment without a newline (GH-105442) (#105444) --- Lib/test/test_tokenize.py | 31 ++++++++++++++++--- ...-06-07-12-20-59.gh-issue-105435.6VllI0.rst | 2 ++ Python/Python-tokenize.c | 11 +++++++ 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index f2847b2fb327f8..6747b0d8f65a17 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1631,13 +1631,34 @@ def test_pathological_trailing_whitespace(self): def test_comment_at_the_end_of_the_source_without_newline(self): # See http://bugs.python.org/issue44667 source = 'b = 1\n\n#test' - expected_tokens = [token.NAME, token.EQUAL, token.NUMBER, token.NEWLINE, token.NL, token.COMMENT] + expected_tokens = [ + TokenInfo(type=token.ENCODING, string='utf-8', start=(0, 0), end=(0, 0), line=''), + TokenInfo(type=token.NAME, string='b', start=(1, 0), end=(1, 1), line='b = 1\n'), + TokenInfo(type=token.OP, string='=', start=(1, 2), end=(1, 3), line='b = 1\n'), + TokenInfo(type=token.NUMBER, string='1', start=(1, 4), end=(1, 5), line='b = 1\n'), + TokenInfo(type=token.NEWLINE, string='\n', start=(1, 5), end=(1, 6), line='b = 1\n'), + TokenInfo(type=token.NL, string='\n', start=(2, 0), end=(2, 1), line='\n'), + TokenInfo(type=token.COMMENT, string='#test', start=(3, 0), end=(3, 5), line='#test\n'), + TokenInfo(type=token.NL, string='', start=(3, 5), end=(3, 6), line='#test\n'), + TokenInfo(type=token.ENDMARKER, string='', start=(4, 0), end=(4, 0), line='') + ] + + tokens = list(tokenize(BytesIO(source.encode('utf-8')).readline)) + self.assertEqual(tokens, expected_tokens) + + def test_newline_and_space_at_the_end_of_the_source_without_newline(self): + # See https://github.com/python/cpython/issues/105435 + source = 'a\n ' + expected_tokens = [ + TokenInfo(token.ENCODING, string='utf-8', start=(0, 0), end=(0, 0), line=''), + TokenInfo(token.NAME, string='a', start=(1, 0), end=(1, 1), line='a\n'), + TokenInfo(token.NEWLINE, string='\n', start=(1, 1), end=(1, 2), line='a\n'), + TokenInfo(token.NL, string='', start=(2, 1), end=(2, 2), line=' \n'), + TokenInfo(token.ENDMARKER, string='', start=(3, 0), end=(3, 0), line='') + ] tokens = list(tokenize(BytesIO(source.encode('utf-8')).readline)) - self.assertEqual(tok_name[tokens[0].exact_type], tok_name[ENCODING]) - for i in range(6): - self.assertEqual(tok_name[tokens[i + 1].exact_type], tok_name[expected_tokens[i]]) - self.assertEqual(tok_name[tokens[-1].exact_type], tok_name[token.ENDMARKER]) + self.assertEqual(tokens, expected_tokens) def test_invalid_character_in_fstring_middle(self): # See gh-103824 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst new file mode 100644 index 00000000000000..9e4d7e1851ccb5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst @@ -0,0 +1,2 @@ +Fix spurious newline character if file ends on a comment without a newline. +Patch by Pablo Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 4d2179348eed20..83a129c138b174 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -247,6 +247,17 @@ tokenizeriter_next(tokenizeriterobject *it) } end_col_offset++; } + else if (type == NL) { + if (it->tok->implicit_newline) { + Py_DECREF(str); + str = PyUnicode_FromString(""); + } + } + + if (str == NULL) { + Py_DECREF(line); + goto exit; + } } result = Py_BuildValue("(iN(nn)(nn)N)", type, str, lineno, col_offset, end_lineno, end_col_offset, line); From 92ab560ef5af9488476a49f2313a5aa7f7723329 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 06:45:54 -0700 Subject: [PATCH 0147/1206] [3.12] Improve docs for `typing.TypeAlias` (GH-105372) (#105446) Improve docs for `typing.TypeAlias` (GH-105372) (cherry picked from commit c5ec51ec8f4508e1f01f6d98ac8364a13da9bec7) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 05eebcf4b2e6c3..dc3b086d658af7 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -832,19 +832,41 @@ These can be used as types in annotations and do not support ``[]``. .. data:: TypeAlias Special annotation for explicitly declaring a :ref:`type alias `. + For example:: - from typing import TypeAlias + from typing import TypeAlias + + Factors: TypeAlias = list[int] + + ``TypeAlias`` is particularly useful on older Python versions for annotating + aliases that make use of forward references, as it can be hard for type + checkers to distinguish these from normal variable assignments: + + .. testcode:: + + from typing import Generic, TypeAlias, TypeVar + + T = TypeVar("T") + + # "Box" does not exist yet, + # so we have to use quotes for the forward reference on Python <3.12. + # Using ``TypeAlias`` tells the type checker that this is a type alias declaration, + # not a variable assignment to a string. + BoxOfStrings: TypeAlias = "Box[str]" - Factors: TypeAlias = list[int] + class Box(Generic[T]): + @classmethod + def make_box_of_strings(cls) -> BoxOfStrings: ... - See :pep:`613` for more details about explicit type aliases. + See :pep:`613` for more details. .. versionadded:: 3.10 .. deprecated:: 3.12 :data:`TypeAlias` is deprecated in favor of the :keyword:`type` statement, - which creates instances of :class:`TypeAliasType`. + which creates instances of :class:`TypeAliasType` + and which natively supports forward references. Note that while :data:`TypeAlias` and :class:`TypeAliasType` serve similar purposes and have similar names, they are distinct and the latter is not the type of the former. From 241c36e1dc317fbfaea75edf4c5c52c5bbe3e19a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 06:57:25 -0700 Subject: [PATCH 0148/1206] [3.12] gh-97797: Improve documentation for typing.Annotated (GH-105365) (#105448) gh-97797: Improve documentation for typing.Annotated (GH-105365) (cherry picked from commit e26d296984b2b6279231922ab0940d904aa6144e) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 73 +++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index dc3b086d658af7..5f559cf3f49361 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -5,6 +5,7 @@ .. testsetup:: * import typing + from dataclasses import dataclass from typing import * .. module:: typing @@ -1184,7 +1185,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn (possibly multiple pieces of it, as ``Annotated`` is variadic). Specifically, a type ``T`` can be annotated with metadata ``x`` via the typehint ``Annotated[T, x]``. This metadata can be used for either static - analysis or at runtime. If a library (or tool) encounters a typehint + analysis or at runtime: at runtime, it is stored in a :attr:`__metadata__` + attribute. If a library (or tool) encounters a typehint ``Annotated[T, x]`` and has no special logic for metadata ``x``, it should ignore it and simply treat the type as ``T``. Unlike the ``no_type_check`` functionality that currently exists in the ``typing`` @@ -1211,10 +1213,17 @@ These can be used as types in annotations using ``[]``, each having a unique syn the same (or different) type(s) on any node, the tools or libraries consuming those annotations are in charge of dealing with potential duplicates. For example, if you are doing value range analysis you might - allow this:: + allow this: - T1 = Annotated[int, ValueRange(-10, 5)] - T2 = Annotated[T1, ValueRange(-20, 3)] + .. testcode:: + + @dataclass + class ValueRange: + lo: int + hi: int + + T1 = Annotated[int, ValueRange(-10, 5)] + T2 = Annotated[T1, ValueRange(-20, 3)] Passing ``include_extras=True`` to :func:`get_type_hints` lets one access the extra annotations at runtime. @@ -1226,7 +1235,11 @@ These can be used as types in annotations using ``[]``, each having a unique syn * Multiple type annotations are supported (``Annotated`` supports variadic arguments):: - Annotated[int, ValueRange(3, 10), ctype("char")] + @dataclass + class ctype: + kind: str + + Annotated[int, ValueRange(3, 10), ctype("char")] * ``Annotated`` must be called with at least two arguments ( ``Annotated[int]`` is not valid) @@ -1234,30 +1247,52 @@ These can be used as types in annotations using ``[]``, each having a unique syn * The order of the annotations is preserved and matters for equality checks:: - Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[ - int, ctype("char"), ValueRange(3, 10) - ] + assert Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[ + int, ctype("char"), ValueRange(3, 10) + ] * Nested ``Annotated`` types are flattened, with metadata ordered starting with the innermost annotation:: - Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[ - int, ValueRange(3, 10), ctype("char") - ] + assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[ + int, ValueRange(3, 10), ctype("char") + ] * Duplicated annotations are not removed:: - Annotated[int, ValueRange(3, 10)] != Annotated[ - int, ValueRange(3, 10), ValueRange(3, 10) - ] + assert Annotated[int, ValueRange(3, 10)] != Annotated[ + int, ValueRange(3, 10), ValueRange(3, 10) + ] + + * ``Annotated`` can be used with nested and generic aliases: + + .. testcode:: - * ``Annotated`` can be used with nested and generic aliases:: + @dataclass + class MaxLen: + value: int - T = TypeVar('T') - Vec = Annotated[list[tuple[T, T]], MaxLen(10)] - V = Vec[int] + type Vec[T] = Annotated[list[tuple[T, T]], MaxLen(10)] + + # When used in a type annotation, a type checker will treat "V" the same as + # ``Annotated[list[tuple[int, int]], MaxLen(10)]``: + type V = Vec[int] + + .. attribute:: __metadata__ + + At runtime, the metadata associated with an ``Annotated`` type can be + retrieved via the ``__metadata__`` attribute. + + For example: + + .. doctest:: - V == Annotated[list[tuple[int, int]], MaxLen(10)] + >>> from typing import Annotated + >>> X = Annotated[int, "very", "important", "metadata"] + >>> X + typing.Annotated[int, 'very', 'important', 'metadata'] + >>> X.__metadata__ + ('very', 'important', 'metadata') .. versionadded:: 3.9 From 98ccc2de6b71d62388045f4877ee0d2143227a02 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 07:30:39 -0700 Subject: [PATCH 0149/1206] [3.12] gh-105430: Remove `typing._Immutable` unused internal helper (GH-105434) (#105451) gh-105430: Remove `typing._Immutable` unused internal helper (GH-105434) (cherry picked from commit 18309ad94bb1ae0b092f34dc3fd54199876a6ebd) Co-authored-by: Nikita Sobolev --- Lib/typing.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index 3dda940b07accb..0983f20f9b276f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -425,17 +425,6 @@ def __init_subclass__(cls, /, *args, **kwds): if '_root' not in kwds: raise TypeError("Cannot subclass special typing classes") -class _Immutable: - """Mixin to indicate that object should not be copied.""" - - __slots__ = () - - def __copy__(self): - return self - - def __deepcopy__(self, memo): - return self - class _NotIterable: """Mixin to prevent iteration, without being compatible with Iterable. From d36aa244c860f96564c6a94d568bfb7f6a0251bf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 07:35:12 -0700 Subject: [PATCH 0150/1206] [3.12] gh-105437: Improve tests of type params names for PEP 695 (GH-105438) (#105452) (cherry picked from commit 76883af6bf28b7e810df172bd6762bf2cb64df08) Co-authored-by: Nikita Sobolev --- Lib/test/test_type_aliases.py | 6 ++++-- Lib/test/test_type_params.py | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index c43499609aaa56..a3067e521e023e 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -8,8 +8,10 @@ class TypeParamsInvalidTest(unittest.TestCase): - def test_name_collision_01(self): - check_syntax_error(self, """type TA1[A, **A] = None""", "duplicate type parameter 'A'") + def test_name_collisions(self): + check_syntax_error(self, 'type TA1[A, **A] = None', "duplicate type parameter 'A'") + check_syntax_error(self, 'type T[A, *A] = None', "duplicate type parameter 'A'") + check_syntax_error(self, 'type T[*A, **A] = None', "duplicate type parameter 'A'") def test_name_non_collision_02(self): ns = run_code("""type TA1[A] = lambda A: A""") diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 7b7b6122c028e5..6475df6f5bba43 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -8,8 +8,14 @@ class TypeParamsInvalidTest(unittest.TestCase): - def test_name_collision_01(self): - check_syntax_error(self, """def func[**A, A](): ...""") + def test_name_collisions(self): + check_syntax_error(self, 'def func[**A, A](): ...', "duplicate type parameter 'A'") + check_syntax_error(self, 'def func[A, *A](): ...', "duplicate type parameter 'A'") + check_syntax_error(self, 'def func[*A, **A](): ...', "duplicate type parameter 'A'") + + check_syntax_error(self, 'class C[**A, A](): ...', "duplicate type parameter 'A'") + check_syntax_error(self, 'class C[A, *A](): ...', "duplicate type parameter 'A'") + check_syntax_error(self, 'class C[*A, **A](): ...', "duplicate type parameter 'A'") def test_name_non_collision_02(self): ns = run_code("""def func[A](A): return A""") From 9a7c4a5f39ec795f1ea77e1dfc557514f8f8a04a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 08:04:14 -0700 Subject: [PATCH 0151/1206] [3.12] typing: Improve documentation of generic classes and aliases (GH-105369) (#105453) typing: Improve documentation of generic classes and aliases (GH-105369) (cherry picked from commit d63a7c3694d5c4484fcaa01c33590b1d4bc2559e) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 148 ++++++++++++++++++++++++----------------- Lib/typing.py | 8 ++- 2 files changed, 91 insertions(+), 65 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 5f559cf3f49361..3fa0651546ab04 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -311,21 +311,28 @@ Generics ======== Since type information about objects kept in containers cannot be statically -inferred in a generic way, abstract base classes have been extended to support -subscription to denote expected types for container elements. +inferred in a generic way, many container classes in the standard library support +subscription to denote the expected types of container elements. -:: +.. testcode:: from collections.abc import Mapping, Sequence + class Employee: ... + + # Sequence[Employee] indicates that all elements in the sequence + # must be instances of "Employee". + # Mapping[str, str] indicates that all keys and all values in the mapping + # must be strings. def notify_by_email(employees: Sequence[Employee], overrides: Mapping[str, str]) -> None: ... -Generics can be parameterized by using :ref:`type parameter syntax `:: +Generic functions and classes can be parameterized by using +:ref:`type parameter syntax `:: from collections.abc import Sequence - def first[T](l: Sequence[T]) -> T: # Generic function + def first[T](l: Sequence[T]) -> T: # Function is generic over the TypeVar "T" return l[0] Or by using the :class:`TypeVar` factory directly:: @@ -333,10 +340,10 @@ Or by using the :class:`TypeVar` factory directly:: from collections.abc import Sequence from typing import TypeVar - U = TypeVar('U') # Declare type variable + U = TypeVar('U') # Declare type variable "U" - def first(l: Sequence[U]) -> U: # Generic function - return l[0] + def second(l: Sequence[U]) -> U: # Function is generic over the TypeVar "U" + return l[1] .. versionchanged:: 3.12 Syntactic support for generics is new in Python 3.12. @@ -515,7 +522,7 @@ to the former, so the following are equivalent:: >>> X[[int, str]] __main__.X[[int, str]] -Do note that generics with :class:`ParamSpec` may not have correct +Note that generics with :class:`ParamSpec` may not have correct ``__parameters__`` after substitution in some cases because they are intended primarily for static type checking. @@ -654,14 +661,14 @@ The module defines the following classes, functions and decorators. .. note:: - This module defines several types that are subclasses of pre-existing - standard library classes which also extend :class:`Generic` - to support type variables inside ``[]``. - These types became redundant in Python 3.9 when the + This module defines several deprecated aliases to pre-existing + standard library classes. These were originally included in the typing + module in order to support parameterizing these generic classes using ``[]``. + However, the aliases became redundant in Python 3.9 when the corresponding pre-existing classes were enhanced to support ``[]``. The redundant types are deprecated as of Python 3.9 but no - deprecation warnings will be issued by the interpreter. + deprecation warnings are issued by the interpreter. It is expected that type checkers will flag the deprecated types when the checked program targets Python 3.9 or newer. @@ -881,7 +888,9 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Tuple - Tuple type; ``Tuple[X, Y]`` is the type of a tuple of two items + Deprecated alias for :class:`tuple`. + + ``Tuple[X, Y]`` is the type of a tuple of two items with the first item of type X and the second of type Y. The type of the empty tuple can be written as ``Tuple[()]``. @@ -890,8 +899,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn of an int, a float and a string. To specify a variable-length tuple of homogeneous type, - use literal ellipsis, e.g. ``Tuple[int, ...]``. A plain :data:`Tuple` - is equivalent to ``Tuple[Any, ...]``, and in turn to :class:`tuple`. + use literal ellipsis, e.g. ``Tuple[int, ...]``. A plain ``Tuple`` annotation + is equivalent to ``tuple``, ``Tuple[Any, ...]``, or ``tuple[Any, ...]``. .. deprecated:: 3.9 :class:`builtins.tuple ` now supports subscripting (``[]``). @@ -959,12 +968,15 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Callable - Callable type; ``Callable[[int], str]`` is a function of (int) -> str. + Deprecated alias to :class:`collections.abc.Callable`. + + ``Callable[[int], str]`` signifies a function that takes a single parameter + of type :class:`int` and returns a :class:`str`. The subscription syntax must always be used with exactly two values: the argument list and the return type. The argument list - must be a list of types or an ellipsis; the return type must be - a single type. + must be a list of types, a :class:`ParamSpec`, :data:`Concatenate`, + or an ellipsis. The return type must be a single type. There is no syntax to indicate optional or keyword arguments; such function types are rarely used as callback types. @@ -1050,8 +1062,10 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. class:: Type(Generic[CT_co]) + Deprecated alias to :class:`type`. + A variable annotated with ``C`` may accept a value of type ``C``. In - contrast, a variable annotated with ``Type[C]`` may accept values that are + contrast, a variable annotated with ``type[C]`` or ``Type[C]`` may accept values that are classes themselves -- specifically, it will accept the *class object* of ``C``. For example:: @@ -2321,9 +2335,11 @@ Corresponding to built-in types .. class:: Dict(dict, MutableMapping[KT, VT]) - A generic version of :class:`dict`. - Useful for annotating return types. To annotate arguments it is preferred - to use an abstract collection type such as :class:`Mapping`. + Deprecated alias to :class:`dict`. + + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`Mapping` + rather than to use :class:`dict` or :class:`!typing.Dict`. This type can be used as follows:: @@ -2336,10 +2352,11 @@ Corresponding to built-in types .. class:: List(list, MutableSequence[T]) - Generic version of :class:`list`. - Useful for annotating return types. To annotate arguments it is preferred + Deprecated alias to :class:`list`. + + Note that to annotate arguments, it is preferred to use an abstract collection type such as :class:`Sequence` or - :class:`Iterable`. + :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`. This type may be used as follows:: @@ -2355,9 +2372,11 @@ Corresponding to built-in types .. class:: Set(set, MutableSet[T]) - A generic version of :class:`builtins.set `. - Useful for annotating return types. To annotate arguments it is preferred - to use an abstract collection type such as :class:`AbstractSet`. + Deprecated alias to :class:`builtins.set `. + + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`AbstractSet` + rather than to use :class:`set` or :class:`!typing.Set`. .. deprecated:: 3.9 :class:`builtins.set ` now supports subscripting (``[]``). @@ -2365,7 +2384,7 @@ Corresponding to built-in types .. class:: FrozenSet(frozenset, AbstractSet[T_co]) - A generic version of :class:`builtins.frozenset `. + Deprecated alias to :class:`builtins.frozenset `. .. deprecated:: 3.9 :class:`builtins.frozenset ` @@ -2379,7 +2398,7 @@ Corresponding to types in :mod:`collections` .. class:: DefaultDict(collections.defaultdict, MutableMapping[KT, VT]) - A generic version of :class:`collections.defaultdict`. + Deprecated alias to :class:`collections.defaultdict`. .. versionadded:: 3.5.2 @@ -2389,7 +2408,7 @@ Corresponding to types in :mod:`collections` .. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) - A generic version of :class:`collections.OrderedDict`. + Deprecated alias to :class:`collections.OrderedDict`. .. versionadded:: 3.7.2 @@ -2399,7 +2418,7 @@ Corresponding to types in :mod:`collections` .. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) - A generic version of :class:`collections.ChainMap`. + Deprecated alias to :class:`collections.ChainMap`. .. versionadded:: 3.5.4 .. versionadded:: 3.6.1 @@ -2410,7 +2429,7 @@ Corresponding to types in :mod:`collections` .. class:: Counter(collections.Counter, Dict[T, int]) - A generic version of :class:`collections.Counter`. + Deprecated alias to :class:`collections.Counter`. .. versionadded:: 3.5.4 .. versionadded:: 3.6.1 @@ -2421,7 +2440,7 @@ Corresponding to types in :mod:`collections` .. class:: Deque(deque, MutableSequence[T]) - A generic version of :class:`collections.deque`. + Deprecated alias to :class:`collections.deque`. .. versionadded:: 3.5.4 .. versionadded:: 3.6.1 @@ -2492,7 +2511,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: AbstractSet(Collection[T_co]) - A generic version of :class:`collections.abc.Set`. + Deprecated alias to :class:`collections.abc.Set`. .. deprecated:: 3.9 :class:`collections.abc.Set` now supports subscripting (``[]``). @@ -2508,7 +2527,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) - A generic version of :class:`collections.abc.Collection` + Deprecated alias to :class:`collections.abc.Collection`. .. versionadded:: 3.6.0 @@ -2518,7 +2537,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: Container(Generic[T_co]) - A generic version of :class:`collections.abc.Container`. + Deprecated alias to :class:`collections.abc.Container`. .. deprecated:: 3.9 :class:`collections.abc.Container` now supports subscripting (``[]``). @@ -2526,7 +2545,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) - A generic version of :class:`collections.abc.ItemsView`. + Deprecated alias to :class:`collections.abc.ItemsView`. .. deprecated:: 3.9 :class:`collections.abc.ItemsView` now supports subscripting (``[]``). @@ -2534,7 +2553,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: KeysView(MappingView, AbstractSet[KT_co]) - A generic version of :class:`collections.abc.KeysView`. + Deprecated alias to :class:`collections.abc.KeysView`. .. deprecated:: 3.9 :class:`collections.abc.KeysView` now supports subscripting (``[]``). @@ -2542,7 +2561,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: Mapping(Collection[KT], Generic[KT, VT_co]) - A generic version of :class:`collections.abc.Mapping`. + Deprecated alias to :class:`collections.abc.Mapping`. This type can be used as follows:: def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: @@ -2554,7 +2573,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: MappingView(Sized) - A generic version of :class:`collections.abc.MappingView`. + Deprecated alias to :class:`collections.abc.MappingView`. .. deprecated:: 3.9 :class:`collections.abc.MappingView` now supports subscripting (``[]``). @@ -2562,7 +2581,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: MutableMapping(Mapping[KT, VT]) - A generic version of :class:`collections.abc.MutableMapping`. + Deprecated alias to :class:`collections.abc.MutableMapping`. .. deprecated:: 3.9 :class:`collections.abc.MutableMapping` @@ -2571,7 +2590,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: MutableSequence(Sequence[T]) - A generic version of :class:`collections.abc.MutableSequence`. + Deprecated alias to :class:`collections.abc.MutableSequence`. .. deprecated:: 3.9 :class:`collections.abc.MutableSequence` @@ -2580,7 +2599,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: MutableSet(AbstractSet[T]) - A generic version of :class:`collections.abc.MutableSet`. + Deprecated alias to :class:`collections.abc.MutableSet`. .. deprecated:: 3.9 :class:`collections.abc.MutableSet` now supports subscripting (``[]``). @@ -2588,7 +2607,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: Sequence(Reversible[T_co], Collection[T_co]) - A generic version of :class:`collections.abc.Sequence`. + Deprecated alias to :class:`collections.abc.Sequence`. .. deprecated:: 3.9 :class:`collections.abc.Sequence` now supports subscripting (``[]``). @@ -2596,7 +2615,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: ValuesView(MappingView, Collection[_VT_co]) - A generic version of :class:`collections.abc.ValuesView`. + Deprecated alias to :class:`collections.abc.ValuesView`. .. deprecated:: 3.9 :class:`collections.abc.ValuesView` now supports subscripting (``[]``). @@ -2607,7 +2626,7 @@ Corresponding to other types in :mod:`collections.abc` .. class:: Iterable(Generic[T_co]) - A generic version of :class:`collections.abc.Iterable`. + Deprecated alias to :class:`collections.abc.Iterable`. .. deprecated:: 3.9 :class:`collections.abc.Iterable` now supports subscripting (``[]``). @@ -2615,13 +2634,15 @@ Corresponding to other types in :mod:`collections.abc` .. class:: Iterator(Iterable[T_co]) - A generic version of :class:`collections.abc.Iterator`. + Deprecated alias to :class:`collections.abc.Iterator`. .. deprecated:: 3.9 :class:`collections.abc.Iterator` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -.. class:: Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]) +.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) + + Deprecated alias to :class:`collections.abc.Generator`. A generator can be annotated by the generic type ``Generator[YieldType, SendType, ReturnType]``. For example:: @@ -2658,14 +2679,14 @@ Corresponding to other types in :mod:`collections.abc` .. class:: Hashable - An alias to :class:`collections.abc.Hashable`. + Deprecated alias to :class:`collections.abc.Hashable`. .. deprecated:: 3.12 Use :class:`collections.abc.Hashable` directly instead. .. class:: Reversible(Iterable[T_co]) - A generic version of :class:`collections.abc.Reversible`. + Deprecated alias to :class:`collections.abc.Reversible`. .. deprecated:: 3.9 :class:`collections.abc.Reversible` now supports subscripting (``[]``). @@ -2673,7 +2694,7 @@ Corresponding to other types in :mod:`collections.abc` .. class:: Sized - An alias to :class:`collections.abc.Sized`. + Deprecated alias to :class:`collections.abc.Sized`. .. deprecated:: 3.12 Use :class:`collections.abc.Sized` directly instead. @@ -2681,9 +2702,10 @@ Corresponding to other types in :mod:`collections.abc` Asynchronous programming """""""""""""""""""""""" -.. class:: Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co]) +.. class:: Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType]) + + Deprecated alias to :class:`collections.abc.Coroutine`. - A generic version of :class:`collections.abc.Coroutine`. The variance and order of type variables correspond to those of :class:`Generator`, for example:: @@ -2699,7 +2721,9 @@ Asynchronous programming :class:`collections.abc.Coroutine` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -.. class:: AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra]) +.. class:: AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType]) + + Deprecated alias to :class:`collections.abc.AsyncGenerator`. An async generator can be annotated by the generic type ``AsyncGenerator[YieldType, SendType]``. For example:: @@ -2739,7 +2763,7 @@ Asynchronous programming .. class:: AsyncIterable(Generic[T_co]) - A generic version of :class:`collections.abc.AsyncIterable`. + Deprecated alias to :class:`collections.abc.AsyncIterable`. .. versionadded:: 3.5.2 @@ -2749,7 +2773,7 @@ Asynchronous programming .. class:: AsyncIterator(AsyncIterable[T_co]) - A generic version of :class:`collections.abc.AsyncIterator`. + Deprecated alias to :class:`collections.abc.AsyncIterator`. .. versionadded:: 3.5.2 @@ -2759,7 +2783,7 @@ Asynchronous programming .. class:: Awaitable(Generic[T_co]) - A generic version of :class:`collections.abc.Awaitable`. + Deprecated alias to :class:`collections.abc.Awaitable`. .. versionadded:: 3.5.2 @@ -2773,7 +2797,7 @@ Context manager types .. class:: ContextManager(Generic[T_co]) - A generic version of :class:`contextlib.AbstractContextManager`. + Deprecated alias to :class:`contextlib.AbstractContextManager`. .. versionadded:: 3.5.4 .. versionadded:: 3.6.0 @@ -2785,7 +2809,7 @@ Context manager types .. class:: AsyncContextManager(Generic[T_co]) - A generic version of :class:`contextlib.AbstractAsyncContextManager`. + Deprecated alias to :class:`contextlib.AbstractAsyncContextManager`. .. versionadded:: 3.5.4 .. versionadded:: 3.6.2 diff --git a/Lib/typing.py b/Lib/typing.py index 0983f20f9b276f..0ff29fa43558d3 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2549,11 +2549,13 @@ class Other(Leaf): # Error reported by type checker Callable.__doc__ = \ """Deprecated alias to collections.abc.Callable. - Callable[[int], str] signifies a function of (int) -> str. + Callable[[int], str] signifies a function that takes a single + parameter of type int and returns a str. + The subscription syntax must always be used with exactly two values: the argument list and the return type. - The argument list must be a list of types, a ParamSpec or ellipsis. - The return type must be a single type. + The argument list must be a list of types, a ParamSpec, + Concatenate or ellipsis. The return type must be a single type. There is no syntax to indicate optional or keyword arguments; such function types are rarely used as callback types. From d3092573a827ec9b8cf2094f0fddc2eaa95a5127 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 10:41:04 -0700 Subject: [PATCH 0152/1206] [3.12] Fix grammar and improve clarity for an deprecation message. (GH-105457) (#105458) --- Modules/itertoolsmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 4a6d1314b3864e..ae63bae79d5d07 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -98,8 +98,8 @@ class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type" #define ITERTOOL_PICKLE_DEPRECATION \ if (PyErr_WarnEx( \ PyExc_DeprecationWarning, \ - "Itertool pickle/copy/deepcopy support " \ - "will be removed in a Python 3.14.", 1) < 0) { \ + "Pickle, copy, and deepcopy support will be " \ + "removed from itertools in Python 3.14.", 1) < 0) { \ return NULL; \ } From 4eadfb1c1a035970905b00263db8d9bd277098fc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 11:11:48 -0700 Subject: [PATCH 0153/1206] [3.12] gh-90015: Document that PEP-604 unions do not support forward references (GH-105366) (#105460) gh-90015: Document that PEP-604 unions do not support forward references (GH-105366) (cherry picked from commit fbdee000de47ae96fbf53ce8908e8efbb23cfba4) Co-authored-by: Alex Waygood --- Doc/library/stdtypes.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index fdef5314b9a4ef..0caa725f75e642 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5162,6 +5162,14 @@ enables cleaner type hinting syntax compared to :data:`typing.Union`. def square(number: int | float) -> int | float: return number ** 2 + .. note:: + + The ``|`` operand cannot be used at runtime to define unions where one or + more members is a forward reference. For example, ``int | "Foo"``, where + ``"Foo"`` is a reference to a class not yet defined, will fail at + runtime. For unions which include forward references, present the + whole expression as a string, e.g. ``"int | Foo"``. + .. describe:: union_object == other Union objects can be tested for equality with other union objects. Details: From 1e128779befad65ec8208e0ef0d0688ef8a7f5d2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 13:11:10 -0700 Subject: [PATCH 0154/1206] [3.12] gh-94673: Ensure subtypes are readied only once in math.trunc() (gh-105465) (gh-105471) Fixes a typo in d2e2e53. (cherry picked from commit 5394bf92aa6516feb3322d8372d1579bd9c1417b) Co-authored-by: neonene <53406459+neonene@users.noreply.github.com> --- Modules/mathmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index f26602d5871acc..f5679fe3a6f362 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2067,7 +2067,7 @@ math_trunc(PyObject *module, PyObject *x) return PyFloat_Type.tp_as_number->nb_int(x); } - if (_PyType_IsReady(Py_TYPE(x))) { + if (!_PyType_IsReady(Py_TYPE(x))) { if (PyType_Ready(Py_TYPE(x)) < 0) return NULL; } From 3d4a786b9b6382efa0dbe6f28d34b26426bb4165 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:46:24 -0700 Subject: [PATCH 0155/1206] [3.12] gh-105390: Add explicit type cast (GH-105466) (#105472) --- Python/Python-tokenize.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 83a129c138b174..2cf052a0cdeb3b 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -85,7 +85,8 @@ _tokenizer_error(struct tok_state *tok) break; case E_EOF: PyErr_SetString(PyExc_SyntaxError, "unexpected EOF in multi-line statement"); - PyErr_SyntaxLocationObject(tok->filename, tok->lineno, tok->inp - tok->buf < 0 ? 0 : tok->inp - tok->buf); + PyErr_SyntaxLocationObject(tok->filename, tok->lineno, + tok->inp - tok->buf < 0 ? 0 : (int)(tok->inp - tok->buf)); return -1; case E_DEDENT: msg = "unindent does not match any outer indentation level"; From 4b2263e4bf4952cf9671298f5cde2bc92333223b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:54:42 -0700 Subject: [PATCH 0156/1206] [3.12] gh-103171: Forward-port new tests for runtime-checkable protocols decorated with `@final` (GH-105473) (#105474) Forward-port of the tests that were added to the 3.11 branch in GH-105445 (cherry picked from commit f5df347fcf5fe029edbe6bf274da0f4880401852) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ef1db06109eca3..74480891fb50d4 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3800,6 +3800,71 @@ class Foo(typing.Sized, Protocol): pass # before any isinstance() checks against Sized self.assertNotIsInstance(1, typing.Sized) + def test_empty_protocol_decorated_with_final(self): + @final + @runtime_checkable + class EmptyProtocol(Protocol): ... + + self.assertIsSubclass(object, EmptyProtocol) + self.assertIsInstance(object(), EmptyProtocol) + + def test_protocol_decorated_with_final_callable_members(self): + @final + @runtime_checkable + class ProtocolWithMethod(Protocol): + def startswith(self, string: str) -> bool: ... + + self.assertIsSubclass(str, ProtocolWithMethod) + self.assertNotIsSubclass(int, ProtocolWithMethod) + self.assertIsInstance('foo', ProtocolWithMethod) + self.assertNotIsInstance(42, ProtocolWithMethod) + + def test_protocol_decorated_with_final_noncallable_members(self): + @final + @runtime_checkable + class ProtocolWithNonCallableMember(Protocol): + x: int + + class Foo: + x = 42 + + only_callable_members_please = ( + r"Protocols with non-method members don't support issubclass()" + ) + + with self.assertRaisesRegex(TypeError, only_callable_members_please): + issubclass(Foo, ProtocolWithNonCallableMember) + + with self.assertRaisesRegex(TypeError, only_callable_members_please): + issubclass(int, ProtocolWithNonCallableMember) + + self.assertIsInstance(Foo(), ProtocolWithNonCallableMember) + self.assertNotIsInstance(42, ProtocolWithNonCallableMember) + + def test_protocol_decorated_with_final_mixed_members(self): + @final + @runtime_checkable + class ProtocolWithMixedMembers(Protocol): + x: int + def method(self) -> None: ... + + class Foo: + x = 42 + def method(self) -> None: ... + + only_callable_members_please = ( + r"Protocols with non-method members don't support issubclass()" + ) + + with self.assertRaisesRegex(TypeError, only_callable_members_please): + issubclass(Foo, ProtocolWithMixedMembers) + + with self.assertRaisesRegex(TypeError, only_callable_members_please): + issubclass(int, ProtocolWithMixedMembers) + + self.assertIsInstance(Foo(), ProtocolWithMixedMembers) + self.assertNotIsInstance(42, ProtocolWithMixedMembers) + class GenericTests(BaseTestCase): From ae25f1c8e5522dee4131a3b48490cdb199e9ae22 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Thu, 8 Jun 2023 00:25:45 +0100 Subject: [PATCH 0157/1206] [3.12] GH-104996: Defer joining of `pathlib.PurePath()` arguments. (GH-104999) (GH-105483) Joining of arguments is moved to `_load_parts`, which is called when a normalized path is needed. (cherry picked from commit ffeaec7e60c88d585deacb10264ba7a96e5e52df) --- Lib/pathlib.py | 38 ++++++++++++------- ...-05-26-21-24-06.gh-issue-104996.aaW78g.rst | 2 + 2 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 29517e4c74db1c..d279fd2958b170 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -293,9 +293,9 @@ class PurePath(object): """ __slots__ = ( - # The `_raw_path` slot stores an unnormalized string path. This is set + # The `_raw_paths` slot stores unnormalized string paths. This is set # in the `__init__()` method. - '_raw_path', + '_raw_paths', # The `_drv`, `_root` and `_tail_cached` slots store parsed and # normalized parts of the path. They are set when any of the `drive`, @@ -352,10 +352,11 @@ def __init__(self, *args): paths = [] for arg in args: if isinstance(arg, PurePath): - path = arg._raw_path if arg._flavour is ntpath and self._flavour is posixpath: # GH-103631: Convert separators for backwards compatibility. - path = path.replace('\\', '/') + paths.extend(path.replace('\\', '/') for path in arg._raw_paths) + else: + paths.extend(arg._raw_paths) else: try: path = os.fspath(arg) @@ -366,13 +367,8 @@ def __init__(self, *args): "argument should be a str or an os.PathLike " "object where __fspath__ returns a str, " f"not {type(path).__name__!r}") - paths.append(path) - if len(paths) == 0: - self._raw_path = '' - elif len(paths) == 1: - self._raw_path = paths[0] - else: - self._raw_path = self._flavour.join(*paths) + paths.append(path) + self._raw_paths = paths def with_segments(self, *pathsegments): """Construct a new path object from any number of path-like objects. @@ -402,7 +398,14 @@ def _parse_path(cls, path): return drv, root, parsed def _load_parts(self): - drv, root, tail = self._parse_path(self._raw_path) + paths = self._raw_paths + if len(paths) == 0: + path = '' + elif len(paths) == 1: + path = paths[0] + else: + path = self._flavour.join(*paths) + drv, root, tail = self._parse_path(path) self._drv = drv self._root = root self._tail_cached = tail @@ -733,10 +736,17 @@ def parents(self): def is_absolute(self): """True if the path is absolute (has both a root and, if applicable, a drive).""" - # ntpath.isabs() is defective - see GH-44626 . if self._flavour is ntpath: + # ntpath.isabs() is defective - see GH-44626. return bool(self.drive and self.root) - return self._flavour.isabs(self._raw_path) + elif self._flavour is posixpath: + # Optimization: work with raw paths on POSIX. + for path in self._raw_paths: + if path.startswith('/'): + return True + return False + else: + return self._flavour.isabs(str(self)) def is_reserved(self): """Return True if the path contains one of the special names reserved diff --git a/Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst b/Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst new file mode 100644 index 00000000000000..8b81b681af94aa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst @@ -0,0 +1,2 @@ +Improve performance of :class:`pathlib.PurePath` initialisation by +deferring joining of paths when multiple arguments are given. From 2b6f475db8adf0d75a8fce5dd8f2f50b875753d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:57:21 -0700 Subject: [PATCH 0158/1206] [3.12] gh-105431: Remove unused stuff from `test_typing.NewTypeTests` (GH-105432) (#105489) gh-105431: Remove unused stuff from `test_typing.NewTypeTests` (GH-105432) (cherry picked from commit 9d35a71a76cb033598ce136ea655d9e452fe3af0) Co-authored-by: Nikita Sobolev --- Lib/test/test_typing.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 74480891fb50d4..7dc64c6ecc9e5b 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -6893,10 +6893,6 @@ def test_c_functions(self): class NewTypeTests(BaseTestCase): - def cleanup(self): - for f in typing._cleanups: - f() - @classmethod def setUpClass(cls): global UserId @@ -6909,9 +6905,6 @@ def tearDownClass(cls): del UserId del cls.UserName - def tearDown(self): - self.cleanup() - def test_basic(self): self.assertIsInstance(UserId(5), int) self.assertIsInstance(self.UserName('Joe'), str) From 3c5f0eadd800c2d66f5249398a8f6ef72972fbd0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 08:12:35 -0700 Subject: [PATCH 0159/1206] [3.12] Further improve docs for `typing.Annotated` (GH-105498) (#105503) Further improve docs for `typing.Annotated` (GH-105498) (cherry picked from commit d213c2990f0db62ed39fc5468977f989c2658675) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 132 ++++++++++++++++++++++++----------------- Lib/typing.py | 14 +++-- 2 files changed, 85 insertions(+), 61 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 3fa0651546ab04..f9b44e1c74aa73 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1194,40 +1194,36 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Annotated - A type, introduced in :pep:`593` (``Flexible function and variable - annotations``), to decorate existing types with context-specific metadata - (possibly multiple pieces of it, as ``Annotated`` is variadic). - Specifically, a type ``T`` can be annotated with metadata ``x`` via the - typehint ``Annotated[T, x]``. This metadata can be used for either static - analysis or at runtime: at runtime, it is stored in a :attr:`__metadata__` - attribute. If a library (or tool) encounters a typehint - ``Annotated[T, x]`` and has no special logic for metadata ``x``, it - should ignore it and simply treat the type as ``T``. Unlike the - ``no_type_check`` functionality that currently exists in the ``typing`` - module which completely disables typechecking annotations on a function - or a class, the ``Annotated`` type allows for both static typechecking - of ``T`` (which can safely ignore ``x``) - together with runtime access to ``x`` within a specific application. - - Ultimately, the responsibility of how to interpret the annotations (if - at all) is the responsibility of the tool or library encountering the - ``Annotated`` type. A tool or library encountering an ``Annotated`` type - can scan through the annotations to determine if they are of interest - (e.g., using ``isinstance()``). - - When a tool or a library does not support annotations or encounters an - unknown annotation it should just ignore it and treat annotated type as - the underlying type. - - It's up to the tool consuming the annotations to decide whether the - client is allowed to have several annotations on one type and how to - merge those annotations. - - Since the ``Annotated`` type allows you to put several annotations of - the same (or different) type(s) on any node, the tools or libraries - consuming those annotations are in charge of dealing with potential - duplicates. For example, if you are doing value range analysis you might - allow this: + Special typing form to add context-specific metadata to an annotation. + + Add metadata ``x`` to a given type ``T`` by using the annotation + ``Annotated[T, x]``. Metadata added using ``Annotated`` can be used by + static analysis tools or at runtime. At runtime, the metadata is stored + in a :attr:`!__metadata__` attribute. + + If a library or tool encounters an annotation ``Annotated[T, x]`` and has + no special logic for the metadata, it should ignore the metadata and simply + treat the annotation as ``T``. As such, ``Annotated`` can be useful for code + that wants to use annotations for purposes outside Python's static typing + system. + + Using ``Annotated[T, x]`` as an annotation still allows for static + typechecking of ``T``, as type checkers will simply ignore the metadata ``x``. + In this way, ``Annotated`` differs from the + :func:`@no_type_check ` decorator, which can also be used for + adding annotations outside the scope of the typing system, but + completely disables typechecking for a function or class. + + The responsibility of how to interpret the metadata + lies with the the tool or library encountering an + ``Annotated`` annotation. A tool or library encountering an ``Annotated`` type + can scan through the metadata elements to determine if they are of interest + (e.g., using :func:`isinstance`). + + .. describe:: Annotated[, ] + + Here is an example of how you might use ``Annotated`` to add metadata to + type annotations if you were doing range analysis: .. testcode:: @@ -1239,14 +1235,11 @@ These can be used as types in annotations using ``[]``, each having a unique syn T1 = Annotated[int, ValueRange(-10, 5)] T2 = Annotated[T1, ValueRange(-20, 3)] - Passing ``include_extras=True`` to :func:`get_type_hints` lets one - access the extra annotations at runtime. - - The details of the syntax: + Details of the syntax: * The first argument to ``Annotated`` must be a valid type - * Multiple type annotations are supported (``Annotated`` supports variadic + * Multiple metadata elements can be supplied (``Annotated`` supports variadic arguments):: @dataclass @@ -1255,24 +1248,28 @@ These can be used as types in annotations using ``[]``, each having a unique syn Annotated[int, ValueRange(3, 10), ctype("char")] - * ``Annotated`` must be called with at least two arguments ( + It is up to the tool consuming the annotations to decide whether the + client is allowed to add multiple metadata elements to one annotation and how to + merge those annotations. + + * ``Annotated`` must be subscripted with at least two arguments ( ``Annotated[int]`` is not valid) - * The order of the annotations is preserved and matters for equality + * The order of the metadata elements is preserved and matters for equality checks:: assert Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[ int, ctype("char"), ValueRange(3, 10) ] - * Nested ``Annotated`` types are flattened, with metadata ordered - starting with the innermost annotation:: + * Nested ``Annotated`` types are flattened. The order of the metadata elements + starts with the innermost annotation:: assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[ int, ValueRange(3, 10), ctype("char") ] - * Duplicated annotations are not removed:: + * Duplicated metadata elements are not removed:: assert Annotated[int, ValueRange(3, 10)] != Annotated[ int, ValueRange(3, 10), ValueRange(3, 10) @@ -1292,21 +1289,46 @@ These can be used as types in annotations using ``[]``, each having a unique syn # ``Annotated[list[tuple[int, int]], MaxLen(10)]``: type V = Vec[int] - .. attribute:: __metadata__ + * ``Annotated`` cannot be used with an unpacked :class:`TypeVarTuple`:: - At runtime, the metadata associated with an ``Annotated`` type can be - retrieved via the ``__metadata__`` attribute. + type Variadic[*Ts] = Annotated[*Ts, Ann1] # NOT valid - For example: + This would be equivalent to:: - .. doctest:: + Annotated[T1, T2, T3, ..., Ann1] + + where ``T1``, ``T2``, etc. are :class:`TypeVars `. This would be + invalid: only one type should be passed to Annotated. + + * By default, :func:`get_type_hints` strips the metadata from annotations. + Pass ``include_extras=True`` to have the metadata preserved: + + .. doctest:: + + >>> from typing import Annotated, get_type_hints + >>> def func(x: Annotated[int, "metadata"]) -> None: pass + ... + >>> get_type_hints(func) + {'x': , 'return': } + >>> get_type_hints(func, include_extras=True) + {'x': typing.Annotated[int, 'metadata'], 'return': } + + * At runtime, the metadata associated with an ``Annotated`` type can be + retrieved via the :attr:`!__metadata__` attribute: + + .. doctest:: + + >>> from typing import Annotated + >>> X = Annotated[int, "very", "important", "metadata"] + >>> X + typing.Annotated[int, 'very', 'important', 'metadata'] + >>> X.__metadata__ + ('very', 'important', 'metadata') + + .. seealso:: - >>> from typing import Annotated - >>> X = Annotated[int, "very", "important", "metadata"] - >>> X - typing.Annotated[int, 'very', 'important', 'metadata'] - >>> X.__metadata__ - ('very', 'important', 'metadata') + :pep:`593` - Flexible function and variable annotations + The PEP introducing ``Annotated`` to the standard library. .. versionadded:: 3.9 diff --git a/Lib/typing.py b/Lib/typing.py index 0ff29fa43558d3..44b26af92b3d99 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2021,7 +2021,7 @@ class Annotated: assert Annotated[int, '$'].__metadata__ == ('$',) - - Nested Annotated are flattened:: + - Nested Annotated types are flattened:: assert Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] @@ -2032,15 +2032,17 @@ class Annotated: - Annotated can be used as a generic type alias:: - Optimized = Annotated[T, runtime.Optimize()] - assert Optimized[int] == Annotated[int, runtime.Optimize()] + type Optimized[T] = Annotated[T, runtime.Optimize()] + # type checker will treat Optimized[int] + # as equivalent to Annotated[int, runtime.Optimize()] - OptimizedList = Annotated[List[T], runtime.Optimize()] - assert OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + type OptimizedList[T] = Annotated[list[T], runtime.Optimize()] + # type checker will treat OptimizedList[int] + # as equivalent to Annotated[list[int], runtime.Optimize()] - Annotated cannot be used with an unpacked TypeVarTuple:: - Annotated[*Ts, Ann1] # NOT valid + type Variadic[*Ts] = Annotated[*Ts, Ann1] # NOT valid This would be equivalent to:: From 1f90b2f57a21b48858a2c60c2c1e59b8ff9f63b7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 08:19:11 -0700 Subject: [PATCH 0160/1206] [3.12] test_types: Replace raw assert statements (GH-105500) (#105507) (cherry picked from commit a8eb7372eebe182fd4ef7381a742d84a368a7d1b) Co-authored-by: Jelle Zijlstra --- Lib/test/test_types.py | 52 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 89548100da62d7..81744940f25b82 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -226,8 +226,8 @@ def test_type_function(self): def test_int__format__(self): def test(i, format_spec, result): # just make sure we have the unified type for integers - assert type(i) == int - assert type(format_spec) == str + self.assertIs(type(i), int) + self.assertIs(type(format_spec), str) self.assertEqual(i.__format__(format_spec), result) test(123456789, 'd', '123456789') @@ -782,8 +782,8 @@ def __subclasscheck__(cls, sub): def test_or_type_operator_with_TypeVar(self): TV = typing.TypeVar('T') - assert TV | str == typing.Union[TV, str] - assert str | TV == typing.Union[str, TV] + self.assertEqual(TV | str, typing.Union[TV, str]) + self.assertEqual(str | TV, typing.Union[str, TV]) self.assertIs((int | TV)[int], int) self.assertIs((TV | int)[int], int) @@ -887,43 +887,45 @@ def test_or_type_operator_with_forward(self): ForwardBefore = 'Forward' | T def forward_after(x: ForwardAfter[int]) -> None: ... def forward_before(x: ForwardBefore[int]) -> None: ... - assert typing.get_args(typing.get_type_hints(forward_after)['x']) == (int, Forward) - assert typing.get_args(typing.get_type_hints(forward_before)['x']) == (int, Forward) + self.assertEqual(typing.get_args(typing.get_type_hints(forward_after)['x']), + (int, Forward)) + self.assertEqual(typing.get_args(typing.get_type_hints(forward_before)['x']), + (int, Forward)) def test_or_type_operator_with_Protocol(self): class Proto(typing.Protocol): def meth(self) -> int: ... - assert Proto | str == typing.Union[Proto, str] + self.assertEqual(Proto | str, typing.Union[Proto, str]) def test_or_type_operator_with_Alias(self): - assert list | str == typing.Union[list, str] - assert typing.List | str == typing.Union[typing.List, str] + self.assertEqual(list | str, typing.Union[list, str]) + self.assertEqual(typing.List | str, typing.Union[typing.List, str]) def test_or_type_operator_with_NamedTuple(self): - NT=namedtuple('A', ['B', 'C', 'D']) - assert NT | str == typing.Union[NT,str] + NT = namedtuple('A', ['B', 'C', 'D']) + self.assertEqual(NT | str, typing.Union[NT, str]) def test_or_type_operator_with_TypedDict(self): class Point2D(typing.TypedDict): x: int y: int label: str - assert Point2D | str == typing.Union[Point2D, str] + self.assertEqual(Point2D | str, typing.Union[Point2D, str]) def test_or_type_operator_with_NewType(self): UserId = typing.NewType('UserId', int) - assert UserId | str == typing.Union[UserId, str] + self.assertEqual(UserId | str, typing.Union[UserId, str]) def test_or_type_operator_with_IO(self): - assert typing.IO | str == typing.Union[typing.IO, str] + self.assertEqual(typing.IO | str, typing.Union[typing.IO, str]) def test_or_type_operator_with_SpecialForm(self): - assert typing.Any | str == typing.Union[typing.Any, str] - assert typing.NoReturn | str == typing.Union[typing.NoReturn, str] - assert typing.Optional[int] | str == typing.Union[typing.Optional[int], str] - assert typing.Optional[int] | str == typing.Union[int, str, None] - assert typing.Union[int, bool] | str == typing.Union[int, bool, str] + self.assertEqual(typing.Any | str, typing.Union[typing.Any, str]) + self.assertEqual(typing.NoReturn | str, typing.Union[typing.NoReturn, str]) + self.assertEqual(typing.Optional[int] | str, typing.Union[typing.Optional[int], str]) + self.assertEqual(typing.Optional[int] | str, typing.Union[int, str, None]) + self.assertEqual(typing.Union[int, bool] | str, typing.Union[int, bool, str]) def test_or_type_operator_with_Literal(self): Literal = typing.Literal @@ -955,12 +957,12 @@ class Ints(enum.IntEnum): (Literal[1], Literal[Ints.B])) def test_or_type_repr(self): - assert repr(int | str) == "int | str" - assert repr((int | str) | list) == "int | str | list" - assert repr(int | (str | list)) == "int | str | list" - assert repr(int | None) == "int | None" - assert repr(int | type(None)) == "int | None" - assert repr(int | typing.GenericAlias(list, int)) == "int | list[int]" + self.assertEqual(repr(int | str), "int | str") + self.assertEqual(repr((int | str) | list), "int | str | list") + self.assertEqual(repr(int | (str | list)), "int | str | list") + self.assertEqual(repr(int | None), "int | None") + self.assertEqual(repr(int | type(None)), "int | None") + self.assertEqual(repr(int | typing.GenericAlias(list, int)), "int | list[int]") def test_or_type_operator_with_genericalias(self): a = list[int] From 8698fa83f6c226d35af0367e40dd4387fcccbe40 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 12:00:04 -0700 Subject: [PATCH 0161/1206] [3.12] gh-104310: Rename the New Function in importlib.util (gh-105255) (gh-105518) The original name wasn't as clear as it could have been. This change includes the following: * rename the function * change the default value for "disable_check" to False * add clues to the docstring that folks should probably not use the function --------- (cherry picked from commit 34c63b86d3c33a85acf55a0c5c118304754e145d) Co-authored-by: Eric Snow Co-authored-by: Kirill Podoprigora --- Lib/importlib/util.py | 26 +++++++++++++++---- Lib/test/test_importlib/test_util.py | 26 +++++++++---------- ...-06-02-14-23-41.gh-issue-104310.UamCOB.rst | 7 +++++ 3 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py index b1d9271f8e47ca..f4d6e82331516f 100644 --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -116,12 +116,24 @@ def find_spec(name, package=None): # is imported by runpy, which means we want to avoid any unnecessary # dependencies. Thus we use a class. -class allowing_all_extensions: - """A context manager that lets users skip the compatibility check. +class _incompatible_extension_module_restrictions: + """A context manager that can temporarily skip the compatibility check. + + NOTE: This function is meant to accommodate an unusual case; one + which is likely to eventually go away. There's is a pretty good + chance this is not what you were looking for. + + WARNING: Using this function to disable the check can lead to + unexpected behavior and even crashes. It should only be used during + extension module development. + + If "disable_check" is True then the compatibility check will not + happen while the context manager is active. Otherwise the check + *will* happen. Normally, extensions that do not support multiple interpreters may not be imported in a subinterpreter. That implies modules - that do not implement multi-phase init. + that do not implement multi-phase init or that explicitly of out. Likewise for modules import in a subinterpeter with its own GIL when the extension does not support a per-interpreter GIL. This @@ -130,10 +142,14 @@ class allowing_all_extensions: In both cases, this context manager may be used to temporarily disable the check for compatible extension modules. + + You can get the same effect as this function by implementing the + basic interface of multi-phase init (PEP 489) and lying about + support for mulitple interpreters (or per-interpreter GIL). """ - def __init__(self, disable_check=True): - self.disable_check = disable_check + def __init__(self, *, disable_check): + self.disable_check = bool(disable_check) def __enter__(self): self.old = _imp._override_multi_interp_extensions_check(self.override) diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index 0be504925ecc6a..e967adc9451c81 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -653,7 +653,7 @@ def test_magic_number(self): @unittest.skipIf(_interpreters is None, 'subinterpreters required') -class AllowingAllExtensionsTests(unittest.TestCase): +class IncompatibleExtensionModuleRestrictionsTests(unittest.TestCase): ERROR = re.compile("^: module (.*) does not support loading in subinterpreters") @@ -678,8 +678,8 @@ def run_with_shared_gil(self, script): @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module") def test_single_phase_init_module(self): script = textwrap.dedent(''' - import importlib.util - with importlib.util.allowing_all_extensions(): + from importlib.util import _incompatible_extension_module_restrictions + with _incompatible_extension_module_restrictions(disable_check=True): import _testsinglephase ''') with self.subTest('check disabled, shared GIL'): @@ -688,8 +688,8 @@ def test_single_phase_init_module(self): self.run_with_own_gil(script) script = textwrap.dedent(f''' - import importlib.util - with importlib.util.allowing_all_extensions(False): + from importlib.util import _incompatible_extension_module_restrictions + with _incompatible_extension_module_restrictions(disable_check=False): import _testsinglephase ''') with self.subTest('check enabled, shared GIL'): @@ -713,8 +713,8 @@ def test_incomplete_multi_phase_init_module(self): ''') script = prescript + textwrap.dedent(''' - import importlib.util - with importlib.util.allowing_all_extensions(): + from importlib.util import _incompatible_extension_module_restrictions + with _incompatible_extension_module_restrictions(disable_check=True): module = module_from_spec(spec) loader.exec_module(module) ''') @@ -724,8 +724,8 @@ def test_incomplete_multi_phase_init_module(self): self.run_with_own_gil(script) script = prescript + textwrap.dedent(''' - import importlib.util - with importlib.util.allowing_all_extensions(False): + from importlib.util import _incompatible_extension_module_restrictions + with _incompatible_extension_module_restrictions(disable_check=False): module = module_from_spec(spec) loader.exec_module(module) ''') @@ -738,8 +738,8 @@ def test_incomplete_multi_phase_init_module(self): @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") def test_complete_multi_phase_init_module(self): script = textwrap.dedent(''' - import importlib.util - with importlib.util.allowing_all_extensions(): + from importlib.util import _incompatible_extension_module_restrictions + with _incompatible_extension_module_restrictions(disable_check=True): import _testmultiphase ''') with self.subTest('check disabled, shared GIL'): @@ -748,8 +748,8 @@ def test_complete_multi_phase_init_module(self): self.run_with_own_gil(script) script = textwrap.dedent(f''' - import importlib.util - with importlib.util.allowing_all_extensions(False): + from importlib.util import _incompatible_extension_module_restrictions + with _incompatible_extension_module_restrictions(disable_check=False): import _testmultiphase ''') with self.subTest('check enabled, shared GIL'): diff --git a/Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst b/Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst new file mode 100644 index 00000000000000..461a3a25fe1b43 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst @@ -0,0 +1,7 @@ +In the beta 1 release we added a utility function for extension module +authors, to use when testing their module for support in multiple +interpreters or under a per-interpreter GIL. The name of that function has +changed from ``allowing_all_extensions`` to +``_incompatible_extension_module_restrictions``. The default for the +"disable_check" argument has change from ``True`` to ``False``, to better +match the new function name. From 2ad2bd8b14505ee92600e7988379cfac63086dab Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 12:27:44 -0700 Subject: [PATCH 0162/1206] [3.12] gh-100227: Lock Around Use of the Global "atexit" State (gh-105514) (gh-105517) The risk of a race with this state is relatively low, but we play it safe anyway. (cherry picked from commit 7799c8e678f759c7787785c6287140abe641d1b9) Co-authored-by: Eric Snow --- Doc/data/python3.12.abi | 878 ++++++++++++++++--------------- Include/internal/pycore_atexit.h | 1 + Python/pylifecycle.c | 17 +- Python/pystate.c | 35 +- 4 files changed, 481 insertions(+), 450 deletions(-) diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 55d8468d57c05a..d6680f9064f3b1 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1702,7 +1702,7 @@ - + @@ -7546,30 +7546,30 @@ - - + + - - - - + + + + - - + + - - - - + + + + - - - - + + + + @@ -8230,8 +8230,8 @@ - - + + @@ -8868,111 +8868,111 @@ - + - - + + - - + + - - - + + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - - + + + - - - - - + + + + + - - - - + + + + - - + + - - + + - - - + + + - - + + - - + + - - - + + + - - - + + + - - + + - - + + - - - + + + - + @@ -10883,10 +10883,10 @@ - + - + @@ -12759,114 +12759,117 @@ - + - + - - + + + + + - + - + - + - + - - + + - + - + - + - - + + - + - + - + - + - + - - - - - + + + + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -12883,7 +12886,7 @@ - + @@ -12891,10 +12894,10 @@ - + - + @@ -12906,10 +12909,10 @@ - + - + @@ -13113,10 +13116,10 @@ - + - + @@ -13322,10 +13325,10 @@ - + - + @@ -13447,10 +13450,10 @@ - + - + @@ -13479,7 +13482,7 @@ - + @@ -13494,7 +13497,7 @@ - + @@ -13515,13 +13518,13 @@ - + - + - + @@ -13557,7 +13560,7 @@ - + @@ -13658,7 +13661,7 @@ - + @@ -14258,7 +14261,7 @@ - + @@ -14318,7 +14321,7 @@ - + @@ -14372,7 +14375,7 @@ - + @@ -14531,7 +14534,7 @@ - + @@ -14615,7 +14618,7 @@ - + @@ -15098,7 +15101,7 @@ - + @@ -15233,7 +15236,7 @@ - + @@ -15317,7 +15320,7 @@ - + @@ -15389,7 +15392,7 @@ - + @@ -15695,7 +15698,7 @@ - + @@ -15832,7 +15835,7 @@ - + @@ -15962,7 +15965,7 @@ - + @@ -15999,7 +16002,7 @@ - + @@ -16053,7 +16056,7 @@ - + @@ -16062,7 +16065,7 @@ - + @@ -16134,7 +16137,7 @@ - + @@ -16515,7 +16518,7 @@ - + @@ -16541,7 +16544,7 @@ - + @@ -16558,7 +16561,7 @@ - + @@ -16602,61 +16605,61 @@ - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -16670,7 +16673,7 @@ - + @@ -16684,7 +16687,7 @@ - + @@ -16698,10 +16701,10 @@ - + - + @@ -16767,7 +16770,7 @@ - + @@ -16884,7 +16887,7 @@ - + @@ -16943,7 +16946,7 @@ - + @@ -17337,12 +17340,12 @@ - - - + + + - + @@ -17356,7 +17359,7 @@ - + @@ -17372,8 +17375,8 @@ - - + + @@ -17412,15 +17415,15 @@ - + - + - + @@ -17736,7 +17739,7 @@ - + @@ -17843,49 +17846,55 @@ - + - + - + - - - - + - + - + - + - + - + - - + + - - + + - - + + - + - + + + + + + + + + + @@ -18792,12 +18801,17 @@ - + + + + + + - + @@ -18807,39 +18821,39 @@ - + - + - + - + - + - + - + @@ -18850,31 +18864,31 @@ - + - + - + - + - + - + @@ -18917,7 +18931,7 @@ - + @@ -18929,7 +18943,7 @@ - + @@ -19960,13 +19974,13 @@ - + - + @@ -20345,7 +20359,7 @@ - + @@ -20452,49 +20466,55 @@ - + - + - + - - - - + - + - + - + - + - + - - + + - - + + - - + + - + - + + + + + + + + + + @@ -20667,7 +20687,7 @@ - + @@ -20796,42 +20816,42 @@ - + - + - + - + - + - + - + - + @@ -21245,17 +21265,30 @@ - + + + + + + + - + + + + + + + + @@ -21928,7 +21961,7 @@ - + @@ -21976,7 +22009,7 @@ - + @@ -22015,53 +22048,53 @@ - - + + - + - + - + - + - + - - + + - - + + - - + + - - + + - - - - + + + + - - - + + + - + @@ -22687,35 +22720,35 @@ - - - - - - + + + + + + - - - - + + + + - + - - - - + + + + - - - - - + + + + + @@ -22963,12 +22996,6 @@ - - - - - - @@ -24341,40 +24368,40 @@ - - - - + + + + - - - - + + + + - - + + - - + + - - + + - - + + - - - + + + - + @@ -24664,13 +24691,13 @@ - + - + - + @@ -24732,6 +24759,7 @@ + @@ -25333,27 +25361,27 @@ - - + + - - - + + + - - - + + + - - + + - - - + + + @@ -25363,7 +25391,7 @@ - + @@ -25430,137 +25458,137 @@ - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - - + + + - + - + - + - + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - + + + - - + + @@ -26311,7 +26339,7 @@ - + diff --git a/Include/internal/pycore_atexit.h b/Include/internal/pycore_atexit.h index b4663b396852f3..63a2cd5d507d2c 100644 --- a/Include/internal/pycore_atexit.h +++ b/Include/internal/pycore_atexit.h @@ -15,6 +15,7 @@ extern "C" { typedef void (*atexit_callbackfunc)(void); struct _atexit_runtime_state { + PyThread_type_lock mutex; #define NEXITFUNCS 32 atexit_callbackfunc callbacks[NEXITFUNCS]; int ncallbacks; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8b846443ce8f6a..95b39f478f51f6 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2974,24 +2974,35 @@ wait_for_thread_shutdown(PyThreadState *tstate) int Py_AtExit(void (*func)(void)) { - if (_PyRuntime.atexit.ncallbacks >= NEXITFUNCS) + struct _atexit_runtime_state *state = &_PyRuntime.atexit; + PyThread_acquire_lock(state->mutex, WAIT_LOCK); + if (state->ncallbacks >= NEXITFUNCS) { + PyThread_release_lock(state->mutex); return -1; - _PyRuntime.atexit.callbacks[_PyRuntime.atexit.ncallbacks++] = func; + } + state->callbacks[state->ncallbacks++] = func; + PyThread_release_lock(state->mutex); return 0; } static void call_ll_exitfuncs(_PyRuntimeState *runtime) { + atexit_callbackfunc exitfunc; struct _atexit_runtime_state *state = &runtime->atexit; + + PyThread_acquire_lock(state->mutex, WAIT_LOCK); while (state->ncallbacks > 0) { /* pop last function from the list */ state->ncallbacks--; - atexit_callbackfunc exitfunc = state->callbacks[state->ncallbacks]; + exitfunc = state->callbacks[state->ncallbacks]; state->callbacks[state->ncallbacks] = NULL; + PyThread_release_lock(state->mutex); exitfunc(); + PyThread_acquire_lock(state->mutex, WAIT_LOCK); } + PyThread_release_lock(state->mutex); fflush(stdout); fflush(stderr); diff --git a/Python/pystate.c b/Python/pystate.c index 39fe5473ed46b3..e3a010adbf5480 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -380,7 +380,16 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP -#define NUMLOCKS 5 +#define NUMLOCKS 6 +#define LOCKS_INIT(runtime) \ + { \ + &(runtime)->interpreters.mutex, \ + &(runtime)->xidregistry.mutex, \ + &(runtime)->getargs.mutex, \ + &(runtime)->unicode_state.ids.lock, \ + &(runtime)->imports.extensions.mutex, \ + &(runtime)->atexit.mutex, \ + } static int alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS]) @@ -427,13 +436,7 @@ init_runtime(_PyRuntimeState *runtime, PyPreConfig_InitPythonConfig(&runtime->preconfig); - PyThread_type_lock *lockptrs[NUMLOCKS] = { - &runtime->interpreters.mutex, - &runtime->xidregistry.mutex, - &runtime->getargs.mutex, - &runtime->unicode_state.ids.lock, - &runtime->imports.extensions.mutex, - }; + PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime); for (int i = 0; i < NUMLOCKS; i++) { assert(locks[i] != NULL); *lockptrs[i] = locks[i]; @@ -512,13 +515,7 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime) LOCK = NULL; \ } - PyThread_type_lock *lockptrs[NUMLOCKS] = { - &runtime->interpreters.mutex, - &runtime->xidregistry.mutex, - &runtime->getargs.mutex, - &runtime->unicode_state.ids.lock, - &runtime->imports.extensions.mutex, - }; + PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime); for (int i = 0; i < NUMLOCKS; i++) { FREE_LOCK(*lockptrs[i]); } @@ -541,13 +538,7 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - PyThread_type_lock *lockptrs[NUMLOCKS] = { - &runtime->interpreters.mutex, - &runtime->xidregistry.mutex, - &runtime->getargs.mutex, - &runtime->unicode_state.ids.lock, - &runtime->imports.extensions.mutex, - }; + PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime); int reinit_err = 0; for (int i = 0; i < NUMLOCKS; i++) { reinit_err += _PyThread_at_fork_reinit(lockptrs[i]); From b08ea9a561e93e421e55b6eba5da350e6919708e Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 8 Jun 2023 15:05:47 -0600 Subject: [PATCH 0163/1206] [3.12] gh-100227: Lock Around Adding Global Audit Hooks (gh-105515) (gh-105525) The risk of a race with this state is relatively low, but we play it safe anyway. (cherry picked from commit e822a676f1f3bef6c5413e9b856db481c08ac2a5) --- Doc/data/python3.12.abi | 2540 +++++++++++++++-------------- Include/internal/pycore_runtime.h | 5 +- Python/pystate.c | 7 +- Python/sysmodule.c | 56 +- 4 files changed, 1321 insertions(+), 1287 deletions(-) diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index d6680f9064f3b1..52618bc69dc7cf 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1702,7 +1702,7 @@ - + @@ -2530,7 +2530,7 @@ - + @@ -3705,70 +3705,70 @@ - - - + + + - - + + - + - - - - + + + + - + - - + + - - + + - + - - + + - + - + - - + + - - - - + + + + - - - + + + - - + + - - + + @@ -11112,7 +11112,7 @@ - + @@ -11913,7 +11913,7 @@ - + @@ -11994,7 +11994,7 @@ - + @@ -13351,7 +13351,7 @@ - + @@ -13380,7 +13380,7 @@ - + @@ -13428,7 +13428,7 @@ - + @@ -13456,7 +13456,7 @@ - + @@ -13536,7 +13536,7 @@ - + @@ -13544,7 +13544,7 @@ - + @@ -13552,7 +13552,7 @@ - + @@ -13560,7 +13560,7 @@ - + @@ -13568,7 +13568,7 @@ - + @@ -13576,7 +13576,7 @@ - + @@ -13584,7 +13584,7 @@ - + @@ -13592,7 +13592,7 @@ - + @@ -13600,7 +13600,7 @@ - + @@ -13608,7 +13608,7 @@ - + @@ -13616,7 +13616,7 @@ - + @@ -13624,7 +13624,7 @@ - + @@ -13632,7 +13632,7 @@ - + @@ -15707,7 +15707,7 @@ - + @@ -15715,7 +15715,7 @@ - + @@ -15723,7 +15723,7 @@ - + @@ -15731,7 +15731,7 @@ - + @@ -15739,7 +15739,7 @@ - + @@ -15747,7 +15747,7 @@ - + @@ -15755,7 +15755,7 @@ - + @@ -15763,7 +15763,7 @@ - + @@ -15771,7 +15771,7 @@ - + @@ -15779,7 +15779,7 @@ - + @@ -15787,7 +15787,7 @@ - + @@ -15795,7 +15795,7 @@ - + @@ -15803,7 +15803,7 @@ - + @@ -15811,7 +15811,7 @@ - + @@ -15819,7 +15819,7 @@ - + @@ -15827,7 +15827,7 @@ - + @@ -15835,7 +15835,7 @@ - + @@ -16000,7 +16000,7 @@ - + @@ -16011,7 +16011,7 @@ - + @@ -16544,7 +16544,7 @@ - + @@ -16636,25 +16636,25 @@ - + - - - - - + + - - + + - - + + - + + + + - - + + @@ -16679,12 +16679,20 @@ + + + + + + + + - + @@ -16699,7 +16707,7 @@ - + @@ -16707,9 +16715,9 @@ - + - + @@ -16723,9 +16731,9 @@ - + - + @@ -16734,7 +16742,7 @@ - + @@ -16748,7 +16756,7 @@ - + @@ -16764,10 +16772,10 @@ - + - + @@ -16779,28 +16787,28 @@ - + - + - + - + - + - + - + @@ -16819,7 +16827,7 @@ - + @@ -16835,12 +16843,12 @@ - + - + @@ -16860,13 +16868,13 @@ - + - + @@ -16875,17 +16883,17 @@ - - + + - + - + - - + + @@ -16893,12 +16901,12 @@ - + - + - + @@ -16912,7 +16920,7 @@ - + @@ -16922,13 +16930,13 @@ - + - + - + @@ -16949,11 +16957,11 @@ - - + + - - + + @@ -16967,18 +16975,18 @@ - - + + - + - + - + @@ -16986,8 +16994,8 @@ - - + + @@ -16995,11 +17003,11 @@ - + - + - + @@ -17008,10 +17016,10 @@ - - + + - + @@ -17020,10 +17028,10 @@ - + - + @@ -17035,21 +17043,21 @@ - + - + - + - - - - - - - + + + + + + + @@ -17072,24 +17080,24 @@ - + - + - + - + - - + + - + - + @@ -17107,25 +17115,25 @@ - - - - - - + + + + + + - - + + - - + + @@ -17133,9 +17141,9 @@ - - - + + + @@ -17149,36 +17157,36 @@ - + - + - + - + - + - + - + - + - + - + @@ -17186,7 +17194,7 @@ - + @@ -17194,10 +17202,10 @@ - + - + @@ -17205,10 +17213,10 @@ - + - + @@ -17225,7 +17233,7 @@ - + @@ -17233,18 +17241,18 @@ - + - + - + - + - + @@ -17252,7 +17260,7 @@ - + @@ -17260,7 +17268,7 @@ - + @@ -17271,8 +17279,8 @@ - - + + @@ -17283,7 +17291,7 @@ - + @@ -17291,24 +17299,24 @@ - + - + - + - - - - + + + + @@ -17318,20 +17326,20 @@ - + - + - - - + + + - + @@ -17341,48 +17349,48 @@ - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + @@ -17405,7 +17413,7 @@ - + @@ -17413,7 +17421,7 @@ - + @@ -17458,163 +17466,163 @@ - + - + - - + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -17622,8 +17630,8 @@ - - + + @@ -17636,17 +17644,17 @@ - - + + - + - - + + @@ -17654,8 +17662,8 @@ - - + + @@ -17663,8 +17671,8 @@ - - + + @@ -17672,35 +17680,35 @@ - - + + - + - - + + - + - - + + - - + + @@ -17708,8 +17716,8 @@ - - + + @@ -17717,29 +17725,29 @@ - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -17777,7 +17785,7 @@ - + @@ -17807,22 +17815,22 @@ - + - + - + - + - + @@ -17873,13 +17881,13 @@ - + - + @@ -18172,7 +18180,7 @@ - + @@ -18203,7 +18211,7 @@ - + @@ -18254,7 +18262,7 @@ - + @@ -18264,7 +18272,7 @@ - + @@ -18275,7 +18283,7 @@ - + @@ -18285,7 +18293,7 @@ - + @@ -18348,7 +18356,7 @@ - + @@ -18369,7 +18377,7 @@ - + @@ -18512,27 +18520,27 @@ - + - + - + - + @@ -18574,7 +18582,7 @@ - + @@ -18587,11 +18595,11 @@ - + - + @@ -18608,24 +18616,24 @@ - + - - + + - + - + - - + + @@ -18634,7 +18642,7 @@ - + @@ -18653,18 +18661,18 @@ - + - + - + - + @@ -18677,32 +18685,32 @@ - + - + - + - + - + - + @@ -18710,28 +18718,28 @@ - + - - + + - + - + - - - + + + @@ -18742,8 +18750,8 @@ - - + + @@ -18755,7 +18763,7 @@ - + @@ -18773,22 +18781,22 @@ - + - + - + - + @@ -18833,9 +18841,9 @@ - - - + + + @@ -18851,7 +18859,7 @@ - + @@ -18862,7 +18870,7 @@ - + @@ -18875,13 +18883,13 @@ - + - + @@ -18895,27 +18903,27 @@ - + - + - + - + - + @@ -18923,8 +18931,8 @@ - - + + @@ -18953,22 +18961,22 @@ - + - + - + - - - - + + + + @@ -18982,39 +18990,39 @@ - - + + - + - - + + - + - + - + - - - + + + - + - + @@ -19022,189 +19030,189 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - - + + - + - + - + - - - + + + - + - + - + - + - - + + - + - - + + @@ -19224,43 +19232,43 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -19275,16 +19283,16 @@ - + - + - + @@ -19302,22 +19310,22 @@ - + - + - + - + - + @@ -19356,17 +19364,17 @@ - - - + + + - + - + @@ -19375,7 +19383,7 @@ - + @@ -19395,7 +19403,7 @@ - + @@ -19403,25 +19411,25 @@ - + - - - + + + - - + + - - + + @@ -19437,20 +19445,20 @@ - - + + - - - - - - + + + + + + @@ -19458,11 +19466,11 @@ - + - - + + @@ -19470,11 +19478,11 @@ - + - - + + @@ -19482,11 +19490,11 @@ - + - - + + @@ -19494,11 +19502,11 @@ - + - - + + @@ -19530,10 +19538,10 @@ - + - + @@ -19548,42 +19556,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -19595,51 +19603,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -19647,7 +19655,7 @@ - + @@ -19658,15 +19666,15 @@ - + - + - + @@ -19674,7 +19682,7 @@ - + @@ -19685,7 +19693,7 @@ - + @@ -19693,20 +19701,20 @@ - + - + - + - + @@ -19714,7 +19722,7 @@ - + @@ -19722,7 +19730,7 @@ - + @@ -19733,7 +19741,7 @@ - + @@ -19744,7 +19752,7 @@ - + @@ -19755,12 +19763,12 @@ - + - + @@ -19768,7 +19776,7 @@ - + @@ -19779,7 +19787,7 @@ - + @@ -19790,7 +19798,7 @@ - + @@ -19798,7 +19806,7 @@ - + @@ -19806,7 +19814,7 @@ - + @@ -19814,7 +19822,7 @@ - + @@ -19825,7 +19833,7 @@ - + @@ -19839,7 +19847,7 @@ - + @@ -19862,7 +19870,7 @@ - + @@ -19885,7 +19893,7 @@ - + @@ -19905,9 +19913,9 @@ - - - + + + @@ -19921,23 +19929,23 @@ - + - + - + - + - + @@ -19945,43 +19953,43 @@ - - - - + + + + - - - - - + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + @@ -20016,24 +20024,24 @@ - - - + + + - - - - - - - - + + + + + + + + - - - + + + @@ -20071,10 +20079,10 @@ - + - + @@ -20083,31 +20091,31 @@ - + - + - + - + - + - + @@ -20119,11 +20127,11 @@ - + - + @@ -20134,11 +20142,11 @@ - + - - + + @@ -20161,14 +20169,14 @@ - + - - + + @@ -20176,10 +20184,10 @@ - - + + - + @@ -20188,7 +20196,7 @@ - + @@ -20196,13 +20204,13 @@ - - + + - + - + @@ -20217,7 +20225,7 @@ - + @@ -20253,7 +20261,7 @@ - + @@ -20268,19 +20276,19 @@ - - + + - + - + @@ -20306,14 +20314,14 @@ - + - + - + @@ -20358,8 +20366,8 @@ - - + + @@ -20397,7 +20405,7 @@ - + @@ -20427,22 +20435,22 @@ - + - + - + - + - + @@ -20493,13 +20501,13 @@ - + - + @@ -20517,82 +20525,82 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + - - + + + - + - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - + + - - - - + + + + @@ -20824,143 +20832,143 @@ - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -21090,14 +21098,14 @@ - - + + - + - + @@ -21115,9 +21123,9 @@ - - + + @@ -21212,7 +21220,7 @@ - + @@ -21286,7 +21294,7 @@ - + @@ -21394,7 +21402,7 @@ - + @@ -21476,7 +21484,7 @@ - + @@ -21942,7 +21950,7 @@ - + @@ -21950,30 +21958,30 @@ - - + + - + - + - - - - - + + + + + - - - - - + + + + + - + @@ -22013,38 +22021,38 @@ - - + + - + - + - + - + - + - - + + - - + + @@ -22098,7 +22106,7 @@ - + @@ -22199,16 +22207,16 @@ - + - + - + - + @@ -22222,17 +22230,17 @@ - - + + - + - - + + @@ -22246,8 +22254,8 @@ - - + + @@ -22258,8 +22266,8 @@ - - + + @@ -22267,16 +22275,16 @@ - + - + - - + + - + @@ -22294,8 +22302,8 @@ - - + + @@ -22333,8 +22341,8 @@ - - + + @@ -22342,46 +22350,46 @@ - + - + - + - - + + - - + + - + - - + + - + - + - + - + - + @@ -22417,23 +22425,23 @@ - - + + - + - + - + - + - - + + @@ -22443,8 +22451,8 @@ - - + + @@ -22452,16 +22460,16 @@ - - + + - + - + @@ -22479,7 +22487,7 @@ - + @@ -22488,7 +22496,7 @@ - + @@ -22511,7 +22519,7 @@ - + @@ -22529,7 +22537,7 @@ - + @@ -22580,23 +22588,23 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -22612,38 +22620,38 @@ - - + + - + - + - - + + - + - + - + - + - + @@ -22653,56 +22661,56 @@ - + - + - + - + - + - - - + + + - + - + - + - + - + @@ -22711,7 +22719,7 @@ - + @@ -22735,11 +22743,11 @@ - + - + @@ -23017,15 +23025,15 @@ - + - + - + @@ -23033,11 +23041,11 @@ - - - - - + + + + + @@ -23082,7 +23090,7 @@ - + @@ -23165,7 +23173,7 @@ - + @@ -23239,15 +23247,15 @@ - + - + - + @@ -23265,7 +23273,7 @@ - + @@ -23282,7 +23290,7 @@ - + @@ -23290,15 +23298,15 @@ - - - - - - - - - + + + + + + + + + @@ -23370,9 +23378,9 @@ - + - + @@ -23384,7 +23392,7 @@ - + @@ -23423,7 +23431,7 @@ - + @@ -23557,8 +23565,8 @@ - - + + @@ -23570,11 +23578,11 @@ - - - - - + + + + + @@ -23589,28 +23597,28 @@ - + - + - + - + - - + + @@ -23619,24 +23627,24 @@ - - + + - + - + - + - - + + @@ -23644,7 +23652,7 @@ - + @@ -23652,9 +23660,9 @@ - - - + + + @@ -23666,7 +23674,7 @@ - + @@ -23860,7 +23868,7 @@ - + @@ -23871,11 +23879,11 @@ - + - - + + @@ -23895,24 +23903,24 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - + + - - + + @@ -23954,13 +23962,13 @@ - + - - + + @@ -23985,30 +23993,30 @@ - + - + - - + + - - + + - + - + @@ -24022,7 +24030,7 @@ - + @@ -24031,7 +24039,7 @@ - + @@ -24073,12 +24081,12 @@ - + - + @@ -24106,27 +24114,27 @@ - + - + - + - + - + @@ -24147,7 +24155,7 @@ - + @@ -24182,12 +24190,12 @@ - + - + @@ -24205,24 +24213,24 @@ - + - + - + - + - - - - - - + + + + + + @@ -24239,8 +24247,8 @@ - - + + @@ -24267,12 +24275,12 @@ - + - + @@ -24280,7 +24288,7 @@ - + @@ -24289,7 +24297,7 @@ - + @@ -24299,18 +24307,18 @@ - + - + - + - + @@ -24328,34 +24336,34 @@ - + - + - + - + - + - + - + - + - - - - + + + + @@ -24523,7 +24531,7 @@ - + @@ -24555,55 +24563,55 @@ - + - + - + - + - + - - - - + + + + - + - + - + - + - + - + - + - + - + @@ -24611,7 +24619,7 @@ - + @@ -24619,26 +24627,26 @@ - + - + - + - + - - + + - + @@ -24650,22 +24658,22 @@ - - - - - + + + + + - + - + - + @@ -24688,8 +24696,8 @@ - - + + @@ -24700,8 +24708,8 @@ - - + + @@ -24715,21 +24723,21 @@ - - - + + + - - - - - - - - - - - + + + + + + + + + + + @@ -24764,7 +24772,7 @@ - + @@ -24874,17 +24882,17 @@ - + - - + + - + @@ -25107,12 +25115,12 @@ - - + + - + @@ -25252,7 +25260,7 @@ - + @@ -25261,8 +25269,8 @@ - - + + @@ -25298,24 +25306,24 @@ - - + + - + - + - + @@ -25332,8 +25340,8 @@ - - + + @@ -25377,25 +25385,25 @@ - + - - + + - - - + + + - + @@ -25403,7 +25411,7 @@ - + @@ -25458,137 +25466,137 @@ - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - - + + + - + - + - + - + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - + + + - - + + @@ -25856,7 +25864,7 @@ - + @@ -25870,16 +25878,16 @@ - - + + - + - + @@ -25917,25 +25925,25 @@ - - - - - - - + + + + + + + - + - + - - + + - - + + @@ -25970,21 +25978,21 @@ - + - - + + - - + + @@ -26000,30 +26008,30 @@ - + - + - - + + - + - + - + - + @@ -26040,26 +26048,26 @@ - + - - + + - - + + - + @@ -26076,21 +26084,21 @@ - - + + - - + + - - + + @@ -26159,55 +26167,55 @@ - + - - + + - + - + - + - + - - + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - + + + @@ -26223,26 +26231,26 @@ - + - + - + - + - - + + @@ -26255,7 +26263,7 @@ - + @@ -26273,31 +26281,31 @@ - + - + - + - + - + - + @@ -26342,7 +26350,7 @@ - + @@ -26367,7 +26375,7 @@ - + diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 6e06e874711bc2..8f51e2def69fc9 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -143,7 +143,10 @@ typedef struct pyruntimestate { // is called multiple times. Py_OpenCodeHookFunction open_code_hook; void *open_code_userdata; - _Py_AuditHookEntry *audit_hook_head; + struct { + PyThread_type_lock mutex; + _Py_AuditHookEntry *head; + } audit_hooks; struct _py_object_runtime_state object_state; struct _Py_float_runtime_state float_state; diff --git a/Python/pystate.c b/Python/pystate.c index e3a010adbf5480..14ae1656ee73b0 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -380,7 +380,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP -#define NUMLOCKS 6 +#define NUMLOCKS 7 #define LOCKS_INIT(runtime) \ { \ &(runtime)->interpreters.mutex, \ @@ -389,6 +389,7 @@ _Py_COMP_DIAG_POP &(runtime)->unicode_state.ids.lock, \ &(runtime)->imports.extensions.mutex, \ &(runtime)->atexit.mutex, \ + &(runtime)->audit_hooks.mutex, \ } static int @@ -432,7 +433,7 @@ init_runtime(_PyRuntimeState *runtime, runtime->open_code_hook = open_code_hook; runtime->open_code_userdata = open_code_userdata; - runtime->audit_hook_head = audit_hook_head; + runtime->audit_hooks.head = audit_hook_head; PyPreConfig_InitPythonConfig(&runtime->preconfig); @@ -458,7 +459,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) initialization and interpreter initialization. */ void *open_code_hook = runtime->open_code_hook; void *open_code_userdata = runtime->open_code_userdata; - _Py_AuditHookEntry *audit_hook_head = runtime->audit_hook_head; + _Py_AuditHookEntry *audit_hook_head = runtime->audit_hooks.head; // bpo-42882: Preserve next_index value if Py_Initialize()/Py_Finalize() // is called multiple times. Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 33147f012b611d..e6731e7565fcec 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -168,7 +168,7 @@ should_audit(PyInterpreterState *interp) if (!interp) { return 0; } - return (interp->runtime->audit_hook_head + return (interp->runtime->audit_hooks.head || interp->audit_hooks || PyDTrace_AUDIT_ENABLED()); } @@ -224,8 +224,11 @@ sys_audit_tstate(PyThreadState *ts, const char *event, goto exit; } - /* Call global hooks */ - _Py_AuditHookEntry *e = is->runtime->audit_hook_head; + /* Call global hooks + * + * We don't worry about any races on hooks getting added, + * since that would not leave is in an inconsistent state. */ + _Py_AuditHookEntry *e = is->runtime->audit_hooks.head; for (; e; e = e->next) { if (e->hookCFunction(event, eventArgs, e->userData) < 0) { goto exit; @@ -353,8 +356,12 @@ _PySys_ClearAuditHooks(PyThreadState *ts) _PySys_Audit(ts, "cpython._PySys_ClearAuditHooks", NULL); _PyErr_Clear(ts); - _Py_AuditHookEntry *e = runtime->audit_hook_head, *n; - runtime->audit_hook_head = NULL; + /* We don't worry about the very unlikely race right here, + * since it's entirely benign. Nothing else removes entries + * from the list and adding an entry right now would not cause + * any trouble. */ + _Py_AuditHookEntry *e = runtime->audit_hooks.head, *n; + runtime->audit_hooks.head = NULL; while (e) { n = e->next; PyMem_RawFree(e); @@ -362,6 +369,22 @@ _PySys_ClearAuditHooks(PyThreadState *ts) } } +static void +add_audit_hook_entry_unlocked(_PyRuntimeState *runtime, + _Py_AuditHookEntry *entry) +{ + if (runtime->audit_hooks.head == NULL) { + runtime->audit_hooks.head = entry; + } + else { + _Py_AuditHookEntry *last = runtime->audit_hooks.head; + while (last->next) { + last = last->next; + } + last->next = entry; + } +} + int PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData) { @@ -389,29 +412,28 @@ PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData) } } - _Py_AuditHookEntry *e = runtime->audit_hook_head; - if (!e) { - e = (_Py_AuditHookEntry*)PyMem_RawMalloc(sizeof(_Py_AuditHookEntry)); - runtime->audit_hook_head = e; - } else { - while (e->next) { - e = e->next; - } - e = e->next = (_Py_AuditHookEntry*)PyMem_RawMalloc( + _Py_AuditHookEntry *e = (_Py_AuditHookEntry*)PyMem_RawMalloc( sizeof(_Py_AuditHookEntry)); - } - if (!e) { if (tstate != NULL) { _PyErr_NoMemory(tstate); } return -1; } - e->next = NULL; e->hookCFunction = (Py_AuditHookFunction)hook; e->userData = userData; + if (runtime->audit_hooks.mutex == NULL) { + /* The runtime must not be initailized yet. */ + add_audit_hook_entry_unlocked(runtime, e); + } + else { + PyThread_acquire_lock(runtime->audit_hooks.mutex, WAIT_LOCK); + add_audit_hook_entry_unlocked(runtime, e); + PyThread_release_lock(runtime->audit_hooks.mutex); + } + return 0; } From f565fed548dde2a4b36e1e91059ad0fb19697a2d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 14:57:33 -0700 Subject: [PATCH 0164/1206] [3.12] gh-102832: IDLE - remove use of deprecated sys.last_xyzs for stackviewer (GH-103339) (#105526) gh-102832: IDLE - remove use of deprecated sys.last_xyzs for stackviewer (GH-103339) (cherry picked from commit 3ee921d84f06da9dfa8aa29e0d33778b9dbf8f23) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/idlelib/idle_test/test_stackviewer.py | 14 +++----- Lib/idlelib/pyshell.py | 12 +++---- Lib/idlelib/run.py | 7 ++-- Lib/idlelib/stackviewer.py | 41 +++++------------------ 4 files changed, 22 insertions(+), 52 deletions(-) diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index 98f53f9537bb25..55f510382bf4c3 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -6,19 +6,12 @@ from tkinter import Tk from idlelib.tree import TreeNode, ScrolledCanvas -import sys class StackBrowserTest(unittest.TestCase): @classmethod def setUpClass(cls): - svs = stackviewer.sys - try: - abc - except NameError: - svs.last_type, svs.last_value, svs.last_traceback = ( - sys.exc_info()) requires('gui') cls.root = Tk() @@ -26,8 +19,6 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - svs = stackviewer.sys - del svs.last_traceback, svs.last_type, svs.last_value cls.root.update_idletasks() ## for id in cls.root.tk.call('after', 'info'): @@ -36,7 +27,10 @@ def tearDownClass(cls): del cls.root def test_init(self): - sb = stackviewer.StackBrowser(self.root) + try: + abc + except NameError as exc: + sb = stackviewer.StackBrowser(self.root, exc) isi = self.assertIsInstance isi(stackviewer.sc, ScrolledCanvas) isi(stackviewer.item, stackviewer.StackTreeItem) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index bdde156166171b..3141b477eff181 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1363,19 +1363,19 @@ def runit(self): self.text.tag_remove(self.user_input_insert_tags, index_before) self.shell_sidebar.update_sidebar() - def open_stack_viewer(self, event=None): + def open_stack_viewer(self, event=None): # -n mode only if self.interp.rpcclt: return self.interp.remote_stack_viewer() + + from idlelib.stackviewer import StackBrowser try: - sys.last_traceback + StackBrowser(self.root, sys.last_value, self.flist) except: messagebox.showerror("No stack trace", "There is no stack trace yet.\n" - "(sys.last_traceback is not defined)", + "(sys.last_value is not defined)", parent=self.text) - return - from idlelib.stackviewer import StackBrowser - StackBrowser(self.root, self.flist) + return None def view_restart_mark(self, event=None): self.text.see("iomark") diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 84792a82b0022c..4ffc90ab0c852a 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -622,7 +622,7 @@ def get_the_completion_list(self, what, mode): def stackviewer(self, flist_oid=None): if self.user_exc_info: - typ, val, tb = self.user_exc_info + _, exc, tb = self.user_exc_info else: return None flist = None @@ -630,9 +630,8 @@ def stackviewer(self, flist_oid=None): flist = self.rpchandler.get_remote_proxy(flist_oid) while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: tb = tb.tb_next - sys.last_type = typ - sys.last_value = val - item = stackviewer.StackTreeItem(flist, tb) + exc.__traceback__ = tb + item = stackviewer.StackTreeItem(exc, flist) return debugobj_r.remote_object_tree_item(item) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 94ffb4eff4dd26..7b00c4cdb7d033 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -1,33 +1,30 @@ import linecache import os -import sys import tkinter as tk from idlelib.debugobj import ObjectTreeItem, make_objecttreeitem from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas -def StackBrowser(root, flist=None, tb=None, top=None): +def StackBrowser(root, exc, flist=None, top=None): global sc, item, node # For testing. if top is None: top = tk.Toplevel(root) sc = ScrolledCanvas(top, bg="white", highlightthickness=0) sc.frame.pack(expand=1, fill="both") - item = StackTreeItem(flist, tb) + item = StackTreeItem(exc, flist) node = TreeNode(sc.canvas, None, item) node.expand() class StackTreeItem(TreeItem): - def __init__(self, flist=None, tb=None): + def __init__(self, exc, flist=None): self.flist = flist - self.stack = self.get_stack(tb) - self.text = self.get_exception() + self.stack = self.get_stack(None if exc is None else exc.__traceback__) + self.text = f"{type(exc).__name__}: {str(exc)}" def get_stack(self, tb): - if tb is None: - tb = sys.last_traceback stack = [] if tb and tb.tb_frame is None: tb = tb.tb_next @@ -36,17 +33,7 @@ def get_stack(self, tb): tb = tb.tb_next return stack - def get_exception(self): - type = sys.last_type - value = sys.last_value - if hasattr(type, "__name__"): - type = type.__name__ - s = str(type) - if value is not None: - s = s + ": " + str(value) - return s - - def GetText(self): + def GetText(self): # Titlecase names are overrides. return self.text def GetSubList(self): @@ -133,19 +120,9 @@ def _stack_viewer(parent): # htest # flist = PyShellFileList(top) try: # to obtain a traceback object intentional_name_error - except NameError: - exc_type, exc_value, exc_tb = sys.exc_info() - # inject stack trace to sys - sys.last_type = exc_type - sys.last_value = exc_value - sys.last_traceback = exc_tb - - StackBrowser(top, flist=flist, top=top, tb=exc_tb) - - # restore sys to original state - del sys.last_type - del sys.last_value - del sys.last_traceback + except NameError as e: + StackBrowser(top, e, flist=flist, top=top) + if __name__ == '__main__': from unittest import main From 3eccd95f56f2c360ec39a37e15ce7e9c3f134528 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 15:29:24 -0700 Subject: [PATCH 0165/1206] [3.12] gh-102832: IDLE - update stackviewer open (GH-105528) (#105534) gh-102832: IDLE - update stackviewer open (GH-105528) Use 'last_exc' instead of 'last_value' in 3.12/3. (cherry picked from commit bb3454c1a75c90da3c34c060eb23403fed3fd958) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/pyshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 3141b477eff181..6028700356b171 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1369,11 +1369,11 @@ def open_stack_viewer(self, event=None): # -n mode only from idlelib.stackviewer import StackBrowser try: - StackBrowser(self.root, sys.last_value, self.flist) + StackBrowser(self.root, sys.last_exc, self.flist) except: messagebox.showerror("No stack trace", "There is no stack trace yet.\n" - "(sys.last_value is not defined)", + "(sys.last_exc is not defined)", parent=self.text) return None From 77c03a3b7241a8476665db89f058bb6eb15f8abb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 15:35:53 -0700 Subject: [PATCH 0166/1206] [3.12] gh-100227: Lock Around Modification of the Global Allocators State (gh-105516) (gh-105532) The risk of a race with this state is relatively low, but we play it safe anyway. We do avoid using the lock in performance-sensitive cases where the risk of a race is very, very low. (cherry picked from commit 68dfa496278aa21585eb4654d5f7ef13ef76cb50) Co-authored-by: Eric Snow --- Doc/data/python3.12.abi | 345 +++++++++++++------------ Include/internal/pycore_pymem.h | 1 + Include/internal/pycore_runtime_init.h | 6 +- Objects/obmalloc.c | 229 ++++++++++++---- Python/pystate.c | 3 +- 5 files changed, 357 insertions(+), 227 deletions(-) diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 52618bc69dc7cf..0615923c38b667 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1702,7 +1702,7 @@ - + @@ -8477,63 +8477,63 @@ - - - + + + - - - + + + - - + + - + - + - - - + + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + @@ -10883,10 +10883,10 @@ - + - + @@ -13450,10 +13450,10 @@ - + - + @@ -13482,7 +13482,7 @@ - + @@ -13497,7 +13497,7 @@ - + @@ -13518,13 +13518,13 @@ - + - + - + @@ -13560,7 +13560,7 @@ - + @@ -13661,7 +13661,7 @@ - + @@ -14261,7 +14261,7 @@ - + @@ -14321,7 +14321,7 @@ - + @@ -14375,7 +14375,7 @@ - + @@ -14534,7 +14534,7 @@ - + @@ -14618,7 +14618,7 @@ - + @@ -15101,7 +15101,7 @@ - + @@ -15236,7 +15236,7 @@ - + @@ -15320,7 +15320,7 @@ - + @@ -15392,7 +15392,7 @@ - + @@ -15698,7 +15698,7 @@ - + @@ -15835,7 +15835,7 @@ - + @@ -16467,37 +16467,40 @@ - + - + - - + + - - + + + + + - + - + - + - + - + - + - + - + @@ -16544,7 +16547,7 @@ - + @@ -16566,94 +16569,94 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -17389,8 +17392,8 @@ - + @@ -25466,137 +25469,137 @@ - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - - + + + - + - + - + - + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - + + + - - + + diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h index 4cc953d8d779c9..c2f03254bb8760 100644 --- a/Include/internal/pycore_pymem.h +++ b/Include/internal/pycore_pymem.h @@ -18,6 +18,7 @@ typedef struct { } debug_alloc_api_t; struct _pymem_allocators { + PyThread_type_lock mutex; struct { PyMemAllocatorEx raw; PyMemAllocatorEx mem; diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 3b1444f3429b9a..b507de0437d9aa 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -25,9 +25,9 @@ extern PyTypeObject _PyExc_MemoryError; #define _PyRuntimeState_INIT(runtime) \ { \ .allocators = { \ - _pymem_allocators_standard_INIT(runtime), \ - _pymem_allocators_debug_INIT, \ - _pymem_allocators_obj_arena_INIT, \ + .standard = _pymem_allocators_standard_INIT(runtime), \ + .debug = _pymem_allocators_debug_INIT, \ + .obj_arena = _pymem_allocators_obj_arena_INIT, \ }, \ .obmalloc = _obmalloc_global_state_INIT, \ .pyhash_state = pyhash_state_INIT, \ diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 090129fe8653f2..9620a8fbb44cac 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1,3 +1,5 @@ +/* Python's malloc wrappers (see pymem.h) */ + #include "Python.h" #include "pycore_code.h" // stats #include "pycore_pystate.h" // _PyInterpreterState_GET @@ -15,13 +17,14 @@ /* Defined in tracemalloc.c */ extern void _PyMem_DumpTraceback(int fd, const void *ptr); - -/* Python's malloc wrappers (see pymem.h) */ - static void _PyObject_DebugDumpAddress(const void *p); static void _PyMem_DebugCheckAddress(const char *func, char api_id, const void *p); -static void _PyMem_SetupDebugHooksDomain(PyMemAllocatorDomain domain); + +static void set_up_debug_hooks_domain_unlocked(PyMemAllocatorDomain domain); +static void set_up_debug_hooks_unlocked(void); +static void get_allocator_unlocked(PyMemAllocatorDomain, PyMemAllocatorEx *); +static void set_allocator_unlocked(PyMemAllocatorDomain, PyMemAllocatorEx *); /***************************************/ @@ -200,6 +203,7 @@ _PyMem_ArenaFree(void *Py_UNUSED(ctx), void *ptr, #endif +#define ALLOCATORS_MUTEX (_PyRuntime.allocators.mutex) #define _PyMem_Raw (_PyRuntime.allocators.standard.raw) #define _PyMem (_PyRuntime.allocators.standard.mem) #define _PyObject (_PyRuntime.allocators.standard.obj) @@ -207,12 +211,16 @@ _PyMem_ArenaFree(void *Py_UNUSED(ctx), void *ptr, #define _PyObject_Arena (_PyRuntime.allocators.obj_arena) +/***************************/ +/* managing the allocators */ +/***************************/ + static int -pymem_set_default_allocator(PyMemAllocatorDomain domain, int debug, - PyMemAllocatorEx *old_alloc) +set_default_allocator_unlocked(PyMemAllocatorDomain domain, int debug, + PyMemAllocatorEx *old_alloc) { if (old_alloc != NULL) { - PyMem_GetAllocator(domain, old_alloc); + get_allocator_unlocked(domain, old_alloc); } @@ -232,24 +240,32 @@ pymem_set_default_allocator(PyMemAllocatorDomain domain, int debug, /* unknown domain */ return -1; } - PyMem_SetAllocator(domain, &new_alloc); + set_allocator_unlocked(domain, &new_alloc); if (debug) { - _PyMem_SetupDebugHooksDomain(domain); + set_up_debug_hooks_domain_unlocked(domain); } return 0; } +#ifdef Py_DEBUG +static const int pydebug = 1; +#else +static const int pydebug = 0; +#endif + int _PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *old_alloc) { -#ifdef Py_DEBUG - const int debug = 1; -#else - const int debug = 0; -#endif - return pymem_set_default_allocator(domain, debug, old_alloc); + if (ALLOCATORS_MUTEX == NULL) { + /* The runtime must be initializing. */ + return set_default_allocator_unlocked(domain, pydebug, old_alloc); + } + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); + int res = set_default_allocator_unlocked(domain, pydebug, old_alloc); + PyThread_release_lock(ALLOCATORS_MUTEX); + return res; } @@ -289,8 +305,8 @@ _PyMem_GetAllocatorName(const char *name, PyMemAllocatorName *allocator) } -int -_PyMem_SetupAllocators(PyMemAllocatorName allocator) +static int +set_up_allocators_unlocked(PyMemAllocatorName allocator) { switch (allocator) { case PYMEM_ALLOCATOR_NOT_SET: @@ -298,15 +314,15 @@ _PyMem_SetupAllocators(PyMemAllocatorName allocator) break; case PYMEM_ALLOCATOR_DEFAULT: - (void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, NULL); - (void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_MEM, NULL); - (void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_OBJ, NULL); + (void)set_default_allocator_unlocked(PYMEM_DOMAIN_RAW, pydebug, NULL); + (void)set_default_allocator_unlocked(PYMEM_DOMAIN_MEM, pydebug, NULL); + (void)set_default_allocator_unlocked(PYMEM_DOMAIN_OBJ, pydebug, NULL); break; case PYMEM_ALLOCATOR_DEBUG: - (void)pymem_set_default_allocator(PYMEM_DOMAIN_RAW, 1, NULL); - (void)pymem_set_default_allocator(PYMEM_DOMAIN_MEM, 1, NULL); - (void)pymem_set_default_allocator(PYMEM_DOMAIN_OBJ, 1, NULL); + (void)set_default_allocator_unlocked(PYMEM_DOMAIN_RAW, 1, NULL); + (void)set_default_allocator_unlocked(PYMEM_DOMAIN_MEM, 1, NULL); + (void)set_default_allocator_unlocked(PYMEM_DOMAIN_OBJ, 1, NULL); break; #ifdef WITH_PYMALLOC @@ -314,14 +330,14 @@ _PyMem_SetupAllocators(PyMemAllocatorName allocator) case PYMEM_ALLOCATOR_PYMALLOC_DEBUG: { PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC; - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc); + set_allocator_unlocked(PYMEM_DOMAIN_RAW, &malloc_alloc); PyMemAllocatorEx pymalloc = PYMALLOC_ALLOC; - PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &pymalloc); - PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &pymalloc); + set_allocator_unlocked(PYMEM_DOMAIN_MEM, &pymalloc); + set_allocator_unlocked(PYMEM_DOMAIN_OBJ, &pymalloc); if (allocator == PYMEM_ALLOCATOR_PYMALLOC_DEBUG) { - PyMem_SetupDebugHooks(); + set_up_debug_hooks_unlocked(); } break; } @@ -331,12 +347,12 @@ _PyMem_SetupAllocators(PyMemAllocatorName allocator) case PYMEM_ALLOCATOR_MALLOC_DEBUG: { PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC; - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc); - PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &malloc_alloc); - PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &malloc_alloc); + set_allocator_unlocked(PYMEM_DOMAIN_RAW, &malloc_alloc); + set_allocator_unlocked(PYMEM_DOMAIN_MEM, &malloc_alloc); + set_allocator_unlocked(PYMEM_DOMAIN_OBJ, &malloc_alloc); if (allocator == PYMEM_ALLOCATOR_MALLOC_DEBUG) { - PyMem_SetupDebugHooks(); + set_up_debug_hooks_unlocked(); } break; } @@ -345,9 +361,19 @@ _PyMem_SetupAllocators(PyMemAllocatorName allocator) /* unknown allocator */ return -1; } + return 0; } +int +_PyMem_SetupAllocators(PyMemAllocatorName allocator) +{ + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); + int res = set_up_allocators_unlocked(allocator); + PyThread_release_lock(ALLOCATORS_MUTEX); + return res; +} + static int pymemallocator_eq(PyMemAllocatorEx *a, PyMemAllocatorEx *b) @@ -356,8 +382,8 @@ pymemallocator_eq(PyMemAllocatorEx *a, PyMemAllocatorEx *b) } -const char* -_PyMem_GetCurrentAllocatorName(void) +static const char* +get_current_allocator_name_unlocked(void) { PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC; #ifdef WITH_PYMALLOC @@ -406,6 +432,15 @@ _PyMem_GetCurrentAllocatorName(void) return NULL; } +const char* +_PyMem_GetCurrentAllocatorName(void) +{ + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); + const char *name = get_current_allocator_name_unlocked(); + PyThread_release_lock(ALLOCATORS_MUTEX); + return name; +} + #ifdef WITH_PYMALLOC static int @@ -428,7 +463,7 @@ _PyMem_PymallocEnabled(void) static void -_PyMem_SetupDebugHooksDomain(PyMemAllocatorDomain domain) +set_up_debug_hooks_domain_unlocked(PyMemAllocatorDomain domain) { PyMemAllocatorEx alloc; @@ -437,53 +472,66 @@ _PyMem_SetupDebugHooksDomain(PyMemAllocatorDomain domain) return; } - PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &_PyMem_Debug.raw.alloc); + get_allocator_unlocked(domain, &_PyMem_Debug.raw.alloc); alloc.ctx = &_PyMem_Debug.raw; alloc.malloc = _PyMem_DebugRawMalloc; alloc.calloc = _PyMem_DebugRawCalloc; alloc.realloc = _PyMem_DebugRawRealloc; alloc.free = _PyMem_DebugRawFree; - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); + set_allocator_unlocked(domain, &alloc); } else if (domain == PYMEM_DOMAIN_MEM) { if (_PyMem.malloc == _PyMem_DebugMalloc) { return; } - PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &_PyMem_Debug.mem.alloc); + get_allocator_unlocked(domain, &_PyMem_Debug.mem.alloc); alloc.ctx = &_PyMem_Debug.mem; alloc.malloc = _PyMem_DebugMalloc; alloc.calloc = _PyMem_DebugCalloc; alloc.realloc = _PyMem_DebugRealloc; alloc.free = _PyMem_DebugFree; - PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + set_allocator_unlocked(domain, &alloc); } else if (domain == PYMEM_DOMAIN_OBJ) { if (_PyObject.malloc == _PyMem_DebugMalloc) { return; } - PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &_PyMem_Debug.obj.alloc); + get_allocator_unlocked(domain, &_PyMem_Debug.obj.alloc); alloc.ctx = &_PyMem_Debug.obj; alloc.malloc = _PyMem_DebugMalloc; alloc.calloc = _PyMem_DebugCalloc; alloc.realloc = _PyMem_DebugRealloc; alloc.free = _PyMem_DebugFree; - PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); + set_allocator_unlocked(domain, &alloc); } } +static void +set_up_debug_hooks_unlocked(void) +{ + set_up_debug_hooks_domain_unlocked(PYMEM_DOMAIN_RAW); + set_up_debug_hooks_domain_unlocked(PYMEM_DOMAIN_MEM); + set_up_debug_hooks_domain_unlocked(PYMEM_DOMAIN_OBJ); +} + void PyMem_SetupDebugHooks(void) { - _PyMem_SetupDebugHooksDomain(PYMEM_DOMAIN_RAW); - _PyMem_SetupDebugHooksDomain(PYMEM_DOMAIN_MEM); - _PyMem_SetupDebugHooksDomain(PYMEM_DOMAIN_OBJ); + if (ALLOCATORS_MUTEX == NULL) { + /* The runtime must not be completely initialized yet. */ + set_up_debug_hooks_unlocked(); + return; + } + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); + set_up_debug_hooks_unlocked(); + PyThread_release_lock(ALLOCATORS_MUTEX); } -void -PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) +static void +get_allocator_unlocked(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) { switch(domain) { @@ -500,8 +548,8 @@ PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) } } -void -PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) +static void +set_allocator_unlocked(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) { switch(domain) { @@ -512,12 +560,77 @@ PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) } } +void +PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) +{ + if (ALLOCATORS_MUTEX == NULL) { + /* The runtime must not be completely initialized yet. */ + get_allocator_unlocked(domain, allocator); + return; + } + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); + get_allocator_unlocked(domain, allocator); + PyThread_release_lock(ALLOCATORS_MUTEX); +} + +void +PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator) +{ + if (ALLOCATORS_MUTEX == NULL) { + /* The runtime must not be completely initialized yet. */ + set_allocator_unlocked(domain, allocator); + return; + } + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); + set_allocator_unlocked(domain, allocator); + PyThread_release_lock(ALLOCATORS_MUTEX); +} + void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator) { + if (ALLOCATORS_MUTEX == NULL) { + /* The runtime must not be completely initialized yet. */ + *allocator = _PyObject_Arena; + return; + } + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); *allocator = _PyObject_Arena; + PyThread_release_lock(ALLOCATORS_MUTEX); } +void +PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator) +{ + if (ALLOCATORS_MUTEX == NULL) { + /* The runtime must not be completely initialized yet. */ + _PyObject_Arena = *allocator; + return; + } + PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK); + _PyObject_Arena = *allocator; + PyThread_release_lock(ALLOCATORS_MUTEX); +} + + +/* Note that there is a possible, but very unlikely, race in any place + * below where we call one of the allocator functions. We access two + * fields in each case: "malloc", etc. and "ctx". + * + * It is unlikely that the allocator will be changed while one of those + * calls is happening, much less in that very narrow window. + * Furthermore, the likelihood of a race is drastically reduced by the + * fact that the allocator may not be changed after runtime init + * (except with a wrapper). + * + * With the above in mind, we currently don't worry about locking + * around these uses of the runtime-global allocators state. */ + + +/*************************/ +/* the "arena" allocator */ +/*************************/ + void * _PyObject_VirtualAlloc(size_t size) { @@ -530,11 +643,10 @@ _PyObject_VirtualFree(void *obj, size_t size) _PyObject_Arena.free(_PyObject_Arena.ctx, obj, size); } -void -PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator) -{ - _PyObject_Arena = *allocator; -} + +/***********************/ +/* the "raw" allocator */ +/***********************/ void * PyMem_RawMalloc(size_t size) @@ -574,6 +686,10 @@ void PyMem_RawFree(void *ptr) } +/***********************/ +/* the "mem" allocator */ +/***********************/ + void * PyMem_Malloc(size_t size) { @@ -617,6 +733,10 @@ PyMem_Free(void *ptr) } +/***************************/ +/* pymem utility functions */ +/***************************/ + wchar_t* _PyMem_RawWcsdup(const wchar_t *str) { @@ -663,6 +783,11 @@ _PyMem_Strdup(const char *str) return copy; } + +/**************************/ +/* the "object" allocator */ +/**************************/ + void * PyObject_Malloc(size_t size) { diff --git a/Python/pystate.c b/Python/pystate.c index 14ae1656ee73b0..d63a873a5c3025 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -380,7 +380,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP -#define NUMLOCKS 7 +#define NUMLOCKS 8 #define LOCKS_INIT(runtime) \ { \ &(runtime)->interpreters.mutex, \ @@ -390,6 +390,7 @@ _Py_COMP_DIAG_POP &(runtime)->imports.extensions.mutex, \ &(runtime)->atexit.mutex, \ &(runtime)->audit_hooks.mutex, \ + &(runtime)->allocators.mutex, \ } static int From 68eeab7fdd1afd11bb058df173cab40d9ebe2b06 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 16:00:53 -0700 Subject: [PATCH 0167/1206] [3.12] CI: Configure macOS build as per updated devguide recommendations (GH-105533) (#105536) (cherry picked from commit a5f23d411062f9f29f8a7d7ddefe60d5d8e17d2e) Co-authored-by: Erlend E. Aasland --- .github/workflows/build.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 99acce905a8472..e1d4047a877739 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -242,9 +242,8 @@ jobs: run: brew install pkg-config openssl@1.1 xz gdbm tcl-tk - name: Configure CPython run: | - CFLAGS="-I$(brew --prefix gdbm)/include -I$(brew --prefix xz)/include" \ - LDFLAGS="-L$(brew --prefix gdbm)/lib -I$(brew --prefix xz)/lib" \ - PKG_CONFIG_PATH="$(brew --prefix tcl-tk)/lib/pkgconfig" \ + GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ + GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \ ./configure \ --config-cache \ --with-pydebug \ From 2f4a2d6c1b0c95f6be33a8c778b0212922a50530 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 8 Jun 2023 18:01:51 -0700 Subject: [PATCH 0168/1206] [3.12] gh-105332: [Enum] Fix unpickling flags in edge-cases (GH-105348) (GH-105520) * revert enum pickling from by-name to by-value (cherry picked from commit 4ff5690e591b7d11cf11e34bf61004e2ea58ab3c) Co-authored-by: Nikita Sobolev Co-authored-by: Ethan Furman --- Doc/howto/enum.rst | 11 ++++++- Lib/enum.py | 30 ++++++------------- Lib/test/test_enum.py | 28 ++++++++++++++++- ...-06-06-11-50-33.gh-issue-105332.tmpgRA.rst | 1 + 4 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 68b75c529e92c7..4312b4c8140f5c 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -517,7 +517,16 @@ from that module. nested in other classes. It is possible to modify how enum members are pickled/unpickled by defining -:meth:`__reduce_ex__` in the enumeration class. +:meth:`__reduce_ex__` in the enumeration class. The default method is by-value, +but enums with complicated values may want to use by-name:: + + >>> class MyEnum(Enum): + ... __reduce_ex__ = enum.pickle_by_enum_name + +.. note:: + + Using by-name for flags is not recommended, as unnamed aliases will + not unpickle. Functional API diff --git a/Lib/enum.py b/Lib/enum.py index bb71c84bd46373..62df304057a108 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -12,6 +12,7 @@ 'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP', 'global_flag_repr', 'global_enum_repr', 'global_str', 'global_enum', 'EnumCheck', 'CONTINUOUS', 'NAMED_FLAGS', 'UNIQUE', + 'pickle_by_global_name', 'pickle_by_enum_name', ] @@ -922,7 +923,6 @@ def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_globa body['__module__'] = module tmp_cls = type(name, (object, ), body) cls = _simple_enum(etype=cls, boundary=boundary or KEEP)(tmp_cls) - cls.__reduce_ex__ = _reduce_ex_by_global_name if as_global: global_enum(cls) else: @@ -1240,7 +1240,7 @@ def __hash__(self): return hash(self._name_) def __reduce_ex__(self, proto): - return getattr, (self.__class__, self._name_) + return self.__class__, (self._value_, ) # enum.property is used to provide access to the `name` and # `value` attributes of enum members while keeping some measure of @@ -1307,8 +1307,14 @@ def _generate_next_value_(name, start, count, last_values): return name.lower() -def _reduce_ex_by_global_name(self, proto): +def pickle_by_global_name(self, proto): + # should not be used with Flag-type enums return self.name +_reduce_ex_by_global_name = pickle_by_global_name + +def pickle_by_enum_name(self, proto): + # should not be used with Flag-type enums + return getattr, (self.__class__, self._name_) class FlagBoundary(StrEnum): """ @@ -1330,23 +1336,6 @@ class Flag(Enum, boundary=STRICT): Support for flags """ - def __reduce_ex__(self, proto): - cls = self.__class__ - unknown = self._value_ & ~cls._flag_mask_ - member_value = self._value_ & cls._flag_mask_ - if unknown and member_value: - return _or_, (cls(member_value), unknown) - for val in _iter_bits_lsb(member_value): - rest = member_value & ~val - if rest: - return _or_, (cls(rest), cls._value2member_map_.get(val)) - else: - break - if self._name_ is None: - return cls, (self._value_,) - else: - return getattr, (cls, self._name_) - _numeric_repr_ = repr @staticmethod @@ -2073,7 +2062,6 @@ def _old_convert_(etype, name, module, filter, source=None, *, boundary=None): # unless some values aren't comparable, in which case sort by name members.sort(key=lambda t: t[0]) cls = etype(name, members, module=module, boundary=boundary or KEEP) - cls.__reduce_ex__ = _reduce_ex_by_global_name return cls _stdlib_enums = IntEnum, StrEnum, IntFlag diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 98010d18c0adb2..b4ac3abfc7006f 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -31,6 +31,11 @@ def load_tests(loader, tests, ignore): '../../Doc/library/enum.rst', optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE, )) + if os.path.exists('Doc/howto/enum.rst'): + tests.addTests(doctest.DocFileSuite( + '../../Doc/howto/enum.rst', + optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE, + )) return tests MODULE = __name__ @@ -66,6 +71,7 @@ class FlagStooges(Flag): LARRY = 1 CURLY = 2 MOE = 4 + BIG = 389 except Exception as exc: FlagStooges = exc @@ -74,17 +80,20 @@ class FlagStoogesWithZero(Flag): LARRY = 1 CURLY = 2 MOE = 4 + BIG = 389 class IntFlagStooges(IntFlag): LARRY = 1 CURLY = 2 MOE = 4 + BIG = 389 class IntFlagStoogesWithZero(IntFlag): NOFLAG = 0 LARRY = 1 CURLY = 2 MOE = 4 + BIG = 389 # for pickle test and subclass tests class Name(StrEnum): @@ -1942,7 +1951,6 @@ class NEI(NamedInt, Enum): __qualname__ = 'NEI' x = ('the-x', 1) y = ('the-y', 2) - self.assertIs(NEI.__new__, Enum.__new__) self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") globals()['NamedInt'] = NamedInt @@ -1950,6 +1958,10 @@ class NEI(NamedInt, Enum): NI5 = NamedInt('test', 5) self.assertEqual(NI5, 5) self.assertEqual(NEI.y.value, 2) + with self.assertRaisesRegex(TypeError, "name and value must be specified"): + test_pickle_dump_load(self.assertIs, NEI.y) + # fix pickle support and try again + NEI.__reduce_ex__ = enum.pickle_by_enum_name test_pickle_dump_load(self.assertIs, NEI.y) test_pickle_dump_load(self.assertIs, NEI) @@ -3252,11 +3264,17 @@ def test_pickle(self): test_pickle_dump_load(self.assertEqual, FlagStooges.CURLY&~FlagStooges.CURLY) test_pickle_dump_load(self.assertIs, FlagStooges) + test_pickle_dump_load(self.assertEqual, FlagStooges.BIG) + test_pickle_dump_load(self.assertEqual, + FlagStooges.CURLY|FlagStooges.BIG) test_pickle_dump_load(self.assertIs, FlagStoogesWithZero.CURLY) test_pickle_dump_load(self.assertEqual, FlagStoogesWithZero.CURLY|FlagStoogesWithZero.MOE) test_pickle_dump_load(self.assertIs, FlagStoogesWithZero.NOFLAG) + test_pickle_dump_load(self.assertEqual, FlagStoogesWithZero.BIG) + test_pickle_dump_load(self.assertEqual, + FlagStoogesWithZero.CURLY|FlagStoogesWithZero.BIG) test_pickle_dump_load(self.assertIs, IntFlagStooges.CURLY) test_pickle_dump_load(self.assertEqual, @@ -3266,11 +3284,19 @@ def test_pickle(self): test_pickle_dump_load(self.assertEqual, IntFlagStooges(0)) test_pickle_dump_load(self.assertEqual, IntFlagStooges(0x30)) test_pickle_dump_load(self.assertIs, IntFlagStooges) + test_pickle_dump_load(self.assertEqual, IntFlagStooges.BIG) + test_pickle_dump_load(self.assertEqual, IntFlagStooges.BIG|1) + test_pickle_dump_load(self.assertEqual, + IntFlagStooges.CURLY|IntFlagStooges.BIG) test_pickle_dump_load(self.assertIs, IntFlagStoogesWithZero.CURLY) test_pickle_dump_load(self.assertEqual, IntFlagStoogesWithZero.CURLY|IntFlagStoogesWithZero.MOE) test_pickle_dump_load(self.assertIs, IntFlagStoogesWithZero.NOFLAG) + test_pickle_dump_load(self.assertEqual, IntFlagStoogesWithZero.BIG) + test_pickle_dump_load(self.assertEqual, IntFlagStoogesWithZero.BIG|1) + test_pickle_dump_load(self.assertEqual, + IntFlagStoogesWithZero.CURLY|IntFlagStoogesWithZero.BIG) def test_contains_tf(self): Open = self.Open diff --git a/Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst b/Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst new file mode 100644 index 00000000000000..31b6855a6ebfad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst @@ -0,0 +1 @@ +Revert pickling method from by-name back to by-value. From d29e86bea3bcd7a8379d8368b36c718ab7b5b3f3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Jun 2023 12:32:46 +0200 Subject: [PATCH 0169/1206] [3.12] gh-102304: Fix Py_INCREF() for limited C API 3.9 (#105553) * gh-102304: Fix Py_INCREF() for limited C API 3.9 (#105550) When Python is built in debug mode (Py_REF_DEBUG macro), Py_INCREF() and Py_DECREF() of the limited C API 3.9 (and older) now call Py_IncRef() and Py_DecRef(), since _Py_IncRef() and _Py_DecRef() were added to Python 3.10. (cherry picked from commit 7ba0fd9f87ad75f8eda8e002c2fc71049b815f33) * gh-102304: Remove Py_INCREF() doc change (#105552) Py_INCREF() was made compatible again with Python 3.9 and older in the limited API of Python debug mode. (cherry picked from commit 58e4b69f698e6fd0694a58f18679bbe0e7e50e91) --- Doc/whatsnew/3.12.rst | 9 --------- Include/object.h | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 18516cb9563f8b..8bc7e8a630e2a6 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1536,15 +1536,6 @@ Build Changes :file:`!configure`. (Contributed by Christian Heimes in :gh:`89886`.) -* C extensions built with the :ref:`limited C API ` - on :ref:`Python build in debug mode ` no longer support Python - 3.9 and older. In this configuration, :c:func:`Py_INCREF` and - :c:func:`Py_DECREF` are now always implemented as opaque function calls, - but the called functions were added to Python 3.10. Build C extensions - with a release build of Python or with Python 3.12 and older, to keep support - for Python 3.9 and older. - (Contributed by Victor Stinner in :gh:`102304`.) - C API Changes ============= diff --git a/Include/object.h b/Include/object.h index dc5b087db2f467..ad16b72cd42474 100644 --- a/Include/object.h +++ b/Include/object.h @@ -611,8 +611,14 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *); static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) { #if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) - // Stable ABI for Python built in debug mode + // Stable ABI for Python built in debug mode. _Py_IncRef() was added to + // Python 3.10.0a7, use Py_IncRef() on older Python versions. Py_IncRef() + // accepts NULL whereas _Py_IncRef() doesn't. +# if Py_LIMITED_API+0 >= 0x030a00A7 _Py_IncRef(op); +# else + Py_IncRef(op); +# endif #else // Non-limited C API and limited C API for Python 3.9 and older access // directly PyObject.ob_refcnt. @@ -642,9 +648,15 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) #endif #if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) -// Stable ABI for Python built in debug mode +// Stable ABI for Python built in debug mode. _Py_DecRef() was added to Python +// 3.10.0a7, use Py_DecRef() on older Python versions. Py_DecRef() accepts NULL +// whereas _Py_IncRef() doesn't. static inline void Py_DECREF(PyObject *op) { +# if Py_LIMITED_API+0 >= 0x030a00A7 _Py_DecRef(op); +# else + Py_DecRef(op); +# endif } #define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op)) From 7c298d2dc5fd2ccffff5a8f72646e50d5d3682f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 08:37:33 -0700 Subject: [PATCH 0170/1206] [3.12] Miscellaneous improvements to the typing docs (GH-105529) (#105567) Miscellaneous improvements to the typing docs (GH-105529) Mostly, these are changes so that we use shorter sentences and shorter paragraphs. In particular, I've tried to make the first sentence introducing each object in the typing API short and declarative. (cherry picked from commit 8e755923c97d689ba7c7fe8deb50c1b169263264) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 217 ++++++++++++++++++++++++++-------------- Lib/typing.py | 12 +-- Objects/typevarobject.c | 145 +++++++++++++++------------ 3 files changed, 229 insertions(+), 145 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index f9b44e1c74aa73..caf4a53006f5e7 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -158,9 +158,6 @@ Type aliases are useful for simplifying complex type signatures. For example:: servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None: ... -Note that ``None`` as a type hint is a special case and is replaced by -``type(None)``. - The :keyword:`type` statement is new in Python 3.12. For backwards compatibility, type aliases can also be created through simple assignment:: @@ -699,24 +696,31 @@ These can be used as types in annotations and do not support ``[]``. .. data:: AnyStr - ``AnyStr`` is a :ref:`constrained type variable ` defined as - ``AnyStr = TypeVar('AnyStr', str, bytes)``. + A :ref:`constrained type variable `. + + Definition:: + + AnyStr = TypeVar('AnyStr', str, bytes) - It is meant to be used for functions that may accept any kind of string - without allowing different kinds of strings to mix. For example:: + ``AnyStr`` is meant to be used for functions that may accept :class:`str` or + :class:`bytes` arguments but cannot allow the two to mix. + + For example:: def concat(a: AnyStr, b: AnyStr) -> AnyStr: return a + b - concat(u"foo", u"bar") # Ok, output has type 'unicode' - concat(b"foo", b"bar") # Ok, output has type 'bytes' - concat(u"foo", b"bar") # Error, cannot mix unicode and bytes + concat("foo", "bar") # OK, output has type 'str' + concat(b"foo", b"bar") # OK, output has type 'bytes' + concat("foo", b"bar") # Error, cannot mix str and bytes .. data:: LiteralString - Special type that includes only literal strings. A string + Special type that includes only literal strings. + + Any string literal is compatible with ``LiteralString``, as is another - ``LiteralString``, but an object typed as just ``str`` is not. + ``LiteralString``. However, an object typed as just ``str`` is not. A string created by composing ``LiteralString``-typed objects is also acceptable as a ``LiteralString``. @@ -728,15 +732,15 @@ These can be used as types in annotations and do not support ``[]``. ... def caller(arbitrary_string: str, literal_string: LiteralString) -> None: - run_query("SELECT * FROM students") # ok - run_query(literal_string) # ok - run_query("SELECT * FROM " + literal_string) # ok + run_query("SELECT * FROM students") # OK + run_query(literal_string) # OK + run_query("SELECT * FROM " + literal_string) # OK run_query(arbitrary_string) # type checker error run_query( # type checker error f"SELECT * FROM students WHERE name = {arbitrary_string}" ) - This is useful for sensitive APIs where arbitrary user-generated + ``LiteralString`` is useful for sensitive APIs where arbitrary user-generated strings could generate problems. For example, the two cases above that generate type checker errors could be vulnerable to an SQL injection attack. @@ -766,7 +770,7 @@ These can be used as types in annotations and do not support ``[]``. case str(): print("It's a str") case _: - never_call_me(arg) # ok, arg is of type Never + never_call_me(arg) # OK, arg is of type Never .. versionadded:: 3.11 @@ -776,6 +780,7 @@ These can be used as types in annotations and do not support ``[]``. .. data:: NoReturn Special type indicating that a function never returns. + For example:: from typing import NoReturn @@ -795,6 +800,7 @@ These can be used as types in annotations and do not support ``[]``. .. data:: Self Special type to represent the current enclosed class. + For example:: from typing import Self @@ -943,8 +949,6 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Optional - Optional type. - ``Optional[X]`` is equivalent to ``X | None`` (or ``Union[X, None]``). Note that this is not the same concept as an optional argument, @@ -1008,8 +1012,11 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Concatenate - Used with :data:`Callable` and :class:`ParamSpec` to type annotate a higher - order callable which adds, removes, or transforms parameters of another + Special form for annotating higher-order functions. + + ``Concatenate`` can be used in conjunction with :data:`Callable` and + :class:`ParamSpec` to annotate a higher-order callable which adds, removes, + or transforms parameters of another callable. Usage is in the form ``Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]``. ``Concatenate`` is currently only valid when used as the first argument to a :data:`Callable`. @@ -1110,18 +1117,22 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Literal - A type that can be used to indicate to type checkers that the - corresponding variable or function parameter has a value equivalent to - the provided literal (or one of several literals). For example:: + Special typing form to define "literal types". + + ``Literal`` can be used to indicate to type checkers that the + annotated object has a value equivalent to one of the + provided literals. + + For example:: def validate_simple(data: Any) -> Literal[True]: # always returns True ... - MODE = Literal['r', 'rb', 'w', 'wb'] - def open_helper(file: str, mode: MODE) -> str: + type Mode = Literal['r', 'rb', 'w', 'wb'] + def open_helper(file: str, mode: Mode) -> str: ... - open_helper('/some/path', 'r') # Passes type check + open_helper('/some/path', 'r') # Passes type check open_helper('/other/path', 'typo') # Error in type checker ``Literal[...]`` cannot be subclassed. At runtime, an arbitrary value @@ -1164,8 +1175,12 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Final - A special typing construct to indicate to type checkers that a name - cannot be re-assigned or overridden in a subclass. For example:: + Special typing construct to indicate final names to type checkers. + + Final names cannot be reassigned in any scope. Final names declared in class + scopes cannot be overridden in subclasses. + + For example:: MAX_SIZE: Final = 9000 MAX_SIZE += 1 # Error reported by type checker @@ -1183,10 +1198,17 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Required + Special typing construct to mark a :class:`TypedDict` key as required. + + This is mainly useful for ``total=False`` TypedDicts. See :class:`TypedDict` + and :pep:`655` for more details. + + .. versionadded:: 3.11 + .. data:: NotRequired - Special typing constructs that mark individual keys of a :class:`TypedDict` - as either required or non-required respectively. + Special typing construct to mark a :class:`TypedDict` key as potentially + missing. See :class:`TypedDict` and :pep:`655` for more details. @@ -1335,7 +1357,9 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: TypeGuard - Special typing form used to annotate the return type of a user-defined + Special typing construct for marking user-defined type guard functions. + + ``TypeGuard`` can be used to annotate the return type of a user-defined type guard function. ``TypeGuard`` only accepts a single type argument. At runtime, functions marked this way should return a boolean. @@ -1402,8 +1426,9 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. data:: Unpack - A typing operator that conceptually marks an object as having been - unpacked. For example, using the unpack operator ``*`` on a + Typing operator to conceptually mark an object as having been unpacked. + + For example, using the unpack operator ``*`` on a :class:`type variable tuple ` is equivalent to using ``Unpack`` to mark the type variable tuple as having been unpacked:: @@ -1855,11 +1880,16 @@ without the dedicated syntax, as documented below. for runtime introspection and have no special meaning to static type checkers. Calling :func:`get_origin` on either of these objects will return the - original ``ParamSpec``:: + original ``ParamSpec``: + + .. doctest:: - P = ParamSpec("P") - get_origin(P.args) # returns P - get_origin(P.kwargs) # returns P + >>> from typing import ParamSpec + >>> P = ParamSpec("P") + >>> get_origin(P.args) is P + True + >>> get_origin(P.kwargs) is P + True .. versionadded:: 3.10 @@ -2010,13 +2040,15 @@ These are not used in annotations. They are building blocks for declaring types. .. class:: NewType(name, tp) - A helper class to indicate a distinct type to a typechecker, - see :ref:`distinct`. At runtime it returns an object that returns - its argument when called. + Helper class to create low-overhead :ref:`distinct types `. + + A ``NewType`` is considered a distinct type by a typechecker. At runtime, + however, calling a ``NewType`` returns its argument unchanged. + Usage:: - UserId = NewType('UserId', int) - first_user = UserId(1) + UserId = NewType('UserId', int) # Declare the NewType "UserId" + first_user = UserId(1) # "UserId" returns the argument unchanged at runtime .. attribute:: __module__ @@ -2037,7 +2069,9 @@ These are not used in annotations. They are building blocks for declaring types. .. class:: Protocol(Generic) - Base class for protocol classes. Protocol classes are defined like this:: + Base class for protocol classes. + + Protocol classes are defined like this:: class Proto(Protocol): def meth(self) -> int: @@ -2490,11 +2524,12 @@ Other concrete types .. class:: Pattern Match - These type aliases - correspond to the return types from :func:`re.compile` and - :func:`re.match`. These types (and the corresponding functions) - are generic in ``AnyStr`` and can be made specific by writing - ``Pattern[str]``, ``Pattern[bytes]``, ``Match[str]``, or + Deprecated aliases corresponding to the return types from + :func:`re.compile` and :func:`re.match`. + + These types (and the corresponding functions) are generic over + :data:`AnyStr`. ``Pattern`` can be specialised as ``Pattern[str]`` or + ``Pattern[bytes]``; ``Match`` can be specialised as ``Match[str]`` or ``Match[bytes]``. .. deprecated-removed:: 3.8 3.13 @@ -2507,7 +2542,9 @@ Other concrete types .. class:: Text - ``Text`` is an alias for ``str``. It is provided to supply a forward + Deprecated alias for :class:`str`. + + ``Text`` is provided to supply a forward compatible path for Python 2 code: in Python 2, ``Text`` is an alias for ``unicode``. @@ -2584,6 +2621,7 @@ Corresponding to collections in :mod:`collections.abc` .. class:: Mapping(Collection[KT], Generic[KT, VT_co]) Deprecated alias to :class:`collections.abc.Mapping`. + This type can be used as follows:: def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: @@ -2935,6 +2973,7 @@ Functions and decorators last case can never execute, because ``arg`` is either an :class:`int` or a :class:`str`, and both options are covered by earlier cases. + If a type checker finds that a call to ``assert_never()`` is reachable, it will emit an error. For example, if the type annotation for ``arg`` was instead ``int | str | float``, the type checker would @@ -2985,11 +3024,14 @@ Functions and decorators .. decorator:: dataclass_transform - :data:`~typing.dataclass_transform` may be used to + Decorator to mark an object as providing + :func:`~dataclasses.dataclass`-like behavior. + + ``dataclass_transform`` may be used to decorate a class, metaclass, or a function that is itself a decorator. The presence of ``@dataclass_transform()`` tells a static type checker that the decorated object performs runtime "magic" that - transforms a class, giving it :func:`dataclasses.dataclass`-like behaviors. + transforms a class in a similar way to :func:`dataclasses.dataclass`. Example usage with a decorator function: @@ -3090,16 +3132,22 @@ Functions and decorators .. decorator:: overload + Decorator for creating overloaded functions and methods. + The ``@overload`` decorator allows describing functions and methods that support multiple different combinations of argument types. A series of ``@overload``-decorated definitions must be followed by exactly one non-``@overload``-decorated definition (for the same function/method). - The ``@overload``-decorated definitions are for the benefit of the + + ``@overload``-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the - non-``@overload``-decorated definition, while the latter is used at + non-``@overload``-decorated definition. The non-``@overload``-decorated + definition, meanwhile, will be used at runtime but should be ignored by a type checker. At runtime, calling - a ``@overload``-decorated function directly will raise - :exc:`NotImplementedError`. An example of overload that gives a more + an ``@overload``-decorated function directly will raise + :exc:`NotImplementedError`. + + An example of overload that gives a more precise type than can be expressed using a union or a type variable: .. testcode:: @@ -3126,7 +3174,9 @@ Functions and decorators .. function:: get_overloads(func) Return a sequence of :func:`@overload `-decorated definitions for - *func*. *func* is the function object for the implementation of the + *func*. + + *func* is the function object for the implementation of the overloaded function. For example, given the definition of ``process`` in the documentation for :func:`@overload `, ``get_overloads(process)`` will return a sequence of three function objects @@ -3141,16 +3191,21 @@ Functions and decorators .. function:: clear_overloads() - Clear all registered overloads in the internal registry. This can be used - to reclaim the memory used by the registry. + Clear all registered overloads in the internal registry. + + This can be used to reclaim the memory used by the registry. .. versionadded:: 3.11 .. decorator:: final - A decorator to indicate to type checkers that the decorated method - cannot be overridden, and the decorated class cannot be subclassed. + Decorator to indicate final methods and final classes. + + Decorating a method with ``@final`` indicates to a type checker that the + method cannot be overridden in a subclass. Decorating a class with ``@final`` + indicates that it cannot be subclassed. + For example:: class Base: @@ -3173,7 +3228,7 @@ Functions and decorators .. versionadded:: 3.8 .. versionchanged:: 3.11 - The decorator will now set the ``__final__`` attribute to ``True`` + The decorator will now attempt to set a ``__final__`` attribute to ``True`` on the decorated object. Thus, a check like ``if getattr(obj, "__final__", False)`` can be used at runtime to determine whether an object ``obj`` has been marked as final. @@ -3185,11 +3240,13 @@ Functions and decorators Decorator to indicate that annotations are not type hints. - This works as class or function :term:`decorator`. With a class, it + This works as a class or function :term:`decorator`. With a class, it applies recursively to all methods and classes defined in that class - (but not to methods defined in its superclasses or subclasses). + (but not to methods defined in its superclasses or subclasses). Type + checkers will ignore all annotations in a function or class with this + decorator. - This mutates the function(s) in place. + ``@no_type_check`` mutates the decorated object in place. .. decorator:: no_type_check_decorator @@ -3201,8 +3258,11 @@ Functions and decorators .. decorator:: override - A decorator for methods that indicates to type checkers that this method - should override a method or attribute with the same name on a base class. + Decorator to indicate that a method in a subclass is intended to override a + method or attribute in a superclass. + + Type checkers should emit an error if a method decorated with ``@override`` + does not, in fact, override anything. This helps prevent bugs that may occur when a base class is changed without an equivalent change to a child class. @@ -3225,7 +3285,7 @@ Functions and decorators There is no runtime checking of this property. - The decorator will set the ``__override__`` attribute to ``True`` on + The decorator will attempt to set an ``__override__`` attribute to ``True`` on the decorated object. Thus, a check like ``if getattr(obj, "__override__", False)`` can be used at runtime to determine whether an object ``obj`` has been marked as an override. If the decorated object @@ -3239,7 +3299,7 @@ Functions and decorators .. decorator:: type_check_only - Decorator to mark a class or function to be unavailable at runtime. + Decorator to mark a class or function as unavailable at runtime. This decorator is itself not available at runtime. It is mainly intended to mark classes that are defined in type stub files if @@ -3293,6 +3353,7 @@ Introspection helpers .. versionchanged:: 3.9 Added ``include_extras`` parameter as part of :pep:`593`. + See the documentation on :data:`Annotated` for more information. .. versionchanged:: 3.11 Previously, ``Optional[t]`` was added for function and method annotations @@ -3302,11 +3363,14 @@ Introspection helpers .. function:: get_origin(tp) Get the unsubscripted version of a type: for a typing object of the form - ``X[Y, Z, ...]`` return ``X``. If ``X`` is a generic alias for a builtin or - :mod:`collections` class, it gets normalized to the original class. + ``X[Y, Z, ...]`` return ``X``. + + If ``X`` is a typing-module alias for a builtin or + :mod:`collections` class, it will be normalized to the original class. If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, return the underlying :class:`ParamSpec`. Return ``None`` for unsupported objects. + Examples: .. testcode:: @@ -3324,10 +3388,12 @@ Introspection helpers Get type arguments with all substitutions performed: for a typing object of the form ``X[Y, Z, ...]`` return ``(Y, Z, ...)``. + If ``X`` is a union or :class:`Literal` contained in another generic type, the order of ``(Y, Z, ...)`` may be different from the order of the original arguments ``[Y, Z, ...]`` due to type caching. Return ``()`` for unsupported objects. + Examples: .. testcode:: @@ -3361,9 +3427,10 @@ Introspection helpers .. class:: ForwardRef - A class used for internal typing representation of string forward references. + Class used for internal typing representation of string forward references. + For example, ``List["SomeClass"]`` is implicitly transformed into - ``List[ForwardRef("SomeClass")]``. This class should not be instantiated by + ``List[ForwardRef("SomeClass")]``. ``ForwardRef`` should not be instantiated by a user, but may be used by introspection tools. .. note:: @@ -3379,7 +3446,9 @@ Constant .. data:: TYPE_CHECKING A special constant that is assumed to be ``True`` by 3rd party static - type checkers. It is ``False`` at runtime. Usage:: + type checkers. It is ``False`` at runtime. + + Usage:: if TYPE_CHECKING: import expensive_mod diff --git a/Lib/typing.py b/Lib/typing.py index 44b26af92b3d99..0b1d9689a6b7a8 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -567,7 +567,7 @@ def int_or_str(arg: int | str) -> None: case str(): print("It's a str") case _: - never_call_me(arg) # ok, arg is of type Never + never_call_me(arg) # OK, arg is of type Never """ raise TypeError(f"{self} is not subscriptable") @@ -600,13 +600,13 @@ def LiteralString(self, parameters): from typing import LiteralString - def run_query(sql: LiteralString) -> ... + def run_query(sql: LiteralString) -> None: ... def caller(arbitrary_string: str, literal_string: LiteralString) -> None: - run_query("SELECT * FROM students") # ok - run_query(literal_string) # ok - run_query("SELECT * FROM " + literal_string) # ok + run_query("SELECT * FROM students") # OK + run_query(literal_string) # OK + run_query("SELECT * FROM " + literal_string) # OK run_query(arbitrary_string) # type checker error run_query( # type checker error f"SELECT * FROM students WHERE name = {arbitrary_string}" @@ -2124,7 +2124,7 @@ def assert_type(val, typ, /): emits an error if the value is not of the specified type:: def greet(name: str) -> None: - assert_type(name, str) # ok + assert_type(name, str) # OK assert_type(name, int) # type checker error """ return val diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 0b7d84c706d94e..406a6eb76e3a8a 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -443,23 +443,25 @@ static PyMethodDef typevar_methods[] = { PyDoc_STRVAR(typevar_doc, "Type variable.\n\ \n\ -The preferred way to construct a type variable is via the dedicated syntax\n\ -for generic functions, classes, and type aliases:\n\ +The preferred way to construct a type variable is via the dedicated\n\ +syntax for generic functions, classes, and type aliases::\n\ \n\ class Sequence[T]: # T is a TypeVar\n\ ...\n\ \n\ This syntax can also be used to create bound and constrained type\n\ -variables:\n\ +variables::\n\ \n\ - class StrSequence[S: str]: # S is a TypeVar bound to str\n\ + # S is a TypeVar bound to str\n\ + class StrSequence[S: str]:\n\ ...\n\ \n\ - class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes\n\ + # A is a TypeVar constrained to str or bytes\n\ + class StrOrBytesSequence[A: (str, bytes)]:\n\ ...\n\ \n\ However, if desired, reusable type variables can also be constructed\n\ -manually, like so:\n\ +manually, like so::\n\ \n\ T = TypeVar('T') # Can be anything\n\ S = TypeVar('S', bound=str) # Can be any subtype of str\n\ @@ -469,12 +471,13 @@ Type variables exist primarily for the benefit of static type\n\ checkers. They serve as the parameters for generic types as well\n\ as for generic function and type alias definitions.\n\ \n\ -The variance of type variables is inferred by type checkers when they are created\n\ -through the type parameter syntax and when ``infer_variance=True`` is passed.\n\ -Manually created type variables may be explicitly marked covariant or\n\ -contravariant by passing ``covariant=True`` or ``contravariant=True``.\n\ -By default, manually created type variables are invariant. See PEP 484\n\ -and PEP 695 for more details.\n\ +The variance of type variables is inferred by type checkers when they\n\ +are created through the type parameter syntax and when\n\ +``infer_variance=True`` is passed. Manually created type variables may\n\ +be explicitly marked covariant or contravariant by passing\n\ +``covariant=True`` or ``contravariant=True``. By default, manually\n\ +created type variables are invariant. See PEP 484 and PEP 695 for more\n\ +details.\n\ "); static PyType_Slot typevar_slots[] = { @@ -616,12 +619,14 @@ PyDoc_STRVAR(paramspecargs_doc, \n\ Given a ParamSpec object P, P.args is an instance of ParamSpecArgs.\n\ \n\ -ParamSpecArgs objects have a reference back to their ParamSpec:\n\ +ParamSpecArgs objects have a reference back to their ParamSpec::\n\ \n\ - P.args.__origin__ is P\n\ + >>> P = ParamSpec(\"P\")\n\ + >>> P.args.__origin__ is P\n\ + True\n\ \n\ -This type is meant for runtime introspection and has no special meaning to\n\ -static type checkers.\n\ +This type is meant for runtime introspection and has no special meaning\n\ +to static type checkers.\n\ "); static PyType_Slot paramspecargs_slots[] = { @@ -693,12 +698,14 @@ PyDoc_STRVAR(paramspeckwargs_doc, \n\ Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs.\n\ \n\ -ParamSpecKwargs objects have a reference back to their ParamSpec:\n\ +ParamSpecKwargs objects have a reference back to their ParamSpec::\n\ \n\ - P.kwargs.__origin__ is P\n\ + >>> P = ParamSpec(\"P\")\n\ + >>> P.kwargs.__origin__ is P\n\ + True\n\ \n\ -This type is meant for runtime introspection and has no special meaning to\n\ -static type checkers.\n\ +This type is meant for runtime introspection and has no special meaning\n\ +to static type checkers.\n\ "); static PyType_Slot paramspeckwargs_slots[] = { @@ -935,24 +942,26 @@ static PyMethodDef paramspec_methods[] = { PyDoc_STRVAR(paramspec_doc, "Parameter specification variable.\n\ \n\ -The preferred way to construct a parameter specification is via the dedicated syntax\n\ -for generic functions, classes, and type aliases, where\n\ -the use of '**' creates a parameter specification:\n\ +The preferred way to construct a parameter specification is via the\n\ +dedicated syntax for generic functions, classes, and type aliases,\n\ +where the use of '**' creates a parameter specification::\n\ \n\ type IntFunc[**P] = Callable[P, int]\n\ \n\ For compatibility with Python 3.11 and earlier, ParamSpec objects\n\ -can also be created as follows:\n\ +can also be created as follows::\n\ \n\ P = ParamSpec('P')\n\ \n\ -Parameter specification variables exist primarily for the benefit of static\n\ -type checkers. They are used to forward the parameter types of one\n\ -callable to another callable, a pattern commonly found in higher order\n\ -functions and decorators. They are only valid when used in ``Concatenate``,\n\ -or as the first argument to ``Callable``, or as parameters for user-defined\n\ -Generics. See class Generic for more information on generic types. An\n\ -example for annotating a decorator:\n\ +Parameter specification variables exist primarily for the benefit of\n\ +static type checkers. They are used to forward the parameter types of\n\ +one callable to another callable, a pattern commonly found in\n\ +higher-order functions and decorators. They are only valid when used\n\ +in ``Concatenate``, or as the first argument to ``Callable``, or as\n\ +parameters for user-defined Generics. See class Generic for more\n\ +information on generic types.\n\ +\n\ +An example for annotating a decorator::\n\ \n\ def add_logging[**P, T](f: Callable[P, T]) -> Callable[P, T]:\n\ '''A type-safe decorator to add logging to a function.'''\n\ @@ -966,12 +975,14 @@ example for annotating a decorator:\n\ '''Add two numbers together.'''\n\ return x + y\n\ \n\ -Parameter specification variables can be introspected. e.g.:\n\ +Parameter specification variables can be introspected. e.g.::\n\ \n\ - P.__name__ == 'P'\n\ + >>> P = ParamSpec(\"P\")\n\ + >>> P.__name__\n\ + 'P'\n\ \n\ -Note that only parameter specification variables defined in global scope can\n\ -be pickled.\n\ +Note that only parameter specification variables defined in the global\n\ +scope can be pickled.\n\ "); static PyType_Slot paramspec_slots[] = { @@ -1167,34 +1178,35 @@ PyDoc_STRVAR(typevartuple_doc, "Type variable tuple. A specialized form of type variable that enables\n\ variadic generics.\n\ \n\ -The preferred way to construct a type variable tuple is via the dedicated syntax\n\ -for generic functions, classes, and type aliases, where a single\n\ -'*' indicates a type variable tuple:\n\ +The preferred way to construct a type variable tuple is via the\n\ +dedicated syntax for generic functions, classes, and type aliases,\n\ +where a single '*' indicates a type variable tuple::\n\ \n\ def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:\n\ return (*tup[1:], tup[0])\n\ \n\ For compatibility with Python 3.11 and earlier, TypeVarTuple objects\n\ -can also be created as follows:\n\ +can also be created as follows::\n\ \n\ - Ts = TypeVarTuple('Ts') # Can be given any name\n\ + Ts = TypeVarTuple('Ts') # Can be given any name\n\ \n\ Just as a TypeVar (type variable) is a placeholder for a single type,\n\ a TypeVarTuple is a placeholder for an *arbitrary* number of types. For\n\ -example, if we define a generic class using a TypeVarTuple:\n\ +example, if we define a generic class using a TypeVarTuple::\n\ \n\ - class C[*Ts]: ...\n\ + class C[*Ts]: ...\n\ \n\ Then we can parameterize that class with an arbitrary number of type\n\ -arguments:\n\ +arguments::\n\ \n\ - C[int] # Fine\n\ - C[int, str] # Also fine\n\ - C[()] # Even this is fine\n\ + C[int] # Fine\n\ + C[int, str] # Also fine\n\ + C[()] # Even this is fine\n\ \n\ For more details, see PEP 646.\n\ \n\ -Note that only TypeVarTuples defined in global scope can be pickled.\n\ +Note that only TypeVarTuples defined in the global scope can be\n\ +pickled.\n\ "); PyType_Slot typevartuple_slots[] = { @@ -1436,21 +1448,21 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, PyDoc_STRVAR(typealias_doc, "Type alias.\n\ \n\ -Type aliases are created through the type statement:\n\ +Type aliases are created through the type statement::\n\ \n\ - type Alias = int\n\ + type Alias = int\n\ \n\ In this example, Alias and int will be treated equivalently by static\n\ type checkers.\n\ \n\ -At runtime, Alias is an instance of TypeAliasType. The __name__ attribute\n\ -holds the name of the type alias. The value of the type\n\ -alias is stored in the __value__ attribute. It is evaluated lazily, so\n\ -the value is computed only if the attribute is accessed.\n\ +At runtime, Alias is an instance of TypeAliasType. The __name__\n\ +attribute holds the name of the type alias. The value of the type alias\n\ +is stored in the __value__ attribute. It is evaluated lazily, so the\n\ +value is computed only if the attribute is accessed.\n\ \n\ -Type aliases can also be generic:\n\ +Type aliases can also be generic::\n\ \n\ - type ListOrSet[T] = list[T] | set[T]\n\ + type ListOrSet[T] = list[T] | set[T]\n\ \n\ In this case, the type parameters of the alias are stored in the\n\ __type_params__ attribute.\n\ @@ -1502,18 +1514,21 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args) PyDoc_STRVAR(generic_doc, "Abstract base class for generic types.\n\ \n\ -A generic type is typically declared by inheriting from\n\ -this class parameterized with one or more type variables.\n\ -For example, a generic mapping type might be defined as:\n\ +On Python 3.12 and newer, generic classes implicitly inherit from\n\ +Generic when they declare a parameter list after the class's name::\n\ \n\ - class Mapping(Generic[KT, VT]):\n\ + class Mapping[KT, VT]:\n\ def __getitem__(self, key: KT) -> VT:\n\ ...\n\ # Etc.\n\ \n\ -This class can then be used as follows:\n\ +On older versions of Python, however, generic classes have to\n\ +explicitly inherit from Generic.\n\ +\n\ +After a class has been declared to be generic, it can then be used as\n\ +follows::\n\ \n\ - def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:\n\ + def lookup_name[KT, VT](mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:\n\ try:\n\ return mapping[key]\n\ except KeyError:\n\ @@ -1523,12 +1538,12 @@ This class can then be used as follows:\n\ PyDoc_STRVAR(generic_class_getitem_doc, "Parameterizes a generic class.\n\ \n\ -At least, parameterizing a generic class is the *main* thing this method\n\ -does. For example, for some generic class `Foo`, this is called when we\n\ -do `Foo[int]` - there, with `cls=Foo` and `params=int`.\n\ +At least, parameterizing a generic class is the *main* thing this\n\ +method does. For example, for some generic class `Foo`, this is called\n\ +when we do `Foo[int]` - there, with `cls=Foo` and `params=int`.\n\ \n\ However, note that this method is also called when defining generic\n\ -classes in the first place with `class Foo(Generic[T]): ...`.\n\ +classes in the first place with `class Foo[T]: ...`.\n\ "); static PyObject * From 97d846dc2b6a790298cbfbb5669d180281cfda89 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:00:42 -0700 Subject: [PATCH 0171/1206] [3.12] Clarify the supported cases in the tokenize module (GH-105569) (#105573) Co-authored-by: Pablo Galindo Salgado --- Doc/library/tokenize.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/library/tokenize.rst b/Doc/library/tokenize.rst index 41222a771d1b47..bffe93006edc7b 100644 --- a/Doc/library/tokenize.rst +++ b/Doc/library/tokenize.rst @@ -22,6 +22,15 @@ the generic :data:`~token.OP` token type. The exact type can be determined by checking the ``exact_type`` property on the :term:`named tuple` returned from :func:`tokenize.tokenize`. + +.. warning:: + + Note that the functions in this module are only designed to parse + syntactically valid Python code (code that does not raise when parsed + using :func:`ast.parse`). The behavior of the functions in this module is + **undefined** when providing invalid Python code and it can change at any + point. + Tokenizing Input ---------------- From 16b1cdc87c08c01294b66257a26574725b005c50 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:58:14 -0700 Subject: [PATCH 0172/1206] [3.12] gh-105564: Don't include artificial newlines in the line attribute of tokens (GH-105565) (#105579) Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_tokenize.py | 16 ++++++++-------- ...023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst | 2 ++ Python/Python-tokenize.c | 3 +++ 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 6747b0d8f65a17..2c124f062e7fd6 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1229,7 +1229,7 @@ def readline(): # skip the initial encoding token and the end tokens tokens = list(_generate_tokens_from_c_tokenizer(readline().__next__, encoding='utf-8', extra_tokens=True))[:-2] - expected_tokens = [TokenInfo(3, '"ЉЊЈÐЂ"', (1, 0), (1, 7), '"ЉЊЈÐЂ"\n')] + expected_tokens = [TokenInfo(3, '"ЉЊЈÐЂ"', (1, 0), (1, 7), '"ЉЊЈÐЂ"')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") @@ -1638,8 +1638,8 @@ def test_comment_at_the_end_of_the_source_without_newline(self): TokenInfo(type=token.NUMBER, string='1', start=(1, 4), end=(1, 5), line='b = 1\n'), TokenInfo(type=token.NEWLINE, string='\n', start=(1, 5), end=(1, 6), line='b = 1\n'), TokenInfo(type=token.NL, string='\n', start=(2, 0), end=(2, 1), line='\n'), - TokenInfo(type=token.COMMENT, string='#test', start=(3, 0), end=(3, 5), line='#test\n'), - TokenInfo(type=token.NL, string='', start=(3, 5), end=(3, 6), line='#test\n'), + TokenInfo(type=token.COMMENT, string='#test', start=(3, 0), end=(3, 5), line='#test'), + TokenInfo(type=token.NL, string='', start=(3, 5), end=(3, 6), line='#test'), TokenInfo(type=token.ENDMARKER, string='', start=(4, 0), end=(4, 0), line='') ] @@ -1653,7 +1653,7 @@ def test_newline_and_space_at_the_end_of_the_source_without_newline(self): TokenInfo(token.ENCODING, string='utf-8', start=(0, 0), end=(0, 0), line=''), TokenInfo(token.NAME, string='a', start=(1, 0), end=(1, 1), line='a\n'), TokenInfo(token.NEWLINE, string='\n', start=(1, 1), end=(1, 2), line='a\n'), - TokenInfo(token.NL, string='', start=(2, 1), end=(2, 2), line=' \n'), + TokenInfo(token.NL, string='', start=(2, 1), end=(2, 2), line=' '), TokenInfo(token.ENDMARKER, string='', start=(3, 0), end=(3, 0), line='') ] @@ -1889,10 +1889,10 @@ def readline(encoding): yield "1+1".encode(encoding) expected = [ - TokenInfo(type=NUMBER, string='1', start=(1, 0), end=(1, 1), line='1+1\n'), - TokenInfo(type=OP, string='+', start=(1, 1), end=(1, 2), line='1+1\n'), - TokenInfo(type=NUMBER, string='1', start=(1, 2), end=(1, 3), line='1+1\n'), - TokenInfo(type=NEWLINE, string='', start=(1, 3), end=(1, 4), line='1+1\n'), + TokenInfo(type=NUMBER, string='1', start=(1, 0), end=(1, 1), line='1+1'), + TokenInfo(type=OP, string='+', start=(1, 1), end=(1, 2), line='1+1'), + TokenInfo(type=NUMBER, string='1', start=(1, 2), end=(1, 3), line='1+1'), + TokenInfo(type=NEWLINE, string='', start=(1, 3), end=(1, 4), line='1+1'), TokenInfo(type=ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') ] for encoding in ["utf-8", "latin-1", "utf-16"]: diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst new file mode 100644 index 00000000000000..9809fac49164f5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst @@ -0,0 +1,2 @@ +Don't include artificil newlines in the ``line`` attribute of tokens in the +APIs of the :mod:`tokenize` module. Patch by Pablo Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 2cf052a0cdeb3b..1938562706914c 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -206,6 +206,9 @@ tokenizeriter_next(tokenizeriterobject *it) line = PyUnicode_FromString(""); } else { Py_ssize_t size = it->tok->inp - line_start; + if (size >= 1 && it->tok->implicit_newline) { + size -= 1; + } line = PyUnicode_DecodeUTF8(line_start, size, "replace"); } if (line == NULL) { From bc365da711f8c8039f10d75572af674cf82d5b20 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:15:55 -0700 Subject: [PATCH 0173/1206] [3.12] gh-105557: Remove duplicate sqlite3 test method (GH-105558) (#105561) test_func_return_too_large_int() was defined twice. Keep only the redefined method, as that also checks the tracebacks. (cherry picked from commit b8fa7bda4f286503447dc12327b789bbfc836458) Co-authored-by: Erlend E. Aasland --- Lib/test/test_sqlite3/test_userfunctions.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_sqlite3/test_userfunctions.py b/Lib/test/test_sqlite3/test_userfunctions.py index 632d657d416fd4..03d27531666c89 100644 --- a/Lib/test/test_sqlite3/test_userfunctions.py +++ b/Lib/test/test_sqlite3/test_userfunctions.py @@ -195,7 +195,6 @@ def setUp(self): self.con.create_function("returnblob", 0, func_returnblob) self.con.create_function("returnlonglong", 0, func_returnlonglong) self.con.create_function("returnnan", 0, lambda: float("nan")) - self.con.create_function("returntoolargeint", 0, lambda: 1 << 65) self.con.create_function("return_noncont_blob", 0, lambda: memoryview(b"blob")[::2]) self.con.create_function("raiseexception", 0, func_raiseexception) @@ -294,11 +293,6 @@ def test_func_return_nan(self): cur.execute("select returnnan()") self.assertIsNone(cur.fetchone()[0]) - def test_func_return_too_large_int(self): - cur = self.con.cursor() - self.assertRaisesRegex(sqlite.DataError, "string or blob too big", - self.con.execute, "select returntoolargeint()") - @with_tracebacks(ZeroDivisionError, name="func_raiseexception") def test_func_exception(self): cur = self.con.cursor() @@ -444,9 +438,10 @@ def md5sum(t): @with_tracebacks(OverflowError) def test_func_return_too_large_int(self): cur = self.con.cursor() + msg = "string or blob too big" for value in 2**63, -2**63-1, 2**64: self.con.create_function("largeint", 0, lambda value=value: value) - with self.assertRaises(sqlite.DataError): + with self.assertRaisesRegex(sqlite.DataError, msg): cur.execute("select largeint()") @with_tracebacks(UnicodeEncodeError, "surrogates not allowed", "chr") From 65404930bdfcc3755eee70673ed0f592e5fcb37e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 10:23:45 -0700 Subject: [PATCH 0174/1206] [3.12] gh-105375: Improve error handling in compiler_enter_scope() (GH-105494) (#105581) (cherry picked from commit 6c832ddcf28187f86100c790afb16a0223d945d0) Co-authored-by: Erlend E. Aasland --- .../2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst | 1 + Python/compile.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst new file mode 100644 index 00000000000000..b4d3a1a5a3cedb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst @@ -0,0 +1 @@ +Fix bug in the compiler where an exception could end up being overwritten. diff --git a/Python/compile.c b/Python/compile.c index 32eda4d407ea12..f593e957caae97 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1252,8 +1252,12 @@ compiler_enter_scope(struct compiler *c, identifier name, } u->u_metadata.u_name = Py_NewRef(name); u->u_metadata.u_varnames = list2dict(u->u_ste->ste_varnames); + if (!u->u_metadata.u_varnames) { + compiler_unit_free(u); + return ERROR; + } u->u_metadata.u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, DEF_COMP_CELL, 0); - if (!u->u_metadata.u_varnames || !u->u_metadata.u_cellvars) { + if (!u->u_metadata.u_cellvars) { compiler_unit_free(u); return ERROR; } From 04b76ece7f92bd7e46ca2f3b46e7a42cfd75fa05 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 9 Jun 2023 20:08:32 +0200 Subject: [PATCH 0175/1206] [3.12] gh-105375: Improve _pickle error handling (#105475) (#105584) (cherry picked from commit 89aac6f6b7b3af046ec137121c90732289e79efc) Error handling was deferred in some cases, which could potentially lead to exceptions being overwritten. --- ...-06-08-08-58-36.gh-issue-105375.bTcqS9.rst | 1 + Modules/_pickle.c | 39 +++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst b/Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst new file mode 100644 index 00000000000000..3030477c8245b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst @@ -0,0 +1 @@ +Fix bugs in :mod:`pickle` where exceptions could be overwritten. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index bf7ecae0cc0e50..d6a273b1044e44 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1168,10 +1168,13 @@ _Pickler_New(PickleState *st) self->reducer_override = NULL; self->memo = PyMemoTable_New(); + if (self->memo == NULL) { + Py_DECREF(self); + return NULL; + } self->output_buffer = PyBytes_FromStringAndSize(NULL, self->max_output_len); - - if (self->memo == NULL || self->output_buffer == NULL) { + if (self->output_buffer == NULL) { Py_DECREF(self); return NULL; } @@ -1654,9 +1657,12 @@ _Unpickler_New(PyObject *module) self->memo_size = 32; self->memo_len = 0; self->memo = _Unpickler_NewMemo(self->memo_size); + if (self->memo == NULL) { + Py_DECREF(self); + return NULL; + } self->stack = (Pdata *)Pdata_New(st); - - if (self->memo == NULL || self->stack == NULL) { + if (self->stack == NULL) { Py_DECREF(self); return NULL; } @@ -4834,11 +4840,12 @@ _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) PyObject *key, *value; key = PyLong_FromVoidPtr(entry.me_key); + if (key == NULL) { + goto error; + } value = Py_BuildValue("nO", entry.me_value, entry.me_key); - - if (key == NULL || value == NULL) { - Py_XDECREF(key); - Py_XDECREF(value); + if (value == NULL) { + Py_DECREF(key); goto error; } status = PyDict_SetItem(new_memo, key, value); @@ -5994,12 +6001,20 @@ load_stack_global(PickleState *st, UnpicklerObject *self) PyObject *global_name; PDATA_POP(st, self->stack, global_name); + if (global_name == NULL) { + return -1; + } PDATA_POP(st, self->stack, module_name); - if (module_name == NULL || !PyUnicode_CheckExact(module_name) || - global_name == NULL || !PyUnicode_CheckExact(global_name)) { + if (module_name == NULL) { + Py_DECREF(global_name); + return -1; + } + if (!PyUnicode_CheckExact(module_name) || + !PyUnicode_CheckExact(global_name)) + { PyErr_SetString(st->UnpicklingError, "STACK_GLOBAL requires str"); - Py_XDECREF(global_name); - Py_XDECREF(module_name); + Py_DECREF(global_name); + Py_DECREF(module_name); return -1; } global = find_class(self, module_name, global_name); From e0087df65df485478401aec321b22e2f92407cd3 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 9 Jun 2023 22:36:53 +0200 Subject: [PATCH 0176/1206] [3.12] gh-105375: Improve errnomodule error handling (#105590) (#105596) (cherry picked from commit eede1d2f48b4fe7f7918952d9ebeb744b58668c1) Bail immediately if an exception is set, to prevent exceptions from being overwritten. --- .../Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst | 1 + Modules/errnomodule.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst new file mode 100644 index 00000000000000..3030477c8245b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst @@ -0,0 +1 @@ +Fix bugs in :mod:`pickle` where exceptions could be overwritten. diff --git a/Modules/errnomodule.c b/Modules/errnomodule.c index fddde960a5fe9a..301ad8313bc512 100644 --- a/Modules/errnomodule.c +++ b/Modules/errnomodule.c @@ -81,9 +81,12 @@ _add_errcode(PyObject *module_dict, PyObject *error_dict, const char *name_str, static int errno_exec(PyObject *module) { - PyObject *module_dict = PyModule_GetDict(module); + PyObject *module_dict = PyModule_GetDict(module); // Borrowed ref. + if (module_dict == NULL) { + return -1; + } PyObject *error_dict = PyDict_New(); - if (!module_dict || !error_dict) { + if (error_dict == NULL) { return -1; } if (PyDict_SetItemString(module_dict, "errorcode", error_dict) < 0) { From 411366ccdb7708cbf4e00db9186c2cffb3a0c652 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:15:24 -0700 Subject: [PATCH 0177/1206] [3.12] gh-105375: Improve error handling in _elementtree (GH-105591) (#105600) Fix bugs where exceptions could end up being overwritten. (cherry picked from commit 00b599ab5a76023fa0083d7cc5d3c569342a5191) Co-authored-by: Erlend E. Aasland --- .../2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst | 1 + Modules/_elementtree.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst new file mode 100644 index 00000000000000..1894b2b94bb334 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst @@ -0,0 +1 @@ +Fix bugs in :mod:`!_elementtree` where exceptions could be overwritten. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 00d9f647ccfdf3..6244fcc2064c33 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3261,10 +3261,14 @@ expat_start_handler(XMLParserObject* self, const XML_Char* tag_in, } while (attrib_in[0] && attrib_in[1]) { PyObject* key = makeuniversal(self, attrib_in[0]); + if (key == NULL) { + Py_DECREF(attrib); + Py_DECREF(tag); + return; + } PyObject* value = PyUnicode_DecodeUTF8(attrib_in[1], strlen(attrib_in[1]), "strict"); - if (!key || !value) { - Py_XDECREF(value); - Py_XDECREF(key); + if (value == NULL) { + Py_DECREF(key); Py_DECREF(attrib); Py_DECREF(tag); return; From ae6e002f5a27b267192204177a3b23ce23f0a4e7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:40:07 -0700 Subject: [PATCH 0178/1206] [3.12] gh-105549: Tokenize separately NUMBER and NAME tokens and allow 0-prefixed literals (GH-105555) (#105602) Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_tokenize.py | 33 +++++++++++++++++++ ...-06-09-12-59-18.gh-issue-105549.PYfTNp.rst | 2 ++ Parser/tokenizer.c | 13 ++++++-- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 2c124f062e7fd6..df9c9db322dc94 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -284,7 +284,12 @@ def number_token(s): # this won't work with compound complex inputs continue self.assertEqual(number_token(lit), lit) + # Valid cases with extra underscores in the tokenize module + # See gh-105549 for context + extra_valid_cases = {"0_7", "09_99"} for lit in INVALID_UNDERSCORE_LITERALS: + if lit in extra_valid_cases: + continue try: number_token(lit) except TokenError: @@ -1873,6 +1878,34 @@ def test_indentation_semantics_retained(self): self.check_roundtrip(code) +class InvalidPythonTests(TestCase): + def test_number_followed_by_name(self): + # See issue #gh-105549 + source = "2sin(x)" + expected_tokens = [ + TokenInfo(type=token.NUMBER, string='2', start=(1, 0), end=(1, 1), line='2sin(x)'), + TokenInfo(type=token.NAME, string='sin', start=(1, 1), end=(1, 4), line='2sin(x)'), + TokenInfo(type=token.OP, string='(', start=(1, 4), end=(1, 5), line='2sin(x)'), + TokenInfo(type=token.NAME, string='x', start=(1, 5), end=(1, 6), line='2sin(x)'), + TokenInfo(type=token.OP, string=')', start=(1, 6), end=(1, 7), line='2sin(x)'), + TokenInfo(type=token.NEWLINE, string='', start=(1, 7), end=(1, 8), line='2sin(x)'), + TokenInfo(type=token.ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') + ] + + tokens = list(generate_tokens(StringIO(source).readline)) + self.assertEqual(tokens, expected_tokens) + + def test_number_starting_with_zero(self): + source = "01234" + expected_tokens = [ + TokenInfo(type=token.NUMBER, string='01234', start=(1, 0), end=(1, 5), line='01234'), + TokenInfo(type=token.NEWLINE, string='', start=(1, 5), end=(1, 6), line='01234'), + TokenInfo(type=token.ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') + ] + + tokens = list(generate_tokens(StringIO(source).readline)) + self.assertEqual(tokens, expected_tokens) + class CTokenizeTest(TestCase): def check_tokenize(self, s, expected): # Format the tokens in s in a table format. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst new file mode 100644 index 00000000000000..c3dcaeea7a11cd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst @@ -0,0 +1,2 @@ +Tokenize separately `NUMBER` and `NAME` tokens that are not ambiguous. Patch +by Pablo Galindo diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 89594e6974fe04..57c98fe5fcaa40 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1600,8 +1600,12 @@ lookahead(struct tok_state *tok, const char *test) } static int -verify_end_of_number(struct tok_state *tok, int c, const char *kind) -{ +verify_end_of_number(struct tok_state *tok, int c, const char *kind) { + if (tok->tok_extra_tokens) { + // When we are parsing extra tokens, we don't want to emit warnings + // about invalid literals, because we want to be a bit more liberal. + return 1; + } /* Emit a deprecation warning only if the numeric literal is immediately * followed by one of keywords which can occur after a numeric literal * in valid code: "and", "else", "for", "if", "in", "is" and "or". @@ -1659,6 +1663,9 @@ verify_end_of_number(struct tok_state *tok, int c, const char *kind) static int verify_identifier(struct tok_state *tok) { + if (tok->tok_extra_tokens) { + return 1; + } PyObject *s; if (tok->decoding_erred) return 0; @@ -2318,7 +2325,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t else if (c == 'j' || c == 'J') { goto imaginary; } - else if (nonzero) { + else if (nonzero && !tok->tok_extra_tokens) { /* Old-style octal: now disallowed. */ tok_backup(tok, c); return MAKE_TOKEN(syntaxerror_known_range( From 5dae2b1a5dc38aa82501510efdc8bf4c898f35d2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:53:53 -0700 Subject: [PATCH 0179/1206] [3.12] Docs: fix formatting in 2023-06-09-12-59-18 NEWS item (GH-105607) (#105614) (cherry picked from commit 91441bf7cbaefbd328ee7efa59a06e661f61542e) Co-authored-by: Erlend E. Aasland --- .../2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst index c3dcaeea7a11cd..7cb177b9353373 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst @@ -1,2 +1,2 @@ -Tokenize separately `NUMBER` and `NAME` tokens that are not ambiguous. Patch -by Pablo Galindo +Tokenize separately ``NUMBER`` and ``NAME`` tokens that are not ambiguous. Patch +by Pablo Galindo. From 4fbbf699c0d72f6db62484c88a05c826c3703eb5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:21:42 -0700 Subject: [PATCH 0180/1206] [3.12] gh-105375: Harden error handling in `_testcapi/heaptype.c` (GH-105608) (#105615) Bail on first error in heapctypesubclasswithfinalizer_finalize() (cherry picked from commit d636d7dfe714e7168b342c7ea5f9f9d3b3569ed0) Co-authored-by: Erlend E. Aasland --- Modules/_testcapi/heaptype.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index 3488e35922c5ac..565ab570a42bde 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -661,8 +661,11 @@ heapctypesubclasswithfinalizer_finalize(PyObject *self) goto cleanup_finalize; } oldtype = PyObject_GetAttrString(m, "HeapCTypeSubclassWithFinalizer"); + if (oldtype == NULL) { + goto cleanup_finalize; + } newtype = PyObject_GetAttrString(m, "HeapCTypeSubclass"); - if (oldtype == NULL || newtype == NULL) { + if (newtype == NULL) { goto cleanup_finalize; } From 8c4cf96a06e2483a11a4cb34c550df5bd22f990b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:22:10 -0700 Subject: [PATCH 0181/1206] [3.12] gh-105375: Improve error handling in `zoneinfo` module (GH-105586) (#105612) Fix bugs where exceptions could end up being overwritten because of deferred error handling. (cherry picked from commit 33c92c4f15539806c8aff8574ff30a8b307e3e4d) Co-authored-by: Nikita Sobolev Co-authored-by: Erlend E. Aasland --- ...23-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst | 1 + Modules/_zoneinfo.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst new file mode 100644 index 00000000000000..4202b758d1db56 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst @@ -0,0 +1 @@ +Fix bugs in :mod:`zoneinfo` where exceptions could be overwritten. diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index c8c791b6d7c0d8..38b806c244061d 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -694,14 +694,19 @@ zoneinfo_fromutc(PyObject *obj_self, PyObject *dt) } else { PyObject *replace = PyObject_GetAttrString(tmp, "replace"); + Py_DECREF(tmp); + if (replace == NULL) { + return NULL; + } PyObject *args = PyTuple_New(0); + if (args == NULL) { + Py_DECREF(replace); + return NULL; + } PyObject *kwargs = PyDict_New(); - - Py_DECREF(tmp); - if (args == NULL || kwargs == NULL || replace == NULL) { - Py_XDECREF(args); - Py_XDECREF(kwargs); - Py_XDECREF(replace); + if (kwargs == NULL) { + Py_DECREF(replace); + Py_DECREF(args); return NULL; } From e2bbe62e00754e64446369a43a003c03ccf36250 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 10 Jun 2023 11:49:59 -0700 Subject: [PATCH 0182/1206] [3.12] Cleanup and clarify our hashlib docs. (GH-105624) (#105632) Cleanup and clarify our hashlib docs. (GH-105624) Clarify and improve our hashlib docs. Now with 50% less mess! (cherry picked from commit 0d1d6ab966ff4e4d651d0dee0ec9a2f868ef42da) Co-authored-by: Gregory P. Smith --- Doc/library/hashlib.rst | 137 ++++++++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 47 deletions(-) diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 797870b9d7e260..7f06151675c7f0 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -11,7 +11,7 @@ .. index:: single: message digest, MD5 - single: secure hash algorithm, SHA1, SHA224, SHA256, SHA384, SHA512 + single: secure hash algorithm, SHA1, SHA2, SHA224, SHA256, SHA384, SHA512, SHA3, Shake, Blake2 .. testsetup:: @@ -22,7 +22,8 @@ This module implements a common interface to many different secure hash and message digest algorithms. Included are the FIPS secure hash algorithms SHA1, -SHA224, SHA256, SHA384, and SHA512 (defined in FIPS 180-2) as well as RSA's MD5 +SHA224, SHA256, SHA384, SHA512, (defined in `the FIPS 180-4 standard`_), +the SHA-3 series (defined in `the FIPS 202 standard`_) as well as RSA's MD5 algorithm (defined in internet :rfc:`1321`). The terms "secure hash" and "message digest" are interchangeable. Older algorithms were called message digests. The modern term is secure hash. @@ -32,11 +33,6 @@ digests. The modern term is secure hash. If you want the adler32 or crc32 hash functions, they are available in the :mod:`zlib` module. -.. warning:: - - Some algorithms have known hash collision weaknesses, refer to the "See - also" section at the end. - .. _hash-algorithms: @@ -44,38 +40,43 @@ Hash algorithms --------------- There is one constructor method named for each type of :dfn:`hash`. All return -a hash object with the same simple interface. For example: use :func:`sha256` to -create a SHA-256 hash object. You can now feed this object with :term:`bytes-like -objects ` (normally :class:`bytes`) using the :meth:`update` method. -At any point you can ask it for the :dfn:`digest` of the -concatenation of the data fed to it so far using the :meth:`digest` or -:meth:`hexdigest` methods. - -.. note:: - - For better multithreading performance, the Python :term:`GIL` is released for - data larger than 2047 bytes at object creation or on update. +a hash object with the same simple interface. For example: use :func:`sha256` +to create a SHA-256 hash object. You can now feed this object with +:term:`bytes-like objects ` (normally :class:`bytes`) using +the :meth:`update` method. At any point you can ask it for the +:dfn:`digest` of the concatenation of the data fed to it so far using the +:meth:`digest()` or :meth:`hexdigest()` methods. -.. note:: +To allow multithreading, the Python :term:`GIL` is released while computing a +hash supplied more than 2047 bytes of data at once in its constructor or +:meth:`.update` method. - Feeding string objects into :meth:`update` is not supported, as hashes work - on bytes, not on characters. .. index:: single: OpenSSL; (use in module hashlib) Constructors for hash algorithms that are always present in this module are -:func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, -:func:`sha512`, :func:`blake2b`, and :func:`blake2s`. -:func:`md5` is normally available as well, though it -may be missing or blocked if you are using a rare "FIPS compliant" build of Python. -Additional algorithms may also be available depending upon the OpenSSL -library that Python uses on your platform. On most platforms the +:func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, :func:`sha512`, :func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, :func:`sha3_512`, -:func:`shake_128`, :func:`shake_256` are also available. +:func:`shake_128`, :func:`shake_256`, :func:`blake2b`, and :func:`blake2s`. +:func:`md5` is normally available as well, though it may be missing or blocked +if you are using a rare "FIPS compliant" build of Python. +These correspond to :data:`algorithms_guaranteed`. + +Additional algorithms may also be available if your Python distribution's +:mod:`hashlib` was linked against a build of OpenSSL that provides others. +Others *are not guaranteed available* on all installations and will only be +accessible by name via :func:`new`. See :data:`algorithms_available`. + +.. warning:: + + Some algorithms have known hash collision weaknesses (including MD5 and + SHA1). Refer to `Attacks on cryptographic hash algorithms`_ and the + `hashlib-seealso`_ section at the end of this document. .. versionadded:: 3.6 SHA3 (Keccak) and SHAKE constructors :func:`sha3_224`, :func:`sha3_256`, - :func:`sha3_384`, :func:`sha3_512`, :func:`shake_128`, :func:`shake_256`. + :func:`sha3_384`, :func:`sha3_512`, :func:`shake_128`, :func:`shake_256` + were added. .. versionadded:: 3.6 :func:`blake2b` and :func:`blake2s` were added. @@ -89,10 +90,14 @@ library that Python uses on your platform. On most platforms the that the hashing algorithm is not used in a security context, e.g. as a non-cryptographic one-way compression function. - Hashlib now uses SHA3 and SHAKE from OpenSSL 1.1.1 and newer. +.. versionchanged:: 3.9 + Hashlib now uses SHA3 and SHAKE from OpenSSL if it provides it. -For example, to obtain the digest of the byte string ``b"Nobody inspects the -spammish repetition"``:: +Usage +----- + +To obtain the digest of the byte string ``b"Nobody inspects the spammish +repetition"``:: >>> import hashlib >>> m = hashlib.sha256() @@ -108,22 +113,42 @@ More condensed: >>> hashlib.sha256(b"Nobody inspects the spammish repetition").hexdigest() '031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406' -.. function:: new(name[, data], *, usedforsecurity=True) +Constructors +------------ + +.. function:: new(name[, data], \*, usedforsecurity=True) Is a generic constructor that takes the string *name* of the desired algorithm as its first parameter. It also exists to allow access to the above listed hashes as well as any other algorithms that your OpenSSL - library may offer. The named constructors are much faster than :func:`new` - and should be preferred. + library may offer. -Using :func:`new` with an algorithm provided by OpenSSL: +Using :func:`new` with an algorithm name: >>> h = hashlib.new('sha256') >>> h.update(b"Nobody inspects the spammish repetition") >>> h.hexdigest() '031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406' -Hashlib provides the following constant attributes: + +.. function:: md5([, data], \*, usedforsecurity=True) +.. function:: sha1([, data], \*, usedforsecurity=True) +.. function:: sha224([, data], \*, usedforsecurity=True) +.. function:: sha256([, data], \*, usedforsecurity=True) +.. function:: sha384([, data], \*, usedforsecurity=True) +.. function:: sha512([, data], \*, usedforsecurity=True) +.. function:: sha3_224([, data], \*, usedforsecurity=True) +.. function:: sha3_256([, data], \*, usedforsecurity=True) +.. function:: sha3_384([, data], \*, usedforsecurity=True) +.. function:: sha3_512([, data], \*, usedforsecurity=True) + +Named constructors such as these are faster than passing an algorithm name to +:func:`new`. + +Attributes +---------- + +Hashlib provides the following constant module attributes: .. data:: algorithms_guaranteed @@ -144,10 +169,12 @@ Hashlib provides the following constant attributes: .. versionadded:: 3.2 +Hash Objects +------------ + The following values are provided as constant attributes of the hash objects returned by the constructors: - .. data:: hash.digest_size The size of the resulting hash in bytes. @@ -207,6 +234,9 @@ A hash object has the following methods: SHAKE variable length digests ----------------------------- +.. function:: shake_128([, data], \*, usedforsecurity=True) +.. function:: shake_256([, data], \*, usedforsecurity=True) + The :func:`shake_128` and :func:`shake_256` algorithms provide variable length digests with length_in_bits//2 up to 128 or 256 bits of security. As such, their digest methods require a length. Maximum length is not limited @@ -223,8 +253,13 @@ by the SHAKE algorithm. Like :meth:`digest` except the digest is returned as a string object of double length, containing only hexadecimal digits. This may be used to - exchange the value safely in email or other non-binary environments. + exchange the value in email or other non-binary environments. +Example use: + + >>> h = hashlib.shake_256(b'Nobody inspects the spammish repetition') + >>> h.hexdigest(20) + '44709d6fcb83d92a76dcb0b668c98e1b1d3dafe7' File hashing ------------ @@ -768,12 +803,17 @@ Domain Dedication 1.0 Universal: .. _BLAKE2: https://www.blake2.net .. _HMAC: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code .. _BLAKE: https://web.archive.org/web/20200918190133/https://131002.net/blake/ -.. _SHA-3: https://en.wikipedia.org/wiki/NIST_hash_function_competition +.. _SHA-3: https://en.wikipedia.org/wiki/Secure_Hash_Algorithms .. _ChaCha: https://cr.yp.to/chacha.html .. _pyblake2: https://pythonhosted.org/pyblake2/ .. _NIST-SP-800-132: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf .. _stackexchange pbkdf2 iterations question: https://security.stackexchange.com/questions/3959/recommended-of-iterations-when-using-pbkdf2-sha256/ +.. _Attacks on cryptographic hash algorithms: https://en.wikipedia.org/wiki/Cryptographic_hash_function#Attacks_on_cryptographic_hash_algorithms +.. _the FIPS 180-4 standard: https://csrc.nist.gov/publications/detail/fips/180/4/final +.. _the FIPS 202 standard: https://csrc.nist.gov/publications/detail/fips/202/final + +.. _hashlib-seealso: .. seealso:: @@ -783,15 +823,18 @@ Domain Dedication 1.0 Universal: Module :mod:`base64` Another way to encode binary hashes for non-binary environments. - https://www.blake2.net - Official BLAKE2 website. + https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.180-4.pdf + The FIPS 180-4 publication on Secure Hash Algorithms. + + https://csrc.nist.gov/publications/detail/fips/202/final + The FIPS 202 publication on the SHA-3 Standard. - https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf - The FIPS 180-2 publication on Secure Hash Algorithms. + https://www.blake2.net/ + Official BLAKE2 website. - https://en.wikipedia.org/wiki/Cryptographic_hash_function#Cryptographic_hash_algorithms - Wikipedia article with information on which algorithms have known issues and - what that means regarding their use. + https://en.wikipedia.org/wiki/Cryptographic_hash_function + Wikipedia article with information on which algorithms have known issues + and what that means regarding their use. https://www.ietf.org/rfc/rfc8018.txt PKCS #5: Password-Based Cryptography Specification Version 2.1 From bf6e0e618ac2444b00ab72eb60b278a070e47397 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 10 Jun 2023 12:10:04 -0700 Subject: [PATCH 0183/1206] [3.12] gh-99108: Mention HACL\* in the hashlib docs. (GH-105634) (#105635) gh-99108: Mention HACL\* in the hashlib docs. (GH-105634) (cherry picked from commit 3a314f7c3df0dd7c37da7d12b827f169ee60e1ea) Co-authored-by: Gregory P. Smith --- Doc/library/hashlib.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 7f06151675c7f0..8102767a43d6dd 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -93,6 +93,11 @@ accessible by name via :func:`new`. See :data:`algorithms_available`. .. versionchanged:: 3.9 Hashlib now uses SHA3 and SHAKE from OpenSSL if it provides it. +.. versionchanged:: 3.12 + For any of the MD5, SHA1, SHA2, or SHA3 algorithms that the linked + OpenSSL does not provide we fall back to a verified implementation from + the `HACL\* project`_. + Usage ----- @@ -205,11 +210,6 @@ A hash object has the following methods: concatenation of all the arguments: ``m.update(a); m.update(b)`` is equivalent to ``m.update(a+b)``. - .. versionchanged:: 3.1 - The Python GIL is released to allow other threads to run while hash - updates on data larger than 2047 bytes is taking place when using hash - algorithms supplied by OpenSSL. - .. method:: hash.digest() @@ -811,6 +811,7 @@ Domain Dedication 1.0 Universal: .. _Attacks on cryptographic hash algorithms: https://en.wikipedia.org/wiki/Cryptographic_hash_function#Attacks_on_cryptographic_hash_algorithms .. _the FIPS 180-4 standard: https://csrc.nist.gov/publications/detail/fips/180/4/final .. _the FIPS 202 standard: https://csrc.nist.gov/publications/detail/fips/202/final +.. _HACL\* project: https://github.com/hacl-star/hacl-star .. _hashlib-seealso: From d3c69ed366fb6504bb1a02f7d7226b9f788b403a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 03:24:22 -0700 Subject: [PATCH 0184/1206] [3.12] gh-105375: Improve array.array exception handling (GH-105594) (#105644) Fix a bug where 'tp_richcompare' could end up overwriting an exception. (cherry picked from commit 35cff545db7c7912046c0ce5627db2e4d2b60f57) Co-authored-by: Erlend E. Aasland --- .../2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst | 2 ++ Modules/arraymodule.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst new file mode 100644 index 00000000000000..21aea1b0b4082c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst @@ -0,0 +1,2 @@ +Fix a bug in :class:`array.array` where an exception could end up being +overwritten. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index f94bbec8e0bb3c..6680820d8e61bc 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -739,10 +739,12 @@ array_richcompare(PyObject *v, PyObject *w, int op) k = 1; for (i = 0; i < Py_SIZE(va) && i < Py_SIZE(wa); i++) { vi = getarrayitem(v, i); + if (vi == NULL) { + return NULL; + } wi = getarrayitem(w, i); - if (vi == NULL || wi == NULL) { - Py_XDECREF(vi); - Py_XDECREF(wi); + if (wi == NULL) { + Py_DECREF(vi); return NULL; } k = PyObject_RichCompareBool(vi, wi, Py_EQ); From 85a1a0983f7e7b6a5f35cf253d1edf5aee35795d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 03:26:52 -0700 Subject: [PATCH 0185/1206] [3.12] gh-105375: Harden _ssl initialisation (GH-105599) (#105642) Add proper error handling to prevent reference leaks and overwritten exceptions. (cherry picked from commit 01f4230460454d4a849a5ba93320142c1a0c93a8) Co-authored-by: Erlend E. Aasland --- ...023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst | 2 ++ Modules/_ssl.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst b/Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst new file mode 100644 index 00000000000000..49f7df68e927cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst @@ -0,0 +1,2 @@ +Fix bugs in :mod:`!_ssl` initialisation which could lead to leaked +references and overwritten exceptions. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index de90a4a168d2ed..7a13821f9d7b5c 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -6001,15 +6001,21 @@ sslmodule_init_errorcodes(PyObject *module) errcode = error_codes; while (errcode->mnemonic != NULL) { - PyObject *mnemo, *key; - mnemo = PyUnicode_FromString(errcode->mnemonic); - key = Py_BuildValue("ii", errcode->library, errcode->reason); - if (mnemo == NULL || key == NULL) + PyObject *mnemo = PyUnicode_FromString(errcode->mnemonic); + if (mnemo == NULL) { return -1; - if (PyDict_SetItem(state->err_codes_to_names, key, mnemo)) + } + PyObject *key = Py_BuildValue("ii", errcode->library, errcode->reason); + if (key == NULL) { + Py_DECREF(mnemo); return -1; + } + int rc = PyDict_SetItem(state->err_codes_to_names, key, mnemo); Py_DECREF(key); Py_DECREF(mnemo); + if (rc < 0) { + return -1; + } errcode++; } From 36ecbc3570120c55d89eb8695b16525d6e77b454 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 03:46:33 -0700 Subject: [PATCH 0186/1206] [3.12] gh-105375: Harden _datetime initialisation (GH-105604) (#105645) Improve error handling so init bails on the first exception. (cherry picked from commit 16d49680b56e00c53c00683b949138e584669fd3) Co-authored-by: Erlend E. Aasland --- ...-06-09-22-45-26.gh-issue-105375.9rp6tG.rst | 2 ++ Modules/_datetimemodule.c | 35 ++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst b/Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst new file mode 100644 index 00000000000000..352d7b83a71632 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst @@ -0,0 +1,2 @@ +Fix bugs in :mod:`!_datetime` where exceptions could be overwritten in case +of module initialisation failure. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 19e11780ec6e19..cbc331c7e94268 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6871,24 +6871,49 @@ _datetime_exec(PyObject *module) assert(DI100Y == days_before_year(100+1)); us_per_ms = PyLong_FromLong(1000); + if (us_per_ms == NULL) { + goto error; + } us_per_second = PyLong_FromLong(1000000); + if (us_per_second == NULL) { + goto error; + } us_per_minute = PyLong_FromLong(60000000); + if (us_per_minute == NULL) { + goto error; + } seconds_per_day = PyLong_FromLong(24 * 3600); - if (us_per_ms == NULL || us_per_second == NULL || - us_per_minute == NULL || seconds_per_day == NULL) { - return -1; + if (seconds_per_day == NULL) { + goto error; } /* The rest are too big for 32-bit ints, but even * us_per_week fits in 40 bits, so doubles should be exact. */ us_per_hour = PyLong_FromDouble(3600000000.0); + if (us_per_hour == NULL) { + goto error; + } us_per_day = PyLong_FromDouble(86400000000.0); + if (us_per_day == NULL) { + goto error; + } us_per_week = PyLong_FromDouble(604800000000.0); - if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL) { - return -1; + if (us_per_week == NULL) { + goto error; } + return 0; + +error: + Py_XDECREF(us_per_ms); + Py_XDECREF(us_per_second); + Py_XDECREF(us_per_minute); + Py_XDECREF(us_per_hour); + Py_XDECREF(us_per_day); + Py_XDECREF(us_per_week); + Py_XDECREF(seconds_per_day); + return -1; } static struct PyModuleDef datetimemodule = { From b4b5565e4779d81c943bffe22ffe0972fa398702 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 03:55:18 -0700 Subject: [PATCH 0187/1206] [3.12] gh-105375: Improve _decimal error handling (GH-105605) (#105647) Fix a bug where an exception could end up being overwritten. (cherry picked from commit c932f7284977ebf813313157c52d716ba225a7ac) Co-authored-by: Erlend E. Aasland --- .../Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst | 1 + Modules/_decimal/_decimal.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst b/Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst new file mode 100644 index 00000000000000..05e78fdc9b4076 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst @@ -0,0 +1 @@ +Fix bug in :mod:`decimal` where an exception could end up being overwritten. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 0e11c879732ab6..0005081f7c5e80 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3615,9 +3615,13 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) goto error; } Py_SETREF(numerator, _py_long_floor_divide(numerator, tmp)); + if (numerator == NULL) { + Py_DECREF(tmp); + goto error; + } Py_SETREF(denominator, _py_long_floor_divide(denominator, tmp)); Py_DECREF(tmp); - if (numerator == NULL || denominator == NULL) { + if (denominator == NULL) { goto error; } } From 122a1a2629f6d3f39c7f473bc96aa3b5d834c49f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 04:17:48 -0700 Subject: [PATCH 0188/1206] [3.12] gh-105375: Improve error handling in the builtins extension module (GH-105585) (#105649) (cherry picked from commit d4fa52934a282df51cff800eee5caeb94a229547) Co-authored-by: Erlend E. Aasland --- ...-06-08-10-10-07.gh-issue-105375.35VGDd.rst | 2 + Python/bltinmodule.c | 40 +++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst new file mode 100644 index 00000000000000..3ab85538f3fc43 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst @@ -0,0 +1,2 @@ +Fix bugs in the :mod:`builtins` module where exceptions could end up being +overwritten. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index ddddc03ca316e0..45ce3b71e84ecf 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2164,17 +2164,29 @@ builtin_input_impl(PyObject *module, PyObject *prompt) /* stdin is a text stream, so it must have an encoding. */ stdin_encoding = PyObject_GetAttr(fin, &_Py_ID(encoding)); + if (stdin_encoding == NULL) { + tty = 0; + goto _readline_errors; + } stdin_errors = PyObject_GetAttr(fin, &_Py_ID(errors)); - if (!stdin_encoding || !stdin_errors || - !PyUnicode_Check(stdin_encoding) || - !PyUnicode_Check(stdin_errors)) { + if (stdin_errors == NULL) { + tty = 0; + goto _readline_errors; + } + if (!PyUnicode_Check(stdin_encoding) || + !PyUnicode_Check(stdin_errors)) + { tty = 0; goto _readline_errors; } stdin_encoding_str = PyUnicode_AsUTF8(stdin_encoding); + if (stdin_encoding_str == NULL) { + goto _readline_errors; + } stdin_errors_str = PyUnicode_AsUTF8(stdin_errors); - if (!stdin_encoding_str || !stdin_errors_str) + if (stdin_errors_str == NULL) { goto _readline_errors; + } tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush)); if (tmp == NULL) PyErr_Clear(); @@ -2185,17 +2197,29 @@ builtin_input_impl(PyObject *module, PyObject *prompt) const char *stdout_encoding_str, *stdout_errors_str; PyObject *stringpo; stdout_encoding = PyObject_GetAttr(fout, &_Py_ID(encoding)); + if (stdout_encoding == NULL) { + tty = 0; + goto _readline_errors; + } stdout_errors = PyObject_GetAttr(fout, &_Py_ID(errors)); - if (!stdout_encoding || !stdout_errors || - !PyUnicode_Check(stdout_encoding) || - !PyUnicode_Check(stdout_errors)) { + if (stdout_errors == NULL) { + tty = 0; + goto _readline_errors; + } + if (!PyUnicode_Check(stdout_encoding) || + !PyUnicode_Check(stdout_errors)) + { tty = 0; goto _readline_errors; } stdout_encoding_str = PyUnicode_AsUTF8(stdout_encoding); + if (stdout_encoding_str == NULL) { + goto _readline_errors; + } stdout_errors_str = PyUnicode_AsUTF8(stdout_errors); - if (!stdout_encoding_str || !stdout_errors_str) + if (stdout_errors_str == NULL) { goto _readline_errors; + } stringpo = PyObject_Str(prompt); if (stringpo == NULL) goto _readline_errors; From 071d559def83f0bc51e87a0ca83d45cf4bd6662b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 07:31:04 -0700 Subject: [PATCH 0189/1206] [3.12] Fix typo in configparser module docstring (GH-105652) (#105653) Fix typo in configparser module docstring (GH-105652) "zc.buildbot" -> "zc.buildout" (cherry picked from commit 845e593c4ec97dd9f73b50536c1e1e7ed10ceecd) Co-authored-by: litlighilit <97860435+litlighilit@users.noreply.github.com> --- Lib/configparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index dee5a0db7e7ddc..e8aae217949a9f 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -59,7 +59,7 @@ instance. It will be used as the handler for option value pre-processing when using getters. RawConfigParser objects don't do any sort of interpolation, whereas ConfigParser uses an instance of - BasicInterpolation. The library also provides a ``zc.buildbot`` + BasicInterpolation. The library also provides a ``zc.buildout`` inspired ExtendedInterpolation implementation. When `converters` is given, it should be a dictionary where each key From c14f6ea7e44790d0518c3a0c17b8b1336f3a1602 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 12:33:30 -0700 Subject: [PATCH 0190/1206] [3.12] gh-105375: Improve posix error handling (GH-105592) (#105598) Fix a bug where an IndexError could end up being overwritten. (cherry picked from commit f668f73bc88cce0112b304d87aa998fb28013c71) Co-authored-by: Erlend E. Aasland --- .../2023-06-09-21-30-59.gh-issue-105375.eewafp.rst | 2 ++ Modules/posixmodule.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst new file mode 100644 index 00000000000000..e000f98828a211 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst @@ -0,0 +1,2 @@ +Fix a bug in the :mod:`posix` module where an exception could be +overwritten. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index f5e653dd023aef..81c9990220893d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6414,7 +6414,7 @@ parse_envlist(PyObject* env, Py_ssize_t *envc_ptr) { Py_ssize_t i, pos, envc; PyObject *keys=NULL, *vals=NULL; - PyObject *key, *val, *key2, *val2, *keyval; + PyObject *key2, *val2, *keyval; EXECV_CHAR **envlist; i = PyMapping_Size(env); @@ -6439,10 +6439,14 @@ parse_envlist(PyObject* env, Py_ssize_t *envc_ptr) } for (pos = 0; pos < i; pos++) { - key = PyList_GetItem(keys, pos); - val = PyList_GetItem(vals, pos); - if (!key || !val) + PyObject *key = PyList_GetItem(keys, pos); // Borrowed ref. + if (key == NULL) { goto error; + } + PyObject *val = PyList_GetItem(vals, pos); // Borrowed ref. + if (val == NULL) { + goto error; + } #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV) if (!PyUnicode_FSDecoder(key, &key2)) From db5022c16f94622285eda5f036450e34f5f415ce Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 12:51:30 -0700 Subject: [PATCH 0191/1206] [3.12] gh-105375: Improve PyErr_WarnExplicit() error handling (GH-105610) (#105659) Bail on first error to prevent exceptions from possibly being overwritten. (cherry picked from commit 567d6ae8e77579173510fc948ac06b2ababf3d40) Co-authored-by: Erlend E. Aasland --- ...-06-09-23-34-25.gh-issue-105375.n7amiF.rst | 2 ++ Python/_warnings.c | 28 +++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst diff --git a/Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst b/Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst new file mode 100644 index 00000000000000..b9f95496f938ec --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst @@ -0,0 +1,2 @@ +Fix a bug in :c:func:`PyErr_WarnExplicit` where an exception could end up +being overwritten if the API failed internally. diff --git a/Python/_warnings.c b/Python/_warnings.c index dec658680241ed..1f91edbf5cb5dc 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1301,25 +1301,29 @@ PyErr_WarnExplicit(PyObject *category, const char *text, const char *module_str, PyObject *registry) { PyObject *message = PyUnicode_FromString(text); + if (message == NULL) { + return -1; + } PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); + if (filename == NULL) { + Py_DECREF(message); + return -1; + } PyObject *module = NULL; - int ret = -1; - - if (message == NULL || filename == NULL) - goto exit; if (module_str != NULL) { module = PyUnicode_FromString(module_str); - if (module == NULL) - goto exit; + if (module == NULL) { + Py_DECREF(filename); + Py_DECREF(message); + return -1; + } } - ret = PyErr_WarnExplicitObject(category, message, filename, lineno, - module, registry); - - exit: - Py_XDECREF(message); + int ret = PyErr_WarnExplicitObject(category, message, filename, lineno, + module, registry); Py_XDECREF(module); - Py_XDECREF(filename); + Py_DECREF(filename); + Py_DECREF(message); return ret; } From ed038953fc2316117a3eaad066b93b0348131fd8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 13:01:18 -0700 Subject: [PATCH 0192/1206] [3.12] gh-105375: Improve error handling in PyUnicode_BuildEncodingMap() (GH-105491) (#105661) Bail on first error to prevent exceptions from possibly being overwritten. (cherry picked from commit 555be81026fe1205d16c02f6321221381174cd07) Co-authored-by: Erlend E. Aasland --- ...-06-08-09-25-52.gh-issue-105375.ocB7fT.rst | 2 ++ Objects/unicodeobject.c | 29 +++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst new file mode 100644 index 00000000000000..24fac2df4d0955 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst @@ -0,0 +1,2 @@ +Improve error handling in :c:func:`PyUnicode_BuildEncodingMap` where an +exception could end up being overwritten. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 6f25f91c0ff28d..a0be85718119de 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7934,25 +7934,30 @@ PyUnicode_BuildEncodingMap(PyObject* string) if (need_dict) { PyObject *result = PyDict_New(); - PyObject *key, *value; if (!result) return NULL; for (i = 0; i < length; i++) { - key = PyLong_FromLong(PyUnicode_READ(kind, data, i)); - value = PyLong_FromLong(i); - if (!key || !value) - goto failed1; - if (PyDict_SetItem(result, key, value) == -1) - goto failed1; + Py_UCS4 c = PyUnicode_READ(kind, data, i); + PyObject *key = PyLong_FromLong(c); + if (key == NULL) { + Py_DECREF(result); + return NULL; + } + PyObject *value = PyLong_FromLong(i); + if (value == NULL) { + Py_DECREF(key); + Py_DECREF(result); + return NULL; + } + int rc = PyDict_SetItem(result, key, value); Py_DECREF(key); Py_DECREF(value); + if (rc < 0) { + Py_DECREF(result); + return NULL; + } } return result; - failed1: - Py_XDECREF(key); - Py_XDECREF(value); - Py_DECREF(result); - return NULL; } /* Create a three-level trie */ From 82ac2be6b386b7d106a36262f1aa960f638bde8d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 13:25:27 -0700 Subject: [PATCH 0193/1206] [3.12] gh-105375: Improve error handling in _ctypes (GH-105593) (#105663) Prevent repeated PyLong_FromVoidPtr() from possibly overwriting the current exception. (cherry picked from commit e8998e46a7ce8ad336e0941a6da6e50cb88d1e47) Co-authored-by: Erlend E. Aasland --- ...3-06-09-21-40-45.gh-issue-105375._sZilh.rst | 1 + Modules/_ctypes/callbacks.c | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst new file mode 100644 index 00000000000000..87db4c2b4e22e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst @@ -0,0 +1 @@ +Fix bugs in :mod:`_ctypes` where exceptions could end up being overwritten. diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 8e694ba852c1d4..d71297f9c5c2f2 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -479,12 +479,22 @@ long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid); + if (py_rclsid == NULL) { + Py_DECREF(func); + PyErr_WriteUnraisable(context ? context : Py_None); + return E_FAIL; + } PyObject *py_riid = PyLong_FromVoidPtr((void *)riid); + if (py_riid == NULL) { + Py_DECREF(func); + Py_DECREF(py_rclsid); + PyErr_WriteUnraisable(context ? context : Py_None); + return E_FAIL; + } PyObject *py_ppv = PyLong_FromVoidPtr(ppv); - if (!py_rclsid || !py_riid || !py_ppv) { - Py_XDECREF(py_rclsid); - Py_XDECREF(py_riid); - Py_XDECREF(py_ppv); + if (py_ppv == NULL) { + Py_DECREF(py_rclsid); + Py_DECREF(py_riid); Py_DECREF(func); PyErr_WriteUnraisable(context ? context : Py_None); return E_FAIL; From a1034b5fd3af59d813452742153e60b40b39ff4a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 11 Jun 2023 14:12:17 -0700 Subject: [PATCH 0194/1206] [3.12] gh-105375: Improve error handling in the sys extension module (GH-105611) (#105665) In _PySys_AddXOptionWithError() and sys_add_xoption(), bail on first error to prevent exceptions from possibly being overwritten. (cherry picked from commit 41cddc2e93a285b81fa30ac542b088bd9d0112e9) Co-authored-by: Erlend E. Aasland --- ...-06-09-23-46-23.gh-issue-105375.9KaioS.rst | 2 ++ Python/sysmodule.c | 24 ++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst b/Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst new file mode 100644 index 00000000000000..b12d7c864e7b86 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst @@ -0,0 +1,2 @@ +Fix bugs in :mod:`sys` where exceptions could end up being overwritten +because of deferred error handling. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index e6731e7565fcec..a05bdf0ea7eef5 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2718,14 +2718,20 @@ _PySys_AddXOptionWithError(const wchar_t *s) const wchar_t *name_end = wcschr(s, L'='); if (!name_end) { name = PyUnicode_FromWideChar(s, -1); + if (name == NULL) { + goto error; + } value = Py_NewRef(Py_True); } else { name = PyUnicode_FromWideChar(s, name_end - s); + if (name == NULL) { + goto error; + } value = PyUnicode_FromWideChar(name_end + 1, -1); - } - if (name == NULL || value == NULL) { - goto error; + if (value == NULL) { + goto error; + } } if (PyDict_SetItem(opts, name, value) < 0) { goto error; @@ -3370,14 +3376,20 @@ sys_add_xoption(PyObject *opts, const wchar_t *s) const wchar_t *name_end = wcschr(s, L'='); if (!name_end) { name = PyUnicode_FromWideChar(s, -1); + if (name == NULL) { + goto error; + } value = Py_NewRef(Py_True); } else { name = PyUnicode_FromWideChar(s, name_end - s); + if (name == NULL) { + goto error; + } value = PyUnicode_FromWideChar(name_end + 1, -1); - } - if (name == NULL || value == NULL) { - goto error; + if (value == NULL) { + goto error; + } } if (PyDict_SetItem(opts, name, value) < 0) { goto error; From d310fc776ee4ba94a5128bd3c22a7904f6546470 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 11 Jun 2023 23:35:13 +0200 Subject: [PATCH 0195/1206] [3.12] gh-105375: Harden pyexpat initialisation (#105606) (#105669) (cherry picked from commit 20a56d8becba1a5a958b167fdb43b1a1b9228095) Add proper error handling to add_errors_module() to prevent exceptions from possibly being overwritten. --- ...3-06-09-23-00-13.gh-issue-105605.YuwqxY.rst | 3 +++ Modules/pyexpat.c | 18 +++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst b/Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst new file mode 100644 index 00000000000000..5fba6d293a785e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst @@ -0,0 +1,3 @@ +Harden :mod:`pyexpat` error handling during module initialisation to prevent +exceptions from possibly being overwritten, and objects from being +dereferenced twice. diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 92f594ab63ea2a..b21360419d6a14 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1775,14 +1775,18 @@ add_error(PyObject *errors_module, PyObject *codes_dict, static int add_errors_module(PyObject *mod) { + // add_submodule() returns a borrowed ref. PyObject *errors_module = add_submodule(mod, MODULE_NAME ".errors"); if (errors_module == NULL) { return -1; } PyObject *codes_dict = PyDict_New(); + if (codes_dict == NULL) { + return -1; + } PyObject *rev_codes_dict = PyDict_New(); - if (codes_dict == NULL || rev_codes_dict == NULL) { + if (rev_codes_dict == NULL) { goto error; } @@ -1803,17 +1807,17 @@ add_errors_module(PyObject *mod) goto error; } - if (PyModule_AddObject(errors_module, "codes", Py_NewRef(codes_dict)) < 0) { - Py_DECREF(codes_dict); + int rc = PyModule_AddObjectRef(errors_module, "codes", codes_dict); + Py_CLEAR(codes_dict); + if (rc < 0) { goto error; } - Py_CLEAR(codes_dict); - if (PyModule_AddObject(errors_module, "messages", Py_NewRef(rev_codes_dict)) < 0) { - Py_DECREF(rev_codes_dict); + rc = PyModule_AddObjectRef(errors_module, "messages", rev_codes_dict); + Py_CLEAR(rev_codes_dict); + if (rc < 0) { goto error; } - Py_CLEAR(rev_codes_dict); return 0; From 0b305e8d36c5ac5dc83f0c09e7e2b3360b992eea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 12 Jun 2023 02:15:45 -0700 Subject: [PATCH 0196/1206] [3.12] gh-105673: Fix uninitialized warning in sysmodule.c (GH-105674) (#105675) In sys_add_xoption(), 'value' may be uninitialized for some error paths. (cherry picked from commit a8d69fe92c65d636fc454cfb1825c357eb2e6325) Co-authored-by: Nikita Sobolev --- Python/sysmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index a05bdf0ea7eef5..b8254f4e94fd0f 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3371,7 +3371,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) static int sys_add_xoption(PyObject *opts, const wchar_t *s) { - PyObject *name, *value; + PyObject *name, *value = NULL; const wchar_t *name_end = wcschr(s, L'='); if (!name_end) { From 9e3e5d533efe154d0df15b2f666fcf88a936d745 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 12 Jun 2023 09:02:30 -0700 Subject: [PATCH 0197/1206] [3.12] ARM64 clamping bug also exists in MSVC 14.35 (GH-105679) (#105695) ARM64 clamping bug also exists in MSVC 14.35 (GH-105679) (cherry picked from commit 58f0bda34126ed790000451874b96140737f40ed) Co-authored-by: Steve Dower --- PCbuild/pyproject.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index 36c4c269d05da9..fd928cafd77aaa 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -25,7 +25,7 @@ <_VCToolsVersion>$([System.Version]::Parse(`$(VCToolsVersion)`).Major).$([System.Version]::Parse(`$(VCToolsVersion)`).Minor) - true + true From 2eed1f5868b1c54a5314b64c38010258d27658da Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 12 Jun 2023 09:24:21 -0700 Subject: [PATCH 0198/1206] [3.12] gh-103968: PyType_FromMetaclass: Allow metaclasses with tp_new=NULL (GH-105386) (GH-105697) gh-103968: PyType_FromMetaclass: Allow metaclasses with tp_new=NULL (GH-105386) (cherry picked from commit 2b90796be6959d5ef46b38c434a514fce25be971) Co-authored-by: Petr Viktorin --- Doc/c-api/type.rst | 2 +- Lib/test/test_capi/test_misc.py | 43 ++++++++++++++++--- ...-06-06-14-14-41.gh-issue-103968.BTO6II.rst | 2 + Modules/_testcapi/heaptype.c | 13 ++++++ Objects/typeobject.c | 2 +- 5 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index bf261b9814456e..c99c7ef93a45df 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -258,7 +258,7 @@ The following functions and structs are used to create (or *Py_tp_base[s]* slots if *bases* is ``NULL``, see below). Metaclasses that override :c:member:`~PyTypeObject.tp_new` are not - supported. + supported, except if ``tp_new`` is ``NULL``. (For backwards compatibility, other ``PyType_From*`` functions allow such metaclasses. They ignore ``tp_new``, which may result in incomplete initialization. This is deprecated and in Python 3.14+ such metaclasses will diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index e1b55cffe8ff52..9cd1554614695e 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -672,31 +672,60 @@ def test_heaptype_with_setattro(self): self.assertEqual(obj.pvalue, 0) def test_heaptype_with_custom_metaclass(self): - self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclass, type)) - self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclassCustomNew, type)) + metaclass = _testcapi.HeapCTypeMetaclass + self.assertTrue(issubclass(metaclass, type)) - t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclass) + # Class creation from C + t = _testcapi.pytype_fromspec_meta(metaclass) self.assertIsInstance(t, type) self.assertEqual(t.__name__, "HeapCTypeViaMetaclass") - self.assertIs(type(t), _testcapi.HeapCTypeMetaclass) + self.assertIs(type(t), metaclass) + + # Class creation from Python + t = metaclass("PyClassViaMetaclass", (), {}) + self.assertIsInstance(t, type) + self.assertEqual(t.__name__, "PyClassViaMetaclass") + + def test_heaptype_with_custom_metaclass_null_new(self): + metaclass = _testcapi.HeapCTypeMetaclassNullNew + + self.assertTrue(issubclass(metaclass, type)) + + # Class creation from C + t = _testcapi.pytype_fromspec_meta(metaclass) + self.assertIsInstance(t, type) + self.assertEqual(t.__name__, "HeapCTypeViaMetaclass") + self.assertIs(type(t), metaclass) + + # Class creation from Python + with self.assertRaisesRegex(TypeError, "cannot create .* instances"): + metaclass("PyClassViaMetaclass", (), {}) + + def test_heaptype_with_custom_metaclass_custom_new(self): + metaclass = _testcapi.HeapCTypeMetaclassCustomNew + + self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclassCustomNew, type)) msg = "Metaclasses with custom tp_new are not supported." with self.assertRaisesRegex(TypeError, msg): - t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclassCustomNew) + t = _testcapi.pytype_fromspec_meta(metaclass) def test_heaptype_with_custom_metaclass_deprecation(self): + metaclass = _testcapi.HeapCTypeMetaclassCustomNew + # gh-103968: a metaclass with custom tp_new is deprecated, but still # allowed for functions that existed in 3.11 # (PyType_FromSpecWithBases is used here). - class Base(metaclass=_testcapi.HeapCTypeMetaclassCustomNew): + class Base(metaclass=metaclass): pass + # Class creation from C with warnings_helper.check_warnings( ('.*custom tp_new.*in Python 3.14.*', DeprecationWarning), ): sub = _testcapi.make_type_with_base(Base) self.assertTrue(issubclass(sub, Base)) - self.assertIsInstance(sub, _testcapi.HeapCTypeMetaclassCustomNew) + self.assertIsInstance(sub, metaclass) def test_multiple_inheritance_ctypes_with_weakref_or_dict(self): diff --git a/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst b/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst new file mode 100644 index 00000000000000..b73103c4e0ad9e --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst @@ -0,0 +1,2 @@ +:c:func:`PyType_FromMetaclass` now allows metaclasses with ``tp_new`` +set to ``NULL``. diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index 565ab570a42bde..c124871e433431 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -744,6 +744,12 @@ static PyType_Spec HeapCTypeMetaclassCustomNew_spec = { HeapCTypeMetaclassCustomNew_slots }; +static PyType_Spec HeapCTypeMetaclassNullNew_spec = { + .name = "_testcapi.HeapCTypeMetaclassNullNew", + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .slots = empty_type_slots +}; + typedef struct { PyObject_HEAD @@ -1231,6 +1237,13 @@ _PyTestCapi_Init_Heaptype(PyObject *m) { } PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew); + PyObject *HeapCTypeMetaclassNullNew = PyType_FromMetaclass( + &PyType_Type, m, &HeapCTypeMetaclassNullNew_spec, (PyObject *) &PyType_Type); + if (HeapCTypeMetaclassNullNew == NULL) { + return -1; + } + PyModule_AddObject(m, "HeapCTypeMetaclassNullNew", HeapCTypeMetaclassNullNew); + PyObject *HeapCCollection = PyType_FromMetaclass( NULL, m, &HeapCCollection_spec, NULL); if (HeapCCollection == NULL) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b6771d3004df91..bf33bde2571012 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4236,7 +4236,7 @@ _PyType_FromMetaclass_impl( metaclass); goto finally; } - if (metaclass->tp_new != PyType_Type.tp_new) { + if (metaclass->tp_new && metaclass->tp_new != PyType_Type.tp_new) { if (_allow_tp_new) { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, From 77bdeebdda3358186df6e6ba900c562ddaefaa5c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 12 Jun 2023 09:50:58 -0700 Subject: [PATCH 0199/1206] [3.12] gh-105436: The environment block should end with two null wchar_t values (GH-105495) (#105700) gh-105436: The environment block should end with two null wchar_t values (GH-105495) (cherry picked from commit 4f7d3b602d47d61137e82145f601dccfe6f6cd3c) Co-authored-by: Dora203 <66343334+sku2000@users.noreply.github.com> --- Lib/test/test_subprocess.py | 7 +++++++ .../2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst | 2 ++ Modules/_winapi.c | 14 +++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 51ba423a0f1c92..3d4fffbb8e794a 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1692,6 +1692,13 @@ def test_run_with_pathlike_path_and_arguments(self): res = subprocess.run(args) self.assertEqual(res.returncode, 57) + @unittest.skipUnless(mswindows, "Maybe test trigger a leak on Ubuntu") + def test_run_with_an_empty_env(self): + # gh-105436: fix subprocess.run(..., env={}) broken on Windows + args = [sys.executable, "-c", 'import sys; sys.exit(57)'] + res = subprocess.run(args, env={}) + self.assertEqual(res.returncode, 57) + def test_capture_output(self): cp = self.run_python(("import sys;" "sys.stdout.write('BDFL'); " diff --git a/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst b/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst new file mode 100644 index 00000000000000..1e3f298096cdd6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst @@ -0,0 +1,2 @@ +Ensure that an empty environment block is terminated by two null characters, +as is required by Windows. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index bbc9facd227c9e..d6d2f4a6a9b103 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -796,6 +796,17 @@ getenvironment(PyObject* environment) } envsize = PyList_GET_SIZE(keys); + + if (envsize == 0) { + // A environment block must be terminated by two null characters -- + // one for the last string and one for the block. + buffer = PyMem_Calloc(2, sizeof(wchar_t)); + if (!buffer) { + PyErr_NoMemory(); + } + goto cleanup; + } + if (PyList_GET_SIZE(values) != envsize) { PyErr_SetString(PyExc_RuntimeError, "environment changed size during iteration"); @@ -869,7 +880,8 @@ getenvironment(PyObject* environment) *p++ = L'\0'; assert(p == end); - error: +cleanup: +error: Py_XDECREF(keys); Py_XDECREF(values); return buffer; From 017b9595d4060521f93804d5dd555b6cd6585578 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 12 Jun 2023 15:12:17 -0700 Subject: [PATCH 0200/1206] [3.12] gh-105375: Explicitly initialise all {Pickler,Unpickler}Object fields (GH-105686) (#105710) All fields must be explicitly initialised to prevent manipulation of uninitialised fields in dealloc. Align initialisation order with the layout of the object structs. (cherry picked from commit ca3cc4b95d66f7527ebe0ba4cdb1907082d9bfc8) Co-authored-by: Erlend E. Aasland --- Modules/_pickle.c | 90 ++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c index d6a273b1044e44..688bccbab6b4a8 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1145,42 +1145,49 @@ _Pickler_Write(PicklerObject *self, const char *s, Py_ssize_t data_len) static PicklerObject * _Pickler_New(PickleState *st) { - PicklerObject *self; - - self = PyObject_GC_New(PicklerObject, st->Pickler_Type); - if (self == NULL) + PyMemoTable *memo = PyMemoTable_New(); + if (memo == NULL) { return NULL; + } + + const Py_ssize_t max_output_len = WRITE_BUF_SIZE; + PyObject *output_buffer = PyBytes_FromStringAndSize(NULL, max_output_len); + if (output_buffer == NULL) { + goto error; + } + PicklerObject *self = PyObject_GC_New(PicklerObject, st->Pickler_Type); + if (self == NULL) { + goto error; + } + + self->memo = memo; self->pers_func = NULL; + self->pers_func_self = NULL; self->dispatch_table = NULL; - self->buffer_callback = NULL; + self->reducer_override = NULL; self->write = NULL; + self->output_buffer = output_buffer; + self->output_len = 0; + self->max_output_len = max_output_len; self->proto = 0; self->bin = 0; self->framing = 0; self->frame_start = -1; + self->buf_size = 0; self->fast = 0; self->fast_nesting = 0; self->fix_imports = 0; self->fast_memo = NULL; - self->max_output_len = WRITE_BUF_SIZE; - self->output_len = 0; - self->reducer_override = NULL; - - self->memo = PyMemoTable_New(); - if (self->memo == NULL) { - Py_DECREF(self); - return NULL; - } - self->output_buffer = PyBytes_FromStringAndSize(NULL, - self->max_output_len); - if (self->output_buffer == NULL) { - Py_DECREF(self); - return NULL; - } + self->buffer_callback = NULL; PyObject_GC_Track(self); return self; + +error: + PyMem_Free(memo); + Py_XDECREF(output_buffer); + return NULL; } static int @@ -1628,14 +1635,31 @@ _Unpickler_MemoCleanup(UnpicklerObject *self) static UnpicklerObject * _Unpickler_New(PyObject *module) { - UnpicklerObject *self; + const int MEMO_SIZE = 32; + PyObject **memo = _Unpickler_NewMemo(MEMO_SIZE); + if (memo == NULL) { + return NULL; + } + PickleState *st = _Pickle_GetState(module); + PyObject *stack = Pdata_New(st); + if (stack == NULL) { + goto error; + } - self = PyObject_GC_New(UnpicklerObject, st->Unpickler_Type); - if (self == NULL) - return NULL; + UnpicklerObject *self = PyObject_GC_New(UnpicklerObject, + st->Unpickler_Type); + if (self == NULL) { + goto error; + } + self->stack = (Pdata *)stack; + self->memo = memo; + self->memo_size = MEMO_SIZE; + self->memo_len = 0; self->pers_func = NULL; + self->pers_func_self = NULL; + memset(&self->buffer, 0, sizeof(Py_buffer)); self->input_buffer = NULL; self->input_line = NULL; self->input_len = 0; @@ -1653,22 +1677,14 @@ _Unpickler_New(PyObject *module) self->marks_size = 0; self->proto = 0; self->fix_imports = 0; - memset(&self->buffer, 0, sizeof(Py_buffer)); - self->memo_size = 32; - self->memo_len = 0; - self->memo = _Unpickler_NewMemo(self->memo_size); - if (self->memo == NULL) { - Py_DECREF(self); - return NULL; - } - self->stack = (Pdata *)Pdata_New(st); - if (self->stack == NULL) { - Py_DECREF(self); - return NULL; - } PyObject_GC_Track(self); return self; + +error: + PyMem_Free(memo); + Py_XDECREF(stack); + return NULL; } /* Returns -1 (with an exception set) on failure, 0 on success. This may From 56877e4560821ad00cabe6253448c1c938cfed59 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 13 Jun 2023 11:15:19 +0200 Subject: [PATCH 0201/1206] [3.12] gh-105375: Improve error handling in _Unpickler_SetInputStream() (#105667) (#105720) Prevent exceptions from possibly being overwritten in case of multiple failures. (cherry picked from commit 217589d4f3246d67c6ef0eb0be2b1c33987cf260) --- ...-06-11-22-46-06.gh-issue-105375.YkhSNt.rst | 2 ++ Modules/_pickle.c | 31 +++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst b/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst new file mode 100644 index 00000000000000..dda8f428760ba1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst @@ -0,0 +1,2 @@ +Fix a bug in :c:func:`!_Unpickler_SetInputStream` where an exception could +end up being overwritten in case of failure. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 688bccbab6b4a8..d2f6d71059ea00 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1694,25 +1694,30 @@ _Unpickler_SetInputStream(UnpicklerObject *self, PyObject *file) { /* Optional file methods */ if (_PyObject_LookupAttr(file, &_Py_ID(peek), &self->peek) < 0) { - return -1; + goto error; } if (_PyObject_LookupAttr(file, &_Py_ID(readinto), &self->readinto) < 0) { - return -1; + goto error; + } + if (_PyObject_LookupAttr(file, &_Py_ID(read), &self->read) < 0) { + goto error; + } + if (_PyObject_LookupAttr(file, &_Py_ID(readline), &self->readline) < 0) { + goto error; } - (void)_PyObject_LookupAttr(file, &_Py_ID(read), &self->read); - (void)_PyObject_LookupAttr(file, &_Py_ID(readline), &self->readline); if (!self->readline || !self->read) { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "file must have 'read' and 'readline' attributes"); - } - Py_CLEAR(self->read); - Py_CLEAR(self->readinto); - Py_CLEAR(self->readline); - Py_CLEAR(self->peek); - return -1; + PyErr_SetString(PyExc_TypeError, + "file must have 'read' and 'readline' attributes"); + goto error; } return 0; + +error: + Py_CLEAR(self->read); + Py_CLEAR(self->readinto); + Py_CLEAR(self->readline); + Py_CLEAR(self->peek); + return -1; } /* Returns -1 (with an exception set) on failure, 0 on success. This may From 92929fd20ee5cd6ecafcb9f992d24ac2289b3c27 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 03:48:43 -0700 Subject: [PATCH 0202/1206] [3.12] gh-105713: Document that tokenize raises when mixing tabs/spaces (GH-105723) (#105725) * gh-105713: Document that tokenize raises when mixing tabs/spaces * Update Doc/whatsnew/3.12.rst (cherry picked from commit ed8217b493e19cea0f3f539e55b592c09ceb9323) Co-authored-by: Lysandros Nikolaou Co-authored-by: Alex Waygood --- Doc/whatsnew/3.12.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8bc7e8a630e2a6..fcfd034b03903b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1498,6 +1498,9 @@ Changes in the Python API * Some incomplete or invalid Python code now raises :exc:`tokenize.TokenError` instead of returning arbitrary ``ERRORTOKEN`` tokens when tokenizing it. + * Mixing tabs and spaces as indentation in the same file is not supported anymore and will + raise a :exc:`TabError`. + Build Changes ============= From 04b91680373149077f8c466e6694b97966e1f2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 13 Jun 2023 12:54:11 +0200 Subject: [PATCH 0203/1206] [3.12] gh-105084: Tests: Use setuptools+wheel from sysconfig.get_config_var('WHEEL_PKG_DIR') if set (#105056) (#105424) Includes part of the changes from afa759fb800be416f69e3e9c9b3efe68006316f5, to make this apply. Co-Authored-By: Lysandros Nikolaou (cherry picked from commit bd98b65e974b7a1e086a51e7b55131582f7a0491) --- Lib/test/support/__init__.py | 56 +++++++++++++++++++ Lib/test/test_cppext.py | 41 +++----------- ...-05-29-14-49-46.gh-issue-105084.lvVvoj.rst | 3 + 3 files changed, 67 insertions(+), 33 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index d555c53fee50a2..4d01bb5a848f7b 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2270,6 +2270,62 @@ def requires_venv_with_pip(): return unittest.skipUnless(ctypes, 'venv: pip requires ctypes') +@functools.cache +def _findwheel(pkgname): + """Try to find a wheel with the package specified as pkgname. + + If set, the wheels are searched for in WHEEL_PKG_DIR (see ensurepip). + Otherwise, they are searched for in the test directory. + """ + wheel_dir = sysconfig.get_config_var('WHEEL_PKG_DIR') or TEST_HOME_DIR + filenames = os.listdir(wheel_dir) + filenames = sorted(filenames, reverse=True) # approximate "newest" first + for filename in filenames: + # filename is like 'setuptools-67.6.1-py3-none-any.whl' + if not filename.endswith(".whl"): + continue + prefix = pkgname + '-' + if filename.startswith(prefix): + return os.path.join(wheel_dir, filename) + raise FileNotFoundError(f"No wheel for {pkgname} found in {wheel_dir}") + + +# Context manager that creates a virtual environment, install setuptools and wheel in it +# and returns the path to the venv directory and the path to the python executable +@contextlib.contextmanager +def setup_venv_with_pip_setuptools_wheel(venv_dir): + import subprocess + from .os_helper import temp_cwd + + with temp_cwd() as temp_dir: + # Create virtual environment to get setuptools + cmd = [sys.executable, '-X', 'dev', '-m', 'venv', venv_dir] + if verbose: + print() + print('Run:', ' '.join(cmd)) + subprocess.run(cmd, check=True) + + venv = os.path.join(temp_dir, venv_dir) + + # Get the Python executable of the venv + python_exe = os.path.basename(sys.executable) + if sys.platform == 'win32': + python = os.path.join(venv, 'Scripts', python_exe) + else: + python = os.path.join(venv, 'bin', python_exe) + + cmd = [python, '-X', 'dev', + '-m', 'pip', 'install', + _findwheel('setuptools'), + _findwheel('wheel')] + if verbose: + print() + print('Run:', ' '.join(cmd)) + subprocess.run(cmd, check=True) + + yield python + + # True if Python is built with the Py_DEBUG macro defined: if # Python is built in debug mode (./configure --with-pydebug). Py_DEBUG = hasattr(sys, 'gettotalrefcount') diff --git a/Lib/test/test_cppext.py b/Lib/test/test_cppext.py index 4fb62d87e860fc..e2fedc9735079f 100644 --- a/Lib/test/test_cppext.py +++ b/Lib/test/test_cppext.py @@ -35,39 +35,20 @@ def test_build_cpp03(self): # the test uses venv+pip: skip if it's not available @support.requires_venv_with_pip() def check_build(self, std_cpp03, extension_name): - # Build in a temporary directory - with os_helper.temp_cwd(): - self._check_build(std_cpp03, extension_name) + venv_dir = 'env' + with support.setup_venv_with_pip_setuptools_wheel(venv_dir) as python_exe: + self._check_build(std_cpp03, extension_name, python_exe) - def _check_build(self, std_cpp03, extension_name): + def _check_build(self, std_cpp03, extension_name, python_exe): pkg_dir = 'pkg' os.mkdir(pkg_dir) shutil.copy(SETUP_TESTCPPEXT, os.path.join(pkg_dir, "setup.py")) - venv_dir = 'env' - verbose = support.verbose - - # Create virtual environment to get setuptools - cmd = [sys.executable, '-X', 'dev', '-m', 'venv', venv_dir] - if verbose: - print() - print('Run:', ' '.join(cmd)) - subprocess.run(cmd, check=True) - - # Get the Python executable of the venv - python_exe = 'python' - if sys.executable.endswith('.exe'): - python_exe += '.exe' - if MS_WINDOWS: - python = os.path.join(venv_dir, 'Scripts', python_exe) - else: - python = os.path.join(venv_dir, 'bin', python_exe) - def run_cmd(operation, cmd): env = os.environ.copy() env['CPYTHON_TEST_CPP_STD'] = 'c++03' if std_cpp03 else 'c++11' env['CPYTHON_TEST_EXT_NAME'] = extension_name - if verbose: + if support.verbose: print('Run:', ' '.join(cmd)) subprocess.run(cmd, check=True, env=env) else: @@ -81,14 +62,8 @@ def run_cmd(operation, cmd): self.fail( f"{operation} failed with exit code {proc.returncode}") - cmd = [python, '-X', 'dev', - '-m', 'pip', 'install', - support.findfile('setuptools-67.6.1-py3-none-any.whl'), - support.findfile('wheel-0.40.0-py3-none-any.whl')] - run_cmd('Install build dependencies', cmd) - # Build and install the C++ extension - cmd = [python, '-X', 'dev', + cmd = [python_exe, '-X', 'dev', '-m', 'pip', 'install', '--no-build-isolation', os.path.abspath(pkg_dir)] run_cmd('Install', cmd) @@ -96,14 +71,14 @@ def run_cmd(operation, cmd): # Do a reference run. Until we test that running python # doesn't leak references (gh-94755), run it so one can manually check # -X showrefcount results against this baseline. - cmd = [python, + cmd = [python_exe, '-X', 'dev', '-X', 'showrefcount', '-c', 'pass'] run_cmd('Reference run', cmd) # Import the C++ extension - cmd = [python, + cmd = [python_exe, '-X', 'dev', '-X', 'showrefcount', '-c', f"import {extension_name}"] diff --git a/Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst b/Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst new file mode 100644 index 00000000000000..5f80d507147347 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst @@ -0,0 +1,3 @@ +When the Python build is configured ``--with-wheel-pkg-dir``, tests +requiring the ``setuptools`` and ``wheel`` wheels will search for the wheels +in ``WHEEL_PKG_DIR``. From 9c51ea5d550dbcf5568b57913b1b453d1f92fd5c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 08:53:51 -0700 Subject: [PATCH 0204/1206] [3.12] gh-105718: Fix buffer allocation in tokenizer with readline (GH-105728) (#105729) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_tokenize.py | 10 ++++++++++ Parser/tokenizer.c | 4 ---- Parser/tokenizer.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index df9c9db322dc94..15f53632cff814 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -2239,6 +2239,16 @@ def test_string(self): FSTRING_START \'f"\' (1, 0) (1, 2) FSTRING_MIDDLE 'abc\\\\\\ndef' (1, 2) (2, 3) FSTRING_END '"' (2, 3) (2, 4) + """) + + self.check_tokenize('''\ +f"{ +a}"''', """\ + FSTRING_START 'f"' (1, 0) (1, 2) + LBRACE '{' (1, 2) (1, 3) + NAME 'a' (2, 0) (2, 1) + RBRACE '}' (2, 1) (2, 2) + FSTRING_END '"' (2, 2) (2, 3) """) self.check_tokenize(r'Rf"abc\ diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 57c98fe5fcaa40..f41dd130af1f7d 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1106,11 +1106,7 @@ tok_readline_string(struct tok_state* tok) { tok->inp += buflen; *tok->inp = '\0'; - if (tok->start == NULL) { - tok->buf = tok->cur; - } tok->line_start = tok->cur; - Py_DECREF(line); return 1; error: diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 16e919a8931edd..cb44845c1d306e 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -68,7 +68,7 @@ typedef struct _tokenizer_mode { struct tok_state { /* Input state; buf <= cur <= inp <= end */ /* NB an entire line is held in the buffer */ - char *buf; /* Input buffer, or NULL; malloc'ed if fp != NULL */ + char *buf; /* Input buffer, or NULL; malloc'ed if fp != NULL or readline != NULL */ char *cur; /* Next character in buffer */ char *inp; /* End of data in buffer */ int fp_interactive; /* If the file descriptor is interactive */ From c3a2cbb54d19e86f1ff402f7783d51610c2ff646 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:42:56 -0700 Subject: [PATCH 0205/1206] [3.12] gh-105603: Change the PyInterpreterConfig.own gil Field (gh-105620) (gh-105731) We are changing it to be more flexible that a strict bool can be for possible future expanded used cases. (cherry picked from commit b97e14a806477af4225777d215ac38c0d9b845f0) Co-authored-by: Eric Snow --- Include/cpython/initconfig.h | 10 +++++++--- Lib/test/support/__init__.py | 5 ++++- Lib/test/test_import/__init__.py | 3 ++- ...-06-09-19-16-57.gh-issue-105603.-z6G22.rst | 5 +++++ Modules/_testcapimodule.c | 14 +++++++------- Python/pylifecycle.c | 19 +++++++++++++++---- 6 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index efae2409b50069..c103c2026e40e9 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -244,6 +244,10 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config, /* --- PyInterpreterConfig ------------------------------------ */ +#define PyInterpreterConfig_DEFAULT_GIL (0) +#define PyInterpreterConfig_SHARED_GIL (1) +#define PyInterpreterConfig_OWN_GIL (2) + typedef struct { // XXX "allow_object_sharing"? "own_objects"? int use_main_obmalloc; @@ -252,7 +256,7 @@ typedef struct { int allow_threads; int allow_daemon_threads; int check_multi_interp_extensions; - int own_gil; + int gil; } PyInterpreterConfig; #define _PyInterpreterConfig_INIT \ @@ -263,7 +267,7 @@ typedef struct { .allow_threads = 1, \ .allow_daemon_threads = 0, \ .check_multi_interp_extensions = 1, \ - .own_gil = 1, \ + .gil = PyInterpreterConfig_OWN_GIL, \ } #define _PyInterpreterConfig_LEGACY_INIT \ @@ -274,7 +278,7 @@ typedef struct { .allow_threads = 1, \ .allow_daemon_threads = 1, \ .check_multi_interp_extensions = 0, \ - .own_gil = 0, \ + .gil = PyInterpreterConfig_SHARED_GIL, \ } /* --- Helper functions --------------------------------------- */ diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 4d01bb5a848f7b..c59508b40d3203 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1813,13 +1813,16 @@ def run_in_subinterp(code): return _testcapi.run_in_subinterp(code) -def run_in_subinterp_with_config(code, **config): +def run_in_subinterp_with_config(code, *, own_gil=None, **config): """ Run code in a subinterpreter. Raise unittest.SkipTest if the tracemalloc module is enabled. """ _check_tracemalloc() import _testcapi + if own_gil is not None: + assert 'gil' not in config, (own_gil, config) + config['gil'] = 2 if own_gil else 1 return _testcapi.run_in_subinterp_with_config(code, **config) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 227c912bc8c322..71a50bcbeedf9b 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1640,9 +1640,10 @@ class SubinterpImportTests(unittest.TestCase): ) ISOLATED = dict( use_main_obmalloc=False, - own_gil=True, + gil=2, ) NOT_ISOLATED = {k: not v for k, v in ISOLATED.items()} + NOT_ISOLATED['gil'] = 1 @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") def pipe(self): diff --git a/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst b/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst new file mode 100644 index 00000000000000..cd3d9bcdd4e285 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst @@ -0,0 +1,5 @@ +We've renamed the new (in 3.12) ``PyInterpreterConfig.own_gil`` to +``PyInterpreterConfig.gil`` and changed the meaning of the value from "bool" +to an integer with supported values of ``PyInterpreterConfig_DEFAULT_GIL``, +``PyInterpreterConfig_SHARED_GIL``, and ``PyInterpreterConfig_OWN_GIL``. The +default is "shared". diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index b8ad00a0197421..04a880021147e2 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1426,7 +1426,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) int allow_threads = -1; int allow_daemon_threads = -1; int check_multi_interp_extensions = -1; - int own_gil = -1; + int gil = -1; int r; PyThreadState *substate, *mainstate; /* only initialise 'cflags.cf_flags' to test backwards compatibility */ @@ -1439,15 +1439,15 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) "allow_threads", "allow_daemon_threads", "check_multi_interp_extensions", - "own_gil", + "gil", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "s$ppppppp:run_in_subinterp_with_config", kwlist, + "s$ppppppi:run_in_subinterp_with_config", kwlist, &code, &use_main_obmalloc, &allow_fork, &allow_exec, &allow_threads, &allow_daemon_threads, &check_multi_interp_extensions, - &own_gil)) { + &gil)) { return NULL; } if (use_main_obmalloc < 0) { @@ -1466,8 +1466,8 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) PyErr_SetString(PyExc_ValueError, "missing allow_threads"); return NULL; } - if (own_gil < 0) { - PyErr_SetString(PyExc_ValueError, "missing own_gil"); + if (gil < 0) { + PyErr_SetString(PyExc_ValueError, "missing gil"); return NULL; } if (allow_daemon_threads < 0) { @@ -1490,7 +1490,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) .allow_threads = allow_threads, .allow_daemon_threads = allow_daemon_threads, .check_multi_interp_extensions = check_multi_interp_extensions, - .own_gil = own_gil, + .gil = gil, }; PyStatus status = Py_NewInterpreterFromConfig(&substate, &config); if (PyStatus_Exception(status)) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 95b39f478f51f6..c4e6b69d8d56f3 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -578,12 +578,14 @@ init_interp_settings(PyInterpreterState *interp, interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS; } + /* We check "gil" in init_interp_create_gil(). */ + return _PyStatus_OK(); } static PyStatus -init_interp_create_gil(PyThreadState *tstate, int own_gil) +init_interp_create_gil(PyThreadState *tstate, int gil) { PyStatus status; @@ -598,6 +600,15 @@ init_interp_create_gil(PyThreadState *tstate, int own_gil) return status; } + int own_gil; + switch (gil) { + case PyInterpreterConfig_DEFAULT_GIL: own_gil = 0; break; + case PyInterpreterConfig_SHARED_GIL: own_gil = 0; break; + case PyInterpreterConfig_OWN_GIL: own_gil = 1; break; + default: + return _PyStatus_ERR("invalid interpreter config 'gil' value"); + } + /* Create the GIL and take it */ status = _PyEval_InitGIL(tstate, own_gil); if (_PyStatus_EXCEPTION(status)) { @@ -633,7 +644,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; // The main interpreter always has its own GIL. - config.own_gil = 1; + config.gil = PyInterpreterConfig_OWN_GIL; status = init_interp_settings(interp, &config); if (_PyStatus_EXCEPTION(status)) { return status; @@ -647,7 +658,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, // XXX For now we do this before the GIL is created. (void) _PyThreadState_SwapNoGIL(tstate); - status = init_interp_create_gil(tstate, config.own_gil); + status = init_interp_create_gil(tstate, config.gil); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -2057,7 +2068,7 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) goto error; } - status = init_interp_create_gil(tstate, config->own_gil); + status = init_interp_create_gil(tstate, config->gil); if (_PyStatus_EXCEPTION(status)) { goto error; } From 27426d89835ef6e2f28c5b48d553826daa01120b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 14:21:04 -0700 Subject: [PATCH 0206/1206] [3.12] gh-102613: Bump recursion limit to fix running test_pathlib under Coverage (GH-105744) (#105749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-102613: Bump recursion limit to fix running test_pathlib under Coverage (GH-105744) (cherry picked from commit 4e80082723b768df124f77d2b73b3ba6b584a735) Co-authored-by: Åukasz Langa --- Lib/test/test_pathlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index bf4decf9f97ae8..f716f1075bcb3e 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1985,7 +1985,7 @@ def test_glob_long_symlink(self): self.assertEqual(sorted(base.glob('**/*')), [bad_link]) def test_glob_above_recursion_limit(self): - recursion_limit = 40 + recursion_limit = 50 # directory_depth > recursion_limit directory_depth = recursion_limit + 10 base = pathlib.Path(os_helper.TESTFN, 'deep') From 51b533ec5049593dc009383226f935cf5181484c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:59:02 -0700 Subject: [PATCH 0207/1206] [3.12] gh-98040: Fix importbench: use types.ModuleType() (GH-105743) (#105754) gh-98040: Fix importbench: use types.ModuleType() (GH-105743) Replace removed imp.new_module(name) with types.ModuleType(name). (cherry picked from commit 457a459c7804950d4c27a243b176eb933ec87a06) Co-authored-by: Victor Stinner --- Doc/whatsnew/3.12.rst | 2 ++ Tools/importbench/importbench.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index fcfd034b03903b..4849f8c3e281f9 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1368,6 +1368,8 @@ Removed * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in :gh:`98040`.) + * Replace ``imp.new_module(name)`` with ``types.ModuleType(name)``. + * Removed the ``suspicious`` rule from the documentation Makefile, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint `_. diff --git a/Tools/importbench/importbench.py b/Tools/importbench/importbench.py index 619263b553c081..0c4b3bc73517c5 100644 --- a/Tools/importbench/importbench.py +++ b/Tools/importbench/importbench.py @@ -15,6 +15,7 @@ import sys import tabnanny import timeit +import types def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): @@ -40,7 +41,7 @@ def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): def from_cache(seconds, repeat): """sys.modules""" name = '' - module = imp.new_module(name) + module = types.ModuleType(name) module.__file__ = '' module.__package__ = '' with util.uncache(name): From 75239d5ec1505b8f9f20d3c2d366c1a3ebd269aa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 16:41:07 -0700 Subject: [PATCH 0208/1206] [3.12] gh-105436: Ignore unrelated errors when checking empty env (GH-105742) (#105756) gh-105436: Ignore unrelated errors when checking empty env (GH-105742) (cherry picked from commit 4cefe3cf10f498c0927ae4fdba4880d5a64826e4) Co-authored-by: Steve Dower --- Lib/test/test_subprocess.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3d4fffbb8e794a..817eab0c8a7e19 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1695,9 +1695,10 @@ def test_run_with_pathlike_path_and_arguments(self): @unittest.skipUnless(mswindows, "Maybe test trigger a leak on Ubuntu") def test_run_with_an_empty_env(self): # gh-105436: fix subprocess.run(..., env={}) broken on Windows - args = [sys.executable, "-c", 'import sys; sys.exit(57)'] - res = subprocess.run(args, env={}) - self.assertEqual(res.returncode, 57) + args = [sys.executable, "-c", 'pass'] + # Ignore subprocess errors - we only care that the API doesn't + # raise an OSError + subprocess.run(args, env={}) def test_capture_output(self): cp = self.run_python(("import sys;" From 33d3069c45bda38f52053a115e3c0810cd631dd6 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 13 Jun 2023 18:50:08 -0600 Subject: [PATCH 0209/1206] [3.12] gh-104812: Run Pending Calls in any Thread (gh-104813) (gh-105752) For a while now, pending calls only run in the main thread (in the main interpreter). This PR changes things to allow any thread run a pending call, unless the pending call was explicitly added for the main thread to run. (cherry picked from commit 757b402) --- Doc/data/python3.12.abi | 1089 +++++++++-------- Include/cpython/ceval.h | 2 + Include/internal/pycore_ceval.h | 3 +- Include/internal/pycore_ceval_state.h | 38 +- Include/internal/pycore_pystate.h | 8 - Lib/test/support/threading_helper.py | 9 +- Lib/test/test_capi/test_misc.py | 403 +++++- ...-06-02-15-15-41.gh-issue-104812.dfZiG5.rst | 9 + Modules/_queuemodule.c | 3 +- Modules/_testinternalcapi.c | 121 +- Modules/_threadmodule.c | 3 +- Modules/signalmodule.c | 6 +- Python/ceval.c | 55 + Python/ceval_gil.c | 213 ++-- Python/pylifecycle.c | 3 + Python/pystate.c | 3 +- Tools/c-analyzer/cpython/ignored.tsv | 1 + 17 files changed, 1311 insertions(+), 658 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 0615923c38b667..b58ee3744ba3f1 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1079,6 +1079,7 @@ + @@ -1702,7 +1703,7 @@ - + @@ -2512,22 +2513,22 @@ - + - + - + - + @@ -3442,23 +3443,23 @@ - + - - + + - + - + - + - + @@ -3635,37 +3636,37 @@ - + - + - + - + - + - + - + - + - + @@ -3737,38 +3738,38 @@ - - + + - + - + - - + + - - - - + + + + - - - + + + - - + + - - + + @@ -4024,7 +4025,7 @@ - + @@ -5091,7 +5092,7 @@ - + @@ -5373,7 +5374,7 @@ - + @@ -7217,7 +7218,7 @@ - + @@ -7317,7 +7318,7 @@ - + @@ -7493,7 +7494,7 @@ - + @@ -7644,7 +7645,7 @@ - + @@ -8230,8 +8231,8 @@ - - + + @@ -9502,185 +9503,185 @@ - - - - + + + + - - - + + + - - - - + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - + + + - - - + + + - - - - + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - + + + - - - + + + - - - - + + + + - - - + + + - - - - - + + + + + - - - - + + + + - - - + + + - - + + - + @@ -11112,7 +11113,7 @@ - + @@ -11913,7 +11914,7 @@ - + @@ -11994,7 +11995,7 @@ - + @@ -12815,104 +12816,107 @@ - - - - - - - - + - + - + - + + + + - + + + + + + + - + - + - - + + - + + + + + + + + - + - + - + - + - - + + + + + + + + + + - + - + - + - - - - + - + - - - - - - - - - - - - - + + - + - + - + - + - + - + - + - + @@ -13073,7 +13077,7 @@ - + @@ -13090,7 +13094,7 @@ - + @@ -13351,7 +13355,7 @@ - + @@ -13380,7 +13384,7 @@ - + @@ -13428,7 +13432,7 @@ - + @@ -13456,7 +13460,7 @@ - + @@ -13536,7 +13540,7 @@ - + @@ -13544,7 +13548,7 @@ - + @@ -13552,7 +13556,7 @@ - + @@ -13560,7 +13564,7 @@ - + @@ -13568,7 +13572,7 @@ - + @@ -13576,7 +13580,7 @@ - + @@ -13584,7 +13588,7 @@ - + @@ -13592,7 +13596,7 @@ - + @@ -13600,7 +13604,7 @@ - + @@ -13608,7 +13612,7 @@ - + @@ -13616,7 +13620,7 @@ - + @@ -13624,7 +13628,7 @@ - + @@ -13632,7 +13636,7 @@ - + @@ -15707,7 +15711,7 @@ - + @@ -15715,7 +15719,7 @@ - + @@ -15723,7 +15727,7 @@ - + @@ -15731,7 +15735,7 @@ - + @@ -15739,7 +15743,7 @@ - + @@ -15747,7 +15751,7 @@ - + @@ -15755,7 +15759,7 @@ - + @@ -15763,7 +15767,7 @@ - + @@ -15771,7 +15775,7 @@ - + @@ -15779,7 +15783,7 @@ - + @@ -15787,7 +15791,7 @@ - + @@ -15795,7 +15799,7 @@ - + @@ -15803,7 +15807,7 @@ - + @@ -15811,7 +15815,7 @@ - + @@ -15819,7 +15823,7 @@ - + @@ -15827,7 +15831,7 @@ - + @@ -15835,7 +15839,7 @@ - + @@ -15960,7 +15964,7 @@ - + @@ -16000,7 +16004,7 @@ - + @@ -16011,7 +16015,7 @@ - + @@ -16447,7 +16451,7 @@ - + @@ -16481,7 +16485,7 @@ - + @@ -16492,7 +16496,7 @@ - + @@ -16511,7 +16515,7 @@ - + @@ -16547,7 +16551,7 @@ - + @@ -16612,51 +16616,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -16682,7 +16686,7 @@ - + @@ -16710,7 +16714,7 @@ - + @@ -16718,7 +16722,7 @@ - + @@ -16811,7 +16815,7 @@ - + @@ -17189,7 +17193,7 @@ - + @@ -17197,7 +17201,7 @@ - + @@ -17208,7 +17212,7 @@ - + @@ -17219,7 +17223,7 @@ - + @@ -17236,7 +17240,7 @@ - + @@ -17255,7 +17259,7 @@ - + @@ -17263,7 +17267,7 @@ - + @@ -17271,7 +17275,7 @@ - + @@ -17356,7 +17360,7 @@ - + @@ -17370,7 +17374,7 @@ - + @@ -17386,14 +17390,14 @@ - - + + - + @@ -17417,7 +17421,7 @@ - + @@ -19985,13 +19989,13 @@ - + - + @@ -21299,7 +21303,7 @@ - + @@ -21357,17 +21361,17 @@ - - - - - - - + + + + + + + - + @@ -21620,11 +21624,11 @@ - + - + @@ -21897,58 +21901,58 @@ - - + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - + - - + + - - + + - - + + - - + + - - + + - + @@ -21987,7 +21991,7 @@ - + @@ -22003,13 +22007,10 @@ - + - - - @@ -22059,53 +22060,58 @@ - - + + - + - + - + - + - + - - + + - - + + - - + + - - + + - - - - + + + + + + + + + + - - - + + - + @@ -22731,35 +22737,35 @@ - - - - - - + + + + + + - - - - + + + + - + - - - - + + + + - - - - - + + + + + @@ -23689,24 +23695,24 @@ - + - + - + - + - + @@ -24534,7 +24540,7 @@ - + @@ -24676,42 +24682,42 @@ - + - + - + - + - + - + - + - + - - + + - + - + - + - + @@ -24746,30 +24752,30 @@ - + - + - + - + - + - + - + @@ -25106,15 +25112,15 @@ - + - + - + @@ -25236,6 +25242,9 @@ + + + @@ -25308,91 +25317,91 @@ - - - + + + - - - - + + + + - - - - + + + + - - + + - - + + - + - + - + - - - + + + - + - - + + - - - + + + - - + + - - - + + + - - + + - - + + - - - + + + - - - + + + - - + + - - - + + + @@ -25409,7 +25418,7 @@ - + @@ -25454,7 +25463,7 @@ - + @@ -25469,137 +25478,137 @@ - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - - + + + - + - + - + - + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - + + + - - + + diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index 0fbbee10c2edce..a9616bd6a4f518 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -22,6 +22,8 @@ PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, struct _P PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); +PyAPI_FUNC(int) _PyEval_MakePendingCalls(PyThreadState *); + PyAPI_FUNC(Py_ssize_t) PyUnstable_Eval_RequestCodeExtraIndex(freefunc); // Old name -- remove when this API changes: _Py_DEPRECATED_EXTERNALLY(3.12) static inline Py_ssize_t diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index ca2703781de4b0..9e9b523e7c2222 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -27,7 +27,8 @@ PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); PyAPI_FUNC(int) _PyEval_AddPendingCall( PyInterpreterState *interp, int (*func)(void *), - void *arg); + void *arg, + int mainthreadonly); PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *interp); #ifdef HAVE_FORK extern PyStatus _PyEval_ReInitThreads(PyThreadState *tstate); diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h index 95d1fa16ba40dc..e56e43c6e0c6a7 100644 --- a/Include/internal/pycore_ceval_state.h +++ b/Include/internal/pycore_ceval_state.h @@ -13,6 +13,24 @@ extern "C" { #include "pycore_gil.h" // struct _gil_runtime_state +struct _pending_calls { + int busy; + PyThread_type_lock lock; + /* Request for running pending calls. */ + _Py_atomic_int calls_to_do; + /* Request for looking at the `async_exc` field of the current + thread state. + Guarded by the GIL. */ + int async_exc; +#define NPENDINGCALLS 32 + struct _pending_call { + int (*func)(void *); + void *arg; + } calls[NPENDINGCALLS]; + int first; + int last; +}; + typedef enum { PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized @@ -49,6 +67,8 @@ struct _ceval_runtime_state { the main thread of the main interpreter can handle signals: see _Py_ThreadCanHandleSignals(). */ _Py_atomic_int signals_pending; + /* Pending calls to be made only on the main thread. */ + struct _pending_calls pending_mainthread; }; #ifdef PY_HAVE_PERF_TRAMPOLINE @@ -62,24 +82,6 @@ struct _ceval_runtime_state { #endif -struct _pending_calls { - int busy; - PyThread_type_lock lock; - /* Request for running pending calls. */ - _Py_atomic_int calls_to_do; - /* Request for looking at the `async_exc` field of the current - thread state. - Guarded by the GIL. */ - int async_exc; -#define NPENDINGCALLS 32 - struct { - int (*func)(void *); - void *arg; - } calls[NPENDINGCALLS]; - int first; - int last; -}; - struct _ceval_state { /* This single variable consolidates all requests to break out of the fast path in the eval loop. */ diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index daa40cf4bcd855..43652c4405ec1a 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -60,14 +60,6 @@ _Py_ThreadCanHandleSignals(PyInterpreterState *interp) } -/* Only execute pending calls on the main thread. */ -static inline int -_Py_ThreadCanHandlePendingCalls(void) -{ - return _Py_IsMainThread(); -} - - /* Variable and static inline functions for in-line access to current thread and interpreter state */ diff --git a/Lib/test/support/threading_helper.py b/Lib/test/support/threading_helper.py index b9973c8bf5c914..7f16050f32b9d1 100644 --- a/Lib/test/support/threading_helper.py +++ b/Lib/test/support/threading_helper.py @@ -115,7 +115,11 @@ def join_thread(thread, timeout=None): @contextlib.contextmanager def start_threads(threads, unlock=None): - import faulthandler + try: + import faulthandler + except ImportError: + # It isn't supported on subinterpreters yet. + faulthandler = None threads = list(threads) started = [] try: @@ -147,7 +151,8 @@ def start_threads(threads, unlock=None): finally: started = [t for t in started if t.is_alive()] if started: - faulthandler.dump_traceback(sys.stdout) + if faulthandler is not None: + faulthandler.dump_traceback(sys.stdout) raise AssertionError('Unable to join %d threads' % len(started)) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9cd1554614695e..61947cb7945193 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2,18 +2,21 @@ # these are all functions _testcapi exports whose name begins with 'test_'. import _thread -from collections import OrderedDict +from collections import OrderedDict, deque import contextlib import importlib.machinery import importlib.util +import json import os import pickle +import queue import random import subprocess import sys import textwrap import threading import time +import types import unittest import warnings import weakref @@ -37,6 +40,10 @@ import _testsinglephase except ImportError: _testsinglephase = None +try: + import _xxsubinterpreters as _interpreters +except ModuleNotFoundError: + _interpreters = None # Skip this test if the _testcapi module isn't available. _testcapi = import_helper.import_module('_testcapi') @@ -48,6 +55,12 @@ def decode_stderr(err): return err.decode('utf-8', 'replace').replace('\r', '') +def requires_subinterpreters(meth): + """Decorator to skip a test if subinterpreters are not supported.""" + return unittest.skipIf(_interpreters is None, + 'subinterpreters required')(meth) + + def testfunction(self): """some doc""" return self @@ -1260,6 +1273,10 @@ def test_pyobject_getitemdata_error(self): class TestPendingCalls(unittest.TestCase): + # See the comment in ceval.c (at the "handle_eval_breaker" label) + # about when pending calls get run. This is especially relevant + # here for creating deterministic tests. + def pendingcalls_submit(self, l, n): def callback(): #this function can be interrupted by thread switching so let's @@ -1342,6 +1359,390 @@ def genf(): yield gen = genf() self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code) + class PendingTask(types.SimpleNamespace): + + _add_pending = _testinternalcapi.pending_threadfunc + + def __init__(self, req, taskid=None, notify_done=None): + self.id = taskid + self.req = req + self.notify_done = notify_done + + self.creator_tid = threading.get_ident() + self.requester_tid = None + self.runner_tid = None + self.result = None + + def run(self): + assert self.result is None + self.runner_tid = threading.get_ident() + self._run() + if self.notify_done is not None: + self.notify_done() + + def _run(self): + self.result = self.req + + def run_in_pending_call(self, worker_tids): + assert self._add_pending is _testinternalcapi.pending_threadfunc + self.requester_tid = threading.get_ident() + def callback(): + assert self.result is None + # It can be tricky to control which thread handles + # the eval breaker, so we take a naive approach to + # make sure. + if threading.get_ident() not in worker_tids: + self._add_pending(callback, ensure_added=True) + return + self.run() + self._add_pending(callback, ensure_added=True) + + def create_thread(self, worker_tids): + return threading.Thread( + target=self.run_in_pending_call, + args=(worker_tids,), + ) + + def wait_for_result(self): + while self.result is None: + time.sleep(0.01) + + @threading_helper.requires_working_threading() + def test_subthreads_can_handle_pending_calls(self): + payload = 'Spam spam spam spam. Lovely spam! Wonderful spam!' + + task = self.PendingTask(payload) + def do_the_work(): + tid = threading.get_ident() + t = task.create_thread({tid}) + with threading_helper.start_threads([t]): + task.wait_for_result() + t = threading.Thread(target=do_the_work) + with threading_helper.start_threads([t]): + pass + + self.assertEqual(task.result, payload) + + @threading_helper.requires_working_threading() + def test_many_subthreads_can_handle_pending_calls(self): + main_tid = threading.get_ident() + self.assertEqual(threading.main_thread().ident, main_tid) + + # We can't use queue.Queue since it isn't reentrant relative + # to pending calls. + _queue = deque() + _active = deque() + _done_lock = threading.Lock() + def queue_put(task): + _queue.append(task) + _active.append(True) + def queue_get(): + try: + task = _queue.popleft() + except IndexError: + raise queue.Empty + return task + def queue_task_done(): + _active.pop() + if not _active: + try: + _done_lock.release() + except RuntimeError: + assert not _done_lock.locked() + def queue_empty(): + return not _queue + def queue_join(): + _done_lock.acquire() + _done_lock.release() + + tasks = [] + for i in range(20): + task = self.PendingTask( + req=f'request {i}', + taskid=i, + notify_done=queue_task_done, + ) + tasks.append(task) + queue_put(task) + # This will be released once all the tasks have finished. + _done_lock.acquire() + + def add_tasks(worker_tids): + while True: + if done: + return + try: + task = queue_get() + except queue.Empty: + break + task.run_in_pending_call(worker_tids) + + done = False + def run_tasks(): + while not queue_empty(): + if done: + return + time.sleep(0.01) + # Give the worker a chance to handle any remaining pending calls. + while not done: + time.sleep(0.01) + + # Start the workers and wait for them to finish. + worker_threads = [threading.Thread(target=run_tasks) + for _ in range(3)] + with threading_helper.start_threads(worker_threads): + try: + # Add a pending call for each task. + worker_tids = [t.ident for t in worker_threads] + threads = [threading.Thread(target=add_tasks, args=(worker_tids,)) + for _ in range(3)] + with threading_helper.start_threads(threads): + try: + pass + except BaseException: + done = True + raise # re-raise + # Wait for the pending calls to finish. + queue_join() + # Notify the workers that they can stop. + done = True + except BaseException: + done = True + raise # re-raise + runner_tids = [t.runner_tid for t in tasks] + + self.assertNotIn(main_tid, runner_tids) + for task in tasks: + with self.subTest(f'task {task.id}'): + self.assertNotEqual(task.requester_tid, main_tid) + self.assertNotEqual(task.requester_tid, task.runner_tid) + self.assertNotIn(task.requester_tid, runner_tids) + + @requires_subinterpreters + def test_isolated_subinterpreter(self): + # We exercise the most important permutations. + + # This test relies on pending calls getting called + # (eval breaker tripped) at each loop iteration + # and at each call. + + maxtext = 250 + main_interpid = 0 + interpid = _interpreters.create() + _interpreters.run_string(interpid, f"""if True: + import json + import os + import threading + import time + import _testinternalcapi + from test.support import threading_helper + """) + + def create_pipe(): + r, w = os.pipe() + self.addCleanup(lambda: os.close(r)) + self.addCleanup(lambda: os.close(w)) + return r, w + + with self.subTest('add in main, run in subinterpreter'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + timeout = time.time() + 30 # seconds + + def do_work(): + _interpreters.run_string(interpid, f"""if True: + # Wait until this interp has handled the pending call. + waiting = False + done = False + def wait(os_read=os.read): + global done, waiting + waiting = True + os_read({r_done}, 1) + done = True + t = threading.Thread(target=wait) + with threading_helper.start_threads([t]): + while not waiting: + pass + os.write({w_ready}, b'\\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > {timeout}: + raise Exception('timed out!') + """) + t = threading.Thread(target=do_work) + with threading_helper.start_threads([t]): + os.read(r_ready, 1) + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify(interpid) + # Signal the subinterpreter to stop. + os.write(w_done, b'\0') + + self.assertEqual(actual, int(interpid)) + + with self.subTest('add in main, run in subinterpreter sub-thread'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + timeout = time.time() + 30 # seconds + + def do_work(): + _interpreters.run_string(interpid, f"""if True: + waiting = False + done = False + def subthread(): + while not waiting: + pass + os.write({w_ready}, b'\\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > {timeout}: + raise Exception('timed out!') + t = threading.Thread(target=subthread) + with threading_helper.start_threads([t]): + # Wait until this interp has handled the pending call. + waiting = True + os.read({r_done}, 1) + done = True + """) + t = threading.Thread(target=do_work) + with threading_helper.start_threads([t]): + os.read(r_ready, 1) + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify(interpid) + # Signal the subinterpreter to stop. + os.write(w_done, b'\0') + + self.assertEqual(actual, int(interpid)) + + with self.subTest('add in subinterpreter, run in main'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + r_data, w_data= create_pipe() + timeout = time.time() + 30 # seconds + + def add_job(): + os.read(r_ready, 1) + _interpreters.run_string(interpid, f"""if True: + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify({main_interpid}) + # Signal the subinterpreter to stop. + os.write({w_done}, b'\\0') + os.write({w_data}, actual.to_bytes(1, 'little')) + """) + # Wait until this interp has handled the pending call. + waiting = False + done = False + def wait(os_read=os.read): + nonlocal done, waiting + waiting = True + os_read(r_done, 1) + done = True + t1 = threading.Thread(target=add_job) + t2 = threading.Thread(target=wait) + with threading_helper.start_threads([t1, t2]): + while not waiting: + pass + os.write(w_ready, b'\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > timeout: + raise Exception('timed out!') + text = os.read(r_data, 1) + actual = int.from_bytes(text, 'little') + + self.assertEqual(actual, int(main_interpid)) + + with self.subTest('add in subinterpreter, run in sub-thread'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + r_data, w_data= create_pipe() + timeout = time.time() + 30 # seconds + + def add_job(): + os.read(r_ready, 1) + _interpreters.run_string(interpid, f"""if True: + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify({main_interpid}) + # Signal the subinterpreter to stop. + os.write({w_done}, b'\\0') + os.write({w_data}, actual.to_bytes(1, 'little')) + """) + # Wait until this interp has handled the pending call. + waiting = False + done = False + def wait(os_read=os.read): + nonlocal done, waiting + waiting = True + os_read(r_done, 1) + done = True + def subthread(): + while not waiting: + pass + os.write(w_ready, b'\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > timeout: + raise Exception('timed out!') + t1 = threading.Thread(target=add_job) + t2 = threading.Thread(target=wait) + t3 = threading.Thread(target=subthread) + with threading_helper.start_threads([t1, t2, t3]): + pass + text = os.read(r_data, 1) + actual = int.from_bytes(text, 'little') + + self.assertEqual(actual, int(main_interpid)) + + # XXX We can't use the rest until gh-105716 is fixed. + return + + with self.subTest('add in subinterpreter, run in subinterpreter sub-thread'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + r_data, w_data= create_pipe() + timeout = time.time() + 30 # seconds + + def do_work(): + _interpreters.run_string(interpid, f"""if True: + waiting = False + done = False + def subthread(): + while not waiting: + pass + os.write({w_ready}, b'\\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > {timeout}: + raise Exception('timed out!') + t = threading.Thread(target=subthread) + with threading_helper.start_threads([t]): + # Wait until this interp has handled the pending call. + waiting = True + os.read({r_done}, 1) + done = True + """) + t = threading.Thread(target=do_work) + #with threading_helper.start_threads([t]): + t.start() + if True: + os.read(r_ready, 1) + _interpreters.run_string(interpid, f"""if True: + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify({interpid}) + # Signal the subinterpreter to stop. + os.write({w_done}, b'\\0') + os.write({w_data}, actual.to_bytes(1, 'little')) + """) + t.join() + text = os.read(r_data, 1) + actual = int.from_bytes(text, 'little') + + self.assertEqual(actual, int(interpid)) + class SubinterpreterTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst new file mode 100644 index 00000000000000..da29a8cae61839 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst @@ -0,0 +1,9 @@ +The "pending call" machinery now works for all interpreters, not just the +main interpreter, and runs in all threads, not just the main thread. Some +calls are still only done in the main thread, ergo in the main interpreter. +This change does not affect signal handling nor the existing public C-API +(``Py_AddPendingCall()``), which both still only target the main thread. +The new functionality is meant strictly for internal use for now, since +consequences of its use are not well understood yet outside some very +restricted cases. This change brings the capability in line with the +intention when the state was made per-interpreter several years ago. diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index d36a911a57c02c..db5be842b8a35c 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -210,6 +210,7 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls, PyObject *item; PyLockStatus r; PY_TIMEOUT_T microseconds; + PyThreadState *tstate = PyThreadState_Get(); if (block == 0) { /* Non-blocking */ @@ -253,7 +254,7 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls, Py_END_ALLOW_THREADS } - if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) { + if (r == PY_LOCK_INTR && _PyEval_MakePendingCalls(tstate) < 0) { return NULL; } if (r == PY_LOCK_FAILURE) { diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 8267dbf6779017..7e2def7c20b1bb 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -16,13 +16,15 @@ #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble +#include "pycore_ceval.h" // _PyEval_AddPendingCall #include "pycore_fileutils.h" // _Py_normpath #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_gc.h" // PyGC_Head #include "pycore_hashtable.h" // _Py_hashtable_new() #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() -#include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() #include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy() +#include "pycore_interpreteridobject.h" // _PyInterpreterID_LookUp() +#include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() #include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost() #include "pycore_pystate.h" // _PyThreadState_GET() #include "osdefs.h" // MAXPATHLEN @@ -822,6 +824,120 @@ iframe_getlasti(PyObject *self, PyObject *frame) return PyLong_FromLong(PyUnstable_InterpreterFrame_GetLasti(f)); } + +static int _pending_callback(void *arg) +{ + /* we assume the argument is callable object to which we own a reference */ + PyObject *callable = (PyObject *)arg; + PyObject *r = PyObject_CallNoArgs(callable); + Py_DECREF(callable); + Py_XDECREF(r); + return r != NULL ? 0 : -1; +} + +/* The following requests n callbacks to _pending_callback. It can be + * run from any python thread. + */ +static PyObject * +pending_threadfunc(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *callable; + int ensure_added = 0; + static char *kwlist[] = {"", "ensure_added", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|$p:pending_threadfunc", kwlist, + &callable, &ensure_added)) + { + return NULL; + } + PyInterpreterState *interp = PyInterpreterState_Get(); + + /* create the reference for the callbackwhile we hold the lock */ + Py_INCREF(callable); + + int r; + Py_BEGIN_ALLOW_THREADS + r = _PyEval_AddPendingCall(interp, &_pending_callback, callable, 0); + Py_END_ALLOW_THREADS + if (r < 0) { + /* unsuccessful add */ + if (!ensure_added) { + Py_DECREF(callable); + Py_RETURN_FALSE; + } + do { + Py_BEGIN_ALLOW_THREADS + r = _PyEval_AddPendingCall(interp, &_pending_callback, callable, 0); + Py_END_ALLOW_THREADS + } while (r < 0); + } + + Py_RETURN_TRUE; +} + + +static struct { + int64_t interpid; +} pending_identify_result; + +static int +_pending_identify_callback(void *arg) +{ + PyThread_type_lock mutex = (PyThread_type_lock)arg; + assert(pending_identify_result.interpid == -1); + PyThreadState *tstate = PyThreadState_Get(); + pending_identify_result.interpid = PyInterpreterState_GetID(tstate->interp); + PyThread_release_lock(mutex); + return 0; +} + +static PyObject * +pending_identify(PyObject *self, PyObject *args) +{ + PyObject *interpid; + if (!PyArg_ParseTuple(args, "O:pending_identify", &interpid)) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterID_LookUp(interpid); + if (interp == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "interpreter not found"); + } + return NULL; + } + + pending_identify_result.interpid = -1; + + PyThread_type_lock mutex = PyThread_allocate_lock(); + if (mutex == NULL) { + return NULL; + } + PyThread_acquire_lock(mutex, WAIT_LOCK); + /* It gets released in _pending_identify_callback(). */ + + int r; + do { + Py_BEGIN_ALLOW_THREADS + r = _PyEval_AddPendingCall(interp, + &_pending_identify_callback, (void *)mutex, + 0); + Py_END_ALLOW_THREADS + } while (r < 0); + + /* Wait for the pending call to complete. */ + PyThread_acquire_lock(mutex, WAIT_LOCK); + PyThread_release_lock(mutex); + PyThread_free_lock(mutex); + + PyObject *res = PyLong_FromLongLong(pending_identify_result.interpid); + pending_identify_result.interpid = -1; + if (res == NULL) { + return NULL; + } + return res; +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -850,6 +966,9 @@ static PyMethodDef module_functions[] = { {"iframe_getcode", iframe_getcode, METH_O, NULL}, {"iframe_getline", iframe_getline, METH_O, NULL}, {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, + {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), + METH_VARARGS | METH_KEYWORDS}, + {"pending_identify", pending_identify, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index b6f878e07526db..c553d039462af0 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -81,6 +81,7 @@ lock_dealloc(lockobject *self) static PyLockStatus acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) { + PyThreadState *tstate = _PyThreadState_GET(); _PyTime_t endtime = 0; if (timeout > 0) { endtime = _PyDeadline_Init(timeout); @@ -103,7 +104,7 @@ acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) /* Run signal handlers if we were interrupted. Propagate * exceptions from signal handlers, such as KeyboardInterrupt, by * passing up PY_LOCK_INTR. */ - if (Py_MakePendingCalls() < 0) { + if (_PyEval_MakePendingCalls(tstate) < 0) { return PY_LOCK_INTR; } diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 2350236ad46b25..00ea4343735dab 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -314,7 +314,8 @@ trip_signal(int sig_num) still use it for this exceptional case. */ _PyEval_AddPendingCall(interp, report_wakeup_send_error, - (void *)(intptr_t) last_error); + (void *)(intptr_t) last_error, + 1); } } } @@ -333,7 +334,8 @@ trip_signal(int sig_num) still use it for this exceptional case. */ _PyEval_AddPendingCall(interp, report_wakeup_write_error, - (void *)(intptr_t)errno); + (void *)(intptr_t)errno, + 1); } } } diff --git a/Python/ceval.c b/Python/ceval.c index df997e1ed283d7..4762dfac4812a6 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -758,6 +758,61 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int * We need to do reasonably frequently, but not too frequently. * All loops should include a check of the eval breaker. * We also check on return from any builtin function. + * + * ## More Details ### + * + * The eval loop (this function) normally executes the instructions + * of a code object sequentially. However, the runtime supports a + * number of out-of-band execution scenarios that may pause that + * sequential execution long enough to do that out-of-band work + * in the current thread using the current PyThreadState. + * + * The scenarios include: + * + * - cyclic garbage collection + * - GIL drop requests + * - "async" exceptions + * - "pending calls" (some only in the main thread) + * - signal handling (only in the main thread) + * + * When the need for one of the above is detected, the eval loop + * pauses long enough to handle the detected case. Then, if doing + * so didn't trigger an exception, the eval loop resumes executing + * the sequential instructions. + * + * To make this work, the eval loop periodically checks if any + * of the above needs to happen. The individual checks can be + * expensive if computed each time, so a while back we switched + * to using pre-computed, per-interpreter variables for the checks, + * and later consolidated that to a single "eval breaker" variable + * (now a PyInterpreterState field). + * + * For the longest time, the eval breaker check would happen + * frequently, every 5 or so times through the loop, regardless + * of what instruction ran last or what would run next. Then, in + * early 2021 (gh-18334, commit 4958f5d), we switched to checking + * the eval breaker less frequently, by hard-coding the check to + * specific places in the eval loop (e.g. certain instructions). + * The intent then was to check after returning from calls + * and on the back edges of loops. + * + * In addition to being more efficient, that approach keeps + * the eval loop from running arbitrary code between instructions + * that don't handle that well. (See gh-74174.) + * + * Currently, the eval breaker check happens here at the + * "handle_eval_breaker" label. Some instructions come here + * explicitly (goto) and some indirectly. Notably, the check + * happens on back edges in the control flow graph, which + * pretty much applies to all loops and most calls. + * (See bytecodes.c for exact information.) + * + * One consequence of this approach is that it might not be obvious + * how to force any specific thread to pick up the eval breaker, + * or for any specific thread to not pick it up. Mostly this + * involves judicious uses of locks and careful ordering of code, + * while avoiding code that might trigger the eval breaker + * until so desired. */ if (_Py_HandlePending(tstate) != 0) { goto error; diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 764278ac130dfa..aacf2b5c2e2c4f 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -68,8 +68,9 @@ COMPUTE_EVAL_BREAKER(PyInterpreterState *interp, _Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request) | (_Py_atomic_load_relaxed_int32(&ceval->signals_pending) && _Py_ThreadCanHandleSignals(interp)) - | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do) - && _Py_ThreadCanHandlePendingCalls()) + | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do)) + | (_Py_IsMainThread() && _Py_IsMainInterpreter(interp) + &&_Py_atomic_load_relaxed_int32(&ceval->pending_mainthread.calls_to_do)) | ceval2->pending.async_exc | _Py_atomic_load_relaxed_int32(&ceval2->gc_scheduled)); } @@ -95,11 +96,11 @@ RESET_GIL_DROP_REQUEST(PyInterpreterState *interp) static inline void -SIGNAL_PENDING_CALLS(PyInterpreterState *interp) +SIGNAL_PENDING_CALLS(struct _pending_calls *pending, PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 1); + _Py_atomic_store_relaxed(&pending->calls_to_do, 1); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } @@ -109,6 +110,9 @@ UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; + if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) { + _Py_atomic_store_relaxed(&ceval->pending_mainthread.calls_to_do, 0); + } _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 0); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } @@ -798,19 +802,31 @@ _push_pending_call(struct _pending_calls *pending, return 0; } -/* Pop one item off the queue while holding the lock. */ -static void -_pop_pending_call(struct _pending_calls *pending, - int (**func)(void *), void **arg) +static int +_next_pending_call(struct _pending_calls *pending, + int (**func)(void *), void **arg) { int i = pending->first; if (i == pending->last) { - return; /* Queue empty */ + /* Queue empty */ + assert(pending->calls[i].func == NULL); + return -1; } - *func = pending->calls[i].func; *arg = pending->calls[i].arg; - pending->first = (i + 1) % NPENDINGCALLS; + return i; +} + +/* Pop one item off the queue while holding the lock. */ +static void +_pop_pending_call(struct _pending_calls *pending, + int (**func)(void *), void **arg) +{ + int i = _next_pending_call(pending, func, arg); + if (i >= 0) { + pending->calls[i] = (struct _pending_call){0}; + pending->first = (i + 1) % NPENDINGCALLS; + } } /* This implementation is thread-safe. It allows @@ -820,9 +836,16 @@ _pop_pending_call(struct _pending_calls *pending, int _PyEval_AddPendingCall(PyInterpreterState *interp, - int (*func)(void *), void *arg) + int (*func)(void *), void *arg, + int mainthreadonly) { + assert(!mainthreadonly || _Py_IsMainInterpreter(interp)); struct _pending_calls *pending = &interp->ceval.pending; + if (mainthreadonly) { + /* The main thread only exists in the main interpreter. */ + assert(_Py_IsMainInterpreter(interp)); + pending = &_PyRuntime.ceval.pending_mainthread; + } /* Ensure that _PyEval_InitState() was called and that _PyEval_FiniState() is not called yet. */ assert(pending->lock != NULL); @@ -832,39 +855,17 @@ _PyEval_AddPendingCall(PyInterpreterState *interp, PyThread_release_lock(pending->lock); /* signal main loop */ - SIGNAL_PENDING_CALLS(interp); + SIGNAL_PENDING_CALLS(pending, interp); return result; } int Py_AddPendingCall(int (*func)(void *), void *arg) { - /* Best-effort to support subinterpreters and calls with the GIL released. - - First attempt _PyThreadState_GET() since it supports subinterpreters. - - If the GIL is released, _PyThreadState_GET() returns NULL . In this - case, use PyGILState_GetThisThreadState() which works even if the GIL - is released. - - Sadly, PyGILState_GetThisThreadState() doesn't support subinterpreters: - see bpo-10915 and bpo-15751. - - Py_AddPendingCall() doesn't require the caller to hold the GIL. */ - PyThreadState *tstate = _PyThreadState_GET(); - if (tstate == NULL) { - tstate = PyGILState_GetThisThreadState(); - } - - PyInterpreterState *interp; - if (tstate != NULL) { - interp = tstate->interp; - } - else { - /* Last resort: use the main interpreter */ - interp = _PyInterpreterState_Main(); - } - return _PyEval_AddPendingCall(interp, func, arg); + /* Legacy users of this API will continue to target the main thread + (of the main interpreter). */ + PyInterpreterState *interp = _PyInterpreterState_Main(); + return _PyEval_AddPendingCall(interp, func, arg, 1); } static int @@ -884,27 +885,24 @@ handle_signals(PyThreadState *tstate) return 0; } -static int -make_pending_calls(PyInterpreterState *interp) +static inline int +maybe_has_pending_calls(PyInterpreterState *interp) { - /* only execute pending calls on main thread */ - if (!_Py_ThreadCanHandlePendingCalls()) { - return 0; + struct _pending_calls *pending = &interp->ceval.pending; + if (_Py_atomic_load_relaxed_int32(&pending->calls_to_do)) { + return 1; } - - /* don't perform recursive pending calls */ - if (interp->ceval.pending.busy) { + if (!_Py_IsMainThread() || !_Py_IsMainInterpreter(interp)) { return 0; } - interp->ceval.pending.busy = 1; - - /* unsignal before starting to call callbacks, so that any callback - added in-between re-signals */ - UNSIGNAL_PENDING_CALLS(interp); - int res = 0; + pending = &_PyRuntime.ceval.pending_mainthread; + return _Py_atomic_load_relaxed_int32(&pending->calls_to_do); +} +static int +_make_pending_calls(struct _pending_calls *pending) +{ /* perform a bounded number of calls, in case of recursion */ - struct _pending_calls *pending = &interp->ceval.pending; for (int i=0; iceval.pending; + struct _pending_calls *pending_main = &_PyRuntime.ceval.pending_mainthread; + + /* Only one thread (per interpreter) may run the pending calls + at once. In the same way, we don't do recursive pending calls. */ + PyThread_acquire_lock(pending->lock, WAIT_LOCK); + if (pending->busy) { + /* A pending call was added after another thread was already + handling the pending calls (and had already "unsignaled"). + Once that thread is done, it may have taken care of all the + pending calls, or there might be some still waiting. + Regardless, this interpreter's pending calls will stay + "signaled" until that first thread has finished. At that + point the next thread to trip the eval breaker will take + care of any remaining pending calls. Until then, though, + all the interpreter's threads will be tripping the eval + breaker every time it's checked. */ + PyThread_release_lock(pending->lock); + return 0; + } + pending->busy = 1; + PyThread_release_lock(pending->lock); + + /* unsignal before starting to call callbacks, so that any callback + added in-between re-signals */ + UNSIGNAL_PENDING_CALLS(interp); + + if (_make_pending_calls(pending) != 0) { + pending->busy = 0; + /* There might not be more calls to make, but we play it safe. */ + SIGNAL_PENDING_CALLS(pending, interp); + return -1; + } - interp->ceval.pending.busy = 0; - return res; + if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) { + if (_make_pending_calls(pending_main) != 0) { + pending->busy = 0; + /* There might not be more calls to make, but we play it safe. */ + SIGNAL_PENDING_CALLS(pending_main, interp); + return -1; + } + } -error: - interp->ceval.pending.busy = 0; - SIGNAL_PENDING_CALLS(interp); - return res; + pending->busy = 0; + return 0; } void @@ -939,12 +979,6 @@ _Py_FinishPendingCalls(PyThreadState *tstate) assert(PyGILState_Check()); assert(is_tstate_valid(tstate)); - struct _pending_calls *pending = &tstate->interp->ceval.pending; - - if (!_Py_atomic_load_relaxed_int32(&(pending->calls_to_do))) { - return; - } - if (make_pending_calls(tstate->interp) < 0) { PyObject *exc = _PyErr_GetRaisedException(tstate); PyErr_BadInternalCall(); @@ -953,6 +987,29 @@ _Py_FinishPendingCalls(PyThreadState *tstate) } } +int +_PyEval_MakePendingCalls(PyThreadState *tstate) +{ + int res; + + if (_Py_IsMainThread() && _Py_IsMainInterpreter(tstate->interp)) { + /* Python signal handler doesn't really queue a callback: + it only signals that a signal was received, + see _PyEval_SignalReceived(). */ + res = handle_signals(tstate); + if (res != 0) { + return res; + } + } + + res = make_pending_calls(tstate->interp); + if (res != 0) { + return res; + } + + return 0; +} + /* Py_MakePendingCalls() is a simple wrapper for the sake of backward-compatibility. */ int @@ -963,19 +1020,11 @@ Py_MakePendingCalls(void) PyThreadState *tstate = _PyThreadState_GET(); assert(is_tstate_valid(tstate)); - /* Python signal handler doesn't really queue a callback: it only signals - that a signal was received, see _PyEval_SignalReceived(). */ - int res = handle_signals(tstate); - if (res != 0) { - return res; - } - - res = make_pending_calls(tstate->interp); - if (res != 0) { - return res; + /* Only execute pending calls on the main thread. */ + if (!_Py_IsMainThread() || !_Py_IsMainInterpreter(tstate->interp)) { + return 0; } - - return 0; + return _PyEval_MakePendingCalls(tstate); } void @@ -1015,7 +1064,7 @@ _Py_HandlePending(PyThreadState *tstate) } /* Pending calls */ - if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->pending.calls_to_do)) { + if (maybe_has_pending_calls(tstate->interp)) { if (make_pending_calls(tstate->interp) != 0) { return -1; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index c4e6b69d8d56f3..a67fa26b372278 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2152,6 +2152,9 @@ Py_EndInterpreter(PyThreadState *tstate) // Wrap up existing "threading"-module-created, non-daemon threads. wait_for_thread_shutdown(tstate); + // Make any remaining pending calls. + _Py_FinishPendingCalls(tstate); + _PyAtExit_Call(tstate->interp); if (tstate != interp->threads.head || tstate->next != NULL) { diff --git a/Python/pystate.c b/Python/pystate.c index d63a873a5c3025..da0e1c42d7275f 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -380,7 +380,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP -#define NUMLOCKS 8 +#define NUMLOCKS 9 #define LOCKS_INIT(runtime) \ { \ &(runtime)->interpreters.mutex, \ @@ -388,6 +388,7 @@ _Py_COMP_DIAG_POP &(runtime)->getargs.mutex, \ &(runtime)->unicode_state.ids.lock, \ &(runtime)->imports.extensions.mutex, \ + &(runtime)->ceval.pending_mainthread.lock, \ &(runtime)->atexit.mutex, \ &(runtime)->audit_hooks.mutex, \ &(runtime)->allocators.mutex, \ diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 4c40a04a6854bf..b6745b6aeb0b61 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -517,6 +517,7 @@ Modules/_testcapimodule.c - g_type_watchers_installed - Modules/_testimportmultiple.c - _barmodule - Modules/_testimportmultiple.c - _foomodule - Modules/_testimportmultiple.c - _testimportmultiple - +Modules/_testinternalcapi.c - pending_identify_result - Modules/_testmultiphase.c - Example_Type_slots - Modules/_testmultiphase.c - Example_Type_spec - Modules/_testmultiphase.c - Example_methods - From 26bc2cc06128890ac89492eca20e83abe0789c1c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 18:05:01 -0700 Subject: [PATCH 0210/1206] [3.12] gh-105387: Limited C API implements Py_INCREF() as func (GH-105388) (#105763) gh-105387: Limited C API implements Py_INCREF() as func (GH-105388) In the limited C API version 3.12, Py_INCREF() and Py_DECREF() functions are now implemented as opaque function calls to hide implementation details. (cherry picked from commit b542972dc133973a7f0517aa1b61779271789111) Co-authored-by: Victor Stinner --- Doc/whatsnew/3.12.rst | 5 +++++ Include/object.h | 18 ++++++++++-------- ...3-06-09-12-35-55.gh-issue-105387.wM_oL-.rst | 3 +++ 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4849f8c3e281f9..28bd4a8a64ee4b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1693,6 +1693,11 @@ New Features (Contributed by Eddie Elizondo in :gh:`84436`.) +* In the limited C API version 3.12, :c:func:`Py_INCREF` and + :c:func:`Py_DECREF` functions are now implemented as opaque function calls to + hide implementation details. + (Contributed by Victor Stinner in :gh:`105387`.) + Porting to Python 3.12 ---------------------- diff --git a/Include/object.h b/Include/object.h index ad16b72cd42474..3ef64511399c66 100644 --- a/Include/object.h +++ b/Include/object.h @@ -610,10 +610,11 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *); static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) { -#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) - // Stable ABI for Python built in debug mode. _Py_IncRef() was added to - // Python 3.10.0a7, use Py_IncRef() on older Python versions. Py_IncRef() - // accepts NULL whereas _Py_IncRef() doesn't. +#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG)) + // Stable ABI implements Py_INCREF() as a function call on limited C API + // version 3.12 and newer, and on Python built in debug mode. _Py_IncRef() + // was added to Python 3.10.0a7, use Py_IncRef() on older Python versions. + // Py_IncRef() accepts NULL whereas _Py_IncRef() doesn't. # if Py_LIMITED_API+0 >= 0x030a00A7 _Py_IncRef(op); # else @@ -647,10 +648,11 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) # define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op)) #endif -#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) -// Stable ABI for Python built in debug mode. _Py_DecRef() was added to Python -// 3.10.0a7, use Py_DecRef() on older Python versions. Py_DecRef() accepts NULL -// whereas _Py_IncRef() doesn't. +#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG)) +// Stable ABI implements Py_DECREF() as a function call on limited C API +// version 3.12 and newer, and on Python built in debug mode. _Py_DecRef() was +// added to Python 3.10.0a7, use Py_DecRef() on older Python versions. +// Py_DecRef() accepts NULL whereas _Py_IncRef() doesn't. static inline void Py_DECREF(PyObject *op) { # if Py_LIMITED_API+0 >= 0x030a00A7 _Py_DecRef(op); diff --git a/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst b/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst new file mode 100644 index 00000000000000..d7ee7d2eb9d908 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst @@ -0,0 +1,3 @@ +In the limited C API version 3.12, :c:func:`Py_INCREF` and +:c:func:`Py_DECREF` functions are now implemented as opaque function calls +to hide implementation details. Patch by Victor Stinner. From bc997b38b66cd61ab2ba9697546c39472cb93ee3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 18:34:26 -0700 Subject: [PATCH 0211/1206] [3.12] gh-105699: Use a Thread-Local Variable for PKGCONTEXT (gh-105740) (gh-105765) This fixes a race during import. The existing _PyRuntimeState.imports.pkgcontext is shared between interpreters, and occasionally this would cause a crash when multiple interpreters were importing extensions modules at the same time. To solve this we add a thread-local variable for the value. We also leave the existing state (and infrequent race) in place for platforms that do not support thread-local variables. (cherry picked from commit b87d2882754a7c273e2695c33384383eba380d7d) Co-authored-by: Eric Snow --- Python/import.c | 15 +++++++++++++++ Tools/c-analyzer/c_parser/parser/_regexes.py | 3 ++- Tools/c-analyzer/c_parser/preprocessor/gcc.py | 1 + Tools/c-analyzer/cpython/ignored.tsv | 6 ++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Python/import.c b/Python/import.c index 9e1857d5f3e4e6..24723d64bd0c2a 100644 --- a/Python/import.c +++ b/Python/import.c @@ -703,10 +703,19 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) _PyRuntime.imports.pkgcontext, and PyModule_Create*() will substitute this (if the name actually matches). */ + +#ifdef HAVE_THREAD_LOCAL +_Py_thread_local const char *pkgcontext = NULL; +# undef PKGCONTEXT +# define PKGCONTEXT pkgcontext +#endif + const char * _PyImport_ResolveNameWithPackageContext(const char *name) { +#ifndef HAVE_THREAD_LOCAL PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); +#endif if (PKGCONTEXT != NULL) { const char *p = strrchr(PKGCONTEXT, '.'); if (p != NULL && strcmp(name, p+1) == 0) { @@ -714,17 +723,23 @@ _PyImport_ResolveNameWithPackageContext(const char *name) PKGCONTEXT = NULL; } } +#ifndef HAVE_THREAD_LOCAL PyThread_release_lock(EXTENSIONS.mutex); +#endif return name; } const char * _PyImport_SwapPackageContext(const char *newcontext) { +#ifndef HAVE_THREAD_LOCAL PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); +#endif const char *oldcontext = PKGCONTEXT; PKGCONTEXT = newcontext; +#ifndef HAVE_THREAD_LOCAL PyThread_release_lock(EXTENSIONS.mutex); +#endif return oldcontext; } diff --git a/Tools/c-analyzer/c_parser/parser/_regexes.py b/Tools/c-analyzer/c_parser/parser/_regexes.py index b7f22b186f4965..5695daff67d6bd 100644 --- a/Tools/c-analyzer/c_parser/parser/_regexes.py +++ b/Tools/c-analyzer/c_parser/parser/_regexes.py @@ -58,6 +58,7 @@ def _ind(text, level=1, edges='both'): extern | register | static | + _Thread_local | typedef | const | @@ -137,7 +138,7 @@ def _ind(text, level=1, edges='both'): ####################################### # variable declarations -_STORAGE = 'auto register static extern'.split() +_STORAGE = 'auto register static extern _Thread_local'.split() STORAGE_CLASS = rf'(?: \b (?: {" | ".join(_STORAGE)} ) \b )' TYPE_QUALIFIER = r'(?: \b (?: const | volatile ) \b )' PTR_QUALIFIER = rf'(?: [*] (?: \s* {TYPE_QUALIFIER} )? )' diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index c680f351f22416..147615707a3cb8 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -219,6 +219,7 @@ def _strip_directives(line, partial=0): line = line[m.end():] line = re.sub(r'__extension__', '', line) + line = re.sub(r'__thread\b', '_Thread_local', line) while (m := COMPILER_DIRECTIVE_RE.match(line)): before, _, _, closed = m.groups() diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index b6745b6aeb0b61..afc28e551813b4 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -168,6 +168,12 @@ Modules/_xxinterpchannelsmodule.c - _globals - Python/pyfpe.c - PyFPE_counter - +##----------------------- +## thread-local variables + +Python/import.c - pkgcontext - +Python/pystate.c - _Py_tss_tstate - + ##----------------------- ## should be const # XXX Make them const. From 0a9346d3d8b52e585a43ee6c7708e5a639fa9fed Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 13 Jun 2023 22:04:22 -0700 Subject: [PATCH 0212/1206] [3.12] gh-105587: Remove assertion from `_PyStaticObject_CheckRefcnt` (GH-105638) (#105769) gh-105587: Remove assertion from `_PyStaticObject_CheckRefcnt` (GH-105638) (cherry picked from commit 6199fe3b3236748033a7ce2559aeddb5a91bbbd9) Co-authored-by: Eddie Elizondo --- Include/internal/pycore_global_objects_fini_generated.h | 5 ++--- .../2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index d5819fcd1c5038..439f47a263dfa1 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -12,9 +12,8 @@ extern "C" { static inline void _PyStaticObject_CheckRefcnt(PyObject *obj) { if (Py_REFCNT(obj) < _Py_IMMORTAL_REFCNT) { - _PyObject_ASSERT_FAILED_MSG(obj, - "immortal object has less refcnt than expected " - "_Py_IMMORTAL_REFCNT"); + fprintf(stderr, "Immortal Object has less refcnt than expected.\n"); + _PyObject_Dump(obj); } } #endif diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst new file mode 100644 index 00000000000000..488f82c3fb574c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst @@ -0,0 +1,3 @@ +The runtime can't guarantee that immortal objects will not be mutated by +Extensions. Thus, this modifies _PyStaticObject_CheckRefcnt to warn +instead of asserting. From ad7371e407fa0474a152b4a607bea127a257ff85 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 14 Jun 2023 05:26:33 -0700 Subject: [PATCH 0213/1206] [3.12] gh-105745: Fix open method of webbrowser.Konqueror (GH-105746) (#105777) gh-105745: Fix open method of webbrowser.Konqueror (GH-105746) (cherry picked from commit e5d45b7444733861153d6e8959c34323fd361322) Co-authored-by: Nikita Sobolev --- Lib/webbrowser.py | 9 --------- .../2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst | 1 + 2 files changed, 1 insertion(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index b86d131f030d80..e0170afdf4da7d 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -391,15 +391,6 @@ def open(self, url, new=0, autoraise=True): return (p.poll() is None) - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) - if new: - ok = self._remote("LOADNEW " + url) - else: - ok = self._remote("LOAD " + url) - return ok - - class Edge(UnixBrowser): "Launcher class for Microsoft Edge browser." diff --git a/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst b/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst new file mode 100644 index 00000000000000..7df7c5a79ec6eb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst @@ -0,0 +1 @@ +Fix ``webbrowser.Konqueror.open`` method. From 52a2bbdc9d6d62bad34d9bc42db613ea498ded1a Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 14 Jun 2023 16:03:30 +0100 Subject: [PATCH 0214/1206] [3.12] Typing docs: move the deprecated stuff below the non-deprecated stuff (#105781) (#105783) --- Doc/library/typing.rst | 1476 ++++++++++++++++++++-------------------- 1 file changed, 738 insertions(+), 738 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index caf4a53006f5e7..7e10b03eaa89dd 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2383,1093 +2383,1093 @@ These are not used in annotations. They are building blocks for declaring types. .. versionchanged:: 3.11 Added support for generic ``TypedDict``\ s. -Generic concrete collections ----------------------------- +Protocols +--------- -Corresponding to built-in types -""""""""""""""""""""""""""""""" +These protocols are decorated with :func:`runtime_checkable`. -.. class:: Dict(dict, MutableMapping[KT, VT]) +.. class:: SupportsAbs - Deprecated alias to :class:`dict`. + An ABC with one abstract method ``__abs__`` that is covariant + in its return type. - Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`Mapping` - rather than to use :class:`dict` or :class:`!typing.Dict`. +.. class:: SupportsBytes - This type can be used as follows:: + An ABC with one abstract method ``__bytes__``. - def count_words(text: str) -> Dict[str, int]: - ... +.. class:: SupportsComplex - .. deprecated:: 3.9 - :class:`builtins.dict ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + An ABC with one abstract method ``__complex__``. -.. class:: List(list, MutableSequence[T]) +.. class:: SupportsFloat - Deprecated alias to :class:`list`. + An ABC with one abstract method ``__float__``. - Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`Sequence` or - :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`. +.. class:: SupportsIndex - This type may be used as follows:: + An ABC with one abstract method ``__index__``. - def vec2[T: (int, float)](x: T, y: T) -> List[T]: - return [x, y] + .. versionadded:: 3.8 - def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]: - return [item for item in vector if item > 0] +.. class:: SupportsInt - .. deprecated:: 3.9 - :class:`builtins.list ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + An ABC with one abstract method ``__int__``. -.. class:: Set(set, MutableSet[T]) +.. class:: SupportsRound - Deprecated alias to :class:`builtins.set `. + An ABC with one abstract method ``__round__`` + that is covariant in its return type. - Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`AbstractSet` - rather than to use :class:`set` or :class:`!typing.Set`. +Functions and decorators +------------------------ - .. deprecated:: 3.9 - :class:`builtins.set ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. function:: cast(typ, val) -.. class:: FrozenSet(frozenset, AbstractSet[T_co]) + Cast a value to a type. - Deprecated alias to :class:`builtins.frozenset `. + This returns the value unchanged. To the type checker this + signals that the return value has the designated type, but at + runtime we intentionally don't check anything (we want this + to be as fast as possible). - .. deprecated:: 3.9 - :class:`builtins.frozenset ` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. function:: assert_type(val, typ, /) -.. note:: :data:`Tuple` is a special form. + Ask a static type checker to confirm that *val* has an inferred type of *typ*. -Corresponding to types in :mod:`collections` -"""""""""""""""""""""""""""""""""""""""""""" + At runtime this does nothing: it returns the first argument unchanged with no + checks or side effects, no matter the actual type of the argument. -.. class:: DefaultDict(collections.defaultdict, MutableMapping[KT, VT]) + When a static type checker encounters a call to ``assert_type()``, it + emits an error if the value is not of the specified type:: - Deprecated alias to :class:`collections.defaultdict`. + def greet(name: str) -> None: + assert_type(name, str) # OK, inferred type of `name` is `str` + assert_type(name, int) # type checker error - .. versionadded:: 3.5.2 + This function is useful for ensuring the type checker's understanding of a + script is in line with the developer's intentions:: - .. deprecated:: 3.9 - :class:`collections.defaultdict` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + def complex_function(arg: object): + # Do some complex type-narrowing logic, + # after which we hope the inferred type will be `int` + ... + # Test whether the type checker correctly understands our function + assert_type(arg, int) -.. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) + .. versionadded:: 3.11 - Deprecated alias to :class:`collections.OrderedDict`. +.. function:: assert_never(arg, /) - .. versionadded:: 3.7.2 + Ask a static type checker to confirm that a line of code is unreachable. - .. deprecated:: 3.9 - :class:`collections.OrderedDict` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Example:: -.. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _ as unreachable: + assert_never(unreachable) - Deprecated alias to :class:`collections.ChainMap`. + Here, the annotations allow the type checker to infer that the + last case can never execute, because ``arg`` is either + an :class:`int` or a :class:`str`, and both options are covered by + earlier cases. - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.1 + If a type checker finds that a call to ``assert_never()`` is + reachable, it will emit an error. For example, if the type annotation + for ``arg`` was instead ``int | str | float``, the type checker would + emit an error pointing out that ``unreachable`` is of type :class:`float`. + For a call to ``assert_never`` to pass type checking, the inferred type of + the argument passed in must be the bottom type, :data:`Never`, and nothing + else. - .. deprecated:: 3.9 - :class:`collections.ChainMap` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + At runtime, this throws an exception when called. -.. class:: Counter(collections.Counter, Dict[T, int]) + .. seealso:: + `Unreachable Code and Exhaustiveness Checking + `__ has more + information about exhaustiveness checking with static typing. - Deprecated alias to :class:`collections.Counter`. + .. versionadded:: 3.11 - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.1 +.. function:: reveal_type(obj, /) - .. deprecated:: 3.9 - :class:`collections.Counter` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Reveal the inferred static type of an expression. -.. class:: Deque(deque, MutableSequence[T]) + When a static type checker encounters a call to this function, + it emits a diagnostic with the type of the argument. For example:: - Deprecated alias to :class:`collections.deque`. + x: int = 1 + reveal_type(x) # Revealed type is "builtins.int" - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.1 + This can be useful when you want to debug how your type checker + handles a particular piece of code. - .. deprecated:: 3.9 - :class:`collections.deque` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + The function returns its argument unchanged, which allows using + it within an expression:: -Other concrete types -"""""""""""""""""""" + x = reveal_type(1) # Revealed type is "builtins.int" -.. class:: IO - TextIO - BinaryIO + Most type checkers support ``reveal_type()`` anywhere, even if the + name is not imported from ``typing``. Importing the name from + ``typing`` allows your code to run without runtime errors and + communicates intent more clearly. - Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` - and ``BinaryIO(IO[bytes])`` - represent the types of I/O streams such as returned by - :func:`open`. + At runtime, this function prints the runtime type of its argument to stderr + and returns it unchanged:: - .. deprecated-removed:: 3.8 3.13 - The ``typing.io`` namespace is deprecated and will be removed. - These types should be directly imported from ``typing`` instead. + x = reveal_type(1) # prints "Runtime type is int" + print(x) # prints "1" -.. class:: Pattern - Match + .. versionadded:: 3.11 - Deprecated aliases corresponding to the return types from - :func:`re.compile` and :func:`re.match`. +.. decorator:: dataclass_transform - These types (and the corresponding functions) are generic over - :data:`AnyStr`. ``Pattern`` can be specialised as ``Pattern[str]`` or - ``Pattern[bytes]``; ``Match`` can be specialised as ``Match[str]`` or - ``Match[bytes]``. + Decorator to mark an object as providing + :func:`~dataclasses.dataclass`-like behavior. - .. deprecated-removed:: 3.8 3.13 - The ``typing.re`` namespace is deprecated and will be removed. - These types should be directly imported from ``typing`` instead. + ``dataclass_transform`` may be used to + decorate a class, metaclass, or a function that is itself a decorator. + The presence of ``@dataclass_transform()`` tells a static type checker that the + decorated object performs runtime "magic" that + transforms a class in a similar way to :func:`dataclasses.dataclass`. - .. deprecated:: 3.9 - Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. - See :pep:`585` and :ref:`types-genericalias`. + Example usage with a decorator function: -.. class:: Text + .. testcode:: - Deprecated alias for :class:`str`. + @dataclass_transform() + def create_model[T](cls: type[T]) -> type[T]: + ... + return cls - ``Text`` is provided to supply a forward - compatible path for Python 2 code: in Python 2, ``Text`` is an alias for - ``unicode``. + @create_model + class CustomerModel: + id: int + name: str - Use ``Text`` to indicate that a value must contain a unicode string in - a manner that is compatible with both Python 2 and Python 3:: + On a base class:: - def add_unicode_checkmark(text: Text) -> Text: - return text + u' \u2713' + @dataclass_transform() + class ModelBase: ... - .. versionadded:: 3.5.2 + class CustomerModel(ModelBase): + id: int + name: str - .. deprecated:: 3.11 - Python 2 is no longer supported, and most type checkers also no longer - support type checking Python 2 code. Removal of the alias is not - currently planned, but users are encouraged to use - :class:`str` instead of ``Text``. + On a metaclass:: -Abstract Base Classes ---------------------- + @dataclass_transform() + class ModelMeta(type): ... -Corresponding to collections in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" + class ModelBase(metaclass=ModelMeta): ... -.. class:: AbstractSet(Collection[T_co]) + class CustomerModel(ModelBase): + id: int + name: str - Deprecated alias to :class:`collections.abc.Set`. + The ``CustomerModel`` classes defined above will + be treated by type checkers similarly to classes created with + :func:`@dataclasses.dataclass `. + For example, type checkers will assume these classes have + ``__init__`` methods that accept ``id`` and ``name``. - .. deprecated:: 3.9 - :class:`collections.abc.Set` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + The decorated class, metaclass, or function may accept the following bool + arguments which type checkers will assume have the same effect as they + would have on the + :func:`@dataclasses.dataclass` decorator: ``init``, + ``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``, + ``kw_only``, and ``slots``. It must be possible for the value of these + arguments (``True`` or ``False``) to be statically evaluated. -.. class:: ByteString(Sequence[int]) + The arguments to the ``dataclass_transform`` decorator can be used to + customize the default behaviors of the decorated class, metaclass, or + function: - This type represents the types :class:`bytes`, :class:`bytearray`, - and :class:`memoryview` of byte sequences. + * ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + ``True`` or ``False`` if it is omitted by the caller. + * ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + * ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + * ``frozen_default`` indicates whether the ``frozen`` parameter is + assumed to be True or False if it is omitted by the caller. - .. deprecated-removed:: 3.9 3.14 - Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. + .. versionadded:: 3.12 + * ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + * Arbitrary other keyword arguments are accepted in order to allow for + possible future extensions. -.. class:: Collection(Sized, Iterable[T_co], Container[T_co]) + Type checkers recognize the following optional arguments on field + specifiers: - Deprecated alias to :class:`collections.abc.Collection`. + * ``init`` indicates whether the field should be included in the + synthesized ``__init__`` method. If unspecified, ``init`` defaults to + ``True``. + * ``default`` provides the default value for the field. + * ``default_factory`` provides a runtime callback that returns the + default value for the field. If neither ``default`` nor + ``default_factory`` are specified, the field is assumed to have no + default value and must be provided a value when the class is + instantiated. + * ``factory`` is an alias for ``default_factory``. + * ``kw_only`` indicates whether the field should be marked as + keyword-only. If ``True``, the field will be keyword-only. If + ``False``, it will not be keyword-only. If unspecified, the value of + the ``kw_only`` parameter on the object decorated with + ``dataclass_transform`` will be used, or if that is unspecified, the + value of ``kw_only_default`` on ``dataclass_transform`` will be used. + * ``alias`` provides an alternative name for the field. This alternative + name is used in the synthesized ``__init__`` method. - .. versionadded:: 3.6.0 + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + It has no other runtime effect. - .. deprecated:: 3.9 - :class:`collections.abc.Collection` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + See :pep:`681` for more details. -.. class:: Container(Generic[T_co]) + .. versionadded:: 3.11 - Deprecated alias to :class:`collections.abc.Container`. +.. decorator:: overload - .. deprecated:: 3.9 - :class:`collections.abc.Container` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Decorator for creating overloaded functions and methods. -.. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) + The ``@overload`` decorator allows describing functions and methods + that support multiple different combinations of argument types. A series + of ``@overload``-decorated definitions must be followed by exactly one + non-``@overload``-decorated definition (for the same function/method). - Deprecated alias to :class:`collections.abc.ItemsView`. + ``@overload``-decorated definitions are for the benefit of the + type checker only, since they will be overwritten by the + non-``@overload``-decorated definition. The non-``@overload``-decorated + definition, meanwhile, will be used at + runtime but should be ignored by a type checker. At runtime, calling + an ``@overload``-decorated function directly will raise + :exc:`NotImplementedError`. - .. deprecated:: 3.9 - :class:`collections.abc.ItemsView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + An example of overload that gives a more + precise type than can be expressed using a union or a type variable: -.. class:: KeysView(MappingView, AbstractSet[KT_co]) + .. testcode:: - Deprecated alias to :class:`collections.abc.KeysView`. + @overload + def process(response: None) -> None: + ... + @overload + def process(response: int) -> tuple[int, str]: + ... + @overload + def process(response: bytes) -> str: + ... + def process(response): + ... # actual implementation goes here - .. deprecated:: 3.9 - :class:`collections.abc.KeysView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + See :pep:`484` for more details and comparison with other typing semantics. -.. class:: Mapping(Collection[KT], Generic[KT, VT_co]) + .. versionchanged:: 3.11 + Overloaded functions can now be introspected at runtime using + :func:`get_overloads`. - Deprecated alias to :class:`collections.abc.Mapping`. - This type can be used as follows:: +.. function:: get_overloads(func) - def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: - return word_list[word] + Return a sequence of :func:`@overload `-decorated definitions for + *func*. - .. deprecated:: 3.9 - :class:`collections.abc.Mapping` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + *func* is the function object for the implementation of the + overloaded function. For example, given the definition of ``process`` in + the documentation for :func:`@overload `, + ``get_overloads(process)`` will return a sequence of three function objects + for the three defined overloads. If called on a function with no overloads, + ``get_overloads()`` returns an empty sequence. -.. class:: MappingView(Sized) + ``get_overloads()`` can be used for introspecting an overloaded function at + runtime. - Deprecated alias to :class:`collections.abc.MappingView`. + .. versionadded:: 3.11 - .. deprecated:: 3.9 - :class:`collections.abc.MappingView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. -.. class:: MutableMapping(Mapping[KT, VT]) +.. function:: clear_overloads() - Deprecated alias to :class:`collections.abc.MutableMapping`. + Clear all registered overloads in the internal registry. - .. deprecated:: 3.9 - :class:`collections.abc.MutableMapping` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + This can be used to reclaim the memory used by the registry. -.. class:: MutableSequence(Sequence[T]) + .. versionadded:: 3.11 - Deprecated alias to :class:`collections.abc.MutableSequence`. - .. deprecated:: 3.9 - :class:`collections.abc.MutableSequence` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. decorator:: final -.. class:: MutableSet(AbstractSet[T]) + Decorator to indicate final methods and final classes. - Deprecated alias to :class:`collections.abc.MutableSet`. + Decorating a method with ``@final`` indicates to a type checker that the + method cannot be overridden in a subclass. Decorating a class with ``@final`` + indicates that it cannot be subclassed. - .. deprecated:: 3.9 - :class:`collections.abc.MutableSet` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + For example:: -.. class:: Sequence(Reversible[T_co], Collection[T_co]) + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... - Deprecated alias to :class:`collections.abc.Sequence`. + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... - .. deprecated:: 3.9 - :class:`collections.abc.Sequence` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + There is no runtime checking of these properties. See :pep:`591` for + more details. -.. class:: ValuesView(MappingView, Collection[_VT_co]) + .. versionadded:: 3.8 - Deprecated alias to :class:`collections.abc.ValuesView`. + .. versionchanged:: 3.11 + The decorator will now attempt to set a ``__final__`` attribute to ``True`` + on the decorated object. Thus, a check like + ``if getattr(obj, "__final__", False)`` can be used at runtime + to determine whether an object ``obj`` has been marked as final. + If the decorated object does not support setting attributes, + the decorator returns the object unchanged without raising an exception. - .. deprecated:: 3.9 - :class:`collections.abc.ValuesView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. -Corresponding to other types in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" +.. decorator:: no_type_check -.. class:: Iterable(Generic[T_co]) + Decorator to indicate that annotations are not type hints. - Deprecated alias to :class:`collections.abc.Iterable`. + This works as a class or function :term:`decorator`. With a class, it + applies recursively to all methods and classes defined in that class + (but not to methods defined in its superclasses or subclasses). Type + checkers will ignore all annotations in a function or class with this + decorator. - .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + ``@no_type_check`` mutates the decorated object in place. -.. class:: Iterator(Iterable[T_co]) +.. decorator:: no_type_check_decorator - Deprecated alias to :class:`collections.abc.Iterator`. + Decorator to give another decorator the :func:`no_type_check` effect. - .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + This wraps the decorator with something that wraps the decorated + function in :func:`no_type_check`. -.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) - Deprecated alias to :class:`collections.abc.Generator`. +.. decorator:: override - A generator can be annotated by the generic type - ``Generator[YieldType, SendType, ReturnType]``. For example:: + Decorator to indicate that a method in a subclass is intended to override a + method or attribute in a superclass. - def echo_round() -> Generator[int, float, str]: - sent = yield 0 - while sent >= 0: - sent = yield round(sent) - return 'Done' + Type checkers should emit an error if a method decorated with ``@override`` + does not, in fact, override anything. + This helps prevent bugs that may occur when a base class is changed without + an equivalent change to a child class. - Note that unlike many other generics in the typing module, the ``SendType`` - of :class:`Generator` behaves contravariantly, not covariantly or - invariantly. + For example: - If your generator will only yield values, set the ``SendType`` and - ``ReturnType`` to ``None``:: + .. testcode:: - def infinite_stream(start: int) -> Generator[int, None, None]: - while True: - yield start - start += 1 + class Base: + def log_status(self) -> None: + ... - Alternatively, annotate your generator as having a return type of - either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: + class Sub(Base): + @override + def log_status(self) -> None: # Okay: overrides Base.log_status + ... - def infinite_stream(start: int) -> Iterator[int]: - while True: - yield start - start += 1 + @override + def done(self) -> None: # Error reported by type checker + ... - .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + There is no runtime checking of this property. -.. class:: Hashable + The decorator will attempt to set an ``__override__`` attribute to ``True`` on + the decorated object. Thus, a check like + ``if getattr(obj, "__override__", False)`` can be used at runtime to determine + whether an object ``obj`` has been marked as an override. If the decorated object + does not support setting attributes, the decorator returns the object unchanged + without raising an exception. - Deprecated alias to :class:`collections.abc.Hashable`. + See :pep:`698` for more details. - .. deprecated:: 3.12 - Use :class:`collections.abc.Hashable` directly instead. + .. versionadded:: 3.12 -.. class:: Reversible(Iterable[T_co]) - Deprecated alias to :class:`collections.abc.Reversible`. +.. decorator:: type_check_only - .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Decorator to mark a class or function as unavailable at runtime. -.. class:: Sized + This decorator is itself not available at runtime. It is mainly + intended to mark classes that are defined in type stub files if + an implementation returns an instance of a private class:: - Deprecated alias to :class:`collections.abc.Sized`. + @type_check_only + class Response: # private or not available at runtime + code: int + def get_header(self, name: str) -> str: ... - .. deprecated:: 3.12 - Use :class:`collections.abc.Sized` directly instead. + def fetch_response() -> Response: ... -Asynchronous programming -"""""""""""""""""""""""" + Note that returning instances of private classes is not recommended. + It is usually preferable to make such classes public. -.. class:: Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType]) +Introspection helpers +--------------------- - Deprecated alias to :class:`collections.abc.Coroutine`. +.. function:: get_type_hints(obj, globalns=None, localns=None, include_extras=False) - The variance and order of type variables - correspond to those of :class:`Generator`, for example:: + Return a dictionary containing type hints for a function, method, module + or class object. - from collections.abc import Coroutine - c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere - x = c.send('hi') # Inferred type of 'x' is list[str] - async def bar() -> None: - y = await c # Inferred type of 'y' is int + This is often the same as ``obj.__annotations__``. In addition, + forward references encoded as string literals are handled by evaluating + them in ``globals`` and ``locals`` namespaces. For a class ``C``, return + a dictionary constructed by merging all the ``__annotations__`` along + ``C.__mro__`` in reverse order. - .. versionadded:: 3.5.3 + The function recursively replaces all ``Annotated[T, ...]`` with ``T``, + unless ``include_extras`` is set to ``True`` (see :class:`Annotated` for + more information). For example: - .. deprecated:: 3.9 - :class:`collections.abc.Coroutine` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. testcode:: -.. class:: AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType]) + class Student(NamedTuple): + name: Annotated[str, 'some marker'] - Deprecated alias to :class:`collections.abc.AsyncGenerator`. + assert get_type_hints(Student) == {'name': str} + assert get_type_hints(Student, include_extras=False) == {'name': str} + assert get_type_hints(Student, include_extras=True) == { + 'name': Annotated[str, 'some marker'] + } - An async generator can be annotated by the generic type - ``AsyncGenerator[YieldType, SendType]``. For example:: + .. note:: - async def echo_round() -> AsyncGenerator[int, float]: - sent = yield 0 - while sent >= 0.0: - rounded = await round(sent) - sent = yield rounded + :func:`get_type_hints` does not work with imported + :ref:`type aliases ` that include forward references. + Enabling postponed evaluation of annotations (:pep:`563`) may remove + the need for most forward references. - Unlike normal generators, async generators cannot return a value, so there - is no ``ReturnType`` type parameter. As with :class:`Generator`, the - ``SendType`` behaves contravariantly. + .. versionchanged:: 3.9 + Added ``include_extras`` parameter as part of :pep:`593`. + See the documentation on :data:`Annotated` for more information. - If your generator will only yield values, set the ``SendType`` to - ``None``:: + .. versionchanged:: 3.11 + Previously, ``Optional[t]`` was added for function and method annotations + if a default value equal to ``None`` was set. + Now the annotation is returned unchanged. - async def infinite_stream(start: int) -> AsyncGenerator[int, None]: - while True: - yield start - start = await increment(start) +.. function:: get_origin(tp) - Alternatively, annotate your generator as having a return type of - either ``AsyncIterable[YieldType]`` or ``AsyncIterator[YieldType]``:: + Get the unsubscripted version of a type: for a typing object of the form + ``X[Y, Z, ...]`` return ``X``. - async def infinite_stream(start: int) -> AsyncIterator[int]: - while True: - yield start - start = await increment(start) + If ``X`` is a typing-module alias for a builtin or + :mod:`collections` class, it will be normalized to the original class. + If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, + return the underlying :class:`ParamSpec`. + Return ``None`` for unsupported objects. - .. versionadded:: 3.6.1 + Examples: - .. deprecated:: 3.9 - :class:`collections.abc.AsyncGenerator` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. testcode:: -.. class:: AsyncIterable(Generic[T_co]) + assert get_origin(str) is None + assert get_origin(Dict[str, int]) is dict + assert get_origin(Union[int, str]) is Union + P = ParamSpec('P') + assert get_origin(P.args) is P + assert get_origin(P.kwargs) is P - Deprecated alias to :class:`collections.abc.AsyncIterable`. + .. versionadded:: 3.8 - .. versionadded:: 3.5.2 +.. function:: get_args(tp) - .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Get type arguments with all substitutions performed: for a typing object + of the form ``X[Y, Z, ...]`` return ``(Y, Z, ...)``. -.. class:: AsyncIterator(AsyncIterable[T_co]) + If ``X`` is a union or :class:`Literal` contained in another + generic type, the order of ``(Y, Z, ...)`` may be different from the order + of the original arguments ``[Y, Z, ...]`` due to type caching. + Return ``()`` for unsupported objects. - Deprecated alias to :class:`collections.abc.AsyncIterator`. + Examples: - .. versionadded:: 3.5.2 + .. testcode:: - .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + assert get_args(int) == () + assert get_args(Dict[int, str]) == (int, str) + assert get_args(Union[int, str]) == (int, str) -.. class:: Awaitable(Generic[T_co]) + .. versionadded:: 3.8 - Deprecated alias to :class:`collections.abc.Awaitable`. +.. function:: is_typeddict(tp) - .. versionadded:: 3.5.2 + Check if a type is a :class:`TypedDict`. - .. deprecated:: 3.9 - :class:`collections.abc.Awaitable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + For example: + .. testcode:: -Context manager types -""""""""""""""""""""" + class Film(TypedDict): + title: str + year: int -.. class:: ContextManager(Generic[T_co]) + assert is_typeddict(Film) + assert not is_typeddict(list | str) - Deprecated alias to :class:`contextlib.AbstractContextManager`. + # TypedDict is a factory for creating typed dicts, + # not a typed dict itself + assert not is_typeddict(TypedDict) - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.0 + .. versionadded:: 3.10 - .. deprecated:: 3.9 - :class:`contextlib.AbstractContextManager` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. class:: ForwardRef -.. class:: AsyncContextManager(Generic[T_co]) + Class used for internal typing representation of string forward references. - Deprecated alias to :class:`contextlib.AbstractAsyncContextManager`. + For example, ``List["SomeClass"]`` is implicitly transformed into + ``List[ForwardRef("SomeClass")]``. ``ForwardRef`` should not be instantiated by + a user, but may be used by introspection tools. - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.2 + .. note:: + :pep:`585` generic types such as ``list["SomeClass"]`` will not be + implicitly transformed into ``list[ForwardRef("SomeClass")]`` and thus + will not automatically resolve to ``list[SomeClass]``. - .. deprecated:: 3.9 - :class:`contextlib.AbstractAsyncContextManager` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. versionadded:: 3.7.4 -Protocols ---------- +Constant +-------- -These protocols are decorated with :func:`runtime_checkable`. +.. data:: TYPE_CHECKING -.. class:: SupportsAbs + A special constant that is assumed to be ``True`` by 3rd party static + type checkers. It is ``False`` at runtime. - An ABC with one abstract method ``__abs__`` that is covariant - in its return type. + Usage:: -.. class:: SupportsBytes + if TYPE_CHECKING: + import expensive_mod - An ABC with one abstract method ``__bytes__``. + def fun(arg: 'expensive_mod.SomeType') -> None: + local_var: expensive_mod.AnotherType = other_fun() -.. class:: SupportsComplex + The first type annotation must be enclosed in quotes, making it a + "forward reference", to hide the ``expensive_mod`` reference from the + interpreter runtime. Type annotations for local variables are not + evaluated, so the second annotation does not need to be enclosed in quotes. - An ABC with one abstract method ``__complex__``. + .. note:: -.. class:: SupportsFloat + If ``from __future__ import annotations`` is used, + annotations are not evaluated at function definition time. + Instead, they are stored as strings in ``__annotations__``. + This makes it unnecessary to use quotes around the annotation + (see :pep:`563`). - An ABC with one abstract method ``__float__``. + .. versionadded:: 3.5.2 -.. class:: SupportsIndex +Generic concrete collections +---------------------------- - An ABC with one abstract method ``__index__``. +Corresponding to built-in types +""""""""""""""""""""""""""""""" - .. versionadded:: 3.8 +.. class:: Dict(dict, MutableMapping[KT, VT]) -.. class:: SupportsInt + Deprecated alias to :class:`dict`. - An ABC with one abstract method ``__int__``. + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`Mapping` + rather than to use :class:`dict` or :class:`!typing.Dict`. -.. class:: SupportsRound + This type can be used as follows:: - An ABC with one abstract method ``__round__`` - that is covariant in its return type. + def count_words(text: str) -> Dict[str, int]: + ... -Functions and decorators ------------------------- + .. deprecated:: 3.9 + :class:`builtins.dict ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -.. function:: cast(typ, val) +.. class:: List(list, MutableSequence[T]) - Cast a value to a type. + Deprecated alias to :class:`list`. - This returns the value unchanged. To the type checker this - signals that the return value has the designated type, but at - runtime we intentionally don't check anything (we want this - to be as fast as possible). + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`Sequence` or + :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`. -.. function:: assert_type(val, typ, /) + This type may be used as follows:: - Ask a static type checker to confirm that *val* has an inferred type of *typ*. + def vec2[T: (int, float)](x: T, y: T) -> List[T]: + return [x, y] - At runtime this does nothing: it returns the first argument unchanged with no - checks or side effects, no matter the actual type of the argument. + def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]: + return [item for item in vector if item > 0] - When a static type checker encounters a call to ``assert_type()``, it - emits an error if the value is not of the specified type:: + .. deprecated:: 3.9 + :class:`builtins.list ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - def greet(name: str) -> None: - assert_type(name, str) # OK, inferred type of `name` is `str` - assert_type(name, int) # type checker error +.. class:: Set(set, MutableSet[T]) - This function is useful for ensuring the type checker's understanding of a - script is in line with the developer's intentions:: + Deprecated alias to :class:`builtins.set `. - def complex_function(arg: object): - # Do some complex type-narrowing logic, - # after which we hope the inferred type will be `int` - ... - # Test whether the type checker correctly understands our function - assert_type(arg, int) + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`AbstractSet` + rather than to use :class:`set` or :class:`!typing.Set`. - .. versionadded:: 3.11 + .. deprecated:: 3.9 + :class:`builtins.set ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -.. function:: assert_never(arg, /) +.. class:: FrozenSet(frozenset, AbstractSet[T_co]) - Ask a static type checker to confirm that a line of code is unreachable. + Deprecated alias to :class:`builtins.frozenset `. - Example:: + .. deprecated:: 3.9 + :class:`builtins.frozenset ` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - def int_or_str(arg: int | str) -> None: - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _ as unreachable: - assert_never(unreachable) +.. note:: :data:`Tuple` is a special form. - Here, the annotations allow the type checker to infer that the - last case can never execute, because ``arg`` is either - an :class:`int` or a :class:`str`, and both options are covered by - earlier cases. +Corresponding to types in :mod:`collections` +"""""""""""""""""""""""""""""""""""""""""""" - If a type checker finds that a call to ``assert_never()`` is - reachable, it will emit an error. For example, if the type annotation - for ``arg`` was instead ``int | str | float``, the type checker would - emit an error pointing out that ``unreachable`` is of type :class:`float`. - For a call to ``assert_never`` to pass type checking, the inferred type of - the argument passed in must be the bottom type, :data:`Never`, and nothing - else. +.. class:: DefaultDict(collections.defaultdict, MutableMapping[KT, VT]) - At runtime, this throws an exception when called. + Deprecated alias to :class:`collections.defaultdict`. - .. seealso:: - `Unreachable Code and Exhaustiveness Checking - `__ has more - information about exhaustiveness checking with static typing. + .. versionadded:: 3.5.2 - .. versionadded:: 3.11 + .. deprecated:: 3.9 + :class:`collections.defaultdict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -.. function:: reveal_type(obj, /) +.. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) - Reveal the inferred static type of an expression. + Deprecated alias to :class:`collections.OrderedDict`. - When a static type checker encounters a call to this function, - it emits a diagnostic with the type of the argument. For example:: + .. versionadded:: 3.7.2 - x: int = 1 - reveal_type(x) # Revealed type is "builtins.int" + .. deprecated:: 3.9 + :class:`collections.OrderedDict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - This can be useful when you want to debug how your type checker - handles a particular piece of code. +.. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) - The function returns its argument unchanged, which allows using - it within an expression:: + Deprecated alias to :class:`collections.ChainMap`. - x = reveal_type(1) # Revealed type is "builtins.int" + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.1 - Most type checkers support ``reveal_type()`` anywhere, even if the - name is not imported from ``typing``. Importing the name from - ``typing`` allows your code to run without runtime errors and - communicates intent more clearly. + .. deprecated:: 3.9 + :class:`collections.ChainMap` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - At runtime, this function prints the runtime type of its argument to stderr - and returns it unchanged:: +.. class:: Counter(collections.Counter, Dict[T, int]) - x = reveal_type(1) # prints "Runtime type is int" - print(x) # prints "1" + Deprecated alias to :class:`collections.Counter`. - .. versionadded:: 3.11 + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.1 -.. decorator:: dataclass_transform + .. deprecated:: 3.9 + :class:`collections.Counter` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Decorator to mark an object as providing - :func:`~dataclasses.dataclass`-like behavior. +.. class:: Deque(deque, MutableSequence[T]) - ``dataclass_transform`` may be used to - decorate a class, metaclass, or a function that is itself a decorator. - The presence of ``@dataclass_transform()`` tells a static type checker that the - decorated object performs runtime "magic" that - transforms a class in a similar way to :func:`dataclasses.dataclass`. + Deprecated alias to :class:`collections.deque`. - Example usage with a decorator function: + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.1 - .. testcode:: + .. deprecated:: 3.9 + :class:`collections.deque` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - @dataclass_transform() - def create_model[T](cls: type[T]) -> type[T]: - ... - return cls +Other concrete types +"""""""""""""""""""" - @create_model - class CustomerModel: - id: int - name: str +.. class:: IO + TextIO + BinaryIO - On a base class:: + Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` + and ``BinaryIO(IO[bytes])`` + represent the types of I/O streams such as returned by + :func:`open`. - @dataclass_transform() - class ModelBase: ... + .. deprecated-removed:: 3.8 3.13 + The ``typing.io`` namespace is deprecated and will be removed. + These types should be directly imported from ``typing`` instead. - class CustomerModel(ModelBase): - id: int - name: str +.. class:: Pattern + Match - On a metaclass:: + Deprecated aliases corresponding to the return types from + :func:`re.compile` and :func:`re.match`. - @dataclass_transform() - class ModelMeta(type): ... + These types (and the corresponding functions) are generic over + :data:`AnyStr`. ``Pattern`` can be specialised as ``Pattern[str]`` or + ``Pattern[bytes]``; ``Match`` can be specialised as ``Match[str]`` or + ``Match[bytes]``. - class ModelBase(metaclass=ModelMeta): ... + .. deprecated-removed:: 3.8 3.13 + The ``typing.re`` namespace is deprecated and will be removed. + These types should be directly imported from ``typing`` instead. - class CustomerModel(ModelBase): - id: int - name: str + .. deprecated:: 3.9 + Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. + See :pep:`585` and :ref:`types-genericalias`. - The ``CustomerModel`` classes defined above will - be treated by type checkers similarly to classes created with - :func:`@dataclasses.dataclass `. - For example, type checkers will assume these classes have - ``__init__`` methods that accept ``id`` and ``name``. +.. class:: Text - The decorated class, metaclass, or function may accept the following bool - arguments which type checkers will assume have the same effect as they - would have on the - :func:`@dataclasses.dataclass` decorator: ``init``, - ``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``, - ``kw_only``, and ``slots``. It must be possible for the value of these - arguments (``True`` or ``False``) to be statically evaluated. + Deprecated alias for :class:`str`. - The arguments to the ``dataclass_transform`` decorator can be used to - customize the default behaviors of the decorated class, metaclass, or - function: + ``Text`` is provided to supply a forward + compatible path for Python 2 code: in Python 2, ``Text`` is an alias for + ``unicode``. - * ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - ``True`` or ``False`` if it is omitted by the caller. - * ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``frozen_default`` indicates whether the ``frozen`` parameter is - assumed to be True or False if it is omitted by the caller. + Use ``Text`` to indicate that a value must contain a unicode string in + a manner that is compatible with both Python 2 and Python 3:: - .. versionadded:: 3.12 - * ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - * Arbitrary other keyword arguments are accepted in order to allow for - possible future extensions. + def add_unicode_checkmark(text: Text) -> Text: + return text + u' \u2713' - Type checkers recognize the following optional arguments on field - specifiers: + .. versionadded:: 3.5.2 - * ``init`` indicates whether the field should be included in the - synthesized ``__init__`` method. If unspecified, ``init`` defaults to - ``True``. - * ``default`` provides the default value for the field. - * ``default_factory`` provides a runtime callback that returns the - default value for the field. If neither ``default`` nor - ``default_factory`` are specified, the field is assumed to have no - default value and must be provided a value when the class is - instantiated. - * ``factory`` is an alias for ``default_factory``. - * ``kw_only`` indicates whether the field should be marked as - keyword-only. If ``True``, the field will be keyword-only. If - ``False``, it will not be keyword-only. If unspecified, the value of - the ``kw_only`` parameter on the object decorated with - ``dataclass_transform`` will be used, or if that is unspecified, the - value of ``kw_only_default`` on ``dataclass_transform`` will be used. - * ``alias`` provides an alternative name for the field. This alternative - name is used in the synthesized ``__init__`` method. + .. deprecated:: 3.11 + Python 2 is no longer supported, and most type checkers also no longer + support type checking Python 2 code. Removal of the alias is not + currently planned, but users are encouraged to use + :class:`str` instead of ``Text``. - At runtime, this decorator records its arguments in the - ``__dataclass_transform__`` attribute on the decorated object. - It has no other runtime effect. +Abstract Base Classes +--------------------- - See :pep:`681` for more details. +Corresponding to collections in :mod:`collections.abc` +"""""""""""""""""""""""""""""""""""""""""""""""""""""" - .. versionadded:: 3.11 +.. class:: AbstractSet(Collection[T_co]) -.. decorator:: overload + Deprecated alias to :class:`collections.abc.Set`. - Decorator for creating overloaded functions and methods. + .. deprecated:: 3.9 + :class:`collections.abc.Set` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - The ``@overload`` decorator allows describing functions and methods - that support multiple different combinations of argument types. A series - of ``@overload``-decorated definitions must be followed by exactly one - non-``@overload``-decorated definition (for the same function/method). +.. class:: ByteString(Sequence[int]) - ``@overload``-decorated definitions are for the benefit of the - type checker only, since they will be overwritten by the - non-``@overload``-decorated definition. The non-``@overload``-decorated - definition, meanwhile, will be used at - runtime but should be ignored by a type checker. At runtime, calling - an ``@overload``-decorated function directly will raise - :exc:`NotImplementedError`. + This type represents the types :class:`bytes`, :class:`bytearray`, + and :class:`memoryview` of byte sequences. - An example of overload that gives a more - precise type than can be expressed using a union or a type variable: + .. deprecated-removed:: 3.9 3.14 + Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. - .. testcode:: +.. class:: Collection(Sized, Iterable[T_co], Container[T_co]) - @overload - def process(response: None) -> None: - ... - @overload - def process(response: int) -> tuple[int, str]: - ... - @overload - def process(response: bytes) -> str: - ... - def process(response): - ... # actual implementation goes here + Deprecated alias to :class:`collections.abc.Collection`. - See :pep:`484` for more details and comparison with other typing semantics. + .. versionadded:: 3.6.0 - .. versionchanged:: 3.11 - Overloaded functions can now be introspected at runtime using - :func:`get_overloads`. + .. deprecated:: 3.9 + :class:`collections.abc.Collection` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. +.. class:: Container(Generic[T_co]) -.. function:: get_overloads(func) + Deprecated alias to :class:`collections.abc.Container`. - Return a sequence of :func:`@overload `-decorated definitions for - *func*. + .. deprecated:: 3.9 + :class:`collections.abc.Container` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - *func* is the function object for the implementation of the - overloaded function. For example, given the definition of ``process`` in - the documentation for :func:`@overload `, - ``get_overloads(process)`` will return a sequence of three function objects - for the three defined overloads. If called on a function with no overloads, - ``get_overloads()`` returns an empty sequence. +.. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) - ``get_overloads()`` can be used for introspecting an overloaded function at - runtime. + Deprecated alias to :class:`collections.abc.ItemsView`. - .. versionadded:: 3.11 + .. deprecated:: 3.9 + :class:`collections.abc.ItemsView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. +.. class:: KeysView(MappingView, AbstractSet[KT_co]) -.. function:: clear_overloads() + Deprecated alias to :class:`collections.abc.KeysView`. - Clear all registered overloads in the internal registry. + .. deprecated:: 3.9 + :class:`collections.abc.KeysView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - This can be used to reclaim the memory used by the registry. +.. class:: Mapping(Collection[KT], Generic[KT, VT_co]) - .. versionadded:: 3.11 + Deprecated alias to :class:`collections.abc.Mapping`. + This type can be used as follows:: -.. decorator:: final + def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: + return word_list[word] - Decorator to indicate final methods and final classes. + .. deprecated:: 3.9 + :class:`collections.abc.Mapping` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Decorating a method with ``@final`` indicates to a type checker that the - method cannot be overridden in a subclass. Decorating a class with ``@final`` - indicates that it cannot be subclassed. +.. class:: MappingView(Sized) - For example:: + Deprecated alias to :class:`collections.abc.MappingView`. - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker - ... + .. deprecated:: 3.9 + :class:`collections.abc.MappingView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... +.. class:: MutableMapping(Mapping[KT, VT]) - There is no runtime checking of these properties. See :pep:`591` for - more details. + Deprecated alias to :class:`collections.abc.MutableMapping`. - .. versionadded:: 3.8 + .. deprecated:: 3.9 + :class:`collections.abc.MutableMapping` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. versionchanged:: 3.11 - The decorator will now attempt to set a ``__final__`` attribute to ``True`` - on the decorated object. Thus, a check like - ``if getattr(obj, "__final__", False)`` can be used at runtime - to determine whether an object ``obj`` has been marked as final. - If the decorated object does not support setting attributes, - the decorator returns the object unchanged without raising an exception. +.. class:: MutableSequence(Sequence[T]) + Deprecated alias to :class:`collections.abc.MutableSequence`. -.. decorator:: no_type_check + .. deprecated:: 3.9 + :class:`collections.abc.MutableSequence` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Decorator to indicate that annotations are not type hints. +.. class:: MutableSet(AbstractSet[T]) - This works as a class or function :term:`decorator`. With a class, it - applies recursively to all methods and classes defined in that class - (but not to methods defined in its superclasses or subclasses). Type - checkers will ignore all annotations in a function or class with this - decorator. + Deprecated alias to :class:`collections.abc.MutableSet`. - ``@no_type_check`` mutates the decorated object in place. + .. deprecated:: 3.9 + :class:`collections.abc.MutableSet` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -.. decorator:: no_type_check_decorator +.. class:: Sequence(Reversible[T_co], Collection[T_co]) - Decorator to give another decorator the :func:`no_type_check` effect. + Deprecated alias to :class:`collections.abc.Sequence`. - This wraps the decorator with something that wraps the decorated - function in :func:`no_type_check`. + .. deprecated:: 3.9 + :class:`collections.abc.Sequence` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. +.. class:: ValuesView(MappingView, Collection[_VT_co]) -.. decorator:: override + Deprecated alias to :class:`collections.abc.ValuesView`. - Decorator to indicate that a method in a subclass is intended to override a - method or attribute in a superclass. + .. deprecated:: 3.9 + :class:`collections.abc.ValuesView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Type checkers should emit an error if a method decorated with ``@override`` - does not, in fact, override anything. - This helps prevent bugs that may occur when a base class is changed without - an equivalent change to a child class. +Corresponding to other types in :mod:`collections.abc` +"""""""""""""""""""""""""""""""""""""""""""""""""""""" - For example: +.. class:: Iterable(Generic[T_co]) - .. testcode:: + Deprecated alias to :class:`collections.abc.Iterable`. - class Base: - def log_status(self) -> None: - ... + .. deprecated:: 3.9 + :class:`collections.abc.Iterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - class Sub(Base): - @override - def log_status(self) -> None: # Okay: overrides Base.log_status - ... +.. class:: Iterator(Iterable[T_co]) - @override - def done(self) -> None: # Error reported by type checker - ... + Deprecated alias to :class:`collections.abc.Iterator`. - There is no runtime checking of this property. + .. deprecated:: 3.9 + :class:`collections.abc.Iterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - The decorator will attempt to set an ``__override__`` attribute to ``True`` on - the decorated object. Thus, a check like - ``if getattr(obj, "__override__", False)`` can be used at runtime to determine - whether an object ``obj`` has been marked as an override. If the decorated object - does not support setting attributes, the decorator returns the object unchanged - without raising an exception. +.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) - See :pep:`698` for more details. + Deprecated alias to :class:`collections.abc.Generator`. - .. versionadded:: 3.12 + A generator can be annotated by the generic type + ``Generator[YieldType, SendType, ReturnType]``. For example:: + def echo_round() -> Generator[int, float, str]: + sent = yield 0 + while sent >= 0: + sent = yield round(sent) + return 'Done' -.. decorator:: type_check_only + Note that unlike many other generics in the typing module, the ``SendType`` + of :class:`Generator` behaves contravariantly, not covariantly or + invariantly. - Decorator to mark a class or function as unavailable at runtime. + If your generator will only yield values, set the ``SendType`` and + ``ReturnType`` to ``None``:: - This decorator is itself not available at runtime. It is mainly - intended to mark classes that are defined in type stub files if - an implementation returns an instance of a private class:: + def infinite_stream(start: int) -> Generator[int, None, None]: + while True: + yield start + start += 1 - @type_check_only - class Response: # private or not available at runtime - code: int - def get_header(self, name: str) -> str: ... + Alternatively, annotate your generator as having a return type of + either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: - def fetch_response() -> Response: ... + def infinite_stream(start: int) -> Iterator[int]: + while True: + yield start + start += 1 - Note that returning instances of private classes is not recommended. - It is usually preferable to make such classes public. + .. deprecated:: 3.9 + :class:`collections.abc.Generator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -Introspection helpers ---------------------- +.. class:: Hashable -.. function:: get_type_hints(obj, globalns=None, localns=None, include_extras=False) + Deprecated alias to :class:`collections.abc.Hashable`. - Return a dictionary containing type hints for a function, method, module - or class object. + .. deprecated:: 3.12 + Use :class:`collections.abc.Hashable` directly instead. - This is often the same as ``obj.__annotations__``. In addition, - forward references encoded as string literals are handled by evaluating - them in ``globals`` and ``locals`` namespaces. For a class ``C``, return - a dictionary constructed by merging all the ``__annotations__`` along - ``C.__mro__`` in reverse order. +.. class:: Reversible(Iterable[T_co]) - The function recursively replaces all ``Annotated[T, ...]`` with ``T``, - unless ``include_extras`` is set to ``True`` (see :class:`Annotated` for - more information). For example: + Deprecated alias to :class:`collections.abc.Reversible`. - .. testcode:: + .. deprecated:: 3.9 + :class:`collections.abc.Reversible` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - class Student(NamedTuple): - name: Annotated[str, 'some marker'] +.. class:: Sized - assert get_type_hints(Student) == {'name': str} - assert get_type_hints(Student, include_extras=False) == {'name': str} - assert get_type_hints(Student, include_extras=True) == { - 'name': Annotated[str, 'some marker'] - } + Deprecated alias to :class:`collections.abc.Sized`. - .. note:: + .. deprecated:: 3.12 + Use :class:`collections.abc.Sized` directly instead. - :func:`get_type_hints` does not work with imported - :ref:`type aliases ` that include forward references. - Enabling postponed evaluation of annotations (:pep:`563`) may remove - the need for most forward references. +Asynchronous programming +"""""""""""""""""""""""" - .. versionchanged:: 3.9 - Added ``include_extras`` parameter as part of :pep:`593`. - See the documentation on :data:`Annotated` for more information. +.. class:: Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType]) - .. versionchanged:: 3.11 - Previously, ``Optional[t]`` was added for function and method annotations - if a default value equal to ``None`` was set. - Now the annotation is returned unchanged. + Deprecated alias to :class:`collections.abc.Coroutine`. -.. function:: get_origin(tp) + The variance and order of type variables + correspond to those of :class:`Generator`, for example:: - Get the unsubscripted version of a type: for a typing object of the form - ``X[Y, Z, ...]`` return ``X``. + from collections.abc import Coroutine + c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere + x = c.send('hi') # Inferred type of 'x' is list[str] + async def bar() -> None: + y = await c # Inferred type of 'y' is int - If ``X`` is a typing-module alias for a builtin or - :mod:`collections` class, it will be normalized to the original class. - If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, - return the underlying :class:`ParamSpec`. - Return ``None`` for unsupported objects. + .. versionadded:: 3.5.3 - Examples: + .. deprecated:: 3.9 + :class:`collections.abc.Coroutine` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. testcode:: +.. class:: AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType]) - assert get_origin(str) is None - assert get_origin(Dict[str, int]) is dict - assert get_origin(Union[int, str]) is Union - P = ParamSpec('P') - assert get_origin(P.args) is P - assert get_origin(P.kwargs) is P + Deprecated alias to :class:`collections.abc.AsyncGenerator`. - .. versionadded:: 3.8 + An async generator can be annotated by the generic type + ``AsyncGenerator[YieldType, SendType]``. For example:: -.. function:: get_args(tp) + async def echo_round() -> AsyncGenerator[int, float]: + sent = yield 0 + while sent >= 0.0: + rounded = await round(sent) + sent = yield rounded - Get type arguments with all substitutions performed: for a typing object - of the form ``X[Y, Z, ...]`` return ``(Y, Z, ...)``. + Unlike normal generators, async generators cannot return a value, so there + is no ``ReturnType`` type parameter. As with :class:`Generator`, the + ``SendType`` behaves contravariantly. - If ``X`` is a union or :class:`Literal` contained in another - generic type, the order of ``(Y, Z, ...)`` may be different from the order - of the original arguments ``[Y, Z, ...]`` due to type caching. - Return ``()`` for unsupported objects. + If your generator will only yield values, set the ``SendType`` to + ``None``:: - Examples: + async def infinite_stream(start: int) -> AsyncGenerator[int, None]: + while True: + yield start + start = await increment(start) - .. testcode:: + Alternatively, annotate your generator as having a return type of + either ``AsyncIterable[YieldType]`` or ``AsyncIterator[YieldType]``:: - assert get_args(int) == () - assert get_args(Dict[int, str]) == (int, str) - assert get_args(Union[int, str]) == (int, str) + async def infinite_stream(start: int) -> AsyncIterator[int]: + while True: + yield start + start = await increment(start) - .. versionadded:: 3.8 + .. versionadded:: 3.6.1 -.. function:: is_typeddict(tp) + .. deprecated:: 3.9 + :class:`collections.abc.AsyncGenerator` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Check if a type is a :class:`TypedDict`. +.. class:: AsyncIterable(Generic[T_co]) - For example: + Deprecated alias to :class:`collections.abc.AsyncIterable`. - .. testcode:: + .. versionadded:: 3.5.2 - class Film(TypedDict): - title: str - year: int + .. deprecated:: 3.9 + :class:`collections.abc.AsyncIterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - assert is_typeddict(Film) - assert not is_typeddict(list | str) +.. class:: AsyncIterator(AsyncIterable[T_co]) - # TypedDict is a factory for creating typed dicts, - # not a typed dict itself - assert not is_typeddict(TypedDict) + Deprecated alias to :class:`collections.abc.AsyncIterator`. - .. versionadded:: 3.10 + .. versionadded:: 3.5.2 -.. class:: ForwardRef + .. deprecated:: 3.9 + :class:`collections.abc.AsyncIterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Class used for internal typing representation of string forward references. +.. class:: Awaitable(Generic[T_co]) - For example, ``List["SomeClass"]`` is implicitly transformed into - ``List[ForwardRef("SomeClass")]``. ``ForwardRef`` should not be instantiated by - a user, but may be used by introspection tools. + Deprecated alias to :class:`collections.abc.Awaitable`. - .. note:: - :pep:`585` generic types such as ``list["SomeClass"]`` will not be - implicitly transformed into ``list[ForwardRef("SomeClass")]`` and thus - will not automatically resolve to ``list[SomeClass]``. + .. versionadded:: 3.5.2 - .. versionadded:: 3.7.4 + .. deprecated:: 3.9 + :class:`collections.abc.Awaitable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -Constant --------- -.. data:: TYPE_CHECKING +Context manager types +""""""""""""""""""""" - A special constant that is assumed to be ``True`` by 3rd party static - type checkers. It is ``False`` at runtime. +.. class:: ContextManager(Generic[T_co]) - Usage:: + Deprecated alias to :class:`contextlib.AbstractContextManager`. - if TYPE_CHECKING: - import expensive_mod + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.0 - def fun(arg: 'expensive_mod.SomeType') -> None: - local_var: expensive_mod.AnotherType = other_fun() + .. deprecated:: 3.9 + :class:`contextlib.AbstractContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - The first type annotation must be enclosed in quotes, making it a - "forward reference", to hide the ``expensive_mod`` reference from the - interpreter runtime. Type annotations for local variables are not - evaluated, so the second annotation does not need to be enclosed in quotes. +.. class:: AsyncContextManager(Generic[T_co]) - .. note:: + Deprecated alias to :class:`contextlib.AbstractAsyncContextManager`. - If ``from __future__ import annotations`` is used, - annotations are not evaluated at function definition time. - Instead, they are stored as strings in ``__annotations__``. - This makes it unnecessary to use quotes around the annotation - (see :pep:`563`). + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.2 - .. versionadded:: 3.5.2 + .. deprecated:: 3.9 + :class:`contextlib.AbstractAsyncContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Deprecation Timeline of Major Features ====================================== From 638c2bacde87abbcc7dc067564941d707aed788c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 14 Jun 2023 17:36:40 -0700 Subject: [PATCH 0215/1206] [3.12] gh-105800: Issue SyntaxWarning in f-strings for invalid escape sequences (GH-105801) (#105806) Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_fstring.py | 3 +++ .../2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst | 2 ++ Parser/action_helpers.c | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 031b94d8d58a39..cbb03080f797bc 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -907,6 +907,9 @@ def test_backslashes_in_string_part(self): with self.assertWarns(DeprecationWarning): # invalid escape sequence value = eval(r"f'\{6*7}'") self.assertEqual(value, '\\42') + with self.assertWarns(SyntaxWarning): # invalid escape sequence + value = eval(r"f'\g'") + self.assertEqual(value, '\\g') self.assertEqual(f'\\{6*7}', '\\42') self.assertEqual(fr'\{6*7}', '\\42') diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst new file mode 100644 index 00000000000000..d6ef7b68b833c6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst @@ -0,0 +1,2 @@ +Correctly issue :exc:`SyntaxWarning` in f-strings if invalid sequences are +used. Patch by Pablo Galindo diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 9f5135380db1b2..dbad56b5164b6f 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1231,7 +1231,7 @@ _PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq // Fstring stuff static expr_ty -_PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant) { +_PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant, Token* token) { assert(PyUnicode_CheckExact(constant->v.Constant.value)); const char* bstr = PyUnicode_AsUTF8(constant->v.Constant.value); @@ -1247,7 +1247,7 @@ _PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant) { } is_raw = is_raw || strchr(bstr, '\\') == NULL; - PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, NULL); + PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, token); if (str == NULL) { _Pypegen_raise_decode_error(p); return NULL; @@ -1321,7 +1321,7 @@ _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b for (Py_ssize_t i = 0; i < n_items; i++) { expr_ty item = asdl_seq_GET(expr, i); if (item->kind == Constant_kind) { - item = _PyPegen_decode_fstring_part(p, is_raw, item); + item = _PyPegen_decode_fstring_part(p, is_raw, item, b); if (item == NULL) { return NULL; } From 335fbd65db695d29f481b6a8559c391d919099be Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 14 Jun 2023 20:30:00 -0700 Subject: [PATCH 0216/1206] [3.12] gh-105196: Fix indentations of section headings in C API docs (GH-105672) (#105782) gh-105196: Fix indentations of section headings in C API docs (GH-105672) (cherry picked from commit d32e8d6070057eb7ad0eb2f9d9f1efab38b2cff4) Co-authored-by: TATHAGATA ROY --- Doc/c-api/float.rst | 8 ++++---- Doc/c-api/frame.rst | 2 +- Doc/c-api/slice.rst | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 05b2d100d575cb..0118bea4e720f8 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -3,7 +3,7 @@ .. _floatobjects: Floating Point Objects ----------------------- +====================== .. index:: pair: object; floating point @@ -79,7 +79,7 @@ Floating Point Objects Pack and Unpack functions -========================= +------------------------- The pack and unpack functions provide an efficient platform-independent way to store floating-point values as byte strings. The Pack routines produce a bytes @@ -104,7 +104,7 @@ happens in such cases is partly accidental (alas). .. versionadded:: 3.11 Pack functions --------------- +^^^^^^^^^^^^^^ The pack routines write 2, 4 or 8 bytes, starting at *p*. *le* is an :c:expr:`int` argument, non-zero if you want the bytes string in little-endian @@ -135,7 +135,7 @@ There are two problems on non-IEEE platforms: Unpack functions ----------------- +^^^^^^^^^^^^^^^^ The unpack routines read 2, 4 or 8 bytes, starting at *p*. *le* is an :c:expr:`int` argument, non-zero if the bytes string is in little-endian format diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst index 9f7addfbbf3cb4..1accee2767a485 100644 --- a/Doc/c-api/frame.rst +++ b/Doc/c-api/frame.rst @@ -134,7 +134,7 @@ See also :ref:`Reflection `. Internal Frames ---------------- +^^^^^^^^^^^^^^^ Unless using :pep:`523`, you will not need this. diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst index 8271d9acfb645e..33169ccce89043 100644 --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -113,7 +113,7 @@ Slice Objects Ellipsis Object ---------------- +^^^^^^^^^^^^^^^ .. c:var:: PyObject *Py_Ellipsis From 1573f1605ffd6c7949c4e08c5f96389ad02d4291 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 14 Jun 2023 23:12:26 -0700 Subject: [PATCH 0217/1206] [3.12] Improve docs for `typing.dataclass_transform` (GH-105792) (#105809) Improve docs for `typing.dataclass_transform` (GH-105792) (cherry picked from commit 006a4532058f1fadba93283c0f45b0d82735b364) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 106 +++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 7e10b03eaa89dd..67e4a27a291bc7 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2526,16 +2526,19 @@ Functions and decorators .. versionadded:: 3.11 -.. decorator:: dataclass_transform +.. decorator:: dataclass_transform(*, eq_default=True, order_default=False, \ + kw_only_default=False, frozen_default=False, \ + field_specifiers=(), **kwargs) Decorator to mark an object as providing - :func:`~dataclasses.dataclass`-like behavior. + :func:`dataclass `-like behavior. ``dataclass_transform`` may be used to decorate a class, metaclass, or a function that is itself a decorator. The presence of ``@dataclass_transform()`` tells a static type checker that the decorated object performs runtime "magic" that - transforms a class in a similar way to :func:`dataclasses.dataclass`. + transforms a class in a similar way to + :func:`@dataclasses.dataclass `. Example usage with a decorator function: @@ -2589,42 +2592,71 @@ Functions and decorators customize the default behaviors of the decorated class, metaclass, or function: - * ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - ``True`` or ``False`` if it is omitted by the caller. - * ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``frozen_default`` indicates whether the ``frozen`` parameter is - assumed to be True or False if it is omitted by the caller. - - .. versionadded:: 3.12 - * ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - * Arbitrary other keyword arguments are accepted in order to allow for - possible future extensions. - - Type checkers recognize the following optional arguments on field + :param bool eq_default: + Indicates whether the ``eq`` parameter is assumed to be + ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``True``. + + :param bool order_default: + Indicates whether the ``order`` parameter is + assumed to be ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``False``. + + :param bool kw_only_default: + Indicates whether the ``kw_only`` parameter is + assumed to be ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``False``. + + :param bool frozen_default: + Indicates whether the ``frozen`` parameter is + assumed to be ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``False``. + + .. versionadded:: 3.12 + + :param field_specifiers: + Specifies a static list of supported classes + or functions that describe fields, similar to :func:`dataclasses.field`. + Defaults to ``()``. + :type field_specifiers: tuple[Callable[..., Any], ...] + + :param Any \**kwargs: + Arbitrary other keyword arguments are accepted in order to allow for + possible future extensions. + + Type checkers recognize the following optional parameters on field specifiers: - * ``init`` indicates whether the field should be included in the - synthesized ``__init__`` method. If unspecified, ``init`` defaults to - ``True``. - * ``default`` provides the default value for the field. - * ``default_factory`` provides a runtime callback that returns the - default value for the field. If neither ``default`` nor - ``default_factory`` are specified, the field is assumed to have no - default value and must be provided a value when the class is - instantiated. - * ``factory`` is an alias for ``default_factory``. - * ``kw_only`` indicates whether the field should be marked as - keyword-only. If ``True``, the field will be keyword-only. If - ``False``, it will not be keyword-only. If unspecified, the value of - the ``kw_only`` parameter on the object decorated with - ``dataclass_transform`` will be used, or if that is unspecified, the - value of ``kw_only_default`` on ``dataclass_transform`` will be used. - * ``alias`` provides an alternative name for the field. This alternative - name is used in the synthesized ``__init__`` method. + .. list-table:: **Recognised parameters for field specifiers** + :header-rows: 1 + :widths: 20 80 + + * - Parameter name + - Description + * - ``init`` + - Indicates whether the field should be included in the + synthesized ``__init__`` method. If unspecified, ``init`` defaults to + ``True``. + * - ``default`` + - Provides the default value for the field. + * - ``default_factory`` + - Provides a runtime callback that returns the + default value for the field. If neither ``default`` nor + ``default_factory`` are specified, the field is assumed to have no + default value and must be provided a value when the class is + instantiated. + * - ``factory`` + - An alias for the ``default_factory`` parameter on field specifiers. + * - ``kw_only`` + - Indicates whether the field should be marked as + keyword-only. If ``True``, the field will be keyword-only. If + ``False``, it will not be keyword-only. If unspecified, the value of + the ``kw_only`` parameter on the object decorated with + ``dataclass_transform`` will be used, or if that is unspecified, the + value of ``kw_only_default`` on ``dataclass_transform`` will be used. + * - ``alias`` + - Provides an alternative name for the field. This alternative + name is used in the synthesized ``__init__`` method. At runtime, this decorator records its arguments in the ``__dataclass_transform__`` attribute on the decorated object. From 9012c55af8877eedc0a35955b01281958703c6e2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 14 Jun 2023 23:12:42 -0700 Subject: [PATCH 0218/1206] [3.12] More reorganisation of the typing docs (GH-105787) (#105810) More reorganisation of the typing docs (GH-105787) (cherry picked from commit da911a6b226ca47cc15088d800b575e19a731f1c) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 218 ++++++++++++++++++++++------------------- 1 file changed, 117 insertions(+), 101 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 67e4a27a291bc7..5c7ddc7e5a29b0 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2420,6 +2420,18 @@ These protocols are decorated with :func:`runtime_checkable`. An ABC with one abstract method ``__round__`` that is covariant in its return type. +ABCs for working with IO +------------------------ + +.. class:: IO + TextIO + BinaryIO + + Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` + and ``BinaryIO(IO[bytes])`` + represent the types of I/O streams such as returned by + :func:`open`. + Functions and decorators ------------------------ @@ -3007,11 +3019,15 @@ Constant .. versionadded:: 3.5.2 -Generic concrete collections ----------------------------- +.. _generic-concrete-collections: -Corresponding to built-in types -""""""""""""""""""""""""""""""" +Deprecated aliases +------------------ + +.. _corresponding-to-built-in-types: + +Aliases to built-in types +""""""""""""""""""""""""" .. class:: Dict(dict, MutableMapping[KT, VT]) @@ -3073,8 +3089,10 @@ Corresponding to built-in types .. note:: :data:`Tuple` is a special form. -Corresponding to types in :mod:`collections` -"""""""""""""""""""""""""""""""""""""""""""" +.. _corresponding-to-types-in-collections: + +Aliases to types in :mod:`collections` +"""""""""""""""""""""""""""""""""""""" .. class:: DefaultDict(collections.defaultdict, MutableMapping[KT, VT]) @@ -3129,17 +3147,10 @@ Corresponding to types in :mod:`collections` :class:`collections.deque` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -Other concrete types -"""""""""""""""""""" +.. _other-concrete-types: -.. class:: IO - TextIO - BinaryIO - - Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` - and ``BinaryIO(IO[bytes])`` - represent the types of I/O streams such as returned by - :func:`open`. +Aliases to other concrete types +""""""""""""""""""""""""""""""" .. deprecated-removed:: 3.8 3.13 The ``typing.io`` namespace is deprecated and will be removed. @@ -3186,11 +3197,11 @@ Other concrete types currently planned, but users are encouraged to use :class:`str` instead of ``Text``. -Abstract Base Classes ---------------------- +.. _abstract-base-classes: +.. _corresponding-to-collections-in-collections-abc: -Corresponding to collections in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" +Aliases to container ABCs in :mod:`collections.abc` +""""""""""""""""""""""""""""""""""""""""""""""""""" .. class:: AbstractSet(Collection[T_co]) @@ -3305,86 +3316,10 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.ValuesView` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -Corresponding to other types in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" - -.. class:: Iterable(Generic[T_co]) - - Deprecated alias to :class:`collections.abc.Iterable`. - - .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Iterator(Iterable[T_co]) - - Deprecated alias to :class:`collections.abc.Iterator`. - - .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) - - Deprecated alias to :class:`collections.abc.Generator`. - - A generator can be annotated by the generic type - ``Generator[YieldType, SendType, ReturnType]``. For example:: - - def echo_round() -> Generator[int, float, str]: - sent = yield 0 - while sent >= 0: - sent = yield round(sent) - return 'Done' - - Note that unlike many other generics in the typing module, the ``SendType`` - of :class:`Generator` behaves contravariantly, not covariantly or - invariantly. - - If your generator will only yield values, set the ``SendType`` and - ``ReturnType`` to ``None``:: - - def infinite_stream(start: int) -> Generator[int, None, None]: - while True: - yield start - start += 1 - - Alternatively, annotate your generator as having a return type of - either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: - - def infinite_stream(start: int) -> Iterator[int]: - while True: - yield start - start += 1 - - .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Hashable - - Deprecated alias to :class:`collections.abc.Hashable`. - - .. deprecated:: 3.12 - Use :class:`collections.abc.Hashable` directly instead. - -.. class:: Reversible(Iterable[T_co]) - - Deprecated alias to :class:`collections.abc.Reversible`. +.. _asynchronous-programming: - .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Sized - - Deprecated alias to :class:`collections.abc.Sized`. - - .. deprecated:: 3.12 - Use :class:`collections.abc.Sized` directly instead. - -Asynchronous programming -"""""""""""""""""""""""" +Aliases to asynchronous ABCs in :mod:`collections.abc` +"""""""""""""""""""""""""""""""""""""""""""""""""""""" .. class:: Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType]) @@ -3475,9 +3410,90 @@ Asynchronous programming :class:`collections.abc.Awaitable` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. +.. _corresponding-to-other-types-in-collections-abc: + +Aliases to other ABCs in :mod:`collections.abc` +""""""""""""""""""""""""""""""""""""""""""""""" + +.. class:: Iterable(Generic[T_co]) + + Deprecated alias to :class:`collections.abc.Iterable`. + + .. deprecated:: 3.9 + :class:`collections.abc.Iterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Iterator(Iterable[T_co]) + + Deprecated alias to :class:`collections.abc.Iterator`. + + .. deprecated:: 3.9 + :class:`collections.abc.Iterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) + + Deprecated alias to :class:`collections.abc.Generator`. + + A generator can be annotated by the generic type + ``Generator[YieldType, SendType, ReturnType]``. For example:: + + def echo_round() -> Generator[int, float, str]: + sent = yield 0 + while sent >= 0: + sent = yield round(sent) + return 'Done' + + Note that unlike many other generics in the typing module, the ``SendType`` + of :class:`Generator` behaves contravariantly, not covariantly or + invariantly. + + If your generator will only yield values, set the ``SendType`` and + ``ReturnType`` to ``None``:: + + def infinite_stream(start: int) -> Generator[int, None, None]: + while True: + yield start + start += 1 + + Alternatively, annotate your generator as having a return type of + either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: + + def infinite_stream(start: int) -> Iterator[int]: + while True: + yield start + start += 1 + + .. deprecated:: 3.9 + :class:`collections.abc.Generator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Hashable + + Deprecated alias to :class:`collections.abc.Hashable`. + + .. deprecated:: 3.12 + Use :class:`collections.abc.Hashable` directly instead. + +.. class:: Reversible(Iterable[T_co]) + + Deprecated alias to :class:`collections.abc.Reversible`. + + .. deprecated:: 3.9 + :class:`collections.abc.Reversible` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Sized + + Deprecated alias to :class:`collections.abc.Sized`. + + .. deprecated:: 3.12 + Use :class:`collections.abc.Sized` directly instead. + +.. _context-manager-types: -Context manager types -""""""""""""""""""""" +Aliases to :mod:`contextlib` ABCs +""""""""""""""""""""""""""""""""" .. class:: ContextManager(Generic[T_co]) From 3073e232291915e969af8f54653bf28256fc76b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 15 Jun 2023 04:13:22 -0700 Subject: [PATCH 0219/1206] [3.12] gh-105821: Use a raw f-string in test_httpservers.py (GH-105822) (#105824) gh-105821: Use a raw f-string in test_httpservers.py (GH-105822) Use a raw f-string in test_httpservers.py (cherry picked from commit 09ce8c3b48f940eb8865330f029b8069854c3106) Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_httpservers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index cdd1bea754a020..cfd8a101dcc1c1 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -442,10 +442,10 @@ def test_undecodable_filename(self): def test_undecodable_parameter(self): # sanity check using a valid parameter response = self.request(self.base_url + '/?x=123').read() - self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1')) + self.assertRegex(response, rf'listing for {self.base_url}/\?x=123'.encode('latin1')) # now the bogus encoding response = self.request(self.base_url + '/?x=%bb').read() - self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) + self.assertRegex(response, rf'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) def test_get_dir_redirect_location_domain_injection_bug(self): """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. From abb4eaa46fc386b0244370c711f0af90c575e27f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 15 Jun 2023 07:56:04 -0700 Subject: [PATCH 0220/1206] [3.12] gh-102541: Hide traceback in help prompt (gh-102614) (gh-105778) gh-102541: Hide traceback in help prompt (gh-102614) (cherry picked from commit ba516e70c6d156dc59dede35b6fc3db0151780a5) Co-authored-by: Kirill Podoprigora --- Lib/pydoc.py | 21 ++++++++++++------- ...-03-12-01-17-15.gh-issue-102541.LK1adc.rst | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 84e673a7f87f90..d69369d4196eaa 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1780,10 +1780,15 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0, return title % desc + '\n\n' + renderer.document(object, name) def doc(thing, title='Python Library Documentation: %s', forceload=0, - output=None): + output=None, is_cli=False): """Display text documentation, given an object or a path to an object.""" if output is None: - pager(render_doc(thing, title, forceload)) + try: + pager(render_doc(thing, title, forceload)) + except ImportError as exc: + if is_cli: + raise + print(exc) else: output.write(render_doc(thing, title, forceload, plaintext)) @@ -2044,7 +2049,7 @@ def getline(self, prompt): self.output.flush() return self.input.readline() - def help(self, request): + def help(self, request, is_cli=False): if isinstance(request, str): request = request.strip() if request == 'keywords': self.listkeywords() @@ -2056,13 +2061,13 @@ def help(self, request): elif request in self.symbols: self.showsymbol(request) elif request in ['True', 'False', 'None']: # special case these keywords since they are objects too - doc(eval(request), 'Help on %s:') + doc(eval(request), 'Help on %s:', is_cli=is_cli) elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) - elif request: doc(request, 'Help on %s:', output=self._output) - else: doc(str, 'Help on %s:', output=self._output) + elif request: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) + else: doc(str, 'Help on %s:', output=self._output, is_cli=is_cli) elif isinstance(request, Helper): self() - else: doc(request, 'Help on %s:', output=self._output) + else: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) self.output.write('\n') def intro(self): @@ -2800,7 +2805,7 @@ class BadUsage(Exception): pass else: writedoc(arg) else: - help.help(arg) + help.help(arg, is_cli=True) except (ImportError, ErrorDuringImport) as value: print(value) sys.exit(1) diff --git a/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst b/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst new file mode 100644 index 00000000000000..45b10679e19e2d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst @@ -0,0 +1 @@ +Hide traceback in :func:`help` prompt, when import failed. From e9cf5a324e10b693d464692ab19422c40d5e179f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 15 Jun 2023 10:21:58 -0700 Subject: [PATCH 0221/1206] [3.12] gh-105820: Fix tok_mode expression buffer in file & readline tokenizer (GH-105828) (#105832) (cherry picked from commit d382ad49157b3802fc5619f68d96810def517869) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_fstring.py | 15 ++++++++++++++- Lib/test/test_tokenize.py | 13 +++++++++++++ ...2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst | 3 +++ Parser/tokenizer.c | 11 ++++++++--- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index cbb03080f797bc..8f6b576b5f785f 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -15,7 +15,7 @@ import unittest from test import support from test.support.os_helper import temp_cwd -from test.support.script_helper import assert_python_failure +from test.support.script_helper import assert_python_failure, assert_python_ok a_global = 'global variable' @@ -1635,5 +1635,18 @@ def test_syntax_error_after_debug(self): "f'{1=}{1;}'", ]) + def test_debug_in_file(self): + with temp_cwd(): + script = 'script.py' + with open('script.py', 'w') as f: + f.write(f"""\ +print(f'''{{ +3 +=}}''')""") + + _, stdout, _ = assert_python_ok(script) + self.assertEqual(stdout.decode('utf-8').strip().replace('\r\n', '\n').replace('\r', '\n'), + "3\n=3") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 15f53632cff814..5ad278499c9df9 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -558,6 +558,19 @@ def test_string(self): OP '}' (1, 39) (1, 40) FSTRING_MIDDLE ' final words' (1, 40) (1, 52) FSTRING_END "'" (1, 52) (1, 53) + """) + self.check_tokenize("""\ +f'''{ +3 +=}'''""", """\ + FSTRING_START "f'''" (1, 0) (1, 4) + OP '{' (1, 4) (1, 5) + NL '\\n' (1, 5) (1, 6) + NUMBER '3' (2, 0) (2, 1) + NL '\\n' (2, 1) (2, 2) + OP '=' (3, 0) (3, 1) + OP '}' (3, 1) (3, 2) + FSTRING_END "'''" (3, 2) (3, 5) """) def test_function(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst new file mode 100644 index 00000000000000..407940add56752 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst @@ -0,0 +1,3 @@ +Fix an f-string bug, where using a debug expression (the ``=`` sign) that +appears in the last line of a file results to the debug buffer that holds the +expression text being one character too small. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index f41dd130af1f7d..1a59f542409fe6 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1039,9 +1039,6 @@ tok_readline_raw(struct tok_state *tok) if (line == NULL) { return 1; } - if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { - return 0; - } if (tok->fp_interactive && tok_concatenate_interactive_new_line(tok, line) == -1) { return 0; @@ -1270,6 +1267,10 @@ tok_underflow_file(struct tok_state *tok) { tok->implicit_newline = 1; } + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } + ADVANCE_LINENO(); if (tok->decoding_state != STATE_NORMAL) { if (tok->lineno > 2) { @@ -1314,6 +1315,10 @@ tok_underflow_readline(struct tok_state* tok) { tok->implicit_newline = 1; } + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } + ADVANCE_LINENO(); /* The default encoding is UTF-8, so make sure we don't have any non-UTF-8 sequences in it. */ From 0add51672d8c8db4b18838dd592991a6cd9b55ca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 15 Jun 2023 16:12:01 -0700 Subject: [PATCH 0222/1206] [3.12] GH-105588: Add missing error checks to some obj2ast_* converters (GH-105838) GH-105588: Add missing error checks to some obj2ast_* converters (GH-105589) (cherry picked from commit a4056c8f9c2d9970d39e3cb6bffb255cd4b8a42c) Co-authored-by: Brandt Bucher --- Lib/test/test_ast.py | 27 +++++++++++++++++++ ...-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst | 2 ++ Parser/asdl_c.py | 1 + Python/Python-ast.c | 7 +++++ 4 files changed, 37 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index ffd082ec11806a..a03fa4c7187b05 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -3,6 +3,7 @@ import dis import enum import os +import re import sys import textwrap import types @@ -1110,6 +1111,32 @@ def test_null_bytes(self): msg="source code string cannot contain null bytes"): ast.parse("a\0b") + def assert_none_check(self, node: type[ast.AST], attr: str, source: str) -> None: + with self.subTest(f"{node.__name__}.{attr}"): + tree = ast.parse(source) + found = 0 + for child in ast.walk(tree): + if isinstance(child, node): + setattr(child, attr, None) + found += 1 + self.assertEqual(found, 1) + e = re.escape(f"field '{attr}' is required for {node.__name__}") + with self.assertRaisesRegex(ValueError, f"^{e}$"): + compile(tree, "", "exec") + + def test_none_checks(self) -> None: + tests = [ + (ast.alias, "name", "import spam as SPAM"), + (ast.arg, "arg", "def spam(SPAM): spam"), + (ast.comprehension, "target", "[spam for SPAM in spam]"), + (ast.comprehension, "iter", "[spam for spam in SPAM]"), + (ast.keyword, "value", "spam(**SPAM)"), + (ast.match_case, "pattern", "match spam:\n case SPAM: spam"), + (ast.withitem, "context_expr", "with SPAM: spam"), + ] + for node, attr, source in tests: + self.assert_none_check(node, attr, source) + class ASTHelpers_Test(unittest.TestCase): maxDiff = None diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst new file mode 100644 index 00000000000000..3981dad7a49dfb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst @@ -0,0 +1,2 @@ +Fix an issue that could result in crashes when compiling malformed +:mod:`ast` nodes. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index cb312796f89e04..d4763ea260a5a2 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -601,6 +601,7 @@ def visitProduct(self, prod, name): args = [f.name for f in prod.fields] args.extend([a.name for a in prod.attributes]) self.emit("*out = %s(%s);" % (ast_func_name(name), self.buildArgs(args)), 1) + self.emit("if (*out == NULL) goto failed;", 1) self.emit("return 0;", 1) self.emit("failed:", 0) self.emit("Py_XDECREF(tmp);", 1) diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 84bce59e271471..1ffb8354e3a1b1 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -10834,6 +10834,7 @@ obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* Py_CLEAR(tmp); } *out = _PyAST_comprehension(target, iter, ifs, is_async, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11258,6 +11259,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, } *out = _PyAST_arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11397,6 +11399,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) } *out = _PyAST_arg(arg, annotation, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11519,6 +11522,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, } *out = _PyAST_keyword(arg, value, lineno, col_offset, end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11641,6 +11645,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* } *out = _PyAST_alias(name, asname, lineno, col_offset, end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11690,6 +11695,7 @@ obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out, Py_CLEAR(tmp); } *out = _PyAST_withitem(context_expr, optional_vars, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11778,6 +11784,7 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, Py_CLEAR(tmp); } *out = _PyAST_match_case(pattern, guard, body, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); From 0cb670f7e2c7b5951e520d7bd5ca20d103ba8810 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 15 Jun 2023 18:26:45 -0700 Subject: [PATCH 0223/1206] [3.12] gh-105433: Add `pickle` tests for PEP695 (GH-105443) (#105845) (cherry picked from commit 1af8251d9ec2f18e131c19ccf776fb9ec132c7a8) Co-authored-by: Nikita Sobolev --- Lib/test/test_type_aliases.py | 69 +++++++++++++++++++++++++++++++++-- Lib/test/test_type_params.py | 66 +++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index a3067e521e023e..b9b24448e83d8e 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -228,8 +228,69 @@ def test_module(self): self.assertEqual(mod_generics_cache.OldStyle.__module__, mod_generics_cache.__name__) + +# All these type aliases are used for pickling tests: +T = TypeVar('T') +type SimpleAlias = int +type RecursiveAlias = dict[str, RecursiveAlias] +type GenericAlias[X] = list[X] +type GenericAliasMultipleTypes[X, Y] = dict[X, Y] +type RecursiveGenericAlias[X] = dict[str, RecursiveAlias[X]] +type BoundGenericAlias[X: int] = set[X] +type ConstrainedGenericAlias[LongName: (str, bytes)] = list[LongName] +type AllTypesAlias[A, *B, **C] = Callable[C, A] | tuple[*B] + + +class TypeAliasPickleTest(unittest.TestCase): def test_pickling(self): - pickled = pickle.dumps(mod_generics_cache.Alias) - self.assertIs(pickle.loads(pickled), mod_generics_cache.Alias) - pickled = pickle.dumps(mod_generics_cache.OldStyle) - self.assertIs(pickle.loads(pickled), mod_generics_cache.OldStyle) + things_to_test = [ + SimpleAlias, + RecursiveAlias, + + GenericAlias, + GenericAlias[T], + GenericAlias[int], + + GenericAliasMultipleTypes, + GenericAliasMultipleTypes[str, T], + GenericAliasMultipleTypes[T, str], + GenericAliasMultipleTypes[int, str], + + RecursiveGenericAlias, + RecursiveGenericAlias[T], + RecursiveGenericAlias[int], + + BoundGenericAlias, + BoundGenericAlias[int], + BoundGenericAlias[T], + + ConstrainedGenericAlias, + ConstrainedGenericAlias[str], + ConstrainedGenericAlias[T], + + AllTypesAlias, + AllTypesAlias[int, str, T, [T, object]], + + # Other modules: + mod_generics_cache.Alias, + mod_generics_cache.OldStyle, + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + self.assertEqual(pickle.loads(pickled), thing) + + type ClassLevel = str + + def test_pickling_local(self): + type A = int + things_to_test = [ + self.ClassLevel, + A, + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + with self.assertRaises(pickle.PickleError): + pickle.dumps(thing, protocol=proto) diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 6475df6f5bba43..3026cc22476619 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -2,6 +2,7 @@ import textwrap import types import unittest +import pickle from test.support import requires_working_socket, check_syntax_error, run_code from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args @@ -855,3 +856,68 @@ def func[A](): ns = run_code(code) self.assertEqual(ns["func"].__type_params__, ()) + + + +# All these type aliases are used for pickling tests: +T = TypeVar('T') +def func1[X](x: X) -> X: ... +def func2[X, Y](x: X | Y) -> X | Y: ... +def func3[X, *Y, **Z](x: X, y: tuple[*Y], z: Z) -> X: ... +def func4[X: int, Y: (bytes, str)](x: X, y: Y) -> X | Y: ... + +class Class1[X]: ... +class Class2[X, Y]: ... +class Class3[X, *Y, **Z]: ... +class Class4[X: int, Y: (bytes, str)]: ... + + +class TypeParamsPickleTest(unittest.TestCase): + def test_pickling_functions(self): + things_to_test = [ + func1, + func2, + func3, + func4, + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + self.assertEqual(pickle.loads(pickled), thing) + + def test_pickling_classes(self): + things_to_test = [ + Class1, + Class1[int], + Class1[T], + + Class2, + Class2[int, T], + Class2[T, int], + Class2[int, str], + + Class3, + Class3[int, T, str, bytes, [float, object, T]], + + Class4, + Class4[int, bytes], + Class4[T, bytes], + Class4[int, T], + Class4[T, T], + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + self.assertEqual(pickle.loads(pickled), thing) + + for klass in things_to_test: + real_class = getattr(klass, '__origin__', klass) + thing = klass() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + # These instances are not equal, + # but class check is good enough: + self.assertIsInstance(pickle.loads(pickled), real_class) From f94cb788f96c2ba29f6d2f19dd0bb08256072ef9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 15 Jun 2023 22:43:19 -0700 Subject: [PATCH 0224/1206] [3.12] tarfile: Fix positional-only syntax in docs (GH-105770) (#105773) The syntax used in the current docs (a / before any args) is invalid. I think the right approach is for the arguments to arbitrary filter functions to be treated as positional-only, meaning that users can supply filter functions with any names for the argument. tarfile.py only calls the filter function with positional arguments. (cherry picked from commit 5cdd5ba49db10f05e204e7a49ce184222a93dce8) Co-authored-by: Jelle Zijlstra --- Doc/library/tarfile.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 891af1bcf7edff..6a5947b788fdae 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -903,7 +903,7 @@ can be: path to where the archive is extracted (i.e. the same path is used for all members):: - filter(/, member: TarInfo, path: str) -> TarInfo | None + filter(member: TarInfo, path: str, /) -> TarInfo | None The callable is called just before each member is extracted, so it can take the current state of the disk into account. @@ -923,13 +923,13 @@ Default named filters The pre-defined, named filters are available as functions, so they can be reused in custom filters: -.. function:: fully_trusted_filter(/, member, path) +.. function:: fully_trusted_filter(member, path) Return *member* unchanged. This implements the ``'fully_trusted'`` filter. -.. function:: tar_filter(/, member, path) +.. function:: tar_filter(member, path) Implements the ``'tar'`` filter. @@ -946,7 +946,7 @@ reused in custom filters: Return the modified ``TarInfo`` member. -.. function:: data_filter(/, member, path) +.. function:: data_filter(member, path) Implements the ``'data'`` filter. In addition to what ``tar_filter`` does: From 6f0f27eba0f41375ae12a37c6cc8a278526917a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 00:56:40 -0700 Subject: [PATCH 0225/1206] [3.12] Fix inaccuracies in "Assorted Topics" section of "Defining Extension Types" tutorial (GH-104969) (#105850) Fix inaccuracies in "Assorted Topics" section of "Defining Extension Types" tutorial (GH-104969) (cherry picked from commit 0d0963737a0f4b7cadedfae7e8fd33ed18269289) Co-authored-by: chgnrdv <52372310+chgnrdv@users.noreply.github.com> --- Doc/extending/newtypes.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 6852a385f0c63c..7f8f8ddaaaccd6 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -168,7 +168,7 @@ representation of the instance for which it is called. Here is a simple example:: static PyObject * - newdatatype_repr(newdatatypeobject * obj) + newdatatype_repr(newdatatypeobject *obj) { return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); @@ -188,7 +188,7 @@ used instead. Here is a simple example:: static PyObject * - newdatatype_str(newdatatypeobject * obj) + newdatatype_str(newdatatypeobject *obj) { return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); @@ -338,7 +338,7 @@ Here is an example:: PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.400s'", - tp->tp_name, name); + Py_TYPE(obj)->tp_name, name); return NULL; } @@ -379,7 +379,7 @@ Here is a sample implementation, for a datatype that is considered equal if the size of an internal pointer is equal:: static PyObject * - newdatatype_richcmp(PyObject *obj1, PyObject *obj2, int op) + newdatatype_richcmp(newdatatypeobject *obj1, newdatatypeobject *obj2, int op) { PyObject *result; int c, size1, size2; @@ -478,7 +478,7 @@ This function takes three arguments: Here is a toy ``tp_call`` implementation:: static PyObject * - newdatatype_call(newdatatypeobject *self, PyObject *args, PyObject *kwds) + newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *kwds) { PyObject *result; const char *arg1; From 1eeb2e62d0a7d37fea192df47d7a8ec1227bef6d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 01:56:32 -0700 Subject: [PATCH 0226/1206] [3.12] gh-105844: Consistently use 'minor version' for X.Y versions (GH-105851) (#105853) (cherry picked from commit 0bffe1acd78069ea21f6b1347bec9cc9747342cb) Co-authored-by: Erlend E. Aasland --- Doc/faq/general.rst | 4 ++-- Doc/install/index.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index a9b2622e02ef3b..298ce111698a65 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -135,7 +135,7 @@ Python versions are numbered "A.B.C" or "A.B": See :pep:`6` for more information about bugfix releases. -Not all releases are bugfix releases. In the run-up to a new major release, a +Not all releases are bugfix releases. In the run-up to a new minor release, a series of development releases are made, denoted as alpha, beta, or release candidate. Alphas are early releases in which interfaces aren't yet finalized; it's not unexpected to see an interface change between two alpha releases. @@ -297,7 +297,7 @@ How stable is Python? Very stable. New, stable releases have been coming out roughly every 6 to 18 months since 1991, and this seems likely to continue. As of version 3.9, -Python will have a major new release every 12 months (:pep:`602`). +Python will have a minor new release every 12 months (:pep:`602`). The developers issue "bugfix" releases of older versions, so the stability of existing releases gradually improves. Bugfix releases, indicated by a third diff --git a/Doc/install/index.rst b/Doc/install/index.rst index ab581d785ef7f0..beb34f0cf21b22 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -696,7 +696,7 @@ is supplied to suppress this behaviour. So you could simply edit import sys sys.path.append('/www/python/') -However, if you reinstall the same major version of Python (perhaps when +However, if you reinstall the same minor version of Python (perhaps when upgrading from 2.2 to 2.2.2, for example) :file:`site.py` will be overwritten by the stock version. You'd have to remember that it was modified and save a copy before doing the installation. From 32d8b56dff65f8e1634ebe965357bd60719241b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 04:30:36 -0700 Subject: [PATCH 0227/1206] [3.12] CI: Remove docs build from Azure Pipelines (GH-105823) (#105854) Co-authored-by: Hugo van Kemenade --- .azure-pipelines/ci.yml | 14 --------- .azure-pipelines/docs-steps.yml | 47 ---------------------------- .azure-pipelines/pr.yml | 12 ------- .azure-pipelines/prebuild-checks.yml | 12 ------- 4 files changed, 85 deletions(-) delete mode 100644 .azure-pipelines/docs-steps.yml diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index fb4a2218ddd8d8..63252a76abb69f 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -14,20 +14,6 @@ jobs: - template: ./prebuild-checks.yml -- job: Docs_PR - displayName: Docs PR - dependsOn: Prebuild - condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true')) - - pool: - vmImage: ubuntu-22.04 - - steps: - - template: ./docs-steps.yml - parameters: - upload: true - - - job: macOS_CI_Tests displayName: macOS CI Tests dependsOn: Prebuild diff --git a/.azure-pipelines/docs-steps.yml b/.azure-pipelines/docs-steps.yml deleted file mode 100644 index 647daff7a033a8..00000000000000 --- a/.azure-pipelines/docs-steps.yml +++ /dev/null @@ -1,47 +0,0 @@ -parameters: - latex: false - upload: false - -steps: -- checkout: self - clean: true - fetchDepth: 5 - -- task: UsePythonVersion@0 - displayName: 'Use Python 3.6 or later' - inputs: - versionSpec: '>=3.6' - -- script: python -m pip install -r requirements.txt - workingDirectory: '$(build.sourcesDirectory)/Doc' - displayName: 'Install build dependencies' - -- ${{ if ne(parameters.latex, 'true') }}: - - script: make check html PYTHON=python - workingDirectory: '$(build.sourcesDirectory)/Doc' - displayName: 'Build documentation' - -- ${{ if eq(parameters.latex, 'true') }}: - - script: sudo apt-get update && sudo apt-get install -qy --force-yes texlive-full - displayName: 'Install LaTeX' - - - script: make dist PYTHON=python SPHINXBUILD='python -m sphinx' BLURB='python -m blurb' - workingDirectory: '$(build.sourcesDirectory)/Doc' - displayName: 'Build documentation' - -- ${{ if eq(parameters.upload, 'true') }}: - - task: PublishBuildArtifacts@1 - displayName: 'Publish docs' - - inputs: - PathToPublish: '$(build.sourcesDirectory)/Doc/build' - ArtifactName: docs - publishLocation: Container - - - ${{ if eq(parameters.latex, 'true') }}: - - task: PublishBuildArtifacts@1 - displayName: 'Publish dist' - inputs: - PathToPublish: '$(build.sourcesDirectory)/Doc/dist' - ArtifactName: docs_dist - publishLocation: Container diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index b822d58806b9a6..939c9b4249a3c2 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -14,18 +14,6 @@ jobs: - template: ./prebuild-checks.yml -- job: Docs_PR - displayName: Docs PR - dependsOn: Prebuild - condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true')) - - pool: - vmImage: ubuntu-22.04 - - steps: - - template: ./docs-steps.yml - - - job: macOS_PR_Tests displayName: macOS PR Tests dependsOn: Prebuild diff --git a/.azure-pipelines/prebuild-checks.yml b/.azure-pipelines/prebuild-checks.yml index 30ff642d1267a1..2c6460d2386735 100644 --- a/.azure-pipelines/prebuild-checks.yml +++ b/.azure-pipelines/prebuild-checks.yml @@ -11,18 +11,6 @@ steps: displayName: Fetch comparison tree condition: and(succeeded(), variables['System.PullRequest.TargetBranch']) -- script: | - if ! git diff --name-only $(diffTarget) | grep -qE '(\.rst$|^Doc|^Misc)' - then - echo "No docs were updated: docs.run=false" - echo "##vso[task.setvariable variable=run;isOutput=true]false" - else - echo "Docs were updated: docs.run=true" - echo "##vso[task.setvariable variable=run;isOutput=true]true" - fi - displayName: Detect documentation changes - name: docs - - script: | if ! git diff --name-only $(diffTarget) | grep -qvE '(\.rst$|^Doc|^Misc)' then From e6982c58602bba9bc1f7c1e6e9cc5f65610d1c6e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 09:20:19 -0700 Subject: [PATCH 0228/1206] [3.12] gh-105834: Add tests for calling `issubclass()` between two protocols (GH-105835) (#105859) Some parts of the implementation of `typing.Protocol` had poor test coverage (cherry picked from commit 70c075c194d3739ae10ce76265f05fa82ed46487) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7dc64c6ecc9e5b..a1fa54a9f1cad2 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2759,6 +2759,80 @@ def x(self): ... with self.assertRaisesRegex(TypeError, only_classes_allowed): issubclass(1, BadPG) + def test_implicit_issubclass_between_two_protocols(self): + @runtime_checkable + class CallableMembersProto(Protocol): + def meth(self): ... + + # All the below protocols should be considered "subclasses" + # of CallableMembersProto at runtime, + # even though none of them explicitly subclass CallableMembersProto + + class IdenticalProto(Protocol): + def meth(self): ... + + class SupersetProto(Protocol): + def meth(self): ... + def meth2(self): ... + + class NonCallableMembersProto(Protocol): + meth: Callable[[], None] + + class NonCallableMembersSupersetProto(Protocol): + meth: Callable[[], None] + meth2: Callable[[str, int], bool] + + class MixedMembersProto1(Protocol): + meth: Callable[[], None] + def meth2(self): ... + + class MixedMembersProto2(Protocol): + def meth(self): ... + meth2: Callable[[str, int], bool] + + for proto in ( + IdenticalProto, SupersetProto, NonCallableMembersProto, + NonCallableMembersSupersetProto, MixedMembersProto1, MixedMembersProto2 + ): + with self.subTest(proto=proto.__name__): + self.assertIsSubclass(proto, CallableMembersProto) + + # These two shouldn't be considered subclasses of CallableMembersProto, however, + # since they don't have the `meth` protocol member + + class EmptyProtocol(Protocol): ... + class UnrelatedProtocol(Protocol): + def wut(self): ... + + self.assertNotIsSubclass(EmptyProtocol, CallableMembersProto) + self.assertNotIsSubclass(UnrelatedProtocol, CallableMembersProto) + + # These aren't protocols at all (despite having annotations), + # so they should only be considered subclasses of CallableMembersProto + # if they *actually have an attribute* matching the `meth` member + # (just having an annotation is insufficient) + + class AnnotatedButNotAProtocol: + meth: Callable[[], None] + + class NotAProtocolButAnImplicitSubclass: + def meth(self): pass + + class NotAProtocolButAnImplicitSubclass2: + meth: Callable[[], None] + def meth(self): pass + + class NotAProtocolButAnImplicitSubclass3: + meth: Callable[[], None] + meth2: Callable[[int, str], bool] + def meth(self): pass + def meth(self, x, y): return True + + self.assertNotIsSubclass(AnnotatedButNotAProtocol, CallableMembersProto) + self.assertIsSubclass(NotAProtocolButAnImplicitSubclass, CallableMembersProto) + self.assertIsSubclass(NotAProtocolButAnImplicitSubclass2, CallableMembersProto) + self.assertIsSubclass(NotAProtocolButAnImplicitSubclass3, CallableMembersProto) + def test_isinstance_checks_not_at_whim_of_gc(self): self.addCleanup(gc.enable) gc.disable() From 5ca707d1e41af165d6bbc6bbc8026256a0a941d3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 09:59:25 -0700 Subject: [PATCH 0229/1206] [3.12] gh-104799: PEP 695 backward compatibility for ast.unparse (GH-105846) (#105862) (cherry picked from commit 957a974d4fc1575787e4a29a399a47520d6df6d3) Co-authored-by: Jelle Zijlstra --- Lib/ast.py | 6 +- Lib/test/test_unparse.py | 74 ++++++++++++++++++- ...-06-15-18-11-47.gh-issue-104799.BcLzbP.rst | 3 + 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst diff --git a/Lib/ast.py b/Lib/ast.py index 226910ecac0b4a..a307f3ecd06175 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1051,7 +1051,8 @@ def visit_ClassDef(self, node): self.fill("@") self.traverse(deco) self.fill("class " + node.name) - self._type_params_helper(node.type_params) + if hasattr(node, "type_params"): + self._type_params_helper(node.type_params) with self.delimit_if("(", ")", condition = node.bases or node.keywords): comma = False for e in node.bases: @@ -1083,7 +1084,8 @@ def _function_helper(self, node, fill_suffix): self.traverse(deco) def_str = fill_suffix + " " + node.name self.fill(def_str) - self._type_params_helper(node.type_params) + if hasattr(node, "type_params"): + self._type_params_helper(node.type_params) with self.delimit("(", ")"): self.traverse(node.args) if node.returns: diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 88c7c3a0af8771..41a6318d1499b4 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -1,4 +1,4 @@ -"""Tests for the unparse.py script in the Tools/parser directory.""" +"""Tests for ast.unparse.""" import unittest import test.support @@ -625,6 +625,78 @@ def test_star_expr_assign_target_multiple(self): self.check_src_roundtrip("a, b = [c, d] = e, f = g") +class ManualASTCreationTestCase(unittest.TestCase): + """Test that AST nodes created without a type_params field unparse correctly.""" + + def test_class(self): + node = ast.ClassDef(name="X", bases=[], keywords=[], body=[ast.Pass()], decorator_list=[]) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "class X:\n pass") + + def test_class_with_type_params(self): + node = ast.ClassDef(name="X", bases=[], keywords=[], body=[ast.Pass()], decorator_list=[], + type_params=[ast.TypeVar("T")]) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "class X[T]:\n pass") + + def test_function(self): + node = ast.FunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "def f():\n pass") + + def test_function_with_type_params(self): + node = ast.FunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + type_params=[ast.TypeVar("T")], + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "def f[T]():\n pass") + + def test_function_with_type_params_and_bound(self): + node = ast.FunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + type_params=[ast.TypeVar("T", bound=ast.Name("int"))], + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "def f[T: int]():\n pass") + + def test_async_function(self): + node = ast.AsyncFunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "async def f():\n pass") + + def test_async_function_with_type_params(self): + node = ast.AsyncFunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + type_params=[ast.TypeVar("T")], + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "async def f[T]():\n pass") + class DirectoryTestCase(ASTTestCase): """Test roundtrip behaviour on all files in Lib and Lib/test.""" diff --git a/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst b/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst new file mode 100644 index 00000000000000..d0dbff4f1553e2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst @@ -0,0 +1,3 @@ +Enable :func:`ast.unparse` to unparse function and class definitions created +without the new ``type_params`` field from :pep:`695`. Patch by Jelle +Zijlstra. From 32c0aeb8a796d85720c6046ad855cc1eb65f0c98 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 10:17:33 -0700 Subject: [PATCH 0230/1206] [3.12] bpo-44530: Document the change in MAKE_FUNCTION behavior (GH-93189) (#105841) bpo-44530: Document the change in MAKE_FUNCTION behavior (GH-93189) * bpo-44530: Document the change in MAKE_FUNCTION behavior Fixes dis module documentation for MAKE_FUNCTION due to https://github.com/python/cpython/commit/2f180ce2cb6e6a7e3c517495e0f4873d6aaf5f2f (bpo-44530, released as part of 3.11) removes the qualified name at TOS (cherry picked from commit 486b52a3158e0f64fc54efdfa34ed5437b3619f2) Co-authored-by: Alex Doe --- Doc/library/dis.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 9b90f1ef23d92c..3b31384edeb54b 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1389,12 +1389,15 @@ iterations of the loop. * ``0x02`` a dictionary of keyword-only parameters' default values * ``0x04`` a tuple of strings containing parameters' annotations * ``0x08`` a tuple containing cells for free variables, making a closure - * the code associated with the function (at ``STACK[-2]``) - * the :term:`qualified name` of the function (at ``STACK[-1]``) + * the code associated with the function (at ``STACK[-1]``) .. versionchanged:: 3.10 Flag value ``0x04`` is a tuple of strings instead of dictionary + .. versionchanged:: 3.11 + Qualified name at ``STACK[-1]`` was removed. + + .. opcode:: BUILD_SLICE (argc) .. index:: pair: built-in function; slice From 560adb01f97015a6778568e057aa3eeaace3b5f4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 11:29:55 -0700 Subject: [PATCH 0231/1206] [3.12] GH-105840: Fix assertion failures when specializing calls with too many __defaults__ (GH-105863) GH-105840: Fix assertion failures when specializing calls with too many __defaults__ (GH-105847) (cherry picked from commit 2beab5bdef5fa2a00a59371e6137f769586b7404) Co-authored-by: Brandt Bucher --- Lib/test/test_opcache.py | 29 +++++++++++++++++++ ...-06-15-22-11-43.gh-issue-105840.Fum_g_.rst | 2 ++ Python/specialize.c | 4 +-- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 57fed5d09fd7b8..5281eb77c02d1b 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -452,6 +452,35 @@ def f(): self.assertFalse(f()) +class TestCallCache(unittest.TestCase): + def test_too_many_defaults_0(self): + def f(): + pass + + f.__defaults__ = (None,) + for _ in range(1025): + f() + + def test_too_many_defaults_1(self): + def f(x): + pass + + f.__defaults__ = (None, None) + for _ in range(1025): + f(None) + f() + + def test_too_many_defaults_2(self): + def f(x, y): + pass + + f.__defaults__ = (None, None, None) + for _ in range(1025): + f(None, None) + f(None) + f() + + if __name__ == "__main__": import unittest unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst new file mode 100644 index 00000000000000..5225031292e6c7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst @@ -0,0 +1,2 @@ +Fix possible crashes when specializing function calls with too many +``__defaults__``. diff --git a/Python/specialize.c b/Python/specialize.c index f1684913b1bc30..63b44461007c6e 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1666,9 +1666,9 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, } int argcount = code->co_argcount; int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults); - assert(defcount <= argcount); int min_args = argcount-defcount; - if (nargs > argcount || nargs < min_args) { + // GH-105840: min_args is negative when somebody sets too many __defaults__! + if (min_args < 0 || nargs > argcount || nargs < min_args) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return -1; } From b34f1df5fa2a8745d6d54e93e5b54624abd65c30 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:34:46 -0700 Subject: [PATCH 0232/1206] [3.12] CI: Bump macOS build to use OpenSSL v3.0 (GH-105538) (#105867) (cherry picked from commit 34e93d3998bab8acd651c50724eb1977f4860a08) Co-authored-by: Erlend E. Aasland --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e1d4047a877739..197953b513f06f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -239,7 +239,7 @@ jobs: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Install Homebrew dependencies - run: brew install pkg-config openssl@1.1 xz gdbm tcl-tk + run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk - name: Configure CPython run: | GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ @@ -248,7 +248,7 @@ jobs: --config-cache \ --with-pydebug \ --prefix=/opt/python-dev \ - --with-openssl="$(brew --prefix openssl@1.1)" + --with-openssl="$(brew --prefix openssl@3.0)" - name: Build CPython run: make -j4 - name: Display build info From 6baddd9fb25e03040c1c07c410eae834463874d1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 18 Jun 2023 05:21:34 -0700 Subject: [PATCH 0233/1206] [3.12] Docs: move sphinx-lint to pre-commit (GH-105750) (#105894) Docs: move sphinx-lint to pre-commit (GH-105750) (cherry picked from commit bc07c8f096791d678ca5c1e3486cb9648f7a027b) Co-authored-by: Hugo van Kemenade --- .github/workflows/doc.yml | 4 ---- .pre-commit-config.yaml | 8 ++++++++ Doc/Makefile | 8 +++----- Doc/constraints.txt | 4 ---- Doc/requirements.txt | 1 - 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index ec900ce68a1dde..3211b526efc7a5 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -51,8 +51,6 @@ jobs: cache-dependency-path: 'Doc/requirements.txt' - name: 'Install build dependencies' run: make -C Doc/ venv - - name: 'Check documentation' - run: make -C Doc/ check - name: 'Build HTML documentation' run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html @@ -82,8 +80,6 @@ jobs: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going" html 2>&1 # This build doesn't use problem matchers or check annotations - # It also does not run 'make check', as sphinx-lint is not installed into the - # environment. build_doc_oldest_supported_sphinx: name: 'Docs (Oldest Sphinx)' runs-on: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 808622f19a3dbf..464bcde6e98424 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,3 +5,11 @@ repos: - id: check-yaml - id: trailing-whitespace types_or: [c, python, rst] + + - repo: https://github.com/sphinx-contrib/sphinx-lint + rev: v0.6.7 + hooks: + - id: sphinx-lint + args: [--enable=default-role] + files: ^Doc/ + types: [rst] diff --git a/Doc/Makefile b/Doc/Makefile index c11ea6ce03e8a4..22691895068fea 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -216,11 +216,9 @@ dist: rm dist/python-$(DISTVERSION)-docs-texinfo.tar .PHONY: check -check: - # Check the docs and NEWS files with sphinx-lint. - # Ignore the tools and venv dirs and check that the default role is not used. - $(SPHINXLINT) -i tools -i $(VENVDIR) --enable default-role - $(SPHINXLINT) --enable default-role ../Misc/NEWS.d/next/ +check: venv + $(VENVDIR)/bin/python3 -m pre_commit --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install pre-commit + $(VENVDIR)/bin/python3 -m pre_commit run --all-files .PHONY: serve serve: diff --git a/Doc/constraints.txt b/Doc/constraints.txt index 66c748eb092d83..54888eaab242ee 100644 --- a/Doc/constraints.txt +++ b/Doc/constraints.txt @@ -23,7 +23,3 @@ sphinxcontrib-serializinghtml<1.2 # Direct dependencies of Jinja2 (Jinja is a dependency of Sphinx, see above) MarkupSafe<2.2 - -# Direct dependencies of sphinx-lint -polib<1.3 -regex<2024 diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 9cbd15c2209dc6..4c9d02ea37ab58 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -10,7 +10,6 @@ sphinx==4.5.0 blurb -sphinx-lint==0.6.7 sphinxext-opengraph==0.7.5 # The theme used by the documentation is stored separately, so we need From 1606cbc2fd6b48a3818635fdb2caee4e297343f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 18 Jun 2023 10:56:35 -0700 Subject: [PATCH 0234/1206] [3.12] gh-105844: Use devguide terminology to denote versions (GH-105882) (#105892) (cherry picked from commit dba72175116373c1d15e25d84c88b516daf9f5c4) Co-authored-by: Erlend E. Aasland --- Doc/faq/general.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 298ce111698a65..8727332594bda6 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -135,7 +135,7 @@ Python versions are numbered "A.B.C" or "A.B": See :pep:`6` for more information about bugfix releases. -Not all releases are bugfix releases. In the run-up to a new minor release, a +Not all releases are bugfix releases. In the run-up to a new feature release, a series of development releases are made, denoted as alpha, beta, or release candidate. Alphas are early releases in which interfaces aren't yet finalized; it's not unexpected to see an interface change between two alpha releases. @@ -297,9 +297,9 @@ How stable is Python? Very stable. New, stable releases have been coming out roughly every 6 to 18 months since 1991, and this seems likely to continue. As of version 3.9, -Python will have a minor new release every 12 months (:pep:`602`). +Python will have a new feature release every 12 months (:pep:`602`). -The developers issue "bugfix" releases of older versions, so the stability of +The developers issue bugfix releases of older versions, so the stability of existing releases gradually improves. Bugfix releases, indicated by a third component of the version number (e.g. 3.5.3, 3.6.2), are managed for stability; only fixes for known problems are included in a bugfix release, and it's From 5e524ef34687899ed09b5a4c56568346e20f789e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 18 Jun 2023 17:02:48 -0700 Subject: [PATCH 0235/1206] [3.12] typing docs: Improve the intro to each section (GH-105901) (#105902) typing docs: Improve the intro to each section (GH-105901) (cherry picked from commit 4426279a4399158027a1145cff1c4c92424bf5b5) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 76 ++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 5c7ddc7e5a29b0..f6851199466f32 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -23,10 +23,9 @@ -------------- -This module provides runtime support for type hints. The most fundamental -support consists of the types :data:`Any`, :data:`Union`, :data:`Callable`, -:class:`TypeVar`, and :class:`Generic`. For a specification, please see -:pep:`484`. For a simplified introduction to type hints, see :pep:`483`. +This module provides runtime support for type hints. For the original +specification of the typing system, see :pep:`484`. For a simplified +introduction to type hints, see :pep:`483`. The function below takes and returns a string and is annotated as follows:: @@ -47,16 +46,18 @@ For a summary of deprecated features and a deprecation timeline, please see .. seealso:: - For a quick overview of type hints, refer to - `this cheat sheet `_. + `"Typing cheat sheet" `_ + A quick overview of type hints (hosted at the mypy docs) - The "Type System Reference" section of https://mypy.readthedocs.io/ -- since - the Python typing system is standardised via PEPs, this reference should - broadly apply to most Python type checkers, although some parts may still be - specific to mypy. + "Type System Reference" section of `the mypy docs `_ + The Python typing system is standardised via PEPs, so this reference + should broadly apply to most Python type checkers. (Some parts may still + be specific to mypy.) - The documentation at https://typing.readthedocs.io/ serves as useful reference - for type system features, useful typing related tools and typing best practices. + `"Static Typing with Python" `_ + Type-checker-agnostic documentation written by the community detailing + type system features, useful typing related tools and typing best + practices. .. _relevant-peps: @@ -654,25 +655,7 @@ can define new custom protocols to fully enjoy structural subtyping Module contents =============== -The module defines the following classes, functions and decorators. - -.. note:: - - This module defines several deprecated aliases to pre-existing - standard library classes. These were originally included in the typing - module in order to support parameterizing these generic classes using ``[]``. - However, the aliases became redundant in Python 3.9 when the - corresponding pre-existing classes were enhanced to support ``[]``. - - The redundant types are deprecated as of Python 3.9 but no - deprecation warnings are issued by the interpreter. - It is expected that type checkers will flag the deprecated types - when the checked program targets Python 3.9 or newer. - - The deprecated types will be removed from the :mod:`typing` module - no sooner than the first Python version released 5 years after the release of Python 3.9.0. - See details in :pep:`585`—*Type Hinting Generics In Standard Collections*. - +The ``typing`` module defines the following classes, functions and decorators. Special typing primitives ------------------------- @@ -680,7 +663,8 @@ Special typing primitives Special types """"""""""""" -These can be used as types in annotations and do not support ``[]``. +These can be used as types in annotations. They do not support subscription +using ``[]``. .. data:: Any @@ -890,7 +874,8 @@ These can be used as types in annotations and do not support ``[]``. Special forms """"""""""""" -These can be used as types in annotations using ``[]``, each having a unique syntax. +These can be used as types in annotations. They all support subscription using +``[]``, but each has a unique syntax. .. data:: Tuple @@ -1471,7 +1456,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn Building generic types and type aliases """"""""""""""""""""""""""""""""""""""" -The following objects are not used directly in annotations. Instead, they are building blocks +The following classes should not be used directly as annotations. +Their intended purpose is to be building blocks for creating generic types and type aliases. These objects can be created through special syntax @@ -1962,7 +1948,9 @@ without the dedicated syntax, as documented below. Other special directives """""""""""""""""""""""" -These are not used in annotations. They are building blocks for declaring types. +These functions and classes should not be used directly as annotations. +Their intended purpose is to be building blocks for creating and declaring +types. .. class:: NamedTuple @@ -2386,7 +2374,8 @@ These are not used in annotations. They are building blocks for declaring types. Protocols --------- -These protocols are decorated with :func:`runtime_checkable`. +The following protocols are provided by the typing module. All are decorated +with :func:`@runtime_checkable `. .. class:: SupportsAbs @@ -3024,6 +3013,21 @@ Constant Deprecated aliases ------------------ +This module defines several deprecated aliases to pre-existing +standard library classes. These were originally included in the typing +module in order to support parameterizing these generic classes using ``[]``. +However, the aliases became redundant in Python 3.9 when the +corresponding pre-existing classes were enhanced to support ``[]``. + +The redundant types are deprecated as of Python 3.9 but no +deprecation warnings are issued by the interpreter. +It is expected that type checkers will flag the deprecated types +when the checked program targets Python 3.9 or newer. + +The deprecated types will be removed from the :mod:`typing` module +no sooner than the first Python version released 5 years after the release of Python 3.9.0. +See details in :pep:`585`—*Type Hinting Generics In Standard Collections*. + .. _corresponding-to-built-in-types: Aliases to built-in types From 225cc4c043aca472f0c7c78bed1a7524fae5c278 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 19 Jun 2023 10:42:23 -0700 Subject: [PATCH 0236/1206] [3.12] GH-105808: Fix a regression introduced in GH-101251 (GH-105910) (#105920) GH-105808: Fix a regression introduced in GH-101251 (GH-105910) Fix a regression introduced in pythonGH-101251, causing GzipFile.flush() to not flush the compressor (nor pass along the zip_mode argument). (cherry picked from commit 1858db7cbdbf41aa600c954c15224307bf81a258) Co-authored-by: T. Wouters --- Lib/gzip.py | 3 +- Lib/test/test_gzip.py | 49 +++++++++++++++++++ ...-06-19-11-31-55.gh-issue-105808.NL-quu.rst | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst diff --git a/Lib/gzip.py b/Lib/gzip.py index 8796c8d9fd9a2d..cf8b675064ce89 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -370,8 +370,9 @@ def close(self): def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH): self._check_not_closed() if self.mode == WRITE: - # Ensure the compressor's buffer is flushed self._buffer.flush() + # Ensure the compressor's buffer is flushed + self.fileobj.write(self.compress.flush(zlib_mode)) self.fileobj.flush() def fileno(self): diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index 6de413e5056ef0..c7ac7c687c8b2d 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -9,6 +9,7 @@ import struct import sys import unittest +import zlib from subprocess import PIPE, Popen from test.support import import_helper from test.support import os_helper @@ -616,6 +617,54 @@ def test_issue44439(self): self.assertEqual(f.write(q), LENGTH) self.assertEqual(f.tell(), LENGTH) + def test_flush_flushes_compressor(self): + # See issue GH-105808. + b = io.BytesIO() + message = b"important message here." + with gzip.GzipFile(fileobj=b, mode='w') as f: + f.write(message) + f.flush() + partial_data = b.getvalue() + full_data = b.getvalue() + self.assertEqual(gzip.decompress(full_data), message) + # The partial data should contain the gzip header and the complete + # message, but not the end-of-stream markers (so we can't just + # decompress it directly). + with self.assertRaises(EOFError): + gzip.decompress(partial_data) + d = zlib.decompressobj(wbits=-zlib.MAX_WBITS) + f = io.BytesIO(partial_data) + gzip._read_gzip_header(f) + read_message = d.decompress(f.read()) + self.assertEqual(read_message, message) + + def test_flush_modes(self): + # Make sure the argument to flush is properly passed to the + # zlib.compressobj; see issue GH-105808. + class FakeCompressor: + def __init__(self): + self.modes = [] + def compress(self, data): + return b'' + def flush(self, mode=-1): + self.modes.append(mode) + return b'' + b = io.BytesIO() + fc = FakeCompressor() + with gzip.GzipFile(fileobj=b, mode='w') as f: + f.compress = fc + f.flush() + f.flush(50) + f.flush(zlib_mode=100) + # The implicit close will also flush the compressor. + expected_modes = [ + zlib.Z_SYNC_FLUSH, + 50, + 100, + -1, + ] + self.assertEqual(fc.modes, expected_modes) + class TestOpen(BaseTest): def test_binary_modes(self): diff --git a/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst b/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst new file mode 100644 index 00000000000000..8e69fd627c28e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst @@ -0,0 +1 @@ +Fix a regression introduced in GH-101251 for 3.12, causing :meth:`gzip.GzipFile.flush` to not flush the compressor (nor pass along the ``zip_mode`` argument). From f992a60014b7ca83de038fc64572a63f4eb39c74 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Mon, 19 Jun 2023 20:55:07 +0200 Subject: [PATCH 0237/1206] Python 3.12.0b3 --- Include/patchlevel.h | 4 +- Lib/pydoc_data/topics.py | 38 +- Misc/NEWS.d/3.12.0b3.rst | 411 ++++++++++++++++++ ...-06-06-14-14-41.gh-issue-103968.BTO6II.rst | 2 - ...-06-09-12-35-55.gh-issue-105387.wM_oL-.rst | 3 - ...-06-09-19-16-57.gh-issue-105603.-z6G22.rst | 5 - ...-06-09-23-34-25.gh-issue-105375.n7amiF.rst | 2 - ...-06-02-15-15-41.gh-issue-104812.dfZiG5.rst | 9 - ...-06-06-17-10-42.gh-issue-105390.DvqI-e.rst | 3 - ...-06-07-12-20-59.gh-issue-105435.6VllI0.rst | 2 - ...-06-08-09-25-52.gh-issue-105375.ocB7fT.rst | 2 - ...-06-08-09-54-37.gh-issue-105375.kqKT3E.rst | 1 - ...-06-08-10-10-07.gh-issue-105375.35VGDd.rst | 2 - ...-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst | 2 - ...-06-09-12-59-18.gh-issue-105549.PYfTNp.rst | 2 - ...-06-09-15-25-12.gh-issue-105564.sFdUu4.rst | 2 - ...-06-10-21-38-49.gh-issue-105587.rL3rzv.rst | 3 - ...-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst | 2 - ...-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst | 3 - ...-06-15-22-11-43.gh-issue-105840.Fum_g_.rst | 2 - ...-03-12-01-17-15.gh-issue-102541.LK1adc.rst | 1 - ...-05-26-21-24-06.gh-issue-104996.aaW78g.rst | 2 - ...-06-02-14-23-41.gh-issue-104310.UamCOB.rst | 7 - ...-06-06-11-50-33.gh-issue-105332.tmpgRA.rst | 1 - ...-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst | 2 - ...-06-08-08-58-36.gh-issue-105375.bTcqS9.rst | 1 - ...-06-09-21-04-39.gh-issue-105375.bTcqS9.rst | 1 - ...-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst | 1 - ...-06-09-21-25-14.gh-issue-105375.95g1eI.rst | 1 - ...-06-09-21-30-59.gh-issue-105375.eewafp.rst | 2 - ...-06-09-21-40-45.gh-issue-105375._sZilh.rst | 1 - ...-06-09-21-46-52.gh-issue-105375.yrJelV.rst | 2 - ...-06-09-22-16-46.gh-issue-105375.EgVJOP.rst | 2 - ...-06-09-22-45-26.gh-issue-105375.9rp6tG.rst | 2 - ...-06-09-22-52-45.gh-issue-105375.6igkhn.rst | 1 - ...-06-09-23-00-13.gh-issue-105605.YuwqxY.rst | 3 - ...-06-09-23-46-23.gh-issue-105375.9KaioS.rst | 2 - ...-06-11-22-46-06.gh-issue-105375.YkhSNt.rst | 2 - ...-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst | 1 - ...-06-15-18-11-47.gh-issue-104799.BcLzbP.rst | 3 - ...-06-19-11-31-55.gh-issue-105808.NL-quu.rst | 1 - ...-05-29-14-49-46.gh-issue-105084.lvVvoj.rst | 3 - ...-06-08-11-30-17.gh-issue-105436.1qlDxw.rst | 2 - README.rst | 2 +- 44 files changed, 435 insertions(+), 111 deletions(-) create mode 100644 Misc/NEWS.d/3.12.0b3.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index a6d20e4d03cf58..b950076894a7c1 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 2 +#define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.12.0b2+" +#define PY_VERSION "3.12.0b3" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index d70bf9e86b2de2..9a6a1b37545720 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Jun 6 16:12:51 2023 +# Autogenerated by Sphinx on Mon Jun 19 20:55:48 2023 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -6522,22 +6522,26 @@ 'positional\n' 'argument, and if it’s a keyword, it refers to a named ' 'keyword\n' - 'argument. If the numerical arg_names in a format string ' - 'are 0, 1, 2,\n' - '… in sequence, they can all be omitted (not just some) and ' - 'the numbers\n' - '0, 1, 2, … will be automatically inserted in that order. ' - 'Because\n' - '*arg_name* is not quote-delimited, it is not possible to ' - 'specify\n' - 'arbitrary dictionary keys (e.g., the strings "\'10\'" or ' - '"\':-]\'") within\n' - 'a format string. The *arg_name* can be followed by any ' - 'number of index\n' - 'or attribute expressions. An expression of the form ' - '"\'.name\'" selects\n' - 'the named attribute using "getattr()", while an expression ' - 'of the form\n' + 'argument. An *arg_name* is treated as a number if a call ' + 'to\n' + '"str.isdecimal()" on the string would return true. If the ' + 'numerical\n' + 'arg_names in a format string are 0, 1, 2, … in sequence, ' + 'they can all\n' + 'be omitted (not just some) and the numbers 0, 1, 2, … will ' + 'be\n' + 'automatically inserted in that order. Because *arg_name* is ' + 'not quote-\n' + 'delimited, it is not possible to specify arbitrary ' + 'dictionary keys\n' + '(e.g., the strings "\'10\'" or "\':-]\'") within a format ' + 'string. The\n' + '*arg_name* can be followed by any number of index or ' + 'attribute\n' + 'expressions. An expression of the form "\'.name\'" selects ' + 'the named\n' + 'attribute using "getattr()", while an expression of the ' + 'form\n' '"\'[index]\'" does an index lookup using "__getitem__()".\n' '\n' 'Changed in version 3.1: The positional argument specifiers ' diff --git a/Misc/NEWS.d/3.12.0b3.rst b/Misc/NEWS.d/3.12.0b3.rst new file mode 100644 index 00000000000000..ffd880f8688679 --- /dev/null +++ b/Misc/NEWS.d/3.12.0b3.rst @@ -0,0 +1,411 @@ +.. date: 2023-06-15-22-11-43 +.. gh-issue: 105840 +.. nonce: Fum_g_ +.. release date: 2023-06-19 +.. section: Core and Builtins + +Fix possible crashes when specializing function calls with too many +``__defaults__``. + +.. + +.. date: 2023-06-15-15-54-47 +.. gh-issue: 105831 +.. nonce: -MC9Zs +.. section: Core and Builtins + +Fix an f-string bug, where using a debug expression (the ``=`` sign) that +appears in the last line of a file results to the debug buffer that holds +the expression text being one character too small. + +.. + +.. date: 2023-06-14-22-52-06 +.. gh-issue: 105800 +.. nonce: hdpPzZ +.. section: Core and Builtins + +Correctly issue :exc:`SyntaxWarning` in f-strings if invalid sequences are +used. Patch by Pablo Galindo + +.. + +.. date: 2023-06-10-21-38-49 +.. gh-issue: 105587 +.. nonce: rL3rzv +.. section: Core and Builtins + +The runtime can't guarantee that immortal objects will not be mutated by +Extensions. Thus, this modifies _PyStaticObject_CheckRefcnt to warn instead +of asserting. + +.. + +.. date: 2023-06-09-15-25-12 +.. gh-issue: 105564 +.. nonce: sFdUu4 +.. section: Core and Builtins + +Don't include artificil newlines in the ``line`` attribute of tokens in the +APIs of the :mod:`tokenize` module. Patch by Pablo Galindo + +.. + +.. date: 2023-06-09-12-59-18 +.. gh-issue: 105549 +.. nonce: PYfTNp +.. section: Core and Builtins + +Tokenize separately ``NUMBER`` and ``NAME`` tokens that are not ambiguous. +Patch by Pablo Galindo. + +.. + +.. date: 2023-06-09-11-19-51 +.. gh-issue: 105588 +.. nonce: Y5ovpY +.. section: Core and Builtins + +Fix an issue that could result in crashes when compiling malformed +:mod:`ast` nodes. + +.. + +.. date: 2023-06-08-10-10-07 +.. gh-issue: 105375 +.. nonce: 35VGDd +.. section: Core and Builtins + +Fix bugs in the :mod:`builtins` module where exceptions could end up being +overwritten. + +.. + +.. date: 2023-06-08-09-54-37 +.. gh-issue: 105375 +.. nonce: kqKT3E +.. section: Core and Builtins + +Fix bug in the compiler where an exception could end up being overwritten. + +.. + +.. date: 2023-06-08-09-25-52 +.. gh-issue: 105375 +.. nonce: ocB7fT +.. section: Core and Builtins + +Improve error handling in :c:func:`PyUnicode_BuildEncodingMap` where an +exception could end up being overwritten. + +.. + +.. date: 2023-06-07-12-20-59 +.. gh-issue: 105435 +.. nonce: 6VllI0 +.. section: Core and Builtins + +Fix spurious newline character if file ends on a comment without a newline. +Patch by Pablo Galindo + +.. + +.. date: 2023-06-06-17-10-42 +.. gh-issue: 105390 +.. nonce: DvqI-e +.. section: Core and Builtins + +Correctly raise :exc:`tokenize.TokenError` exceptions instead of +:exc:`SyntaxError` for tokenize errors such as incomplete input. Patch by +Pablo Galindo + +.. + +.. date: 2023-06-02-15-15-41 +.. gh-issue: 104812 +.. nonce: dfZiG5 +.. section: Core and Builtins + +The "pending call" machinery now works for all interpreters, not just the +main interpreter, and runs in all threads, not just the main thread. Some +calls are still only done in the main thread, ergo in the main interpreter. +This change does not affect signal handling nor the existing public C-API +(``Py_AddPendingCall()``), which both still only target the main thread. The +new functionality is meant strictly for internal use for now, since +consequences of its use are not well understood yet outside some very +restricted cases. This change brings the capability in line with the +intention when the state was made per-interpreter several years ago. + +.. + +.. date: 2023-06-19-11-31-55 +.. gh-issue: 105808 +.. nonce: NL-quu +.. section: Library + +Fix a regression introduced in GH-101251 for 3.12, causing +:meth:`gzip.GzipFile.flush` to not flush the compressor (nor pass along the +``zip_mode`` argument). + +.. + +.. date: 2023-06-15-18-11-47 +.. gh-issue: 104799 +.. nonce: BcLzbP +.. section: Library + +Enable :func:`ast.unparse` to unparse function and class definitions created +without the new ``type_params`` field from :pep:`695`. Patch by Jelle +Zijlstra. + +.. + +.. date: 2023-06-14-10-27-34 +.. gh-issue: 105745 +.. nonce: l1ttOQ +.. section: Library + +Fix ``webbrowser.Konqueror.open`` method. + +.. + +.. date: 2023-06-11-22-46-06 +.. gh-issue: 105375 +.. nonce: YkhSNt +.. section: Library + +Fix a bug in :c:func:`!_Unpickler_SetInputStream` where an exception could +end up being overwritten in case of failure. + +.. + +.. date: 2023-06-09-23-46-23 +.. gh-issue: 105375 +.. nonce: 9KaioS +.. section: Library + +Fix bugs in :mod:`sys` where exceptions could end up being overwritten +because of deferred error handling. + +.. + +.. date: 2023-06-09-23-00-13 +.. gh-issue: 105605 +.. nonce: YuwqxY +.. section: Library + +Harden :mod:`pyexpat` error handling during module initialisation to prevent +exceptions from possibly being overwritten, and objects from being +dereferenced twice. + +.. + +.. date: 2023-06-09-22-52-45 +.. gh-issue: 105375 +.. nonce: 6igkhn +.. section: Library + +Fix bug in :mod:`decimal` where an exception could end up being overwritten. + +.. + +.. date: 2023-06-09-22-45-26 +.. gh-issue: 105375 +.. nonce: 9rp6tG +.. section: Library + +Fix bugs in :mod:`!_datetime` where exceptions could be overwritten in case +of module initialisation failure. + +.. + +.. date: 2023-06-09-22-16-46 +.. gh-issue: 105375 +.. nonce: EgVJOP +.. section: Library + +Fix bugs in :mod:`!_ssl` initialisation which could lead to leaked +references and overwritten exceptions. + +.. + +.. date: 2023-06-09-21-46-52 +.. gh-issue: 105375 +.. nonce: yrJelV +.. section: Library + +Fix a bug in :class:`array.array` where an exception could end up being +overwritten. + +.. + +.. date: 2023-06-09-21-40-45 +.. gh-issue: 105375 +.. nonce: _sZilh +.. section: Library + +Fix bugs in :mod:`_ctypes` where exceptions could end up being overwritten. + +.. + +.. date: 2023-06-09-21-30-59 +.. gh-issue: 105375 +.. nonce: eewafp +.. section: Library + +Fix a bug in the :mod:`posix` module where an exception could be +overwritten. + +.. + +.. date: 2023-06-09-21-25-14 +.. gh-issue: 105375 +.. nonce: 95g1eI +.. section: Library + +Fix bugs in :mod:`!_elementtree` where exceptions could be overwritten. + +.. + +.. date: 2023-06-09-21-11-28 +.. gh-issue: 105375 +.. nonce: 4Mxn7t +.. section: Library + +Fix bugs in :mod:`zoneinfo` where exceptions could be overwritten. + +.. + +.. date: 2023-06-09-21-04-39 +.. gh-issue: 105375 +.. nonce: bTcqS9 +.. section: Library + +Fix bugs in :mod:`pickle` where exceptions could be overwritten. + +.. + +.. date: 2023-06-08-08-58-36 +.. gh-issue: 105375 +.. nonce: bTcqS9 +.. section: Library + +Fix bugs in :mod:`pickle` where exceptions could be overwritten. + +.. + +.. date: 2023-06-07-00-09-52 +.. gh-issue: 105375 +.. nonce: Y_9D4n +.. section: Library + +Fix a bug in :mod:`sqlite3` where an exception could be overwritten in the +:meth:`collation ` callback. + +.. + +.. date: 2023-06-06-11-50-33 +.. gh-issue: 105332 +.. nonce: tmpgRA +.. section: Library + +Revert pickling method from by-name back to by-value. + +.. + +.. date: 2023-06-02-14-23-41 +.. gh-issue: 104310 +.. nonce: UamCOB +.. section: Library + +In the beta 1 release we added a utility function for extension module +authors, to use when testing their module for support in multiple +interpreters or under a per-interpreter GIL. The name of that function has +changed from ``allowing_all_extensions`` to +``_incompatible_extension_module_restrictions``. The default for the +"disable_check" argument has change from ``True`` to ``False``, to better +match the new function name. + +.. + +.. date: 2023-05-26-21-24-06 +.. gh-issue: 104996 +.. nonce: aaW78g +.. section: Library + +Improve performance of :class:`pathlib.PurePath` initialisation by deferring +joining of paths when multiple arguments are given. + +.. + +.. date: 2023-03-12-01-17-15 +.. gh-issue: 102541 +.. nonce: LK1adc +.. section: Library + +Hide traceback in :func:`help` prompt, when import failed. + +.. + +.. date: 2023-05-29-14-49-46 +.. gh-issue: 105084 +.. nonce: lvVvoj +.. section: Tests + +When the Python build is configured ``--with-wheel-pkg-dir``, tests +requiring the ``setuptools`` and ``wheel`` wheels will search for the wheels +in ``WHEEL_PKG_DIR``. + +.. + +.. date: 2023-06-08-11-30-17 +.. gh-issue: 105436 +.. nonce: 1qlDxw +.. section: Windows + +Ensure that an empty environment block is terminated by two null characters, +as is required by Windows. + +.. + +.. date: 2023-06-09-23-34-25 +.. gh-issue: 105375 +.. nonce: n7amiF +.. section: C API + +Fix a bug in :c:func:`PyErr_WarnExplicit` where an exception could end up +being overwritten if the API failed internally. + +.. + +.. date: 2023-06-09-19-16-57 +.. gh-issue: 105603 +.. nonce: -z6G22 +.. section: C API + +We've renamed the new (in 3.12) ``PyInterpreterConfig.own_gil`` to +``PyInterpreterConfig.gil`` and changed the meaning of the value from "bool" +to an integer with supported values of ``PyInterpreterConfig_DEFAULT_GIL``, +``PyInterpreterConfig_SHARED_GIL``, and ``PyInterpreterConfig_OWN_GIL``. The +default is "shared". + +.. + +.. date: 2023-06-09-12-35-55 +.. gh-issue: 105387 +.. nonce: wM_oL- +.. section: C API + +In the limited C API version 3.12, :c:func:`Py_INCREF` and +:c:func:`Py_DECREF` functions are now implemented as opaque function calls +to hide implementation details. Patch by Victor Stinner. + +.. + +.. date: 2023-06-06-14-14-41 +.. gh-issue: 103968 +.. nonce: BTO6II +.. section: C API + +:c:func:`PyType_FromMetaclass` now allows metaclasses with ``tp_new`` set to +``NULL``. diff --git a/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst b/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst deleted file mode 100644 index b73103c4e0ad9e..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst +++ /dev/null @@ -1,2 +0,0 @@ -:c:func:`PyType_FromMetaclass` now allows metaclasses with ``tp_new`` -set to ``NULL``. diff --git a/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst b/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst deleted file mode 100644 index d7ee7d2eb9d908..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst +++ /dev/null @@ -1,3 +0,0 @@ -In the limited C API version 3.12, :c:func:`Py_INCREF` and -:c:func:`Py_DECREF` functions are now implemented as opaque function calls -to hide implementation details. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst b/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst deleted file mode 100644 index cd3d9bcdd4e285..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst +++ /dev/null @@ -1,5 +0,0 @@ -We've renamed the new (in 3.12) ``PyInterpreterConfig.own_gil`` to -``PyInterpreterConfig.gil`` and changed the meaning of the value from "bool" -to an integer with supported values of ``PyInterpreterConfig_DEFAULT_GIL``, -``PyInterpreterConfig_SHARED_GIL``, and ``PyInterpreterConfig_OWN_GIL``. The -default is "shared". diff --git a/Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst b/Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst deleted file mode 100644 index b9f95496f938ec..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-06-09-23-34-25.gh-issue-105375.n7amiF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug in :c:func:`PyErr_WarnExplicit` where an exception could end up -being overwritten if the API failed internally. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst deleted file mode 100644 index da29a8cae61839..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst +++ /dev/null @@ -1,9 +0,0 @@ -The "pending call" machinery now works for all interpreters, not just the -main interpreter, and runs in all threads, not just the main thread. Some -calls are still only done in the main thread, ergo in the main interpreter. -This change does not affect signal handling nor the existing public C-API -(``Py_AddPendingCall()``), which both still only target the main thread. -The new functionality is meant strictly for internal use for now, since -consequences of its use are not well understood yet outside some very -restricted cases. This change brings the capability in line with the -intention when the state was made per-interpreter several years ago. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst deleted file mode 100644 index de59b54d8f6053..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-17-10-42.gh-issue-105390.DvqI-e.rst +++ /dev/null @@ -1,3 +0,0 @@ -Correctly raise :exc:`tokenize.TokenError` exceptions instead of -:exc:`SyntaxError` for tokenize errors such as incomplete input. Patch by -Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst deleted file mode 100644 index 9e4d7e1851ccb5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-07-12-20-59.gh-issue-105435.6VllI0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix spurious newline character if file ends on a comment without a newline. -Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst deleted file mode 100644 index 24fac2df4d0955..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-25-52.gh-issue-105375.ocB7fT.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve error handling in :c:func:`PyUnicode_BuildEncodingMap` where an -exception could end up being overwritten. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst deleted file mode 100644 index b4d3a1a5a3cedb..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-54-37.gh-issue-105375.kqKT3E.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug in the compiler where an exception could end up being overwritten. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst deleted file mode 100644 index 3ab85538f3fc43..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-10-10-07.gh-issue-105375.35VGDd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bugs in the :mod:`builtins` module where exceptions could end up being -overwritten. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst deleted file mode 100644 index 3981dad7a49dfb..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue that could result in crashes when compiling malformed -:mod:`ast` nodes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst deleted file mode 100644 index 7cb177b9353373..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-12-59-18.gh-issue-105549.PYfTNp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Tokenize separately ``NUMBER`` and ``NAME`` tokens that are not ambiguous. Patch -by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst deleted file mode 100644 index 9809fac49164f5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-15-25-12.gh-issue-105564.sFdUu4.rst +++ /dev/null @@ -1,2 +0,0 @@ -Don't include artificil newlines in the ``line`` attribute of tokens in the -APIs of the :mod:`tokenize` module. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst deleted file mode 100644 index 488f82c3fb574c..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst +++ /dev/null @@ -1,3 +0,0 @@ -The runtime can't guarantee that immortal objects will not be mutated by -Extensions. Thus, this modifies _PyStaticObject_CheckRefcnt to warn -instead of asserting. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst deleted file mode 100644 index d6ef7b68b833c6..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly issue :exc:`SyntaxWarning` in f-strings if invalid sequences are -used. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst deleted file mode 100644 index 407940add56752..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix an f-string bug, where using a debug expression (the ``=`` sign) that -appears in the last line of a file results to the debug buffer that holds the -expression text being one character too small. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst deleted file mode 100644 index 5225031292e6c7..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix possible crashes when specializing function calls with too many -``__defaults__``. diff --git a/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst b/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst deleted file mode 100644 index 45b10679e19e2d..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst +++ /dev/null @@ -1 +0,0 @@ -Hide traceback in :func:`help` prompt, when import failed. diff --git a/Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst b/Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst deleted file mode 100644 index 8b81b681af94aa..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-26-21-24-06.gh-issue-104996.aaW78g.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :class:`pathlib.PurePath` initialisation by -deferring joining of paths when multiple arguments are given. diff --git a/Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst b/Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst deleted file mode 100644 index 461a3a25fe1b43..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-02-14-23-41.gh-issue-104310.UamCOB.rst +++ /dev/null @@ -1,7 +0,0 @@ -In the beta 1 release we added a utility function for extension module -authors, to use when testing their module for support in multiple -interpreters or under a per-interpreter GIL. The name of that function has -changed from ``allowing_all_extensions`` to -``_incompatible_extension_module_restrictions``. The default for the -"disable_check" argument has change from ``True`` to ``False``, to better -match the new function name. diff --git a/Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst b/Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst deleted file mode 100644 index 31b6855a6ebfad..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-06-11-50-33.gh-issue-105332.tmpgRA.rst +++ /dev/null @@ -1 +0,0 @@ -Revert pickling method from by-name back to by-value. diff --git a/Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst b/Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst deleted file mode 100644 index ec10d63822c203..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-07-00-09-52.gh-issue-105375.Y_9D4n.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug in :mod:`sqlite3` where an exception could be overwritten in the -:meth:`collation ` callback. diff --git a/Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst b/Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst deleted file mode 100644 index 3030477c8245b5..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-08-08-58-36.gh-issue-105375.bTcqS9.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bugs in :mod:`pickle` where exceptions could be overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst deleted file mode 100644 index 3030477c8245b5..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-21-04-39.gh-issue-105375.bTcqS9.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bugs in :mod:`pickle` where exceptions could be overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst deleted file mode 100644 index 4202b758d1db56..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-21-11-28.gh-issue-105375.4Mxn7t.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bugs in :mod:`zoneinfo` where exceptions could be overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst deleted file mode 100644 index 1894b2b94bb334..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-21-25-14.gh-issue-105375.95g1eI.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bugs in :mod:`!_elementtree` where exceptions could be overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst deleted file mode 100644 index e000f98828a211..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-21-30-59.gh-issue-105375.eewafp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug in the :mod:`posix` module where an exception could be -overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst deleted file mode 100644 index 87db4c2b4e22e3..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-21-40-45.gh-issue-105375._sZilh.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bugs in :mod:`_ctypes` where exceptions could end up being overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst b/Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst deleted file mode 100644 index 21aea1b0b4082c..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-21-46-52.gh-issue-105375.yrJelV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug in :class:`array.array` where an exception could end up being -overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst b/Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst deleted file mode 100644 index 49f7df68e927cb..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-22-16-46.gh-issue-105375.EgVJOP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bugs in :mod:`!_ssl` initialisation which could lead to leaked -references and overwritten exceptions. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst b/Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst deleted file mode 100644 index 352d7b83a71632..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-22-45-26.gh-issue-105375.9rp6tG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bugs in :mod:`!_datetime` where exceptions could be overwritten in case -of module initialisation failure. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst b/Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst deleted file mode 100644 index 05e78fdc9b4076..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-22-52-45.gh-issue-105375.6igkhn.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug in :mod:`decimal` where an exception could end up being overwritten. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst b/Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst deleted file mode 100644 index 5fba6d293a785e..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-23-00-13.gh-issue-105605.YuwqxY.rst +++ /dev/null @@ -1,3 +0,0 @@ -Harden :mod:`pyexpat` error handling during module initialisation to prevent -exceptions from possibly being overwritten, and objects from being -dereferenced twice. diff --git a/Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst b/Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst deleted file mode 100644 index b12d7c864e7b86..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-09-23-46-23.gh-issue-105375.9KaioS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bugs in :mod:`sys` where exceptions could end up being overwritten -because of deferred error handling. diff --git a/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst b/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst deleted file mode 100644 index dda8f428760ba1..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug in :c:func:`!_Unpickler_SetInputStream` where an exception could -end up being overwritten in case of failure. diff --git a/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst b/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst deleted file mode 100644 index 7df7c5a79ec6eb..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``webbrowser.Konqueror.open`` method. diff --git a/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst b/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst deleted file mode 100644 index d0dbff4f1553e2..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst +++ /dev/null @@ -1,3 +0,0 @@ -Enable :func:`ast.unparse` to unparse function and class definitions created -without the new ``type_params`` field from :pep:`695`. Patch by Jelle -Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst b/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst deleted file mode 100644 index 8e69fd627c28e8..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a regression introduced in GH-101251 for 3.12, causing :meth:`gzip.GzipFile.flush` to not flush the compressor (nor pass along the ``zip_mode`` argument). diff --git a/Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst b/Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst deleted file mode 100644 index 5f80d507147347..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-05-29-14-49-46.gh-issue-105084.lvVvoj.rst +++ /dev/null @@ -1,3 +0,0 @@ -When the Python build is configured ``--with-wheel-pkg-dir``, tests -requiring the ``setuptools`` and ``wheel`` wheels will search for the wheels -in ``WHEEL_PKG_DIR``. diff --git a/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst b/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst deleted file mode 100644 index 1e3f298096cdd6..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure that an empty environment block is terminated by two null characters, -as is required by Windows. diff --git a/README.rst b/README.rst index bd1c1b06667aa8..daa30b1a65dfbb 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 beta 2 +This is Python version 3.12.0 beta 3 ===================================== .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From cc18a8b78ac85159dad8f2f3ee93799f5df6fa82 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 19 Jun 2023 20:05:20 -0700 Subject: [PATCH 0238/1206] [3.12] gh-105908: fix `barry_as_FLUFL` future import (GH-105909) (#105930) (cherry picked from commit 28187a9c4f95affe50fd37e0db0db177e2b9c2e9) Co-authored-by: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> --- Lib/test/test_future.py | 8 ++++++++ ...023-06-19-11-04-01.gh-issue-105908.7oanny.rst | 1 + Python/compile.c | 16 ++++++++++------ 3 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py index b8b591a1bcf2c6..4730bfafbd9cfe 100644 --- a/Lib/test/test_future.py +++ b/Lib/test/test_future.py @@ -4,6 +4,7 @@ import ast import unittest from test.support import import_helper +from test.support.script_helper import spawn_python, kill_python from textwrap import dedent import os import re @@ -121,6 +122,13 @@ def test_unicode_literals_exec(self): exec("from __future__ import unicode_literals; x = ''", {}, scope) self.assertIsInstance(scope["x"], str) + def test_syntactical_future_repl(self): + p = spawn_python('-i') + p.stdin.write(b"from __future__ import barry_as_FLUFL\n") + p.stdin.write(b"2 <> 3\n") + out = kill_python(p) + self.assertNotIn(b'SyntaxError: invalid syntax', out) + class AnnotationsFutureTestCase(unittest.TestCase): template = dedent( """ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst new file mode 100644 index 00000000000000..03db3f064f503f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst @@ -0,0 +1 @@ +Fixed bug where :gh:`99111` breaks future import ``barry_as_FLUFL`` in the Python REPL. diff --git a/Python/compile.c b/Python/compile.c index f593e957caae97..a8d0016a10786a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -510,8 +510,10 @@ static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone); static int compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, - PyCompilerFlags flags, int optimize, PyArena *arena) + PyCompilerFlags *flags, int optimize, PyArena *arena) { + PyCompilerFlags local_flags = _PyCompilerFlags_INIT; + c->c_const_cache = PyDict_New(); if (!c->c_const_cache) { return ERROR; @@ -527,10 +529,13 @@ compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, if (!_PyFuture_FromAST(mod, filename, &c->c_future)) { return ERROR; } - int merged = c->c_future.ff_features | flags.cf_flags; + if (!flags) { + flags = &local_flags; + } + int merged = c->c_future.ff_features | flags->cf_flags; c->c_future.ff_features = merged; - flags.cf_flags = merged; - c->c_flags = flags; + flags->cf_flags = merged; + c->c_flags = *flags; c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize; c->c_nestlevel = 0; @@ -555,12 +560,11 @@ static struct compiler* new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, int optimize, PyArena *arena) { - PyCompilerFlags flags = pflags ? *pflags : _PyCompilerFlags_INIT; struct compiler *c = PyMem_Calloc(1, sizeof(struct compiler)); if (c == NULL) { return NULL; } - if (compiler_setup(c, mod, filename, flags, optimize, arena) < 0) { + if (compiler_setup(c, mod, filename, pflags, optimize, arena) < 0) { compiler_free(c); return NULL; } From fea0d2fbaae69d95549891678339a67549a57e38 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 20 Jun 2023 06:09:48 -0700 Subject: [PATCH 0239/1206] [3.12] gh-105938: Emit a SyntaxWarning for escaped braces in an f-string (GH-105939) (#105941) (cherry picked from commit 6586cee27f32f0354fe4e77c7b8c6e399329b5e2) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_fstring.py | 11 +++++++++-- Parser/string_parser.c | 7 ++++++- Parser/tokenizer.c | 6 +++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 8f6b576b5f785f..ad5ac6a2f0432e 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -13,6 +13,7 @@ import types import decimal import unittest +import warnings from test import support from test.support.os_helper import temp_cwd from test.support.script_helper import assert_python_failure, assert_python_ok @@ -904,7 +905,7 @@ def test_backslashes_in_string_part(self): self.assertEqual(f'2\x203', '2 3') self.assertEqual(f'\x203', ' 3') - with self.assertWarns(DeprecationWarning): # invalid escape sequence + with self.assertWarns(SyntaxWarning): # invalid escape sequence value = eval(r"f'\{6*7}'") self.assertEqual(value, '\\42') with self.assertWarns(SyntaxWarning): # invalid escape sequence @@ -1037,7 +1038,7 @@ def test_fstring_backslash_before_double_bracket(self): ] for case, expected_result in deprecated_cases: with self.subTest(case=case, expected_result=expected_result): - with self.assertWarns(DeprecationWarning): + with self.assertWarns(SyntaxWarning): result = eval(case) self.assertEqual(result, expected_result) self.assertEqual(fr'\{{\}}', '\\{\\}') @@ -1046,6 +1047,12 @@ def test_fstring_backslash_before_double_bracket(self): self.assertEqual(fr'\}}{1+1}', '\\}2') self.assertEqual(fr'{1+1}\}}', '2\\}') + def test_fstring_backslash_before_double_bracket_warns_once(self): + with warnings.catch_warnings(record=True) as w: + eval(r"f'\{{'") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].category, SyntaxWarning) + def test_fstring_backslash_prefix_raw(self): self.assertEqual(f'\\', '\\') self.assertEqual(f'\\\\', '\\\\') diff --git a/Parser/string_parser.c b/Parser/string_parser.c index d4ce33850f7c58..20459e89463494 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -12,6 +12,11 @@ static int warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token *t) { unsigned char c = *first_invalid_escape; + if ((t->type == FSTRING_MIDDLE || t->type == FSTRING_END) && (c == '{' || c == '}')) { // in this case the tokenizer has already emitted a warning, + // see tokenizer.c:warn_invalid_escape_sequence + return 0; + } + int octal = ('4' <= c && c <= '7'); PyObject *msg = octal @@ -31,7 +36,7 @@ warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token if (PyErr_WarnExplicitObject(category, msg, p->tok->filename, t->lineno, NULL, NULL) < 0) { if (PyErr_ExceptionMatches(category)) { - /* Replace the DeprecationWarning exception with a SyntaxError + /* Replace the Syntax/DeprecationWarning exception with a SyntaxError to get a more accurate error report */ PyErr_Clear(); diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 1a59f542409fe6..115b497cc24090 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1559,12 +1559,12 @@ warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_cha return -1; } - if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, tok->filename, + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename, tok->lineno, NULL, NULL) < 0) { Py_DECREF(msg); - if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) { - /* Replace the DeprecationWarning exception with a SyntaxError + if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { + /* Replace the SyntaxWarning exception with a SyntaxError to get a more accurate error report */ PyErr_Clear(); return syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char); From 164fa930011c46d3261538c17f8c4ffbeedc0f7e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 20 Jun 2023 06:16:21 -0700 Subject: [PATCH 0240/1206] [3.12] gh-105915: Add 'r' prefix to not emit SyntaxWarning in test_fstring (GH-105940) (#105942) (cherry picked from commit 4b431d2e90bf5760a57aa40af2dd78e7bbf0b1ae) Co-authored-by: @sunmy2019 Co-authored-by: Lysandros Nikolaou --- Lib/test/test_fstring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index ad5ac6a2f0432e..1eb3bfb41888c2 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -773,7 +773,7 @@ def __format__(self, format_spec): self.assertEqual(f'{CustomFormat():\n}', '\n') self.assertEqual(f'{CustomFormat():\u2603}', '☃') with self.assertWarns(SyntaxWarning): - exec('f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat}) + exec(r'f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat}) def test_side_effect_order(self): class X: From e904c35c315a20de97b59f146da3d47402c029da Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 20 Jun 2023 15:32:24 +0200 Subject: [PATCH 0241/1206] Post 3.12.0b3 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index b950076894a7c1..aa35c24a9fa301 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.12.0b3" +#define PY_VERSION "3.12.0b3+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From c5c8111acf2a3a62ee06567593c78e8d5229fc79 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 20 Jun 2023 08:08:29 -0700 Subject: [PATCH 0242/1206] [3.12] gh-105915: Fix SyntaxWarning becoming a SyntaxError with -We in test_fstring (GH-105943) (#105945) (cherry picked from commit 6e40ee6e8456da04d6970a46863300c043c81208) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_fstring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 1eb3bfb41888c2..ba223ae124a8fb 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1048,10 +1048,10 @@ def test_fstring_backslash_before_double_bracket(self): self.assertEqual(fr'{1+1}\}}', '2\\}') def test_fstring_backslash_before_double_bracket_warns_once(self): - with warnings.catch_warnings(record=True) as w: + with self.assertWarns(SyntaxWarning) as w: eval(r"f'\{{'") - self.assertEqual(len(w), 1) - self.assertEqual(w[0].category, SyntaxWarning) + self.assertEqual(len(w.warnings), 1) + self.assertEqual(w.warnings[0].category, SyntaxWarning) def test_fstring_backslash_prefix_raw(self): self.assertEqual(f'\\', '\\') From 5729b418fe282bf7b2e890d3b757836e5a582905 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 20 Jun 2023 16:03:54 -0700 Subject: [PATCH 0243/1206] [3.12] gh-104212: Explain how to port imp code to importlib (GH-105905) (#105952) gh-104212: Explain how to port imp code to importlib (GH-105905) (cherry picked from commit 7a56a4148c521969d64164d2776641f19e3ca9e8) Co-authored-by: Victor Stinner --- Doc/whatsnew/3.12.rst | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 28bd4a8a64ee4b..ed4657c5b7a4a2 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1368,7 +1368,38 @@ Removed * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in :gh:`98040`.) - * Replace ``imp.new_module(name)`` with ``types.ModuleType(name)``. + * Replace removed :mod:`!imp` functions with :mod:`importlib` functions: + + ================================= ======================================= + imp importlib + ================================= ======================================= + ``imp.NullImporter`` Insert ``None`` into ``sys.path_importer_cache`` + ``imp.cache_from_source()`` :func:`importlib.util.cache_from_source` + ``imp.find_module()`` :func:`importlib.util.find_spec` + ``imp.get_magic()`` :attr:`importlib.util.MAGIC_NUMBER` + ``imp.get_suffixes()`` :attr:`importlib.machinery.SOURCE_SUFFIXES`, :attr:`importlib.machinery.EXTENSION_SUFFIXES`, and :attr:`importlib.machinery.BYTECODE_SUFFIXES` + ``imp.get_tag()`` :attr:`sys.implementation.cache_tag ` + ``imp.load_module()`` :func:`importlib.import_module` + ``imp.new_module(name)`` ``types.ModuleType(name)`` + ``imp.reload()`` :func:`importlib.reload` + ``imp.source_from_cache()`` :func:`importlib.util.source_from_cache` + ================================= ======================================= + + * Removed :mod:`!imp` functions and attributes with no replacements: + + * undocumented functions: + + * ``imp.init_builtin()`` + * ``imp.load_compiled()`` + * ``imp.load_dynamic()`` + * ``imp.load_package()`` + * ``imp.load_source()`` + + * ``imp.lock_held()``, ``imp.acquire_lock()``, ``imp.release_lock()``: + the locking scheme has changed in Python 3.3 to per-module locks. + * ``imp.find_module()`` constants: ``SEARCH_ERROR``, ``PY_SOURCE``, + ``PY_COMPILED``, ``C_EXTENSION``, ``PY_RESOURCE``, ``PKG_DIRECTORY``, + ``C_BUILTIN``, ``PY_FROZEN``, ``PY_CODERESOURCE``, ``IMP_HOOK``. * Removed the ``suspicious`` rule from the documentation Makefile, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint From 025c9912eeecc8b2584bc5143150fc548db2254b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 21 Jun 2023 07:40:54 -0700 Subject: [PATCH 0244/1206] [3.12] stdtypes.rst: remove a period (GH-105959) (#105968) stdtypes.rst: remove a period (GH-105959) (cherry picked from commit c5a722be5f7979c73e2451e537a8fc58bf9af12e) Co-authored-by: Mathieu Dupuy --- Doc/library/stdtypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 0caa725f75e642..0ac727e0df38b3 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -52,7 +52,7 @@ objects considered false: single: None (Built-in object) single: False (Built-in object) -* constants defined to be false: ``None`` and ``False``. +* constants defined to be false: ``None`` and ``False`` * zero of any numeric type: ``0``, ``0.0``, ``0j``, ``Decimal(0)``, ``Fraction(0, 1)`` From c407ef0a8a829c4e506bf43e412df176cc8cc2c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 22 Jun 2023 09:28:06 -0700 Subject: [PATCH 0245/1206] [3.12] gh-98931: Add custom error messages to invalid import/from with multiple targets (GH-105985) (#105991) Co-authored-by: Pablo Galindo Salgado Co-authored-by: Alex Waygood --- Grammar/python.gram | 2 +- Lib/test/test_syntax.py | 16 + ...3-06-22-14-19-17.gh-issue-98931.PPgvSF.rst | 2 + Parser/parser.c | 1537 +++++++++-------- 4 files changed, 849 insertions(+), 708 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 6b2a46aff0dcf0..c1863aec67cc2b 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -1293,7 +1293,7 @@ invalid_group: | '(' a='**' expression ')' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use double starred expression here") } invalid_import: - | a='import' dotted_name 'from' dotted_name { + | a='import' ','.dotted_name+ 'from' dotted_name { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") } invalid_import_from_targets: diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 477879db2fd493..f3d6cd7bad0eec 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1621,6 +1621,22 @@ Traceback (most recent call last): SyntaxError: Did you mean to use 'from ... import ...' instead? +>>> import a, b,c from b +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + +>>> import a.y.z, b.y.z, c.y.z from b.y.z +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + +>>> import a,b,c from b as bar +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + +>>> import a.y.z, b.y.z, c.y.z from b.y.z as bar +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + # Check that we dont raise the "trailing comma" error if there is more # input to the left of the valid part that we parsed. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst new file mode 100644 index 00000000000000..611660d6286263 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst @@ -0,0 +1,2 @@ +Ensure custom :exc:`SyntaxError` error messages are raised for invalid +imports with multiple targets. Patch by Pablo Galindo diff --git a/Parser/parser.c b/Parser/parser.c index 006ee297974a61..f2ea8f59b00567 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -532,14 +532,14 @@ static char *soft_keywords[] = { #define _gather_207_type 1451 #define _loop0_210_type 1452 #define _gather_209_type 1453 -#define _tmp_211_type 1454 -#define _loop0_212_type 1455 -#define _loop1_213_type 1456 -#define _tmp_214_type 1457 -#define _loop0_215_type 1458 -#define _loop1_216_type 1459 -#define _tmp_217_type 1460 -#define _tmp_218_type 1461 +#define _loop0_212_type 1454 +#define _gather_211_type 1455 +#define _tmp_213_type 1456 +#define _loop0_214_type 1457 +#define _loop1_215_type 1458 +#define _tmp_216_type 1459 +#define _loop0_217_type 1460 +#define _loop1_218_type 1461 #define _tmp_219_type 1462 #define _tmp_220_type 1463 #define _tmp_221_type 1464 @@ -548,10 +548,10 @@ static char *soft_keywords[] = { #define _tmp_224_type 1467 #define _tmp_225_type 1468 #define _tmp_226_type 1469 -#define _loop0_228_type 1470 -#define _gather_227_type 1471 -#define _tmp_229_type 1472 -#define _tmp_230_type 1473 +#define _tmp_227_type 1470 +#define _tmp_228_type 1471 +#define _loop0_230_type 1472 +#define _gather_229_type 1473 #define _tmp_231_type 1474 #define _tmp_232_type 1475 #define _tmp_233_type 1476 @@ -563,9 +563,9 @@ static char *soft_keywords[] = { #define _tmp_239_type 1482 #define _tmp_240_type 1483 #define _tmp_241_type 1484 -#define _loop0_242_type 1485 +#define _tmp_242_type 1485 #define _tmp_243_type 1486 -#define _tmp_244_type 1487 +#define _loop0_244_type 1487 #define _tmp_245_type 1488 #define _tmp_246_type 1489 #define _tmp_247_type 1490 @@ -596,6 +596,8 @@ static char *soft_keywords[] = { #define _tmp_272_type 1515 #define _tmp_273_type 1516 #define _tmp_274_type 1517 +#define _tmp_275_type 1518 +#define _tmp_276_type 1519 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -1051,14 +1053,14 @@ static asdl_seq *_loop0_208_rule(Parser *p); static asdl_seq *_gather_207_rule(Parser *p); static asdl_seq *_loop0_210_rule(Parser *p); static asdl_seq *_gather_209_rule(Parser *p); -static void *_tmp_211_rule(Parser *p); static asdl_seq *_loop0_212_rule(Parser *p); -static asdl_seq *_loop1_213_rule(Parser *p); -static void *_tmp_214_rule(Parser *p); -static asdl_seq *_loop0_215_rule(Parser *p); -static asdl_seq *_loop1_216_rule(Parser *p); -static void *_tmp_217_rule(Parser *p); -static void *_tmp_218_rule(Parser *p); +static asdl_seq *_gather_211_rule(Parser *p); +static void *_tmp_213_rule(Parser *p); +static asdl_seq *_loop0_214_rule(Parser *p); +static asdl_seq *_loop1_215_rule(Parser *p); +static void *_tmp_216_rule(Parser *p); +static asdl_seq *_loop0_217_rule(Parser *p); +static asdl_seq *_loop1_218_rule(Parser *p); static void *_tmp_219_rule(Parser *p); static void *_tmp_220_rule(Parser *p); static void *_tmp_221_rule(Parser *p); @@ -1067,10 +1069,10 @@ static void *_tmp_223_rule(Parser *p); static void *_tmp_224_rule(Parser *p); static void *_tmp_225_rule(Parser *p); static void *_tmp_226_rule(Parser *p); -static asdl_seq *_loop0_228_rule(Parser *p); -static asdl_seq *_gather_227_rule(Parser *p); -static void *_tmp_229_rule(Parser *p); -static void *_tmp_230_rule(Parser *p); +static void *_tmp_227_rule(Parser *p); +static void *_tmp_228_rule(Parser *p); +static asdl_seq *_loop0_230_rule(Parser *p); +static asdl_seq *_gather_229_rule(Parser *p); static void *_tmp_231_rule(Parser *p); static void *_tmp_232_rule(Parser *p); static void *_tmp_233_rule(Parser *p); @@ -1082,9 +1084,9 @@ static void *_tmp_238_rule(Parser *p); static void *_tmp_239_rule(Parser *p); static void *_tmp_240_rule(Parser *p); static void *_tmp_241_rule(Parser *p); -static asdl_seq *_loop0_242_rule(Parser *p); +static void *_tmp_242_rule(Parser *p); static void *_tmp_243_rule(Parser *p); -static void *_tmp_244_rule(Parser *p); +static asdl_seq *_loop0_244_rule(Parser *p); static void *_tmp_245_rule(Parser *p); static void *_tmp_246_rule(Parser *p); static void *_tmp_247_rule(Parser *p); @@ -1115,6 +1117,8 @@ static void *_tmp_271_rule(Parser *p); static void *_tmp_272_rule(Parser *p); static void *_tmp_273_rule(Parser *p); static void *_tmp_274_rule(Parser *p); +static void *_tmp_275_rule(Parser *p); +static void *_tmp_276_rule(Parser *p); // file: statements? $ @@ -22648,7 +22652,7 @@ invalid_group_rule(Parser *p) return _res; } -// invalid_import: 'import' dotted_name 'from' dotted_name +// invalid_import: 'import' ','.dotted_name+ 'from' dotted_name static void * invalid_import_rule(Parser *p) { @@ -22662,27 +22666,27 @@ invalid_import_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // 'import' dotted_name 'from' dotted_name + { // 'import' ','.dotted_name+ 'from' dotted_name if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' dotted_name 'from' dotted_name")); + D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); + asdl_seq * _gather_203_var; Token * _keyword; Token * a; expr_ty dotted_name_var; - expr_ty dotted_name_var_1; if ( (a = _PyPegen_expect_token(p, 607)) // token='import' && - (dotted_name_var = dotted_name_rule(p)) // dotted_name + (_gather_203_var = _gather_203_rule(p)) // ','.dotted_name+ && (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && - (dotted_name_var_1 = dotted_name_rule(p)) // dotted_name + (dotted_name_var = dotted_name_rule(p)) // dotted_name ) { - D(fprintf(stderr, "%*c+ invalid_import[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import' dotted_name 'from' dotted_name")); + D(fprintf(stderr, "%*c+ invalid_import[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( a , "Did you mean to use 'from ... import ...' instead?" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -22693,7 +22697,7 @@ invalid_import_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_import[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'import' dotted_name 'from' dotted_name")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); } _res = NULL; done: @@ -22773,7 +22777,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_203_var; + asdl_seq * _gather_205_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22783,7 +22787,7 @@ invalid_with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_203_var = _gather_203_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_205_var = _gather_205_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22807,7 +22811,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_205_var; + asdl_seq * _gather_207_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -22823,7 +22827,7 @@ invalid_with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_205_var = _gather_205_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_207_var = _gather_207_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22873,7 +22877,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_207_var; + asdl_seq * _gather_209_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22884,7 +22888,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (a = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_207_var = _gather_207_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_209_var = _gather_209_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22912,7 +22916,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_209_var; + asdl_seq * _gather_211_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -22929,7 +22933,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_209_var = _gather_209_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_211_var = _gather_211_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -23027,7 +23031,7 @@ invalid_try_stmt_rule(Parser *p) && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_211_rule, p) + _PyPegen_lookahead(0, _tmp_213_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -23052,8 +23056,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_212_var; - asdl_seq * _loop1_213_var; + asdl_seq * _loop0_214_var; + asdl_seq * _loop1_215_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -23064,9 +23068,9 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_212_var = _loop0_212_rule(p)) // block* + (_loop0_214_var = _loop0_214_rule(p)) // block* && - (_loop1_213_var = _loop1_213_rule(p)) // except_block+ + (_loop1_215_var = _loop1_215_rule(p)) // except_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && @@ -23074,7 +23078,7 @@ invalid_try_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_214_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23101,8 +23105,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_215_var; - asdl_seq * _loop1_216_var; + asdl_seq * _loop0_217_var; + asdl_seq * _loop1_218_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -23111,13 +23115,13 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_215_var = _loop0_215_rule(p)) // block* + (_loop0_217_var = _loop0_217_rule(p)) // block* && - (_loop1_216_var = _loop1_216_rule(p)) // except_star_block+ + (_loop1_218_var = _loop1_218_rule(p)) // except_star_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && - (_opt_var = _tmp_217_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_219_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23185,7 +23189,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var_1 = _tmp_218_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23223,7 +23227,7 @@ invalid_except_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var_1 = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23275,14 +23279,14 @@ invalid_except_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_220_var; + void *_tmp_222_var; Token * a; if ( (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_220_var = _tmp_220_rule(p)) // NEWLINE | ':' + (_tmp_222_var = _tmp_222_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -23389,7 +23393,7 @@ invalid_except_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23484,7 +23488,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_222_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23853,7 +23857,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_223_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_225_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -24347,7 +24351,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_224_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_2 = _tmp_226_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24407,7 +24411,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_225_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24442,7 +24446,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_226_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_228_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24493,11 +24497,11 @@ invalid_double_starred_kvpairs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_227_var; + asdl_seq * _gather_229_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_227_var = _gather_227_rule(p)) // ','.double_starred_kvpair+ + (_gather_229_var = _gather_229_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24505,7 +24509,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_227_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_229_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -24558,7 +24562,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_229_rule, p) + _PyPegen_lookahead(1, _tmp_231_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24669,7 +24673,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_230_rule, p) + _PyPegen_lookahead(1, _tmp_232_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24887,7 +24891,7 @@ invalid_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - _PyPegen_lookahead(0, _tmp_231_rule, p) + _PyPegen_lookahead(0, _tmp_233_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)")); @@ -24910,13 +24914,13 @@ invalid_replacement_field_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); Token * _literal; - void *_tmp_232_var; + void *_tmp_234_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_232_var = _tmp_232_rule(p)) // yield_expr | star_expressions + (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions && - _PyPegen_lookahead(0, _tmp_233_rule, p) + _PyPegen_lookahead(0, _tmp_235_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); @@ -24940,15 +24944,15 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); Token * _literal; Token * _literal_1; - void *_tmp_234_var; + void *_tmp_236_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions + (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_235_rule, p) + _PyPegen_lookahead(0, _tmp_237_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); @@ -24973,12 +24977,12 @@ invalid_replacement_field_rule(Parser *p) Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_236_var; + void *_tmp_238_var; void *invalid_conversion_character_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions + (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && @@ -24986,7 +24990,7 @@ invalid_replacement_field_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_236_var, _opt_var, invalid_conversion_character_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_238_var, _opt_var, invalid_conversion_character_var); goto done; } p->mark = _mark; @@ -25004,17 +25008,17 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_237_var; + void *_tmp_239_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_237_var = _tmp_237_rule(p)) // yield_expr | star_expressions + (_tmp_239_var = _tmp_239_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_238_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_240_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_239_rule, p) + _PyPegen_lookahead(0, _tmp_241_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); @@ -25038,24 +25042,24 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_242_var; + asdl_seq * _loop0_244_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_240_var; + void *_tmp_242_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_240_var = _tmp_240_rule(p)) // yield_expr | star_expressions + (_tmp_242_var = _tmp_242_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_241_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_243_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_242_var = _loop0_242_rule(p)) // fstring_format_spec* + (_loop0_244_var = _loop0_244_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -25084,15 +25088,15 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_243_var; + void *_tmp_245_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_243_var = _tmp_243_rule(p)) // yield_expr | star_expressions + (_tmp_245_var = _tmp_245_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_244_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_246_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -25140,7 +25144,7 @@ invalid_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_245_rule, p) + _PyPegen_lookahead(1, _tmp_247_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -26085,12 +26089,12 @@ _loop1_15_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_246_var; + void *_tmp_248_var; while ( - (_tmp_246_var = _tmp_246_rule(p)) // star_targets '=' + (_tmp_248_var = _tmp_248_rule(p)) // star_targets '=' ) { - _res = _tmp_246_var; + _res = _tmp_248_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26664,12 +26668,12 @@ _loop0_25_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_247_var; + void *_tmp_249_var; while ( - (_tmp_247_var = _tmp_247_rule(p)) // '.' | '...' + (_tmp_249_var = _tmp_249_rule(p)) // '.' | '...' ) { - _res = _tmp_247_var; + _res = _tmp_249_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26732,12 +26736,12 @@ _loop1_26_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_248_var; + void *_tmp_250_var; while ( - (_tmp_248_var = _tmp_248_rule(p)) // '.' | '...' + (_tmp_250_var = _tmp_250_rule(p)) // '.' | '...' ) { - _res = _tmp_248_var; + _res = _tmp_250_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -27137,12 +27141,12 @@ _loop1_33_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_249_var; + void *_tmp_251_var; while ( - (_tmp_249_var = _tmp_249_rule(p)) // '@' named_expression NEWLINE + (_tmp_251_var = _tmp_251_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_249_var; + _res = _tmp_251_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30317,12 +30321,12 @@ _loop1_83_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_250_var; + void *_tmp_252_var; while ( - (_tmp_250_var = _tmp_250_rule(p)) // ',' expression + (_tmp_252_var = _tmp_252_rule(p)) // ',' expression ) { - _res = _tmp_250_var; + _res = _tmp_252_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30390,12 +30394,12 @@ _loop1_84_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_251_var; + void *_tmp_253_var; while ( - (_tmp_251_var = _tmp_251_rule(p)) // ',' star_expression + (_tmp_253_var = _tmp_253_rule(p)) // ',' star_expression ) { - _res = _tmp_251_var; + _res = _tmp_253_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30582,12 +30586,12 @@ _loop1_87_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_252_var; + void *_tmp_254_var; while ( - (_tmp_252_var = _tmp_252_rule(p)) // 'or' conjunction + (_tmp_254_var = _tmp_254_rule(p)) // 'or' conjunction ) { - _res = _tmp_252_var; + _res = _tmp_254_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30655,12 +30659,12 @@ _loop1_88_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_253_var; + void *_tmp_255_var; while ( - (_tmp_253_var = _tmp_253_rule(p)) // 'and' inversion + (_tmp_255_var = _tmp_255_rule(p)) // 'and' inversion ) { - _res = _tmp_253_var; + _res = _tmp_255_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30850,7 +30854,7 @@ _loop0_92_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_254_rule(p)) // slice | starred_expression + (elem = _tmp_256_rule(p)) // slice | starred_expression ) { _res = elem; @@ -30916,7 +30920,7 @@ _gather_91_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_254_rule(p)) // slice | starred_expression + (elem = _tmp_256_rule(p)) // slice | starred_expression && (seq = _loop0_92_rule(p)) // _loop0_92 ) @@ -32471,12 +32475,12 @@ _loop1_115_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_255_var; + void *_tmp_257_var; while ( - (_tmp_255_var = _tmp_255_rule(p)) // fstring | string + (_tmp_257_var = _tmp_257_rule(p)) // fstring | string ) { - _res = _tmp_255_var; + _res = _tmp_257_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32786,12 +32790,12 @@ _loop0_120_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_256_var; + void *_tmp_258_var; while ( - (_tmp_256_var = _tmp_256_rule(p)) // 'if' disjunction + (_tmp_258_var = _tmp_258_rule(p)) // 'if' disjunction ) { - _res = _tmp_256_var; + _res = _tmp_258_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32854,12 +32858,12 @@ _loop0_121_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_257_var; + void *_tmp_259_var; while ( - (_tmp_257_var = _tmp_257_rule(p)) // 'if' disjunction + (_tmp_259_var = _tmp_259_rule(p)) // 'if' disjunction ) { - _res = _tmp_257_var; + _res = _tmp_259_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32987,7 +32991,7 @@ _loop0_124_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -33054,7 +33058,7 @@ _gather_123_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && (seq = _loop0_124_rule(p)) // _loop0_124 ) @@ -33625,12 +33629,12 @@ _loop0_134_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_259_var; + void *_tmp_261_var; while ( - (_tmp_259_var = _tmp_259_rule(p)) // ',' star_target + (_tmp_261_var = _tmp_261_rule(p)) // ',' star_target ) { - _res = _tmp_259_var; + _res = _tmp_261_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33812,12 +33816,12 @@ _loop1_137_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_260_var; + void *_tmp_262_var; while ( - (_tmp_260_var = _tmp_260_rule(p)) // ',' star_target + (_tmp_262_var = _tmp_262_rule(p)) // ',' star_target ) { - _res = _tmp_260_var; + _res = _tmp_262_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35338,12 +35342,12 @@ _loop0_162_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_261_var; + void *_tmp_263_var; while ( - (_tmp_261_var = _tmp_261_rule(p)) // star_targets '=' + (_tmp_263_var = _tmp_263_rule(p)) // star_targets '=' ) { - _res = _tmp_261_var; + _res = _tmp_263_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35406,12 +35410,12 @@ _loop0_163_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_262_var; + void *_tmp_264_var; while ( - (_tmp_262_var = _tmp_262_rule(p)) // star_targets '=' + (_tmp_264_var = _tmp_264_rule(p)) // star_targets '=' ) { - _res = _tmp_262_var; + _res = _tmp_264_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -36454,15 +36458,15 @@ _tmp_179_rule(Parser *p) } D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_263_var; + void *_tmp_265_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_263_var = _tmp_263_rule(p)) // ')' | '**' + (_tmp_265_var = _tmp_265_rule(p)) // ')' | '**' ) { D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_263_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_265_var); goto done; } p->mark = _mark; @@ -37628,15 +37632,15 @@ _tmp_197_rule(Parser *p) } D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_264_var; + void *_tmp_266_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_264_var = _tmp_264_rule(p)) // ':' | '**' + (_tmp_266_var = _tmp_266_rule(p)) // ':' | '**' ) { D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_264_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_266_var); goto done; } p->mark = _mark; @@ -37987,7 +37991,7 @@ _tmp_202_rule(Parser *p) return _res; } -// _loop0_204: ',' (expression ['as' star_target]) +// _loop0_204: ',' dotted_name static asdl_seq * _loop0_204_rule(Parser *p) { @@ -38010,18 +38014,18 @@ _loop0_204_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expression ['as' star_target]) + { // ',' dotted_name if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); Token * _literal; - void *elem; + expr_ty elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_265_rule(p)) // expression ['as' star_target] + (elem = dotted_name_rule(p)) // dotted_name ) { _res = elem; @@ -38048,7 +38052,7 @@ _loop0_204_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_204[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38064,7 +38068,7 @@ _loop0_204_rule(Parser *p) return _seq; } -// _gather_203: (expression ['as' star_target]) _loop0_204 +// _gather_203: dotted_name _loop0_204 static asdl_seq * _gather_203_rule(Parser *p) { @@ -38078,27 +38082,27 @@ _gather_203_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_204 + { // dotted_name _loop0_204 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); - void *elem; + D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); + expr_ty elem; asdl_seq * seq; if ( - (elem = _tmp_265_rule(p)) // expression ['as' star_target] + (elem = dotted_name_rule(p)) // dotted_name && (seq = _loop0_204_rule(p)) // _loop0_204 ) { - D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_204")); } _res = NULL; done: @@ -38106,7 +38110,7 @@ _gather_203_rule(Parser *p) return _res; } -// _loop0_206: ',' (expressions ['as' star_target]) +// _loop0_206: ',' (expression ['as' star_target]) static asdl_seq * _loop0_206_rule(Parser *p) { @@ -38129,18 +38133,18 @@ _loop0_206_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expressions ['as' star_target]) + { // ',' (expression ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -38167,7 +38171,7 @@ _loop0_206_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_206[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38183,7 +38187,7 @@ _loop0_206_rule(Parser *p) return _seq; } -// _gather_205: (expressions ['as' star_target]) _loop0_206 +// _gather_205: (expression ['as' star_target]) _loop0_206 static asdl_seq * _gather_205_rule(Parser *p) { @@ -38197,27 +38201,27 @@ _gather_205_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_206 + { // (expression ['as' star_target]) _loop0_206 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expression ['as' star_target] && (seq = _loop0_206_rule(p)) // _loop0_206 ) { - D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); } _res = NULL; done: @@ -38225,7 +38229,7 @@ _gather_205_rule(Parser *p) return _res; } -// _loop0_208: ',' (expression ['as' star_target]) +// _loop0_208: ',' (expressions ['as' star_target]) static asdl_seq * _loop0_208_rule(Parser *p) { @@ -38248,18 +38252,18 @@ _loop0_208_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expression ['as' star_target]) + { // ',' (expressions ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_267_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -38286,7 +38290,7 @@ _loop0_208_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38302,7 +38306,7 @@ _loop0_208_rule(Parser *p) return _seq; } -// _gather_207: (expression ['as' star_target]) _loop0_208 +// _gather_207: (expressions ['as' star_target]) _loop0_208 static asdl_seq * _gather_207_rule(Parser *p) { @@ -38316,27 +38320,27 @@ _gather_207_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_208 + { // (expressions ['as' star_target]) _loop0_208 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_267_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expressions ['as' star_target] && (seq = _loop0_208_rule(p)) // _loop0_208 ) { - D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); } _res = NULL; done: @@ -38344,7 +38348,7 @@ _gather_207_rule(Parser *p) return _res; } -// _loop0_210: ',' (expressions ['as' star_target]) +// _loop0_210: ',' (expression ['as' star_target]) static asdl_seq * _loop0_210_rule(Parser *p) { @@ -38367,18 +38371,18 @@ _loop0_210_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expressions ['as' star_target]) + { // ',' (expression ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_268_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -38405,7 +38409,7 @@ _loop0_210_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38421,7 +38425,7 @@ _loop0_210_rule(Parser *p) return _seq; } -// _gather_209: (expressions ['as' star_target]) _loop0_210 +// _gather_209: (expression ['as' star_target]) _loop0_210 static asdl_seq * _gather_209_rule(Parser *p) { @@ -38435,27 +38439,27 @@ _gather_209_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_210 + { // (expression ['as' star_target]) _loop0_210 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); + D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_268_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expression ['as' star_target] && (seq = _loop0_210_rule(p)) // _loop0_210 ) { - D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); + D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_209[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); } _res = NULL; done: @@ -38463,65 +38467,7 @@ _gather_209_rule(Parser *p) return _res; } -// _tmp_211: 'except' | 'finally' -static void * -_tmp_211_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // 'except' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); - Token * _keyword; - if ( - (_keyword = _PyPegen_expect_token(p, 637)) // token='except' - ) - { - D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); - _res = _keyword; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); - } - { // 'finally' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); - Token * _keyword; - if ( - (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' - ) - { - D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); - _res = _keyword; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop0_212: block +// _loop0_212: ',' (expressions ['as' star_target]) static asdl_seq * _loop0_212_rule(Parser *p) { @@ -38544,18 +38490,27 @@ _loop0_212_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // block + { // ',' (expressions ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); - asdl_stmt_seq* block_var; + D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + Token * _literal; + void *elem; while ( - (block_var = block_rule(p)) // block + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = _tmp_270_rule(p)) // expressions ['as' star_target] ) { - _res = block_var; + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -38573,7 +38528,7 @@ _loop0_212_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_212[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38589,9 +38544,9 @@ _loop0_212_rule(Parser *p) return _seq; } -// _loop1_213: except_block +// _gather_211: (expressions ['as' star_target]) _loop0_212 static asdl_seq * -_loop1_213_rule(Parser *p) +_gather_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38601,70 +38556,39 @@ _loop1_213_rule(Parser *p) p->level--; return NULL; } - void *_res = NULL; + asdl_seq * _res = NULL; int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // except_block + { // (expressions ['as' star_target]) _loop0_212 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); - excepthandler_ty except_block_var; - while ( - (except_block_var = except_block_rule(p)) // except_block + D(fprintf(stderr, "%*c> _gather_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); + void *elem; + asdl_seq * seq; + if ( + (elem = _tmp_270_rule(p)) // expressions ['as' star_target] + && + (seq = _loop0_212_rule(p)) // _loop0_212 ) { - _res = except_block_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; + D(fprintf(stderr, "%*c+ _gather_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_213[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; + D(fprintf(stderr, "%*c%s _gather_211[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); + _res = NULL; + done: p->level--; - return _seq; + return _res; } -// _tmp_214: 'as' NAME +// _tmp_213: 'except' | 'finally' static void * -_tmp_214_rule(Parser *p) +_tmp_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38676,27 +38600,43 @@ _tmp_214_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // 'as' NAME + { // 'except' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; - expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 640)) // token='as' - && - (name_var = _PyPegen_name_token(p)) // NAME + (_keyword = _PyPegen_expect_token(p, 637)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_214[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); - _res = _PyPegen_dummy_name(p, _keyword, name_var); + D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_214[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); + } + { // 'finally' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + Token * _keyword; + if ( + (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' + ) + { + D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + _res = _keyword; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; done: @@ -38704,9 +38644,9 @@ _tmp_214_rule(Parser *p) return _res; } -// _loop0_215: block +// _loop0_214: block static asdl_seq * -_loop0_215_rule(Parser *p) +_loop0_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38732,7 +38672,7 @@ _loop0_215_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38755,7 +38695,7 @@ _loop0_215_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_215[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_214[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38772,9 +38712,9 @@ _loop0_215_rule(Parser *p) return _seq; } -// _loop1_216: except_star_block +// _loop1_215: except_block static asdl_seq * -_loop1_216_rule(Parser *p) +_loop1_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38795,18 +38735,18 @@ _loop1_216_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // except_star_block + { // except_block if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); - excepthandler_ty except_star_block_var; + D(fprintf(stderr, "%*c> _loop1_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + excepthandler_ty except_block_var; while ( - (except_star_block_var = except_star_block_rule(p)) // except_star_block + (except_block_var = except_block_rule(p)) // except_block ) { - _res = except_star_block_var; + _res = except_block_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -38823,8 +38763,8 @@ _loop1_216_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_216[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c%s _loop1_215[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -38845,9 +38785,192 @@ _loop1_216_rule(Parser *p) return _seq; } -// _tmp_217: expression ['as' NAME] +// _tmp_216: 'as' NAME static void * -_tmp_217_rule(Parser *p) +_tmp_216_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // 'as' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + Token * _keyword; + expr_ty name_var; + if ( + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' + && + (name_var = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + _res = _PyPegen_dummy_name(p, _keyword, name_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_217: block +static asdl_seq * +_loop0_217_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // block + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + asdl_stmt_seq* block_var; + while ( + (block_var = block_rule(p)) // block + ) + { + _res = block_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_217[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop1_218: except_star_block +static asdl_seq * +_loop1_218_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // except_star_block + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop1_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + excepthandler_ty except_star_block_var; + while ( + (except_star_block_var = except_star_block_rule(p)) // except_star_block + ) + { + _res = except_star_block_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop1_218[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); + } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _tmp_219: expression ['as' NAME] +static void * +_tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38864,22 +38987,22 @@ _tmp_217_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_269_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -38888,9 +39011,9 @@ _tmp_217_rule(Parser *p) return _res; } -// _tmp_218: 'as' NAME +// _tmp_220: 'as' NAME static void * -_tmp_218_rule(Parser *p) +_tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38907,7 +39030,7 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38916,12 +39039,12 @@ _tmp_218_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38930,9 +39053,9 @@ _tmp_218_rule(Parser *p) return _res; } -// _tmp_219: 'as' NAME +// _tmp_221: 'as' NAME static void * -_tmp_219_rule(Parser *p) +_tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38949,7 +39072,7 @@ _tmp_219_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38958,12 +39081,12 @@ _tmp_219_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38972,9 +39095,9 @@ _tmp_219_rule(Parser *p) return _res; } -// _tmp_220: NEWLINE | ':' +// _tmp_222: NEWLINE | ':' static void * -_tmp_220_rule(Parser *p) +_tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38991,18 +39114,18 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -39010,18 +39133,18 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -39030,9 +39153,9 @@ _tmp_220_rule(Parser *p) return _res; } -// _tmp_221: 'as' NAME +// _tmp_223: 'as' NAME static void * -_tmp_221_rule(Parser *p) +_tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39049,7 +39172,7 @@ _tmp_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -39058,12 +39181,12 @@ _tmp_221_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -39072,9 +39195,9 @@ _tmp_221_rule(Parser *p) return _res; } -// _tmp_222: 'as' NAME +// _tmp_224: 'as' NAME static void * -_tmp_222_rule(Parser *p) +_tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39091,7 +39214,7 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -39100,12 +39223,12 @@ _tmp_222_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -39114,9 +39237,9 @@ _tmp_222_rule(Parser *p) return _res; } -// _tmp_223: positional_patterns ',' +// _tmp_225: positional_patterns ',' static void * -_tmp_223_rule(Parser *p) +_tmp_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39133,7 +39256,7 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -39142,12 +39265,12 @@ _tmp_223_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -39156,9 +39279,9 @@ _tmp_223_rule(Parser *p) return _res; } -// _tmp_224: '->' expression +// _tmp_226: '->' expression static void * -_tmp_224_rule(Parser *p) +_tmp_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39175,7 +39298,7 @@ _tmp_224_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty expression_var; if ( @@ -39184,12 +39307,12 @@ _tmp_224_rule(Parser *p) (expression_var = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = _PyPegen_dummy_name(p, _literal, expression_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -39198,9 +39321,9 @@ _tmp_224_rule(Parser *p) return _res; } -// _tmp_225: '(' arguments? ')' +// _tmp_227: '(' arguments? ')' static void * -_tmp_225_rule(Parser *p) +_tmp_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39217,7 +39340,7 @@ _tmp_225_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -39230,12 +39353,12 @@ _tmp_225_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -39244,9 +39367,9 @@ _tmp_225_rule(Parser *p) return _res; } -// _tmp_226: '(' arguments? ')' +// _tmp_228: '(' arguments? ')' static void * -_tmp_226_rule(Parser *p) +_tmp_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39263,7 +39386,7 @@ _tmp_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -39276,12 +39399,12 @@ _tmp_226_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -39290,9 +39413,9 @@ _tmp_226_rule(Parser *p) return _res; } -// _loop0_228: ',' double_starred_kvpair +// _loop0_230: ',' double_starred_kvpair static asdl_seq * -_loop0_228_rule(Parser *p) +_loop0_230_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39318,7 +39441,7 @@ _loop0_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -39350,7 +39473,7 @@ _loop0_228_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_228[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -39367,9 +39490,9 @@ _loop0_228_rule(Parser *p) return _seq; } -// _gather_227: double_starred_kvpair _loop0_228 +// _gather_229: double_starred_kvpair _loop0_230 static asdl_seq * -_gather_227_rule(Parser *p) +_gather_229_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39381,27 +39504,27 @@ _gather_227_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_228 + { // double_starred_kvpair _loop0_230 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228")); + D(fprintf(stderr, "%*c> _gather_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_228_rule(p)) // _loop0_228 + (seq = _loop0_230_rule(p)) // _loop0_230 ) { - D(fprintf(stderr, "%*c+ _gather_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228")); + D(fprintf(stderr, "%*c+ _gather_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_227[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_228")); + D(fprintf(stderr, "%*c%s _gather_229[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_230")); } _res = NULL; done: @@ -39409,9 +39532,9 @@ _gather_227_rule(Parser *p) return _res; } -// _tmp_229: '}' | ',' +// _tmp_231: '}' | ',' static void * -_tmp_229_rule(Parser *p) +_tmp_231_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39428,18 +39551,18 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -39447,18 +39570,18 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -39467,9 +39590,9 @@ _tmp_229_rule(Parser *p) return _res; } -// _tmp_230: '}' | ',' +// _tmp_232: '}' | ',' static void * -_tmp_230_rule(Parser *p) +_tmp_232_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39486,18 +39609,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -39505,18 +39628,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -39525,9 +39648,9 @@ _tmp_230_rule(Parser *p) return _res; } -// _tmp_231: yield_expr | star_expressions +// _tmp_233: yield_expr | star_expressions static void * -_tmp_231_rule(Parser *p) +_tmp_233_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39544,18 +39667,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39563,18 +39686,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39583,9 +39706,9 @@ _tmp_231_rule(Parser *p) return _res; } -// _tmp_232: yield_expr | star_expressions +// _tmp_234: yield_expr | star_expressions static void * -_tmp_232_rule(Parser *p) +_tmp_234_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39602,18 +39725,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39621,18 +39744,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39641,9 +39764,9 @@ _tmp_232_rule(Parser *p) return _res; } -// _tmp_233: '=' | '!' | ':' | '}' +// _tmp_235: '=' | '!' | ':' | '}' static void * -_tmp_233_rule(Parser *p) +_tmp_235_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39660,18 +39783,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // '!' @@ -39679,18 +39802,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39698,18 +39821,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39717,18 +39840,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39737,9 +39860,9 @@ _tmp_233_rule(Parser *p) return _res; } -// _tmp_234: yield_expr | star_expressions +// _tmp_236: yield_expr | star_expressions static void * -_tmp_234_rule(Parser *p) +_tmp_236_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39756,18 +39879,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39775,18 +39898,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39795,9 +39918,9 @@ _tmp_234_rule(Parser *p) return _res; } -// _tmp_235: '!' | ':' | '}' +// _tmp_237: '!' | ':' | '}' static void * -_tmp_235_rule(Parser *p) +_tmp_237_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39814,18 +39937,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39833,18 +39956,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39852,18 +39975,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39872,9 +39995,9 @@ _tmp_235_rule(Parser *p) return _res; } -// _tmp_236: yield_expr | star_expressions +// _tmp_238: yield_expr | star_expressions static void * -_tmp_236_rule(Parser *p) +_tmp_238_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39891,18 +40014,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39910,18 +40033,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39930,9 +40053,9 @@ _tmp_236_rule(Parser *p) return _res; } -// _tmp_237: yield_expr | star_expressions +// _tmp_239: yield_expr | star_expressions static void * -_tmp_237_rule(Parser *p) +_tmp_239_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39949,18 +40072,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39968,18 +40091,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39988,9 +40111,9 @@ _tmp_237_rule(Parser *p) return _res; } -// _tmp_238: '!' NAME +// _tmp_240: '!' NAME static void * -_tmp_238_rule(Parser *p) +_tmp_240_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40007,7 +40130,7 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -40016,12 +40139,12 @@ _tmp_238_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -40030,9 +40153,9 @@ _tmp_238_rule(Parser *p) return _res; } -// _tmp_239: ':' | '}' +// _tmp_241: ':' | '}' static void * -_tmp_239_rule(Parser *p) +_tmp_241_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40049,18 +40172,18 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -40068,18 +40191,18 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -40088,9 +40211,9 @@ _tmp_239_rule(Parser *p) return _res; } -// _tmp_240: yield_expr | star_expressions +// _tmp_242: yield_expr | star_expressions static void * -_tmp_240_rule(Parser *p) +_tmp_242_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40107,18 +40230,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -40126,18 +40249,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -40146,9 +40269,9 @@ _tmp_240_rule(Parser *p) return _res; } -// _tmp_241: '!' NAME +// _tmp_243: '!' NAME static void * -_tmp_241_rule(Parser *p) +_tmp_243_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40165,7 +40288,7 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -40174,12 +40297,12 @@ _tmp_241_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -40188,9 +40311,9 @@ _tmp_241_rule(Parser *p) return _res; } -// _loop0_242: fstring_format_spec +// _loop0_244: fstring_format_spec static asdl_seq * -_loop0_242_rule(Parser *p) +_loop0_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40216,7 +40339,7 @@ _loop0_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -40239,7 +40362,7 @@ _loop0_242_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_242[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -40256,9 +40379,9 @@ _loop0_242_rule(Parser *p) return _seq; } -// _tmp_243: yield_expr | star_expressions +// _tmp_245: yield_expr | star_expressions static void * -_tmp_243_rule(Parser *p) +_tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40275,18 +40398,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -40294,18 +40417,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -40314,9 +40437,9 @@ _tmp_243_rule(Parser *p) return _res; } -// _tmp_244: '!' NAME +// _tmp_246: '!' NAME static void * -_tmp_244_rule(Parser *p) +_tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40333,7 +40456,7 @@ _tmp_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -40342,12 +40465,12 @@ _tmp_244_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -40356,9 +40479,9 @@ _tmp_244_rule(Parser *p) return _res; } -// _tmp_245: ':' | '}' +// _tmp_247: ':' | '}' static void * -_tmp_245_rule(Parser *p) +_tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40375,18 +40498,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -40394,18 +40517,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -40414,9 +40537,9 @@ _tmp_245_rule(Parser *p) return _res; } -// _tmp_246: star_targets '=' +// _tmp_248: star_targets '=' static void * -_tmp_246_rule(Parser *p) +_tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40433,7 +40556,7 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -40442,7 +40565,7 @@ _tmp_246_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40452,7 +40575,7 @@ _tmp_246_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40461,9 +40584,9 @@ _tmp_246_rule(Parser *p) return _res; } -// _tmp_247: '.' | '...' +// _tmp_249: '.' | '...' static void * -_tmp_247_rule(Parser *p) +_tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40480,18 +40603,18 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40499,18 +40622,18 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40519,9 +40642,9 @@ _tmp_247_rule(Parser *p) return _res; } -// _tmp_248: '.' | '...' +// _tmp_250: '.' | '...' static void * -_tmp_248_rule(Parser *p) +_tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40538,18 +40661,18 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40557,18 +40680,18 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40577,9 +40700,9 @@ _tmp_248_rule(Parser *p) return _res; } -// _tmp_249: '@' named_expression NEWLINE +// _tmp_251: '@' named_expression NEWLINE static void * -_tmp_249_rule(Parser *p) +_tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40596,7 +40719,7 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -40608,7 +40731,7 @@ _tmp_249_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40618,7 +40741,7 @@ _tmp_249_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -40627,9 +40750,9 @@ _tmp_249_rule(Parser *p) return _res; } -// _tmp_250: ',' expression +// _tmp_252: ',' expression static void * -_tmp_250_rule(Parser *p) +_tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40646,7 +40769,7 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -40655,7 +40778,7 @@ _tmp_250_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40665,7 +40788,7 @@ _tmp_250_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -40674,9 +40797,9 @@ _tmp_250_rule(Parser *p) return _res; } -// _tmp_251: ',' star_expression +// _tmp_253: ',' star_expression static void * -_tmp_251_rule(Parser *p) +_tmp_253_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40693,7 +40816,7 @@ _tmp_251_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -40702,7 +40825,7 @@ _tmp_251_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40712,7 +40835,7 @@ _tmp_251_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -40721,9 +40844,9 @@ _tmp_251_rule(Parser *p) return _res; } -// _tmp_252: 'or' conjunction +// _tmp_254: 'or' conjunction static void * -_tmp_252_rule(Parser *p) +_tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40740,7 +40863,7 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -40749,7 +40872,7 @@ _tmp_252_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40759,7 +40882,7 @@ _tmp_252_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -40768,9 +40891,9 @@ _tmp_252_rule(Parser *p) return _res; } -// _tmp_253: 'and' inversion +// _tmp_255: 'and' inversion static void * -_tmp_253_rule(Parser *p) +_tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40787,7 +40910,7 @@ _tmp_253_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -40796,7 +40919,7 @@ _tmp_253_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40806,7 +40929,7 @@ _tmp_253_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -40815,9 +40938,9 @@ _tmp_253_rule(Parser *p) return _res; } -// _tmp_254: slice | starred_expression +// _tmp_256: slice | starred_expression static void * -_tmp_254_rule(Parser *p) +_tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40834,18 +40957,18 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -40853,18 +40976,18 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -40873,9 +40996,9 @@ _tmp_254_rule(Parser *p) return _res; } -// _tmp_255: fstring | string +// _tmp_257: fstring | string static void * -_tmp_255_rule(Parser *p) +_tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40892,18 +41015,18 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -40911,18 +41034,18 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -40931,9 +41054,9 @@ _tmp_255_rule(Parser *p) return _res; } -// _tmp_256: 'if' disjunction +// _tmp_258: 'if' disjunction static void * -_tmp_256_rule(Parser *p) +_tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40950,7 +41073,7 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40959,7 +41082,7 @@ _tmp_256_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40969,7 +41092,7 @@ _tmp_256_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40978,9 +41101,9 @@ _tmp_256_rule(Parser *p) return _res; } -// _tmp_257: 'if' disjunction +// _tmp_259: 'if' disjunction static void * -_tmp_257_rule(Parser *p) +_tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40997,7 +41120,7 @@ _tmp_257_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -41006,7 +41129,7 @@ _tmp_257_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -41016,7 +41139,7 @@ _tmp_257_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -41025,9 +41148,9 @@ _tmp_257_rule(Parser *p) return _res; } -// _tmp_258: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_260: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_258_rule(Parser *p) +_tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41044,18 +41167,18 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -41063,20 +41186,20 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_270_var; + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_272_var; if ( - (_tmp_270_var = _tmp_270_rule(p)) // assignment_expression | expression !':=' + (_tmp_272_var = _tmp_272_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_270_var; + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_272_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -41085,9 +41208,9 @@ _tmp_258_rule(Parser *p) return _res; } -// _tmp_259: ',' star_target +// _tmp_261: ',' star_target static void * -_tmp_259_rule(Parser *p) +_tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41104,7 +41227,7 @@ _tmp_259_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -41113,7 +41236,7 @@ _tmp_259_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -41123,7 +41246,7 @@ _tmp_259_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -41132,9 +41255,9 @@ _tmp_259_rule(Parser *p) return _res; } -// _tmp_260: ',' star_target +// _tmp_262: ',' star_target static void * -_tmp_260_rule(Parser *p) +_tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41151,7 +41274,7 @@ _tmp_260_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -41160,7 +41283,7 @@ _tmp_260_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -41170,7 +41293,7 @@ _tmp_260_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -41179,9 +41302,9 @@ _tmp_260_rule(Parser *p) return _res; } -// _tmp_261: star_targets '=' +// _tmp_263: star_targets '=' static void * -_tmp_261_rule(Parser *p) +_tmp_263_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41198,7 +41321,7 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -41207,12 +41330,12 @@ _tmp_261_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -41221,9 +41344,9 @@ _tmp_261_rule(Parser *p) return _res; } -// _tmp_262: star_targets '=' +// _tmp_264: star_targets '=' static void * -_tmp_262_rule(Parser *p) +_tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41240,7 +41363,7 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -41249,12 +41372,12 @@ _tmp_262_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -41263,9 +41386,9 @@ _tmp_262_rule(Parser *p) return _res; } -// _tmp_263: ')' | '**' +// _tmp_265: ')' | '**' static void * -_tmp_263_rule(Parser *p) +_tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41282,18 +41405,18 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -41301,18 +41424,18 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -41321,9 +41444,9 @@ _tmp_263_rule(Parser *p) return _res; } -// _tmp_264: ':' | '**' +// _tmp_266: ':' | '**' static void * -_tmp_264_rule(Parser *p) +_tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41340,18 +41463,18 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -41359,18 +41482,18 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -41379,9 +41502,9 @@ _tmp_264_rule(Parser *p) return _res; } -// _tmp_265: expression ['as' star_target] +// _tmp_267: expression ['as' star_target] static void * -_tmp_265_rule(Parser *p) +_tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41398,22 +41521,22 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -41422,9 +41545,9 @@ _tmp_265_rule(Parser *p) return _res; } -// _tmp_266: expressions ['as' star_target] +// _tmp_268: expressions ['as' star_target] static void * -_tmp_266_rule(Parser *p) +_tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41441,22 +41564,22 @@ _tmp_266_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41465,9 +41588,9 @@ _tmp_266_rule(Parser *p) return _res; } -// _tmp_267: expression ['as' star_target] +// _tmp_269: expression ['as' star_target] static void * -_tmp_267_rule(Parser *p) +_tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41484,22 +41607,22 @@ _tmp_267_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_275_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -41508,9 +41631,9 @@ _tmp_267_rule(Parser *p) return _res; } -// _tmp_268: expressions ['as' star_target] +// _tmp_270: expressions ['as' star_target] static void * -_tmp_268_rule(Parser *p) +_tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41527,22 +41650,22 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_276_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41551,9 +41674,9 @@ _tmp_268_rule(Parser *p) return _res; } -// _tmp_269: 'as' NAME +// _tmp_271: 'as' NAME static void * -_tmp_269_rule(Parser *p) +_tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41570,7 +41693,7 @@ _tmp_269_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -41579,12 +41702,12 @@ _tmp_269_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -41593,9 +41716,9 @@ _tmp_269_rule(Parser *p) return _res; } -// _tmp_270: assignment_expression | expression !':=' +// _tmp_272: assignment_expression | expression !':=' static void * -_tmp_270_rule(Parser *p) +_tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41612,18 +41735,18 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -41631,7 +41754,7 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -41639,12 +41762,12 @@ _tmp_270_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -41653,9 +41776,9 @@ _tmp_270_rule(Parser *p) return _res; } -// _tmp_271: 'as' star_target +// _tmp_273: 'as' star_target static void * -_tmp_271_rule(Parser *p) +_tmp_273_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41672,7 +41795,7 @@ _tmp_271_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41681,12 +41804,12 @@ _tmp_271_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41695,9 +41818,9 @@ _tmp_271_rule(Parser *p) return _res; } -// _tmp_272: 'as' star_target +// _tmp_274: 'as' star_target static void * -_tmp_272_rule(Parser *p) +_tmp_274_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41714,7 +41837,7 @@ _tmp_272_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41723,12 +41846,12 @@ _tmp_272_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41737,9 +41860,9 @@ _tmp_272_rule(Parser *p) return _res; } -// _tmp_273: 'as' star_target +// _tmp_275: 'as' star_target static void * -_tmp_273_rule(Parser *p) +_tmp_275_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41756,7 +41879,7 @@ _tmp_273_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_275[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41765,12 +41888,12 @@ _tmp_273_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_275[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_275[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41779,9 +41902,9 @@ _tmp_273_rule(Parser *p) return _res; } -// _tmp_274: 'as' star_target +// _tmp_276: 'as' star_target static void * -_tmp_274_rule(Parser *p) +_tmp_276_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41798,7 +41921,7 @@ _tmp_274_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_276[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41807,12 +41930,12 @@ _tmp_274_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_276[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_276[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; From 3cc552331223f420fbc8977eef6105634594e5c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Jun 2023 01:07:58 -0700 Subject: [PATCH 0246/1206] [3.12] Docs: Avoid a DeprecationWarning in `pyspecific.py` when running with Sphinx >=6.1 (GH-105886) (#106010) Docs: Avoid a DeprecationWarning in `pyspecific.py` when running with Sphinx >=6.1 (GH-105886) (cherry picked from commit a72683ba8e0337650cc490dbe593a5e46aba60cb) Co-authored-by: Alex Waygood Co-authored-by: Hugo van Kemenade --- Doc/tools/extensions/pyspecific.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 3a5b26f7779618..8a9e2fc61327e7 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -14,29 +14,27 @@ from os import getenv, path from time import asctime from pprint import pformat + +from docutils import nodes, utils from docutils.io import StringOutput from docutils.parsers.rst import Directive from docutils.utils import new_document - -from docutils import nodes, utils - from sphinx import addnodes from sphinx.builders import Builder -try: - from sphinx.errors import NoUri -except ImportError: - from sphinx.environment import NoUri +from sphinx.domains.python import PyFunction, PyMethod +from sphinx.errors import NoUri from sphinx.locale import _ as sphinx_gettext -from sphinx.util import status_iterator, logging +from sphinx.util import logging from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import split_explicit_title from sphinx.writers.text import TextWriter, TextTranslator try: - from sphinx.domains.python import PyFunction, PyMethod + # Sphinx 6+ + from sphinx.util.display import status_iterator except ImportError: - from sphinx.domains.python import PyClassmember as PyMethod - from sphinx.domains.python import PyModulelevel as PyFunction + # Deprecated in Sphinx 6.1, will be removed in Sphinx 8 + from sphinx.util import status_iterator ISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s' From 1ffcd49be2a090375a77b3ad9dc5ccd8bfc2944f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Jun 2023 07:48:29 -0700 Subject: [PATCH 0247/1206] [3.12] Typing docs: improve the guidance on annotating tuples (GH-106021) (#106027) Typing docs: improve the guidance on annotating tuples (GH-106021) (cherry picked from commit 968435ddb1c1af9333befb26f7970cded8a5c710) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 93 ++++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index f6851199466f32..99a26d7a5e0fd9 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -346,6 +346,68 @@ Or by using the :class:`TypeVar` factory directly:: .. versionchanged:: 3.12 Syntactic support for generics is new in Python 3.12. +.. _annotating-tuples: + +Annotating tuples +================= + +For most containers in Python, the typing system assumes that all elements in +the container will be of the same type. For example:: + + from collections.abc import Mapping + + # Type checker will infer that all elements in ``x`` are meant to be ints + x: list[int] = [] + + # Type checker error: ``list`` only accepts a single type argument: + y: list[int, str] = [1, 'foo'] + + # Type checker will infer that all keys in ``y`` are meant to be strings, + # and that all values in ``y`` are meant to be either strings or ints + z: Mapping[str, str | int] = {} + +:class:`list` only accepts one type argument, so a type checker would emit an +error on the ``y`` assignment above. Similarly, +:class:`~collections.abc.Mapping` only accepts two type arguments: the first +indicates the type of the keys, and the second indicates the type of the +values. + +Unlike most other Python containers, however, it is common in idiomatic Python +code for tuples to have elements which are not all of the same type. For this +reason, tuples are special-cased in Python's typing system. :class:`tuple` +accepts *any number* of type arguments:: + + # OK: ``x`` is assigned to a tuple of length 1 where the sole element is an int + x: tuple[int] = (5,) + + # OK: ``y`` is assigned to a tuple of length 2; + # element 1 is an int, element 2 is a str + y: tuple[int, str] = (5, "foo") + + # Error: the type annotation indicates a tuple of length 1, + # but ``z`` has been assigned to a tuple of length 3 + z: tuple[int] = (1, 2, 3) + +To denote a tuple which could be of *any* length, and in which all elements are +of the same type ``T``, use ``tuple[T, ...]``. To denote an empty tuple, use +``tuple[()]``. Using plain ``tuple`` as an annotation is equivalent to using +``tuple[Any, ...]``:: + + x: tuple[int, ...] = (1, 2) + # These reassignments are OK: ``tuple[int, ...]`` indicates x can be of any length + x = (1, 2, 3) + x = () + # This reassignment is an error: all elements in ``x`` must be ints + x = ("foo", "bar") + + # ``y`` can only ever be assigned to an empty tuple + y: tuple[()] = () + + z: tuple = ("foo", "bar") + # These reassignments are OK: plain ``tuple`` is equivalent to ``tuple[Any, ...]`` + z = (1, 2, 3) + z = () + .. _user-defined-generics: User-defined generic types @@ -877,26 +939,6 @@ Special forms These can be used as types in annotations. They all support subscription using ``[]``, but each has a unique syntax. -.. data:: Tuple - - Deprecated alias for :class:`tuple`. - - ``Tuple[X, Y]`` is the type of a tuple of two items - with the first item of type X and the second of type Y. The type of - the empty tuple can be written as ``Tuple[()]``. - - Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding - to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, - use literal ellipsis, e.g. ``Tuple[int, ...]``. A plain ``Tuple`` annotation - is equivalent to ``tuple``, ``Tuple[Any, ...]``, or ``tuple[Any, ...]``. - - .. deprecated:: 3.9 - :class:`builtins.tuple ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - .. data:: Union Union type; ``Union[X, Y]`` is equivalent to ``X | Y`` and means either X or Y. @@ -3091,7 +3133,16 @@ Aliases to built-in types now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -.. note:: :data:`Tuple` is a special form. +.. data:: Tuple + + Deprecated alias for :class:`tuple`. + + :class:`tuple` and ``Tuple`` are special-cased in the type system; see + :ref:`annotating-tuples` for more details. + + .. deprecated:: 3.9 + :class:`builtins.tuple ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. _corresponding-to-types-in-collections: From 7d6ee298e96559e13d343b47ac489fcb4f219cd4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Jun 2023 08:26:37 -0700 Subject: [PATCH 0248/1206] [3.12] gh-105974: Revert unintentional behaviour change for protocols with non-callable members and custom `__subclasshook__` methods (GH-105976) (#106032) gh-105974: Revert unintentional behaviour change for protocols with non-callable members and custom `__subclasshook__` methods (GH-105976) (cherry picked from commit 9499b0f138cc53b9a2590350d0b545d2f69ee126) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 40 ++++++++++++ Lib/typing.py | 65 ++++++++++--------- ...-06-21-19-04-27.gh-issue-105974.M47n3t.rst | 6 ++ 3 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a1fa54a9f1cad2..c88152de7725fb 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3465,6 +3465,46 @@ def __subclasshook__(cls, other): self.assertIsSubclass(OKClass, C) self.assertNotIsSubclass(BadClass, C) + def test_custom_subclasshook_2(self): + @runtime_checkable + class HasX(Protocol): + # The presence of a non-callable member + # would mean issubclass() checks would fail with TypeError + # if it weren't for the custom `__subclasshook__` method + x = 1 + + @classmethod + def __subclasshook__(cls, other): + return hasattr(other, 'x') + + class Empty: pass + + class ImplementsHasX: + x = 1 + + self.assertIsInstance(ImplementsHasX(), HasX) + self.assertNotIsInstance(Empty(), HasX) + self.assertIsSubclass(ImplementsHasX, HasX) + self.assertNotIsSubclass(Empty, HasX) + + # isinstance() and issubclass() checks against this still raise TypeError, + # despite the presence of the custom __subclasshook__ method, + # as it's not decorated with @runtime_checkable + class NotRuntimeCheckable(Protocol): + @classmethod + def __subclasshook__(cls, other): + return hasattr(other, 'x') + + must_be_runtime_checkable = ( + "Instance and class checks can only be used " + "with @runtime_checkable protocols" + ) + + with self.assertRaisesRegex(TypeError, must_be_runtime_checkable): + issubclass(object, NotRuntimeCheckable) + with self.assertRaisesRegex(TypeError, must_be_runtime_checkable): + isinstance(object(), NotRuntimeCheckable) + def test_issubclass_fails_correctly(self): @runtime_checkable class P(Protocol): diff --git a/Lib/typing.py b/Lib/typing.py index 0b1d9689a6b7a8..9e2adbe2214a8a 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1822,14 +1822,17 @@ def __init__(cls, *args, **kwargs): def __subclasscheck__(cls, other): if cls is Protocol: return type.__subclasscheck__(cls, other) - if not isinstance(other, type): - # Same error message as for issubclass(1, int). - raise TypeError('issubclass() arg 1 must be a class') if ( getattr(cls, '_is_protocol', False) and not _allow_reckless_class_checks() ): - if not cls.__callable_proto_members_only__: + if not isinstance(other, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') + if ( + not cls.__callable_proto_members_only__ + and cls.__dict__.get("__subclasshook__") is _proto_hook + ): raise TypeError( "Protocols with non-method members don't support issubclass()" ) @@ -1873,6 +1876,30 @@ def __instancecheck__(cls, instance): return False +@classmethod +def _proto_hook(cls, other): + if not cls.__dict__.get('_is_protocol', False): + return NotImplemented + + for attr in cls.__protocol_attrs__: + for base in other.__mro__: + # Check if the members appears in the class dictionary... + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + + # ...or in annotations, if it is a sub-protocol. + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, collections.abc.Mapping) and + attr in annotations and + issubclass(other, Generic) and getattr(other, '_is_protocol', False)): + break + else: + return NotImplemented + return True + + class Protocol(Generic, metaclass=_ProtocolMeta): """Base class for protocol classes. @@ -1918,37 +1945,11 @@ def __init_subclass__(cls, *args, **kwargs): cls._is_protocol = any(b is Protocol for b in cls.__bases__) # Set (or override) the protocol subclass hook. - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', False): - return NotImplemented - - for attr in cls.__protocol_attrs__: - for base in other.__mro__: - # Check if the members appears in the class dictionary... - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - - # ...or in annotations, if it is a sub-protocol. - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, collections.abc.Mapping) and - attr in annotations and - issubclass(other, Generic) and getattr(other, '_is_protocol', False)): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: cls.__subclasshook__ = _proto_hook - # We have nothing more to do for non-protocols... - if not cls._is_protocol: - return - - # ... otherwise prohibit instantiation. - if cls.__init__ is Protocol.__init__: + # Prohibit instantiation for protocol classes + if cls._is_protocol and cls.__init__ is Protocol.__init__: cls.__init__ = _no_init_or_replace_init diff --git a/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst b/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst new file mode 100644 index 00000000000000..982192e59e3a50 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst @@ -0,0 +1,6 @@ +Fix bug where a :class:`typing.Protocol` class that had one or more +non-callable members would raise :exc:`TypeError` when :func:`issubclass` +was called against it, even if it defined a custom ``__subclasshook__`` +method. The behaviour in Python 3.11 and lower -- which has now been +restored -- was not to raise :exc:`TypeError` in these situations if a +custom ``__subclasshook__`` method was defined. Patch by Alex Waygood. From de1c090879b9fe81fc08271484036f3abb16f6e4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:35:00 -0700 Subject: [PATCH 0249/1206] [3.12] Typing docs: fix typo in annotating tuples comment (GH-106048) (#106049) Typing docs: fix typo in annotating tuples comment (GH-106048) (cherry picked from commit 8ef0ee4ebc84ee68f16cea85ffdb949ecccb4ba5) Co-authored-by: Eamon Tracey <66919574+EamonTracey@users.noreply.github.com> --- Doc/library/typing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 99a26d7a5e0fd9..4c6f89b2048c9d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -362,8 +362,8 @@ the container will be of the same type. For example:: # Type checker error: ``list`` only accepts a single type argument: y: list[int, str] = [1, 'foo'] - # Type checker will infer that all keys in ``y`` are meant to be strings, - # and that all values in ``y`` are meant to be either strings or ints + # Type checker will infer that all keys in ``z`` are meant to be strings, + # and that all values in ``z`` are meant to be either strings or ints z: Mapping[str, str | int] = {} :class:`list` only accepts one type argument, so a type checker would emit an From ef58c0428db898a725c090f0636156f3c28cd4ed Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 24 Jun 2023 16:25:47 +0100 Subject: [PATCH 0250/1206] [3.12] GH-104375: Use `versionchanged` to describe new arguments in pathlib docs (GH-104376, GH-106058) (cherry picked from commit 4a6c84fc1ea8f26d84a0fbeeff6f8dedc32263d4) --- Doc/library/pathlib.rst | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 39b9eb84e7e068..2fb4dc42f46feb 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -585,8 +585,8 @@ Pure paths provide the following methods and properties: Set *case_sensitive* to ``True`` or ``False`` to override this behaviour. - .. versionadded:: 3.12 - The *case_sensitive* argument. + .. versionchanged:: 3.12 + The *case_sensitive* parameter was added. .. method:: PurePath.relative_to(other, walk_up=False) @@ -627,8 +627,8 @@ Pure paths provide the following methods and properties: are present in the path; call :meth:`~Path.resolve` first if necessary to resolve symlinks. - .. versionadded:: 3.12 - The *walk_up* argument (old behavior is the same as ``walk_up=False``). + .. versionchanged:: 3.12 + The *walk_up* parameter was added (old behavior is the same as ``walk_up=False``). .. deprecated-removed:: 3.12 3.14 @@ -928,8 +928,9 @@ call fails (for example because the path doesn't exist). Return only directories if *pattern* ends with a pathname components separator (:data:`~os.sep` or :data:`~os.altsep`). - .. versionadded:: 3.12 - The *case_sensitive* argument. + .. versionchanged:: 3.12 + The *case_sensitive* parameter was added. + .. method:: Path.group() @@ -1313,8 +1314,8 @@ call fails (for example because the path doesn't exist). infinite loop is encountered along the resolution path, :exc:`RuntimeError` is raised. - .. versionadded:: 3.6 - The *strict* argument (pre-3.6 behavior is strict). + .. versionchanged:: 3.6 + The *strict* parameter was added (pre-3.6 behavior is strict). .. method:: Path.rglob(pattern, *, case_sensitive=None) @@ -1340,8 +1341,9 @@ call fails (for example because the path doesn't exist). Return only directories if *pattern* ends with a pathname components separator (:data:`~os.sep` or :data:`~os.altsep`). - .. versionadded:: 3.12 - The *case_sensitive* argument. + .. versionchanged:: 3.12 + The *case_sensitive* parameter was added. + .. method:: Path.rmdir() From 746c0f3d8fddb2a88028707b18930243c86ce437 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 24 Jun 2023 16:30:27 -0700 Subject: [PATCH 0251/1206] [3.12] gh-106033: [docs] Improve C API GetItem & HasAttr notes. (GH-106047) (#106070) gh-106033: [docs] Improve C API GetItem & HasAttr notes. (GH-106047) Use a note:: tag so that these dict and object API deficiencies show up clearly. A caution:: tag was considered, but our current python docs rendering doesn't do much with that (no box or color change). warning:: seemed too extreme. note looks good. (cherry picked from commit 19d6511b0b8f3f74e668ae32ccef89bcbf1a8a62) Co-authored-by: Gregory P. Smith --- Doc/c-api/dict.rst | 19 ++++++++++++------- Doc/c-api/object.rst | 18 +++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 0ca8ad624b2034..bd0c36a217e2ce 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -98,9 +98,11 @@ Dictionary Objects Return the object from dictionary *p* which has a key *key*. Return ``NULL`` if the key *key* is not present, but *without* setting an exception. - Note that exceptions which occur while calling :meth:`__hash__` and - :meth:`__eq__` methods will get suppressed. - To get error reporting use :c:func:`PyDict_GetItemWithError()` instead. + .. note:: + + Exceptions that occur while this calls :meth:`~object.__hash__` and + :meth:`~object.__eq__` methods are silently ignored. + Prefer the :c:func:`PyDict_GetItemWithError` function instead. .. versionchanged:: 3.10 Calling this API without :term:`GIL` held had been allowed for historical @@ -120,10 +122,13 @@ Dictionary Objects This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a :c:expr:`const char*`, rather than a :c:expr:`PyObject*`. - Note that exceptions which occur while calling :meth:`__hash__` and - :meth:`__eq__` methods and creating a temporary string object - will get suppressed. - To get error reporting use :c:func:`PyDict_GetItemWithError()` instead. + .. note:: + + Exceptions that occur while this calls :meth:`~object.__hash__` and + :meth:`~object.__eq__` methods or while creating the temporary :class:`str` + object are silently ignored. + Prefer using the :c:func:`PyDict_GetItemWithError` function with your own + :c:func:`PyUnicode_FromString` *key* instead. .. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *defaultobj) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index a25ff244c9f07c..22e7458013fb3d 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -33,9 +33,11 @@ Object Protocol is equivalent to the Python expression ``hasattr(o, attr_name)``. This function always succeeds. - Note that exceptions which occur while calling :meth:`__getattr__` and - :meth:`__getattribute__` methods will get suppressed. - To get error reporting use :c:func:`PyObject_GetAttr()` instead. + .. note:: + + Exceptions that occur when this calls :meth:`~object.__getattr__` and + :meth:`~object.__getattribute__` methods are silently ignored. + For proper error handling, use :c:func:`PyObject_GetAttr` instead. .. c:function:: int PyObject_HasAttrString(PyObject *o, const char *attr_name) @@ -44,10 +46,12 @@ Object Protocol is equivalent to the Python expression ``hasattr(o, attr_name)``. This function always succeeds. - Note that exceptions which occur while calling :meth:`__getattr__` and - :meth:`__getattribute__` methods and creating a temporary string object - will get suppressed. - To get error reporting use :c:func:`PyObject_GetAttrString()` instead. + .. note:: + + Exceptions that occur when this calls :meth:`~object.__getattr__` and + :meth:`~object.__getattribute__` methods or while creating the temporary :class:`str` + object are silently ignored. + For proper error handling, use :c:func:`PyObject_GetAttrString` instead. .. c:function:: PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name) From 9cd366462b8c45c5cd9e99b76047b517cece939e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 25 Jun 2023 02:36:34 +0300 Subject: [PATCH 0252/1206] =?UTF-8?q?[3.12]=20gh-106033:=20Get=20rid=20of?= =?UTF-8?q?=20new=20occurrences=20of=20PyDict=5FGetItem=20and=20Py?= =?UTF-8?q?=E2=80=A6=20(#106041)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [3.12] gh-106033: Get rid of new occurrences of PyDict_GetItem and PyObject_HasAttr (GH-106034) These functions are broken by design because they discard any exceptions raised inside, including MemoryError and KeyboardInterrupt. They should not be used in new code. (cherry picked from commit 1d33d5378058671bfabb6f4d4b5bfd4726973ff9) --- Modules/_hashopenssl.c | 13 +++++++------ Modules/_testcapi/code.c | 2 +- Objects/exceptions.c | 31 +++++++++++++++---------------- Objects/typeobject.c | 5 ++++- Python/pythonrun.c | 12 +++++------- 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 4b425f4147513e..af6d1b23d3ae91 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -383,14 +383,15 @@ py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type } else { _hashlibstate *state = get_hashlib_state(module); // borrowed ref - name_obj = PyDict_GetItem(state->constructs, digestmod); + name_obj = PyDict_GetItemWithError(state->constructs, digestmod); } if (name_obj == NULL) { - _hashlibstate *state = get_hashlib_state(module); - PyErr_Clear(); - PyErr_Format( - state->unsupported_digestmod_error, - "Unsupported digestmod %R", digestmod); + if (!PyErr_Occurred()) { + _hashlibstate *state = get_hashlib_state(module); + PyErr_Format( + state->unsupported_digestmod_error, + "Unsupported digestmod %R", digestmod); + } return NULL; } diff --git a/Modules/_testcapi/code.c b/Modules/_testcapi/code.c index 84c668cd6b3b00..cadaf5eb94692e 100644 --- a/Modules/_testcapi/code.c +++ b/Modules/_testcapi/code.c @@ -9,7 +9,7 @@ get_code_extra_index(PyInterpreterState* interp) { PyObject *interp_dict = PyInterpreterState_GetDict(interp); // borrowed assert(interp_dict); // real users would handle missing dict... somehow - PyObject *index_obj = PyDict_GetItemString(interp_dict, key); // borrowed + PyObject *index_obj = _PyDict_GetItemStringWithError(interp_dict, key); // borrowed Py_ssize_t index = 0; if (!index_obj) { if (PyErr_Occurred()) { diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 7bec7395cc7f0b..f376ff24386a37 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -207,22 +207,21 @@ BaseException_add_note(PyObject *self, PyObject *note) return NULL; } - if (!PyObject_HasAttr(self, &_Py_ID(__notes__))) { - PyObject *new_notes = PyList_New(0); - if (new_notes == NULL) { + PyObject *notes; + if (_PyObject_LookupAttr(self, &_Py_ID(__notes__), ¬es) < 0) { + return NULL; + } + if (notes == NULL) { + notes = PyList_New(0); + if (notes == NULL) { return NULL; } - if (PyObject_SetAttr(self, &_Py_ID(__notes__), new_notes) < 0) { - Py_DECREF(new_notes); + if (PyObject_SetAttr(self, &_Py_ID(__notes__), notes) < 0) { + Py_DECREF(notes); return NULL; } - Py_DECREF(new_notes); } - PyObject *notes = PyObject_GetAttr(self, &_Py_ID(__notes__)); - if (notes == NULL) { - return NULL; - } - if (!PyList_Check(notes)) { + else if (!PyList_Check(notes)) { Py_DECREF(notes); PyErr_SetString(PyExc_TypeError, "Cannot add note: __notes__ is not a list"); return NULL; @@ -941,11 +940,11 @@ exceptiongroup_subset( PyException_SetContext(eg, PyException_GetContext(orig)); PyException_SetCause(eg, PyException_GetCause(orig)); - if (PyObject_HasAttr(orig, &_Py_ID(__notes__))) { - PyObject *notes = PyObject_GetAttr(orig, &_Py_ID(__notes__)); - if (notes == NULL) { - goto error; - } + PyObject *notes; + if (_PyObject_LookupAttr(orig, &_Py_ID(__notes__), ¬es) < 0) { + goto error; + } + if (notes) { if (PySequence_Check(notes)) { /* Make a copy so the parts have independent notes lists. */ PyObject *notes_copy = PySequence_List(notes); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index bf33bde2571012..966471e9341a85 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1507,11 +1507,14 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context) static PyObject * type_get_type_params(PyTypeObject *type, void *context) { - PyObject *params = PyDict_GetItem(lookup_tp_dict(type), &_Py_ID(__type_params__)); + PyObject *params = PyDict_GetItemWithError(lookup_tp_dict(type), &_Py_ID(__type_params__)); if (params) { return Py_NewRef(params); } + if (PyErr_Occurred()) { + return NULL; + } return PyTuple_New(0); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 05e7b4370869af..99e2eec453ee4b 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1100,15 +1100,13 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value) return 0; } - if (!PyObject_HasAttr(value, &_Py_ID(__notes__))) { - return 0; - } - PyObject *notes = PyObject_GetAttr(value, &_Py_ID(__notes__)); - if (notes == NULL) { - return -1; + PyObject *notes; + int res = _PyObject_LookupAttr(value, &_Py_ID(__notes__), ¬es); + if (res <= 0) { + return res; } if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) { - int res = 0; + res = 0; if (write_indented_margin(ctx, f) < 0) { res = -1; } From f930bee0037b7c54ded9043618bcae65f018ef03 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Jun 2023 01:16:12 -0700 Subject: [PATCH 0253/1206] [3.12] Docs: add links to 'callable' term in sqlite3 docs (GH-106072) (#106073) (cherry picked from commit bef1c8761e3b0dfc5708747bb646ad8b669cbd67) Co-authored-by: Erlend E. Aasland --- Doc/library/sqlite3.rst | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index e7129fb3e4de6d..3ca8ea9011c7e0 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -413,15 +413,15 @@ Module functions .. function:: register_adapter(type, adapter, /) - Register an *adapter* callable to adapt the Python type *type* into an - SQLite type. + Register an *adapter* :term:`callable` to adapt the Python type *type* + into an SQLite type. The adapter is called with a Python object of type *type* as its sole argument, and must return a value of a :ref:`type that SQLite natively understands `. .. function:: register_converter(typename, converter, /) - Register the *converter* callable to convert SQLite objects of type + Register the *converter* :term:`callable` to convert SQLite objects of type *typename* into a Python object of a specific type. The converter is invoked for all SQLite values of type *typename*; it is passed a :class:`bytes` object and should return an object of the @@ -484,7 +484,7 @@ Module constants SQLITE_DENY SQLITE_IGNORE - Flags that should be returned by the *authorizer_callback* callable + Flags that should be returned by the *authorizer_callback* :term:`callable` passed to :meth:`Connection.set_authorizer`, to indicate whether: * Access is allowed (:const:`!SQLITE_OK`), @@ -629,8 +629,8 @@ Connection objects Create and return a :class:`Cursor` object. The cursor method accepts a single optional parameter *factory*. If - supplied, this must be a callable returning an instance of :class:`Cursor` - or its subclasses. + supplied, this must be a :term:`callable` returning + an instance of :class:`Cursor` or its subclasses. .. method:: blobopen(table, column, row, /, *, readonly=False, name="main") @@ -723,7 +723,7 @@ Connection objects If ``-1``, it may take any number of arguments. :param func: - A callable that is called when the SQL function is invoked. + A :term:`callable` that is called when the SQL function is invoked. The callable must return :ref:`a type natively supported by SQLite `. Set to ``None`` to remove an existing SQL function. @@ -948,9 +948,10 @@ Connection objects .. method:: set_authorizer(authorizer_callback) - Register callable *authorizer_callback* to be invoked for each attempt to - access a column of a table in the database. The callback should return - one of :const:`SQLITE_OK`, :const:`SQLITE_DENY`, or :const:`SQLITE_IGNORE` + Register :term:`callable` *authorizer_callback* to be invoked + for each attempt to access a column of a table in the database. + The callback should return one of :const:`SQLITE_OK`, + :const:`SQLITE_DENY`, or :const:`SQLITE_IGNORE` to signal how access to the column should be handled by the underlying SQLite library. @@ -973,7 +974,7 @@ Connection objects .. method:: set_progress_handler(progress_handler, n) - Register callable *progress_handler* to be invoked for every *n* + Register :term:`callable` *progress_handler* to be invoked for every *n* instructions of the SQLite virtual machine. This is useful if you want to get called from SQLite during long-running operations, for example to update a GUI. @@ -988,8 +989,8 @@ Connection objects .. method:: set_trace_callback(trace_callback) - Register callable *trace_callback* to be invoked for each SQL statement - that is actually executed by the SQLite backend. + Register :term:`callable` *trace_callback* to be invoked + for each SQL statement that is actually executed by the SQLite backend. The only argument passed to the callback is the statement (as :class:`str`) that is being executed. The return value of the callback is @@ -1139,8 +1140,8 @@ Connection objects Defaults to ``-1``. :param progress: - If set to a callable, it is invoked with three integer arguments for - every backup iteration: + If set to a :term:`callable`, + it is invoked with three integer arguments for every backup iteration: the *status* of the last iteration, the *remaining* number of pages still to be copied, and the *total* number of pages. @@ -1404,8 +1405,8 @@ Connection objects .. attribute:: text_factory - A callable that accepts a :class:`bytes` parameter and returns a text - representation of it. + A :term:`callable` that accepts a :class:`bytes` parameter + and returns a text representation of it. The callable is invoked for SQLite values with the ``TEXT`` data type. By default, this attribute is set to :class:`str`. If you want to return ``bytes`` instead, set *text_factory* to ``bytes``. From f955ed9da74e50f3901fbefb2e9a9309563077c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Jun 2023 04:18:22 -0700 Subject: [PATCH 0254/1206] [3.12] Add end-of-file-fixer to pre-commit (GH-106065) (#106080) Add end-of-file-fixer to pre-commit (GH-106065) (cherry picked from commit 8c24a837371439b8e922ff47275085b581f510c5) Co-authored-by: Hugo van Kemenade --- .pre-commit-config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 464bcde6e98424..d62c57c044728f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,6 +3,9 @@ repos: rev: v4.4.0 hooks: - id: check-yaml + - id: end-of-file-fixer + types: [python] + exclude: Lib/test/coding20731.py - id: trailing-whitespace types_or: [c, python, rst] From e9366df3ecb360882020131def3f5c400ae54ba8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 25 Jun 2023 08:14:18 -0700 Subject: [PATCH 0255/1206] [3.12] gh-104212: Explain how to port imp.load_source() (GH-105978) (#106083) gh-104212: Explain how to port imp.load_source() (GH-105978) Explain how to port removed imp.load_source() to importlib in What's New in Python 3.12. (cherry picked from commit 18a7c86697493510993e43bafe8bd4046928bec5) Co-authored-by: Victor Stinner --- Doc/whatsnew/3.12.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ed4657c5b7a4a2..e06faf3ccaa1a6 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1385,6 +1385,21 @@ Removed ``imp.source_from_cache()`` :func:`importlib.util.source_from_cache` ================================= ======================================= + * Replace ``imp.load_source()`` with:: + + import importlib.util + import importlib.machinery + + def load_source(modname, filename): + loader = importlib.machinery.SourceFileLoader(modname, filename) + spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) + module = importlib.util.module_from_spec(spec) + # The module is always executed and not cached in sys.modules. + # Uncomment the following line to cache the module. + # sys.modules[module.__name__] = module + loader.exec_module(module) + return module + * Removed :mod:`!imp` functions and attributes with no replacements: * undocumented functions: @@ -1393,7 +1408,6 @@ Removed * ``imp.load_compiled()`` * ``imp.load_dynamic()`` * ``imp.load_package()`` - * ``imp.load_source()`` * ``imp.lock_held()``, ``imp.acquire_lock()``, ``imp.release_lock()``: the locking scheme has changed in Python 3.3 to per-module locks. From b786fe8a0913e4ecfc5f04749a36a85a8aa6fc1c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 01:31:01 -0700 Subject: [PATCH 0256/1206] [3.12] gh-105979: Fix exception handling in `unmarshal_frozen_code` (`Python/import.c`) (GH-105980) (#106055) gh-105979: Fix exception handling in `unmarshal_frozen_code` (`Python/import.c`) (GH-105980) (cherry picked from commit cd5280367a3a7065d13b8f7234474f7a2e9a18fd) Co-authored-by: chgnrdv <52372310+chgnrdv@users.noreply.github.com> --- Lib/test/test_import/__init__.py | 8 ++++++++ .../2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst | 1 + Python/import.c | 1 + 3 files changed, 10 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 71a50bcbeedf9b..ee9fe4d574dd42 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -23,6 +23,7 @@ import unittest from unittest import mock import _testinternalcapi +import _imp from test.support import os_helper from test.support import ( @@ -763,6 +764,13 @@ def test_dll_dependency_import(self): env=env, cwd=os.path.dirname(pyexe)) + def test_issue105979(self): + # this used to crash + with self.assertRaises(ImportError) as cm: + _imp.get_frozen_object("x", b"6\'\xd5Cu\x12") + self.assertIn("Frozen object named 'x' is invalid", + str(cm.exception)) + @skip_if_dont_write_bytecode class FilePermissionTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst new file mode 100644 index 00000000000000..be6962afd0c78f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst @@ -0,0 +1 @@ +Fix crash in :func:`!_imp.get_frozen_object` due to improper exception handling. diff --git a/Python/import.c b/Python/import.c index 24723d64bd0c2a..d10c5ce63a2c8b 100644 --- a/Python/import.c +++ b/Python/import.c @@ -2053,6 +2053,7 @@ unmarshal_frozen_code(PyInterpreterState *interp, struct frozen_info *info) PyObject *co = PyMarshal_ReadObjectFromString(info->data, info->size); if (co == NULL) { /* Does not contain executable code. */ + PyErr_Clear(); set_frozen_error(FROZEN_INVALID, info->nameobj); return NULL; } From 592d1eadc6266fa1c43fce54af540b63ceb09e1f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 01:32:00 -0700 Subject: [PATCH 0257/1206] [3.12] gh-84436: update docs on Py_None/Py_True/Py_False/Py_Ellipsis becoming immortal (GH-105195) (#105977) gh-84436: update docs on Py_None/Py_True/Py_False/Py_Ellipsis becoming immortal (GH-105195) (cherry picked from commit a2392720d6108041d17960a86514ba859b436f05) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Doc/c-api/bool.rst | 25 ++++++++++++++----------- Doc/c-api/none.rst | 10 +++++----- Doc/c-api/slice.rst | 9 ++++++--- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/Doc/c-api/bool.rst b/Doc/c-api/bool.rst index c197d447e9618c..b2d8f2124fc203 100644 --- a/Doc/c-api/bool.rst +++ b/Doc/c-api/bool.rst @@ -6,7 +6,7 @@ Boolean Objects --------------- Booleans in Python are implemented as a subclass of integers. There are only -two booleans, :const:`Py_False` and :const:`Py_True`. As such, the normal +two booleans, :c:data:`Py_False` and :c:data:`Py_True`. As such, the normal creation and deletion functions don't apply to booleans. The following macros are available, however. @@ -19,29 +19,32 @@ are available, however. .. c:var:: PyObject* Py_False - The Python ``False`` object. This object has no methods. It needs to be - treated just like any other object with respect to reference counts. + The Python ``False`` object. This object has no methods and is + `immortal `_. + +.. versionchanged:: 3.12 + :c:data:`Py_False` is immortal. .. c:var:: PyObject* Py_True - The Python ``True`` object. This object has no methods. It needs to be treated - just like any other object with respect to reference counts. + The Python ``True`` object. This object has no methods and is + `immortal `_. + +.. versionchanged:: 3.12 + :c:data:`Py_True` is immortal. .. c:macro:: Py_RETURN_FALSE - Return :const:`Py_False` from a function, properly incrementing its reference - count. + Return :c:data:`Py_False` from a function. .. c:macro:: Py_RETURN_TRUE - Return :const:`Py_True` from a function, properly incrementing its reference - count. + Return :c:data:`Py_True` from a function. .. c:function:: PyObject* PyBool_FromLong(long v) - Return a new reference to :const:`Py_True` or :const:`Py_False` depending on the - truth value of *v*. + Return :c:data:`Py_True` or :c:data:`Py_False`, depending on the truth value of *v*. diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst index b84a16a28ead56..1a497652ac5655 100644 --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -15,12 +15,12 @@ same reason. .. c:var:: PyObject* Py_None - The Python ``None`` object, denoting lack of value. This object has no methods. - It needs to be treated just like any other object with respect to reference - counts. + The Python ``None`` object, denoting lack of value. This object has no methods + and is `immortal `_. +.. versionchanged:: 3.12 + :c:data:`Py_None` is immortal. .. c:macro:: Py_RETURN_NONE - Properly handle returning :c:data:`Py_None` from within a C function (that is, - increment the reference count of ``None`` and return it.) + Return :c:data:`Py_None` from a function. diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst index 33169ccce89043..c54a659cf2ffd8 100644 --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -118,6 +118,9 @@ Ellipsis Object .. c:var:: PyObject *Py_Ellipsis - The Python ``Ellipsis`` object. This object has no methods. It needs to be - treated just like any other object with respect to reference counts. Like - :c:data:`Py_None` it is a singleton object. + The Python ``Ellipsis`` object. This object has no methods. Like + :c:data:`Py_None`, it is an `immortal `_. + singleton object. + + .. versionchanged:: 3.12 + :c:data:`Py_Ellipsis` is immortal. From 84189640b72cb64d8be297ac1574351f7a611d2a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 01:43:24 -0700 Subject: [PATCH 0258/1206] [3.12] Improve typing docs on the type of class objects (GH-106081) (#106096) Improve typing docs on the type of class objects (GH-106081) (cherry picked from commit 3eeb8c89063d5ac22c0b1d26e4ae2fd12c149650) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 108 ++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 4c6f89b2048c9d..12a20ae543c77b 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -408,6 +408,52 @@ of the same type ``T``, use ``tuple[T, ...]``. To denote an empty tuple, use z = (1, 2, 3) z = () +.. _type-of-class-objects: + +The type of class objects +========================= + +A variable annotated with ``C`` may accept a value of type ``C``. In +contrast, a variable annotated with ``type[C]`` (or +:class:`typing.Type[C] `) may accept values that are classes +themselves -- specifically, it will accept the *class object* of ``C``. For +example:: + + a = 3 # Has type ``int``` + b = int # Has type ``type[int]`` + c = type(a) # Also has type ``type[int]`` + +Note that ``type[C]`` is covariant:: + + class User: ... + class ProUser(User): ... + class TeamUser(User): ... + + def make_new_user(user_class: type[User]) -> User: + # ... + return user_class() + + make_new_user(User) # OK + make_new_user(ProUser) # Also OK: ``type[ProUser]`` is a subtype of ``type[User]`` + make_new_user(TeamUser) # Still fine + make_new_user(User()) # Error: expected ``type[User]`` but got ``User`` + make_new_user(int) # Error: ``type[int]`` is not a subtype of ``type[User]`` + +The only legal parameters for :class:`type` are classes, :data:`Any`, +:ref:`type variables `, and unions of any of these types. +For example:: + + def new_non_team_user(user_class: type[BasicUser | ProUser]): ... + + new_non_team_user(BasicUser) # OK + new_non_team_user(ProUser) # OK + new_non_team_user(TeamUser) # Error: ``type[TeamUser]`` is not a subtype + # of ``type[BasicUser | ProUser]`` + new_non_team_user(User) # Also an error + +``type[Any]`` is equivalent to :class:`type`, which is the root of Python's +:ref:`metaclass hierarchy `. + .. _user-defined-generics: User-defined generic types @@ -1093,55 +1139,6 @@ These can be used as types in annotations. They all support subscription using ``ParamSpec`` and ``Concatenate``). * :class:`ParamSpec` and :class:`Callable`. - -.. class:: Type(Generic[CT_co]) - - Deprecated alias to :class:`type`. - - A variable annotated with ``C`` may accept a value of type ``C``. In - contrast, a variable annotated with ``type[C]`` or ``Type[C]`` may accept values that are - classes themselves -- specifically, it will accept the *class object* of - ``C``. For example:: - - a = 3 # Has type 'int' - b = int # Has type 'Type[int]' - c = type(a) # Also has type 'Type[int]' - - Note that ``Type[C]`` is covariant:: - - class User: ... - class BasicUser(User): ... - class ProUser(User): ... - class TeamUser(User): ... - - # Accepts User, BasicUser, ProUser, TeamUser, ... - def make_new_user(user_class: Type[User]) -> User: - # ... - return user_class() - - The fact that ``Type[C]`` is covariant implies that all subclasses of - ``C`` should implement the same constructor signature and class method - signatures as ``C``. The type checker should flag violations of this, - but should also allow constructor calls in subclasses that match the - constructor calls in the indicated base class. How the type checker is - required to handle this particular case may change in future revisions of - :pep:`484`. - - The only legal parameters for :class:`Type` are classes, :data:`Any`, - :ref:`type variables `, and unions of any of these types. - For example:: - - def new_non_team_user(user_class: Type[BasicUser | ProUser]): ... - - ``Type[Any]`` is equivalent to ``Type`` which in turn is equivalent - to ``type``, which is the root of Python's metaclass hierarchy. - - .. versionadded:: 3.5.2 - - .. deprecated:: 3.9 - :class:`builtins.type ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - .. data:: Literal Special typing form to define "literal types". @@ -3144,6 +3141,19 @@ Aliases to built-in types :class:`builtins.tuple ` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. +.. class:: Type(Generic[CT_co]) + + Deprecated alias to :class:`type`. + + See :ref:`type-of-class-objects` for details on using :class:`type` or + ``typing.Type`` in type annotations. + + .. versionadded:: 3.5.2 + + .. deprecated:: 3.9 + :class:`builtins.type ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + .. _corresponding-to-types-in-collections: Aliases to types in :mod:`collections` From 9e6f8d46150c1a0af09d68ce63c603cf321994aa Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:21:28 +0530 Subject: [PATCH 0259/1206] =?UTF-8?q?[3.12]=20gh-105987:=20Fix=20reference?= =?UTF-8?q?=20counting=20issue=20in=20`=5Fasyncio.=5Fswap=5Fcur=E2=80=A6?= =?UTF-8?q?=20(#106099)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [3.12] gh-105987: Fix reference counting issue in `_asyncio._swap_current_task` (GH-105989). (cherry picked from commit d2cbb6e918d9ea39f0dd44acb53270f2dac07454) Co-authored-by: chgnrdv <52372310+chgnrdv@users.noreply.github.com> --- .../test_asyncio/test_eager_task_factory.py | 19 ++++++++++++++++++- ...-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst | 1 + Modules/_asynciomodule.c | 11 +++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py index fe690934292a86..346888735ff70b 100644 --- a/Lib/test/test_asyncio/test_eager_task_factory.py +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -12,7 +12,7 @@ from asyncio import tasks from test.test_asyncio import utils as test_utils from test.test_asyncio.test_tasks import get_innermost_context -from test import support +from test.support.script_helper import assert_python_ok MOCK_ANY = mock.ANY @@ -228,6 +228,23 @@ class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): Task = getattr(tasks, '_CTask', None) + def test_issue105987(self): + code = """if 1: + from _asyncio import _swap_current_task + + class DummyTask: + pass + + class DummyLoop: + pass + + l = DummyLoop() + _swap_current_task(l, DummyTask()) + t = _swap_current_task(l, None) + """ + + _, out, err = assert_python_ok("-c", code) + self.assertFalse(err) class AsyncTaskCounter: def __init__(self, loop, *, task_class, eager): diff --git a/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst b/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst new file mode 100644 index 00000000000000..0bc97da4edf0f9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst @@ -0,0 +1 @@ +Fix crash due to improper reference counting in :mod:`asyncio` eager task factory internal routines. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 7e33558dba3e32..a465090bfaaa38 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2047,20 +2047,23 @@ swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task) } prev_task = Py_None; } + Py_INCREF(prev_task); if (task == Py_None) { if (_PyDict_DelItem_KnownHash(state->current_tasks, loop, hash) == -1) { - return NULL; + goto error; } } else { if (_PyDict_SetItem_KnownHash(state->current_tasks, loop, task, hash) == -1) { - return NULL; + goto error; } } - Py_INCREF(prev_task); - return prev_task; + +error: + Py_DECREF(prev_task); + return NULL; } /* ----- Task */ From 8d5d60f72da9a9a150e24ccf75029d85cf4e4fc0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 05:26:15 -0700 Subject: [PATCH 0260/1206] [3.12] gh-106075: add `asyncio.taskgroups.__all__` to `asyncio.__all__` (GH-106090) (#106098) gh-106075: add `asyncio.taskgroups.__all__` to `asyncio.__all__` (GH-106090) (cherry picked from commit a12e8ffb49e05a1d1874389318911ce9685db232) Co-authored-by: James Webber Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Lib/asyncio/__init__.py | 1 + Lib/asyncio/taskgroups.py | 2 +- Misc/ACKS | 1 + .../next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py index fed16ec7c67fac..03165a425eb7d2 100644 --- a/Lib/asyncio/__init__.py +++ b/Lib/asyncio/__init__.py @@ -34,6 +34,7 @@ streams.__all__ + subprocess.__all__ + tasks.__all__ + + taskgroups.__all__ + threads.__all__ + timeouts.__all__ + transports.__all__) diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 06b2e0db86a1fe..930da53d908e36 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -2,7 +2,7 @@ # license: PSFL. -__all__ = ["TaskGroup"] +__all__ = ("TaskGroup",) from . import events from . import exceptions diff --git a/Misc/ACKS b/Misc/ACKS index be8755637ffa3c..454b63155f013c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1946,6 +1946,7 @@ Colin Watson David Watson Aaron Watters Alex Waygood +James Webber Russel Webber Henrik Weber Leon Weber diff --git a/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst b/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst new file mode 100644 index 00000000000000..d2687154a58594 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst @@ -0,0 +1 @@ +Added `asyncio.taskgroups.__all__` to `asyncio.__all__` for export in star imports. From e923971c6d99c67d80265be95dabe491327b3244 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 09:11:48 -0700 Subject: [PATCH 0261/1206] [3.12] Update test.support.interpreters to include missing RunFailedError import (GH-103841) (#106110) (cherry picked from commit 1a2bc94fc2bbdf5f810b441ebbbd8fec95a3207c) Co-authored-by: Bruce Eckel Co-authored-by: Alex Waygood --- Lib/test/support/interpreters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/support/interpreters.py b/Lib/test/support/interpreters.py index eeff3abe0324e5..5c484d1170d1d9 100644 --- a/Lib/test/support/interpreters.py +++ b/Lib/test/support/interpreters.py @@ -5,7 +5,7 @@ import _xxinterpchannels as _channels # aliases: -from _xxsubinterpreters import is_shareable +from _xxsubinterpreters import is_shareable, RunFailedError from _xxinterpchannels import ( ChannelError, ChannelNotFoundError, ChannelEmptyError, ) From fa3a75dc68514c1b7e8c154a731c67a52ff64d3f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 09:26:40 -0700 Subject: [PATCH 0262/1206] [3.12] gh-106111: Remove zipapp documentation on creating a Windows executable (GH-106112) (#106114) Remove zipapp documentation on creating a Windows executable (cherry picked from commit 5d4dbf0e309255e5bce9e31d805a8f950ebf9161) Co-authored-by: Paul Moore --- Doc/library/zipapp.rst | 115 ++++------------------------------------- 1 file changed, 9 insertions(+), 106 deletions(-) diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index 981020b13cd988..8cee85b32d2a83 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -303,115 +303,18 @@ the Python interpreter registers the ``.pyz`` and ``.pyzw`` file extensions when installed. -Making a Windows executable -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -On Windows, registration of the ``.pyz`` extension is optional, and -furthermore, there are certain places that don't recognise registered -extensions "transparently" (the simplest example is that -``subprocess.run(['myapp'])`` won't find your application - you need to -explicitly specify the extension). - -On Windows, therefore, it is often preferable to create an executable from the -zipapp. This is relatively easy, although it does require a C compiler. The -basic approach relies on the fact that zipfiles can have arbitrary data -prepended, and Windows exe files can have arbitrary data appended. So by -creating a suitable launcher and tacking the ``.pyz`` file onto the end of it, -you end up with a single-file executable that runs your application. - -A suitable launcher can be as simple as the following:: - - #define Py_LIMITED_API 1 - #include "Python.h" - - #define WIN32_LEAN_AND_MEAN - #include - - #ifdef WINDOWS - int WINAPI wWinMain( - HINSTANCE hInstance, /* handle to current instance */ - HINSTANCE hPrevInstance, /* handle to previous instance */ - LPWSTR lpCmdLine, /* pointer to command line */ - int nCmdShow /* show state of window */ - ) - #else - int wmain() - #endif - { - wchar_t **myargv = _alloca((__argc + 1) * sizeof(wchar_t*)); - myargv[0] = __wargv[0]; - memcpy(myargv + 1, __wargv, __argc * sizeof(wchar_t *)); - return Py_Main(__argc+1, myargv); - } - -If you define the ``WINDOWS`` preprocessor symbol, this will generate a -GUI executable, and without it, a console executable. - -To compile the executable, you can either just use the standard MSVC -command line tools, or you can take advantage of the fact that distutils -knows how to compile Python source:: - - >>> from distutils.ccompiler import new_compiler - >>> import distutils.sysconfig - >>> import sys - >>> import os - >>> from pathlib import Path - - >>> def compile(src): - >>> src = Path(src) - >>> cc = new_compiler() - >>> exe = src.stem - >>> cc.add_include_dir(distutils.sysconfig.get_python_inc()) - >>> cc.add_library_dir(os.path.join(sys.base_exec_prefix, 'libs')) - >>> # First the CLI executable - >>> objs = cc.compile([str(src)]) - >>> cc.link_executable(objs, exe) - >>> # Now the GUI executable - >>> cc.define_macro('WINDOWS') - >>> objs = cc.compile([str(src)]) - >>> cc.link_executable(objs, exe + 'w') - - >>> if __name__ == "__main__": - >>> compile("zastub.c") - -The resulting launcher uses the "Limited ABI", so it will run unchanged with -any version of Python 3.x. All it needs is for Python (``python3.dll``) to be -on the user's ``PATH``. - -For a fully standalone distribution, you can distribute the launcher with your -application appended, bundled with the Python "embedded" distribution. This -will run on any PC with the appropriate architecture (32 bit or 64 bit). - - Caveats ~~~~~~~ -There are some limitations to the process of bundling your application into -a single file. In most, if not all, cases they can be addressed without -needing major changes to your application. - -1. If your application depends on a package that includes a C extension, that - package cannot be run from a zip file (this is an OS limitation, as executable - code must be present in the filesystem for the OS loader to load it). In this - case, you can exclude that dependency from the zipfile, and either require - your users to have it installed, or ship it alongside your zipfile and add code - to your ``__main__.py`` to include the directory containing the unzipped - module in ``sys.path``. In this case, you will need to make sure to ship - appropriate binaries for your target architecture(s) (and potentially pick the - correct version to add to ``sys.path`` at runtime, based on the user's machine). - -2. If you are shipping a Windows executable as described above, you either need to - ensure that your users have ``python3.dll`` on their PATH (which is not the - default behaviour of the installer) or you should bundle your application with - the embedded distribution. - -3. The suggested launcher above uses the Python embedding API. This means that in - your application, ``sys.executable`` will be your application, and *not* a - conventional Python interpreter. Your code and its dependencies need to be - prepared for this possibility. For example, if your application uses the - :mod:`multiprocessing` module, it will need to call - :func:`multiprocessing.set_executable` to let the module know where to find the - standard Python interpreter. +If your application depends on a package that includes a C extension, that +package cannot be run from a zip file (this is an OS limitation, as executable +code must be present in the filesystem for the OS loader to load it). In this +case, you can exclude that dependency from the zipfile, and either require +your users to have it installed, or ship it alongside your zipfile and add code +to your ``__main__.py`` to include the directory containing the unzipped +module in ``sys.path``. In this case, you will need to make sure to ship +appropriate binaries for your target architecture(s) (and potentially pick the +correct version to add to ``sys.path`` at runtime, based on the user's machine). The Python Zip Application Archive Format From ea6a4b7523a356b3e3c9182ad34b23f91885a335 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 11:12:52 -0700 Subject: [PATCH 0263/1206] [3.12] gh-106107: document correct error that's raised when a mutable default value for a field is detected (gh-106109) (gh-106115) gh-106107: document correct error that's raised when a mutable default value for a field is detected (gh-106109) (cherry picked from commit 512f299e557f4ab60768d36cee9968bd92116367) Co-authored-by: Roderich Schupp --- Doc/library/dataclasses.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index a5b20149921042..535a60ccca8d07 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -738,7 +738,7 @@ for ``x`` when creating a class instance will share the same copy of ``x``. Because dataclasses just use normal Python class creation they also share this behavior. There is no general way for Data Classes to detect this condition. Instead, the -:func:`dataclass` decorator will raise a :exc:`TypeError` if it +:func:`dataclass` decorator will raise a :exc:`ValueError` if it detects an unhashable default parameter. The assumption is that if a value is unhashable, it is mutable. This is a partial solution, but it does protect against many common errors. From 1acfecbc0041b8a3b6c017d23ebed55aba39de6b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 12:11:49 -0700 Subject: [PATCH 0264/1206] [3.12] Revert "GH-96145: Add AttrDict to JSON module for use with object_hook (GH-96146)" (GH-105948) (#106117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "GH-96145: Add AttrDict to JSON module for use with object_hook (GH-96146)" (GH-105948) This reverts commit 1f0eafa844bf5a380603d55e8d4b42d8c2a3439d. (cherry picked from commit d3af83b9342457d8b24476baeb799f7506ff04f3) Co-authored-by: Åukasz Langa --- Doc/library/json.rst | 43 ------ Doc/whatsnew/3.12.rst | 8 - Lib/json/__init__.py | 52 +------ Lib/test/test_json/__init__.py | 1 - Lib/test/test_json/test_attrdict.py | 145 ------------------ ...3-06-20-23-18-45.gh-issue-96145.o5dTRM.rst | 1 + 6 files changed, 2 insertions(+), 248 deletions(-) delete mode 100644 Lib/test/test_json/test_attrdict.py create mode 100644 Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst diff --git a/Doc/library/json.rst b/Doc/library/json.rst index ef58dd09423640..5383614575c213 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -9,11 +9,6 @@ **Source code:** :source:`Lib/json/__init__.py` -.. testsetup:: * - - import json - from json import AttrDict - -------------- `JSON (JavaScript Object Notation) `_, specified by @@ -548,44 +543,6 @@ Exceptions .. versionadded:: 3.5 -.. class:: AttrDict(**kwargs) - AttrDict(mapping, **kwargs) - AttrDict(iterable, **kwargs) - - Subclass of :class:`dict` that also supports attribute style dotted access. - - This class is intended for use with the :attr:`object_hook` in - :func:`json.load` and :func:`json.loads`: - - .. doctest:: - - >>> json_string = '{"mercury": 88, "venus": 225, "earth": 365, "mars": 687}' - >>> orbital_period = json.loads(json_string, object_hook=AttrDict) - >>> orbital_period['earth'] # Dict style lookup - 365 - >>> orbital_period.earth # Attribute style lookup - 365 - >>> orbital_period.keys() # All dict methods are present - dict_keys(['mercury', 'venus', 'earth', 'mars']) - - Attribute style access only works for keys that are valid attribute - names. In contrast, dictionary style access works for all keys. For - example, ``d.two words`` contains a space and is not syntactically - valid Python, so ``d["two words"]`` should be used instead. - - If a key has the same name as a dictionary method, then a dictionary - lookup finds the key and an attribute lookup finds the method: - - .. doctest:: - - >>> d = AttrDict(items=50) - >>> d['items'] # Lookup the key - 50 - >>> d.items() # Call the method - dict_items([('items', 50)]) - - .. versionadded:: 3.12 - Standard Compliance and Interoperability ---------------------------------------- diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index e06faf3ccaa1a6..782a5013e869c7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -593,14 +593,6 @@ itertools tuples where the last batch may be shorter than the rest. (Contributed by Raymond Hettinger in :gh:`98363`.) -json ----- - -* Added :class:`json.AttrDict` for use with ``object_hook`` in :func:`json.load` - or :func:`json.loads`. This is a subclass of :class:`dict` that also supports - attribute style dotted access. - (Contributed by Raymond Hettinger in :gh:`96145`.) - math ---- diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 256e76a0a67f8f..ed2c74771ea87d 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -97,7 +97,7 @@ """ __version__ = '2.0.9' __all__ = [ - 'dump', 'dumps', 'load', 'loads', 'AttrDict', + 'dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', ] @@ -357,53 +357,3 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None, if parse_constant is not None: kw['parse_constant'] = parse_constant return cls(**kw).decode(s) - -class AttrDict(dict): - """Dict like object that supports attribute style dotted access. - - This class is intended for use with the *object_hook* in json.loads(): - - >>> from json import loads, AttrDict - >>> json_string = '{"mercury": 88, "venus": 225, "earth": 365, "mars": 687}' - >>> orbital_period = loads(json_string, object_hook=AttrDict) - >>> orbital_period['earth'] # Dict style lookup - 365 - >>> orbital_period.earth # Attribute style lookup - 365 - >>> orbital_period.keys() # All dict methods are present - dict_keys(['mercury', 'venus', 'earth', 'mars']) - - Attribute style access only works for keys that are valid attribute names. - In contrast, dictionary style access works for all keys. - For example, ``d.two words`` contains a space and is not syntactically - valid Python, so ``d["two words"]`` should be used instead. - - If a key has the same name as dictionary method, then a dictionary - lookup finds the key and an attribute lookup finds the method: - - >>> d = AttrDict(items=50) - >>> d['items'] # Lookup the key - 50 - >>> d.items() # Call the method - dict_items([('items', 50)]) - - """ - __slots__ = () - - def __getattr__(self, attr): - try: - return self[attr] - except KeyError: - raise AttributeError(attr) from None - - def __setattr__(self, attr, value): - self[attr] = value - - def __delattr__(self, attr): - try: - del self[attr] - except KeyError: - raise AttributeError(attr) from None - - def __dir__(self): - return list(self) + dir(type(self)) diff --git a/Lib/test/test_json/__init__.py b/Lib/test/test_json/__init__.py index 37b2e0d5e26d16..74b64ed86a3183 100644 --- a/Lib/test/test_json/__init__.py +++ b/Lib/test/test_json/__init__.py @@ -18,7 +18,6 @@ class PyTest(unittest.TestCase): json = pyjson loads = staticmethod(pyjson.loads) dumps = staticmethod(pyjson.dumps) - AttrDict = pyjson.AttrDict JSONDecodeError = staticmethod(pyjson.JSONDecodeError) @unittest.skipUnless(cjson, 'requires _json') diff --git a/Lib/test/test_json/test_attrdict.py b/Lib/test/test_json/test_attrdict.py deleted file mode 100644 index 143ea462d310aa..00000000000000 --- a/Lib/test/test_json/test_attrdict.py +++ /dev/null @@ -1,145 +0,0 @@ -from test.test_json import PyTest -import pickle -import sys -import unittest - -kepler_dict = { - "orbital_period": { - "mercury": 88, - "venus": 225, - "earth": 365, - "mars": 687, - "jupiter": 4331, - "saturn": 10_756, - "uranus": 30_687, - "neptune": 60_190, - }, - "dist_from_sun": { - "mercury": 58, - "venus": 108, - "earth": 150, - "mars": 228, - "jupiter": 778, - "saturn": 1_400, - "uranus": 2_900, - "neptune": 4_500, - } -} - -class TestAttrDict(PyTest): - - def test_dict_subclass(self): - self.assertTrue(issubclass(self.AttrDict, dict)) - - def test_slots(self): - d = self.AttrDict(x=1, y=2) - with self.assertRaises(TypeError): - vars(d) - - def test_constructor_signatures(self): - AttrDict = self.AttrDict - target = dict(x=1, y=2) - self.assertEqual(AttrDict(x=1, y=2), target) # kwargs - self.assertEqual(AttrDict(dict(x=1, y=2)), target) # mapping - self.assertEqual(AttrDict(dict(x=1, y=0), y=2), target) # mapping, kwargs - self.assertEqual(AttrDict([('x', 1), ('y', 2)]), target) # iterable - self.assertEqual(AttrDict([('x', 1), ('y', 0)], y=2), target) # iterable, kwargs - - def test_getattr(self): - d = self.AttrDict(x=1, y=2) - self.assertEqual(d.x, 1) - with self.assertRaises(AttributeError): - d.z - - def test_setattr(self): - d = self.AttrDict(x=1, y=2) - d.x = 3 - d.z = 5 - self.assertEqual(d, dict(x=3, y=2, z=5)) - - def test_delattr(self): - d = self.AttrDict(x=1, y=2) - del d.x - self.assertEqual(d, dict(y=2)) - with self.assertRaises(AttributeError): - del d.z - - def test_dir(self): - d = self.AttrDict(x=1, y=2) - self.assertTrue(set(dir(d)), set(dir(dict)).union({'x', 'y'})) - - def test_repr(self): - # This repr is doesn't round-trip. It matches a regular dict. - # That seems to be the norm for AttrDict recipes being used - # in the wild. Also it supports the design concept that an - # AttrDict is just like a regular dict but has optional - # attribute style lookup. - self.assertEqual(repr(self.AttrDict(x=1, y=2)), - repr(dict(x=1, y=2))) - - def test_overlapping_keys_and_methods(self): - d = self.AttrDict(items=50) - self.assertEqual(d['items'], 50) - self.assertEqual(d.items(), dict(d).items()) - - def test_invalid_attribute_names(self): - d = self.AttrDict({ - 'control': 'normal case', - 'class': 'keyword', - 'two words': 'contains space', - 'hypen-ate': 'contains a hyphen' - }) - self.assertEqual(d.control, dict(d)['control']) - self.assertEqual(d['class'], dict(d)['class']) - self.assertEqual(d['two words'], dict(d)['two words']) - self.assertEqual(d['hypen-ate'], dict(d)['hypen-ate']) - - def test_object_hook_use_case(self): - AttrDict = self.AttrDict - json_string = self.dumps(kepler_dict) - kepler_ad = self.loads(json_string, object_hook=AttrDict) - - self.assertEqual(kepler_ad, kepler_dict) # Match regular dict - self.assertIsInstance(kepler_ad, AttrDict) # Verify conversion - self.assertIsInstance(kepler_ad.orbital_period, AttrDict) # Nested - - # Exercise dotted lookups - self.assertEqual(kepler_ad.orbital_period, kepler_dict['orbital_period']) - self.assertEqual(kepler_ad.orbital_period.earth, - kepler_dict['orbital_period']['earth']) - self.assertEqual(kepler_ad['orbital_period'].earth, - kepler_dict['orbital_period']['earth']) - - # Dict style error handling and Attribute style error handling - with self.assertRaises(KeyError): - kepler_ad.orbital_period['pluto'] - with self.assertRaises(AttributeError): - kepler_ad.orbital_period.Pluto - - # Order preservation - self.assertEqual(list(kepler_ad.items()), list(kepler_dict.items())) - self.assertEqual(list(kepler_ad.orbital_period.items()), - list(kepler_dict['orbital_period'].items())) - - # Round trip - self.assertEqual(self.dumps(kepler_ad), json_string) - - def test_pickle(self): - AttrDict = self.AttrDict - json_string = self.dumps(kepler_dict) - kepler_ad = self.loads(json_string, object_hook=AttrDict) - - # Pickling requires the cached module to be the real module - cached_module = sys.modules.get('json') - sys.modules['json'] = self.json - try: - for protocol in range(pickle.HIGHEST_PROTOCOL + 1): - kepler_ad2 = pickle.loads(pickle.dumps(kepler_ad, protocol)) - self.assertEqual(kepler_ad2, kepler_ad) - self.assertEqual(type(kepler_ad2), AttrDict) - finally: - sys.modules['json'] = cached_module - - -if __name__ == "__main__": - unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst b/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst new file mode 100644 index 00000000000000..f4fb0e46ce5e57 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst @@ -0,0 +1 @@ +Reverted addition of ``json.AttrDict``. From 364cb6683bc6c11af2b62ca4bc5100078d381479 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 20:41:52 -0700 Subject: [PATCH 0265/1206] [3.12] gh-84976: Add back UTC to datetime.__all__ (GH-104920) (#106019) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Lib/datetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/datetime.py b/Lib/datetime.py index bad8beb4f6b026..a33d2d724cb33d 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -6,4 +6,4 @@ from _pydatetime import __doc__ __all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo", - "MINYEAR", "MAXYEAR") + "MINYEAR", "MAXYEAR", "UTC") From 1bb2bf7cd6d8dc8c644e9591282a70f6b3550026 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 20:43:20 -0700 Subject: [PATCH 0266/1206] [3.12] gh-106030: Miscellaneous fixes in Python/suggestions.c (GH-106031) (#106036) Co-authored-by: Serhiy Storchaka --- Python/suggestions.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/Python/suggestions.c b/Python/suggestions.c index f2c018ef2c4533..ad58393490efc2 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -151,15 +151,15 @@ calculate_suggestions(PyObject *dir, } for (int i = 0; i < dir_size; ++i) { PyObject *item = PyList_GET_ITEM(dir, i); + if (_PyUnicode_Equal(name, item)) { + continue; + } Py_ssize_t item_size; const char *item_str = PyUnicode_AsUTF8AndSize(item, &item_size); if (item_str == NULL) { PyMem_Free(buffer); return NULL; } - if (PyUnicode_CompareWithASCIIString(name, item_str) == 0) { - continue; - } // No more than 1/3 of the involved characters should need changed. Py_ssize_t max_distance = (name_size + item_size + 3) * MOVE_COST / 6; // Don't take matches we've already beaten. @@ -220,37 +220,48 @@ get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame) assert(code != NULL && code->co_localsplusnames != NULL); PyObject *varnames = _PyCode_GetVarnames(code); + Py_DECREF(code); if (varnames == NULL) { return NULL; } PyObject *dir = PySequence_List(varnames); Py_DECREF(varnames); - Py_DECREF(code); if (dir == NULL) { return NULL; } // Are we inside a method and the instance has an attribute called 'name'? - if (PySequence_Contains(dir, &_Py_ID(self)) > 0) { + int res = PySequence_Contains(dir, &_Py_ID(self)); + if (res < 0) { + goto error; + } + if (res > 0) { PyObject* locals = PyFrame_GetLocals(frame); if (!locals) { goto error; } - PyObject* self = PyDict_GetItem(locals, &_Py_ID(self)); /* borrowed */ - Py_DECREF(locals); + PyObject* self = PyDict_GetItemWithError(locals, &_Py_ID(self)); /* borrowed */ if (!self) { + Py_DECREF(locals); goto error; } - if (PyObject_HasAttr(self, name)) { + PyObject *value; + res = _PyObject_LookupAttr(self, name, &value); + Py_DECREF(locals); + if (res < 0) { + goto error; + } + if (value) { + Py_DECREF(value); Py_DECREF(dir); - return PyUnicode_FromFormat("self.%S", name); + return PyUnicode_FromFormat("self.%U", name); } } PyObject *suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); - if (suggestions != NULL) { + if (suggestions != NULL || PyErr_Occurred()) { return suggestions; } @@ -260,7 +271,7 @@ get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame) } suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); - if (suggestions != NULL) { + if (suggestions != NULL || PyErr_Occurred()) { return suggestions; } @@ -319,15 +330,16 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) assert(frame != NULL); PyObject* suggestion = get_suggestions_for_name_error(name, frame); - bool is_stdlib_module = is_name_stdlib_module(name); - - if (suggestion == NULL && !is_stdlib_module) { + if (suggestion == NULL && PyErr_Occurred()) { return NULL; } // Add a trailer ". Did you mean: (...)?" PyObject* result = NULL; - if (!is_stdlib_module) { + if (!is_name_stdlib_module(name)) { + if (suggestion == NULL) { + return NULL; + } result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); } else if (suggestion == NULL) { result = PyUnicode_FromFormat(". Did you forget to import %R?", name); From c2e8e347b37784e83ff1807d1e91035a38c17957 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 21:32:16 -0700 Subject: [PATCH 0267/1206] [3.12] GH-105774: Clarify operation of normalize() (GH-106093) (GH-106128) --- Doc/library/decimal.rst | 43 +++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 0b4a4973cb4da0..018ec1abf36406 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -743,12 +743,23 @@ Decimal objects .. method:: normalize(context=None) - Normalize the number by stripping the rightmost trailing zeros and - converting any result equal to ``Decimal('0')`` to - ``Decimal('0e0')``. Used for producing canonical values for attributes - of an equivalence class. For example, ``Decimal('32.100')`` and - ``Decimal('0.321000e+2')`` both normalize to the equivalent value - ``Decimal('32.1')``. + Used for producing canonical values of an equivalence + class within either the current context or the specified context. + + This has the same semantics as the unary plus operation, except that if + the final result is finite it is reduced to its simplest form, with all + trailing zeros removed and its sign preserved. That is, while the + coefficient is non-zero and a multiple of ten the coefficient is divided + by ten and the exponent is incremented by 1. Otherwise (the coefficient is + zero) the exponent is set to 0. In all cases the sign is unchanged. + + For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both + normalize to the equivalent value ``Decimal('32.1')``. + + Note that rounding is applied *before* reducing to simplest form. + + In the latest versions of the specification, this operation is also known + as ``reduce``. .. method:: number_class(context=None) @@ -2078,6 +2089,26 @@ representative: >>> [v.normalize() for v in values] [Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')] +Q. When does rounding occur in a computation? + +A. It occurs *after* the computation. The philosophy of the decimal +specification is that numbers are considered exact and are created +independent of the current context. They can even have greater +precision than current context. Computations process with those +exact inputs and then rounding (or other context operations) is +applied to the *result* of the computation:: + + >>> getcontext().prec = 5 + >>> pi = Decimal('3.1415926535') # More than 5 digits + >>> pi # All digits are retained + Decimal('3.1415926535') + >>> pi + 0 # Rounded after an addition + Decimal('3.1416') + >>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round + Decimal('3.1415') + >>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded + Decimal('3.1416') + Q. Some decimal values always print with exponential notation. Is there a way to get a non-exponential representation? From 0efbe4d1899cff34033183649c48151849d67c27 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 26 Jun 2023 22:49:32 -0700 Subject: [PATCH 0268/1206] [3.12] gh-106123: Modules/_sha3 appears to no longer be necessary (GH-106124) (#106127) Co-authored-by: Skip Montanaro --- configure | 1 - configure.ac | 1 - 2 files changed, 2 deletions(-) diff --git a/configure b/configure index e89155b5bbef94..248b14e254f6db 100755 --- a/configure +++ b/configure @@ -27291,7 +27291,6 @@ SRCDIRS="\ Modules/_hacl \ Modules/_io \ Modules/_multiprocessing \ - Modules/_sha3 \ Modules/_sqlite \ Modules/_sre \ Modules/_testcapi \ diff --git a/configure.ac b/configure.ac index 14354a07ab5073..96c96e4b0d735b 100644 --- a/configure.ac +++ b/configure.ac @@ -6697,7 +6697,6 @@ SRCDIRS="\ Modules/_hacl \ Modules/_io \ Modules/_multiprocessing \ - Modules/_sha3 \ Modules/_sqlite \ Modules/_sre \ Modules/_testcapi \ From 0555722a8a4a6555153c37617f7fb17e7f7f86a8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 27 Jun 2023 06:44:44 -0700 Subject: [PATCH 0269/1206] [3.12] gh-92788: Add docs for `ast.Module`, `ast.Expression`, and others (GH-101055) (#106139) gh-92788: Add docs for `ast.Module`, `ast.Expression`, and others (GH-101055) (cherry picked from commit 33608fd67df8b1033519f808441ee00289e2dac0) Co-authored-by: Nikita Sobolev --- Doc/library/ast.rst | 101 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index f3b0bf0c4f7779..530cf30643687f 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -146,6 +146,102 @@ Node classes Snakes `__ project and all its contributors. + +.. _ast-root-nodes: + +Root nodes +^^^^^^^^^^ + +.. class:: Module(body, type_ignores) + + A Python module, as with :ref:`file input `. + Node type generated by :func:`ast.parse` in the default ``"exec"`` *mode*. + + *body* is a :class:`list` of the module's :ref:`ast-statements`. + + *type_ignores* is a :class:`list` of the module's type ignore comments; + see :func:`ast.parse` for more details. + + .. doctest:: + + >>> print(ast.dump(ast.parse('x = 1'), indent=4)) + Module( + body=[ + Assign( + targets=[ + Name(id='x', ctx=Store())], + value=Constant(value=1))], + type_ignores=[]) + + +.. class:: Expression(body) + + A single Python :ref:`expression input `. + Node type generated by :func:`ast.parse` when *mode* is ``"eval"``. + + *body* is a single node, + one of the :ref:`expression types `. + + .. doctest:: + + >>> print(ast.dump(ast.parse('123', mode='eval'), indent=4)) + Expression( + body=Constant(value=123)) + + +.. class:: Interactive(body) + + A single :ref:`interactive input `, like in :ref:`tut-interac`. + Node type generated by :func:`ast.parse` when *mode* is ``"single"``. + + *body* is a :class:`list` of :ref:`statement nodes `. + + .. doctest:: + + >>> print(ast.dump(ast.parse('x = 1; y = 2', mode='single'), indent=4)) + Interactive( + body=[ + Assign( + targets=[ + Name(id='x', ctx=Store())], + value=Constant(value=1)), + Assign( + targets=[ + Name(id='y', ctx=Store())], + value=Constant(value=2))]) + + +.. class:: FunctionType(argtypes, returns) + + A representation of an old-style type comments for functions, + as Python versions prior to 3.5 didn't support :pep:`484` annotations. + Node type generated by :func:`ast.parse` when *mode* is ``"func_type"``. + + Such type comments would look like this:: + + def sum_two_number(a, b): + # type: (int, int) -> int + return a + b + + *argtypes* is a :class:`list` of :ref:`expression nodes `. + + *returns* is a single :ref:`expression node `. + + .. doctest:: + + >>> print(ast.dump(ast.parse('(int, str) -> List[int]', mode='func_type'), indent=4)) + FunctionType( + argtypes=[ + Name(id='int', ctx=Load()), + Name(id='str', ctx=Load())], + returns=Subscript( + value=Name(id='List', ctx=Load()), + slice=Name(id='int', ctx=Load()), + ctx=Load())) + + .. versionadded:: 3.8 + + Literals ^^^^^^^^ @@ -344,6 +440,8 @@ Variables type_ignores=[]) +.. _ast-expressions: + Expressions ^^^^^^^^^^^ @@ -735,6 +833,9 @@ Comprehensions ifs=[], is_async=1)])) + +.. _ast-statements: + Statements ^^^^^^^^^^ From 264b54bf51dfbc1c6901389eb4bf8c2f8ea542a7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 27 Jun 2023 10:35:48 -0700 Subject: [PATCH 0270/1206] [3.12] IDLE: Condense run.main threading.Thread start. (GH-106125) (#106154) IDLE: Condense run.main threading.Thread start. (GH-106125) Use daemon argument added in 3.3 and directly call .start. Remove now unused 'sockthread' name. (cherry picked from commit eaa1eae55ea66d74c5303924320185dac74d4eb1) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/run.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 4ffc90ab0c852a..53e80a9b42801f 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -140,11 +140,12 @@ def main(del_exitfunc=False): capture_warnings(True) sys.argv[:] = [""] - sockthread = threading.Thread(target=manage_socket, - name='SockThread', - args=((LOCALHOST, port),)) - sockthread.daemon = True - sockthread.start() + threading.Thread(target=manage_socket, + name='SockThread', + args=((LOCALHOST, port),), + daemon=True, + ).start() + while True: try: if exit_now: From ac80beb1ec7b888244c98b122ccae5474ed46858 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 27 Jun 2023 10:44:37 -0700 Subject: [PATCH 0271/1206] [3.12] gh-106140: Reorder some fields to facilitate out-of-process inspection (GH-106143) (#106147) gh-106140: Reorder some fields to facilitate out-of-process inspection (GH-106143) (cherry picked from commit 2d5a1c281161d037148ffb5983decc6d31c2557d) Signed-off-by: Pablo Galindo Co-authored-by: Pablo Galindo Salgado --- Doc/data/python3.12.abi | 52940 ++++++++++++++-------------- Include/internal/pycore_interp.h | 71 +- Include/internal/pycore_runtime.h | 22 +- 3 files changed, 26522 insertions(+), 26511 deletions(-) diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index b58ee3744ba3f1..52764c1a340427 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1,26470 +1,26470 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 04474c1da8855a..b12dd952556f0e 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -48,12 +48,22 @@ struct _Py_long_state { */ struct _is { - struct _ceval_state ceval; PyInterpreterState *next; + int64_t id; + int64_t id_refcount; + int requires_idref; + PyThread_type_lock id_mutex; + + /* Has been initialized to a safe state. + + In order to be effective, this must be set to 0 during or right + after allocation. */ + int _initialized; + int finalizing; + uint64_t monitoring_version; uint64_t last_restart_version; - struct pythreads { uint64_t next_unique_id; /* The linked list of threads, newest first. */ @@ -72,18 +82,6 @@ struct _is { Get runtime from tstate: tstate->interp->runtime. */ struct pyruntimestate *runtime; - int64_t id; - int64_t id_refcount; - int requires_idref; - PyThread_type_lock id_mutex; - - /* Has been initialized to a safe state. - - In order to be effective, this must be set to 0 during or right - after allocation. */ - int _initialized; - int finalizing; - /* Set by Py_EndInterpreter(). Use _PyInterpreterState_GetFinalizing() @@ -91,17 +89,33 @@ struct _is { to access it, don't access it directly. */ _Py_atomic_address _finalizing; - struct _obmalloc_state obmalloc; - struct _gc_runtime_state gc; - struct _import_state imports; + /* The following fields are here to avoid allocation during init. + The data is exposed through PyInterpreterState pointer fields. + These fields should not be accessed directly outside of init. + + All other PyInterpreterState pointer fields are populated when + needed and default to NULL. + + For now there are some exceptions to that rule, which require + allocation during init. These will be addressed on a case-by-case + basis. Also see _PyRuntimeState regarding the various mutex fields. + */ + + /* The per-interpreter GIL, which might not be used. */ + struct _gil_runtime_state _gil; // Dictionary of the sys module PyObject *sysdict; // Dictionary of the builtins module PyObject *builtins; + /* ---------- IMPORTANT --------------------------- + The fields above this line are declared as early as + possible to facilitate out-of-process observability + tools. */ + PyObject *codec_search_path; PyObject *codec_search_cache; PyObject *codec_error_registry; @@ -133,6 +147,12 @@ struct _is { struct _warnings_runtime_state warnings; struct atexit_state atexit; + struct _ceval_state ceval; + + struct _obmalloc_state obmalloc; + + struct _import_state imports; + PyObject *audit_hooks; PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; @@ -173,22 +193,7 @@ struct _is { struct _Py_interp_cached_objects cached_objects; struct _Py_interp_static_objects static_objects; - /* The following fields are here to avoid allocation during init. - The data is exposed through PyInterpreterState pointer fields. - These fields should not be accessed directly outside of init. - - All other PyInterpreterState pointer fields are populated when - needed and default to NULL. - - For now there are some exceptions to that rule, which require - allocation during init. These will be addressed on a case-by-case - basis. Also see _PyRuntimeState regarding the various mutex fields. - */ - - /* The per-interpreter GIL, which might not be used. */ - struct _gil_runtime_state _gil; - - /* the initial PyInterpreterState.threads.head */ + /* the initial PyInterpreterState.threads.head */ PyThreadState _initial_thread; }; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 8f51e2def69fc9..5ed97e9715b2b0 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -84,13 +84,6 @@ typedef struct pyruntimestate { to access it, don't access it directly. */ _Py_atomic_address _finalizing; - struct _pymem_allocators allocators; - struct _obmalloc_global_state obmalloc; - struct pyhash_runtime_state pyhash_state; - struct _time_runtime_state time; - struct _pythread_runtime_state threads; - struct _signals_runtime_state signals; - struct pyinterpreters { PyThread_type_lock mutex; /* The linked list of interpreters, newest first. */ @@ -109,13 +102,26 @@ typedef struct pyruntimestate { using a Python int. */ int64_t next_id; } interpreters; + + unsigned long main_thread; + + /* ---------- IMPORTANT --------------------------- + The fields above this line are declared as early as + possible to facilitate out-of-process observability + tools. */ + // XXX Remove this field once we have a tp_* slot. struct _xidregistry { PyThread_type_lock mutex; struct _xidregitem *head; } xidregistry; - unsigned long main_thread; + struct _pymem_allocators allocators; + struct _obmalloc_global_state obmalloc; + struct pyhash_runtime_state pyhash_state; + struct _time_runtime_state time; + struct _pythread_runtime_state threads; + struct _signals_runtime_state signals; /* Used for the thread state bound to the current thread. */ Py_tss_t autoTSSkey; From 20315d141a2288c43273922213863b4594e8ab42 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 27 Jun 2023 19:33:01 +0100 Subject: [PATCH 0272/1206] [3.12] gh-106140: Reorder some more fields to facilitate out-of-process inspection (GH-106148) (#106155) (cherry picked from commit 9126a6a9ce3772d5dc785cbee159b07a1ff7d531) --- Doc/data/python3.12.abi | 190 +++++++++++++++---------------- Include/internal/pycore_interp.h | 15 +-- 2 files changed, 103 insertions(+), 102 deletions(-) diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 52764c1a340427..4cd130f86e2f7e 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -7570,19 +7570,19 @@ - + - + - + - + @@ -11113,7 +11113,7 @@ - + @@ -16004,7 +16004,7 @@ - + @@ -16015,7 +16015,7 @@ - + @@ -16072,175 +16072,175 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -16257,18 +16257,18 @@ - + - + - + - + - + @@ -17396,8 +17396,8 @@ - + @@ -24923,7 +24923,7 @@ - + diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index b12dd952556f0e..619225c939664e 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -103,14 +103,19 @@ struct _is { basis. Also see _PyRuntimeState regarding the various mutex fields. */ - /* The per-interpreter GIL, which might not be used. */ - struct _gil_runtime_state _gil; - // Dictionary of the sys module PyObject *sysdict; + // Dictionary of the builtins module PyObject *builtins; + struct _ceval_state ceval; + + struct _import_state imports; + + /* The per-interpreter GIL, which might not be used. */ + struct _gil_runtime_state _gil; + /* ---------- IMPORTANT --------------------------- The fields above this line are declared as early as possible to facilitate out-of-process observability @@ -147,12 +152,8 @@ struct _is { struct _warnings_runtime_state warnings; struct atexit_state atexit; - struct _ceval_state ceval; - struct _obmalloc_state obmalloc; - struct _import_state imports; - PyObject *audit_hooks; PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; From c1c6738526853c77c55b92ccd756aec96053677e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 27 Jun 2023 19:55:27 -0700 Subject: [PATCH 0273/1206] [3.12] gh-101634: regrtest reports decoding error as failed test (GH-106169) (#106174) gh-101634: regrtest reports decoding error as failed test (GH-106169) When running the Python test suite with -jN option, if a worker stdout cannot be decoded from the locale encoding report a failed testn so the exitcode is non-zero. (cherry picked from commit 2ac3eec103cf450aaaebeb932e51155d2e7fb37b) Co-authored-by: Victor Stinner --- Lib/test/libregrtest/runtest_mp.py | 12 ++++++- Lib/test/test_regrtest.py | 36 +++++++++++++++++++ ...-06-28-02-51-08.gh-issue-101634.Rayczr.rst | 3 ++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index a12fcb46e0fd0b..62e6c6df36518c 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -277,6 +277,7 @@ def _runtest(self, test_name: str) -> MultiprocessResult: encoding = locale.getencoding() else: encoding = sys.stdout.encoding + # gh-94026: Write stdout+stderr to a tempfile as workaround for # non-blocking pipes on Emscripten with NodeJS. with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh: @@ -298,7 +299,14 @@ def _runtest(self, test_name: str) -> MultiprocessResult: retcode = self._run_process(test_name, None, stdout_fh) tmp_files = () stdout_fh.seek(0) - stdout = stdout_fh.read().strip() + + try: + stdout = stdout_fh.read().strip() + except Exception as exc: + # gh-101634: Catch UnicodeDecodeError if stdout cannot be + # decoded from encoding + err_msg = f"Cannot read process stdout: {exc}" + return self.mp_result_error(ChildError(test_name), '', err_msg) if retcode is None: return self.mp_result_error(Timeout(test_name), stdout) @@ -481,6 +489,8 @@ def _process_result(self, item: QueueOutput) -> bool: # Thread got an exception format_exc = item[1] print_warning(f"regrtest worker thread failed: {format_exc}") + result = ChildError("") + self.regrtest.accumulate_result(result) return True self.test_index += 1 diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index ac49fbae847726..806b932a164df8 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -7,6 +7,7 @@ import contextlib import glob import io +import locale import os.path import platform import re @@ -1551,6 +1552,41 @@ def test_leak_tmp_file(self): f"files (1): mytmpfile", output) + def test_mp_decode_error(self): + # gh-101634: If a worker stdout cannot be decoded, report a failed test + # and a non-zero exit code. + if sys.platform == 'win32': + encoding = locale.getencoding() + else: + encoding = sys.stdout.encoding + if encoding is None: + encoding = sys.__stdout__.encoding + if encoding is None: + self.skipTest(f"cannot get regrtest worker encoding") + + nonascii = b"byte:\xa0\xa9\xff\n" + try: + nonascii.decode(encoding) + except UnicodeDecodeError: + pass + else: + self.skipTest(f"{encoding} can decode non-ASCII bytes {nonascii!a}") + + code = textwrap.dedent(fr""" + import sys + # bytes which cannot be decoded from UTF-8 + nonascii = {nonascii!a} + sys.stdout.buffer.write(nonascii) + sys.stdout.buffer.flush() + """) + testname = self.create_test(code=code) + + output = self.run_tests("--fail-env-changed", "-v", "-j1", testname, + exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, [testname], + failed=[testname], + randomize=True) + class TestUtils(unittest.TestCase): def test_format_duration(self): diff --git a/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst b/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst new file mode 100644 index 00000000000000..6fbfc84c19e1b8 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst @@ -0,0 +1,3 @@ +When running the Python test suite with ``-jN`` option, if a worker stdout +cannot be decoded from the locale encoding report a failed testn so the +exitcode is non-zero. Patch by Victor Stinner. From 0373c2ccd5f60dd7b6435879e2f8c1b9ed879a3a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:41:36 -0700 Subject: [PATCH 0274/1206] [3.12] Fix c-analyzer for GCC: ignore LANG env var (GH-106173) (#106178) Fix c-analyzer for GCC: ignore LANG env var (GH-106173) The c-analyzer doesn't support GCC localized messages, so just unset the LANG environment variable. (cherry picked from commit 1f74b9e933d546a015e8497e3b8728357196acc8) Co-authored-by: Victor Stinner --- Tools/c-analyzer/c_parser/preprocessor/common.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Tools/c-analyzer/c_parser/preprocessor/common.py b/Tools/c-analyzer/c_parser/preprocessor/common.py index dbe1edeef38527..06f8f4da62b224 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/common.py +++ b/Tools/c-analyzer/c_parser/preprocessor/common.py @@ -1,6 +1,7 @@ import contextlib import distutils.ccompiler import logging +import os import shlex import subprocess import sys @@ -40,7 +41,12 @@ def run_cmd(argv, *, kw.pop('kwargs') kwargs.update(kw) - proc = subprocess.run(argv, **kwargs) + # Remove LANG environment variable: the C parser doesn't support GCC + # localized messages + env = dict(os.environ) + env.pop('LANG', None) + + proc = subprocess.run(argv, env=env, **kwargs) return proc.stdout From 56e39192c8e78ef498aa60a9fd5eb15b2c7338e1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 27 Jun 2023 22:38:01 -0700 Subject: [PATCH 0275/1206] [3.12] Refer to `TimeoutError` instead of `asyncio.TimeoutError` in `asyncio-task.rst` (GH-106136) (#106179) Co-authored-by: lightdrk <108566237+lightdrk@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/library/asyncio-task.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index fe8d028150403d..d07fbae287e535 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -651,16 +651,16 @@ Timeouts If ``long_running_task`` takes more than 10 seconds to complete, the context manager will cancel the current task and handle the resulting :exc:`asyncio.CancelledError` internally, transforming it - into an :exc:`asyncio.TimeoutError` which can be caught and handled. + into a :exc:`TimeoutError` which can be caught and handled. .. note:: The :func:`asyncio.timeout` context manager is what transforms - the :exc:`asyncio.CancelledError` into an :exc:`asyncio.TimeoutError`, - which means the :exc:`asyncio.TimeoutError` can only be caught + the :exc:`asyncio.CancelledError` into a :exc:`TimeoutError`, + which means the :exc:`TimeoutError` can only be caught *outside* of the context manager. - Example of catching :exc:`asyncio.TimeoutError`:: + Example of catching :exc:`TimeoutError`:: async def main(): try: From 442f5ec042a2d18eaaa49346d9c86bba6389958d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 28 Jun 2023 03:46:16 -0700 Subject: [PATCH 0276/1206] [3.12] GH-106160: Fix test_gzip failing under WASI, which does not have zlib. (GH-106167) (#106170) GH-106160: Fix test_gzip failing under WASI, which does not have zlib. (GH-106167) Fix test_gzip's failure under WASI, which does not have zlib, by using test.support.import_helper.import_module to import zlib. (gzip unconditionally imports zlib, so this does not cause any new skips.) (cherry picked from commit 161012fc25910a47423bae8012398bf519a88140) Co-authored-by: T. Wouters --- Lib/test/test_gzip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index c7ac7c687c8b2d..b06b3b09411d62 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -9,7 +9,6 @@ import struct import sys import unittest -import zlib from subprocess import PIPE, Popen from test.support import import_helper from test.support import os_helper @@ -17,6 +16,7 @@ from test.support.script_helper import assert_python_ok, assert_python_failure gzip = import_helper.import_module('gzip') +zlib = import_helper.import_module('zlib') data1 = b""" int length=DEFAULTALLOC, err = Z_OK; PyObject *RetVal; From 27bd2d1a9bbf2c3182f1565d38eff93e03417057 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 28 Jun 2023 04:06:02 -0700 Subject: [PATCH 0277/1206] [3.12] gh-101100: Fix reference to asynchronous methods (GH-106172) (#106191) gh-101100: Fix reference to asynchronous methods (GH-106172) (cherry picked from commit bbf722dcd39c66418e45991dcf1cdf140c2ce20e) Co-authored-by: F3eQnxN3RriK --- Doc/glossary.rst | 18 +++++++++--------- Doc/library/exceptions.rst | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 53e8cdcae1cd66..5c0f0f15217a07 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -92,8 +92,8 @@ Glossary asynchronous context manager An object which controls the environment seen in an - :keyword:`async with` statement by defining :meth:`__aenter__` and - :meth:`__aexit__` methods. Introduced by :pep:`492`. + :keyword:`async with` statement by defining :meth:`~object.__aenter__` and + :meth:`~object.__aexit__` methods. Introduced by :pep:`492`. asynchronous generator A function which returns an :term:`asynchronous generator iterator`. It @@ -113,26 +113,26 @@ Glossary An object created by a :term:`asynchronous generator` function. This is an :term:`asynchronous iterator` which when called using the - :meth:`__anext__` method returns an awaitable object which will execute + :meth:`~object.__anext__` method returns an awaitable object which will execute the body of the asynchronous generator function until the next :keyword:`yield` expression. Each :keyword:`yield` temporarily suspends processing, remembering the location execution state (including local variables and pending try-statements). When the *asynchronous generator iterator* effectively - resumes with another awaitable returned by :meth:`__anext__`, it + resumes with another awaitable returned by :meth:`~object.__anext__`, it picks up where it left off. See :pep:`492` and :pep:`525`. asynchronous iterable An object, that can be used in an :keyword:`async for` statement. Must return an :term:`asynchronous iterator` from its - :meth:`__aiter__` method. Introduced by :pep:`492`. + :meth:`~object.__aiter__` method. Introduced by :pep:`492`. asynchronous iterator - An object that implements the :meth:`__aiter__` and :meth:`__anext__` - methods. ``__anext__`` must return an :term:`awaitable` object. + An object that implements the :meth:`~object.__aiter__` and :meth:`~object.__anext__` + methods. :meth:`~object.__anext__` must return an :term:`awaitable` object. :keyword:`async for` resolves the awaitables returned by an asynchronous - iterator's :meth:`__anext__` method until it raises a + iterator's :meth:`~object.__anext__` method until it raises a :exc:`StopAsyncIteration` exception. Introduced by :pep:`492`. attribute @@ -149,7 +149,7 @@ Glossary awaitable An object that can be used in an :keyword:`await` expression. Can be - a :term:`coroutine` or an object with an :meth:`__await__` method. + a :term:`coroutine` or an object with an :meth:`~object.__await__` method. See also :pep:`492`. BDFL diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 4c84e5f855431a..49ede20070d8af 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -450,7 +450,7 @@ The following exceptions are the exceptions that are usually raised. .. exception:: StopAsyncIteration - Must be raised by :meth:`__anext__` method of an + Must be raised by :meth:`~object.__anext__` method of an :term:`asynchronous iterator` object to stop the iteration. .. versionadded:: 3.5 From 7bdf2c16e6dc8dabfff3314b61b2db7b0e156dc3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 28 Jun 2023 04:06:49 -0700 Subject: [PATCH 0278/1206] [3.12] gh-105993: Add possible `None` return type to `asyncio.EventLoop.start_tls` docs (GH-105995) (#106188) gh-105993: Add possible `None` return type to `asyncio.EventLoop.start_tls` docs (GH-105995) (cherry picked from commit 6b52a581c151914e59c8c367a03bc7309713a73b) Co-authored-by: Sam Bull --- Doc/library/asyncio-eventloop.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 8d0022cc66daac..38f2e2f510c176 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -895,6 +895,9 @@ TLS Upgrade object only because the coder caches *protocol*-side data and sporadically exchanges extra TLS session packets with *transport*. + In some situations (e.g. when the passed transport is already closing) this + may return ``None``. + Parameters: * *transport* and *protocol* instances that methods like From 78cedf260725849a83a7149650268f715c27bbff Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 28 Jun 2023 04:54:53 -0700 Subject: [PATCH 0279/1206] [3.12] gh-106118: Add O_CLOEXEC preprocessor guard (GH-106120) (#106199) (cherry picked from commit 6c60684bf5d34fae27a2f6a142ff794b38cefe1b) Co-authored-by: Erlend E. Aasland --- .../Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst | 2 ++ Python/sysmodule.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst diff --git a/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst b/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst new file mode 100644 index 00000000000000..f93cae5d03b539 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst @@ -0,0 +1,2 @@ +Fix compilation for platforms without :data:`!O_CLOEXEC`. The issue was +introduced with Python 3.12b1 in :gh:`103295`. Patch by Erlend Aasland. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index b8254f4e94fd0f..4bd38b4b267873 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2277,7 +2277,10 @@ PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void) { char filename[100]; pid_t pid = getpid(); // Use nofollow flag to prevent symlink attacks. - int flags = O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW | O_CLOEXEC; + int flags = O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW; +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; +#endif snprintf(filename, sizeof(filename) - 1, "/tmp/perf-%jd.map", (intmax_t)pid); int fd = open(filename, flags, 0600); From 0cd07b327283f7bfba2fcdb0bdb2886214157d67 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 28 Jun 2023 05:44:23 -0700 Subject: [PATCH 0280/1206] [3.12] gh-101100: Fix reference to `parse_args` in `optparse.rst` (GH-105265) (#106204) Co-authored-by: F3eQnxN3RriK --- Doc/library/optparse.rst | 51 +++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst index 5c02d8bc8835bf..0cff3817452364 100644 --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -42,8 +42,8 @@ on the command-line, for example:: --file=outfile -q As it parses the command line, :mod:`optparse` sets attributes of the -``options`` object returned by :meth:`parse_args` based on user-supplied -command-line values. When :meth:`parse_args` returns from parsing this command +``options`` object returned by :meth:`~OptionParser.parse_args` based on user-supplied +command-line values. When :meth:`~OptionParser.parse_args` returns from parsing this command line, ``options.filename`` will be ``"outfile"`` and ``options.verbose`` will be ``False``. :mod:`optparse` supports both long and short options, allows short options to be merged together, and allows options to be associated with their @@ -285,10 +285,10 @@ program's command line:: (options, args) = parser.parse_args() -(If you like, you can pass a custom argument list to :meth:`parse_args`, but +(If you like, you can pass a custom argument list to :meth:`~OptionParser.parse_args`, but that's rarely necessary: by default it uses ``sys.argv[1:]``.) -:meth:`parse_args` returns two values: +:meth:`~OptionParser.parse_args` returns two values: * ``options``, an object containing values for all of your options---e.g. if ``--file`` takes a single string argument, then ``options.file`` will be the @@ -339,7 +339,7 @@ Now let's make up a fake command line and ask :mod:`optparse` to parse it:: When :mod:`optparse` sees the option string ``-f``, it consumes the next argument, ``foo.txt``, and stores it in ``options.filename``. So, after this -call to :meth:`parse_args`, ``options.filename`` is ``"foo.txt"``. +call to :meth:`~OptionParser.parse_args`, ``options.filename`` is ``"foo.txt"``. Some other option types supported by :mod:`optparse` are ``int`` and ``float``. Here's an option that expects an integer argument:: @@ -453,7 +453,8 @@ Again, the default value for ``verbose`` will be ``True``: the last default value supplied for any particular destination is the one that counts. A clearer way to specify default values is the :meth:`set_defaults` method of -OptionParser, which you can call at any time before calling :meth:`parse_args`:: +OptionParser, which you can call at any time before calling +:meth:`~OptionParser.parse_args`:: parser.set_defaults(verbose=True) parser.add_option(...) @@ -1338,35 +1339,37 @@ Parsing arguments ^^^^^^^^^^^^^^^^^ The whole point of creating and populating an OptionParser is to call its -:meth:`parse_args` method:: +:meth:`~OptionParser.parse_args` method. - (options, args) = parser.parse_args(args=None, values=None) +.. method:: OptionParser.parse_args(args=None, values=None) -where the input parameters are + Parse the command-line options found in *args*. -``args`` - the list of arguments to process (default: ``sys.argv[1:]``) + The input parameters are -``values`` - an :class:`optparse.Values` object to store option arguments in (default: a - new instance of :class:`Values`) -- if you give an existing object, the - option defaults will not be initialized on it + ``args`` + the list of arguments to process (default: ``sys.argv[1:]``) -and the return values are + ``values`` + an :class:`Values` object to store option arguments in (default: a + new instance of :class:`Values`) -- if you give an existing object, the + option defaults will not be initialized on it -``options`` - the same object that was passed in as ``values``, or the optparse.Values - instance created by :mod:`optparse` + and the return value is a pair ``(options, args)`` where -``args`` - the leftover positional arguments after all options have been processed + ``options`` + the same object that was passed in as *values*, or the ``optparse.Values`` + instance created by :mod:`optparse` + + ``args`` + the leftover positional arguments after all options have been processed The most common usage is to supply neither keyword argument. If you supply ``values``, it will be modified with repeated :func:`setattr` calls (roughly one for every option argument stored to an option destination) and returned by -:meth:`parse_args`. +:meth:`~OptionParser.parse_args`. -If :meth:`parse_args` encounters any errors in the argument list, it calls the +If :meth:`~OptionParser.parse_args` encounters any errors in the argument list, it calls the OptionParser's :meth:`error` method with an appropriate end-user error message. This ultimately terminates your process with an exit status of 2 (the traditional Unix exit status for command-line errors). @@ -1661,7 +1664,7 @@ where the current list of leftover arguments, ie. arguments that have been consumed but are neither options nor option arguments. Feel free to modify ``parser.largs``, e.g. by adding more arguments to it. (This list will - become ``args``, the second return value of :meth:`parse_args`.) + become ``args``, the second return value of :meth:`~OptionParser.parse_args`.) ``parser.rargs`` the current list of remaining arguments, ie. with ``opt_str`` and From ed2114f1cf927206d08b3bc824b2fc3d515f5eae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 28 Jun 2023 08:13:57 -0700 Subject: [PATCH 0281/1206] [3.12] gh-106197: Deduplicate tests in `test_buffer` (GH-106198) (#106206) gh-106197: Deduplicate tests in `test_buffer` (GH-106198) (cherry picked from commit c283a0cff5603540f06d9017e484b3602cc62e7c) Co-authored-by: Nikita Sobolev --- Lib/test/test_buffer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 94fc9d4436b717..9f00bd5e76195f 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -4718,7 +4718,7 @@ def __buffer__(self, flags): with self.assertRaises(ValueError): c.buffer.tobytes() - def test_multiple_inheritance_buffer_last(self): + def test_multiple_inheritance_buffer_last_raising(self): class A: def __buffer__(self, flags): raise RuntimeError("should not be called") From e12045d64853ddfd5f4dbf193270b644de3b8d9a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:12:12 -0700 Subject: [PATCH 0282/1206] [3.12] gh-106194: Rename duplicated tests in `test_curses` (GH-106196) (#106216) Co-authored-by: Nikita Sobolev --- Lib/test/test_curses.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 3ab837e4f95681..31bc108e7712ea 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1364,26 +1364,33 @@ def test_move_left(self): self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_LEFT) self.mock_win.move.assert_called_with(1, 0) + self.mock_win.reset_mock() + + def test_move_right(self): + """Test moving the cursor right.""" + self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_RIGHT) self.mock_win.move.assert_called_with(1, 2) self.mock_win.reset_mock() - def test_move_left(self): - """Test moving the cursor left.""" + def test_move_left_and_right(self): + """Test moving the cursor left and then right.""" self.mock_win.reset_mock() + self.textbox.do_command(curses.KEY_LEFT) + self.mock_win.move.assert_called_with(1, 0) self.textbox.do_command(curses.KEY_RIGHT) self.mock_win.move.assert_called_with(1, 2) self.mock_win.reset_mock() def test_move_up(self): - """Test moving the cursor left.""" + """Test moving the cursor up.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_UP) self.mock_win.move.assert_called_with(0, 1) self.mock_win.reset_mock() def test_move_down(self): - """Test moving the cursor left.""" + """Test moving the cursor down.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_DOWN) self.mock_win.move.assert_called_with(2, 1) From e0fa531d7aa2f1e809dc77c222538620b2cf24b9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 29 Jun 2023 03:45:39 -0700 Subject: [PATCH 0283/1206] [3.12] gh-106033: Get rid of PyDict_GetItem in _PyFunction_FromConstructor (GH-106044) (GH-106228) gh-106033: Get rid of PyDict_GetItem in _PyFunction_FromConstructor (GH-106044) (cherry picked from commit 08c08d21b03d949452a77d9ed5e3cf48d6b9804d) Co-authored-by: Serhiy Storchaka --- Objects/funcobject.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 753038600aa858..f43e3a2787b846 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -106,9 +106,14 @@ PyFunction_ClearWatcher(int watcher_id) PyFunctionObject * _PyFunction_FromConstructor(PyFrameConstructor *constr) { + PyObject *module = Py_XNewRef(PyDict_GetItemWithError(constr->fc_globals, &_Py_ID(__name__))); + if (!module && PyErr_Occurred()) { + return NULL; + } PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); if (op == NULL) { + Py_XDECREF(module); return NULL; } op->func_globals = Py_NewRef(constr->fc_globals); @@ -122,10 +127,7 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr) op->func_doc = Py_NewRef(Py_None); op->func_dict = NULL; op->func_weakreflist = NULL; - op->func_module = Py_XNewRef(PyDict_GetItem(op->func_globals, &_Py_ID(__name__))); - if (!op->func_module) { - PyErr_Clear(); - } + op->func_module = module; op->func_annotations = NULL; op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; From c9b9555650fee56a2fcb66c1db25e2b57f71a5d9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 29 Jun 2023 03:46:51 -0700 Subject: [PATCH 0284/1206] [3.12] gh-101006: Improve error handling when read marshal data (GH-101007) (GH-106226) * EOFError no longer overrides other errors such as MemoryError or OSError at the start of the object. * Raise more relevant error when the NULL object occurs as a code object component. * Minimize an overhead of calling PyErr_Occurred(). (cherry picked from commit 8bf6904b229583033035d91a3800da5604dcaad4) Co-authored-by: Serhiy Storchaka --- ...-01-13-11-37-41.gh-issue-101006.fuLvn2.rst | 1 + Python/marshal.c | 132 ++++++++++-------- 2 files changed, 72 insertions(+), 61 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst new file mode 100644 index 00000000000000..c98670d8c4963d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst @@ -0,0 +1 @@ +Improve error handling when read :mod:`marshal` data. diff --git a/Python/marshal.c b/Python/marshal.c index 6439503d2c6879..90953cbb728459 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -751,23 +751,28 @@ r_string(Py_ssize_t n, RFILE *p) static int r_byte(RFILE *p) { - int c = EOF; - if (p->ptr != NULL) { - if (p->ptr < p->end) - c = (unsigned char) *p->ptr++; - return c; + if (p->ptr < p->end) { + return (unsigned char) *p->ptr++; + } } - if (!p->readable) { + else if (!p->readable) { assert(p->fp); - c = getc(p->fp); + int c = getc(p->fp); + if (c != EOF) { + return c; + } } else { const char *ptr = r_string(1, p); - if (ptr != NULL) - c = *(const unsigned char *) ptr; + if (ptr != NULL) { + return *(const unsigned char *) ptr; + } + return EOF; } - return c; + PyErr_SetString(PyExc_EOFError, + "EOF read where not expected"); + return EOF; } static int @@ -828,10 +833,11 @@ r_PyLong(RFILE *p) digit d; n = r_long(p); - if (PyErr_Occurred()) - return NULL; if (n == 0) return (PyObject *)_PyLong_New(0); + if (n == -1 && PyErr_Occurred()) { + return NULL; + } if (n < -SIZE32_MAX || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (long size out of range)"); @@ -850,10 +856,6 @@ r_PyLong(RFILE *p) d = 0; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { md = r_short(p); - if (PyErr_Occurred()) { - Py_DECREF(ob); - return NULL; - } if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; @@ -864,10 +866,6 @@ r_PyLong(RFILE *p) d = 0; for (j=0; j < shorts_in_top_digit; j++) { md = r_short(p); - if (PyErr_Occurred()) { - Py_DECREF(ob); - return NULL; - } if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; /* topmost marshal digit should be nonzero */ @@ -879,18 +877,17 @@ r_PyLong(RFILE *p) } d += (digit)md << j*PyLong_MARSHAL_SHIFT; } - if (PyErr_Occurred()) { - Py_DECREF(ob); - return NULL; - } + assert(!PyErr_Occurred()); /* top digit should be nonzero, else the resulting PyLong won't be normalized */ ob->long_value.ob_digit[size-1] = d; return (PyObject *)ob; bad_digit: Py_DECREF(ob); - PyErr_SetString(PyExc_ValueError, - "bad marshal data (digit out of range in long)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (digit out of range in long)"); + } return NULL; } @@ -913,8 +910,6 @@ r_float_str(RFILE *p) const char *ptr; n = r_byte(p); if (n == EOF) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); return -1; } ptr = r_string(n, p); @@ -992,8 +987,10 @@ r_object(RFILE *p) PyObject *retval = NULL; if (code == EOF) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); + if (PyErr_ExceptionMatches(PyExc_EOFError)) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + } return NULL; } @@ -1040,7 +1037,10 @@ r_object(RFILE *p) case TYPE_INT: n = r_long(p); - retval = PyErr_Occurred() ? NULL : PyLong_FromLong(n); + if (n == -1 && PyErr_Occurred()) { + break; + } + retval = PyLong_FromLong(n); R_REF(retval); break; @@ -1106,10 +1106,11 @@ r_object(RFILE *p) { const char *ptr; n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (bytes object size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (bytes object size out of range)"); + } break; } v = PyBytes_FromStringAndSize((char *)NULL, n); @@ -1131,10 +1132,11 @@ r_object(RFILE *p) /* fall through */ case TYPE_ASCII: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (string size out of range)"); + } break; } goto _read_ascii; @@ -1145,8 +1147,6 @@ r_object(RFILE *p) case TYPE_SHORT_ASCII: n = r_byte(p); if (n == EOF) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); break; } _read_ascii: @@ -1173,10 +1173,11 @@ r_object(RFILE *p) const char *buffer; n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (string size out of range)"); + } break; } if (n != 0) { @@ -1198,16 +1199,18 @@ r_object(RFILE *p) } case TYPE_SMALL_TUPLE: - n = (unsigned char) r_byte(p); - if (PyErr_Occurred()) + n = r_byte(p); + if (n == EOF) { break; + } goto _read_tuple; case TYPE_TUPLE: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (tuple size out of range)"); + } break; } _read_tuple: @@ -1232,10 +1235,11 @@ r_object(RFILE *p) case TYPE_LIST: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (list size out of range)"); + } break; } v = PyList_New(n); @@ -1288,10 +1292,11 @@ r_object(RFILE *p) case TYPE_SET: case TYPE_FROZENSET: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (set size out of range)"); + } break; } @@ -1368,20 +1373,20 @@ r_object(RFILE *p) /* XXX ignore long->int overflows for now */ argcount = (int)r_long(p); - if (PyErr_Occurred()) + if (argcount == -1 && PyErr_Occurred()) goto code_error; posonlyargcount = (int)r_long(p); - if (PyErr_Occurred()) { + if (posonlyargcount == -1 && PyErr_Occurred()) { goto code_error; } kwonlyargcount = (int)r_long(p); - if (PyErr_Occurred()) + if (kwonlyargcount == -1 && PyErr_Occurred()) goto code_error; stacksize = (int)r_long(p); - if (PyErr_Occurred()) + if (stacksize == -1 && PyErr_Occurred()) goto code_error; flags = (int)r_long(p); - if (PyErr_Occurred()) + if (flags == -1 && PyErr_Occurred()) goto code_error; code = r_object(p); if (code == NULL) @@ -1454,6 +1459,10 @@ r_object(RFILE *p) v = r_ref_insert(v, idx, flag, p); code_error: + if (v == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "NULL object in marshal data for code object"); + } Py_XDECREF(code); Py_XDECREF(consts); Py_XDECREF(names); @@ -1471,9 +1480,10 @@ r_object(RFILE *p) case TYPE_REF: n = r_long(p); if (n < 0 || n >= PyList_GET_SIZE(p->refs)) { - if (n == -1 && PyErr_Occurred()) - break; - PyErr_SetString(PyExc_ValueError, "bad marshal data (invalid reference)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (invalid reference)"); + } break; } v = PyList_GET_ITEM(p->refs, n); From 2405929c35239580aa0344f0e8fd31b87f9ccfe9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 29 Jun 2023 11:41:01 -0700 Subject: [PATCH 0285/1206] [3.12] Fix possible refleak in CodeType.replace() (GH-106243) (GH-106244) Fix possible refleak in CodeType.replace() (GH-106243) A reference to c_code was leaked if PySys_Audit() failed. (cherry picked from commit 3c70d467c148875f2ce17bacab8909ecc3e9fc1d) Co-authored-by: Serhiy Storchaka --- Objects/codeobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 9b54c610581174..d47ca731a10c87 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2030,6 +2030,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount, co_code, co_filename, co_name, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags) < 0) { + Py_XDECREF(code); return NULL; } From 04a165f4f96792e4c9409420ae12002cf6ce9701 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:39:18 -0700 Subject: [PATCH 0286/1206] [3.12] GH-106152: Add PY_THROW event to cProfile (GH-106256) GH-106152: Add PY_THROW event to cProfile (GH-106161) (cherry picked from commit cea9d4ea82abcb2c6f1d83a2fe819859da4bbda4) Co-authored-by: Tian Gao --- Lib/test/test_cprofile.py | 20 +++++++++++++++++++ ...-06-27-23-22-37.gh-issue-106152.ya5jBT.rst | 1 + Modules/_lsprof.c | 1 + 3 files changed, 22 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 484b8f8e3a365c..3056fe84dac5dd 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -66,6 +66,26 @@ def test_second_profiler(self): self.assertRaises(ValueError, pr2.enable) pr.disable() + def test_throw(self): + """ + gh-106152 + generator.throw() should trigger a call in cProfile + In the any() call below, there should be two entries for the generator: + * one for the call to __next__ which gets a True and terminates any + * one when the generator is garbage collected which will effectively + do a throw. + """ + pr = self.profilerclass() + pr.enable() + any(a == 1 for a in (1, 2)) + pr.disable() + pr.create_stats() + + for func, (cc, nc, _, _, _) in pr.stats.items(): + if func[2] == "": + self.assertEqual(cc, 2) + self.assertEqual(nc, 2) + class TestCommandLine(unittest.TestCase): def test_sort(self): diff --git a/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst b/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst new file mode 100644 index 00000000000000..da9d2605f46294 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst @@ -0,0 +1 @@ +Added PY_THROW event hook for :mod:`cProfile` for generators diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 1c84f66ee6f579..257de4387c0ab9 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -678,6 +678,7 @@ static const struct { } callback_table[] = { {PY_MONITORING_EVENT_PY_START, "_pystart_callback"}, {PY_MONITORING_EVENT_PY_RESUME, "_pystart_callback"}, + {PY_MONITORING_EVENT_PY_THROW, "_pystart_callback"}, {PY_MONITORING_EVENT_PY_RETURN, "_pyreturn_callback"}, {PY_MONITORING_EVENT_PY_YIELD, "_pyreturn_callback"}, {PY_MONITORING_EVENT_PY_UNWIND, "_pyreturn_callback"}, From 7a1b946a8d9ec6ffd5946a946158d844dfd4ee69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 30 Jun 2023 03:21:36 -0700 Subject: [PATCH 0287/1206] [3.12] gh-77782: Deprecate Py_HasFileSystemDefaultEncoding (GH-106272) (#106274) gh-77782: Deprecate Py_HasFileSystemDefaultEncoding (GH-106272) Deprecate Py_HasFileSystemDefaultEncoding variable. (cherry picked from commit f3cf2ddd8ddc7dfa6b06e6da640391a1bcd62b8a) Co-authored-by: Victor Stinner --- Doc/whatsnew/3.12.rst | 1 + Include/fileobject.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 782a5013e869c7..ec13ed57a5c45d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1857,6 +1857,7 @@ Deprecated * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) diff --git a/Include/fileobject.h b/Include/fileobject.h index 02bd7c915a23f7..2deef544d667a5 100644 --- a/Include/fileobject.h +++ b/Include/fileobject.h @@ -23,7 +23,7 @@ Py_DEPRECATED(3.12) PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding; #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 Py_DEPRECATED(3.12) PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors; #endif -PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding; +Py_DEPRECATED(3.12) PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding; #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000 Py_DEPRECATED(3.12) PyAPI_DATA(int) Py_UTF8Mode; From d6a5a30669b1bb383f05208299fa911720d4d88b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 30 Jun 2023 07:39:52 -0700 Subject: [PATCH 0288/1206] [3.12] gh-101100: Docs: Fix references to several numeric dunders (GH-106278) (#106281) gh-101100: Docs: Fix references to several numeric dunders (GH-106278) (cherry picked from commit a8ae73965b02302b7661ea07a6e4f955a961aca9) Co-authored-by: F3eQnxN3RriK Co-authored-by: Alex Waygood --- Doc/c-api/complex.rst | 10 +++++----- Doc/c-api/float.rst | 6 +++--- Doc/c-api/long.rst | 36 ++++++++++++++++++------------------ Doc/library/cmath.rst | 2 +- Doc/library/functions.rst | 32 ++++++++++++++++---------------- Doc/library/struct.rst | 4 ++-- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index 344da903da4c1a..cb8b270fcbab6e 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -127,12 +127,12 @@ Complex Numbers as Python Objects Return the :c:type:`Py_complex` value of the complex number *op*. - If *op* is not a Python complex number object but has a :meth:`__complex__` + If *op* is not a Python complex number object but has a :meth:`~object.__complex__` method, this method will first be called to convert *op* to a Python complex - number object. If ``__complex__()`` is not defined then it falls back to - :meth:`__float__`. If ``__float__()`` is not defined then it falls back - to :meth:`__index__`. Upon failure, this method returns ``-1.0`` as a real + number object. If :meth:`!__complex__` is not defined then it falls back to + :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back + to :meth:`~object.__index__`. Upon failure, this method returns ``-1.0`` as a real value. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 0118bea4e720f8..fd0be1108c6300 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -45,14 +45,14 @@ Floating Point Objects .. c:function:: double PyFloat_AsDouble(PyObject *pyfloat) Return a C :c:expr:`double` representation of the contents of *pyfloat*. If - *pyfloat* is not a Python floating point object but has a :meth:`__float__` + *pyfloat* is not a Python floating point object but has a :meth:`~object.__float__` method, this method will first be called to convert *pyfloat* into a float. - If ``__float__()`` is not defined then it falls back to :meth:`__index__`. + If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`. This method returns ``-1.0`` upon failure, so one should call :c:func:`PyErr_Occurred` to check for errors. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. c:function:: double PyFloat_AS_DOUBLE(PyObject *pyfloat) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 5c1d026a330ae7..fe379ffe912391 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -121,7 +121,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: OverflowError (built-in exception) Return a C :c:expr:`long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a @@ -130,16 +130,16 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow) Return a C :c:expr:`long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is greater than :const:`LONG_MAX` or less than @@ -150,10 +150,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: long long PyLong_AsLongLong(PyObject *obj) @@ -162,7 +162,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: OverflowError (built-in exception) Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a @@ -171,16 +171,16 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: long long PyLong_AsLongLongAndOverflow(PyObject *obj, int *overflow) Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is greater than :const:`LLONG_MAX` or less than @@ -193,10 +193,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionadded:: 3.2 .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong) @@ -267,7 +267,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long PyLong_AsUnsignedLongMask(PyObject *obj) Return a C :c:expr:`unsigned long` representation of *obj*. If *obj* is not - an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` + an instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:expr:`unsigned long`, @@ -277,17 +277,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj) Return a C :c:expr:`unsigned long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its - :meth:`__index__` method (if present) to convert it to a + :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:expr:`unsigned long long`, @@ -297,10 +297,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: double PyLong_AsDouble(PyObject *pylong) diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index b17d58e1cc0ce1..fdac51d9603ceb 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -9,7 +9,7 @@ This module provides access to mathematical functions for complex numbers. The functions in this module accept integers, floating-point numbers or complex numbers as arguments. They will also accept any Python object that has either a -:meth:`__complex__` or a :meth:`__float__` method: these methods are used to +:meth:`~object.__complex__` or a :meth:`~object.__float__` method: these methods are used to convert the object to a complex or floating-point number, respectively, and the function is then applied to the result of the conversion. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 3d2bb8efc95d8e..9b9731e9189853 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -122,7 +122,7 @@ are always available. They are listed here in alphabetical order. Convert an integer number to a binary string prefixed with "0b". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it - has to define an :meth:`__index__` method that returns an integer. Some + has to define an :meth:`~object.__index__` method that returns an integer. Some examples: >>> bin(3) @@ -383,9 +383,9 @@ are always available. They are listed here in alphabetical order. ``0j``. For a general Python object ``x``, ``complex(x)`` delegates to - ``x.__complex__()``. If ``__complex__()`` is not defined then it falls back - to :meth:`__float__`. If ``__float__()`` is not defined then it falls back - to :meth:`__index__`. + ``x.__complex__()``. If :meth:`~object.__complex__` is not defined then it falls back + to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back + to :meth:`~object.__index__`. .. note:: @@ -400,8 +400,8 @@ are always available. They are listed here in alphabetical order. Grouping digits with underscores as in code literals is allowed. .. versionchanged:: 3.8 - Falls back to :meth:`__index__` if :meth:`__complex__` and - :meth:`__float__` are not defined. + Falls back to :meth:`~object.__index__` if :meth:`~object.__complex__` and + :meth:`~object.__float__` are not defined. .. function:: delattr(object, name) @@ -681,8 +681,8 @@ are always available. They are listed here in alphabetical order. float, an :exc:`OverflowError` will be raised. For a general Python object ``x``, ``float(x)`` delegates to - ``x.__float__()``. If ``__float__()`` is not defined then it falls back - to :meth:`__index__`. + ``x.__float__()``. If :meth:`~object.__float__` is not defined then it falls back + to :meth:`~object.__index__`. If no argument is given, ``0.0`` is returned. @@ -708,7 +708,7 @@ are always available. They are listed here in alphabetical order. *x* is now a positional-only parameter. .. versionchanged:: 3.8 - Falls back to :meth:`__index__` if :meth:`__float__` is not defined. + Falls back to :meth:`~object.__index__` if :meth:`~object.__float__` is not defined. .. index:: @@ -822,7 +822,7 @@ are always available. They are listed here in alphabetical order. Convert an integer number to a lowercase hexadecimal string prefixed with "0x". If *x* is not a Python :class:`int` object, it has to define an - :meth:`__index__` method that returns an integer. Some examples: + :meth:`~object.__index__` method that returns an integer. Some examples: >>> hex(255) '0xff' @@ -893,9 +893,9 @@ are always available. They are listed here in alphabetical order. int(x, base=10) Return an integer object constructed from a number or string *x*, or return - ``0`` if no arguments are given. If *x* defines :meth:`__int__`, - ``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`__index__`, - it returns ``x.__index__()``. If *x* defines :meth:`__trunc__`, + ``0`` if no arguments are given. If *x* defines :meth:`~object.__int__`, + ``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`~object.__index__`, + it returns ``x.__index__()``. If *x* defines :meth:`~object.__trunc__`, it returns ``x.__trunc__()``. For floating point numbers, this truncates towards zero. @@ -932,10 +932,10 @@ are always available. They are listed here in alphabetical order. *x* is now a positional-only parameter. .. versionchanged:: 3.8 - Falls back to :meth:`__index__` if :meth:`__int__` is not defined. + Falls back to :meth:`~object.__index__` if :meth:`~object.__int__` is not defined. .. versionchanged:: 3.11 - The delegation to :meth:`__trunc__` is deprecated. + The delegation to :meth:`~object.__trunc__` is deprecated. .. versionchanged:: 3.11 :class:`int` string inputs and string representations can be limited to @@ -1138,7 +1138,7 @@ are always available. They are listed here in alphabetical order. Convert an integer number to an octal string prefixed with "0o". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it - has to define an :meth:`__index__` method that returns an integer. For + has to define an :meth:`~object.__index__` method that returns an integer. For example: >>> oct(8) diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 78fd6e397ae635..6d2739b4557fbf 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -266,11 +266,11 @@ Notes: (2) When attempting to pack a non-integer using any of the integer conversion - codes, if the non-integer has a :meth:`__index__` method then that method is + codes, if the non-integer has a :meth:`~object.__index__` method then that method is called to convert the argument to an integer before packing. .. versionchanged:: 3.2 - Added use of the :meth:`__index__` method for non-integers. + Added use of the :meth:`~object.__index__` method for non-integers. (3) The ``'n'`` and ``'N'`` conversion codes are only available for the native From 0616c83f57a8d2fd62d12ddaba987052c5015260 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 30 Jun 2023 17:15:18 -0700 Subject: [PATCH 0289/1206] [3.12] gh-106145: Make `end_{lineno,col_offset}` required on `type_param` nodes (GH-106224) (#106295) gh-106145: Make `end_{lineno,col_offset}` required on `type_param` nodes (GH-106224) (cherry picked from commit 46c1097868745eeb47abbc8af8c34e8fcb80ff1d) Co-authored-by: Nikita Sobolev --- Lib/test/test_unparse.py | 2 +- ...3-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst | 2 ++ Parser/Python.asdl | 2 +- Python/Python-ast.c | 18 ++++++------------ 4 files changed, 10 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 41a6318d1499b4..b3efb61e83049e 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -705,7 +705,7 @@ class DirectoryTestCase(ASTTestCase): test_directories = (lib_dir, lib_dir / "test") run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py", "test_ast.py", "test_asdl_parser.py", "test_fstring.py", - "test_patma.py"} + "test_patma.py", "test_type_alias.py", "test_type_params.py"} _files_to_test = None diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst new file mode 100644 index 00000000000000..4f9445bbcbe550 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst @@ -0,0 +1,2 @@ +Make ``end_lineno`` and ``end_col_offset`` required on ``type_param`` ast +nodes. diff --git a/Parser/Python.asdl b/Parser/Python.asdl index 93632a09f0959b..0d154867276c36 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -148,5 +148,5 @@ module Python type_param = TypeVar(identifier name, expr? bound) | ParamSpec(identifier name) | TypeVarTuple(identifier name) - attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) + attributes (int lineno, int col_offset, int end_lineno, int end_col_offset) } diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 1ffb8354e3a1b1..5db9ade3af4547 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -1902,12 +1902,6 @@ init_types(struct ast_state *state) if (!state->type_param_type) return 0; if (!add_attributes(state, state->type_param_type, type_param_attributes, 4)) return 0; - if (PyObject_SetAttr(state->type_param_type, state->end_lineno, Py_None) == - -1) - return 0; - if (PyObject_SetAttr(state->type_param_type, state->end_col_offset, - Py_None) == -1) - return 0; state->TypeVar_type = make_type(state, "TypeVar", state->type_param_type, TypeVar_fields, 2, "TypeVar(identifier name, expr? bound)"); @@ -12500,9 +12494,9 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); - end_lineno = lineno; + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"end_lineno\" missing from type_param"); + return 1; } else { int res; @@ -12517,9 +12511,9 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); - end_col_offset = col_offset; + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"end_col_offset\" missing from type_param"); + return 1; } else { int res; From c4298d5c648ba79d0a3dbf16e9aa8a6011802470 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 30 Jun 2023 17:32:44 -0700 Subject: [PATCH 0290/1206] [3.12] gh-105486: Change the `repr` of `ParamSpec` list of args in `GenericAlias` (GH-105488) (#106297) gh-105486: Change the `repr` of `ParamSpec` list of args in `GenericAlias` (GH-105488) (cherry picked from commit eb7d6e7ad844955f9af88707d296e003c7ce4394) Co-authored-by: Nikita Sobolev --- Lib/test/test_genericalias.py | 8 ++++ Lib/test/test_type_aliases.py | 16 ++++++++ ...-06-08-09-10-15.gh-issue-105486.dev-WS.rst | 1 + Objects/genericaliasobject.c | 38 ++++++++++++++++++- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 24d4216417521c..bf600a0f4d1834 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -209,6 +209,9 @@ class MyList(list): def test_repr(self): class MyList(list): pass + class MyGeneric: + __class_getitem__ = classmethod(GenericAlias) + self.assertEqual(repr(list[str]), 'list[str]') self.assertEqual(repr(list[()]), 'list[()]') self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]') @@ -221,6 +224,11 @@ class MyList(list): self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr..MyList[int]')) self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr + # gh-105488 + self.assertTrue(repr(MyGeneric[int]).endswith('MyGeneric[int]')) + self.assertTrue(repr(MyGeneric[[]]).endswith('MyGeneric[[]]')) + self.assertTrue(repr(MyGeneric[[int, str]]).endswith('MyGeneric[[int, str]]')) + def test_exposed_type(self): import types a = types.GenericAlias(list, int) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index b9b24448e83d8e..0ce97f57de6860 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -142,7 +142,16 @@ def test_subscripting(self): def test_repr(self): type Simple = int + type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]] + self.assertEqual(repr(Simple), "Simple") + self.assertEqual(repr(VeryGeneric), "VeryGeneric") + self.assertEqual(repr(VeryGeneric[int, bytes, str, [float, object]]), + "VeryGeneric[int, bytes, str, [float, object]]") + self.assertEqual(repr(VeryGeneric[int, []]), + "VeryGeneric[int, []]") + self.assertEqual(repr(VeryGeneric[int, [VeryGeneric[int], list[str]]]), + "VeryGeneric[int, [VeryGeneric[int], list[str]]]") def test_recursive_repr(self): type Recursive = Recursive @@ -151,6 +160,13 @@ def test_recursive_repr(self): type X = list[Y] type Y = list[X] self.assertEqual(repr(X), "X") + self.assertEqual(repr(Y), "Y") + + type GenericRecursive[X] = list[X | GenericRecursive[X]] + self.assertEqual(repr(GenericRecursive), "GenericRecursive") + self.assertEqual(repr(GenericRecursive[int]), "GenericRecursive[int]") + self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]), + "GenericRecursive[GenericRecursive[int]]") class TypeAliasConstructorTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst new file mode 100644 index 00000000000000..9f735db3dc89c3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst @@ -0,0 +1 @@ +Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 888cb16edd1b46..117b4e8dfb960a 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -121,6 +121,36 @@ ga_repr_item(_PyUnicodeWriter *writer, PyObject *p) return err; } +static int +ga_repr_items_list(_PyUnicodeWriter *writer, PyObject *p) +{ + assert(PyList_CheckExact(p)); + + Py_ssize_t len = PyList_GET_SIZE(p); + + if (_PyUnicodeWriter_WriteASCIIString(writer, "[", 1) < 0) { + return -1; + } + + for (Py_ssize_t i = 0; i < len; i++) { + if (i > 0) { + if (_PyUnicodeWriter_WriteASCIIString(writer, ", ", 2) < 0) { + return -1; + } + } + PyObject *item = PyList_GET_ITEM(p, i); + if (ga_repr_item(writer, item) < 0) { + return -1; + } + } + + if (_PyUnicodeWriter_WriteASCIIString(writer, "]", 1) < 0) { + return -1; + } + + return 0; +} + static PyObject * ga_repr(PyObject *self) { @@ -148,7 +178,13 @@ ga_repr(PyObject *self) } } PyObject *p = PyTuple_GET_ITEM(alias->args, i); - if (ga_repr_item(&writer, p) < 0) { + if (PyList_CheckExact(p)) { + // Looks like we are working with ParamSpec's list of type args: + if (ga_repr_items_list(&writer, p) < 0) { + goto error; + } + } + else if (ga_repr_item(&writer, p) < 0) { goto error; } } From 8738c5bceea309944dc4f18e49cf90e871ecbe65 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 30 Jun 2023 19:40:43 -0700 Subject: [PATCH 0291/1206] [3.12] gh-106232: Make timeit doc command lines compatible with Windows. (GH-106296) (#106298) gh-106232: Make timeit doc command lines compatible with Windows. (GH-106296) Command Prompt (CMD Shell) and older versions of PowerShell require double quotes and single quotes inside the string. This form also works on linux and macOS. (cherry picked from commit 04dfc6fa9018e92a5b51c29fc0ff45419c596bc3) Co-authored-by: Terry Jan Reedy --- Doc/library/timeit.rst | 18 +++++++++--------- Doc/using/cmdline.rst | 2 +- ...3-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst | 2 ++ 3 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst index 32ab565aba0c08..a559e0a2eb3dad 100644 --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -27,11 +27,11 @@ can be used to compare three different expressions: .. code-block:: shell-session - $ python -m timeit '"-".join(str(n) for n in range(100))' + $ python -m timeit "'-'.join(str(n) for n in range(100))" 10000 loops, best of 5: 30.2 usec per loop - $ python -m timeit '"-".join([str(n) for n in range(100)])' + $ python -m timeit "'-'.join([str(n) for n in range(100)])" 10000 loops, best of 5: 27.5 usec per loop - $ python -m timeit '"-".join(map(str, range(100)))' + $ python -m timeit "'-'.join(map(str, range(100)))" 10000 loops, best of 5: 23.2 usec per loop This can be achieved from the :ref:`python-interface` with:: @@ -277,9 +277,9 @@ It is possible to provide a setup statement that is executed only once at the be .. code-block:: shell-session - $ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text' + $ python -m timeit -s "text = 'sample string'; char = 'g'" "char in text" 5000000 loops, best of 5: 0.0877 usec per loop - $ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)' + $ python -m timeit -s "text = 'sample string'; char = 'g'" "text.find(char)" 1000000 loops, best of 5: 0.342 usec per loop In the output, there are three fields. The loop count, which tells you how many @@ -313,14 +313,14 @@ to test for missing and present object attributes: .. code-block:: shell-session - $ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass' + $ python -m timeit "try:" " str.__bool__" "except AttributeError:" " pass" 20000 loops, best of 5: 15.7 usec per loop - $ python -m timeit 'if hasattr(str, "__bool__"): pass' + $ python -m timeit "if hasattr(str, '__bool__'): pass" 50000 loops, best of 5: 4.26 usec per loop - $ python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass' + $ python -m timeit "try:" " int.__bool__" "except AttributeError:" " pass" 200000 loops, best of 5: 1.43 usec per loop - $ python -m timeit 'if hasattr(int, "__bool__"): pass' + $ python -m timeit "if hasattr(int, '__bool__'): pass" 100000 loops, best of 5: 2.23 usec per loop :: diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 9d4042ce5a7e8a..1b470d395d6d58 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -109,7 +109,7 @@ source. Many standard library modules contain code that is invoked on their execution as a script. An example is the :mod:`timeit` module:: - python -m timeit -s 'setup here' 'benchmarked code here' + python -m timeit -s "setup here" "benchmarked code here" python -m timeit -h # for details .. audit-event:: cpython.run_module module-name cmdoption-m diff --git a/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst b/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst new file mode 100644 index 00000000000000..bc16f92b7d6478 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst @@ -0,0 +1,2 @@ +Make timeit doc command lines compatible with Windows by using double quotes +for arguments. This works on linux and macOS also. From 730c873efd9aecbfa2e788faf021a3523ad6a65e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:16:14 -0700 Subject: [PATCH 0292/1206] [3.12] gh-102541: Fix Helper.help("mod") for non-existent mod (GH-105934) (#106322) gh-102541: Fix Helper.help("mod") for non-existent mod (GH-105934) If the output arg to Helper() is a stream rather than the default None, which means 'page to stdout', the ImportError from pydoc.resolve is currently not caught in pydoc.doc. The same error is caught when output is None. --------- (cherry picked from commit 0530f4f64629ff97f3feb7524da0833b9535e8b6) Co-authored-by: Kirill Podoprigora Co-authored-by: Terry Jan Reedy --- Lib/pydoc.py | 6 +++++- Lib/test/test_pydoc.py | 7 +++++++ .../Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst diff --git a/Lib/pydoc.py b/Lib/pydoc.py index d69369d4196eaa..185f09e603df2e 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1790,7 +1790,11 @@ def doc(thing, title='Python Library Documentation: %s', forceload=0, raise print(exc) else: - output.write(render_doc(thing, title, forceload, plaintext)) + try: + s = render_doc(thing, title, forceload, plaintext) + except ImportError as exc: + s = str(exc) + output.write(s) def writedoc(thing, forceload=0): """Write HTML documentation to a file in the current directory.""" diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index cefc71cb5a7f54..115ffd3c29d4d6 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -631,6 +631,13 @@ def test_builtin_on_metaclasses(self): # Testing that the subclasses section does not appear self.assertNotIn('Built-in subclasses', text) + def test_fail_help_output_redirect(self): + with StringIO() as buf: + helper = pydoc.Helper(output=buf) + helper.help("abd") + expected = missing_pattern % "abd" + self.assertEqual(expected, buf.getvalue().strip().replace('\n', os.linesep)) + @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'trace function introduces __locals__ unexpectedly') @requires_docstrings diff --git a/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst b/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst new file mode 100644 index 00000000000000..efaf5db10f3e1c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst @@ -0,0 +1 @@ +Make pydoc.doc catch bad module ImportError when output stream is not None. From 5e856049b19e2a0c78411b90a8fbc3198ca2a695 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 2 Jul 2023 20:23:27 -0700 Subject: [PATCH 0293/1206] [3.12] Replace the esoteric term 'datum' when describing dict comprehensions (GH-106119) (#106348) Replace the esoteric term 'datum' when describing dict comprehensions (GH-106119) (cherry picked from commit 987b712b4aeeece336eed24fcc87a950a756c3e2) Co-authored-by: Ned Batchelder --- Doc/reference/expressions.rst | 22 +++++++++++----------- Doc/reference/simple_stmts.rst | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index b97a08f25d92a2..08dcc8095bee8c 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -298,27 +298,27 @@ Dictionary displays .. index:: pair: dictionary; display pair: dictionary; comprehensions - key, datum, key/datum pair + key, value, key/value pair pair: object; dictionary single: {} (curly brackets); dictionary expression single: : (colon); in dictionary expressions single: , (comma); in dictionary displays -A dictionary display is a possibly empty series of key/datum pairs enclosed in -curly braces: +A dictionary display is a possibly empty series of dict items (key/value pairs) +enclosed in curly braces: .. productionlist:: python-grammar - dict_display: "{" [`key_datum_list` | `dict_comprehension`] "}" - key_datum_list: `key_datum` ("," `key_datum`)* [","] - key_datum: `expression` ":" `expression` | "**" `or_expr` + dict_display: "{" [`dict_item_list` | `dict_comprehension`] "}" + dict_item_list: `dict_item` ("," `dict_item`)* [","] + dict_item: `expression` ":" `expression` | "**" `or_expr` dict_comprehension: `expression` ":" `expression` `comp_for` A dictionary display yields a new dictionary object. -If a comma-separated sequence of key/datum pairs is given, they are evaluated +If a comma-separated sequence of dict items is given, they are evaluated from left to right to define the entries of the dictionary: each key object is -used as a key into the dictionary to store the corresponding datum. This means -that you can specify the same key multiple times in the key/datum list, and the +used as a key into the dictionary to store the corresponding value. This means +that you can specify the same key multiple times in the dict item list, and the final dictionary's value for that key will be the last one given. .. index:: @@ -328,7 +328,7 @@ final dictionary's value for that key will be the last one given. A double asterisk ``**`` denotes :dfn:`dictionary unpacking`. Its operand must be a :term:`mapping`. Each mapping item is added to the new dictionary. Later values replace values already set by -earlier key/datum pairs and earlier dictionary unpackings. +earlier dict items and earlier dictionary unpackings. .. versionadded:: 3.5 Unpacking into dictionary displays, originally proposed by :pep:`448`. @@ -344,7 +344,7 @@ in the new dictionary in the order they are produced. Restrictions on the types of the key values are listed earlier in section :ref:`types`. (To summarize, the key type should be :term:`hashable`, which excludes all mutable objects.) Clashes between duplicate keys are not detected; the last -datum (textually rightmost in the display) stored for a given key value +value (textually rightmost in the display) stored for a given key value prevails. .. versionchanged:: 3.8 diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 662a4b643c4378..a9e65be1eda340 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -210,7 +210,7 @@ Assignment of an object to a single target is recursively defined as follows. If the primary is a mapping object (such as a dictionary), the subscript must have a type compatible with the mapping's key type, and the mapping is then - asked to create a key/datum pair which maps the subscript to the assigned + asked to create a key/value pair which maps the subscript to the assigned object. This can either replace an existing key/value pair with the same key value, or insert a new key/value pair (if no key with the same value existed). From 5f20152f01febf4ffd9572a8ab3e980a4660ef69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 3 Jul 2023 06:42:20 -0700 Subject: [PATCH 0294/1206] [3.12] gh-106359: Fix corner case bugs in Argument Clinic converter parser (GH-106361) (#106364) gh-106359: Fix corner case bugs in Argument Clinic converter parser (GH-106361) DSLParser.parse_converter() could return unusable kwdicts in some rare cases (cherry picked from commit 0da4c883cf4185efe27b711c3e0a1e6e94397610) Co-authored-by: Erlend E. Aasland Co-authored-by: Alex Waygood --- Lib/test/test_clinic.py | 16 ++++++++++++++++ ...023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst | 2 ++ Tools/clinic/clinic.py | 16 +++++++++------- 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index bea7303805567f..76a06df5fe2e55 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -813,6 +813,22 @@ def test_other_bizarre_things_in_annotations_fail(self): ) self.assertEqual(s, expected_failure_message) + def test_kwarg_splats_disallowed_in_function_call_annotations(self): + expected_error_msg = ( + "Error on line 0:\n" + "Cannot use a kwarg splat in a function-call annotation\n" + ) + dataset = ( + 'module fo\nfo.barbaz\n o: bool(**{None: "bang!"})', + 'module fo\nfo.barbaz -> bool(**{None: "bang!"})', + 'module fo\nfo.barbaz -> bool(**{"bang": 42})', + 'module fo\nfo.barbaz\n o: bool(**{"bang": None})', + ) + for fn in dataset: + with self.subTest(fn=fn): + out = self.parse_function_should_fail(fn) + self.assertEqual(out, expected_error_msg) + def test_unused_param(self): block = self.parse(""" module foo diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst b/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst new file mode 100644 index 00000000000000..600c265391ec5b --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst @@ -0,0 +1,2 @@ +Argument Clinic now explicitly forbids "kwarg splats" in function calls used as +annotations. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index d182e5e7764e46..d67479c7f8ab88 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4289,6 +4289,7 @@ def dedent(self, line): StateKeeper = Callable[[str | None], None] +ConverterArgs = dict[str, Any] class DSLParser: def __init__(self, clinic: Clinic) -> None: @@ -5016,10 +5017,10 @@ def bad_node(self, node): key = f"{parameter_name}_as_{c_name}" if c_name else parameter_name self.function.parameters[key] = p - KwargDict = dict[str | None, Any] - @staticmethod - def parse_converter(annotation: ast.expr | None) -> tuple[str, bool, KwargDict]: + def parse_converter( + annotation: ast.expr | None + ) -> tuple[str, bool, ConverterArgs]: match annotation: case ast.Constant(value=str() as value): return value, True, {} @@ -5027,10 +5028,11 @@ def parse_converter(annotation: ast.expr | None) -> tuple[str, bool, KwargDict]: return name, False, {} case ast.Call(func=ast.Name(name)): symbols = globals() - kwargs = { - node.arg: eval_ast_expr(node.value, symbols) - for node in annotation.keywords - } + kwargs: ConverterArgs = {} + for node in annotation.keywords: + if not isinstance(node.arg, str): + fail("Cannot use a kwarg splat in a function-call annotation") + kwargs[node.arg] = eval_ast_expr(node.value, symbols) return name, False, kwargs case _: fail( From 887a7e603628a7718233cf8068d7be8ccd9d7254 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 3 Jul 2023 08:13:21 -0700 Subject: [PATCH 0295/1206] [3.12] gh-91053: make func watcher tests resilient to other func watchers (GH-106286) (#106365) gh-91053: make func watcher tests resilient to other func watchers (GH-106286) (cherry picked from commit 58906213cc5d8f2be311664766b4923ef29dae1f) Co-authored-by: Carl Meyer --- Modules/_testcapi/watchers.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index d2c71fb401d36a..7167943fffab39 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -432,9 +432,9 @@ allocate_too_many_code_watchers(PyObject *self, PyObject *args) // Test function watchers -#define NUM_FUNC_WATCHERS 2 -static PyObject *pyfunc_watchers[NUM_FUNC_WATCHERS]; -static int func_watcher_ids[NUM_FUNC_WATCHERS] = {-1, -1}; +#define NUM_TEST_FUNC_WATCHERS 2 +static PyObject *pyfunc_watchers[NUM_TEST_FUNC_WATCHERS]; +static int func_watcher_ids[NUM_TEST_FUNC_WATCHERS] = {-1, -1}; static PyObject * get_id(PyObject *obj) @@ -508,7 +508,7 @@ second_func_watcher_callback(PyFunction_WatchEvent event, return call_pyfunc_watcher(pyfunc_watchers[1], event, func, new_value); } -static PyFunction_WatchCallback func_watcher_callbacks[NUM_FUNC_WATCHERS] = { +static PyFunction_WatchCallback func_watcher_callbacks[NUM_TEST_FUNC_WATCHERS] = { first_func_watcher_callback, second_func_watcher_callback }; @@ -533,26 +533,25 @@ add_func_watcher(PyObject *self, PyObject *func) return NULL; } int idx = -1; - for (int i = 0; i < NUM_FUNC_WATCHERS; i++) { + for (int i = 0; i < NUM_TEST_FUNC_WATCHERS; i++) { if (func_watcher_ids[i] == -1) { idx = i; break; } } if (idx == -1) { - PyErr_SetString(PyExc_RuntimeError, "no free watchers"); - return NULL; - } - PyObject *result = PyLong_FromLong(idx); - if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no free test watchers"); return NULL; } func_watcher_ids[idx] = PyFunction_AddWatcher(func_watcher_callbacks[idx]); if (func_watcher_ids[idx] < 0) { - Py_DECREF(result); return NULL; } pyfunc_watchers[idx] = Py_NewRef(func); + PyObject *result = PyLong_FromLong(func_watcher_ids[idx]); + if (result == NULL) { + return NULL; + } return result; } @@ -569,7 +568,7 @@ clear_func_watcher(PyObject *self, PyObject *watcher_id_obj) return NULL; } int idx = -1; - for (int i = 0; i < NUM_FUNC_WATCHERS; i++) { + for (int i = 0; i < NUM_TEST_FUNC_WATCHERS; i++) { if (func_watcher_ids[i] == wid) { idx = i; break; From ddff4737bd1215b151d94aa27559721022ab2a47 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:45:49 -0700 Subject: [PATCH 0296/1206] [3.12] gh-106368: Increase Argument Clinic test coverage (GH-106369) (#106370) Add tests for 'self' and 'defining_class' converter requirements. (cherry picked from commit 7f4c8121db62a9f72f00f2d9f73381e82f289581) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 76a06df5fe2e55..30e8dcc3e8ef12 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -829,6 +829,63 @@ def test_kwarg_splats_disallowed_in_function_call_annotations(self): out = self.parse_function_should_fail(fn) self.assertEqual(out, expected_error_msg) + def test_self_param_placement(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'self' parameter, if specified, must be the very first thing " + "in the parameter block.\n" + ) + block = """ + module foo + foo.func + a: int + self: self(type="PyObject *") + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + + def test_self_param_cannot_be_optional(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'self' parameter cannot be marked optional.\n" + ) + block = """ + module foo + foo.func + self: self(type="PyObject *") = None + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + + def test_defining_class_param_placement(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'defining_class' parameter, if specified, must either be the " + "first thing in the parameter block, or come just after 'self'.\n" + ) + block = """ + module foo + foo.func + self: self(type="PyObject *") + a: int + cls: defining_class + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + + def test_defining_class_param_cannot_be_optional(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'defining_class' parameter cannot be marked optional.\n" + ) + block = """ + module foo + foo.func + cls: defining_class(type="PyObject *") = None + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + def test_unused_param(self): block = self.parse(""" module foo From 67127ca8e2e9c94619503390267467fb3ee216e1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:49:09 -0700 Subject: [PATCH 0297/1206] [3.12] Small speed-up for the convolve() recipe. (GH-106371) (GH-106375) --- Doc/library/itertools.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 56d6599798af20..a2d1798a2c6da1 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1085,8 +1085,8 @@ The following recipes have a more mathematical flavor: kernel = tuple(kernel)[::-1] n = len(kernel) padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1)) - for window in sliding_window(padded_signal, n): - yield math.sumprod(kernel, window) + windowed_signal = sliding_window(padded_signal, n) + return map(math.sumprod, repeat(kernel), windowed_signal) def polynomial_from_roots(roots): """Compute a polynomial's coefficients from its roots. From 38fe0e7c2d0db1bba75bebc7dd5e890a93aa11b0 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 4 Jul 2023 00:27:34 +0200 Subject: [PATCH 0298/1206] [3.12] gh-106368: Clean up Argument Clinic tests (#106373) (#106379) (cherry picked from commit 3ee8dac7a1b3882aa3aac7703bdae2de7b6402ad) --- Lib/test/test_clinic.py | 798 ++++++++++++++++++++++------------------ 1 file changed, 441 insertions(+), 357 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 30e8dcc3e8ef12..b3602887ab6352 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -3,7 +3,8 @@ # Licensed to the PSF under a contributor agreement. from test import support, test_tools -from test.support import import_helper, os_helper +from test.support import os_helper +from textwrap import dedent from unittest import TestCase import collections import inspect @@ -171,43 +172,43 @@ def test_solo_newline(self): def test_no_substitution(self): self._test(""" abc - """, """ + """, """ abc - """) + """) def test_empty_substitution(self): self._test(""" abc {name} def - """, """ + """, """ abc def - """, name='') + """, name='') def test_single_line_substitution(self): self._test(""" abc {name} def - """, """ + """, """ abc GARGLE def - """, name='GARGLE') + """, name='GARGLE') def test_multiline_substitution(self): self._test(""" abc {name} def - """, """ + """, """ abc bingle bungle def - """, name='bingle\nbungle\n') + """, name='bingle\nbungle\n') class InertParser: def __init__(self, clinic): @@ -240,9 +241,9 @@ def round_trip(self, input): def test_round_trip_1(self): self.round_trip(""" - verbatim text here - lah dee dah -""") + verbatim text here + lah dee dah + """) def test_round_trip_2(self): self.round_trip(""" verbatim text here @@ -286,22 +287,38 @@ def test_clinic_1(self): class ClinicParserTest(TestCase): + def checkDocstring(self, fn, expected): + self.assertTrue(hasattr(fn, "docstring")) + self.assertEqual(fn.docstring.strip(), + dedent(expected).strip()) + def test_trivial(self): parser = DSLParser(FakeClinic()) - block = clinic.Block("module os\nos.access") + block = clinic.Block(""" + module os + os.access + """) parser.parse(block) module, function = block.signatures self.assertEqual("access", function.name) self.assertEqual("os", module.name) def test_ignore_line(self): - block = self.parse("#\nmodule os\nos.access") + block = self.parse(dedent(""" + # + module os + os.access + """)) module, function = block.signatures self.assertEqual("access", function.name) self.assertEqual("os", module.name) def test_param(self): - function = self.parse_function("module os\nos.access\n path: int") + function = self.parse_function(""" + module os + os.access + path: int + """) self.assertEqual("access", function.name) self.assertEqual(2, len(function.parameters)) p = function.parameters['path'] @@ -309,236 +326,296 @@ def test_param(self): self.assertIsInstance(p.converter, clinic.int_converter) def test_param_default(self): - function = self.parse_function("module os\nos.access\n follow_symlinks: bool = True") + function = self.parse_function(""" + module os + os.access + follow_symlinks: bool = True + """) p = function.parameters['follow_symlinks'] self.assertEqual(True, p.default) def test_param_with_continuations(self): - function = self.parse_function("module os\nos.access\n follow_symlinks: \\\n bool \\\n =\\\n True") + function = self.parse_function(r""" + module os + os.access + follow_symlinks: \ + bool \ + = \ + True + """) p = function.parameters['follow_symlinks'] self.assertEqual(True, p.default) def test_param_default_expression(self): - function = self.parse_function("module os\nos.access\n follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize") + function = self.parse_function(""" + module os + os.access + follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize + """) p = function.parameters['follow_symlinks'] self.assertEqual(sys.maxsize, p.default) self.assertEqual("MAXSIZE", p.converter.c_default) - s = self.parse_function_should_fail("module os\nos.access\n follow_symlinks: int = sys.maxsize") - self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n") + expected_msg = ( + "Error on line 0:\n" + "When you specify a named constant ('sys.maxsize') as your default value,\n" + "you MUST specify a valid c_default.\n" + ) + out = self.parse_function_should_fail(""" + module os + os.access + follow_symlinks: int = sys.maxsize + """) + self.assertEqual(out, expected_msg) def test_param_no_docstring(self): function = self.parse_function(""" -module os -os.access - follow_symlinks: bool = True - something_else: str = ''""") + module os + os.access + follow_symlinks: bool = True + something_else: str = '' + """) p = function.parameters['follow_symlinks'] self.assertEqual(3, len(function.parameters)) - self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter) + conv = function.parameters['something_else'].converter + self.assertIsInstance(conv, clinic.str_converter) def test_param_default_parameters_out_of_order(self): - s = self.parse_function_should_fail(""" -module os -os.access - follow_symlinks: bool = True - something_else: str""") - self.assertEqual(s, """Error on line 0: -Can't have a parameter without a default ('something_else') -after a parameter with a default! -""") + expected_msg = ( + "Error on line 0:\n" + "Can't have a parameter without a default ('something_else')\n" + "after a parameter with a default!\n" + ) + out = self.parse_function_should_fail(""" + module os + os.access + follow_symlinks: bool = True + something_else: str""") + self.assertEqual(out, expected_msg) def disabled_test_converter_arguments(self): - function = self.parse_function("module os\nos.access\n path: path_t(allow_fd=1)") + function = self.parse_function(""" + module os + os.access + path: path_t(allow_fd=1) + """) p = function.parameters['path'] self.assertEqual(1, p.converter.args['allow_fd']) def test_function_docstring(self): function = self.parse_function(""" -module os -os.stat as os_stat_fn + module os + os.stat as os_stat_fn - path: str - Path to be examined + path: str + Path to be examined -Perform a stat system call on the given path.""") - self.assertEqual(""" -stat($module, /, path) --- + Perform a stat system call on the given path. + """) + self.checkDocstring(function, """ + stat($module, /, path) + -- -Perform a stat system call on the given path. + Perform a stat system call on the given path. - path - Path to be examined -""".strip(), function.docstring) + path + Path to be examined + """) def test_explicit_parameters_in_docstring(self): - function = self.parse_function(""" -module foo -foo.bar - x: int - Documentation for x. - y: int + function = self.parse_function(dedent(""" + module foo + foo.bar + x: int + Documentation for x. + y: int -This is the documentation for foo. + This is the documentation for foo. -Okay, we're done here. -""") - self.assertEqual(""" -bar($module, /, x, y) --- + Okay, we're done here. + """)) + self.checkDocstring(function, """ + bar($module, /, x, y) + -- -This is the documentation for foo. + This is the documentation for foo. - x - Documentation for x. + x + Documentation for x. -Okay, we're done here. -""".strip(), function.docstring) + Okay, we're done here. + """) def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self): - function = self.parse_function(""" -module os -os.stat - path: str -This/used to break Clinic! -""") - self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring) + function = self.parse_function(dedent(""" + module os + os.stat + path: str + This/used to break Clinic! + """)) + self.checkDocstring(function, """ + stat($module, /, path) + -- + + This/used to break Clinic! + """) def test_c_name(self): - function = self.parse_function("module os\nos.stat as os_stat_fn") + function = self.parse_function(""" + module os + os.stat as os_stat_fn + """) self.assertEqual("os_stat_fn", function.c_basename) def test_return_converter(self): - function = self.parse_function("module os\nos.stat -> int") + function = self.parse_function(""" + module os + os.stat -> int + """) self.assertIsInstance(function.return_converter, clinic.int_return_converter) def test_star(self): - function = self.parse_function("module os\nos.access\n *\n follow_symlinks: bool = True") + function = self.parse_function(""" + module os + os.access + * + follow_symlinks: bool = True + """) p = function.parameters['follow_symlinks'] self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind) self.assertEqual(0, p.group) def test_group(self): - function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n") + function = self.parse_function(""" + module window + window.border + [ + ls: int + ] + / + """) p = function.parameters['ls'] self.assertEqual(1, p.group) def test_left_group(self): function = self.parse_function(""" -module curses -curses.addch - [ - y: int - Y-coordinate. - x: int - X-coordinate. - ] - ch: char - Character to add. - [ - attr: long - Attributes for the character. - ] - / -""") - for name, group in ( + module curses + curses.addch + [ + y: int + Y-coordinate. + x: int + X-coordinate. + ] + ch: char + Character to add. + [ + attr: long + Attributes for the character. + ] + / + """) + dataset = ( ('y', -1), ('x', -1), ('ch', 0), ('attr', 1), - ): - p = function.parameters[name] - self.assertEqual(p.group, group) - self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) - self.assertEqual(function.docstring.strip(), """ -addch([y, x,] ch, [attr]) - - - y - Y-coordinate. - x - X-coordinate. - ch - Character to add. - attr - Attributes for the character. - """.strip()) + ) + for name, group in dataset: + with self.subTest(name=name, group=group): + p = function.parameters[name] + self.assertEqual(p.group, group) + self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) + self.checkDocstring(function, """ + addch([y, x,] ch, [attr]) + + + y + Y-coordinate. + x + X-coordinate. + ch + Character to add. + attr + Attributes for the character. + """) def test_nested_groups(self): function = self.parse_function(""" -module curses -curses.imaginary - [ - [ - y1: int - Y-coordinate. - y2: int - Y-coordinate. - ] - x1: int - X-coordinate. - x2: int - X-coordinate. - ] - ch: char - Character to add. - [ - attr1: long - Attributes for the character. - attr2: long - Attributes for the character. - attr3: long - Attributes for the character. - [ - attr4: long - Attributes for the character. - attr5: long - Attributes for the character. - attr6: long - Attributes for the character. - ] - ] - / -""") - for name, group in ( + module curses + curses.imaginary + [ + [ + y1: int + Y-coordinate. + y2: int + Y-coordinate. + ] + x1: int + X-coordinate. + x2: int + X-coordinate. + ] + ch: char + Character to add. + [ + attr1: long + Attributes for the character. + attr2: long + Attributes for the character. + attr3: long + Attributes for the character. + [ + attr4: long + Attributes for the character. + attr5: long + Attributes for the character. + attr6: long + Attributes for the character. + ] + ] + / + """) + dataset = ( ('y1', -2), ('y2', -2), ('x1', -1), ('x2', -1), ('ch', 0), ('attr1', 1), ('attr2', 1), ('attr3', 1), ('attr4', 2), ('attr5', 2), ('attr6', 2), - ): - p = function.parameters[name] - self.assertEqual(p.group, group) - self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) - - self.assertEqual(function.docstring.strip(), """ -imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, - attr6]]) - - - y1 - Y-coordinate. - y2 - Y-coordinate. - x1 - X-coordinate. - x2 - X-coordinate. - ch - Character to add. - attr1 - Attributes for the character. - attr2 - Attributes for the character. - attr3 - Attributes for the character. - attr4 - Attributes for the character. - attr5 - Attributes for the character. - attr6 - Attributes for the character. - """.strip()) + ) + for name, group in dataset: + with self.subTest(name=name, group=group): + p = function.parameters[name] + self.assertEqual(p.group, group) + self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) + + self.checkDocstring(function, """ + imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, + attr6]]) + + + y1 + Y-coordinate. + y2 + Y-coordinate. + x1 + X-coordinate. + x2 + X-coordinate. + ch + Character to add. + attr1 + Attributes for the character. + attr2 + Attributes for the character. + attr3 + Attributes for the character. + attr4 + Attributes for the character. + attr5 + Attributes for the character. + attr6 + Attributes for the character. + """) def parse_function_should_fail(self, s): with support.captured_stdout() as stdout: @@ -547,104 +624,108 @@ def parse_function_should_fail(self, s): return stdout.getvalue() def test_disallowed_grouping__two_top_groups_on_left(self): - s = self.parse_function_should_fail(""" -module foo -foo.two_top_groups_on_left - [ - group1 : int - ] - [ - group2 : int - ] - param: int - """) - self.assertEqual(s, - ('Error on line 0:\n' - 'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2.b)\n')) + expected_msg = ( + 'Error on line 0:\n' + 'Function two_top_groups_on_left has an unsupported group ' + 'configuration. (Unexpected state 2.b)\n' + ) + out = self.parse_function_should_fail(""" + module foo + foo.two_top_groups_on_left + [ + group1 : int + ] + [ + group2 : int + ] + param: int + """) + self.assertEqual(out, expected_msg) def test_disallowed_grouping__two_top_groups_on_right(self): self.parse_function_should_fail(""" -module foo -foo.two_top_groups_on_right - param: int - [ - group1 : int - ] - [ - group2 : int - ] - """) + module foo + foo.two_top_groups_on_right + param: int + [ + group1 : int + ] + [ + group2 : int + ] + """) def test_disallowed_grouping__parameter_after_group_on_right(self): self.parse_function_should_fail(""" -module foo -foo.parameter_after_group_on_right - param: int - [ - [ - group1 : int - ] - group2 : int - ] - """) + module foo + foo.parameter_after_group_on_right + param: int + [ + [ + group1 : int + ] + group2 : int + ] + """) def test_disallowed_grouping__group_after_parameter_on_left(self): self.parse_function_should_fail(""" -module foo -foo.group_after_parameter_on_left - [ - group2 : int - [ - group1 : int - ] - ] - param: int - """) + module foo + foo.group_after_parameter_on_left + [ + group2 : int + [ + group1 : int + ] + ] + param: int + """) def test_disallowed_grouping__empty_group_on_left(self): self.parse_function_should_fail(""" -module foo -foo.empty_group - [ - [ - ] - group2 : int - ] - param: int - """) + module foo + foo.empty_group + [ + [ + ] + group2 : int + ] + param: int + """) def test_disallowed_grouping__empty_group_on_right(self): self.parse_function_should_fail(""" -module foo -foo.empty_group - param: int - [ - [ - ] - group2 : int - ] - """) + module foo + foo.empty_group + param: int + [ + [ + ] + group2 : int + ] + """) def test_no_parameters(self): function = self.parse_function(""" -module foo -foo.bar + module foo + foo.bar -Docstring + Docstring -""") + """) self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring) self.assertEqual(1, len(function.parameters)) # self! def test_init_with_no_parameters(self): function = self.parse_function(""" -module foo -class foo.Bar "unused" "notneeded" -foo.Bar.__init__ + module foo + class foo.Bar "unused" "notneeded" + foo.Bar.__init__ -Docstring + Docstring + + """, signatures_in_block=3, function_index=2) -""", signatures_in_block=3, function_index=2) # self is not in the signature self.assertEqual("Bar()\n--\n\nDocstring", function.docstring) # but it *is* a parameter @@ -652,113 +733,117 @@ class foo.Bar "unused" "notneeded" def test_illegal_module_line(self): self.parse_function_should_fail(""" -module foo -foo.bar => int - / -""") + module foo + foo.bar => int + / + """) def test_illegal_c_basename(self): self.parse_function_should_fail(""" -module foo -foo.bar as 935 - / -""") + module foo + foo.bar as 935 + / + """) def test_single_star(self): self.parse_function_should_fail(""" -module foo -foo.bar - * - * -""") + module foo + foo.bar + * + * + """) def test_parameters_required_after_star_without_initial_parameters_or_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - * -""") + module foo + foo.bar + * + """) def test_parameters_required_after_star_without_initial_parameters_with_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - * -Docstring here. -""") + module foo + foo.bar + * + Docstring here. + """) def test_parameters_required_after_star_with_initial_parameters_without_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - this: int - * -""") + module foo + foo.bar + this: int + * + """) def test_parameters_required_after_star_with_initial_parameters_and_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - this: int - * -Docstring. -""") + module foo + foo.bar + this: int + * + Docstring. + """) def test_single_slash(self): self.parse_function_should_fail(""" -module foo -foo.bar - / - / -""") + module foo + foo.bar + / + / + """) def test_mix_star_and_slash(self): self.parse_function_should_fail(""" -module foo -foo.bar - x: int - y: int - * - z: int - / -""") + module foo + foo.bar + x: int + y: int + * + z: int + / + """) def test_parameters_not_permitted_after_slash_for_now(self): self.parse_function_should_fail(""" -module foo -foo.bar - / - x: int -""") + module foo + foo.bar + / + x: int + """) def test_parameters_no_more_than_one_vararg(self): - s = self.parse_function_should_fail(""" -module foo -foo.bar - *vararg1: object - *vararg2: object -""") - self.assertEqual(s, "Error on line 0:\nToo many var args\n") + expected_msg = ( + "Error on line 0:\n" + "Too many var args\n" + ) + out = self.parse_function_should_fail(""" + module foo + foo.bar + *vararg1: object + *vararg2: object + """) + self.assertEqual(out, expected_msg) def test_function_not_at_column_0(self): function = self.parse_function(""" - module foo - foo.bar - x: int - Nested docstring here, goeth. - * - y: str - Not at column 0! -""") - self.assertEqual(""" -bar($module, /, x, *, y) --- + module foo + foo.bar + x: int + Nested docstring here, goeth. + * + y: str + Not at column 0! + """) + self.checkDocstring(function, """ + bar($module, /, x, *, y) + -- -Not at column 0! + Not at column 0! - x - Nested docstring here, goeth. -""".strip(), function.docstring) + x + Nested docstring here, goeth. + """) def test_directive(self): c = FakeClinic() @@ -772,46 +857,39 @@ def test_directive(self): def test_legacy_converters(self): block = self.parse('module os\nos.access\n path: "s"') module, function = block.signatures - self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter) + conv = (function.parameters['path']).converter + self.assertIsInstance(conv, clinic.str_converter) def test_legacy_converters_non_string_constant_annotation(self): - expected_failure_message = """\ -Error on line 0: -Annotations must be either a name, a function call, or a string. -""" - - s = self.parse_function_should_fail('module os\nos.access\n path: 42') - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail('module os\nos.access\n path: 42.42') - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail('module os\nos.access\n path: 42j') - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail('module os\nos.access\n path: b"42"') - self.assertEqual(s, expected_failure_message) - - def test_other_bizarre_things_in_annotations_fail(self): - expected_failure_message = """\ -Error on line 0: -Annotations must be either a name, a function call, or a string. -""" - - s = self.parse_function_should_fail( - 'module os\nos.access\n path: {"some": "dictionary"}' + expected_failure_message = ( + "Error on line 0:\n" + "Annotations must be either a name, a function call, or a string.\n" ) - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail( - 'module os\nos.access\n path: ["list", "of", "strings"]' + dataset = ( + 'module os\nos.access\n path: 42', + 'module os\nos.access\n path: 42.42', + 'module os\nos.access\n path: 42j', + 'module os\nos.access\n path: b"42"', ) - self.assertEqual(s, expected_failure_message) + for block in dataset: + with self.subTest(block=block): + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_failure_message) - s = self.parse_function_should_fail( - 'module os\nos.access\n path: (x for x in range(42))' + def test_other_bizarre_things_in_annotations_fail(self): + expected_failure_message = ( + "Error on line 0:\n" + "Annotations must be either a name, a function call, or a string.\n" + ) + dataset = ( + 'module os\nos.access\n path: {"some": "dictionary"}', + 'module os\nos.access\n path: ["list", "of", "strings"]', + 'module os\nos.access\n path: (x for x in range(42))', ) - self.assertEqual(s, expected_failure_message) + for block in dataset: + with self.subTest(block=block): + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_failure_message) def test_kwarg_splats_disallowed_in_function_call_annotations(self): expected_error_msg = ( @@ -945,10 +1023,16 @@ def test_scaffolding(self): self.assertEqual(repr(clinic.NULL), '') # test that fail fails + expected = ( + 'Error in file "clown.txt" on line 69:\n' + 'The igloos are melting!\n' + ) with support.captured_stdout() as stdout: with self.assertRaises(SystemExit): - clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69) - self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n') + clinic.fail('The igloos are melting!', + filename='clown.txt', line_number=69) + actual = stdout.getvalue() + self.assertEqual(actual, expected) class ClinicExternalTest(TestCase): From 6720003dae318c417687a8d8b1ecf54b7cad6554 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 3 Jul 2023 16:37:47 -0700 Subject: [PATCH 0299/1206] [3.12] gh-106368: Harden Argument Clinic parser tests (GH-106384) (#106387) (cherry picked from commit 648688c137744a623a71dc2413d2879b80c99eae) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 110 +++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 42 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index b3602887ab6352..c5cfe53e0df99b 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -643,7 +643,7 @@ def test_disallowed_grouping__two_top_groups_on_left(self): self.assertEqual(out, expected_msg) def test_disallowed_grouping__two_top_groups_on_right(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.two_top_groups_on_right param: int @@ -654,9 +654,14 @@ def test_disallowed_grouping__two_top_groups_on_right(self): group2 : int ] """) + msg = ( + "Function two_top_groups_on_right has an unsupported group " + "configuration. (Unexpected state 6.b)" + ) + self.assertIn(msg, out) def test_disallowed_grouping__parameter_after_group_on_right(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.parameter_after_group_on_right param: int @@ -667,9 +672,14 @@ def test_disallowed_grouping__parameter_after_group_on_right(self): group2 : int ] """) + msg = ( + "Function parameter_after_group_on_right has an unsupported group " + "configuration. (Unexpected state 6.a)" + ) + self.assertIn(msg, out) def test_disallowed_grouping__group_after_parameter_on_left(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.group_after_parameter_on_left [ @@ -680,9 +690,14 @@ def test_disallowed_grouping__group_after_parameter_on_left(self): ] param: int """) + msg = ( + "Function group_after_parameter_on_left has an unsupported group " + "configuration. (Unexpected state 2.b)" + ) + self.assertIn(msg, out) def test_disallowed_grouping__empty_group_on_left(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.empty_group [ @@ -692,9 +707,14 @@ def test_disallowed_grouping__empty_group_on_left(self): ] param: int """) + msg = ( + "Function empty_group has an empty group.\n" + "All groups must contain at least one parameter." + ) + self.assertIn(msg, out) def test_disallowed_grouping__empty_group_on_right(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.empty_group param: int @@ -704,6 +724,11 @@ def test_disallowed_grouping__empty_group_on_right(self): group2 : int ] """) + msg = ( + "Function empty_group has an empty group.\n" + "All groups must contain at least one parameter." + ) + self.assertIn(msg, out) def test_no_parameters(self): function = self.parse_function(""" @@ -732,69 +757,60 @@ class foo.Bar "unused" "notneeded" self.assertEqual(1, len(function.parameters)) def test_illegal_module_line(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar => int / """) + msg = "Illegal function name: foo.bar => int" + self.assertIn(msg, out) def test_illegal_c_basename(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar as 935 / """) + msg = "Illegal C basename: 935" + self.assertIn(msg, out) def test_single_star(self): - self.parse_function_should_fail(""" - module foo - foo.bar - * - * - """) - - def test_parameters_required_after_star_without_initial_parameters_or_docstring(self): - self.parse_function_should_fail(""" - module foo - foo.bar - * - """) - - def test_parameters_required_after_star_without_initial_parameters_with_docstring(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar * - Docstring here. - """) - - def test_parameters_required_after_star_with_initial_parameters_without_docstring(self): - self.parse_function_should_fail(""" - module foo - foo.bar - this: int * """) + self.assertIn("Function bar uses '*' more than once.", out) - def test_parameters_required_after_star_with_initial_parameters_and_docstring(self): - self.parse_function_should_fail(""" - module foo - foo.bar - this: int - * - Docstring. - """) + def test_parameters_required_after_star(self): + dataset = ( + "module foo\nfoo.bar\n *", + "module foo\nfoo.bar\n *\nDocstring here.", + "module foo\nfoo.bar\n this: int\n *", + "module foo\nfoo.bar\n this: int\n *\nDocstring.", + ) + msg = "Function bar specifies '*' without any parameters afterwards." + for block in dataset: + with self.subTest(block=block): + out = self.parse_function_should_fail(block) + self.assertIn(msg, out) def test_single_slash(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar / / """) + msg = ( + "Function bar has an unsupported group configuration. " + "(Unexpected state 0.d)" + ) + self.assertIn(msg, out) def test_mix_star_and_slash(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar x: int @@ -803,14 +819,24 @@ def test_mix_star_and_slash(self): z: int / """) + msg = ( + "Function bar mixes keyword-only and positional-only parameters, " + "which is unsupported." + ) + self.assertIn(msg, out) def test_parameters_not_permitted_after_slash_for_now(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar / x: int """) + msg = ( + "Function bar has an unsupported group configuration. " + "(Unexpected state 0.d)" + ) + self.assertIn(msg, out) def test_parameters_no_more_than_one_vararg(self): expected_msg = ( From b84365fe3eaa52bac8ffa7369ad0496a807aa8a7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:26:44 -0700 Subject: [PATCH 0300/1206] [3.12] gh-106368: Increase Argument Clinic test coverage (GH-106389) (#106390) Add: - test_disallowed_gropuing__no_matching_bracket - test_double_slash (cherry picked from commit 3406f8cce542ea4edf4153c0fac5216df283a9b1) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index c5cfe53e0df99b..03754d0bf123be 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -730,6 +730,18 @@ def test_disallowed_grouping__empty_group_on_right(self): ) self.assertIn(msg, out) + def test_disallowed_grouping__no_matching_bracket(self): + out = self.parse_function_should_fail(""" + module foo + foo.empty_group + param: int + ] + group2: int + ] + """) + msg = "Function empty_group has a ] without a matching [." + self.assertIn(msg, out) + def test_no_parameters(self): function = self.parse_function(""" module foo @@ -809,6 +821,18 @@ def test_single_slash(self): ) self.assertIn(msg, out) + def test_double_slash(self): + out = self.parse_function_should_fail(""" + module foo + foo.bar + a: int + / + b: int + / + """) + msg = "Function bar uses '/' more than once." + self.assertIn(msg, out) + def test_mix_star_and_slash(self): out = self.parse_function_should_fail(""" module foo From fda297031bba7c4e46b5959ebaa9c48ca11bb5f4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 4 Jul 2023 05:17:05 -0700 Subject: [PATCH 0301/1206] [3.12] gh-106368: Add tests for permutation helpers in Argument Clinic (GH-106407) (#106409) Added new test class PermutationTests() (cherry picked from commit 8f6df5e9cbc3a1689601714192aa6ecbb23e1927) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 106 ++++++++++++++++++++++++++++++++++++++++ Tools/clinic/clinic.py | 4 +- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 03754d0bf123be..544e7323e4f606 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1586,5 +1586,111 @@ def test_cloned_func_with_converter_exception_message(self): self.assertEqual(func(), name) +class PermutationTests(unittest.TestCase): + """Test permutation support functions.""" + + def test_permute_left_option_groups(self): + expected = ( + (), + (3,), + (2, 3), + (1, 2, 3), + ) + data = list(zip([1, 2, 3])) # Generate a list of 1-tuples. + actual = tuple(clinic.permute_left_option_groups(data)) + self.assertEqual(actual, expected) + + def test_permute_right_option_groups(self): + expected = ( + (), + (1,), + (1, 2), + (1, 2, 3), + ) + data = list(zip([1, 2, 3])) # Generate a list of 1-tuples. + actual = tuple(clinic.permute_right_option_groups(data)) + self.assertEqual(actual, expected) + + def test_permute_optional_groups(self): + empty = { + "left": (), "required": (), "right": (), + "expected": ((),), + } + noleft1 = { + "left": (), "required": ("b",), "right": ("c",), + "expected": ( + ("b",), + ("b", "c"), + ), + } + noleft2 = { + "left": (), "required": ("b", "c",), "right": ("d",), + "expected": ( + ("b", "c"), + ("b", "c", "d"), + ), + } + noleft3 = { + "left": (), "required": ("b", "c",), "right": ("d", "e"), + "expected": ( + ("b", "c"), + ("b", "c", "d"), + ("b", "c", "d", "e"), + ), + } + noright1 = { + "left": ("a",), "required": ("b",), "right": (), + "expected": ( + ("b",), + ("a", "b"), + ), + } + noright2 = { + "left": ("a",), "required": ("b", "c"), "right": (), + "expected": ( + ("b", "c"), + ("a", "b", "c"), + ), + } + noright3 = { + "left": ("a", "b"), "required": ("c",), "right": (), + "expected": ( + ("c",), + ("b", "c"), + ("a", "b", "c"), + ), + } + leftandright1 = { + "left": ("a",), "required": ("b",), "right": ("c",), + "expected": ( + ("b",), + ("a", "b"), # Prefer left. + ("a", "b", "c"), + ), + } + leftandright2 = { + "left": ("a", "b"), "required": ("c", "d"), "right": ("e", "f"), + "expected": ( + ("c", "d"), + ("b", "c", "d"), # Prefer left. + ("a", "b", "c", "d"), # Prefer left. + ("a", "b", "c", "d", "e"), + ("a", "b", "c", "d", "e", "f"), + ), + } + dataset = ( + empty, + noleft1, noleft2, noleft3, + noright1, noright2, noright3, + leftandright1, leftandright2, + ) + for params in dataset: + with self.subTest(**params): + left, required, right, expected = params.values() + permutations = clinic.permute_optional_groups(left, required, right) + actual = tuple(permutations) + self.assertEqual(actual, expected) + + if __name__ == "__main__": unittest.main() diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index d67479c7f8ab88..fa6c1392e1f092 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -509,7 +509,7 @@ class PythonLanguage(Language): def permute_left_option_groups(l): """ - Given [1, 2, 3], should yield: + Given [(1,), (2,), (3,)], should yield: () (3,) (2, 3) @@ -524,7 +524,7 @@ def permute_left_option_groups(l): def permute_right_option_groups(l): """ - Given [1, 2, 3], should yield: + Given [(1,), (2,), (3,)], should yield: () (1,) (1, 2) From 930df7b07e774636ad200a62a7b4b56564f502b0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 4 Jul 2023 06:00:47 -0700 Subject: [PATCH 0302/1206] [3.12] gh-106396: Special-case empty format spec to gen empty JoinedStr node (GH-106401) (#106416) (cherry picked from commit dfe4de203881e8d068e6fc5b8e31075841a86d25) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_fstring.py | 18 ++++++++++++++++++ ...3-07-04-09-51-45.gh-issue-106396.DmYp7x.rst | 3 +++ Parser/action_helpers.c | 12 ++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index ba223ae124a8fb..cb14bba2602def 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -496,6 +496,24 @@ def test_ast_line_numbers_with_parentheses(self): self.assertEqual(wat2.end_col_offset, 17) self.assertEqual(fstring.end_col_offset, 18) + def test_ast_fstring_empty_format_spec(self): + expr = "f'{expr:}'" + + mod = ast.parse(expr) + self.assertEqual(type(mod), ast.Module) + self.assertEqual(len(mod.body), 1) + + fstring = mod.body[0].value + self.assertEqual(type(fstring), ast.JoinedStr) + self.assertEqual(len(fstring.values), 1) + + fv = fstring.values[0] + self.assertEqual(type(fv), ast.FormattedValue) + + format_spec = fv.format_spec + self.assertEqual(type(format_spec), ast.JoinedStr) + self.assertEqual(len(format_spec.values), 0) + def test_docstring(self): def f(): f'''Not a docstring''' diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst new file mode 100644 index 00000000000000..c5767e97271d9d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst @@ -0,0 +1,3 @@ +When the format specification of an f-string expression is empty, the parser now +generates an empty :class:`ast.JoinedStr` node for it instead of an one-element +:class:`ast.JoinedStr` with an empty string :class:`ast.Constant`. diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index dbad56b5164b6f..e68a9cac25908c 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1003,6 +1003,18 @@ _PyPegen_setup_full_format_spec(Parser *p, Token *colon, asdl_expr_seq *spec, in if (!spec) { return NULL; } + + // This is needed to keep compatibility with 3.11, where an empty format spec is parsed + // as an *empty* JoinedStr node, instead of having an empty constant in it. + if (asdl_seq_LEN(spec) == 1) { + expr_ty e = asdl_seq_GET(spec, 0); + if (e->kind == Constant_kind + && PyUnicode_Check(e->v.Constant.value) + && PyUnicode_GetLength(e->v.Constant.value) == 0) { + spec = _Py_asdl_expr_seq_new(0, arena); + } + } + expr_ty res = _PyAST_JoinedStr(spec, lineno, col_offset, end_lineno, end_col_offset, p->arena); if (!res) { return NULL; From d5ed72b696f2d26d85f3599abf0693545a1ac4e2 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Tue, 4 Jul 2023 21:51:36 +0100 Subject: [PATCH 0303/1206] [3.12] GH-106330: Fix matching of empty path in `pathlib.PurePath.match()` (GH-106331) (GH-106372) We match paths using the `_lines` attribute, which is derived from the path's string representation. The bug arises because an empty path's string representation is `'.'` (not `''`), which is matched by the `'*'` wildcard. (cherry picked from commit b4efdf8cda8fbbd0ca53b457d5f6e46a59348caf) --- Lib/pathlib.py | 27 +++++++++++++------ Lib/test/test_pathlib.py | 4 +++ ...-07-02-10-56-41.gh-issue-106330.QSkIUH.rst | 2 ++ 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index d279fd2958b170..b99bf6e7dd2408 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -127,12 +127,19 @@ def _compile_pattern_lines(pattern_lines, case_sensitive): # Match the start of the path, or just after a path separator parts = ['^'] for part in pattern_lines.splitlines(keepends=True): - # We slice off the common prefix and suffix added by translate() to - # ensure that re.DOTALL is not set, and the end of the string not - # matched, respectively. With DOTALL not set, '*' wildcards will not - # match path separators, because the '.' characters in the pattern - # will not match newlines. - parts.append(fnmatch.translate(part)[_FNMATCH_SLICE]) + if part == '*\n': + part = r'.+\n' + elif part == '*': + part = r'.+' + else: + # Any other component: pass to fnmatch.translate(). We slice off + # the common prefix and suffix added by translate() to ensure that + # re.DOTALL is not set, and the end of the string not matched, + # respectively. With DOTALL not set, '*' wildcards will not match + # path separators, because the '.' characters in the pattern will + # not match newlines. + part = fnmatch.translate(part)[_FNMATCH_SLICE] + parts.append(part) # Match the end of the path, always. parts.append(r'\Z') flags = re.MULTILINE @@ -501,8 +508,12 @@ def _lines(self): try: return self._lines_cached except AttributeError: - trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep] - self._lines_cached = str(self).translate(trans) + path_str = str(self) + if path_str == '.': + self._lines_cached = '' + else: + trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep] + self._lines_cached = path_str.translate(trans) return self._lines_cached def __eq__(self, other): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index f716f1075bcb3e..1d28a782f44ab3 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -317,6 +317,10 @@ def test_match_common(self): self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) + # Matching against empty path + self.assertFalse(P().match('*')) + self.assertTrue(P().match('**')) + self.assertFalse(P().match('**/*')) def test_ordering_common(self): # Ordering is tuple-alike. diff --git a/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst b/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst new file mode 100644 index 00000000000000..c1f55ab658b517 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst @@ -0,0 +1,2 @@ +Fix incorrect matching of empty paths in :meth:`pathlib.PurePath.match`. +This bug was introduced in Python 3.12.0 beta 1. From 6f684044a98f3ae26f15c2de5bd61a30927eddf0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:00:32 -0700 Subject: [PATCH 0304/1206] [3.12] gh-106368: Add tests for formatting helpers in Argument Clinic (GH-106415) (#106438) gh-106368: Add tests for formatting helpers in Argument Clinic (GH-106415) (cherry picked from commit 2fb9480c8313ab524d333b18e4af09f05f5b8afa) Co-authored-by: Erlend E. Aasland Co-authored-by: Alex Waygood --- Lib/test/test_clinic.py | 164 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 544e7323e4f606..c095d14234375f 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1692,5 +1692,169 @@ def test_permute_optional_groups(self): self.assertEqual(actual, expected) +class FormatHelperTests(unittest.TestCase): + + def test_strip_leading_and_trailing_blank_lines(self): + dataset = ( + # Input lines, expected output. + ("a\nb", "a\nb"), + ("a\nb\n", "a\nb"), + ("a\nb ", "a\nb"), + ("\na\nb\n\n", "a\nb"), + ("\n\na\nb\n\n", "a\nb"), + ("\n\na\n\nb\n\n", "a\n\nb"), + # Note, leading whitespace is preserved: + (" a\nb", " a\nb"), + (" a\nb ", " a\nb"), + (" \n \n a\nb \n \n ", " a\nb"), + ) + for lines, expected in dataset: + with self.subTest(lines=lines, expected=expected): + out = clinic.strip_leading_and_trailing_blank_lines(lines) + self.assertEqual(out, expected) + + def test_normalize_snippet(self): + snippet = """ + one + two + three + """ + + # Expected outputs: + zero_indent = ( + "one\n" + "two\n" + "three" + ) + four_indent = ( + " one\n" + " two\n" + " three" + ) + eight_indent = ( + " one\n" + " two\n" + " three" + ) + expected_outputs = {0: zero_indent, 4: four_indent, 8: eight_indent} + for indent, expected in expected_outputs.items(): + with self.subTest(indent=indent): + actual = clinic.normalize_snippet(snippet, indent=indent) + self.assertEqual(actual, expected) + + def test_accumulator(self): + acc = clinic.text_accumulator() + self.assertEqual(acc.output(), "") + acc.append("a") + self.assertEqual(acc.output(), "a") + self.assertEqual(acc.output(), "") + acc.append("b") + self.assertEqual(acc.output(), "b") + self.assertEqual(acc.output(), "") + acc.append("c") + acc.append("d") + self.assertEqual(acc.output(), "cd") + self.assertEqual(acc.output(), "") + + def test_quoted_for_c_string(self): + dataset = ( + # input, expected + (r"abc", r"abc"), + (r"\abc", r"\\abc"), + (r"\a\bc", r"\\a\\bc"), + (r"\a\\bc", r"\\a\\\\bc"), + (r'"abc"', r'\"abc\"'), + (r"'a'", r"\'a\'"), + ) + for line, expected in dataset: + with self.subTest(line=line, expected=expected): + out = clinic.quoted_for_c_string(line) + self.assertEqual(out, expected) + + def test_rstrip_lines(self): + lines = ( + "a \n" + "b\n" + " c\n" + " d \n" + ) + expected = ( + "a\n" + "b\n" + " c\n" + " d\n" + ) + out = clinic.rstrip_lines(lines) + self.assertEqual(out, expected) + + def test_format_escape(self): + line = "{}, {a}" + expected = "{{}}, {{a}}" + out = clinic.format_escape(line) + self.assertEqual(out, expected) + + def test_indent_all_lines(self): + # Blank lines are expected to be unchanged. + self.assertEqual(clinic.indent_all_lines("", prefix="bar"), "") + + lines = ( + "one\n" + "two" # The missing newline is deliberate. + ) + expected = ( + "barone\n" + "bartwo" + ) + out = clinic.indent_all_lines(lines, prefix="bar") + self.assertEqual(out, expected) + + # If last line is empty, expect it to be unchanged. + lines = ( + "\n" + "one\n" + "two\n" + "" + ) + expected = ( + "bar\n" + "barone\n" + "bartwo\n" + "" + ) + out = clinic.indent_all_lines(lines, prefix="bar") + self.assertEqual(out, expected) + + def test_suffix_all_lines(self): + # Blank lines are expected to be unchanged. + self.assertEqual(clinic.suffix_all_lines("", suffix="foo"), "") + + lines = ( + "one\n" + "two" # The missing newline is deliberate. + ) + expected = ( + "onefoo\n" + "twofoo" + ) + out = clinic.suffix_all_lines(lines, suffix="foo") + self.assertEqual(out, expected) + + # If last line is empty, expect it to be unchanged. + lines = ( + "\n" + "one\n" + "two\n" + "" + ) + expected = ( + "foo\n" + "onefoo\n" + "twofoo\n" + "" + ) + out = clinic.suffix_all_lines(lines, suffix="foo") + self.assertEqual(out, expected) + + if __name__ == "__main__": unittest.main() From 5784acd08c89d91f616faba3a0b7b88e0ba4ce67 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 4 Jul 2023 23:12:47 -0700 Subject: [PATCH 0305/1206] [3.12] tp_flags docs: fix indentation (GH-106420) (#106442) Co-authored-by: Jelle Zijlstra --- Doc/c-api/typeobj.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index c6e783acdf0654..239c191457f516 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1143,14 +1143,14 @@ and :c:type:`PyType_Type` effectively act as defaults.) :const:`Py_TPFLAGS_IMMUTABLETYPE` flag set. For extension types, it is inherited whenever :c:member:`~PyTypeObject.tp_descr_get` is inherited. - .. data:: Py_TPFLAGS_MANAGED_DICT + .. data:: Py_TPFLAGS_MANAGED_DICT - This bit indicates that instances of the class have a ``__dict__`` - attribute, and that the space for the dictionary is managed by the VM. + This bit indicates that instances of the class have a ``__dict__`` + attribute, and that the space for the dictionary is managed by the VM. - If this flag is set, :const:`Py_TPFLAGS_HAVE_GC` should also be set. + If this flag is set, :const:`Py_TPFLAGS_HAVE_GC` should also be set. - .. versionadded:: 3.12 + .. versionadded:: 3.12 **Inheritance:** @@ -1158,12 +1158,12 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:member:`~PyTypeObject.tp_dictoffset` field is set in a superclass. - .. data:: Py_TPFLAGS_MANAGED_WEAKREF + .. data:: Py_TPFLAGS_MANAGED_WEAKREF - This bit indicates that instances of the class should be weakly - referenceable. + This bit indicates that instances of the class should be weakly + referenceable. - .. versionadded:: 3.12 + .. versionadded:: 3.12 **Inheritance:** From 00c522a81c726f3a15b16ae67bba4840431afdaf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 01:57:59 -0700 Subject: [PATCH 0306/1206] [3.12] gh-104683: Rename Lib/test/clinic.test as Lib/test/clinic.test.c (GH-106443) (#106444) gh-104683: Rename Lib/test/clinic.test as Lib/test/clinic.test.c (GH-106443) (cherry picked from commit a941bd6c53ac4646926292557a7bb2a86f8025c3) Co-authored-by: Erlend E. Aasland --- Lib/test/{clinic.test => clinic.test.c} | 0 Lib/test/test_clinic.py | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename Lib/test/{clinic.test => clinic.test.c} (100%) diff --git a/Lib/test/clinic.test b/Lib/test/clinic.test.c similarity index 100% rename from Lib/test/clinic.test rename to Lib/test/clinic.test.c diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index c095d14234375f..7c46e8a81803a2 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1089,15 +1089,16 @@ class ClinicExternalTest(TestCase): maxDiff = None def test_external(self): + CLINIC_TEST = 'clinic.test.c' # bpo-42398: Test that the destination file is left unchanged if the # content does not change. Moreover, check also that the file # modification time does not change in this case. - source = support.findfile('clinic.test') + source = support.findfile(CLINIC_TEST) with open(source, 'r', encoding='utf-8') as f: orig_contents = f.read() with os_helper.temp_dir() as tmp_dir: - testfile = os.path.join(tmp_dir, 'clinic.test.c') + testfile = os.path.join(tmp_dir, CLINIC_TEST) with open(testfile, 'w', encoding='utf-8') as f: f.write(orig_contents) old_mtime_ns = os.stat(testfile).st_mtime_ns From 637102980d12e5ff99b69ddffd5f05ecfe0adeb6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 02:42:47 -0700 Subject: [PATCH 0307/1206] [3.12] gh-100238: Use setuptools in peg-generator and reenable tests (GH-104798) (#105135) (cherry picked from commit afa759fb800be416f69e3e9c9b3efe68006316f5) Co-authored-by: Lysandros Nikolaou --- Lib/test/support/__init__.py | 7 +-- Lib/test/test_peg_generator/__init__.py | 3 -- Lib/test/test_peg_generator/test_c_parser.py | 14 ++++- Lib/test/test_peg_generator/test_pegen.py | 2 +- Tools/peg_generator/pegen/build.py | 54 +++++++++++++++++--- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index c59508b40d3203..3f1cc3a083a1c7 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1868,15 +1868,16 @@ def missing_compiler_executable(cmd_names=[]): missing. """ - # TODO (PEP 632): alternate check without using distutils - from distutils import ccompiler, sysconfig, spawn, errors + from setuptools._distutils import ccompiler, sysconfig, spawn + from setuptools import errors + compiler = ccompiler.new_compiler() sysconfig.customize_compiler(compiler) if compiler.compiler_type == "msvc": # MSVC has no executables, so check whether initialization succeeds try: compiler.initialize() - except errors.DistutilsPlatformError: + except errors.PlatformError: return "msvc" for name in compiler.executables: if cmd_names and name not in cmd_names: diff --git a/Lib/test/test_peg_generator/__init__.py b/Lib/test/test_peg_generator/__init__.py index 7c402c3d7c5acf..77f72fcc7c6e3b 100644 --- a/Lib/test/test_peg_generator/__init__.py +++ b/Lib/test/test_peg_generator/__init__.py @@ -3,9 +3,6 @@ from test import support from test.support import load_package_tests -# TODO: gh-92584: peg_generator uses distutils which was removed in Python 3.12 -raise unittest.SkipTest("distutils has been removed in Python 3.12") - if support.check_sanitizer(address=True, memory=True): # bpo-46633: Skip the test because it is too slow when Python is built diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index d34ffef0dbc5ec..af39faeba94357 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -1,3 +1,5 @@ +import contextlib +import subprocess import sysconfig import textwrap import unittest @@ -8,7 +10,7 @@ from test import test_tools from test import support -from test.support import os_helper +from test.support import os_helper, import_helper from test.support.script_helper import assert_python_ok _py_cflags_nodist = sysconfig.get_config_var("PY_CFLAGS_NODIST") @@ -88,6 +90,16 @@ def setUpClass(cls): cls.library_dir = tempfile.mkdtemp(dir=cls.tmp_base) cls.addClassCleanup(shutil.rmtree, cls.library_dir) + with contextlib.ExitStack() as stack: + python_exe = stack.enter_context(support.setup_venv_with_pip_setuptools_wheel("venv")) + sitepackages = subprocess.check_output( + [python_exe, "-c", "import sysconfig; print(sysconfig.get_path('platlib'))"], + text=True, + ).strip() + stack.enter_context(import_helper.DirsOnSysPath(sitepackages)) + cls.addClassCleanup(stack.pop_all().close) + + @support.requires_venv_with_pip() def setUp(self): self._backup_config_vars = dict(sysconfig._CONFIG_VARS) cmd = support.missing_compiler_executable() diff --git a/Lib/test/test_peg_generator/test_pegen.py b/Lib/test/test_peg_generator/test_pegen.py index 30e992ed213c67..d92da7b29bff98 100644 --- a/Lib/test/test_peg_generator/test_pegen.py +++ b/Lib/test/test_peg_generator/test_pegen.py @@ -794,7 +794,7 @@ def test_soft_keyword(self) -> None: start: | "number" n=NUMBER { eval(n.string) } | "string" n=STRING { n.string } - | SOFT_KEYWORD l=NAME n=(NUMBER | NAME | STRING) { f"{l.string} = {n.string}"} + | SOFT_KEYWORD l=NAME n=(NUMBER | NAME | STRING) { l.string + " = " + n.string } """ parser_class = make_parser(grammar) self.assertEqual(parse_string("number 1", parser_class), 1) diff --git a/Tools/peg_generator/pegen/build.py b/Tools/peg_generator/pegen/build.py index 5805ff63717440..aace684045b9f8 100644 --- a/Tools/peg_generator/pegen/build.py +++ b/Tools/peg_generator/pegen/build.py @@ -1,4 +1,5 @@ import itertools +import os import pathlib import sys import sysconfig @@ -27,6 +28,46 @@ def get_extra_flags(compiler_flags: str, compiler_py_flags_nodist: str) -> List[ return f"{flags} {py_flags_nodist}".split() +def fixup_build_ext(cmd): + """Function needed to make build_ext tests pass. + + When Python was built with --enable-shared on Unix, -L. is not enough to + find libpython.so, because regrtest runs in a tempdir, not in the + source directory where the .so lives. + + When Python was built with in debug mode on Windows, build_ext commands + need their debug attribute set, and it is not done automatically for + some reason. + + This function handles both of these things. Example use: + + cmd = build_ext(dist) + support.fixup_build_ext(cmd) + cmd.ensure_finalized() + + Unlike most other Unix platforms, Mac OS X embeds absolute paths + to shared libraries into executables, so the fixup is not needed there. + + Taken from distutils (was part of the CPython stdlib until Python 3.11) + """ + if os.name == 'nt': + cmd.debug = sys.executable.endswith('_d.exe') + elif sysconfig.get_config_var('Py_ENABLE_SHARED'): + # To further add to the shared builds fun on Unix, we can't just add + # library_dirs to the Extension() instance because that doesn't get + # plumbed through to the final compiler command. + runshared = sysconfig.get_config_var('RUNSHARED') + if runshared is None: + cmd.library_dirs = ['.'] + else: + if sys.platform == 'darwin': + cmd.library_dirs = [] + else: + name, equals, value = runshared.partition('=') + cmd.library_dirs = [d for d in value.split(os.pathsep) if d] + + + def compile_c_extension( generated_source_path: str, build_dir: Optional[str] = None, @@ -49,16 +90,15 @@ def compile_c_extension( static library of the common parser sources (this is useful in case you are creating multiple extensions). """ - import distutils.log - from distutils.core import Distribution, Extension - from distutils.tests.support import fixup_build_ext # type: ignore + import setuptools.logging - from distutils.ccompiler import new_compiler - from distutils.dep_util import newer_group - from distutils.sysconfig import customize_compiler + from setuptools import Extension, Distribution + from setuptools._distutils.dep_util import newer_group + from setuptools._distutils.ccompiler import new_compiler + from setuptools._distutils.sysconfig import customize_compiler if verbose: - distutils.log.set_threshold(distutils.log.DEBUG) + setuptools.logging.set_threshold(setuptools.logging.logging.DEBUG) source_file_path = pathlib.Path(generated_source_path) extension_name = source_file_path.stem From 2edec6ad9f6cbce217427e2352e577a7a83cd774 Mon Sep 17 00:00:00 2001 From: Jeffery To Date: Wed, 5 Jul 2023 18:51:16 +0800 Subject: [PATCH 0308/1206] [3.12] gh-104692: Include commoninstall as a prerequisite for bininstall (GH-104693) (#105428) This ensures that `commoninstall` is completed before `bininstall` is started when parallel builds are used (`make -j install`), and so the `python3` symlink is only installed after all standard library modules are installed. (cherry picked from commit 990cb3676c2edb7e5787372d6cbe360a73367f4c) --- Makefile.pre.in | 6 +++++- .../Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst diff --git a/Makefile.pre.in b/Makefile.pre.in index e2adc3cb49f2a9..12788d11d1d145 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2014,7 +2014,11 @@ altbininstall: $(BUILDPYTHON) @FRAMEWORKPYTHONW@ fi .PHONY: bininstall -bininstall: altbininstall +# We depend on commoninstall here to make sure the installation is already usable +# before we possibly overwrite the global 'python3' symlink to avoid causing +# problems for anything else trying to run 'python3' while we install, particularly +# if we're installing in parallel with -j. +bininstall: commoninstall altbininstall if test ! -d $(DESTDIR)$(LIBPC); then \ echo "Creating directory $(LIBPC)"; \ $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(LIBPC); \ diff --git a/Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst b/Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst new file mode 100644 index 00000000000000..2936990999e1aa --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst @@ -0,0 +1,6 @@ +Include ``commoninstall`` as a prerequisite for ``bininstall`` + +This ensures that ``commoninstall`` is completed before ``bininstall`` +is started when parallel builds are used (``make -j install``), and so +the ``python3`` symlink is only installed after all standard library +modules are installed. From 334b95b2434880e6138d430054c3054266e6020f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 03:52:16 -0700 Subject: [PATCH 0309/1206] [3.12] gh-89392: Make test_decimal discoverable (GH-106209) (#106230) gh-89392: Make test_decimal discoverable (GH-106209) (cherry picked from commit 0e24499129f3917b199a6d46fa33eeedd2c447fc) Co-authored-by: Serhiy Storchaka --- Lib/test/test_decimal.py | 279 ++++++++++++++++++++------------------- 1 file changed, 146 insertions(+), 133 deletions(-) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 67ccaab40c5edc..749496e3e9455e 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -20,7 +20,7 @@ This test module can be called from command line with one parameter (Arithmetic or Behaviour) to test each part, or without parameter to test both parts. If -you're working through IDLE, you can import this test module and call test_main() +you're working through IDLE, you can import this test module and call test() with the corresponding argument. """ @@ -32,7 +32,7 @@ import unittest import numbers import locale -from test.support import (run_unittest, run_doctest, is_resource_enabled, +from test.support import (is_resource_enabled, requires_IEEE_754, requires_docstrings, requires_legacy_unicode_capi, check_sanitizer) from test.support import (TestFailed, @@ -62,6 +62,7 @@ fractions = {C:cfractions, P:pfractions} sys.modules['decimal'] = orig_sys_decimal +requires_cdecimal = unittest.skipUnless(C, "test requires C version") # Useful Test Constant Signals = { @@ -99,7 +100,7 @@ def assert_signals(cls, context, attr, expected): ] # Tests are built around these assumed context defaults. -# test_main() restores the original context. +# test() restores the original context. ORIGINAL_CONTEXT = { C: C.getcontext().copy() if C else None, P: P.getcontext().copy() @@ -133,7 +134,7 @@ def init(m): EXTRA_FUNCTIONALITY, "test requires regular build") -class IBMTestCases(unittest.TestCase): +class IBMTestCases: """Class which tests the Decimal class against the IBM test cases.""" def setUp(self): @@ -488,14 +489,10 @@ def change_max_exponent(self, exp): def change_clamp(self, clamp): self.context.clamp = clamp -class CIBMTestCases(IBMTestCases): - decimal = C -class PyIBMTestCases(IBMTestCases): - decimal = P # The following classes test the behaviour of Decimal according to PEP 327 -class ExplicitConstructionTest(unittest.TestCase): +class ExplicitConstructionTest: '''Unit tests for Explicit Construction cases of Decimal.''' def test_explicit_empty(self): @@ -838,12 +835,13 @@ def test_unicode_digits(self): for input, expected in test_values.items(): self.assertEqual(str(Decimal(input)), expected) -class CExplicitConstructionTest(ExplicitConstructionTest): +@requires_cdecimal +class CExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase): decimal = C -class PyExplicitConstructionTest(ExplicitConstructionTest): +class PyExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase): decimal = P -class ImplicitConstructionTest(unittest.TestCase): +class ImplicitConstructionTest: '''Unit tests for Implicit Construction cases of Decimal.''' def test_implicit_from_None(self): @@ -920,12 +918,13 @@ def __ne__(self, other): self.assertEqual(eval('Decimal(10)' + sym + 'E()'), '10' + rop + 'str') -class CImplicitConstructionTest(ImplicitConstructionTest): +@requires_cdecimal +class CImplicitConstructionTest(ImplicitConstructionTest, unittest.TestCase): decimal = C -class PyImplicitConstructionTest(ImplicitConstructionTest): +class PyImplicitConstructionTest(ImplicitConstructionTest, unittest.TestCase): decimal = P -class FormatTest(unittest.TestCase): +class FormatTest: '''Unit tests for the format function.''' def test_formatting(self): Decimal = self.decimal.Decimal @@ -1262,12 +1261,13 @@ def __init__(self, a): a = A.from_float(42) self.assertEqual(self.decimal.Decimal, a.a_type) -class CFormatTest(FormatTest): +@requires_cdecimal +class CFormatTest(FormatTest, unittest.TestCase): decimal = C -class PyFormatTest(FormatTest): +class PyFormatTest(FormatTest, unittest.TestCase): decimal = P -class ArithmeticOperatorsTest(unittest.TestCase): +class ArithmeticOperatorsTest: '''Unit tests for all arithmetic operators, binary and unary.''' def test_addition(self): @@ -1523,14 +1523,17 @@ def test_nan_comparisons(self): equality_ops = operator.eq, operator.ne # results when InvalidOperation is not trapped - for x, y in qnan_pairs + snan_pairs: - for op in order_ops + equality_ops: - got = op(x, y) - expected = True if op is operator.ne else False - self.assertIs(expected, got, - "expected {0!r} for operator.{1}({2!r}, {3!r}); " - "got {4!r}".format( - expected, op.__name__, x, y, got)) + with localcontext() as ctx: + ctx.traps[InvalidOperation] = 0 + + for x, y in qnan_pairs + snan_pairs: + for op in order_ops + equality_ops: + got = op(x, y) + expected = True if op is operator.ne else False + self.assertIs(expected, got, + "expected {0!r} for operator.{1}({2!r}, {3!r}); " + "got {4!r}".format( + expected, op.__name__, x, y, got)) # repeat the above, but this time trap the InvalidOperation with localcontext() as ctx: @@ -1562,9 +1565,10 @@ def test_copy_sign(self): self.assertEqual(Decimal(1).copy_sign(-2), d) self.assertRaises(TypeError, Decimal(1).copy_sign, '-2') -class CArithmeticOperatorsTest(ArithmeticOperatorsTest): +@requires_cdecimal +class CArithmeticOperatorsTest(ArithmeticOperatorsTest, unittest.TestCase): decimal = C -class PyArithmeticOperatorsTest(ArithmeticOperatorsTest): +class PyArithmeticOperatorsTest(ArithmeticOperatorsTest, unittest.TestCase): decimal = P # The following are two functions used to test threading in the next class @@ -1654,7 +1658,7 @@ def thfunc2(cls): @threading_helper.requires_working_threading() -class ThreadingTest(unittest.TestCase): +class ThreadingTest: '''Unit tests for thread local contexts in Decimal.''' # Take care executing this test from IDLE, there's an issue in threading @@ -1699,13 +1703,14 @@ def test_threading(self): DefaultContext.Emin = save_emin -class CThreadingTest(ThreadingTest): +@requires_cdecimal +class CThreadingTest(ThreadingTest, unittest.TestCase): decimal = C -class PyThreadingTest(ThreadingTest): +class PyThreadingTest(ThreadingTest, unittest.TestCase): decimal = P -class UsabilityTest(unittest.TestCase): +class UsabilityTest: '''Unit tests for Usability cases of Decimal.''' def test_comparison_operators(self): @@ -2521,9 +2526,10 @@ def test_conversions_from_int(self): self.assertEqual(Decimal(-12).fma(45, Decimal(67)), Decimal(-12).fma(Decimal(45), Decimal(67))) -class CUsabilityTest(UsabilityTest): +@requires_cdecimal +class CUsabilityTest(UsabilityTest, unittest.TestCase): decimal = C -class PyUsabilityTest(UsabilityTest): +class PyUsabilityTest(UsabilityTest, unittest.TestCase): decimal = P def setUp(self): @@ -2535,7 +2541,7 @@ def tearDown(self): sys.set_int_max_str_digits(self._previous_int_limit) super().tearDown() -class PythonAPItests(unittest.TestCase): +class PythonAPItests: def test_abc(self): Decimal = self.decimal.Decimal @@ -2884,12 +2890,13 @@ def test_exception_hierarchy(self): self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError)) self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation)) -class CPythonAPItests(PythonAPItests): +@requires_cdecimal +class CPythonAPItests(PythonAPItests, unittest.TestCase): decimal = C -class PyPythonAPItests(PythonAPItests): +class PyPythonAPItests(PythonAPItests, unittest.TestCase): decimal = P -class ContextAPItests(unittest.TestCase): +class ContextAPItests: def test_none_args(self): Context = self.decimal.Context @@ -3635,12 +3642,13 @@ def test_to_integral_value(self): self.assertRaises(TypeError, c.to_integral_value, '10') self.assertRaises(TypeError, c.to_integral_value, 10, 'x') -class CContextAPItests(ContextAPItests): +@requires_cdecimal +class CContextAPItests(ContextAPItests, unittest.TestCase): decimal = C -class PyContextAPItests(ContextAPItests): +class PyContextAPItests(ContextAPItests, unittest.TestCase): decimal = P -class ContextWithStatement(unittest.TestCase): +class ContextWithStatement: # Can't do these as docstrings until Python 2.6 # as doctest can't handle __future__ statements @@ -3704,9 +3712,13 @@ def test_localcontext_kwargs(self): def test_local_context_kwargs_does_not_overwrite_existing_argument(self): ctx = self.decimal.getcontext() - ctx.prec = 28 + orig_prec = ctx.prec with self.decimal.localcontext(prec=10) as ctx2: - self.assertEqual(ctx.prec, 28) + self.assertEqual(ctx2.prec, 10) + self.assertEqual(ctx.prec, orig_prec) + with self.decimal.localcontext(prec=20) as ctx2: + self.assertEqual(ctx2.prec, 20) + self.assertEqual(ctx.prec, orig_prec) def test_nested_with_statements(self): # Use a copy of the supplied context in the block @@ -3800,12 +3812,13 @@ def test_with_statements_gc3(self): self.assertEqual(c4.prec, 4) del c4 -class CContextWithStatement(ContextWithStatement): +@requires_cdecimal +class CContextWithStatement(ContextWithStatement, unittest.TestCase): decimal = C -class PyContextWithStatement(ContextWithStatement): +class PyContextWithStatement(ContextWithStatement, unittest.TestCase): decimal = P -class ContextFlags(unittest.TestCase): +class ContextFlags: def test_flags_irrelevant(self): # check that the result (numeric result + flags raised) of an @@ -4072,12 +4085,13 @@ def test_float_operation_default(self): self.assertTrue(context.traps[FloatOperation]) self.assertTrue(context.traps[Inexact]) -class CContextFlags(ContextFlags): +@requires_cdecimal +class CContextFlags(ContextFlags, unittest.TestCase): decimal = C -class PyContextFlags(ContextFlags): +class PyContextFlags(ContextFlags, unittest.TestCase): decimal = P -class SpecialContexts(unittest.TestCase): +class SpecialContexts: """Test the context templates.""" def test_context_templates(self): @@ -4157,12 +4171,13 @@ def test_default_context(self): if ex: raise ex -class CSpecialContexts(SpecialContexts): +@requires_cdecimal +class CSpecialContexts(SpecialContexts, unittest.TestCase): decimal = C -class PySpecialContexts(SpecialContexts): +class PySpecialContexts(SpecialContexts, unittest.TestCase): decimal = P -class ContextInputValidation(unittest.TestCase): +class ContextInputValidation: def test_invalid_context(self): Context = self.decimal.Context @@ -4224,12 +4239,13 @@ def test_invalid_context(self): self.assertRaises(TypeError, Context, flags=(0,1)) self.assertRaises(TypeError, Context, traps=(1,0)) -class CContextInputValidation(ContextInputValidation): +@requires_cdecimal +class CContextInputValidation(ContextInputValidation, unittest.TestCase): decimal = C -class PyContextInputValidation(ContextInputValidation): +class PyContextInputValidation(ContextInputValidation, unittest.TestCase): decimal = P -class ContextSubclassing(unittest.TestCase): +class ContextSubclassing: def test_context_subclassing(self): decimal = self.decimal @@ -4338,12 +4354,14 @@ def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, for signal in OrderedSignals[decimal]: self.assertFalse(c.traps[signal]) -class CContextSubclassing(ContextSubclassing): +@requires_cdecimal +class CContextSubclassing(ContextSubclassing, unittest.TestCase): decimal = C -class PyContextSubclassing(ContextSubclassing): +class PyContextSubclassing(ContextSubclassing, unittest.TestCase): decimal = P @skip_if_extra_functionality +@requires_cdecimal class CheckAttributes(unittest.TestCase): def test_module_attributes(self): @@ -4373,7 +4391,7 @@ def test_decimal_attributes(self): y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')] self.assertEqual(set(x) - set(y), set()) -class Coverage(unittest.TestCase): +class Coverage: def test_adjusted(self): Decimal = self.decimal.Decimal @@ -4630,9 +4648,10 @@ def test_copy(self): y = c.copy_sign(x, 1) self.assertEqual(y, -x) -class CCoverage(Coverage): +@requires_cdecimal +class CCoverage(Coverage, unittest.TestCase): decimal = C -class PyCoverage(Coverage): +class PyCoverage(Coverage, unittest.TestCase): decimal = P def setUp(self): @@ -4885,6 +4904,7 @@ def test_constants(self): self.assertEqual(C.DecTraps, C.DecErrors|C.DecOverflow|C.DecUnderflow) +@requires_cdecimal class CWhitebox(unittest.TestCase): """Whitebox testing for _decimal""" @@ -5663,7 +5683,7 @@ def test_maxcontext_exact_arith(self): @requires_docstrings -@unittest.skipUnless(C, "test requires C version") +@requires_cdecimal class SignatureTest(unittest.TestCase): """Function signatures""" @@ -5799,52 +5819,10 @@ def doit(ty): doit('Context') -all_tests = [ - CExplicitConstructionTest, PyExplicitConstructionTest, - CImplicitConstructionTest, PyImplicitConstructionTest, - CFormatTest, PyFormatTest, - CArithmeticOperatorsTest, PyArithmeticOperatorsTest, - CThreadingTest, PyThreadingTest, - CUsabilityTest, PyUsabilityTest, - CPythonAPItests, PyPythonAPItests, - CContextAPItests, PyContextAPItests, - CContextWithStatement, PyContextWithStatement, - CContextFlags, PyContextFlags, - CSpecialContexts, PySpecialContexts, - CContextInputValidation, PyContextInputValidation, - CContextSubclassing, PyContextSubclassing, - CCoverage, PyCoverage, - CFunctionality, PyFunctionality, - CWhitebox, PyWhitebox, - CIBMTestCases, PyIBMTestCases, -] - -# Delete C tests if _decimal.so is not present. -if not C: - all_tests = all_tests[1::2] -else: - all_tests.insert(0, CheckAttributes) - all_tests.insert(1, SignatureTest) - - -def test_main(arith=None, verbose=None, todo_tests=None, debug=None): - """ Execute the tests. - - Runs all arithmetic tests if arith is True or if the "decimal" resource - is enabled in regrtest.py - """ - - init(C) - init(P) - global TEST_ALL, DEBUG - TEST_ALL = arith if arith is not None else is_resource_enabled('decimal') - DEBUG = debug - - if todo_tests is None: - test_classes = all_tests - else: - test_classes = [CIBMTestCases, PyIBMTestCases] - +def load_tests(loader, tests, pattern): + if TODO_TESTS is not None: + # Run only Arithmetic tests + tests = loader.suiteClass() # Dynamically build custom test definition for each file in the test # directory and add the definitions to the DecimalTest class. This # procedure insures that new files do not get skipped. @@ -5852,34 +5830,69 @@ def test_main(arith=None, verbose=None, todo_tests=None, debug=None): if '.decTest' not in filename or filename.startswith("."): continue head, tail = filename.split('.') - if todo_tests is not None and head not in todo_tests: + if TODO_TESTS is not None and head not in TODO_TESTS: continue tester = lambda self, f=filename: self.eval_file(directory + f) - setattr(CIBMTestCases, 'test_' + head, tester) - setattr(PyIBMTestCases, 'test_' + head, tester) + setattr(IBMTestCases, 'test_' + head, tester) del filename, head, tail, tester + for prefix, mod in ('C', C), ('Py', P): + if not mod: + continue + test_class = type(prefix + 'IBMTestCases', + (IBMTestCases, unittest.TestCase), + {'decimal': mod}) + tests.addTest(loader.loadTestsFromTestCase(test_class)) + + if TODO_TESTS is None: + from doctest import DocTestSuite, IGNORE_EXCEPTION_DETAIL + for mod in C, P: + if not mod: + continue + def setUp(slf, mod=mod): + sys.modules['decimal'] = mod + def tearDown(slf): + sys.modules['decimal'] = orig_sys_decimal + optionflags = IGNORE_EXCEPTION_DETAIL if mod is C else 0 + sys.modules['decimal'] = mod + tests.addTest(DocTestSuite(mod, setUp=setUp, tearDown=tearDown, + optionflags=optionflags)) + sys.modules['decimal'] = orig_sys_decimal + return tests + +def setUpModule(): + init(C) + init(P) + global TEST_ALL + TEST_ALL = ARITH if ARITH is not None else is_resource_enabled('decimal') + +def tearDownModule(): + if C: C.setcontext(ORIGINAL_CONTEXT[C]) + P.setcontext(ORIGINAL_CONTEXT[P]) + if not C: + warnings.warn('C tests skipped: no module named _decimal.', + UserWarning) + if not orig_sys_decimal is sys.modules['decimal']: + raise TestFailed("Internal error: unbalanced number of changes to " + "sys.modules['decimal'].") + + +ARITH = None +TEST_ALL = True +TODO_TESTS = None +DEBUG = False + +def test(arith=None, verbose=None, todo_tests=None, debug=None): + """ Execute the tests. + Runs all arithmetic tests if arith is True or if the "decimal" resource + is enabled in regrtest.py + """ - try: - run_unittest(*test_classes) - if todo_tests is None: - from doctest import IGNORE_EXCEPTION_DETAIL - savedecimal = sys.modules['decimal'] - if C: - sys.modules['decimal'] = C - run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL) - sys.modules['decimal'] = P - run_doctest(P, verbose) - sys.modules['decimal'] = savedecimal - finally: - if C: C.setcontext(ORIGINAL_CONTEXT[C]) - P.setcontext(ORIGINAL_CONTEXT[P]) - if not C: - warnings.warn('C tests skipped: no module named _decimal.', - UserWarning) - if not orig_sys_decimal is sys.modules['decimal']: - raise TestFailed("Internal error: unbalanced number of changes to " - "sys.modules['decimal'].") + global ARITH, TODO_TESTS, DEBUG + ARITH = arith + TODO_TESTS = todo_tests + DEBUG = debug + unittest.main(__name__, verbosity=2 if verbose else 1, exit=False, argv=[__name__]) if __name__ == '__main__': @@ -5890,8 +5903,8 @@ def test_main(arith=None, verbose=None, todo_tests=None, debug=None): (opt, args) = p.parse_args() if opt.skip: - test_main(arith=False, verbose=True) + test(arith=False, verbose=True) elif args: - test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug) + test(arith=True, verbose=True, todo_tests=args, debug=opt.debug) else: - test_main(arith=True, verbose=True) + test(arith=True, verbose=True) From fc2393e4177d32dab0c73f69472dc1b726dbeeaf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 03:54:26 -0700 Subject: [PATCH 0310/1206] [3.12] Display the sanitizer config in the regrtest header. (GH-105301) (#105342) Display the sanitizer config in the regrtest header. (GH-105301) Display the sanitizers present in libregrtest. Having this in the CI output for tests with the relevant environment variable displayed will help make it easier to do what we need to create an equivalent local test run. (cherry picked from commit 852348ab65783601e0844b6647ea033668b45c11) Co-authored-by: Gregory P. Smith --- Lib/test/libregrtest/main.py | 20 ++++++++++++++++++++ Lib/test/support/__init__.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 3c3509d0303371..9001ca33b6166a 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -526,6 +526,26 @@ def display_header(self): print("== CPU count:", cpu_count) print("== encodings: locale=%s, FS=%s" % (locale.getencoding(), sys.getfilesystemencoding())) + asan = support.check_sanitizer(address=True) + msan = support.check_sanitizer(memory=True) + ubsan = support.check_sanitizer(ub=True) + # This makes it easier to remember what to set in your local + # environment when trying to reproduce a sanitizer failure. + if asan or msan or ubsan: + names = [n for n in (asan and "address", + msan and "memory", + ubsan and "undefined behavior") + if n] + print(f"== sanitizers: {', '.join(names)}") + a_opts = os.environ.get("ASAN_OPTIONS") + if asan and a_opts is not None: + print(f"== ASAN_OPTIONS={a_opts}") + m_opts = os.environ.get("ASAN_OPTIONS") + if msan and m_opts is not None: + print(f"== MSAN_OPTIONS={m_opts}") + ub_opts = os.environ.get("UBSAN_OPTIONS") + if ubsan and ub_opts is not None: + print(f"== UBSAN_OPTIONS={ub_opts}") def no_tests_run(self): return not any((self.good, self.bad, self.skipped, self.interrupted, diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 3f1cc3a083a1c7..3b332f49951f0c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -414,7 +414,7 @@ def check_sanitizer(*, address=False, memory=False, ub=False): ) address_sanitizer = ( '-fsanitize=address' in _cflags or - '--with-memory-sanitizer' in _config_args + '--with-address-sanitizer' in _config_args ) ub_sanitizer = ( '-fsanitize=undefined' in _cflags or From 53605f285a5e50cd804f3b38aa9e3a71546142b3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 04:02:22 -0700 Subject: [PATCH 0311/1206] [3.12] GH-104554: Add RTSPS support to `urllib/parse.py` (GH-104605) (#105759) RTSPS is the permanent scheme defined in https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml alongside RTSP and RTSPU schemes. (cherry picked from commit f3266c05b6186ab6d1db0799c06b8f76aefe7cf1) Co-authored-by: zentarim <33746047+zentarim@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- Doc/library/urllib.parse.rst | 6 +++--- Lib/urllib/parse.py | 10 +++++----- .../2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 5a9a53f83dace0..e1aa4ebb0964dd 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -23,9 +23,9 @@ to an absolute URL given a "base URL." The module has been designed to match the internet RFC on Relative Uniform Resource Locators. It supports the following URL schemes: ``file``, ``ftp``, ``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``mailto``, ``mms``, -``news``, ``nntp``, ``prospero``, ``rsync``, ``rtsp``, ``rtspu``, ``sftp``, -``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``, ``telnet``, -``wais``, ``ws``, ``wss``. +``news``, ``nntp``, ``prospero``, ``rsync``, ``rtsp``, ``rtsps``, ``rtspu``, +``sftp``, ``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``, +``telnet``, ``wais``, ``ws``, ``wss``. The :mod:`urllib.parse` module defines functions that fall into two broad categories: URL parsing and URL quoting. These are covered in detail in diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index b73b34428764f7..c129b0d7971d71 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -52,18 +52,18 @@ uses_relative = ['', 'ftp', 'http', 'gopher', 'nntp', 'imap', 'wais', 'file', 'https', 'shttp', 'mms', - 'prospero', 'rtsp', 'rtspu', 'sftp', + 'prospero', 'rtsp', 'rtsps', 'rtspu', 'sftp', 'svn', 'svn+ssh', 'ws', 'wss'] uses_netloc = ['', 'ftp', 'http', 'gopher', 'nntp', 'telnet', 'imap', 'wais', 'file', 'mms', 'https', 'shttp', - 'snews', 'prospero', 'rtsp', 'rtspu', 'rsync', + 'snews', 'prospero', 'rtsp', 'rtsps', 'rtspu', 'rsync', 'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh', 'ws', 'wss', 'itms-services'] uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap', - 'https', 'shttp', 'rtsp', 'rtspu', 'sip', 'sips', - 'mms', 'sftp', 'tel'] + 'https', 'shttp', 'rtsp', 'rtsps', 'rtspu', 'sip', + 'sips', 'mms', 'sftp', 'tel'] # These are not actually used anymore, but should stay for backwards # compatibility. (They are undocumented, but have a public-looking name.) @@ -72,7 +72,7 @@ 'telnet', 'wais', 'imap', 'snews', 'sip', 'sips'] uses_query = ['', 'http', 'wais', 'imap', 'https', 'shttp', 'mms', - 'gopher', 'rtsp', 'rtspu', 'sip', 'sips'] + 'gopher', 'rtsp', 'rtsps', 'rtspu', 'sip', 'sips'] uses_fragment = ['', 'ftp', 'hdl', 'http', 'gopher', 'news', 'nntp', 'wais', 'https', 'shttp', 'snews', diff --git a/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst b/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst new file mode 100644 index 00000000000000..9ef8c67459c406 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst @@ -0,0 +1 @@ +Add RTSPS scheme support in urllib.parse From b314194c3c05d388892be2a6bf359fec20d9504c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 04:05:50 -0700 Subject: [PATCH 0312/1206] [3.12] gh-105063: Disable test_peg_generator.TestCParser bco. ref leaks (GH-106024) (#106450) Since gh-104798 (Use setuptools in peg-generator and reenable tests), the TestCParser test case has been producing ref leaks. (cherry picked from commit 41ad4dfc04c201728ce9fa12b1a96922dd15a368) Co-authored-by: Erlend E. Aasland --- Lib/test/test_peg_generator/test_c_parser.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index af39faeba94357..f9105a9f23bd6d 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -74,8 +74,18 @@ def test_parse(self): @support.requires_subprocess() class TestCParser(unittest.TestCase): + _has_run = False + @classmethod def setUpClass(cls): + if cls._has_run: + # Since gh-104798 (Use setuptools in peg-generator and reenable + # tests), this test case has been producing ref leaks. Initial + # debugging points to bug(s) in setuptools and/or importlib. + # See gh-105063 for more info. + raise unittest.SkipTest("gh-105063: can not rerun because of ref. leaks") + cls._has_run = True + # When running under regtest, a separate tempdir is used # as the current directory and watched for left-overs. # Reusing that as the base for temporary directories From da672b2d245fb439f4ff895636bf284e352fa631 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 04:21:38 -0700 Subject: [PATCH 0313/1206] [3.12] Document PYTHONSAFEPATH along side -P (GH-106122) (#106352) Document PYTHONSAFEPATH along side -P (GH-106122) (cherry picked from commit 0355625d94a50f4b816770bad946420d005900b8) Co-authored-by: Jeremy Paige --- Python/initconfig.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/initconfig.c b/Python/initconfig.c index 0d42b7ea082d61..4e5d4bb9876e3b 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -49,7 +49,7 @@ Options (and corresponding environment variables):\n\ .pyc extension; also PYTHONOPTIMIZE=x\n\ -OO : do -O changes and also discard docstrings; add .opt-2 before\n\ .pyc extension\n\ --P : don't prepend a potentially unsafe path to sys.path\n\ +-P : don't prepend a potentially unsafe path to sys.path; also PYTHONSAFEPATH\n\ -q : don't print version and copyright messages on interactive startup\n\ -s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\ -S : don't imply 'import site' on initialization\n\ @@ -144,7 +144,6 @@ static const char usage_envvars[] = "PYTHONSTARTUP: file executed on interactive startup (no default)\n" "PYTHONPATH : '%lc'-separated list of directories prefixed to the\n" " default module search path. The result is sys.path.\n" -"PYTHONSAFEPATH: don't prepend a potentially unsafe path to sys.path.\n" "PYTHONHOME : alternate directory (or %lc).\n" " The default module search path uses %s.\n" "PYTHONPLATLIBDIR : override sys.platlibdir.\n" @@ -184,6 +183,7 @@ static const char usage_envvars[] = " (-X int_max_str_digits=number)\n" "PYTHONNOUSERSITE : disable user site directory (-s)\n" "PYTHONOPTIMIZE : enable level 1 optimizations (-O)\n" +"PYTHONSAFEPATH : don't prepend a potentially unsafe path to sys.path (-P)\n" "PYTHONUNBUFFERED : disable stdout/stderr buffering (-u)\n" "PYTHONVERBOSE : trace import statements (-v)\n" "PYTHONWARNINGS=arg : warning control (-W arg)\n"; From 74d84cf84d18e8cf69ffef0d7955f80fbc47220a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 04:39:59 -0700 Subject: [PATCH 0314/1206] [3.12] gh-105497: [Enum] Fix Flag inversion when alias/mask members exist. (GH-105542) (#105572) gh-105497: [Enum] Fix Flag inversion when alias/mask members exist. (GH-105542) When inverting a Flag member (or boundary STRICT), only consider other canonical flags; when inverting an IntFlag member (or boundary KEEP), also consider aliases. (cherry picked from commit 59f009e5898a006cdc8f5249be589de6edfe5cd0) Co-authored-by: Ethan Furman --- Lib/enum.py | 15 ++++--- Lib/test/test_enum.py | 39 +++++++++++++++++++ ...-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst | 1 + 3 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst diff --git a/Lib/enum.py b/Lib/enum.py index 62df304057a108..92a9632dc892d0 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1463,12 +1463,11 @@ def _missing_(cls, value): else: pseudo_member._name_ = None # use setdefault in case another thread already created a composite - # with this value, but only if all members are known - # note: zero is a special case -- add it - if not unknown: - pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member) - if neg_value is not None: - cls._value2member_map_[neg_value] = pseudo_member + # with this value + # note: zero is a special case -- always add it + pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member) + if neg_value is not None: + cls._value2member_map_[neg_value] = pseudo_member return pseudo_member def __contains__(self, other): @@ -1544,8 +1543,8 @@ def __invert__(self): # use all bits self._inverted_ = self.__class__(~self._value_) else: - # calculate flags not in this member - self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_) + # use canonical bits (i.e. calculate flags not in this member) + self._inverted_ = self.__class__(self._singles_mask_ ^ self._value_) if isinstance(self._inverted_, self.__class__): self._inverted_._inverted_ = self return self._inverted_ diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index b4ac3abfc7006f..291213a13f36b7 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -3045,6 +3045,33 @@ class Color(Flag): WHITE = RED|GREEN|BLUE BLANCO = RED|GREEN|BLUE + class Complete(Flag): + A = 0x01 + B = 0x02 + + class Partial(Flag): + A = 0x01 + B = 0x02 + MASK = 0xff + + class CompleteInt(IntFlag): + A = 0x01 + B = 0x02 + + class PartialInt(IntFlag): + A = 0x01 + B = 0x02 + MASK = 0xff + + class CompleteIntStrict(IntFlag, boundary=STRICT): + A = 0x01 + B = 0x02 + + class PartialIntStrict(IntFlag, boundary=STRICT): + A = 0x01 + B = 0x02 + MASK = 0xff + def test_or(self): Perm = self.Perm for i in Perm: @@ -3103,6 +3130,18 @@ def test_invert(self): Open = self.Open self.assertIs(Open.WO & ~Open.WO, Open.RO) self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE) + Complete = self.Complete + self.assertIs(~Complete.A, Complete.B) + Partial = self.Partial + self.assertIs(~Partial.A, Partial.B) + CompleteInt = self.CompleteInt + self.assertIs(~CompleteInt.A, CompleteInt.B) + PartialInt = self.PartialInt + self.assertIs(~PartialInt.A, PartialInt(254)) + CompleteIntStrict = self.CompleteIntStrict + self.assertIs(~CompleteIntStrict.A, CompleteIntStrict.B) + PartialIntStrict = self.PartialIntStrict + self.assertIs(~PartialIntStrict.A, PartialIntStrict.B) def test_bool(self): Perm = self.Perm diff --git a/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst b/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst new file mode 100644 index 00000000000000..2d4e2091b50714 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst @@ -0,0 +1 @@ +Fix flag inversion when alias/mask members exist. From b72601e7e5a8e3286b1345ac14fa21ac2d3056dc Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 5 Jul 2023 15:17:09 +0200 Subject: [PATCH 0315/1206] [3.12] gh-64595: Fix regression in file write logic in Argument Clinic (#106449) (#106452) Revert the two commits that introduced the regressions: - gh-104152 - gh-104507 (cherry picked from commit 9d1d4f9c73a71192b22ab52a2eb9278737f98ddb) --- Lib/test/test_clinic.py | 7 +++---- Tools/clinic/clinic.py | 35 ++++++++++++----------------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 7c46e8a81803a2..685ba58642a5ae 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -100,9 +100,8 @@ def test_eol(self): # the last line of the block got corrupted. c = clinic.Clinic(clinic.CLanguage(None), filename="file") raw = "/*[clinic]\nfoo\n[clinic]*/" - cooked, _ = c.parse(raw) - lines = cooked.splitlines() - end_line = lines[2].rstrip() + cooked = c.parse(raw).splitlines() + end_line = cooked[2].rstrip() # this test is redundant, it's just here explicitly to catch # the regression test so we don't forget what it looked like self.assertNotEqual(end_line, "[clinic]*/[clinic]*/") @@ -261,7 +260,7 @@ def _test_clinic(self, input, output): c = clinic.Clinic(language, filename="file") c.parsers['inert'] = InertParser(c) c.parsers['copy'] = CopyParser(c) - computed, _ = c.parse(input) + computed = c.parse(input) self.assertEqual(output, computed) def test_clinic_1(self): diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index fa6c1392e1f092..04951e97bbd808 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1966,22 +1966,20 @@ def dump(self): extensions['py'] = PythonLanguage -def file_changed(filename: str, new_contents: str) -> bool: - """Return true if file contents changed (meaning we must update it)""" +def write_file(filename: str, new_contents: str) -> None: try: - with open(filename, encoding="utf-8") as fp: + with open(filename, 'r', encoding="utf-8") as fp: old_contents = fp.read() - return old_contents != new_contents - except FileNotFoundError: - return True - -def write_file(filename: str, new_contents: str): + if old_contents == new_contents: + # no change: avoid modifying the file modification time + return + except FileNotFoundError: + pass # Atomic write using a temporary file and os.replace() filename_new = f"{filename}.new" with open(filename_new, "w", encoding="utf-8") as fp: fp.write(new_contents) - try: os.replace(filename_new, filename) except: @@ -2159,8 +2157,6 @@ def parse(self, input): traceback.format_exc().rstrip()) printer.print_block(block) - clinic_out = [] - # these are destinations not buffers for name, destination in self.destinations.items(): if destination.type == 'suppress': @@ -2168,7 +2164,6 @@ def parse(self, input): output = destination.dump() if output: - block = Block("", dsl_name="clinic", output=output) if destination.type == 'buffer': @@ -2200,11 +2195,10 @@ def parse(self, input): block.input = 'preserve\n' printer_2 = BlockPrinter(self.language) printer_2.print_block(block, core_includes=True) - pair = destination.filename, printer_2.f.getvalue() - clinic_out.append(pair) + write_file(destination.filename, printer_2.f.getvalue()) continue - return printer.f.getvalue(), clinic_out + return printer.f.getvalue() def _module_and_class(self, fields): @@ -2266,14 +2260,9 @@ def parse_file( assert isinstance(language, CLanguage) clinic = Clinic(language, verify=verify, filename=filename) - src_out, clinic_out = clinic.parse(raw) - - changes = [(fn, data) for fn, data in clinic_out if file_changed(fn, data)] - if changes: - # Always (re)write the source file. - write_file(output, src_out) - for fn, data in clinic_out: - write_file(fn, data) + cooked = clinic.parse(raw) + + write_file(output, cooked) def compute_checksum( From a49a29f22bcc39376e760823ec512df831d2e828 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 13:57:49 -0700 Subject: [PATCH 0316/1206] [3.12] shlex docs: remove outdated note (GH-106463) (#106466) shlex docs: remove outdated note (GH-106463) As the versionchanged notice says, this note is no longer true on 3.12+. (cherry picked from commit c16ea94abc73c0098b484f7e2ec23bfd9c36b67c) Co-authored-by: Jelle Zijlstra --- Doc/library/shlex.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst index 0bad51833aae13..f94833ad5331a9 100644 --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -30,12 +30,6 @@ The :mod:`shlex` module defines the following functions: in POSIX mode by default, but uses non-POSIX mode if the *posix* argument is false. - .. note:: - - Since the :func:`split` function instantiates a :class:`~shlex.shlex` - instance, passing ``None`` for *s* will read the string to split from - standard input. - .. versionchanged:: 3.12 Passing ``None`` for *s* argument now raises an exception, rather than reading :data:`sys.stdin`. From bb17e6f5de2bca85746a06d504029f90e85e3892 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 16:31:37 -0700 Subject: [PATCH 0317/1206] [3.12] gh-105340: include hidden fast-locals in locals() (GH-105715) (#106470) gh-105340: include hidden fast-locals in locals() (GH-105715) * gh-105340: include hidden fast-locals in locals() (cherry picked from commit 104d7b760fed18055e4f04e5da3ca619e28bfc81) Co-authored-by: Carl Meyer --- Include/internal/pycore_ceval.h | 1 + Include/internal/pycore_frame.h | 3 + Lib/test/test_listcomps.py | 22 +++++ ...-06-12-16-38-31.gh-issue-105340._jRHXe.rst | 2 + Objects/frameobject.c | 65 ++++++++++++-- Objects/object.c | 7 +- Python/bltinmodule.c | 87 +++++++++++-------- Python/ceval.c | 13 +++ 8 files changed, 158 insertions(+), 42 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 9e9b523e7c2222..fc0f72efdae48e 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -154,6 +154,7 @@ extern PyObject* _Py_MakeCoro(PyFunctionObject *func); extern int _Py_HandlePending(PyThreadState *tstate); +extern PyObject * _PyEval_GetFrameLocals(void); #ifdef __cplusplus diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index a72e03f1438fc8..158db2cf9df82e 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -226,6 +226,9 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame * frame); int _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg); +PyObject * +_PyFrame_GetLocals(_PyInterpreterFrame *frame, int include_hidden); + int _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame); diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index c2cf058c321fa5..9f28ced32bd26c 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -539,6 +539,28 @@ def b(): self._check_in_scopes(code, {"x": True, "y": ["b"]}, scopes=["function"]) self._check_in_scopes(code, raises=NameError, scopes=["class"]) + def test_iter_var_available_in_locals(self): + code = """ + l = [1, 2] + y = 0 + items = [locals()["x"] for x in l] + items2 = [vars()["x"] for x in l] + items3 = [("x" in dir()) for x in l] + items4 = [eval("x") for x in l] + # x is available, and does not overwrite y + [exec("y = x") for x in l] + """ + self._check_in_scopes( + code, + { + "items": [1, 2], + "items2": [1, 2], + "items3": [True, True], + "items4": [1, 2], + "y": 0 + } + ) + __test__ = {'doctests' : doctests} diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst new file mode 100644 index 00000000000000..f6d4fa8fc4d74e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst @@ -0,0 +1,2 @@ +Include the comprehension iteration variable in ``locals()`` inside a +module- or class-scope comprehension. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 2c90a6b71311ca..e62cfab80b2e35 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1199,15 +1199,28 @@ frame_get_var(_PyInterpreterFrame *frame, PyCodeObject *co, int i, return 1; } -int -_PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) + +PyObject * +_PyFrame_GetLocals(_PyInterpreterFrame *frame, int include_hidden) { /* Merge fast locals into f->f_locals */ PyObject *locals = frame->f_locals; if (locals == NULL) { locals = frame->f_locals = PyDict_New(); if (locals == NULL) { - return -1; + return NULL; + } + } + PyObject *hidden = NULL; + + /* If include_hidden, "hidden" fast locals (from inlined comprehensions in + module/class scopes) will be included in the returned dict, but not in + frame->f_locals; the returned dict will be a modified copy. Non-hidden + locals will still be updated in frame->f_locals. */ + if (include_hidden) { + hidden = PyDict_New(); + if (hidden == NULL) { + return NULL; } } @@ -1223,6 +1236,11 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); if (kind & CO_FAST_HIDDEN) { + if (include_hidden && value != NULL) { + if (PyObject_SetItem(hidden, name, value) != 0) { + goto error; + } + } continue; } if (value == NULL) { @@ -1231,16 +1249,53 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) PyErr_Clear(); } else { - return -1; + goto error; } } } else { if (PyObject_SetItem(locals, name, value) != 0) { - return -1; + goto error; } } } + + if (include_hidden && PyDict_Size(hidden)) { + PyObject *innerlocals = PyDict_New(); + if (innerlocals == NULL) { + goto error; + } + if (PyDict_Merge(innerlocals, locals, 1) != 0) { + Py_DECREF(innerlocals); + goto error; + } + if (PyDict_Merge(innerlocals, hidden, 1) != 0) { + Py_DECREF(innerlocals); + goto error; + } + locals = innerlocals; + } + else { + Py_INCREF(locals); + } + Py_CLEAR(hidden); + + return locals; + + error: + Py_XDECREF(hidden); + return NULL; +} + + +int +_PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) +{ + PyObject *locals = _PyFrame_GetLocals(frame, 0); + if (locals == NULL) { + return -1; + } + Py_DECREF(locals); return 0; } diff --git a/Objects/object.c b/Objects/object.c index ece0c5e21e77fa..b8bdf459201d9b 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1704,13 +1704,15 @@ _dir_locals(void) PyObject *names; PyObject *locals; - locals = PyEval_GetLocals(); + locals = _PyEval_GetFrameLocals(); if (locals == NULL) return NULL; names = PyMapping_Keys(locals); - if (!names) + Py_DECREF(locals); + if (!names) { return NULL; + } if (!PyList_Check(names)) { PyErr_Format(PyExc_TypeError, "dir(): expected keys() of locals to be a list, " @@ -1722,7 +1724,6 @@ _dir_locals(void) Py_DECREF(names); return NULL; } - /* the locals don't need to be DECREF'd */ return names; } diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 45ce3b71e84ecf..7f366b43599ae5 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -907,7 +907,7 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, PyObject *locals) /*[clinic end generated code: output=0a0824aa70093116 input=11ee718a8640e527]*/ { - PyObject *result, *source_copy; + PyObject *result = NULL, *source_copy; const char *str; if (locals != Py_None && !PyMapping_Check(locals)) { @@ -923,19 +923,25 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) { - locals = PyEval_GetLocals(); + locals = _PyEval_GetFrameLocals(); if (locals == NULL) return NULL; } + else { + Py_INCREF(locals); + } } else if (locals == Py_None) - locals = globals; + locals = Py_NewRef(globals); + else { + Py_INCREF(locals); + } if (globals == NULL || locals == NULL) { PyErr_SetString(PyExc_TypeError, "eval must be given globals and locals " "when called without a frame"); - return NULL; + goto error; } int r = PyDict_Contains(globals, &_Py_ID(__builtins__)); @@ -943,34 +949,38 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins()); } if (r < 0) { - return NULL; + goto error; } if (PyCode_Check(source)) { if (PySys_Audit("exec", "O", source) < 0) { - return NULL; + goto error; } if (PyCode_GetNumFree((PyCodeObject *)source) > 0) { PyErr_SetString(PyExc_TypeError, "code object passed to eval() may not contain free variables"); - return NULL; + goto error; } - return PyEval_EvalCode(source, globals, locals); + result = PyEval_EvalCode(source, globals, locals); } + else { + PyCompilerFlags cf = _PyCompilerFlags_INIT; + cf.cf_flags = PyCF_SOURCE_IS_UTF8; + str = _Py_SourceAsString(source, "eval", "string, bytes or code", &cf, &source_copy); + if (str == NULL) + goto error; - PyCompilerFlags cf = _PyCompilerFlags_INIT; - cf.cf_flags = PyCF_SOURCE_IS_UTF8; - str = _Py_SourceAsString(source, "eval", "string, bytes or code", &cf, &source_copy); - if (str == NULL) - return NULL; + while (*str == ' ' || *str == '\t') + str++; - while (*str == ' ' || *str == '\t') - str++; + (void)PyEval_MergeCompilerFlags(&cf); + result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); + Py_XDECREF(source_copy); + } - (void)PyEval_MergeCompilerFlags(&cf); - result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); - Py_XDECREF(source_copy); + error: + Py_XDECREF(locals); return result; } @@ -1005,36 +1015,43 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) { - locals = PyEval_GetLocals(); + locals = _PyEval_GetFrameLocals(); if (locals == NULL) return NULL; } + else { + Py_INCREF(locals); + } if (!globals || !locals) { PyErr_SetString(PyExc_SystemError, "globals and locals cannot be NULL"); return NULL; } } - else if (locals == Py_None) - locals = globals; + else if (locals == Py_None) { + locals = Py_NewRef(globals); + } + else { + Py_INCREF(locals); + } if (!PyDict_Check(globals)) { PyErr_Format(PyExc_TypeError, "exec() globals must be a dict, not %.100s", Py_TYPE(globals)->tp_name); - return NULL; + goto error; } if (!PyMapping_Check(locals)) { PyErr_Format(PyExc_TypeError, "locals must be a mapping or None, not %.100s", Py_TYPE(locals)->tp_name); - return NULL; + goto error; } int r = PyDict_Contains(globals, &_Py_ID(__builtins__)); if (r == 0) { r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins()); } if (r < 0) { - return NULL; + goto error; } if (closure == Py_None) { @@ -1047,7 +1064,7 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, if (closure) { PyErr_SetString(PyExc_TypeError, "cannot use a closure with this code object"); - return NULL; + goto error; } } else { int closure_is_ok = @@ -1067,12 +1084,12 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, PyErr_Format(PyExc_TypeError, "code object requires a closure of exactly length %zd", num_free); - return NULL; + goto error; } } if (PySys_Audit("exec", "O", source) < 0) { - return NULL; + goto error; } if (!closure) { @@ -1099,7 +1116,7 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, "string, bytes or code", &cf, &source_copy); if (str == NULL) - return NULL; + goto error; if (PyEval_MergeCompilerFlags(&cf)) v = PyRun_StringFlags(str, Py_file_input, globals, locals, &cf); @@ -1108,9 +1125,14 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, Py_XDECREF(source_copy); } if (v == NULL) - return NULL; + goto error; + Py_DECREF(locals); Py_DECREF(v); Py_RETURN_NONE; + + error: + Py_XDECREF(locals); + return NULL; } @@ -1720,10 +1742,7 @@ static PyObject * builtin_locals_impl(PyObject *module) /*[clinic end generated code: output=b46c94015ce11448 input=7874018d478d5c4b]*/ { - PyObject *d; - - d = PyEval_GetLocals(); - return Py_XNewRef(d); + return _PyEval_GetFrameLocals(); } @@ -2443,7 +2462,7 @@ builtin_vars_impl(PyObject *module, PyObject *object) PyObject *d; if (object == NULL) { - d = Py_XNewRef(PyEval_GetLocals()); + d = _PyEval_GetFrameLocals(); } else { if (_PyObject_LookupAttr(object, &_Py_ID(__dict__), &d) == 0) { diff --git a/Python/ceval.c b/Python/ceval.c index 4762dfac4812a6..c883a903e964f8 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2312,6 +2312,19 @@ PyEval_GetLocals(void) return locals; } +PyObject * +_PyEval_GetFrameLocals(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + _PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate); + if (current_frame == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist"); + return NULL; + } + + return _PyFrame_GetLocals(current_frame, 1); +} + PyObject * PyEval_GetGlobals(void) { From 7b615a1573b8a119e8ad27915912da745756a547 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 16:31:54 -0700 Subject: [PATCH 0318/1206] [3.12] gh-106292: restore checking __dict__ in cached_property.__get__ (GH-106380) (#106469) gh-106292: restore checking __dict__ in cached_property.__get__ (GH-106380) * gh-106292: restore checking __dict__ in cached_property.__get__ (cherry picked from commit 838406b4fc044c0b2f397c23275c69f16a76205b) Co-authored-by: Carl Meyer Co-authored-by: Dong-hee Na --- Lib/functools.py | 23 +++++++++++-------- Lib/test/test_functools.py | 19 +++++++++++++++ ...-07-03-15-09-44.gh-issue-106292.3npldV.rst | 4 ++++ 3 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst diff --git a/Lib/functools.py b/Lib/functools.py index 72b2103e7a5544..2ae4290f983982 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -956,9 +956,10 @@ def __isabstractmethod__(self): ################################################################################ -### cached_property() - computed once per instance, cached as attribute +### cached_property() - property result cached as instance attribute ################################################################################ +_NOT_FOUND = object() class cached_property: def __init__(self, func): @@ -989,15 +990,17 @@ def __get__(self, instance, owner=None): f"instance to cache {self.attrname!r} property." ) raise TypeError(msg) from None - val = self.func(instance) - try: - cache[self.attrname] = val - except TypeError: - msg = ( - f"The '__dict__' attribute on {type(instance).__name__!r} instance " - f"does not support item assignment for caching {self.attrname!r} property." - ) - raise TypeError(msg) from None + val = cache.get(self.attrname, _NOT_FOUND) + if val is _NOT_FOUND: + val = self.func(instance) + try: + cache[self.attrname] = val + except TypeError: + msg = ( + f"The '__dict__' attribute on {type(instance).__name__!r} instance " + f"does not support item assignment for caching {self.attrname!r} property." + ) + raise TypeError(msg) from None return val __class_getitem__ = classmethod(GenericAlias) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index d668fa4c3adf5c..c4eca0f5b79511 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -3037,6 +3037,25 @@ def test_access_from_class(self): def test_doc(self): self.assertEqual(CachedCostItem.cost.__doc__, "The cost of the item.") + def test_subclass_with___set__(self): + """Caching still works for a subclass defining __set__.""" + class readonly_cached_property(py_functools.cached_property): + def __set__(self, obj, value): + raise AttributeError("read only property") + + class Test: + def __init__(self, prop): + self._prop = prop + + @readonly_cached_property + def prop(self): + return self._prop + + t = Test(1) + self.assertEqual(t.prop, 1) + t._prop = 999 + self.assertEqual(t.prop, 1) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst b/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst new file mode 100644 index 00000000000000..233509344d509b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst @@ -0,0 +1,4 @@ +Check for an instance-dict cached value in the :meth:`__get__` method of +:func:`functools.cached_property`. This better matches the pre-3.12 behavior +and improves compatibility for users subclassing +:func:`functools.cached_property` and adding a :meth:`__set__` method. From 1e4c2359e4b88a237ca0ac7d1d0cac8411ba0278 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:53:30 -0700 Subject: [PATCH 0319/1206] [3.12] gh-105256: What's New note for comprehension over locals() (GH-106378) (#106471) gh-105256: What's New note for comprehension over locals() (GH-106378) (cherry picked from commit 13aefd175e3c04529251f175c23cb3ed88451fd0) Co-authored-by: Carl Meyer --- Doc/whatsnew/3.12.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ec13ed57a5c45d..eba3e226fa372c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -253,6 +253,12 @@ Inlining does result in a few visible behavior changes: * Calling :func:`locals` inside a comprehension now includes variables from outside the comprehension, and no longer includes the synthetic ``.0`` variable for the comprehension "argument". +* A comprehension iterating directly over ``locals()`` (e.g. ``[k for k in + locals()]``) may see "RuntimeError: dictionary changed size during iteration" + when run under tracing (e.g. code coverage measurement). This is the same + behavior already seen in e.g. ``for k in locals():``. To avoid the error, first + create a list of keys to iterate over: ``keys = list(locals()); [k for k in + keys]``. Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`. From 84cda268bd2c65c99d2ff69731d83e694146de70 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 5 Jul 2023 22:51:30 -0700 Subject: [PATCH 0320/1206] [3.12] Doc: Add missing ref labels to exception groups/notes sections (GH-106465) (#106473) Co-authored-by: C.A.M. Gerlach --- Doc/library/exceptions.rst | 2 ++ Doc/tutorial/errors.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 49ede20070d8af..d54c49fff6b62a 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -871,6 +871,8 @@ The following exceptions are used as warning categories; see the .. versionadded:: 3.2 +.. _lib-exception-groups: + Exception groups ---------------- diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index ca5dc3314c63b6..6419ff621f1b31 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -578,6 +578,8 @@ the following pattern:: ... +.. _tut-exception-notes: + Enriching Exceptions with Notes =============================== From e229225fbaa2de58b5143fea25b9d47480393f56 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 6 Jul 2023 04:04:43 -0700 Subject: [PATCH 0321/1206] [3.12] Clarify state of CancelledError in doc (GH-106453) (#106454) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify state of CancelledError in doc (GH-106453) This change makes it explicit that asyncio.CancelledError is not a subclass of Exception. (cherry picked from commit 12a98138083589314d3da14bc97f2d8517947437) Co-authored-by: Kristján Valur Jónsson --- Doc/library/asyncio-exceptions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-exceptions.rst b/Doc/library/asyncio-exceptions.rst index 9250f01b8a0895..7ad9103ca3fdfc 100644 --- a/Doc/library/asyncio-exceptions.rst +++ b/Doc/library/asyncio-exceptions.rst @@ -31,7 +31,7 @@ Exceptions .. versionchanged:: 3.8 - :exc:`CancelledError` is now a subclass of :class:`BaseException`. + :exc:`CancelledError` is now a subclass of :class:`BaseException` rather than :class:`Exception`. .. exception:: InvalidStateError From 4787eaed06cf83ed53270c61ac915dc0b15b20e8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:25:06 -0700 Subject: [PATCH 0322/1206] [3.12] gh-90876: Restore the ability to import multiprocessing when `sys.executable` is `None` (GH-106464) (#106494) gh-90876: Restore the ability to import multiprocessing when `sys.executable` is `None` (GH-106464) Prevent `multiprocessing.spawn` from failing to *import* in environments where `sys.executable` is `None`. This regressed in 3.11 with the addition of support for path-like objects in multiprocessing. Adds a test decorator to have tests only run when part of test_multiprocessing_spawn to `_test_multiprocessing.py` so we can start to avoid re-running the same not-global-state specific test in all 3 modes when there is no need. (cherry picked from commit c60df361ce2d734148d503f4a711e67c110fe223) Co-authored-by: Gregory P. Smith --- Lib/multiprocessing/spawn.py | 6 +- Lib/test/_test_multiprocessing.py | 82 +++++++++++++++++-- ...3-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst | 3 + 3 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py index 09f8a229d7cccb..f1af7709104714 100644 --- a/Lib/multiprocessing/spawn.py +++ b/Lib/multiprocessing/spawn.py @@ -31,11 +31,13 @@ WINSERVICE = False else: WINEXE = getattr(sys, 'frozen', False) - WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") + WINSERVICE = sys.executable and sys.executable.lower().endswith("pythonservice.exe") def set_executable(exe): global _python_exe - if sys.platform == 'win32': + if exe is None: + _python_exe = exe + elif sys.platform == 'win32': _python_exe = os.fsdecode(exe) else: _python_exe = os.fsencode(exe) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 767f049b0d717a..c13b049645ac90 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -13,6 +13,7 @@ import os import gc import errno +import functools import signal import array import socket @@ -31,6 +32,7 @@ from test.support import hashlib_helper from test.support import import_helper from test.support import os_helper +from test.support import script_helper from test.support import socket_helper from test.support import threading_helper from test.support import warnings_helper @@ -171,6 +173,59 @@ def check_enough_semaphores(): "to run the test (required: %d)." % nsems_min) +def only_run_in_spawn_testsuite(reason): + """Returns a decorator: raises SkipTest when SM != spawn at test time. + + This can be useful to save overall Python test suite execution time. + "spawn" is the universal mode available on all platforms so this limits the + decorated test to only execute within test_multiprocessing_spawn. + + This would not be necessary if we refactored our test suite to split things + into other test files when they are not start method specific to be rerun + under all start methods. + """ + + def decorator(test_item): + + @functools.wraps(test_item) + def spawn_check_wrapper(*args, **kwargs): + if (start_method := multiprocessing.get_start_method()) != "spawn": + raise unittest.SkipTest(f"{start_method=}, not 'spawn'; {reason}") + return test_item(*args, **kwargs) + + return spawn_check_wrapper + + return decorator + + +class TestInternalDecorators(unittest.TestCase): + """Logic within a test suite that could errantly skip tests? Test it!""" + + @unittest.skipIf(sys.platform == "win32", "test requires that fork exists.") + def test_only_run_in_spawn_testsuite(self): + if multiprocessing.get_start_method() != "spawn": + raise unittest.SkipTest("only run in test_multiprocessing_spawn.") + + try: + @only_run_in_spawn_testsuite("testing this decorator") + def return_four_if_spawn(): + return 4 + except Exception as err: + self.fail(f"expected decorated `def` not to raise; caught {err}") + + orig_start_method = multiprocessing.get_start_method(allow_none=True) + try: + multiprocessing.set_start_method("spawn", force=True) + self.assertEqual(return_four_if_spawn(), 4) + multiprocessing.set_start_method("fork", force=True) + with self.assertRaises(unittest.SkipTest) as ctx: + return_four_if_spawn() + self.assertIn("testing this decorator", str(ctx.exception)) + self.assertIn("start_method=", str(ctx.exception)) + finally: + multiprocessing.set_start_method(orig_start_method, force=True) + + # # Creates a wrapper for a function which records the time it takes to finish # @@ -5815,6 +5870,7 @@ def test_namespace(self): class TestNamedResource(unittest.TestCase): + @only_run_in_spawn_testsuite("spawn specific test.") def test_global_named_resource_spawn(self): # # gh-90549: Check that global named resources in main module @@ -5825,22 +5881,18 @@ def test_global_named_resource_spawn(self): with open(testfn, 'w', encoding='utf-8') as f: f.write(textwrap.dedent('''\ import multiprocessing as mp - ctx = mp.get_context('spawn') - global_resource = ctx.Semaphore() - def submain(): pass - if __name__ == '__main__': p = ctx.Process(target=submain) p.start() p.join() ''')) - rc, out, err = test.support.script_helper.assert_python_ok(testfn) + rc, out, err = script_helper.assert_python_ok(testfn) # on error, err = 'UserWarning: resource_tracker: There appear to # be 1 leaked semaphore objects to clean up at shutdown' - self.assertEqual(err, b'') + self.assertFalse(err, msg=err.decode('utf-8')) class MiscTestCase(unittest.TestCase): @@ -5849,6 +5901,24 @@ def test__all__(self): support.check__all__(self, multiprocessing, extra=multiprocessing.__all__, not_exported=['SUBDEBUG', 'SUBWARNING']) + @only_run_in_spawn_testsuite("avoids redundant testing.") + def test_spawn_sys_executable_none_allows_import(self): + # Regression test for a bug introduced in + # https://github.com/python/cpython/issues/90876 that caused an + # ImportError in multiprocessing when sys.executable was None. + # This can be true in embedded environments. + rc, out, err = script_helper.assert_python_ok( + "-c", + """if 1: + import sys + sys.executable = None + assert "multiprocessing" not in sys.modules, "already imported!" + import multiprocessing + import multiprocessing.spawn # This should not fail\n""", + ) + self.assertEqual(rc, 0) + self.assertFalse(err, msg=err.decode('utf-8')) + # # Mixins diff --git a/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst b/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst new file mode 100644 index 00000000000000..3e062b5add6d89 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst @@ -0,0 +1,3 @@ +Prevent :mod:`multiprocessing.spawn` from failing to *import* in environments +where ``sys.executable`` is ``None``. This regressed in 3.11 with the addition +of support for path-like objects in multiprocessing. From 5293e0108986eadb7e1f5c51e126673f4196ca79 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:30:32 -0700 Subject: [PATCH 0323/1206] [3.12] closes gh-106479: fix typo in __cplusplus macro (gh-106480) (#106493) closes gh-106479: fix typo in __cplusplus macro (gh-106480) (cherry picked from commit 67a798888dcde13bbb1e17cfcc3c742c94e67a07) Co-authored-by: Dustin Rodrigues --- Lib/test/_testcppext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/_testcppext.cpp b/Lib/test/_testcppext.cpp index 0e381a78c5ceed..82b471312dd2b9 100644 --- a/Lib/test/_testcppext.cpp +++ b/Lib/test/_testcppext.cpp @@ -86,7 +86,7 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) // gh-93442: Pass 0 as NULL for PyObject* Py_XINCREF(0); Py_XDECREF(0); -#if _cplusplus >= 201103 +#if __cplusplus >= 201103 // Test nullptr passed as PyObject* Py_XINCREF(nullptr); Py_XDECREF(nullptr); From 7e883d76c0a17a7c97782384d8e2ec025eade91b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 7 Jul 2023 05:08:22 -0700 Subject: [PATCH 0324/1206] [3.12] gh-106503: asyncio._SelectorSocketTransport: fix cyclic reference on close(). (GH-106504) (#106514) gh-106503: asyncio._SelectorSocketTransport: fix cyclic reference on close(). (GH-106504) (cherry picked from commit 3e5ce7968f5ab715f649e296e1f6b499621b8091) Co-authored-by: Andrew Geng --- Lib/asyncio/selector_events.py | 1 + Misc/ACKS | 1 + .../next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index fa2422b7fba4a7..f895750e3cf959 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -1202,6 +1202,7 @@ def _reset_empty_waiter(self): def close(self): self._read_ready_cb = None + self._write_ready = None super().close() diff --git a/Misc/ACKS b/Misc/ACKS index 454b63155f013c..ef0029a7e4119d 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -615,6 +615,7 @@ Marius Gedminas Jan-Philip Gehrcke Thomas Gellekum Gabriel Genellina +Andrew Geng Philip Georgi Christos Georgiou Elazar (×לעזר) Gershuni diff --git a/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst b/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst new file mode 100644 index 00000000000000..b8dd850386e86c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst @@ -0,0 +1,2 @@ +Fix ref cycle in :class:`!asyncio._SelectorSocketTransport` by removing +``_write_ready`` in ``close``. From 2ade2fc148fb25a0306d5b14f705396d98c8b926 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:25:24 -0700 Subject: [PATCH 0325/1206] [3.12] gh-106300: Improve `assertRaises(Exception)` usages in tests (GH-106302) (GH-106534) gh-106300: Improve `assertRaises(Exception)` usages in tests (GH-106302) (cherry picked from commit 6e6a4cd52332017b10c8d88fbbbfe015948093f4) Co-authored-by: Nikita Sobolev --- Lib/test/test_abc.py | 5 +++-- Lib/test/test_codecs.py | 5 +++-- Lib/test/test_email/test_message.py | 6 ++++-- Lib/test/test_importlib/test_main.py | 2 +- Lib/test/test_mailbox.py | 7 +++++-- Lib/test/test_shutil.py | 2 +- Lib/test/test_unittest/testmock/testasync.py | 5 +++-- 7 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index 86f31a9acb4d55..5ce57cc209ea85 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -448,15 +448,16 @@ class S(metaclass=abc_ABCMeta): # Also check that issubclass() propagates exceptions raised by # __subclasses__. + class CustomError(Exception): ... exc_msg = "exception from __subclasses__" def raise_exc(): - raise Exception(exc_msg) + raise CustomError(exc_msg) class S(metaclass=abc_ABCMeta): __subclasses__ = raise_exc - with self.assertRaisesRegex(Exception, exc_msg): + with self.assertRaisesRegex(CustomError, exc_msg): issubclass(int, S) def test_subclasshook(self): diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 376175f90f63eb..91d7eaf997ae20 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2822,14 +2822,15 @@ def test_binary_to_text_denylists_text_transforms(self): def test_custom_zlib_error_is_noted(self): # Check zlib codec gives a good error for malformed input msg = "decoding with 'zlib_codec' codec failed" - with self.assertRaises(Exception) as failure: + with self.assertRaises(zlib.error) as failure: codecs.decode(b"hello", "zlib_codec") self.assertEqual(msg, failure.exception.__notes__[0]) def test_custom_hex_error_is_noted(self): # Check hex codec gives a good error for malformed input + import binascii msg = "decoding with 'hex_codec' codec failed" - with self.assertRaises(Exception) as failure: + with self.assertRaises(binascii.Error) as failure: codecs.decode(b"hello", "hex_codec") self.assertEqual(msg, failure.exception.__notes__[0]) diff --git a/Lib/test/test_email/test_message.py b/Lib/test/test_email/test_message.py index 4c754bf40fc300..d3f396f02e7a72 100644 --- a/Lib/test/test_email/test_message.py +++ b/Lib/test/test_email/test_message.py @@ -696,14 +696,16 @@ def subtype_as_add(self, method, subtype, outcome): self.assertIsNone(part['Content-Disposition']) class _TestSetRaisingContentManager: + class CustomError(Exception): + pass def set_content(self, msg, content, *args, **kw): - raise Exception('test') + raise self.CustomError('test') def test_default_content_manager_for_add_comes_from_policy(self): cm = self._TestSetRaisingContentManager() m = self.message(policy=self.policy.clone(content_manager=cm)) for method in ('add_related', 'add_alternative', 'add_attachment'): - with self.assertRaises(Exception) as ar: + with self.assertRaises(self._TestSetRaisingContentManager.CustomError) as ar: getattr(m, method)('') self.assertEqual(str(ar.exception), 'test') diff --git a/Lib/test/test_importlib/test_main.py b/Lib/test/test_importlib/test_main.py index 46cd2b696d4cc8..81f683799cbc80 100644 --- a/Lib/test/test_importlib/test_main.py +++ b/Lib/test/test_importlib/test_main.py @@ -69,7 +69,7 @@ def test_abc_enforced(self): dict(name=''), ) def test_invalid_inputs_to_from_name(self, name): - with self.assertRaises(Exception): + with self.assertRaises(ValueError): Distribution.from_name(name) diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index 4c592eaf34da23..4977a9369ddf88 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -116,10 +116,13 @@ def test_add_nonascii_string_header_raises(self): self.assertMailboxEmpty() def test_add_that_raises_leaves_mailbox_empty(self): + class CustomError(Exception): ... + exc_msg = "a fake error" + def raiser(*args, **kw): - raise Exception("a fake error") + raise CustomError(exc_msg) support.patch(self, email.generator.BytesGenerator, 'flatten', raiser) - with self.assertRaises(Exception): + with self.assertRaisesRegex(CustomError, exc_msg): self._box.add(email.message_from_string("From: Alphöso")) self.assertEqual(len(self._box), 0) self._box.close() diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 36f0b8a31a3715..d74eee767c991d 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2739,7 +2739,7 @@ def test_regular_copy(self): def test_same_file(self): self.addCleanup(self.reset) with self.get_files() as (src, dst): - with self.assertRaises(Exception): + with self.assertRaises((OSError, _GiveupOnFastCopy)): self.zerocopy_fun(src, src) # Make sure src file is not corrupted. self.assertEqual(read_file(TESTFN, binary=True), self.FILEDATA) diff --git a/Lib/test/test_unittest/testmock/testasync.py b/Lib/test/test_unittest/testmock/testasync.py index 5f12f9f956674a..edd9a5dfc1f89d 100644 --- a/Lib/test/test_unittest/testmock/testasync.py +++ b/Lib/test/test_unittest/testmock/testasync.py @@ -436,9 +436,10 @@ async def addition(self, var): pass self.assertEqual(output, 10) async def test_add_side_effect_exception(self): + class CustomError(Exception): pass async def addition(var): pass - mock = AsyncMock(addition, side_effect=Exception('err')) - with self.assertRaises(Exception): + mock = AsyncMock(addition, side_effect=CustomError('side-effect')) + with self.assertRaisesRegex(CustomError, 'side-effect'): await mock(5) async def test_add_side_effect_coroutine(self): From 8fdb0587935b66c3942c1740ab5e387b2ea415bb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 8 Jul 2023 01:12:33 -0700 Subject: [PATCH 0326/1206] [3.12] gh-106524: Fix a crash in _sre.template() (GH-106525) (GH-106544) Some items remained uninitialized if _sre.template() was called with invalid indices. Then attempt to clear them in the destructor led to dereferencing of uninitialized pointer. (cherry picked from commit 2ef1dc37f02b08536b677dd23ec51541a60effd7) Co-authored-by: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> --- Lib/test/test_re.py | 10 ++++++++++ .../2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst | 1 + Modules/_sre/sre.c | 2 ++ 3 files changed, 13 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 11628a236ade9a..a05a1c99def0bc 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2441,6 +2441,16 @@ def test_regression_gh94675(self): p.terminate() p.join() + def test_sre_template_invalid_group_index(self): + # see gh-106524 + import _sre + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", -1, ""]) + self.assertIn("invalid template", str(cm.exception)) + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", (), ""]) + self.assertIn("an integer is required", str(cm.exception)) + def get_debug_out(pat): with captured_stdout() as out: diff --git a/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst b/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst new file mode 100644 index 00000000000000..f3fd070e391a66 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst @@ -0,0 +1 @@ +Fix crash in :func:`!_sre.template` with templates containing invalid group indices. diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index f8a1a05a318889..2f1c7324a0fa46 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -1549,10 +1549,12 @@ _sre_template_impl(PyObject *module, PyObject *pattern, PyObject *template) for (Py_ssize_t i = 0; i < n; i++) { Py_ssize_t index = PyLong_AsSsize_t(PyList_GET_ITEM(template, 2*i+1)); if (index == -1 && PyErr_Occurred()) { + Py_SET_SIZE(self, i); Py_DECREF(self); return NULL; } if (index < 0) { + Py_SET_SIZE(self, i); goto bad_template; } self->items[i].index = index; From 48f58e02430f046d4b039cefce3856b934b02627 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 8 Jul 2023 01:52:50 -0700 Subject: [PATCH 0327/1206] [3.12] gh-101880: add link to object.__hash__() in hash() builtin documentation (GH-101883) (#106546) gh-101880: add link to object.__hash__() in hash() builtin documentation (GH-101883) (cherry picked from commit ec7180bd1b3c156d4484e8e6babc5ecb707420e3) Co-authored-by: Owain Davies <116417456+OTheDev@users.noreply.github.com> --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 9b9731e9189853..d8091f0b093aab 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -794,7 +794,7 @@ are always available. They are listed here in alphabetical order. For objects with custom :meth:`__hash__` methods, note that :func:`hash` truncates the return value based on the bit width of the host machine. - See :meth:`__hash__` for details. + See :meth:`__hash__ ` for details. .. function:: help() help(request) From 60ade0cb2929b180a50feb288a760038a072ef76 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 8 Jul 2023 05:15:54 -0700 Subject: [PATCH 0328/1206] [3.12] gh-106510: Fix DEBUG output for atomic group (GH-106511) (GH-106548) (cherry picked from commit 74ec02e9490d8aa086aa9ad9d1d34d2ad999b5af) Co-authored-by: Serhiy Storchaka --- Lib/re/_parser.py | 4 +++- Lib/test/test_re.py | 5 ++++- .../Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst diff --git a/Lib/re/_parser.py b/Lib/re/_parser.py index 5709acb6267238..74bda2f103083c 100644 --- a/Lib/re/_parser.py +++ b/Lib/re/_parser.py @@ -114,7 +114,6 @@ def __init__(self, state, data=None): self.width = None def dump(self, level=0): - nl = True seqtypes = (tuple, list) for op, av in self.data: print(level*" " + str(op), end='') @@ -136,6 +135,9 @@ def dump(self, level=0): if item_no: print(level*" " + "ELSE") item_no.dump(level+1) + elif isinstance(av, SubPattern): + print() + av.dump(level+1) elif isinstance(av, seqtypes): nl = False for a in av: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index a05a1c99def0bc..406b665c192df4 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2512,7 +2512,10 @@ def test_debug_flag(self): def test_atomic_group(self): self.assertEqual(get_debug_out(r'(?>ab?)'), '''\ -ATOMIC_GROUP [(LITERAL, 97), (MAX_REPEAT, (0, 1, [(LITERAL, 98)]))] +ATOMIC_GROUP + LITERAL 97 + MAX_REPEAT 0 1 + LITERAL 98 0. INFO 4 0b0 1 2 (to 5) 5: ATOMIC_GROUP 11 (to 17) diff --git a/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst b/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst new file mode 100644 index 00000000000000..e0646fa9bc0211 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst @@ -0,0 +1 @@ +Improve debug output for atomic groups in regular expressions. From 559267fcd359501679530c3ff1ccfa8e9c95ea66 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 9 Jul 2023 03:14:39 -0700 Subject: [PATCH 0329/1206] [3.12] Move implementation specific RE tests to separate class (GH-106563) (#106564) Move implementation specific RE tests to separate class (GH-106563) (cherry picked from commit 8cb6f9761e3c1cff3210697e3670b57591bf2e7a) Co-authored-by: Serhiy Storchaka --- Lib/test/test_re.py | 135 ++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 406b665c192df4..50b9ad701f0ce7 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1046,33 +1046,6 @@ def test_ignore_case_range(self): def test_category(self): self.assertEqual(re.match(r"(\s)", " ").group(1), " ") - @cpython_only - def test_case_helpers(self): - import _sre - for i in range(128): - c = chr(i) - lo = ord(c.lower()) - self.assertEqual(_sre.ascii_tolower(i), lo) - self.assertEqual(_sre.unicode_tolower(i), lo) - iscased = c in string.ascii_letters - self.assertEqual(_sre.ascii_iscased(i), iscased) - self.assertEqual(_sre.unicode_iscased(i), iscased) - - for i in list(range(128, 0x1000)) + [0x10400, 0x10428]: - c = chr(i) - self.assertEqual(_sre.ascii_tolower(i), i) - if i != 0x0130: - self.assertEqual(_sre.unicode_tolower(i), ord(c.lower())) - iscased = c != c.lower() or c != c.upper() - self.assertFalse(_sre.ascii_iscased(i)) - self.assertEqual(_sre.unicode_iscased(i), - c != c.lower() or c != c.upper()) - - self.assertEqual(_sre.ascii_tolower(0x0130), 0x0130) - self.assertEqual(_sre.unicode_tolower(0x0130), ord('i')) - self.assertFalse(_sre.ascii_iscased(0x0130)) - self.assertTrue(_sre.unicode_iscased(0x0130)) - def test_not_literal(self): self.assertEqual(re.search(r"\s([^a])", " b").group(1), "b") self.assertEqual(re.search(r"\s([^a]*)", " bb").group(1), "bb") @@ -1769,20 +1742,6 @@ def test_bug_6509(self): pat = re.compile(b'..') self.assertEqual(pat.sub(lambda m: b'bytes', b'a5'), b'bytes') - def test_dealloc(self): - # issue 3299: check for segfault in debug build - import _sre - # the overflow limit is different on wide and narrow builds and it - # depends on the definition of SRE_CODE (see sre.h). - # 2**128 should be big enough to overflow on both. For smaller values - # a RuntimeError is raised instead of OverflowError. - long_overflow = 2**128 - self.assertRaises(TypeError, re.finditer, "a", {}) - with self.assertRaises(OverflowError): - _sre.compile("abc", 0, [long_overflow], 0, {}, ()) - with self.assertRaises(TypeError): - _sre.compile({}, 0, [], 0, [], []) - def test_search_dot_unicode(self): self.assertTrue(re.search("123.*-", '123abc-')) self.assertTrue(re.search("123.*-", '123\xe9-')) @@ -1840,21 +1799,6 @@ def test_repeat_minmax_overflow(self): self.assertRaises(OverflowError, re.compile, r".{%d,}?" % 2**128) self.assertRaises(OverflowError, re.compile, r".{%d,%d}" % (2**129, 2**128)) - @cpython_only - def test_repeat_minmax_overflow_maxrepeat(self): - try: - from _sre import MAXREPEAT - except ImportError: - self.skipTest('requires _sre.MAXREPEAT constant') - string = "x" * 100000 - self.assertIsNone(re.match(r".{%d}" % (MAXREPEAT - 1), string)) - self.assertEqual(re.match(r".{,%d}" % (MAXREPEAT - 1), string).span(), - (0, 100000)) - self.assertIsNone(re.match(r".{%d,}?" % (MAXREPEAT - 1), string)) - self.assertRaises(OverflowError, re.compile, r".{%d}" % MAXREPEAT) - self.assertRaises(OverflowError, re.compile, r".{,%d}" % MAXREPEAT) - self.assertRaises(OverflowError, re.compile, r".{%d,}?" % MAXREPEAT) - def test_backref_group_name_in_exception(self): # Issue 17341: Poor error message when compiling invalid regex self.checkPatternError('(?P=)', @@ -2441,16 +2385,6 @@ def test_regression_gh94675(self): p.terminate() p.join() - def test_sre_template_invalid_group_index(self): - # see gh-106524 - import _sre - with self.assertRaises(TypeError) as cm: - _sre.template("", ["", -1, ""]) - self.assertIn("invalid template", str(cm.exception)) - with self.assertRaises(TypeError) as cm: - _sre.template("", ["", (), ""]) - self.assertIn("an integer is required", str(cm.exception)) - def get_debug_out(pat): with captured_stdout() as out: @@ -2699,6 +2633,75 @@ def test_deprecated_modules(self): self.assertTrue(hasattr(mod, attr)) del sys.modules[name] + @cpython_only + def test_case_helpers(self): + import _sre + for i in range(128): + c = chr(i) + lo = ord(c.lower()) + self.assertEqual(_sre.ascii_tolower(i), lo) + self.assertEqual(_sre.unicode_tolower(i), lo) + iscased = c in string.ascii_letters + self.assertEqual(_sre.ascii_iscased(i), iscased) + self.assertEqual(_sre.unicode_iscased(i), iscased) + + for i in list(range(128, 0x1000)) + [0x10400, 0x10428]: + c = chr(i) + self.assertEqual(_sre.ascii_tolower(i), i) + if i != 0x0130: + self.assertEqual(_sre.unicode_tolower(i), ord(c.lower())) + iscased = c != c.lower() or c != c.upper() + self.assertFalse(_sre.ascii_iscased(i)) + self.assertEqual(_sre.unicode_iscased(i), + c != c.lower() or c != c.upper()) + + self.assertEqual(_sre.ascii_tolower(0x0130), 0x0130) + self.assertEqual(_sre.unicode_tolower(0x0130), ord('i')) + self.assertFalse(_sre.ascii_iscased(0x0130)) + self.assertTrue(_sre.unicode_iscased(0x0130)) + + @cpython_only + def test_dealloc(self): + # issue 3299: check for segfault in debug build + import _sre + # the overflow limit is different on wide and narrow builds and it + # depends on the definition of SRE_CODE (see sre.h). + # 2**128 should be big enough to overflow on both. For smaller values + # a RuntimeError is raised instead of OverflowError. + long_overflow = 2**128 + self.assertRaises(TypeError, re.finditer, "a", {}) + with self.assertRaises(OverflowError): + _sre.compile("abc", 0, [long_overflow], 0, {}, ()) + with self.assertRaises(TypeError): + _sre.compile({}, 0, [], 0, [], []) + + @cpython_only + def test_repeat_minmax_overflow_maxrepeat(self): + try: + from _sre import MAXREPEAT + except ImportError: + self.skipTest('requires _sre.MAXREPEAT constant') + string = "x" * 100000 + self.assertIsNone(re.match(r".{%d}" % (MAXREPEAT - 1), string)) + self.assertEqual(re.match(r".{,%d}" % (MAXREPEAT - 1), string).span(), + (0, 100000)) + self.assertIsNone(re.match(r".{%d,}?" % (MAXREPEAT - 1), string)) + self.assertRaises(OverflowError, re.compile, r".{%d}" % MAXREPEAT) + self.assertRaises(OverflowError, re.compile, r".{,%d}" % MAXREPEAT) + self.assertRaises(OverflowError, re.compile, r".{%d,}?" % MAXREPEAT) + + @cpython_only + def test_sre_template_invalid_group_index(self): + # see gh-106524 + import _sre + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", -1, ""]) + self.assertIn("invalid template", str(cm.exception)) + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", (), ""]) + self.assertIn("an integer is required", str(cm.exception)) + + class ExternalTests(unittest.TestCase): def test_re_benchmarks(self): From 128a962482ff29325e34b1400c87cc70d509e02a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 9 Jul 2023 14:21:54 -0700 Subject: [PATCH 0330/1206] [3.12] gh-106461: typing: Consolidate docs on `Callable` (GH-106462) (#106574) gh-106461: typing: Consolidate docs on `Callable` (GH-106462) (cherry picked from commit ca8b55c7f54b38e264056148075a8061a7082013) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 130 ++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 55 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 12a20ae543c77b..2a712a4be58904 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -258,18 +258,21 @@ See :pep:`484` for more details. The performance of calling ``NewType`` has been restored to its level in Python 3.9. +.. _annotating-callables: -Callable -======== +Annotating callable objects +=========================== -Frameworks expecting callback functions of specific signatures might be -type hinted using ``Callable[[Arg1Type, Arg2Type], ReturnType]``. +Functions -- or other :term:`callable` objects -- can be annotated using +:class:`collections.abc.Callable` or :data:`typing.Callable`. +``Callable[[int], str]`` signifies a function that takes a single parameter +of type :class:`int` and returns a :class:`str`. For example: .. testcode:: - from collections.abc import Callable + from collections.abc import Callable, Awaitable def feeder(get_next_item: Callable[[], str]) -> None: ... # Body @@ -283,9 +286,49 @@ For example: callback: Callable[[str], Awaitable[None]] = on_update -It is possible to declare the return type of a callable without specifying -the call signature by substituting a literal ellipsis -for the list of arguments in the type hint: ``Callable[..., ReturnType]``. +The subscription syntax must always be used with exactly two values: the +argument list and the return type. The argument list must be a list of types, +a :class:`ParamSpec`, :data:`Concatenate`, or an ellipsis. The return type must +be a single type. + +If a literal ellipsis ``...`` is given as the argument list, it indicates that +a callable with any arbitrary parameter list would be acceptable: + +.. testcode:: + + def concat(x: str, y: str) -> str: + return x + y + + x: Callable[..., str] + x = str # OK + x = concat # Also OK + +``Callable`` cannot express complex signatures such as functions that take a +variadic number of arguments, :func:`overloaded functions `, or +functions that have keyword-only parameters. However, these signatures can be +expressed by defining a :class:`Protocol` class with a +:meth:`~object.__call__` method: + +.. testcode:: + + from collections.abc import Iterable + from typing import Protocol + + class Combiner(Protocol): + def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + + def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes: + for item in data: + ... + + def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]: + ... + def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]: + ... + + batch_proc([], good_cb) # OK + batch_proc([], bad_cb) # Error! Argument 2 has incompatible type because of + # different name and kind in the callback Callables which take other callables as arguments may indicate that their parameter types are dependent on each other using :class:`ParamSpec`. @@ -1043,56 +1086,16 @@ These can be used as types in annotations. They all support subscription using Optional can now be written as ``X | None``. See :ref:`union type expressions`. -.. data:: Callable - - Deprecated alias to :class:`collections.abc.Callable`. - - ``Callable[[int], str]`` signifies a function that takes a single parameter - of type :class:`int` and returns a :class:`str`. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types, a :class:`ParamSpec`, :data:`Concatenate`, - or an ellipsis. The return type must be a single type. - - There is no syntax to indicate optional or keyword arguments; - such function types are rarely used as callback types. - ``Callable[..., ReturnType]`` (literal ellipsis) can be used to - type hint a callable taking any number of arguments and returning - ``ReturnType``. A plain :data:`Callable` is equivalent to - ``Callable[..., Any]``, and in turn to - :class:`collections.abc.Callable`. - - Callables which take other callables as arguments may indicate that their - parameter types are dependent on each other using :class:`ParamSpec`. - Additionally, if that callable adds or removes arguments from other - callables, the :data:`Concatenate` operator may be used. They - take the form ``Callable[ParamSpecVariable, ReturnType]`` and - ``Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]`` - respectively. - - .. deprecated:: 3.9 - :class:`collections.abc.Callable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - - .. versionchanged:: 3.10 - ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more details. - - .. seealso:: - The documentation for :class:`ParamSpec` and :class:`Concatenate` provide - examples of usage with ``Callable``. - .. data:: Concatenate Special form for annotating higher-order functions. - ``Concatenate`` can be used in conjunction with :data:`Callable` and + ``Concatenate`` can be used in conjunction with :ref:`Callable ` and :class:`ParamSpec` to annotate a higher-order callable which adds, removes, or transforms parameters of another callable. Usage is in the form ``Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]``. ``Concatenate`` - is currently only valid when used as the first argument to a :data:`Callable`. + is currently only valid when used as the first argument to a :ref:`Callable `. The last parameter to ``Concatenate`` must be a :class:`ParamSpec` or ellipsis (``...``). @@ -1136,8 +1139,9 @@ These can be used as types in annotations. They all support subscription using .. seealso:: * :pep:`612` -- Parameter Specification Variables (the PEP which introduced - ``ParamSpec`` and ``Concatenate``). - * :class:`ParamSpec` and :class:`Callable`. + ``ParamSpec`` and ``Concatenate``) + * :class:`ParamSpec` + * :ref:`annotating-callables` .. data:: Literal @@ -1893,8 +1897,9 @@ without the dedicated syntax, as documented below. .. seealso:: * :pep:`612` -- Parameter Specification Variables (the PEP which introduced - ``ParamSpec`` and ``Concatenate``). - * :class:`Callable` and :class:`Concatenate`. + ``ParamSpec`` and ``Concatenate``) + * :data:`Concatenate` + * :ref:`annotating-callables` .. data:: ParamSpecArgs .. data:: ParamSpecKwargs @@ -2166,7 +2171,7 @@ types. methods or attributes, not their type signatures or types. For example, :class:`ssl.SSLObject` is a class, therefore it passes an :func:`issubclass` - check against :data:`Callable`. However, the + check against :ref:`Callable `. However, the ``ssl.SSLObject.__init__`` method exists only to raise a :exc:`TypeError` with a more informative message, therefore making it impossible to call (instantiate) :class:`ssl.SSLObject`. @@ -3496,6 +3501,21 @@ Aliases to other ABCs in :mod:`collections.abc` :class:`collections.abc.Iterator` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. +.. data:: Callable + + Deprecated alias to :class:`collections.abc.Callable`. + + See :ref:`annotating-callables` for details on how to use + :class:`collections.abc.Callable` and ``typing.Callable`` in type annotations. + + .. deprecated:: 3.9 + :class:`collections.abc.Callable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + + .. versionchanged:: 3.10 + ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. + See :pep:`612` for more details. + .. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) Deprecated alias to :class:`collections.abc.Generator`. From 0481b805d6631063887fcbcc27684aa8a2576fae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 9 Jul 2023 20:42:22 -0700 Subject: [PATCH 0331/1206] [3.12] Clarify how topics.py gets created. (GH-106121) (#106579) Clarify how topics.py gets created. (GH-106121) When changing docs, it was easy to find text in topics.py, and I wondered whether I was supposed to edit it. Thankfully, the top of the file says it's auto-generated, so I knew I didn't have to edit it. But I didn't know what started the auto-generation process. It's part of the release process, so I'll leave a note here for future editors. (cherry picked from commit dac1e364901d3668742e6eecc2ce63586330c11f) Co-authored-by: Ned Batchelder --- Doc/tools/extensions/pyspecific.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 8a9e2fc61327e7..003229d8a59754 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -559,6 +559,7 @@ def finish(self): try: f.write('# -*- coding: utf-8 -*-\n'.encode('utf-8')) f.write(('# Autogenerated by Sphinx on %s\n' % asctime()).encode('utf-8')) + f.write('# as part of the release process.\n'.encode('utf-8')) f.write(('topics = ' + pformat(self.topics) + '\n').encode('utf-8')) finally: f.close() From 41057b2ffeb5a8cb492e37e5503ab76ed1a3082d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 10 Jul 2023 10:12:15 -0700 Subject: [PATCH 0332/1206] [3.12] gh-105227: Add PyType_GetDict() (GH-105747) (#106600) gh-105227: Add PyType_GetDict() (GH-105747) This compensates for static builtin types having `tp_dict` set to `NULL`. (cherry picked from commit a840806d338805fe74a9de01081d30da7605a29f) Co-authored-by: Eric Snow Co-authored-by: Petr Viktorin --- Doc/c-api/type.rst | 17 +++++++++++++ Doc/c-api/typeobj.rst | 14 ++++++++++- Include/cpython/object.h | 1 + ...-06-13-14-24-55.gh-issue-105227.HDL9aF.rst | 5 ++++ Modules/_testcapimodule.c | 25 +++++++++++++++++++ Objects/typeobject.c | 7 ++++++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index c99c7ef93a45df..a5f333e2a31e03 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -50,6 +50,23 @@ Type Objects The return type is now ``unsigned long`` rather than ``long``. +.. c:function:: PyObject* PyType_GetDict(PyTypeObject* type) + + Return the type object's internal namespace, which is otherwise only + exposed via a read-only proxy (``cls.__dict__``). This is a + replacement for accessing :c:member:`~PyTypeObject.tp_dict` directly. + The returned dictionary must be treated as read-only. + + This function is meant for specific embedding and language-binding cases, + where direct access to the dict is necessary and indirect access + (e.g. via the proxy or :c:func:`PyObject_GetAttr`) isn't adequate. + + Extension modules should continue to use ``tp_dict``, + directly or indirectly, when setting up their own types. + + .. versionadded:: 3.12 + + .. c:function:: void PyType_Modified(PyTypeObject *type) Invalidate the internal lookup cache for the type and all of its diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 239c191457f516..7249cfe79c32e9 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1717,7 +1717,19 @@ and :c:type:`PyType_Type` effectively act as defaults.) called; it may also be initialized to a dictionary containing initial attributes for the type. Once :c:func:`PyType_Ready` has initialized the type, extra attributes for the type may be added to this dictionary only if they don't - correspond to overloaded operations (like :meth:`__add__`). + correspond to overloaded operations (like :meth:`__add__`). Once + initialization for the type has finished, this field should be + treated as read-only. + + Some types may not store their dictionary in this slot. + Use :c:func:`PyType_GetDict` to retreive the dictionary for an arbitrary + type. + + .. versionchanged:: 3.12 + + Internals detail: For static builtin types, this is always ``NULL``. + Instead, the dict for such types is stored on ``PyInterpreterState``. + Use :c:func:`PyType_GetDict` to get the dict for an arbitrary type. **Inheritance:** diff --git a/Include/cpython/object.h b/Include/cpython/object.h index d8eff691039d24..c5d0851a4b11bf 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -283,6 +283,7 @@ PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject * PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *); PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *); PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, PyModuleDef *); +PyAPI_FUNC(PyObject *) PyType_GetDict(PyTypeObject *); PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); PyAPI_FUNC(void) _Py_BreakPoint(void); diff --git a/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst b/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst new file mode 100644 index 00000000000000..846663621e8689 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst @@ -0,0 +1,5 @@ +The new :c:func:`PyType_GetDict` provides the dictionary for the given type +object that is normally exposed by ``cls.__dict__``. Normally it's +sufficient to use :c:member:`~PyTypeObject.tp_dict`, but for the static +builtin types :c:member:`!tp_dict` is now always ``NULL``. :c:func:`!PyType_GetDict()` +provides the correct dict object instead. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 04a880021147e2..6523734131c2de 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -640,6 +640,30 @@ test_get_type_qualname(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } +static PyObject * +test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + /* Test for PyType_GetDict */ + + // Assert ints have a `to_bytes` method + PyObject *long_dict = PyType_GetDict(&PyLong_Type); + assert(long_dict); + assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref + Py_DECREF(long_dict); + + // Make a new type, add an attribute to it and assert it's there + PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec); + assert(HeapTypeNameType); + assert(PyObject_SetAttrString( + HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0); + PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType); + assert(type_dict); + assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref + Py_DECREF(HeapTypeNameType); + Py_DECREF(type_dict); + Py_RETURN_NONE; +} + static PyObject * pyobject_repr_from_null(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -3347,6 +3371,7 @@ static PyMethodDef TestMethods[] = { {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, {"test_get_type_name", test_get_type_name, METH_NOARGS}, {"test_get_type_qualname", test_get_type_qualname, METH_NOARGS}, + {"test_get_type_dict", test_get_type_dict, METH_NOARGS}, {"_test_thread_state", test_thread_state, METH_VARARGS}, #ifndef MS_WINDOWS {"_spawn_pthread_waiter", spawn_pthread_waiter, METH_NOARGS}, diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 966471e9341a85..6662379515f95d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -238,6 +238,13 @@ _PyType_GetDict(PyTypeObject *self) return lookup_tp_dict(self); } +PyObject * +PyType_GetDict(PyTypeObject *self) +{ + PyObject *dict = lookup_tp_dict(self); + return _Py_XNewRef(dict); +} + static inline void set_tp_dict(PyTypeObject *self, PyObject *dict) { From 2da967ea14a49d1ca3e2d22d83ce9f6ffd5e6186 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 10 Jul 2023 20:58:58 +0300 Subject: [PATCH 0333/1206] [3.12] gh-99593: Add tests for Unicode C API (part 3) (GH-104728) (GH-106595) Add tests for codecs. (cherry picked from commit 51ea664d18938645521bdd128a3c55f9c197644c) --- Lib/test/test_capi/test_codecs.py | 466 +++++++++++++++++++++++++++ Modules/_testcapi/unicode.c | 507 +++++++++++++++++++++++++++++- 2 files changed, 972 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_capi/test_codecs.py b/Lib/test/test_capi/test_codecs.py index e46726192aa05b..682c56979c6dfa 100644 --- a/Lib/test/test_capi/test_codecs.py +++ b/Lib/test/test_capi/test_codecs.py @@ -1,10 +1,95 @@ import unittest +import sys from test.support import import_helper _testcapi = import_helper.import_module('_testcapi') +NULL = None + class CAPITest(unittest.TestCase): + # TODO: Test the following functions: + # + # PyUnicode_BuildEncodingMap + # PyUnicode_FSConverter + # PyUnicode_FSDecoder + # PyUnicode_DecodeMBCS + # PyUnicode_DecodeMBCSStateful + # PyUnicode_DecodeCodePageStateful + # PyUnicode_AsMBCSString + # PyUnicode_EncodeCodePage + # PyUnicode_DecodeLocaleAndSize + # PyUnicode_DecodeLocale + # PyUnicode_EncodeLocale + # PyUnicode_DecodeFSDefault + # PyUnicode_DecodeFSDefaultAndSize + # PyUnicode_EncodeFSDefault + + def test_fromencodedobject(self): + """Test PyUnicode_FromEncodedObject()""" + fromencodedobject = _testcapi.unicode_fromencodedobject + + self.assertEqual(fromencodedobject(b'abc', NULL), 'abc') + self.assertEqual(fromencodedobject(b'abc', 'ascii'), 'abc') + b = b'a\xc2\xa1\xe4\xbd\xa0\xf0\x9f\x98\x80' + s = 'a\xa1\u4f60\U0001f600' + self.assertEqual(fromencodedobject(b, NULL), s) + self.assertEqual(fromencodedobject(b, 'utf-8'), s) + self.assertEqual(fromencodedobject(b, 'latin1'), b.decode('latin1')) + self.assertRaises(UnicodeDecodeError, fromencodedobject, b, 'ascii') + self.assertEqual(fromencodedobject(b, 'ascii', 'replace'), + 'a' + '\ufffd'*9) + self.assertEqual(fromencodedobject(bytearray(b), NULL), s) + self.assertEqual(fromencodedobject(bytearray(b), 'utf-8'), s) + self.assertRaises(LookupError, fromencodedobject, b'abc', 'foo') + self.assertRaises(LookupError, fromencodedobject, b, 'ascii', 'foo') + self.assertRaises(TypeError, fromencodedobject, 'abc', NULL) + self.assertRaises(TypeError, fromencodedobject, 'abc', 'ascii') + self.assertRaises(TypeError, fromencodedobject, [], NULL) + self.assertRaises(TypeError, fromencodedobject, [], 'ascii') + self.assertRaises(SystemError, fromencodedobject, NULL, NULL) + self.assertRaises(SystemError, fromencodedobject, NULL, 'ascii') + + def test_decode(self): + """Test PyUnicode_Decode()""" + decode = _testcapi.unicode_decode + + self.assertEqual(decode(b'[\xe2\x82\xac]', 'utf-8'), '[\u20ac]') + self.assertEqual(decode(b'[\xa4]', 'iso8859-15'), '[\u20ac]') + self.assertEqual(decode(b'[\xa4]', 'iso8859-15', 'strict'), '[\u20ac]') + self.assertRaises(UnicodeDecodeError, decode, b'[\xa4]', 'utf-8') + self.assertEqual(decode(b'[\xa4]', 'utf-8', 'replace'), '[\ufffd]') + + self.assertEqual(decode(b'[\xe2\x82\xac]', NULL), '[\u20ac]') + self.assertEqual(decode(b'[\xa4]', NULL, 'replace'), '[\ufffd]') + + self.assertRaises(LookupError, decode, b'\xa4', 'foo') + self.assertRaises(LookupError, decode, b'\xa4', 'utf-8', 'foo') + # TODO: Test PyUnicode_Decode() with NULL as data and + # negative size. + + def test_asencodedstring(self): + """Test PyUnicode_AsEncodedString()""" + asencodedstring = _testcapi.unicode_asencodedstring + + self.assertEqual(asencodedstring('abc', NULL), b'abc') + self.assertEqual(asencodedstring('abc', 'ascii'), b'abc') + s = 'a\xa1\u4f60\U0001f600' + b = b'a\xc2\xa1\xe4\xbd\xa0\xf0\x9f\x98\x80' + self.assertEqual(asencodedstring(s, NULL), b) + self.assertEqual(asencodedstring(s, 'utf-8'), b) + self.assertEqual(asencodedstring('\xa1\xa2', 'latin1'), b'\xa1\xa2') + self.assertRaises(UnicodeEncodeError, asencodedstring, '\xa1\xa2', 'ascii') + self.assertEqual(asencodedstring(s, 'ascii', 'replace'), b'a???') + + self.assertRaises(LookupError, asencodedstring, 'abc', 'foo') + self.assertRaises(LookupError, asencodedstring, s, 'ascii', 'foo') + self.assertRaises(TypeError, asencodedstring, b'abc', NULL) + self.assertRaises(TypeError, asencodedstring, b'abc', 'ascii') + self.assertRaises(TypeError, asencodedstring, [], NULL) + self.assertRaises(TypeError, asencodedstring, [], 'ascii') + # CRASHES asencodedstring(NULL, NULL) + # CRASHES asencodedstring(NULL, 'ascii') def test_decodeutf8(self): """Test PyUnicode_DecodeUTF8()""" @@ -49,6 +134,387 @@ def test_decodeutf8stateful(self): # TODO: Test PyUnicode_DecodeUTF8Stateful() with NULL as the address of # "consumed". + def test_asutf8string(self): + """Test PyUnicode_AsUTF8String()""" + asutf8string = _testcapi.unicode_asutf8string + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + self.assertEqual(asutf8string(s), s.encode('utf-8')) + + self.assertRaises(UnicodeEncodeError, asutf8string, '\ud8ff') + self.assertRaises(TypeError, asutf8string, b'abc') + self.assertRaises(TypeError, asutf8string, []) + # CRASHES asutf8string(NULL) + + def test_decodeutf16(self): + """Test PyUnicode_DecodeUTF16()""" + decodeutf16 = _testcapi.unicode_decodeutf16 + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-16') + self.assertEqual(decodeutf16(0, b), (naturalbyteorder, s)) + b = s.encode('utf-16le') + self.assertEqual(decodeutf16(-1, b), (-1, s)) + self.assertEqual(decodeutf16(0, b'\xff\xfe'+b), (-1, s)) + b = s.encode('utf-16be') + self.assertEqual(decodeutf16(1, b), (1, s)) + self.assertEqual(decodeutf16(0, b'\xfe\xff'+b), (1, s)) + + self.assertRaises(UnicodeDecodeError, decodeutf16, -1, b'a') + self.assertRaises(UnicodeDecodeError, decodeutf16, 1, b'a') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xff\xfea') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xfe\xffa') + + self.assertRaises(UnicodeDecodeError, decodeutf16, -1, b'\x00\xde') + self.assertRaises(UnicodeDecodeError, decodeutf16, 1, b'\xde\x00') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xde\xde') + self.assertEqual(decodeutf16(-1, b'\x00\xde', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(1, b'\xde\x00', 'replace'), (1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xde\xde', 'replace'), (0, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xff\xfe\x00\xde', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xfe\xff\xde\x00', 'replace'), (1, '\ufffd')) + + self.assertRaises(UnicodeDecodeError, decodeutf16, -1, b'\x3d\xd8') + self.assertRaises(UnicodeDecodeError, decodeutf16, 1, b'\xd8\x3d') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xd8\xd8') + self.assertEqual(decodeutf16(-1, b'\x3d\xd8', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(1, b'\xd8\x3d', 'replace'), (1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xd8\xd8', 'replace'), (0, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xff\xfe\x3d\xd8', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xfe\xff\xd8\x3d', 'replace'), (1, '\ufffd')) + + self.assertRaises(LookupError, decodeutf16, -1, b'\x00\xde', 'foo') + self.assertRaises(LookupError, decodeutf16, 1, b'\xde\x00', 'foo') + self.assertRaises(LookupError, decodeutf16, 0, b'\xde\xde', 'foo') + # TODO: Test PyUnicode_DecodeUTF16() with NULL as data and + # negative size. + + def test_decodeutf16stateful(self): + """Test PyUnicode_DecodeUTF16Stateful()""" + decodeutf16stateful = _testcapi.unicode_decodeutf16stateful + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-16') + self.assertEqual(decodeutf16stateful(0, b), (naturalbyteorder, s, len(b))) + b = s.encode('utf-16le') + self.assertEqual(decodeutf16stateful(-1, b), (-1, s, len(b))) + self.assertEqual(decodeutf16stateful(0, b'\xff\xfe'+b), (-1, s, len(b)+2)) + b = s.encode('utf-16be') + self.assertEqual(decodeutf16stateful(1, b), (1, s, len(b))) + self.assertEqual(decodeutf16stateful(0, b'\xfe\xff'+b), (1, s, len(b)+2)) + + self.assertEqual(decodeutf16stateful(-1, b'\x61\x00\x3d'), (-1, 'a', 2)) + self.assertEqual(decodeutf16stateful(-1, b'\x61\x00\x3d\xd8'), (-1, 'a', 2)) + self.assertEqual(decodeutf16stateful(-1, b'\x61\x00\x3d\xd8\x00'), (-1, 'a', 2)) + self.assertEqual(decodeutf16stateful(1, b'\x00\x61\xd8'), (1, 'a', 2)) + self.assertEqual(decodeutf16stateful(1, b'\x00\x61\xd8\x3d'), (1, 'a', 2)) + self.assertEqual(decodeutf16stateful(1, b'\x00\x61\xd8\x3d\xde'), (1, 'a', 2)) + self.assertEqual(decodeutf16stateful(0, b'\xff\xfe\x61\x00\x3d\xd8\x00'), (-1, 'a', 4)) + self.assertEqual(decodeutf16stateful(0, b'\xfe\xff\x00\x61\xd8\x3d\xde'), (1, 'a', 4)) + + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, -1, b'\x00\xde') + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, 1, b'\xde\x00') + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, 0, b'\xde\xde') + self.assertEqual(decodeutf16stateful(-1, b'\x00\xde', 'replace'), (-1, '\ufffd', 2)) + self.assertEqual(decodeutf16stateful(1, b'\xde\x00', 'replace'), (1, '\ufffd', 2)) + self.assertEqual(decodeutf16stateful(0, b'\xde\xde', 'replace'), (0, '\ufffd', 2)) + self.assertEqual(decodeutf16stateful(0, b'\xff\xfe\x00\xde', 'replace'), (-1, '\ufffd', 4)) + self.assertEqual(decodeutf16stateful(0, b'\xfe\xff\xde\x00', 'replace'), (1, '\ufffd', 4)) + + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, -1, b'\x3d\xd8\x61\x00') + self.assertEqual(decodeutf16stateful(-1, b'\x3d\xd8\x61\x00', 'replace'), (-1, '\ufffda', 4)) + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, 1, b'\xd8\x3d\x00\x61') + self.assertEqual(decodeutf16stateful(1, b'\xd8\x3d\x00\x61', 'replace'), (1, '\ufffda', 4)) + + self.assertRaises(LookupError, decodeutf16stateful, -1, b'\x00\xde', 'foo') + self.assertRaises(LookupError, decodeutf16stateful, 1, b'\xde\x00', 'foo') + self.assertRaises(LookupError, decodeutf16stateful, 0, b'\xde\xde', 'foo') + # TODO: Test PyUnicode_DecodeUTF16Stateful() with NULL as data and + # negative size. + # TODO: Test PyUnicode_DecodeUTF16Stateful() with NULL as the address of + # "consumed". + + def test_asutf16string(self): + """Test PyUnicode_AsUTF16String()""" + asutf16string = _testcapi.unicode_asutf16string + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + self.assertEqual(asutf16string(s), s.encode('utf-16')) + + self.assertRaises(UnicodeEncodeError, asutf16string, '\ud8ff') + self.assertRaises(TypeError, asutf16string, b'abc') + self.assertRaises(TypeError, asutf16string, []) + # CRASHES asutf16string(NULL) + + def test_decodeutf32(self): + """Test PyUnicode_DecodeUTF8()""" + decodeutf32 = _testcapi.unicode_decodeutf32 + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-32') + self.assertEqual(decodeutf32(0, b), (naturalbyteorder, s)) + b = s.encode('utf-32le') + self.assertEqual(decodeutf32(-1, b), (-1, s)) + self.assertEqual(decodeutf32(0, b'\xff\xfe\x00\x00'+b), (-1, s)) + b = s.encode('utf-32be') + self.assertEqual(decodeutf32(1, b), (1, s)) + self.assertEqual(decodeutf32(0, b'\x00\x00\xfe\xff'+b), (1, s)) + + self.assertRaises(UnicodeDecodeError, decodeutf32, -1, b'\x61\x00\x00\x00\x00') + self.assertRaises(UnicodeDecodeError, decodeutf32, 1, b'\x00\x00\x00\x61\x00') + self.assertRaises(UnicodeDecodeError, decodeutf32, 0, b'\xff\xfe\x00\x00\x61\x00\x00\x00\x00') + self.assertRaises(UnicodeDecodeError, decodeutf32, 0, b'\x00\x00\xfe\xff\x00\x00\x00\x61\x00') + + self.assertRaises(UnicodeDecodeError, decodeutf32, -1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32, 1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32, 0, b'\xff\xff\xff\xff') + self.assertEqual(decodeutf32(-1, b'\xff\xff\xff\xff', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf32(1, b'\xff\xff\xff\xff', 'replace'), (1, '\ufffd')) + self.assertEqual(decodeutf32(0, b'\xff\xff\xff\xff', 'replace'), (0, '\ufffd')) + self.assertEqual(decodeutf32(0, b'\xff\xfe\x00\x00\xff\xff\xff\xff', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf32(0, b'\x00\x00\xfe\xff\xff\xff\xff\xff', 'replace'), (1, '\ufffd')) + + self.assertRaises(UnicodeDecodeError, decodeutf32, -1, b'\x3d\xd8\x00\x00') + self.assertEqual(decodeutf32(-1, b'\x3d\xd8\x00\x00', 'replace'), (-1, '\ufffd')) + self.assertRaises(UnicodeDecodeError, decodeutf32, 1, b'\x00\x00\xd8\x3d') + self.assertEqual(decodeutf32(1, b'\x00\x00\xd8\x3d', 'replace'), (1, '\ufffd')) + + self.assertRaises(LookupError, decodeutf32, -1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32, 1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32, 0, b'\xff\xff\xff\xff', 'foo') + # TODO: Test PyUnicode_DecodeUTF32() with NULL as data and + # negative size. + + def test_decodeutf32stateful(self): + """Test PyUnicode_DecodeUTF32Stateful()""" + decodeutf32stateful = _testcapi.unicode_decodeutf32stateful + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-32') + self.assertEqual(decodeutf32stateful(0, b), (naturalbyteorder, s, len(b))) + b = s.encode('utf-32le') + self.assertEqual(decodeutf32stateful(-1, b), (-1, s, len(b))) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00'+b), (-1, s, len(b)+4)) + b = s.encode('utf-32be') + self.assertEqual(decodeutf32stateful(1, b), (1, s, len(b))) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff'+b), (1, s, len(b)+4)) + + self.assertEqual(decodeutf32stateful(-1, b'\x61\x00\x00\x00\x00'), (-1, 'a', 4)) + self.assertEqual(decodeutf32stateful(-1, b'\x61\x00\x00\x00\x00\xf6'), (-1, 'a', 4)) + self.assertEqual(decodeutf32stateful(-1, b'\x61\x00\x00\x00\x00\xf6\x01'), (-1, 'a', 4)) + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\x00\x61\x00'), (1, 'a', 4)) + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\x00\x61\x00\x01'), (1, 'a', 4)) + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\x00\x61\x00\x01\xf6'), (1, 'a', 4)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00\x61\x00\x00\x00\x00\xf6\x01'), (-1, 'a', 8)) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff\x00\x00\x00\x61\x00\x01\xf6'), (1, 'a', 8)) + + for b in b'\xff', b'\xff\xff', b'\xff\xff\xff': + self.assertEqual(decodeutf32stateful(-1, b), (-1, '', 0)) + self.assertEqual(decodeutf32stateful(1, b), (1, '', 0)) + self.assertEqual(decodeutf32stateful(0, b), (0, '', 0)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00'+b), (-1, '', 4)) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff'+b), (1, '', 4)) + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, -1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, 1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, 0, b'\xff\xff\xff\xff') + self.assertEqual(decodeutf32stateful(-1, b'\xff\xff\xff\xff', 'replace'), (-1, '\ufffd', 4)) + self.assertEqual(decodeutf32stateful(1, b'\xff\xff\xff\xff', 'replace'), (1, '\ufffd', 4)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xff\xff\xff', 'replace'), (0, '\ufffd', 4)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00\xff\xff\xff\xff', 'replace'), (-1, '\ufffd', 8)) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff\xff\xff\xff\xff', 'replace'), (1, '\ufffd', 8)) + + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, -1, b'\x3d\xd8\x00\x00') + self.assertEqual(decodeutf32stateful(-1, b'\x3d\xd8\x00\x00', 'replace'), (-1, '\ufffd', 4)) + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, 1, b'\x00\x00\xd8\x3d') + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\xd8\x3d', 'replace'), (1, '\ufffd', 4)) + + self.assertRaises(LookupError, decodeutf32stateful, -1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32stateful, 1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32stateful, 0, b'\xff\xff\xff\xff', 'foo') + # TODO: Test PyUnicode_DecodeUTF32Stateful() with NULL as data and + # negative size. + # TODO: Test PyUnicode_DecodeUTF32Stateful() with NULL as the address of + # "consumed". + + def test_asutf32string(self): + """Test PyUnicode_AsUTF32String()""" + asutf32string = _testcapi.unicode_asutf32string + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + self.assertEqual(asutf32string(s), s.encode('utf-32')) + + self.assertRaises(UnicodeEncodeError, asutf32string, '\ud8ff') + self.assertRaises(TypeError, asutf32string, b'abc') + self.assertRaises(TypeError, asutf32string, []) + # CRASHES asutf32string(NULL) + + def test_decodelatin1(self): + """Test PyUnicode_DecodeLatin1()""" + decodelatin1 = _testcapi.unicode_decodelatin1 + + self.assertEqual(decodelatin1(b'abc'), 'abc') + self.assertEqual(decodelatin1(b'abc', 'strict'), 'abc') + self.assertEqual(decodelatin1(b'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decodelatin1(b'\xa1\xa2', 'strict'), '\xa1\xa2') + # TODO: Test PyUnicode_DecodeLatin1() with NULL as data and + # negative size. + + def test_aslatin1string(self): + """Test PyUnicode_AsLatin1String()""" + aslatin1string = _testcapi.unicode_aslatin1string + + self.assertEqual(aslatin1string('abc'), b'abc') + self.assertEqual(aslatin1string('\xa1\xa2'), b'\xa1\xa2') + + self.assertRaises(UnicodeEncodeError, aslatin1string, '\u4f60') + self.assertRaises(TypeError, aslatin1string, b'abc') + self.assertRaises(TypeError, aslatin1string, []) + # CRASHES aslatin1string(NULL) + + def test_decodeascii(self): + """Test PyUnicode_DecodeASCII()""" + decodeascii = _testcapi.unicode_decodeascii + + self.assertEqual(decodeascii(b'abc'), 'abc') + self.assertEqual(decodeascii(b'abc', 'strict'), 'abc') + + self.assertRaises(UnicodeDecodeError, decodeascii, b'\xff') + self.assertEqual(decodeascii(b'a\xff', 'replace'), 'a\ufffd') + self.assertEqual(decodeascii(b'a\xffb', 'replace'), 'a\ufffdb') + + self.assertRaises(LookupError, decodeascii, b'a\xff', 'foo') + # TODO: Test PyUnicode_DecodeASCII() with NULL as data and + # negative size. + + def test_asasciistring(self): + """Test PyUnicode_AsASCIIString()""" + asasciistring = _testcapi.unicode_asasciistring + + self.assertEqual(asasciistring('abc'), b'abc') + + self.assertRaises(UnicodeEncodeError, asasciistring, '\x80') + self.assertRaises(TypeError, asasciistring, b'abc') + self.assertRaises(TypeError, asasciistring, []) + # CRASHES asasciistring(NULL) + + def test_decodecharmap(self): + """Test PyUnicode_DecodeCharmap()""" + decodecharmap = _testcapi.unicode_decodecharmap + + self.assertEqual(decodecharmap(b'\3\0\7', {0: 'a', 3: 'b', 7: 'c'}), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', ['a', 'b', 'c']), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', 'abc'), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', ['\xa1', '\xa2', '\xa3']), '\xa2\xa1\xa3') + self.assertEqual(decodecharmap(b'\1\0\2', ['\u4f60', '\u597d', '\u4e16']), '\u597d\u4f60\u4e16') + self.assertEqual(decodecharmap(b'\1\0\2', ['\U0001f600', '\U0001f601', '\U0001f602']), '\U0001f601\U0001f600\U0001f602') + + self.assertEqual(decodecharmap(b'\1\0\2', [97, 98, 99]), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', ['', 'b', 'cd']), 'bcd') + + self.assertRaises(UnicodeDecodeError, decodecharmap, b'\0', {}) + self.assertRaises(UnicodeDecodeError, decodecharmap, b'\0', {0: None}) + self.assertEqual(decodecharmap(b'\1\0\2', [None, 'b', 'c'], 'replace'), 'b\ufffdc') + self.assertEqual(decodecharmap(b'\1\0\2\xff', NULL), '\1\0\2\xff') + self.assertRaises(TypeError, decodecharmap, b'\0', 42) + + # TODO: Test PyUnicode_DecodeCharmap() with NULL as data and + # negative size. + + def test_ascharmapstring(self): + """Test PyUnicode_AsCharmapString()""" + ascharmapstring = _testcapi.unicode_ascharmapstring + + self.assertEqual(ascharmapstring('abc', {97: 3, 98: 0, 99: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('\xa1\xa2\xa3', {0xa1: 3, 0xa2: 0, 0xa3: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('\u4f60\u597d\u4e16', {0x4f60: 3, 0x597d: 0, 0x4e16: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('\U0001f600\U0001f601\U0001f602', {0x1f600: 3, 0x1f601: 0, 0x1f602: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('abc', {97: 3, 98: b'', 99: b'spam'}), b'\3spam') + + self.assertRaises(UnicodeEncodeError, ascharmapstring, 'a', {}) + self.assertRaises(UnicodeEncodeError, ascharmapstring, 'a', {97: None}) + self.assertRaises(TypeError, ascharmapstring, b'a', {}) + self.assertRaises(TypeError, ascharmapstring, [], {}) + self.assertRaises(TypeError, ascharmapstring, 'a', NULL) + # CRASHES ascharmapstring(NULL, {}) + + def test_decodeunicodeescape(self): + """Test PyUnicode_DecodeUnicodeEscape()""" + decodeunicodeescape = _testcapi.unicode_decodeunicodeescape + + self.assertEqual(decodeunicodeescape(b'abc'), 'abc') + self.assertEqual(decodeunicodeescape(br'\t\n\r\x0b\x0c\x00\\'), '\t\n\r\v\f\0\\') + self.assertEqual(decodeunicodeescape(b'\t\n\r\x0b\x0c\x00'), '\t\n\r\v\f\0') + self.assertEqual(decodeunicodeescape(br'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decodeunicodeescape(b'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decodeunicodeescape(br'\u4f60\u597d'), '\u4f60\u597d') + self.assertEqual(decodeunicodeescape(br'\U0001f600'), '\U0001f600') + with self.assertWarns(DeprecationWarning): + self.assertEqual(decodeunicodeescape(br'\z'), r'\z') + + for b in b'\\', br'\xa', br'\u4f6', br'\U0001f60': + self.assertRaises(UnicodeDecodeError, decodeunicodeescape, b) + self.assertRaises(UnicodeDecodeError, decodeunicodeescape, b, 'strict') + self.assertEqual(decodeunicodeescape(br'x\U0001f60', 'replace'), 'x\ufffd') + self.assertEqual(decodeunicodeescape(br'x\U0001f60y', 'replace'), 'x\ufffdy') + + self.assertRaises(LookupError, decodeunicodeescape, b'\\', 'foo') + # TODO: Test PyUnicode_DecodeUnicodeEscape() with NULL as data and + # negative size. + + def test_asunicodeescapestring(self): + """Test PyUnicode_AsUnicodeEscapeString()""" + asunicodeescapestring = _testcapi.unicode_asunicodeescapestring + + self.assertEqual(asunicodeescapestring('abc'), b'abc') + self.assertEqual(asunicodeescapestring('\t\n\r\v\f\0\\'), br'\t\n\r\x0b\x0c\x00\\') + self.assertEqual(asunicodeescapestring('\xa1\xa2'), br'\xa1\xa2') + self.assertEqual(asunicodeescapestring('\u4f60\u597d'), br'\u4f60\u597d') + self.assertEqual(asunicodeescapestring('\U0001f600'), br'\U0001f600') + + self.assertRaises(TypeError, asunicodeescapestring, b'abc') + self.assertRaises(TypeError, asunicodeescapestring, []) + # CRASHES asunicodeescapestring(NULL) + + def test_decoderawunicodeescape(self): + """Test PyUnicode_DecodeRawUnicodeEscape()""" + decoderawunicodeescape = _testcapi.unicode_decoderawunicodeescape + + self.assertEqual(decoderawunicodeescape(b'abc'), 'abc') + self.assertEqual(decoderawunicodeescape(b'\t\n\r\v\f\0\\'), '\t\n\r\v\f\0\\') + self.assertEqual(decoderawunicodeescape(b'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decoderawunicodeescape(br'\u4f60\u597d'), '\u4f60\u597d') + self.assertEqual(decoderawunicodeescape(br'\U0001f600'), '\U0001f600') + self.assertEqual(decoderawunicodeescape(br'\xa1\xa2'), r'\xa1\xa2') + self.assertEqual(decoderawunicodeescape(br'\z'), r'\z') + + for b in br'\u4f6', br'\U0001f60': + self.assertRaises(UnicodeDecodeError, decoderawunicodeescape, b) + self.assertRaises(UnicodeDecodeError, decoderawunicodeescape, b, 'strict') + self.assertEqual(decoderawunicodeescape(br'x\U0001f60', 'replace'), 'x\ufffd') + self.assertEqual(decoderawunicodeescape(br'x\U0001f60y', 'replace'), 'x\ufffdy') + + self.assertRaises(LookupError, decoderawunicodeescape, br'\U0001f60', 'foo') + # TODO: Test PyUnicode_DecodeRawUnicodeEscape() with NULL as data and + # negative size. + + def test_asrawunicodeescapestring(self): + """Test PyUnicode_AsRawUnicodeEscapeString()""" + asrawunicodeescapestring = _testcapi.unicode_asrawunicodeescapestring + + self.assertEqual(asrawunicodeescapestring('abc'), b'abc') + self.assertEqual(asrawunicodeescapestring('\t\n\r\v\f\0\\'), b'\t\n\r\v\f\0\\') + self.assertEqual(asrawunicodeescapestring('\xa1\xa2'), b'\xa1\xa2') + self.assertEqual(asrawunicodeescapestring('\u4f60\u597d'), br'\u4f60\u597d') + self.assertEqual(asrawunicodeescapestring('\U0001f600'), br'\U0001f600') + + self.assertRaises(TypeError, asrawunicodeescapestring, b'abc') + self.assertRaises(TypeError, asrawunicodeescapestring, []) + # CRASHES asrawunicodeescapestring(NULL) + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index 73929eaffc676d..b4d7bf82d73c83 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -376,6 +376,22 @@ unicode_readchar(PyObject *self, PyObject *args) return PyLong_FromUnsignedLong(result); } +/* Test PyUnicode_FromEncodedObject() */ +static PyObject * +unicode_fromencodedobject(PyObject *self, PyObject *args) +{ + PyObject *obj; + const char *encoding; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "Oz|z", &obj, &encoding, &errors)) { + return NULL; + } + + NULLABLE(obj); + return PyUnicode_FromEncodedObject(obj, encoding, errors); +} + /* Test PyUnicode_FromObject() */ static PyObject * unicode_fromobject(PyObject *self, PyObject *arg) @@ -669,6 +685,78 @@ unicode_transformdecimalandspacetoascii(PyObject *self, PyObject *arg) return _PyUnicode_TransformDecimalAndSpaceToASCII(arg); } +/* Test PyUnicode_Decode() */ +static PyObject * +unicode_decode(PyObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + const char *encoding; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#z|z", &s, &size, &encoding, &errors)) + return NULL; + + return PyUnicode_Decode(s, size, encoding, errors); +} + +/* Test PyUnicode_AsEncodedString() */ +static PyObject * +unicode_asencodedstring(PyObject *self, PyObject *args) +{ + PyObject *unicode; + const char *encoding; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "Oz|z", &unicode, &encoding, &errors)) + return NULL; + + NULLABLE(unicode); + return PyUnicode_AsEncodedString(unicode, encoding, errors); +} + +/* Test PyUnicode_BuildEncodingMap() */ +static PyObject * +unicode_buildencodingmap(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_BuildEncodingMap(arg); +} + +/* Test PyUnicode_DecodeUTF7() */ +static PyObject * +unicode_decodeutf7(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeUTF7(data, size, errors); +} + +/* Test PyUnicode_DecodeUTF7Stateful() */ +static PyObject * +unicode_decodeutf7stateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF7Stateful(data, size, errors, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(Nn)", result, consumed); +} + /* Test PyUnicode_DecodeUTF8() */ static PyObject * unicode_decodeutf8(PyObject *self, PyObject *args) @@ -703,6 +791,387 @@ unicode_decodeutf8stateful(PyObject *self, PyObject *args) return Py_BuildValue("(Nn)", result, consumed); } +/* Test PyUnicode_AsUTF8String() */ +static PyObject * +unicode_asutf8string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUTF8String(arg); +} + +/* Test PyUnicode_DecodeUTF32() */ +static PyObject * +unicode_decodeutf32(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF32(data, size, errors, &byteorder); + if (!result) { + return NULL; + } + return Py_BuildValue("(iN)", byteorder, result); +} + +/* Test PyUnicode_DecodeUTF32Stateful() */ +static PyObject * +unicode_decodeutf32stateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF32Stateful(data, size, errors, &byteorder, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(iNn)", byteorder, result, consumed); +} + +/* Test PyUnicode_AsUTF32String() */ +static PyObject * +unicode_asutf32string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUTF32String(arg); +} + +/* Test PyUnicode_DecodeUTF16() */ +static PyObject * +unicode_decodeutf16(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder = 0; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF16(data, size, errors, &byteorder); + if (!result) { + return NULL; + } + return Py_BuildValue("(iN)", byteorder, result); +} + +/* Test PyUnicode_DecodeUTF16Stateful() */ +static PyObject * +unicode_decodeutf16stateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF16Stateful(data, size, errors, &byteorder, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(iNn)", byteorder, result, consumed); +} + +/* Test PyUnicode_AsUTF16String() */ +static PyObject * +unicode_asutf16string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUTF16String(arg); +} + +/* Test PyUnicode_DecodeUnicodeEscape() */ +static PyObject * +unicode_decodeunicodeescape(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeUnicodeEscape(data, size, errors); +} + +/* Test PyUnicode_AsUnicodeEscapeString() */ +static PyObject * +unicode_asunicodeescapestring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUnicodeEscapeString(arg); +} + +static PyObject * +unicode_decoderawunicodeescape(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeRawUnicodeEscape(data, size, errors); +} + +/* Test PyUnicode_AsRawUnicodeEscapeString() */ +static PyObject * +unicode_asrawunicodeescapestring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsRawUnicodeEscapeString(arg); +} + +static PyObject * +unicode_decodelatin1(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeLatin1(data, size, errors); +} + +/* Test PyUnicode_AsLatin1String() */ +static PyObject * +unicode_aslatin1string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsLatin1String(arg); +} + +/* Test PyUnicode_DecodeASCII() */ +static PyObject * +unicode_decodeascii(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeASCII(data, size, errors); +} + +/* Test PyUnicode_AsASCIIString() */ +static PyObject * +unicode_asasciistring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsASCIIString(arg); +} + +/* Test PyUnicode_DecodeCharmap() */ +static PyObject * +unicode_decodecharmap(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + PyObject *mapping; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#O|z", &data, &size, &mapping, &errors)) + return NULL; + + NULLABLE(mapping); + return PyUnicode_DecodeCharmap(data, size, mapping, errors); +} + +/* Test PyUnicode_AsCharmapString() */ +static PyObject * +unicode_ascharmapstring(PyObject *self, PyObject *args) +{ + PyObject *unicode; + PyObject *mapping; + + if (!PyArg_ParseTuple(args, "OO", &unicode, &mapping)) + return NULL; + + NULLABLE(unicode); + NULLABLE(mapping); + return PyUnicode_AsCharmapString(unicode, mapping); +} + +#ifdef MS_WINDOWS + +/* Test PyUnicode_DecodeMBCS() */ +static PyObject * +unicode_decodembcs(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeMBCS(data, size, errors); +} + +/* Test PyUnicode_DecodeMBCSStateful() */ +static PyObject * +unicode_decodembcsstateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeMBCSStateful(data, size, errors, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(Nn)", result, consumed); +} + +/* Test PyUnicode_DecodeCodePageStateful() */ +static PyObject * +unicode_decodecodepagestateful(PyObject *self, PyObject *args) +{ + int code_page; + const char *data; + Py_ssize_t size; + const char *errors = NULL; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &code_page, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeCodePageStateful(code_page, data, size, errors, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(Nn)", result, consumed); +} + +/* Test PyUnicode_AsMBCSString() */ +static PyObject * +unicode_asmbcsstring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsMBCSString(arg); +} + +/* Test PyUnicode_EncodeCodePage() */ +static PyObject * +unicode_encodecodepage(PyObject *self, PyObject *args) +{ + int code_page; + PyObject *unicode; + const char *errors; + + if (!PyArg_ParseTuple(args, "iO|z", &code_page, &unicode, &errors)) + return NULL; + + NULLABLE(unicode); + return PyUnicode_EncodeCodePage(code_page, unicode, errors); +} + +#endif /* MS_WINDOWS */ + +/* Test PyUnicode_DecodeLocaleAndSize() */ +static PyObject * +unicode_decodelocaleandsize(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeLocaleAndSize(data, size, errors); +} + +/* Test PyUnicode_DecodeLocale() */ +static PyObject * +unicode_decodelocale(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeLocale(data, errors); +} + +/* Test PyUnicode_EncodeLocale() */ +static PyObject * +unicode_encodelocale(PyObject *self, PyObject *args) +{ + PyObject *unicode; + const char *errors; + + if (!PyArg_ParseTuple(args, "O|z", &unicode, &errors)) + return NULL; + + NULLABLE(unicode); + return PyUnicode_EncodeLocale(unicode, errors); +} + +/* Test PyUnicode_DecodeFSDefault() */ +static PyObject * +unicode_decodefsdefault(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "y#", &data, &size)) + return NULL; + + return PyUnicode_DecodeFSDefault(data); +} + +/* Test PyUnicode_DecodeFSDefaultAndSize() */ +static PyObject * +unicode_decodefsdefaultandsize(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "y#|n", &data, &size, &size)) + return NULL; + + return PyUnicode_DecodeFSDefaultAndSize(data, size); +} + +/* Test PyUnicode_EncodeFSDefault() */ +static PyObject * +unicode_encodefsdefault(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_EncodeFSDefault(arg); +} + /* Test PyUnicode_Concat() */ static PyObject * unicode_concat(PyObject *self, PyObject *args) @@ -1528,6 +1997,7 @@ static PyMethodDef TestMethods[] = { {"unicode_substring", unicode_substring, METH_VARARGS}, {"unicode_getlength", unicode_getlength, METH_O}, {"unicode_readchar", unicode_readchar, METH_VARARGS}, + {"unicode_fromencodedobject",unicode_fromencodedobject, METH_VARARGS}, {"unicode_fromobject", unicode_fromobject, METH_O}, {"unicode_interninplace", unicode_interninplace, METH_O}, {"unicode_internfromstring", unicode_internfromstring, METH_O}, @@ -1542,9 +2012,44 @@ static PyMethodDef TestMethods[] = { {"unicode_asutf8", unicode_asutf8, METH_VARARGS}, {"unicode_asutf8andsize", unicode_asutf8andsize, METH_VARARGS}, {"unicode_asutf8andsize_null",unicode_asutf8andsize_null, METH_VARARGS}, + {"unicode_getdefaultencoding",unicode_getdefaultencoding, METH_NOARGS}, + {"unicode_decode", unicode_decode, METH_VARARGS}, + {"unicode_asencodedstring", unicode_asencodedstring, METH_VARARGS}, + {"unicode_buildencodingmap", unicode_buildencodingmap, METH_O}, + {"unicode_decodeutf7", unicode_decodeutf7, METH_VARARGS}, + {"unicode_decodeutf7stateful",unicode_decodeutf7stateful, METH_VARARGS}, {"unicode_decodeutf8", unicode_decodeutf8, METH_VARARGS}, {"unicode_decodeutf8stateful",unicode_decodeutf8stateful, METH_VARARGS}, - {"unicode_getdefaultencoding",unicode_getdefaultencoding, METH_NOARGS}, + {"unicode_asutf8string", unicode_asutf8string, METH_O}, + {"unicode_decodeutf16", unicode_decodeutf16, METH_VARARGS}, + {"unicode_decodeutf16stateful",unicode_decodeutf16stateful, METH_VARARGS}, + {"unicode_asutf16string", unicode_asutf16string, METH_O}, + {"unicode_decodeutf32", unicode_decodeutf32, METH_VARARGS}, + {"unicode_decodeutf32stateful",unicode_decodeutf32stateful, METH_VARARGS}, + {"unicode_asutf32string", unicode_asutf32string, METH_O}, + {"unicode_decodeunicodeescape",unicode_decodeunicodeescape, METH_VARARGS}, + {"unicode_asunicodeescapestring",unicode_asunicodeescapestring,METH_O}, + {"unicode_decoderawunicodeescape",unicode_decoderawunicodeescape,METH_VARARGS}, + {"unicode_asrawunicodeescapestring",unicode_asrawunicodeescapestring,METH_O}, + {"unicode_decodelatin1", unicode_decodelatin1, METH_VARARGS}, + {"unicode_aslatin1string", unicode_aslatin1string, METH_O}, + {"unicode_decodeascii", unicode_decodeascii, METH_VARARGS}, + {"unicode_asasciistring", unicode_asasciistring, METH_O}, + {"unicode_decodecharmap", unicode_decodecharmap, METH_VARARGS}, + {"unicode_ascharmapstring", unicode_ascharmapstring, METH_VARARGS}, +#ifdef MS_WINDOWS + {"unicode_decodembcs", unicode_decodembcs, METH_VARARGS}, + {"unicode_decodembcsstateful",unicode_decodembcsstateful, METH_VARARGS}, + {"unicode_decodecodepagestateful",unicode_decodecodepagestateful,METH_VARARGS}, + {"unicode_asmbcsstring", unicode_asmbcsstring, METH_O}, + {"unicode_encodecodepage", unicode_encodecodepage, METH_VARARGS}, +#endif /* MS_WINDOWS */ + {"unicode_decodelocaleandsize",unicode_decodelocaleandsize, METH_VARARGS}, + {"unicode_decodelocale", unicode_decodelocale, METH_VARARGS}, + {"unicode_encodelocale", unicode_encodelocale, METH_VARARGS}, + {"unicode_decodefsdefault", unicode_decodefsdefault, METH_VARARGS}, + {"unicode_decodefsdefaultandsize",unicode_decodefsdefaultandsize,METH_VARARGS}, + {"unicode_encodefsdefault", unicode_encodefsdefault, METH_O}, {"unicode_transformdecimalandspacetoascii", unicode_transformdecimalandspacetoascii, METH_O}, {"unicode_concat", unicode_concat, METH_VARARGS}, {"unicode_splitlines", unicode_splitlines, METH_VARARGS}, From 68ca19061d19345a72574a6c3849981213de212b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 10 Jul 2023 14:03:32 -0700 Subject: [PATCH 0334/1206] [3.12] gh-103186: Fix or catch 'extra' stderr output from unittests (GH-103196) (#106605) gh-103186: Fix or catch 'extra' stderr output from unittests (GH-103196) Reduce test noise by fixing or catching and testing stderr messages from individual tests. test_cmd_line_script.test_script_as_dev_fd calls spawn_python and hence subprocess.Popen with incompatible arguments. On POSIX, pass_fds forces close_fds to be True (subprocess.py line 848). Correct the call. test_uuid.test_cli_namespace_required_for_uuid3: when the namespace is omitted, uuid.main calls argparse.Argument_Parser.error, which prints to stderr before calling sys.exit, which raises SystemExit. Unittest assertRaises catches the exception but not the previous output. Catch the output and test it. test_warnings.test_catchwarnings_with_simplefilter_error similarly prints before raising. Catch the output and test it. --------- (cherry picked from commit 9d582250d8fde240b8e7299b74ba888c574f74a3) Co-authored-by: Ijtaba Hussain Co-authored-by: Oleg Iarygin --- Lib/test/test_cmd_line_script.py | 2 +- Lib/test/test_uuid.py | 9 ++++++--- Lib/test/test_warnings/__init__.py | 10 +++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 8bf299382e9ca4..1b588826010717 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -777,7 +777,7 @@ def test_script_as_dev_fd(self): with os_helper.temp_dir() as work_dir: script_name = _make_test_script(work_dir, 'script.py', script) with open(script_name, "r") as fp: - p = spawn_python(f"/dev/fd/{fp.fileno()}", close_fds=False, pass_fds=(0,1,2,fp.fileno())) + p = spawn_python(f"/dev/fd/{fp.fileno()}", close_fds=True, pass_fds=(0,1,2,fp.fileno())) out, err = p.communicate() self.assertEqual(out, b"12345678912345678912345\n") diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index a178e942ecda0f..9cec1e87fd3c2d 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -706,20 +706,23 @@ def test_uuid_weakref(self): self.assertIs(strong, weak()) @mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-n", "@dns"]) - def test_cli_namespace_required_for_uuid3(self): + @mock.patch('sys.stderr', new_callable=io.StringIO) + def test_cli_namespace_required_for_uuid3(self, mock_err): with self.assertRaises(SystemExit) as cm: self.uuid.main() # Check that exception code is the same as argparse.ArgumentParser.error self.assertEqual(cm.exception.code, 2) + self.assertIn("error: Incorrect number of arguments", mock_err.getvalue()) @mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-N", "python.org"]) - def test_cli_name_required_for_uuid3(self): + @mock.patch('sys.stderr', new_callable=io.StringIO) + def test_cli_name_required_for_uuid3(self, mock_err): with self.assertRaises(SystemExit) as cm: self.uuid.main() - # Check that exception code is the same as argparse.ArgumentParser.error self.assertEqual(cm.exception.code, 2) + self.assertIn("error: Incorrect number of arguments", mock_err.getvalue()) @mock.patch.object(sys, "argv", [""]) def test_cli_uuid4_outputted_with_no_args(self): diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 9e680c847dab7b..83237f5fe0d1b3 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -387,9 +387,13 @@ def test_catchwarnings_with_simplefilter_error(self): with self.module.catch_warnings( module=self.module, action="error", category=FutureWarning ): - self.module.warn("Other types of warnings are not errors") - self.assertRaises(FutureWarning, - self.module.warn, FutureWarning("msg")) + with support.captured_stderr() as stderr: + error_msg = "Other types of warnings are not errors" + self.module.warn(error_msg) + self.assertRaises(FutureWarning, + self.module.warn, FutureWarning("msg")) + stderr = stderr.getvalue() + self.assertIn(error_msg, stderr) class CFilterTests(FilterTests, unittest.TestCase): module = c_warnings From 90ea3be6fbee1520dd3e9344c71123e15fcbe6f2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:49:07 -0700 Subject: [PATCH 0335/1206] [3.12] gh-94777: Fix deadlock in ProcessPoolExecutor (GH-94784) (#106609) gh-94777: Fix deadlock in ProcessPoolExecutor (GH-94784) Fixes a hang in multiprocessing process pool executor when a child process crashes and code could otherwise block on writing to the pipe. See GH-94777 for more details. (cherry picked from commit 6782fc050281205734700a1c3e13b123961ed15b) Co-authored-by: Louis Paulot <55740424+lpaulot@users.noreply.github.com> --- Lib/concurrent/futures/process.py | 4 ++++ Lib/test/test_concurrent_futures.py | 18 ++++++++++++++++++ ...22-07-12-18-45-13.gh-issue-94777.mOybx7.rst | 1 + 3 files changed, 23 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 816edab99f63e3..301207f59de37a 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -499,6 +499,10 @@ def terminate_broken(self, cause): for p in self.processes.values(): p.terminate() + # Prevent queue writing to a pipe which is no longer read. + # https://github.com/python/cpython/issues/94777 + self.call_queue._reader.close() + # clean up resources self.join_executor_internals() diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index a20cb844a293c9..39dbe234e765e8 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -1172,6 +1172,11 @@ def _crash(delay=None): faulthandler._sigsegv() +def _crash_with_data(data): + """Induces a segfault with dummy data in input.""" + _crash() + + def _exit(): """Induces a sys exit with exitcode 1.""" sys.exit(1) @@ -1371,6 +1376,19 @@ def test_shutdown_deadlock_pickle(self): # dangling threads executor_manager.join() + def test_crash_big_data(self): + # Test that there is a clean exception instad of a deadlock when a + # child process crashes while some data is being written into the + # queue. + # https://github.com/python/cpython/issues/94777 + self.executor.shutdown(wait=True) + data = "a" * support.PIPE_MAX_SIZE + with self.executor_type(max_workers=2, + mp_context=self.get_context()) as executor: + self.executor = executor # Allow clean up in fail_on_deadlock + with self.assertRaises(BrokenProcessPool): + list(executor.map(_crash_with_data, [data] * 10)) + create_executor_tests(ExecutorDeadlockTest, executor_mixins=(ProcessPoolForkMixin, diff --git a/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst b/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst new file mode 100644 index 00000000000000..2c04a35fbfce13 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst @@ -0,0 +1 @@ +Fix hanging :mod:`multiprocessing` ``ProcessPoolExecutor`` when a child process crashes while data is being written in the call queue. From 30870c834ce0e47cc689b56aed7ac468f6e1c1ad Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 10 Jul 2023 16:38:42 -0700 Subject: [PATCH 0336/1206] [3.12] gh-102988: Detect email address parsing errors and return empty tuple to indicate the parsing error (old API) (GH-105127) (#106612) gh-102988: Detect email address parsing errors and return empty tuple to indicate the parsing error (old API) (GH-105127) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). This fixes or at least ameliorates CVE-2023-27043. --------- (cherry picked from commit 18dfbd035775c15533d13a98e56b1d2bf5c65f00) Co-authored-by: Thomas Dwyer Co-authored-by: Gregory P. Smith --- Doc/library/email.utils.rst | 26 +++++- Doc/whatsnew/3.12.rst | 8 ++ Lib/email/utils.py | 63 +++++++++++++-- Lib/test/test_email/test_email.py | 81 ++++++++++++++++++- ...-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst | 4 + 5 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index 345b64001c1ace..a87a0bd2e7de6b 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -65,6 +65,11 @@ of the new API. *email address* parts. Returns a tuple of that information, unless the parse fails, in which case a 2-tuple of ``('', '')`` is returned. + .. versionchanged:: 3.12 + For security reasons, addresses that were ambiguous and could parse into + multiple different addresses now cause ``('', '')`` to be returned + instead of only one of the *potential* addresses. + .. function:: formataddr(pair, charset='utf-8') @@ -87,7 +92,7 @@ of the new API. This method returns a list of 2-tuples of the form returned by ``parseaddr()``. *fieldvalues* is a sequence of header field values as might be returned by :meth:`Message.get_all `. Here's a simple - example that gets all the recipients of a message:: + example that gets all the recipients of a message: from email.utils import getaddresses @@ -97,6 +102,25 @@ of the new API. resent_ccs = msg.get_all('resent-cc', []) all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) + When parsing fails for a single fieldvalue, a 2-tuple of ``('', '')`` + is returned in its place. Other errors in parsing the list of + addresses such as a fieldvalue seemingly parsing into multiple + addresses may result in a list containing a single empty 2-tuple + ``[('', '')]`` being returned rather than returning potentially + invalid output. + + Example malformed input parsing: + + .. doctest:: + + >>> from email.utils import getaddresses + >>> getaddresses(['alice@example.com ', 'me@example.com']) + [('', '')] + + .. versionchanged:: 3.12 + The 2-tuple of ``('', '')`` in the returned values when parsing + fails were added as to address a security issue. + .. function:: parsedate(date) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index eba3e226fa372c..ef00f097b8f0e4 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -570,6 +570,14 @@ dis :data:`~dis.hasarg` collection instead. (Contributed by Irit Katriel in :gh:`94216`.) +email +----- + +* :func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now return + ``('', '')`` 2-tuples in more situations where invalid email addresses are + encountered instead of potentially inaccurate values. + (Contributed by Thomas Dwyer for :gh:`102988` to ameliorate CVE-2023-27043.) + fractions --------- diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 81da5394ea1695..11ad75e94e9345 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -106,12 +106,54 @@ def formataddr(pair, charset='utf-8'): return address +def _pre_parse_validation(email_header_fields): + accepted_values = [] + for v in email_header_fields: + s = v.replace('\\(', '').replace('\\)', '') + if s.count('(') != s.count(')'): + v = "('', '')" + accepted_values.append(v) + + return accepted_values + + +def _post_parse_validation(parsed_email_header_tuples): + accepted_values = [] + # The parser would have parsed a correctly formatted domain-literal + # The existence of an [ after parsing indicates a parsing failure + for v in parsed_email_header_tuples: + if '[' in v[1]: + v = ('', '') + accepted_values.append(v) + + return accepted_values + def getaddresses(fieldvalues): - """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" - all = COMMASPACE.join(str(v) for v in fieldvalues) + """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue. + + When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in + its place. + + If the resulting list of parsed address is not the same as the number of + fieldvalues in the input list a parsing error has occurred. A list + containing a single empty 2-tuple [('', '')] is returned in its place. + This is done to avoid invalid output. + """ + fieldvalues = [str(v) for v in fieldvalues] + fieldvalues = _pre_parse_validation(fieldvalues) + all = COMMASPACE.join(v for v in fieldvalues) a = _AddressList(all) - return a.addresslist + result = _post_parse_validation(a.addresslist) + + n = 0 + for v in fieldvalues: + n += v.count(',') + 1 + + if len(result) != n: + return [('', '')] + + return result def _format_timetuple_and_zone(timetuple, zone): @@ -212,9 +254,18 @@ def parseaddr(addr): Return a tuple of realname and email address, unless the parse fails, in which case return a 2-tuple of ('', ''). """ - addrs = _AddressList(addr).addresslist - if not addrs: - return '', '' + if isinstance(addr, list): + addr = addr[0] + + if not isinstance(addr, str): + return ('', '') + + addr = _pre_parse_validation([addr])[0] + addrs = _post_parse_validation(_AddressList(addr).addresslist) + + if not addrs or len(addrs) > 1: + return ('', '') + return addrs[0] diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 44b405740c4403..5238944d6b4788 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3319,15 +3319,90 @@ def test_getaddresses(self): [('Al Person', 'aperson@dom.ain'), ('Bud Person', 'bperson@dom.ain')]) + def test_getaddresses_parsing_errors(self): + """Test for parsing errors from CVE-2023-27043""" + eq = self.assertEqual + eq(utils.getaddresses(['alice@example.org(']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org)']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org<']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org>']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org@']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org,']), + [('', 'alice@example.org'), ('', 'bob@example.com')]) + eq(utils.getaddresses(['alice@example.org;']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org:']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org.']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org"']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org[']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org]']), + [('', '')]) + + def test_parseaddr_parsing_errors(self): + """Test for parsing errors from CVE-2023-27043""" + eq = self.assertEqual + eq(utils.parseaddr(['alice@example.org(']), + ('', '')) + eq(utils.parseaddr(['alice@example.org)']), + ('', '')) + eq(utils.parseaddr(['alice@example.org<']), + ('', '')) + eq(utils.parseaddr(['alice@example.org>']), + ('', '')) + eq(utils.parseaddr(['alice@example.org@']), + ('', '')) + eq(utils.parseaddr(['alice@example.org,']), + ('', '')) + eq(utils.parseaddr(['alice@example.org;']), + ('', '')) + eq(utils.parseaddr(['alice@example.org:']), + ('', '')) + eq(utils.parseaddr(['alice@example.org.']), + ('', '')) + eq(utils.parseaddr(['alice@example.org"']), + ('', '')) + eq(utils.parseaddr(['alice@example.org[']), + ('', '')) + eq(utils.parseaddr(['alice@example.org]']), + ('', '')) + def test_getaddresses_nasty(self): eq = self.assertEqual eq(utils.getaddresses(['foo: ;']), [('', '')]) - eq(utils.getaddresses( - ['[]*-- =~$']), - [('', ''), ('', ''), ('', '*--')]) + eq(utils.getaddresses(['[]*-- =~$']), [('', '')]) eq(utils.getaddresses( ['foo: ;', '"Jason R. Mastaler" ']), [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) + eq(utils.getaddresses( + [r'Pete(A nice \) chap) ']), + [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]) + eq(utils.getaddresses( + ['(Empty list)(start)Undisclosed recipients :(nobody(I know))']), + [('', '')]) + eq(utils.getaddresses( + ['Mary <@machine.tld:mary@example.net>, , jdoe@test . example']), + [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]) + eq(utils.getaddresses( + ['John Doe ']), + [('John Doe (comment)', 'jdoe@machine.example')]) + eq(utils.getaddresses( + ['"Mary Smith: Personal Account" ']), + [('Mary Smith: Personal Account', 'smith@home.example')]) + eq(utils.getaddresses( + ['Undisclosed recipients:;']), + [('', '')]) + eq(utils.getaddresses( + [r', "Giant; \"Big\" Box" ']), + [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]) def test_getaddresses_embedded_comment(self): """Test proper handling of a nested comment""" diff --git a/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst new file mode 100644 index 00000000000000..e0434ccd2ccab5 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst @@ -0,0 +1,4 @@ +CVE-2023-27043: Prevent :func:`email.utils.parseaddr` +and :func:`email.utils.getaddresses` from returning the realname portion of an +invalid RFC2822 email header in the email address portion of the 2-tuple +returned after being parsed by :class:`email._parseaddr.AddressList`. From 2eb9fe92b4180af0a9e51b1232df5a3d7d93788f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 04:53:40 -0700 Subject: [PATCH 0337/1206] [3.12] gh-103968: What's New: Add porting hints for PyType_From with metaclasses (GH-105698) (GH-106619) gh-103968: What's New: Add porting hints for PyType_From with metaclasses (GH-105698) (cherry picked from commit af5cf1e75136fcef967d4ebe1bc45f29e6dc1bcf) Co-authored-by: Petr Viktorin --- Doc/whatsnew/3.12.rst | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ef00f097b8f0e4..d6d7b7dac9a310 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1836,7 +1836,31 @@ Porting to Python 3.12 allowing incomplete initialization. Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12) - already disallows creating classes whose metaclass overrides ``tp_new``. + already disallows creating classes whose metaclass overrides ``tp_new`` + (:meth:`~object.__new__` in Python). + + Since ``tp_new`` overrides almost everything ``PyType_From*`` functions do, + the two are incompatible with each other. + The existing behavior -- ignoring the metaclass for several steps + of type creation -- is unsafe in general, since (meta)classes assume that + ``tp_new`` was called. + There is no simple general workaround. One of the following may work for you: + + - If you control the metaclass, avoid using ``tp_new`` in it: + + - If initialization can be skipped, it can be done in + :c:member:`~PyTypeObject.tp_init` instead. + - If the metaclass doesn't need to be instantiated from Python, + set its ``tp_new`` to ``NULL`` using + the :const:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag. + This makes it acceptable for ``PyType_From*`` functions. + + - Avoid ``PyType_From*`` functions: if you don't need C-specific features + (slots or setting the instance size), create types by :ref:`calling ` + the metaclass. + + - If you *know* the ``tp_new`` can be skipped safely, filter the deprecation + warning out using :func:`warnings.catch_warnings` from Python. * :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no longer called in :ref:`subinterpreters `. This is From 6968f9e4d3593610b60c1140f04de275ff40cd41 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 05:09:41 -0700 Subject: [PATCH 0338/1206] [3.12] gh-105497: [Enum] Fix flag mask inversion when unnamed flags exist (GH-106468) (#106620) gh-105497: [Enum] Fix flag mask inversion when unnamed flags exist (GH-106468) For example: class Flag(enum.Flag): A = 0x01 B = 0x02 MASK = 0xff ~Flag.MASK is Flag(0) (cherry picked from commit 95b7426f45edb570869a5513c142f29ed9f851a1) Co-authored-by: Ethan Furman --- Lib/enum.py | 8 +- Lib/test/test_enum.py | 138 +++++++++++------- ...-07-05-14-34-10.gh-issue-105497.HU5u89.rst | 1 + 3 files changed, 86 insertions(+), 61 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst diff --git a/Lib/enum.py b/Lib/enum.py index 92a9632dc892d0..56ebfbd1a61f7a 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1539,14 +1539,10 @@ def __xor__(self, other): def __invert__(self): if self._inverted_ is None: - if self._boundary_ is KEEP: - # use all bits + if self._boundary_ in (EJECT, KEEP): self._inverted_ = self.__class__(~self._value_) else: - # use canonical bits (i.e. calculate flags not in this member) - self._inverted_ = self.__class__(self._singles_mask_ ^ self._value_) - if isinstance(self._inverted_, self.__class__): - self._inverted_._inverted_ = self + self._inverted_ = self.__class__(self._singles_mask_ & ~self._value_) return self._inverted_ __rand__ = __and__ diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 291213a13f36b7..592deb837914cb 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -818,6 +818,89 @@ def test_default_missing_with_wrong_type_value(self): self.MainEnum('RED') self.assertIs(ctx.exception.__context__, None) + def test_closed_invert_expectations(self): + class ClosedAB(self.enum_type): + A = 1 + B = 2 + MASK = 3 + A, B = ClosedAB + AB_MASK = ClosedAB.MASK + # + self.assertIs(~A, B) + self.assertIs(~B, A) + self.assertIs(~(A|B), ClosedAB(0)) + self.assertIs(~AB_MASK, ClosedAB(0)) + self.assertIs(~ClosedAB(0), (A|B)) + # + class ClosedXYZ(self.enum_type): + X = 4 + Y = 2 + Z = 1 + MASK = 7 + X, Y, Z = ClosedXYZ + XYZ_MASK = ClosedXYZ.MASK + # + self.assertIs(~X, Y|Z) + self.assertIs(~Y, X|Z) + self.assertIs(~Z, X|Y) + self.assertIs(~(X|Y), Z) + self.assertIs(~(X|Z), Y) + self.assertIs(~(Y|Z), X) + self.assertIs(~(X|Y|Z), ClosedXYZ(0)) + self.assertIs(~XYZ_MASK, ClosedXYZ(0)) + self.assertIs(~ClosedXYZ(0), (X|Y|Z)) + + def test_open_invert_expectations(self): + class OpenAB(self.enum_type): + A = 1 + B = 2 + MASK = 255 + A, B = OpenAB + AB_MASK = OpenAB.MASK + # + if OpenAB._boundary_ in (EJECT, KEEP): + self.assertIs(~A, OpenAB(254)) + self.assertIs(~B, OpenAB(253)) + self.assertIs(~(A|B), OpenAB(252)) + self.assertIs(~AB_MASK, OpenAB(0)) + self.assertIs(~OpenAB(0), AB_MASK) + else: + self.assertIs(~A, B) + self.assertIs(~B, A) + self.assertIs(~(A|B), OpenAB(0)) + self.assertIs(~AB_MASK, OpenAB(0)) + self.assertIs(~OpenAB(0), (A|B)) + # + class OpenXYZ(self.enum_type): + X = 4 + Y = 2 + Z = 1 + MASK = 31 + X, Y, Z = OpenXYZ + XYZ_MASK = OpenXYZ.MASK + # + if OpenXYZ._boundary_ in (EJECT, KEEP): + self.assertIs(~X, OpenXYZ(27)) + self.assertIs(~Y, OpenXYZ(29)) + self.assertIs(~Z, OpenXYZ(30)) + self.assertIs(~(X|Y), OpenXYZ(25)) + self.assertIs(~(X|Z), OpenXYZ(26)) + self.assertIs(~(Y|Z), OpenXYZ(28)) + self.assertIs(~(X|Y|Z), OpenXYZ(24)) + self.assertIs(~XYZ_MASK, OpenXYZ(0)) + self.assertTrue(~OpenXYZ(0), XYZ_MASK) + else: + self.assertIs(~X, Y|Z) + self.assertIs(~Y, X|Z) + self.assertIs(~Z, X|Y) + self.assertIs(~(X|Y), Z) + self.assertIs(~(X|Z), Y) + self.assertIs(~(Y|Z), X) + self.assertIs(~(X|Y|Z), OpenXYZ(0)) + self.assertIs(~XYZ_MASK, OpenXYZ(0)) + self.assertTrue(~OpenXYZ(0), (X|Y|Z)) + + class TestPlainEnum(_EnumTests, _PlainOutputTests, unittest.TestCase): enum_type = Enum @@ -3045,33 +3128,6 @@ class Color(Flag): WHITE = RED|GREEN|BLUE BLANCO = RED|GREEN|BLUE - class Complete(Flag): - A = 0x01 - B = 0x02 - - class Partial(Flag): - A = 0x01 - B = 0x02 - MASK = 0xff - - class CompleteInt(IntFlag): - A = 0x01 - B = 0x02 - - class PartialInt(IntFlag): - A = 0x01 - B = 0x02 - MASK = 0xff - - class CompleteIntStrict(IntFlag, boundary=STRICT): - A = 0x01 - B = 0x02 - - class PartialIntStrict(IntFlag, boundary=STRICT): - A = 0x01 - B = 0x02 - MASK = 0xff - def test_or(self): Perm = self.Perm for i in Perm: @@ -3115,34 +3171,6 @@ def test_xor(self): self.assertIs(Open.RO ^ Open.CE, Open.CE) self.assertIs(Open.CE ^ Open.CE, Open.RO) - def test_invert(self): - Perm = self.Perm - RW = Perm.R | Perm.W - RX = Perm.R | Perm.X - WX = Perm.W | Perm.X - RWX = Perm.R | Perm.W | Perm.X - values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] - for i in values: - self.assertIs(type(~i), Perm) - self.assertEqual(~~i, i) - for i in Perm: - self.assertIs(~~i, i) - Open = self.Open - self.assertIs(Open.WO & ~Open.WO, Open.RO) - self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE) - Complete = self.Complete - self.assertIs(~Complete.A, Complete.B) - Partial = self.Partial - self.assertIs(~Partial.A, Partial.B) - CompleteInt = self.CompleteInt - self.assertIs(~CompleteInt.A, CompleteInt.B) - PartialInt = self.PartialInt - self.assertIs(~PartialInt.A, PartialInt(254)) - CompleteIntStrict = self.CompleteIntStrict - self.assertIs(~CompleteIntStrict.A, CompleteIntStrict.B) - PartialIntStrict = self.PartialIntStrict - self.assertIs(~PartialIntStrict.A, PartialIntStrict.B) - def test_bool(self): Perm = self.Perm for f in Perm: diff --git a/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst b/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst new file mode 100644 index 00000000000000..f4f2db08f73f50 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst @@ -0,0 +1 @@ +Fix flag mask inversion when unnamed flags exist. From 97a6a418167f1c8bbb014fab813e440b88cf2221 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 11 Jul 2023 14:22:17 +0200 Subject: [PATCH 0339/1206] Python 3.12.0b4 --- Include/patchlevel.h | 4 +- Lib/pydoc_data/topics.py | 30 +- Misc/NEWS.d/3.12.0b4.rst | 318 ++++++++++++++++++ ...-05-20-23-49-30.gh-issue-104692.s5UIu5.rst | 6 - ...-06-26-21-56-29.gh-issue-106118.0cCfhl.rst | 2 - ...-06-13-14-24-55.gh-issue-105227.HDL9aF.rst | 5 - ...-01-13-11-37-41.gh-issue-101006.fuLvn2.rst | 1 - ...-06-08-09-10-15.gh-issue-105486.dev-WS.rst | 1 - ...-06-12-16-38-31.gh-issue-105340._jRHXe.rst | 2 - ...-06-19-11-04-01.gh-issue-105908.7oanny.rst | 1 - ...3-06-22-14-19-17.gh-issue-98931.PPgvSF.rst | 2 - ...-06-22-19-16-24.gh-issue-105979.TDP2CU.rst | 1 - ...-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst | 2 - ...-07-04-09-51-45.gh-issue-106396.DmYp7x.rst | 3 - ...-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst | 2 - ...2-07-12-18-45-13.gh-issue-94777.mOybx7.rst | 1 - ...-06-05-14-43-56.gh-issue-104554.pwfKIo.rst | 1 - ...-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst | 1 - ...3-06-20-23-18-45.gh-issue-96145.o5dTRM.rst | 1 - ...-06-21-19-04-27.gh-issue-105974.M47n3t.rst | 6 - ...-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst | 1 - ...-06-25-12-28-55.gh-issue-106075.W7tMRb.rst | 1 - ...-06-27-23-22-37.gh-issue-106152.ya5jBT.rst | 1 - ...-07-01-16-40-54.gh-issue-102541.C1ahtk.rst | 1 - ...-07-02-10-56-41.gh-issue-106330.QSkIUH.rst | 2 - ...-07-03-15-09-44.gh-issue-106292.3npldV.rst | 4 - ...3-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst | 3 - ...-07-05-14-34-10.gh-issue-105497.HU5u89.rst | 1 - ...-07-07-03-05-58.gh-issue-106503.ltfeiH.rst | 2 - ...-07-07-13-47-28.gh-issue-106510.9n5BdC.rst | 1 - ...-07-07-17-44-03.gh-issue-106524.XkBV8h.rst | 1 - ...-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst | 4 - ...-06-28-02-51-08.gh-issue-101634.Rayczr.rst | 3 - ...-07-03-14-06-19.gh-issue-106359.RfJuR0.rst | 2 - README.rst | 2 +- 35 files changed, 337 insertions(+), 82 deletions(-) create mode 100644 Misc/NEWS.d/3.12.0b4.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst delete mode 100644 Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst delete mode 100644 Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index aa35c24a9fa301..62d7e77bdaa8fc 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 3 +#define PY_RELEASE_SERIAL 4 /* Version as a string */ -#define PY_VERSION "3.12.0b3+" +#define PY_VERSION "3.12.0b4" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 9a6a1b37545720..9603975729cfaf 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Jun 19 20:55:48 2023 +# Autogenerated by Sphinx on Tue Jul 11 14:22:58 2023 +# as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -208,7 +209,7 @@ 'the\n' ' subscript must have a type compatible with the mapping’s key ' 'type,\n' - ' and the mapping is then asked to create a key/datum pair ' + ' and the mapping is then asked to create a key/value pair ' 'which maps\n' ' the subscript to the assigned object. This can either ' 'replace an\n' @@ -5687,30 +5688,31 @@ 'dict': 'Dictionary displays\n' '*******************\n' '\n' - 'A dictionary display is a possibly empty series of key/datum pairs\n' - 'enclosed in curly braces:\n' + 'A dictionary display is a possibly empty series of dict items\n' + '(key/value pairs) enclosed in curly braces:\n' '\n' - ' dict_display ::= "{" [key_datum_list | dict_comprehension] ' + ' dict_display ::= "{" [dict_item_list | dict_comprehension] ' '"}"\n' - ' key_datum_list ::= key_datum ("," key_datum)* [","]\n' - ' key_datum ::= expression ":" expression | "**" or_expr\n' + ' dict_item_list ::= dict_item ("," dict_item)* [","]\n' + ' dict_item ::= expression ":" expression | "**" or_expr\n' ' dict_comprehension ::= expression ":" expression comp_for\n' '\n' 'A dictionary display yields a new dictionary object.\n' '\n' - 'If a comma-separated sequence of key/datum pairs is given, they are\n' + 'If a comma-separated sequence of dict items is given, they are\n' 'evaluated from left to right to define the entries of the ' 'dictionary:\n' 'each key object is used as a key into the dictionary to store the\n' - 'corresponding datum. This means that you can specify the same key\n' - 'multiple times in the key/datum list, and the final dictionary’s ' + 'corresponding value. This means that you can specify the same key\n' + 'multiple times in the dict item list, and the final dictionary’s ' 'value\n' 'for that key will be the last one given.\n' '\n' 'A double asterisk "**" denotes *dictionary unpacking*. Its operand\n' 'must be a *mapping*. Each mapping item is added to the new\n' - 'dictionary. Later values replace values already set by earlier\n' - 'key/datum pairs and earlier dictionary unpackings.\n' + 'dictionary. Later values replace values already set by earlier ' + 'dict\n' + 'items and earlier dictionary unpackings.\n' '\n' 'New in version 3.5: Unpacking into dictionary displays, originally\n' 'proposed by **PEP 448**.\n' @@ -5726,7 +5728,7 @@ 'Restrictions on the types of the key values are listed earlier in\n' 'section The standard type hierarchy. (To summarize, the key type\n' 'should be *hashable*, which excludes all mutable objects.) Clashes\n' - 'between duplicate keys are not detected; the last datum (textually\n' + 'between duplicate keys are not detected; the last value (textually\n' 'rightmost in the display) stored for a given key value prevails.\n' '\n' 'Changed in version 3.8: Prior to Python 3.8, in dict ' @@ -13256,7 +13258,7 @@ 'are\n' 'most of the built-in objects considered false:\n' '\n' - '* constants defined to be false: "None" and "False".\n' + '* constants defined to be false: "None" and "False"\n' '\n' '* zero of any numeric type: "0", "0.0", "0j", "Decimal(0)",\n' ' "Fraction(0, 1)"\n' diff --git a/Misc/NEWS.d/3.12.0b4.rst b/Misc/NEWS.d/3.12.0b4.rst new file mode 100644 index 00000000000000..5212f359ec5063 --- /dev/null +++ b/Misc/NEWS.d/3.12.0b4.rst @@ -0,0 +1,318 @@ +.. date: 2023-06-13-20-52-24 +.. gh-issue: 102988 +.. nonce: Kei7Vf +.. release date: 2023-07-11 +.. section: Security + +CVE-2023-27043: Prevent :func:`email.utils.parseaddr` and +:func:`email.utils.getaddresses` from returning the realname portion of an +invalid RFC2822 email header in the email address portion of the 2-tuple +returned after being parsed by :class:`email._parseaddr.AddressList`. + +.. + +.. date: 2023-07-04-09-51-45 +.. gh-issue: 106396 +.. nonce: DmYp7x +.. section: Core and Builtins + +When the format specification of an f-string expression is empty, the parser +now generates an empty :class:`ast.JoinedStr` node for it instead of an +one-element :class:`ast.JoinedStr` with an empty string +:class:`ast.Constant`. + +.. + +.. date: 2023-06-29-09-46-41 +.. gh-issue: 106145 +.. nonce: QC6-Kq +.. section: Core and Builtins + +Make ``end_lineno`` and ``end_col_offset`` required on ``type_param`` ast +nodes. + +.. + +.. date: 2023-06-22-19-16-24 +.. gh-issue: 105979 +.. nonce: TDP2CU +.. section: Core and Builtins + +Fix crash in :func:`!_imp.get_frozen_object` due to improper exception +handling. + +.. + +.. date: 2023-06-22-14-19-17 +.. gh-issue: 98931 +.. nonce: PPgvSF +.. section: Core and Builtins + +Ensure custom :exc:`SyntaxError` error messages are raised for invalid +imports with multiple targets. Patch by Pablo Galindo + +.. + +.. date: 2023-06-19-11-04-01 +.. gh-issue: 105908 +.. nonce: 7oanny +.. section: Core and Builtins + +Fixed bug where :gh:`99111` breaks future import ``barry_as_FLUFL`` in the +Python REPL. + +.. + +.. date: 2023-06-12-16-38-31 +.. gh-issue: 105340 +.. nonce: _jRHXe +.. section: Core and Builtins + +Include the comprehension iteration variable in ``locals()`` inside a +module- or class-scope comprehension. + +.. + +.. date: 2023-06-08-09-10-15 +.. gh-issue: 105486 +.. nonce: dev-WS +.. section: Core and Builtins + +Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``. + +.. + +.. date: 2023-01-13-11-37-41 +.. gh-issue: 101006 +.. nonce: fuLvn2 +.. section: Core and Builtins + +Improve error handling when read :mod:`marshal` data. + +.. + +.. date: 2023-07-07-17-44-03 +.. gh-issue: 106524 +.. nonce: XkBV8h +.. section: Library + +Fix crash in :func:`!_sre.template` with templates containing invalid group +indices. + +.. + +.. date: 2023-07-07-13-47-28 +.. gh-issue: 106510 +.. nonce: 9n5BdC +.. section: Library + +Improve debug output for atomic groups in regular expressions. + +.. + +.. date: 2023-07-07-03-05-58 +.. gh-issue: 106503 +.. nonce: ltfeiH +.. section: Library + +Fix ref cycle in :class:`!asyncio._SelectorSocketTransport` by removing +``_write_ready`` in ``close``. + +.. + +.. date: 2023-07-05-14-34-10 +.. gh-issue: 105497 +.. nonce: HU5u89 +.. section: Library + +Fix flag mask inversion when unnamed flags exist. + +.. + +.. date: 2023-07-05-13-08-23 +.. gh-issue: 90876 +.. nonce: Qvlkfl +.. section: Library + +Prevent :mod:`multiprocessing.spawn` from failing to *import* in +environments where ``sys.executable`` is ``None``. This regressed in 3.11 +with the addition of support for path-like objects in multiprocessing. + +.. + +.. date: 2023-07-03-15-09-44 +.. gh-issue: 106292 +.. nonce: 3npldV +.. section: Library + +Check for an instance-dict cached value in the :meth:`__get__` method of +:func:`functools.cached_property`. This better matches the pre-3.12 behavior +and improves compatibility for users subclassing +:func:`functools.cached_property` and adding a :meth:`__set__` method. + +.. + +.. date: 2023-07-02-10-56-41 +.. gh-issue: 106330 +.. nonce: QSkIUH +.. section: Library + +Fix incorrect matching of empty paths in :meth:`pathlib.PurePath.match`. +This bug was introduced in Python 3.12.0 beta 1. + +.. + +.. date: 2023-07-01-16-40-54 +.. gh-issue: 102541 +.. nonce: C1ahtk +.. section: Library + +Make pydoc.doc catch bad module ImportError when output stream is not None. + +.. + +.. date: 2023-06-27-23-22-37 +.. gh-issue: 106152 +.. nonce: ya5jBT +.. section: Library + +Added PY_THROW event hook for :mod:`cProfile` for generators + +.. + +.. date: 2023-06-25-12-28-55 +.. gh-issue: 106075 +.. nonce: W7tMRb +.. section: Library + +Added `asyncio.taskgroups.__all__` to `asyncio.__all__` for export in star +imports. + +.. + +.. date: 2023-06-22-15-21-11 +.. gh-issue: 105987 +.. nonce: T7Kzrb +.. section: Library + +Fix crash due to improper reference counting in :mod:`asyncio` eager task +factory internal routines. + +.. + +.. date: 2023-06-21-19-04-27 +.. gh-issue: 105974 +.. nonce: M47n3t +.. section: Library + +Fix bug where a :class:`typing.Protocol` class that had one or more +non-callable members would raise :exc:`TypeError` when :func:`issubclass` +was called against it, even if it defined a custom ``__subclasshook__`` +method. The behaviour in Python 3.11 and lower -- which has now been +restored -- was not to raise :exc:`TypeError` in these situations if a +custom ``__subclasshook__`` method was defined. Patch by Alex Waygood. + +.. + +.. date: 2023-06-20-23-18-45 +.. gh-issue: 96145 +.. nonce: o5dTRM +.. section: Library + +Reverted addition of ``json.AttrDict``. + +.. + +.. date: 2023-06-08-17-49-46 +.. gh-issue: 105497 +.. nonce: K6Q8nU +.. section: Library + +Fix flag inversion when alias/mask members exist. + +.. + +.. date: 2023-06-05-14-43-56 +.. gh-issue: 104554 +.. nonce: pwfKIo +.. section: Library + +Add RTSPS scheme support in urllib.parse + +.. + +.. date: 2022-07-12-18-45-13 +.. gh-issue: 94777 +.. nonce: mOybx7 +.. section: Library + +Fix hanging :mod:`multiprocessing` ``ProcessPoolExecutor`` when a child +process crashes while data is being written in the call queue. + +.. + +.. date: 2023-06-30-19-28-59 +.. gh-issue: 106232 +.. nonce: hQ4-tz +.. section: Documentation + +Make timeit doc command lines compatible with Windows by using double quotes +for arguments. This works on linux and macOS also. + +.. + +.. date: 2023-06-28-02-51-08 +.. gh-issue: 101634 +.. nonce: Rayczr +.. section: Tests + +When running the Python test suite with ``-jN`` option, if a worker stdout +cannot be decoded from the locale encoding report a failed testn so the +exitcode is non-zero. Patch by Victor Stinner. + +.. + +.. date: 2023-06-26-21-56-29 +.. gh-issue: 106118 +.. nonce: 0cCfhl +.. section: Build + +Fix compilation for platforms without :data:`!O_CLOEXEC`. The issue was +introduced with Python 3.12b1 in :gh:`103295`. Patch by Erlend Aasland. + +.. + +.. date: 2023-05-20-23-49-30 +.. gh-issue: 104692 +.. nonce: s5UIu5 +.. section: Build + +Include ``commoninstall`` as a prerequisite for ``bininstall`` + +This ensures that ``commoninstall`` is completed before ``bininstall`` is +started when parallel builds are used (``make -j install``), and so the +``python3`` symlink is only installed after all standard library modules are +installed. + +.. + +.. date: 2023-07-03-14-06-19 +.. gh-issue: 106359 +.. nonce: RfJuR0 +.. section: Tools/Demos + +Argument Clinic now explicitly forbids "kwarg splats" in function calls used +as annotations. + +.. + +.. date: 2023-06-13-14-24-55 +.. gh-issue: 105227 +.. nonce: HDL9aF +.. section: C API + +The new :c:func:`PyType_GetDict` provides the dictionary for the given type +object that is normally exposed by ``cls.__dict__``. Normally it's +sufficient to use :c:member:`~PyTypeObject.tp_dict`, but for the static +builtin types :c:member:`!tp_dict` is now always ``NULL``. +:c:func:`!PyType_GetDict()` provides the correct dict object instead. diff --git a/Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst b/Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst deleted file mode 100644 index 2936990999e1aa..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-05-20-23-49-30.gh-issue-104692.s5UIu5.rst +++ /dev/null @@ -1,6 +0,0 @@ -Include ``commoninstall`` as a prerequisite for ``bininstall`` - -This ensures that ``commoninstall`` is completed before ``bininstall`` -is started when parallel builds are used (``make -j install``), and so -the ``python3`` symlink is only installed after all standard library -modules are installed. diff --git a/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst b/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst deleted file mode 100644 index f93cae5d03b539..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix compilation for platforms without :data:`!O_CLOEXEC`. The issue was -introduced with Python 3.12b1 in :gh:`103295`. Patch by Erlend Aasland. diff --git a/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst b/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst deleted file mode 100644 index 846663621e8689..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst +++ /dev/null @@ -1,5 +0,0 @@ -The new :c:func:`PyType_GetDict` provides the dictionary for the given type -object that is normally exposed by ``cls.__dict__``. Normally it's -sufficient to use :c:member:`~PyTypeObject.tp_dict`, but for the static -builtin types :c:member:`!tp_dict` is now always ``NULL``. :c:func:`!PyType_GetDict()` -provides the correct dict object instead. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst deleted file mode 100644 index c98670d8c4963d..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst +++ /dev/null @@ -1 +0,0 @@ -Improve error handling when read :mod:`marshal` data. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst deleted file mode 100644 index 9f735db3dc89c3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst +++ /dev/null @@ -1 +0,0 @@ -Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst deleted file mode 100644 index f6d4fa8fc4d74e..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Include the comprehension iteration variable in ``locals()`` inside a -module- or class-scope comprehension. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst deleted file mode 100644 index 03db3f064f503f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed bug where :gh:`99111` breaks future import ``barry_as_FLUFL`` in the Python REPL. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst deleted file mode 100644 index 611660d6286263..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure custom :exc:`SyntaxError` error messages are raised for invalid -imports with multiple targets. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst deleted file mode 100644 index be6962afd0c78f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash in :func:`!_imp.get_frozen_object` due to improper exception handling. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst deleted file mode 100644 index 4f9445bbcbe550..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make ``end_lineno`` and ``end_col_offset`` required on ``type_param`` ast -nodes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst deleted file mode 100644 index c5767e97271d9d..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst +++ /dev/null @@ -1,3 +0,0 @@ -When the format specification of an f-string expression is empty, the parser now -generates an empty :class:`ast.JoinedStr` node for it instead of an one-element -:class:`ast.JoinedStr` with an empty string :class:`ast.Constant`. diff --git a/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst b/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst deleted file mode 100644 index bc16f92b7d6478..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make timeit doc command lines compatible with Windows by using double quotes -for arguments. This works on linux and macOS also. diff --git a/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst b/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst deleted file mode 100644 index 2c04a35fbfce13..00000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst +++ /dev/null @@ -1 +0,0 @@ -Fix hanging :mod:`multiprocessing` ``ProcessPoolExecutor`` when a child process crashes while data is being written in the call queue. diff --git a/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst b/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst deleted file mode 100644 index 9ef8c67459c406..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst +++ /dev/null @@ -1 +0,0 @@ -Add RTSPS scheme support in urllib.parse diff --git a/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst b/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst deleted file mode 100644 index 2d4e2091b50714..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix flag inversion when alias/mask members exist. diff --git a/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst b/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst deleted file mode 100644 index f4fb0e46ce5e57..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst +++ /dev/null @@ -1 +0,0 @@ -Reverted addition of ``json.AttrDict``. diff --git a/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst b/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst deleted file mode 100644 index 982192e59e3a50..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst +++ /dev/null @@ -1,6 +0,0 @@ -Fix bug where a :class:`typing.Protocol` class that had one or more -non-callable members would raise :exc:`TypeError` when :func:`issubclass` -was called against it, even if it defined a custom ``__subclasshook__`` -method. The behaviour in Python 3.11 and lower -- which has now been -restored -- was not to raise :exc:`TypeError` in these situations if a -custom ``__subclasshook__`` method was defined. Patch by Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst b/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst deleted file mode 100644 index 0bc97da4edf0f9..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash due to improper reference counting in :mod:`asyncio` eager task factory internal routines. diff --git a/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst b/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst deleted file mode 100644 index d2687154a58594..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst +++ /dev/null @@ -1 +0,0 @@ -Added `asyncio.taskgroups.__all__` to `asyncio.__all__` for export in star imports. diff --git a/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst b/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst deleted file mode 100644 index da9d2605f46294..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst +++ /dev/null @@ -1 +0,0 @@ -Added PY_THROW event hook for :mod:`cProfile` for generators diff --git a/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst b/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst deleted file mode 100644 index efaf5db10f3e1c..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst +++ /dev/null @@ -1 +0,0 @@ -Make pydoc.doc catch bad module ImportError when output stream is not None. diff --git a/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst b/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst deleted file mode 100644 index c1f55ab658b517..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix incorrect matching of empty paths in :meth:`pathlib.PurePath.match`. -This bug was introduced in Python 3.12.0 beta 1. diff --git a/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst b/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst deleted file mode 100644 index 233509344d509b..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst +++ /dev/null @@ -1,4 +0,0 @@ -Check for an instance-dict cached value in the :meth:`__get__` method of -:func:`functools.cached_property`. This better matches the pre-3.12 behavior -and improves compatibility for users subclassing -:func:`functools.cached_property` and adding a :meth:`__set__` method. diff --git a/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst b/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst deleted file mode 100644 index 3e062b5add6d89..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst +++ /dev/null @@ -1,3 +0,0 @@ -Prevent :mod:`multiprocessing.spawn` from failing to *import* in environments -where ``sys.executable`` is ``None``. This regressed in 3.11 with the addition -of support for path-like objects in multiprocessing. diff --git a/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst b/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst deleted file mode 100644 index f4f2db08f73f50..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst +++ /dev/null @@ -1 +0,0 @@ -Fix flag mask inversion when unnamed flags exist. diff --git a/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst b/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst deleted file mode 100644 index b8dd850386e86c..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ref cycle in :class:`!asyncio._SelectorSocketTransport` by removing -``_write_ready`` in ``close``. diff --git a/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst b/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst deleted file mode 100644 index e0646fa9bc0211..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst +++ /dev/null @@ -1 +0,0 @@ -Improve debug output for atomic groups in regular expressions. diff --git a/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst b/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst deleted file mode 100644 index f3fd070e391a66..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash in :func:`!_sre.template` with templates containing invalid group indices. diff --git a/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst deleted file mode 100644 index e0434ccd2ccab5..00000000000000 --- a/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst +++ /dev/null @@ -1,4 +0,0 @@ -CVE-2023-27043: Prevent :func:`email.utils.parseaddr` -and :func:`email.utils.getaddresses` from returning the realname portion of an -invalid RFC2822 email header in the email address portion of the 2-tuple -returned after being parsed by :class:`email._parseaddr.AddressList`. diff --git a/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst b/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst deleted file mode 100644 index 6fbfc84c19e1b8..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst +++ /dev/null @@ -1,3 +0,0 @@ -When running the Python test suite with ``-jN`` option, if a worker stdout -cannot be decoded from the locale encoding report a failed testn so the -exitcode is non-zero. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst b/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst deleted file mode 100644 index 600c265391ec5b..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Argument Clinic now explicitly forbids "kwarg splats" in function calls used as -annotations. diff --git a/README.rst b/README.rst index daa30b1a65dfbb..5257beacd31854 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 beta 3 +This is Python version 3.12.0 beta 4 ===================================== .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From c594e25cd76b9d2be04eaebc13df2becbdda7aed Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 08:47:15 -0700 Subject: [PATCH 0340/1206] [3.12] gh-106498: Revert incorrect colorsys.rgb_to_hls change (GH-106627) (#106632) gh-106498: Revert incorrect colorsys.rgb_to_hls change (GH-106627) gh-86618 assumed a-b-c = a-(b+c) = a-d where d = b+d. For floats 2.0, 1.0, and 0.9999999999999999, this assumption is false. The net change of 1.1102230246251565e-16 to 0.0 results in division by 0. Revert the replacement. Add test. (cherry picked from commit a2d54d4e8ab12f967a220be88bde8ac8227c5ab3) Co-authored-by: Terry Jan Reedy --- Lib/colorsys.py | 2 +- Lib/test/test_colorsys.py | 10 ++++++++++ .../2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst diff --git a/Lib/colorsys.py b/Lib/colorsys.py index 9bdc83e3772603..bc897bd0f99298 100644 --- a/Lib/colorsys.py +++ b/Lib/colorsys.py @@ -83,7 +83,7 @@ def rgb_to_hls(r, g, b): if l <= 0.5: s = rangec / sumc else: - s = rangec / (2.0-sumc) + s = rangec / (2.0-maxc-minc) # Not always 2.0-sumc: gh-106498. rc = (maxc-r) / rangec gc = (maxc-g) / rangec bc = (maxc-b) / rangec diff --git a/Lib/test/test_colorsys.py b/Lib/test/test_colorsys.py index a24e3adcb4b842..74d76294b0b4d4 100644 --- a/Lib/test/test_colorsys.py +++ b/Lib/test/test_colorsys.py @@ -69,6 +69,16 @@ def test_hls_values(self): self.assertTripleEqual(hls, colorsys.rgb_to_hls(*rgb)) self.assertTripleEqual(rgb, colorsys.hls_to_rgb(*hls)) + def test_hls_nearwhite(self): # gh-106498 + values = ( + # rgb, hls: these do not work in reverse + ((0.9999999999999999, 1, 1), (0.5, 1.0, 1.0)), + ((1, 0.9999999999999999, 0.9999999999999999), (0.0, 1.0, 1.0)), + ) + for rgb, hls in values: + self.assertTripleEqual(hls, colorsys.rgb_to_hls(*rgb)) + self.assertTripleEqual((1.0, 1.0, 1.0), colorsys.hls_to_rgb(*hls)) + def test_yiq_roundtrip(self): for r in frange(0.0, 1.0, 0.2): for g in frange(0.0, 1.0, 0.2): diff --git a/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst b/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst new file mode 100644 index 00000000000000..09fc647cc01d21 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst @@ -0,0 +1,2 @@ +Revert a change to :func:`colorsys.rgb_to_hls` that caused division by zero +for certain almost-white inputs. Patch by Terry Jan Reedy. From 1336bb667b4eb112afdc7d7f94a9022cfe64d3ec Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 11 Jul 2023 18:05:38 +0200 Subject: [PATCH 0341/1206] Post 3.12.0b4 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 62d7e77bdaa8fc..e3d7ef51ba60c0 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 4 /* Version as a string */ -#define PY_VERSION "3.12.0b4" +#define PY_VERSION "3.12.0b4+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 58f9c8889d8fa79d617fddf6cb48942d3003c7fd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 09:15:30 -0700 Subject: [PATCH 0342/1206] [3.12] gh-106403: Restore weakref support for TypeVar and friends (GH-106418) (#106635) gh-106403: Restore weakref support for TypeVar and friends (GH-106418) (cherry picked from commit 945d3cbf2e8e756ed16c3ec51106e6157abb2698) Co-authored-by: Jelle Zijlstra --- Lib/test/test_type_params.py | 31 +++++++++++++++++++ ...-07-04-07-25-30.gh-issue-106403.GmefbV.rst | 4 +++ Objects/typevarobject.c | 12 ++++--- 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 3026cc22476619..bced641a9661fd 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -3,6 +3,7 @@ import types import unittest import pickle +import weakref from test.support import requires_working_socket, check_syntax_error, run_code from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args @@ -921,3 +922,33 @@ def test_pickling_classes(self): # These instances are not equal, # but class check is good enough: self.assertIsInstance(pickle.loads(pickled), real_class) + + +class TypeParamsWeakRefTest(unittest.TestCase): + def test_weakrefs(self): + T = TypeVar('T') + P = ParamSpec('P') + class OldStyle(Generic[T]): + pass + + class NewStyle[T]: + pass + + cases = [ + T, + TypeVar('T', bound=int), + P, + P.args, + P.kwargs, + TypeVarTuple('Ts'), + OldStyle, + OldStyle[int], + OldStyle(), + NewStyle, + NewStyle[int], + NewStyle(), + Generic[T], + ] + for case in cases: + with self.subTest(case=case): + weakref.ref(case) diff --git a/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst b/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst new file mode 100644 index 00000000000000..4fea45f16c4f8e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst @@ -0,0 +1,4 @@ +Instances of :class:`typing.TypeVar`, :class:`typing.ParamSpec`, +:class:`typing.ParamSpecArgs`, :class:`typing.ParamSpecKwargs`, and +:class:`typing.TypeVarTuple` once again support weak references, fixing a +regression introduced in Python 3.12.0 beta 1. Patch by Jelle Zijlstra. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 406a6eb76e3a8a..97f39136996fcc 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -500,7 +500,7 @@ PyType_Spec typevar_spec = { .name = "typing.TypeVar", .basicsize = sizeof(typevarobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_MANAGED_DICT, + | Py_TPFLAGS_MANAGED_DICT | Py_TPFLAGS_MANAGED_WEAKREF, .slots = typevar_slots, }; @@ -647,7 +647,8 @@ static PyType_Slot paramspecargs_slots[] = { PyType_Spec paramspecargs_spec = { .name = "typing.ParamSpecArgs", .basicsize = sizeof(paramspecattrobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspecargs_slots, }; @@ -726,7 +727,8 @@ static PyType_Slot paramspeckwargs_slots[] = { PyType_Spec paramspeckwargs_spec = { .name = "typing.ParamSpecKwargs", .basicsize = sizeof(paramspecattrobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspeckwargs_slots, }; @@ -1007,7 +1009,7 @@ PyType_Spec paramspec_spec = { .name = "typing.ParamSpec", .basicsize = sizeof(paramspecobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_MANAGED_DICT, + | Py_TPFLAGS_MANAGED_DICT | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspec_slots, }; @@ -1228,7 +1230,7 @@ PyType_Spec typevartuple_spec = { .name = "typing.TypeVarTuple", .basicsize = sizeof(typevartupleobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT - | Py_TPFLAGS_HAVE_GC, + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_WEAKREF, .slots = typevartuple_slots, }; From 139e7ac7c2a798820554abb6c84b9feaf810c493 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 10:40:59 -0700 Subject: [PATCH 0343/1206] [3.12] gh-106625 : Add missing code to tutorial 4.6 example (GH-106623) (#106636) (cherry picked from commit d0b7e18262e69dd4b8252e804e4f98fc9533bcd6) Co-authored-by: RustyNail Co-authored-by: Terry Jan Reedy --- Doc/tutorial/controlflow.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index c9b3d982c31c9a..4336bf50df40a7 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -307,8 +307,9 @@ you can use the class name followed by an argument list resembling a constructor, but with the ability to capture attributes into variables:: class Point: - x: int - y: int + def __init__(self, x, y): + self.x = x + self.y = y def where_is(point): match point: From 46a21f5c5e99aa3017618c7bb52d3254a6c0257b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:35:13 -0700 Subject: [PATCH 0344/1206] [3.12] gh-102541: Add test case for help() for non_existent_module (GH-106340) (#106639) gh-102541: Add test case for help() for non_existent_module (GH-106340) Test fix for when one enters, for instance, 'abd' at the 'help>' prompt. --------- (cherry picked from commit 292ac4bfe92768140c2d383fd329cfa1949869b2) Co-authored-by: Kirill Podoprigora Co-authored-by: Terry Jan Reedy --- Lib/test/test_pydoc.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 115ffd3c29d4d6..ddb5187f90da9b 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -24,7 +24,8 @@ from urllib.request import urlopen, urlcleanup from test.support import import_helper from test.support import os_helper -from test.support.script_helper import assert_python_ok, assert_python_failure +from test.support.script_helper import (assert_python_ok, + assert_python_failure, spawn_python) from test.support import threading_helper from test.support import (reap_children, captured_output, captured_stdout, captured_stderr, is_emscripten, is_wasi, @@ -631,6 +632,14 @@ def test_builtin_on_metaclasses(self): # Testing that the subclasses section does not appear self.assertNotIn('Built-in subclasses', text) + def test_fail_help_cli(self): + elines = (missing_pattern % 'abd').splitlines() + with spawn_python("-c" "help()") as proc: + out, _ = proc.communicate(b"abd") + olines = out.decode().splitlines()[-9:-6] + olines[0] = olines[0].removeprefix('help> ') + self.assertEqual(elines, olines) + def test_fail_help_output_redirect(self): with StringIO() as buf: helper = pydoc.Helper(output=buf) From bf7e92583dd33aa7e83d5929f2138c5d6957f571 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 13:31:16 -0700 Subject: [PATCH 0345/1206] [3.12] gh-96165: Clarify omitting the FROM clause in SQLite queries (GH-106513) (#106645) (cherry picked from commit fc7ff1af457e27b7d9752600b3436641be90f598) Co-authored-by: Mariusz Felisiak --- Doc/library/sqlite3.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 3ca8ea9011c7e0..26f4bfd06f5bbc 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -2522,6 +2522,13 @@ Queries now return :class:`!Row` objects: >>> row["RADIUS"] # Column names are case-insensitive. 6378 +.. note:: + + The ``FROM`` clause can be omitted in the ``SELECT`` statement, as in the + above example. In such cases, SQLite returns a single row with columns + defined by expressions, e.g. literals, with the given aliases + ``expr AS alias``. + You can create a custom :attr:`~Cursor.row_factory` that returns each row as a :class:`dict`, with column names mapped to values: From e248ba7b72adad794399d7b55116862fa31471fd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 13:31:48 -0700 Subject: [PATCH 0346/1206] [3.12] gh-96165: Clarify passing ":memory:" in sqlite3.connect() (GH-106451) (#106647) (cherry picked from commit f520804b039df0d87fb9df6f1fed2a9bc9df8d61) Co-authored-by: Mariusz Felisiak --- Doc/library/sqlite3.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 26f4bfd06f5bbc..2e2c28b1e5fe73 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -266,8 +266,9 @@ Module functions :param database: The path to the database file to be opened. - Pass ``":memory:"`` to open a connection to a database that is - in RAM instead of on disk. + You can pass ``":memory:"`` to create an `SQLite database existing only + in memory `_, and open a connection + to it. :type database: :term:`path-like object` :param float timeout: From ae315991431df5172799ef7ccc0202ac7c0841c9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 11 Jul 2023 19:46:12 -0700 Subject: [PATCH 0347/1206] [3.12] Add Plausible for docs metrics (GH-106644) (#106661) Add Plausible for docs metrics (GH-106644) (cherry picked from commit e8ab0096a583184fe24dfbc39eff70d270c8e6f4) Co-authored-by: Hugo van Kemenade --- Doc/tools/templates/layout.html | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index b91f8138553e62..10cb6fd880fa1a 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -26,6 +26,7 @@ {% endblock %} {% block extrahead %} + {% if builder != "htmlhelp" %} {% if pagename == 'whatsnew/changelog' and not embedded %} From af06a8ad4d94f78d86d59a6268b3f38543921beb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 12 Jul 2023 00:32:51 -0700 Subject: [PATCH 0348/1206] [3.12] gh-103186: In test_tools.freeze, fetch CONFIG_ARGS from original source directory (GH-103213) (#106667) gh-103186: In test_tools.freeze, fetch CONFIG_ARGS from original source directory (GH-103213) Fetch CONFIG_ARGS from the original source directory, instead of from the copied source tree. When "make clean" is executed in the copied source tree, the build directory is cleared and the configure argument lookup fails. However, the original source directory still contains this information. (cherry picked from commit de827322ca47e51d52ff44536a7c3fd44648383a) Co-authored-by: Ijtaba Hussain --- .../Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst | 2 ++ Tools/freeze/test/freeze.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst b/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst new file mode 100644 index 00000000000000..7e28ba6963216a --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst @@ -0,0 +1,2 @@ +``freeze`` now fetches ``CONFIG_ARGS`` from the original CPython instance +the Makefile uses to call utility scripts. Patch by Ijtaba Hussain. diff --git a/Tools/freeze/test/freeze.py b/Tools/freeze/test/freeze.py index f6a5adb4519fdb..92e97cb261719c 100644 --- a/Tools/freeze/test/freeze.py +++ b/Tools/freeze/test/freeze.py @@ -153,7 +153,7 @@ def prepare(script=None, outdir=None): print(f'configuring python in {builddir}...') cmd = [ os.path.join(srcdir, 'configure'), - *shlex.split(get_config_var(srcdir, 'CONFIG_ARGS') or ''), + *shlex.split(get_config_var(SRCDIR, 'CONFIG_ARGS') or ''), ] ensure_opt(cmd, 'cache-file', os.path.join(outdir, 'python-config.cache')) prefix = os.path.join(outdir, 'python-installation') From 6de9cffcd38b7ce0f6b914643d6df08b6fc750d3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 12 Jul 2023 07:30:52 -0700 Subject: [PATCH 0349/1206] [3.12] gh-99079: Update Windows build to use OpenSSL 3.0.9 (GH-106649) (#106680) gh-99079: Update Windows build to use OpenSSL 3.0.9 (GH-106649) (cherry picked from commit e2d7366fb3df44e7434132636d49f22d6d25cc9f) Co-authored-by: Steve Dower --- .../Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst | 1 + PCbuild/get_externals.bat | 4 ++-- PCbuild/openssl.props | 4 ++-- PCbuild/python.props | 4 ++-- PCbuild/readme.txt | 2 +- PCbuild/regen.targets | 3 ++- 6 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst diff --git a/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst b/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst new file mode 100644 index 00000000000000..11f411be0f17c5 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst @@ -0,0 +1 @@ +Update Windows build to use OpenSSL 3.0.9 diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 534a9ebcfd151a..77b9594799ea79 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1u +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.9 set libraries=%libraries% sqlite-3.42.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 @@ -77,7 +77,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1u +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.9 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.13.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/openssl.props b/PCbuild/openssl.props index 7071bb57c06cd7..5fd708b211e42d 100644 --- a/PCbuild/openssl.props +++ b/PCbuild/openssl.props @@ -10,10 +10,10 @@ - <_DLLSuffix>-1_1 + <_DLLSuffix>-3 <_DLLSuffix Condition="$(Platform) == 'ARM'">$(_DLLSuffix)-arm <_DLLSuffix Condition="$(Platform) == 'ARM64'">$(_DLLSuffix)-arm64 - $(_DLLSuffix) + $(_DLLSuffix) <_SSLDLL Include="$(opensslOutDir)\libcrypto$(_DLLSuffix).dll" /> diff --git a/PCbuild/python.props b/PCbuild/python.props index 68052ef668aa6c..d3586235c82652 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -74,8 +74,8 @@ $(ExternalsDir)libffi-3.4.4\ $(libffiDir)$(ArchName)\ $(libffiOutDir)include - $(ExternalsDir)openssl-1.1.1u\ - $(ExternalsDir)openssl-bin-1.1.1u\$(ArchName)\ + $(ExternalsDir)openssl-3.0.9\ + $(ExternalsDir)openssl-bin-3.0.9\$(ArchName)\ $(opensslOutDir)include $(ExternalsDir)\nasm-2.11.06\ $(ExternalsDir)\zlib-1.2.13\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 784d3ce6a60660..2ab4537b99882e 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -169,7 +169,7 @@ _lzma Homepage: https://tukaani.org/xz/ _ssl - Python wrapper for version 1.1.1u of the OpenSSL secure sockets + Python wrapper for version 3.0 of the OpenSSL secure sockets library, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/PCbuild/regen.targets b/PCbuild/regen.targets index 107066817ba6b0..af07adeca8812b 100644 --- a/PCbuild/regen.targets +++ b/PCbuild/regen.targets @@ -104,8 +104,9 @@ <_LicenseSources Include="$(PySourcePath)LICENSE; $(PySourcePath)PC\crtlicense.txt; $(bz2Dir)LICENSE; - $(opensslOutDir)LICENSE; $(libffiDir)LICENSE;" /> + <_LicenseSources Include="$(opensslOutDir)LICENSE.txt" Condition="Exists('$(opensslOutDir)LICENSE.txt')" /> + <_LicenseSources Include="$(opensslOutDir)LICENSE" Condition="!Exists('$(opensslOutDir)LICENSE.txt')" /> <_LicenseSources Include="$(tcltkDir)tcllicense.terms; $(tcltkDir)tklicense.terms; $(tcltkDir)tixlicense.terms" Condition="$(IncludeTkinter)" /> From ec7b05a0bebb2cc2ec42bf00cde2b66145880459 Mon Sep 17 00:00:00 2001 From: Yonatan Bitton Date: Thu, 13 Jul 2023 00:58:51 +0300 Subject: [PATCH 0350/1206] [3.12] gh-96747: Mention the PyPI `passlib` package in the `crypt` deprecation doc (GH-106660) (#106660) * Added mention to passlib package as alternative to the deprecated crypt module. --- Doc/library/crypt.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/crypt.rst b/Doc/library/crypt.rst index 740084b40c5ac9..51f91463f5ff93 100644 --- a/Doc/library/crypt.rst +++ b/Doc/library/crypt.rst @@ -20,6 +20,7 @@ The :mod:`crypt` module is deprecated (see :pep:`PEP 594 <594#crypt>` for details and alternatives). The :mod:`hashlib` module is a potential replacement for certain use cases. + The `passlib `_ package can replace all use cases of this module. -------------- From 77d9fdf23be4b705b65b08ed00bb5df7988ecf3c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:47:53 -0700 Subject: [PATCH 0351/1206] [3.12] gh-106602: [Enum] Add __copy__ and __deepcopy__ (GH-106695) gh-106602: [Enum] Add __copy__ and __deepcopy__ (GH-106666) (cherry picked from commit 357e9e9da3929cb9d55ea31896e66f488e44e8f2) Co-authored-by: Prince Roshan --- Lib/enum.py | 6 ++++++ Lib/test/test_enum.py | 8 ++++++++ .../2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst | 1 + 3 files changed, 15 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst diff --git a/Lib/enum.py b/Lib/enum.py index 56ebfbd1a61f7a..9114c5ccaaa95c 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1242,6 +1242,12 @@ def __hash__(self): def __reduce_ex__(self, proto): return self.__class__, (self._value_, ) + def __deepcopy__(self,memo): + return self + + def __copy__(self): + return self + # enum.property is used to provide access to the `name` and # `value` attributes of enum members while keeping some measure of # protection from modification, while still allowing for an enumeration diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 592deb837914cb..dbdc639d62ec1f 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -804,9 +804,17 @@ def test_copy(self): TE = self.MainEnum copied = copy.copy(TE) self.assertEqual(copied, TE) + self.assertIs(copied, TE) deep = copy.deepcopy(TE) self.assertEqual(deep, TE) + self.assertIs(deep, TE) + def test_copy_member(self): + TE = self.MainEnum + copied = copy.copy(TE.first) + self.assertIs(copied, TE.first) + deep = copy.deepcopy(TE.first) + self.assertIs(deep, TE.first) class _FlagTests: diff --git a/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst b/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst new file mode 100644 index 00000000000000..d9c122f1d3c723 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst @@ -0,0 +1 @@ +Add __copy__ and __deepcopy__ in :mod:`enum` From 6a1a6601582ea893a81fd613f6432c85fc14f460 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:52:21 -0700 Subject: [PATCH 0352/1206] [3.12] gh-106368: Increase Argument Clinic test coverage (GH-106728) (#106730) - improve output_parameter() coverage - improve coverage for Function.kind (cherry picked from commit ec45c513d389510930a62631a21a1dbb3f3aabb7) Co-authored-by: Erlend E. Aasland --- Lib/test/clinic.test.c | 553 ++++++++++++++++++++++++++++++++++++++++ Lib/test/test_clinic.py | 37 +++ 2 files changed, 590 insertions(+) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 564205274edd73..1544599c29fa04 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -3,6 +3,10 @@ output preset block [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=3c81ac2402d06a8b]*/ +/*[clinic input] +class Test "TestObj *" "TestType" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=fc7e50384d12b83f]*/ /*[clinic input] test_object_converter @@ -61,6 +65,58 @@ test_object_converter_impl(PyObject *module, PyObject *a, PyObject *b, /*[clinic end generated code: output=886f4f9b598726b6 input=005e6a8a711a869b]*/ +/*[clinic input] +cloned = test_object_converter +Check the clone feature. +[clinic start generated code]*/ + +PyDoc_STRVAR(cloned__doc__, +"cloned($module, a, b, c, d, /)\n" +"--\n" +"\n" +"Check the clone feature."); + +#define CLONED_METHODDEF \ + {"cloned", _PyCFunction_CAST(cloned), METH_FASTCALL, cloned__doc__}, + +static PyObject * +cloned_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, + PyUnicode_Object *d); + +static PyObject * +cloned(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + PyObject *c; + PyUnicode_Object *d; + + if (!_PyArg_CheckPositional("cloned", nargs, 4, 4)) { + goto exit; + } + a = args[0]; + if (!PyUnicode_FSConverter(args[1], &b)) { + goto exit; + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("cloned", "argument 3", "str", args[2]); + goto exit; + } + c = args[2]; + d = (PyUnicode_Object *)args[3]; + return_value = cloned_impl(module, a, b, c, d); + +exit: + return return_value; +} + +static PyObject * +cloned_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, + PyUnicode_Object *d) +/*[clinic end generated code: output=026b483e27c38065 input=0543614019d6fcc7]*/ + + /*[clinic input] test_object_converter_one_arg @@ -4271,3 +4327,500 @@ static PyObject * mangle2_impl(PyObject *module, PyObject *args, PyObject *kwargs, PyObject *return_value) /*[clinic end generated code: output=2ebb62aaefe7590a input=391766fee51bad7a]*/ + + +/*[clinic input] +Test.cls_with_param + cls: defining_class + / + a: int +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_cls_with_param__doc__, +"cls_with_param($self, /, a)\n" +"--\n" +"\n"); + +#define TEST_CLS_WITH_PARAM_METHODDEF \ + {"cls_with_param", _PyCFunction_CAST(Test_cls_with_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, Test_cls_with_param__doc__}, + +static PyObject * +Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a); + +static PyObject * +Test_cls_with_param(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(a), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"a", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "cls_with_param", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int a; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + a = _PyLong_AsInt(args[0]); + if (a == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = Test_cls_with_param_impl(self, cls, a); + +exit: + return return_value; +} + +static PyObject * +Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a) +/*[clinic end generated code: output=00218e7f583e6c81 input=af158077bd237ef9]*/ + + +/*[clinic input] +Test.__init__ +Empty init method. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test___init____doc__, +"Test()\n" +"--\n" +"\n" +"Empty init method."); + +static int +Test___init___impl(TestObj *self); + +static int +Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + PyTypeObject *base_tp = TestType; + + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoPositional("Test", args)) { + goto exit; + } + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + return_value = Test___init___impl((TestObj *)self); + +exit: + return return_value; +} + +static int +Test___init___impl(TestObj *self) +/*[clinic end generated code: output=f6a35c85bc5b408f input=4ea79fee54d0c3ff]*/ + + +/*[clinic input] +@classmethod +Test.__new__ +Empty new method. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test__doc__, +"Test()\n" +"--\n" +"\n" +"Empty new method."); + +static PyObject * +Test_impl(PyTypeObject *type); + +static PyObject * +Test(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = TestType; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoPositional("Test", args)) { + goto exit; + } + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + return_value = Test_impl(type); + +exit: + return return_value; +} + +static PyObject * +Test_impl(PyTypeObject *type) +/*[clinic end generated code: output=68a117adc057940f input=6fe98a19f097907f]*/ + + +/*[clinic input] +Test.cls_no_params + cls: defining_class + / +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_cls_no_params__doc__, +"cls_no_params($self, /)\n" +"--\n" +"\n"); + +#define TEST_CLS_NO_PARAMS_METHODDEF \ + {"cls_no_params", _PyCFunction_CAST(Test_cls_no_params), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, Test_cls_no_params__doc__}, + +static PyObject * +Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls); + +static PyObject * +Test_cls_no_params(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs) { + PyErr_SetString(PyExc_TypeError, "cls_no_params() takes no arguments"); + return NULL; + } + return Test_cls_no_params_impl(self, cls); +} + +static PyObject * +Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls) +/*[clinic end generated code: output=cc8845f22cff3dcb input=e7e2e4e344e96a11]*/ + + +/*[clinic input] +Test.metho_not_default_return_converter -> int + a: object + / +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_metho_not_default_return_converter__doc__, +"metho_not_default_return_converter($self, a, /)\n" +"--\n" +"\n"); + +#define TEST_METHO_NOT_DEFAULT_RETURN_CONVERTER_METHODDEF \ + {"metho_not_default_return_converter", (PyCFunction)Test_metho_not_default_return_converter, METH_O, Test_metho_not_default_return_converter__doc__}, + +static int +Test_metho_not_default_return_converter_impl(TestObj *self, PyObject *a); + +static PyObject * +Test_metho_not_default_return_converter(TestObj *self, PyObject *a) +{ + PyObject *return_value = NULL; + int _return_value; + + _return_value = Test_metho_not_default_return_converter_impl(self, a); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} + +static int +Test_metho_not_default_return_converter_impl(TestObj *self, PyObject *a) +/*[clinic end generated code: output=3350de11bd538007 input=428657129b521177]*/ + + +/*[clinic input] +Test.an_metho_arg_named_arg + arg: int + Name should be mangled to 'arg_' in generated output. + / +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_an_metho_arg_named_arg__doc__, +"an_metho_arg_named_arg($self, arg, /)\n" +"--\n" +"\n" +"\n" +"\n" +" arg\n" +" Name should be mangled to \'arg_\' in generated output."); + +#define TEST_AN_METHO_ARG_NAMED_ARG_METHODDEF \ + {"an_metho_arg_named_arg", (PyCFunction)Test_an_metho_arg_named_arg, METH_O, Test_an_metho_arg_named_arg__doc__}, + +static PyObject * +Test_an_metho_arg_named_arg_impl(TestObj *self, int arg); + +static PyObject * +Test_an_metho_arg_named_arg(TestObj *self, PyObject *arg_) +{ + PyObject *return_value = NULL; + int arg; + + arg = _PyLong_AsInt(arg_); + if (arg == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = Test_an_metho_arg_named_arg_impl(self, arg); + +exit: + return return_value; +} + +static PyObject * +Test_an_metho_arg_named_arg_impl(TestObj *self, int arg) +/*[clinic end generated code: output=7d590626642194ae input=2a53a57cf5624f95]*/ + + +/*[clinic input] +Test.__init__ + *args: object + / +Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test___init____doc__, +"Test(*args)\n" +"--\n" +"\n" +"Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE."); + +static int +Test___init___impl(TestObj *self, PyObject *args); + +static int +Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + PyTypeObject *base_tp = TestType; + PyObject *__clinic_args = NULL; + + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { + goto exit; + } + __clinic_args = PyTuple_GetSlice(0, -1); + return_value = Test___init___impl((TestObj *)self, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +static int +Test___init___impl(TestObj *self, PyObject *args) +/*[clinic end generated code: output=0ed1009fe0dcf98d input=96c3ddc0cd38fc0c]*/ + + +/*[clinic input] +@classmethod +Test.__new__ + *args: object + / +Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test__doc__, +"Test(*args)\n" +"--\n" +"\n" +"Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE."); + +static PyObject * +Test_impl(PyTypeObject *type, PyObject *args); + +static PyObject * +Test(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = TestType; + PyObject *__clinic_args = NULL; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { + goto exit; + } + __clinic_args = PyTuple_GetSlice(0, -1); + return_value = Test_impl(type, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +static PyObject * +Test_impl(PyTypeObject *type, PyObject *args) +/*[clinic end generated code: output=8b219f6633e2a2e9 input=26a672e2e9750120]*/ + + +/*[clinic input] +Test.__init__ + a: object +Init method with positional or keyword arguments. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test___init____doc__, +"Test(a)\n" +"--\n" +"\n" +"Init method with positional or keyword arguments."); + +static int +Test___init___impl(TestObj *self, PyObject *a); + +static int +Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(a), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"a", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "Test", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *a; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + return_value = Test___init___impl((TestObj *)self, a); + +exit: + return return_value; +} + +static int +Test___init___impl(TestObj *self, PyObject *a) +/*[clinic end generated code: output=0b9ca79638ab3ecb input=a8f9222a6ab35c59]*/ + + +/*[clinic input] +@classmethod +Test.class_method +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_class_method__doc__, +"class_method($type, /)\n" +"--\n" +"\n"); + +#define TEST_CLASS_METHOD_METHODDEF \ + {"class_method", (PyCFunction)Test_class_method, METH_NOARGS|METH_CLASS, Test_class_method__doc__}, + +static PyObject * +Test_class_method_impl(PyTypeObject *type); + +static PyObject * +Test_class_method(PyTypeObject *type, PyObject *Py_UNUSED(ignored)) +{ + return Test_class_method_impl(type); +} + +static PyObject * +Test_class_method_impl(PyTypeObject *type) +/*[clinic end generated code: output=47fb7ecca1abcaaa input=43bc4a0494547b80]*/ + + +/*[clinic input] +@staticmethod +Test.static_method +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_static_method__doc__, +"static_method()\n" +"--\n" +"\n"); + +#define TEST_STATIC_METHOD_METHODDEF \ + {"static_method", (PyCFunction)Test_static_method, METH_NOARGS|METH_STATIC, Test_static_method__doc__}, + +static PyObject * +Test_static_method_impl(); + +static PyObject * +Test_static_method(void *null, PyObject *Py_UNUSED(ignored)) +{ + return Test_static_method_impl(); +} + +static PyObject * +Test_static_method_impl() +/*[clinic end generated code: output=82524a63025cf7ab input=dae892fac55ae72b]*/ + + +/*[clinic input] +@coexist +Test.meth_coexist +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_meth_coexist__doc__, +"meth_coexist($self, /)\n" +"--\n" +"\n"); + +#define TEST_METH_COEXIST_METHODDEF \ + {"meth_coexist", (PyCFunction)Test_meth_coexist, METH_NOARGS|METH_COEXIST, Test_meth_coexist__doc__}, + +static PyObject * +Test_meth_coexist_impl(TestObj *self); + +static PyObject * +Test_meth_coexist(TestObj *self, PyObject *Py_UNUSED(ignored)) +{ + return Test_meth_coexist_impl(self); +} + +static PyObject * +Test_meth_coexist_impl(TestObj *self) +/*[clinic end generated code: output=808a293d0cd27439 input=2a1d75b5e6fec6dd]*/ diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 685ba58642a5ae..975840333e5901 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1013,6 +1013,43 @@ def test_defining_class_param_cannot_be_optional(self): out = self.parse_function_should_fail(block) self.assertEqual(out, expected_error_msg) + def test_slot_methods_cannot_access_defining_class(self): + block = """ + module foo + class Foo "" "" + Foo.__init__ + cls: defining_class + a: object + """ + msg = "Slot methods cannot access their defining class." + with self.assertRaisesRegex(ValueError, msg): + self.parse_function(block) + + def test_new_must_be_a_class_method(self): + expected_error_msg = ( + "Error on line 0:\n" + "__new__ must be a class method!\n" + ) + out = self.parse_function_should_fail(""" + module foo + class Foo "" "" + Foo.__new__ + """) + self.assertEqual(out, expected_error_msg) + + def test_init_must_be_a_normal_method(self): + expected_error_msg = ( + "Error on line 0:\n" + "__init__ must be a normal method, not a class or static method!\n" + ) + out = self.parse_function_should_fail(""" + module foo + class Foo "" "" + @classmethod + Foo.__init__ + """) + self.assertEqual(out, expected_error_msg) + def test_unused_param(self): block = self.parse(""" module foo From e68b2806717997db4fae338f906bd8d60ae9381f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 14 Jul 2023 00:21:02 -0700 Subject: [PATCH 0353/1206] [3.12] gh-105626: Change the default return value of `HTTPConnection.get_proxy_response_headers` (GH-105628) (#106738) gh-105626: Change the default return value of `HTTPConnection.get_proxy_response_headers` (GH-105628) (cherry picked from commit 490295d651d04ec3b3eff2a2cda7501191bad78a) Co-authored-by: Nikita Sobolev --- Doc/library/http.client.rst | 2 +- Lib/http/client.py | 5 ++--- Lib/test/test_httplib.py | 13 +++++++++++++ .../2023-06-10-12-20-17.gh-issue-105626.XyZein.rst | 3 +++ 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 45291933d635b9..b9ceab699cef63 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -390,7 +390,7 @@ HTTPConnection Objects Returns a dictionary with the headers of the response received from the proxy server to the CONNECT request. - If the CONNECT request was not sent, the method returns an empty dictionary. + If the CONNECT request was not sent, the method returns ``None``. .. versionadded:: 3.12 diff --git a/Lib/http/client.py b/Lib/http/client.py index 3d98e4eb54bb45..b35b1d6368aae7 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -970,13 +970,12 @@ def get_proxy_response_headers(self): received from the proxy server to the CONNECT request sent to set the tunnel. - If the CONNECT request was not sent, the method returns - an empty dictionary. + If the CONNECT request was not sent, the method returns None. """ return ( _parse_header_lines(self._raw_proxy_headers) if self._raw_proxy_headers is not None - else {} + else None ) def connect(self): diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 8955d45fa93dd4..fe8105ee2bb3fa 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -2404,6 +2404,19 @@ def test_proxy_response_headers(self): headers = self.conn.get_proxy_response_headers() self.assertIn(expected_header, headers.items()) + def test_no_proxy_response_headers(self): + expected_header = ('X-Dummy', '1') + response_text = ( + 'HTTP/1.0 200 OK\r\n' + '{0}\r\n\r\n'.format(':'.join(expected_header)) + ) + + self.conn._create_connection = self._create_connection(response_text) + + self.conn.request('PUT', '/', '') + headers = self.conn.get_proxy_response_headers() + self.assertIsNone(headers) + def test_tunnel_leak(self): sock = None diff --git a/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst b/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst new file mode 100644 index 00000000000000..2a48361fa596c9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst @@ -0,0 +1,3 @@ +Change the default return value of +:meth:`http.client.HTTPConnection.get_proxy_response_headers` to be ``None`` +and not ``{}``. From 00eb4355e3c3ac891f0951d0ee46b0da3fdc2616 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 14 Jul 2023 01:01:35 -0700 Subject: [PATCH 0354/1206] [3.12] gh-106446: Fix failed doctest in stdtypes (GH-106447) (#106741) (cherry picked from commit 89867d2491c0c3ef77bc237899b2f0762f43c03c) Co-authored-by: Charlie Zhao Co-authored-by: Terry Jan Reedy --- Doc/library/stdtypes.rst | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 0ac727e0df38b3..092f2719379e8a 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -3950,7 +3950,7 @@ copying. >>> m = memoryview(bytearray(b'abc')) >>> mm = m.toreadonly() >>> mm.tolist() - [89, 98, 99] + [97, 98, 99] >>> mm[0] = 42 Traceback (most recent call last): File "", line 1, in @@ -4006,6 +4006,7 @@ copying. :mod:`struct` syntax. One of the formats must be a byte format ('B', 'b' or 'c'). The byte length of the result must be the same as the original length. + Note that all byte lengths may depend on the operating system. Cast 1D/long to 1D/unsigned bytes:: @@ -4036,8 +4037,8 @@ copying. >>> x = memoryview(b) >>> x[0] = b'a' Traceback (most recent call last): - File "", line 1, in - ValueError: memoryview: invalid value for format "B" + ... + TypeError: memoryview: invalid type for format 'B' >>> y = x.cast('c') >>> y[0] = b'a' >>> b @@ -4786,10 +4787,10 @@ An example of dictionary view usage:: >>> # set operations >>> keys & {'eggs', 'bacon', 'salad'} {'bacon'} - >>> keys ^ {'sausage', 'juice'} - {'juice', 'sausage', 'bacon', 'spam'} - >>> keys | ['juice', 'juice', 'juice'] - {'juice', 'sausage', 'bacon', 'spam', 'eggs'} + >>> keys ^ {'sausage', 'juice'} == {'juice', 'sausage', 'bacon', 'spam'} + True + >>> keys | ['juice', 'juice', 'juice'] == {'bacon', 'spam', 'juice'} + True >>> # get back a read-only proxy for the original dictionary >>> values.mapping @@ -4996,8 +4997,8 @@ exception to disallow mistakes like ``dict[str][str]``:: >>> dict[str][str] Traceback (most recent call last): - File "", line 1, in - TypeError: There are no type variables left in dict[str] + ... + TypeError: dict[str] is not a generic class However, such expressions are valid when :ref:`type variables ` are used. The index must have as many elements as there are type variable items @@ -5203,13 +5204,15 @@ enables cleaner type hinting syntax compared to :data:`typing.Union`. >>> isinstance("", int | str) True - However, union objects containing :ref:`parameterized generics - ` cannot be used:: + However, :ref:`parameterized generics ` in + union objects cannot be checked:: - >>> isinstance(1, int | list[int]) + >>> isinstance(1, int | list[int]) # short-circuit evaluation + True + >>> isinstance([1], int | list[int]) Traceback (most recent call last): - File "", line 1, in - TypeError: isinstance() argument 2 cannot contain a parameterized generic + ... + TypeError: isinstance() argument 2 cannot be a parameterized generic The user-exposed type for the union object can be accessed from :data:`types.UnionType` and used for :func:`isinstance` checks. An object cannot be @@ -5512,7 +5515,7 @@ types, where they are relevant. Some of these are not reported by the definition order. Example:: >>> int.__subclasses__() - [] + [, , , ] .. _int_max_str_digits: @@ -5548,7 +5551,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> _ = int('2' * 5432) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit. + ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit >>> i = int('2' * 4300) >>> len(str(i)) 4300 @@ -5556,7 +5559,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> len(str(i_squared)) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit. + ValueError: Exceeds the limit (4300 digits) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit >>> len(hex(i_squared)) 7144 >>> assert int(hex(i_squared), base=16) == i*i # Hexadecimal is unlimited. From dfdded6bebc862edf1b286690b54538eccea8923 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 14 Jul 2023 02:40:32 -0700 Subject: [PATCH 0355/1206] [3.12] gh-106634: Corrected minor asyncio doc issues (GH-106671) (#106712) gh-106634: Corrected minor asyncio doc issues (GH-106671) (cherry picked from commit 4b4a5b70aa8d47b1e2a0582b741c31b786da762a) Co-authored-by: Chris Brett --- Lib/asyncio/base_events.py | 2 +- Lib/asyncio/events.py | 2 +- Misc/ACKS | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 32d7e1c481ecc5..259004650d5ab3 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -727,7 +727,7 @@ def call_later(self, delay, callback, *args, context=None): always relative to the current time. Each callback will be called exactly once. If two callbacks - are scheduled for exactly the same time, it undefined which + are scheduled for exactly the same time, it is undefined which will be called first. Any positional arguments after the callback will be passed to diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index ce44942186b272..0ccf85105e6673 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -617,7 +617,7 @@ class AbstractEventLoopPolicy: def get_event_loop(self): """Get the event loop for the current context. - Returns an event loop object implementing the BaseEventLoop interface, + Returns an event loop object implementing the AbstractEventLoop interface, or raises an exception in case no event loop has been set for the current context and the current policy does not specify to create one. diff --git a/Misc/ACKS b/Misc/ACKS index ef0029a7e4119d..645ad5b700baaa 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -226,6 +226,7 @@ Erik Bray Brian Brazil Demian Brecht Dave Brennan +Christopher Richard James Brett Tom Bridgman Anthony Briggs Keith Briggs From 30f62748e99ef2af3bfbac0e2d84dccf48c81512 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 14 Jul 2023 17:11:13 -0400 Subject: [PATCH 0356/1206] [3.12] gh-106752: Move zipfile._path into its own package (GH-106753) (#106755) * gh-106752: Move zipfile._path into its own package so it may have supplementary behavior. * Add blurb. (cherry picked from commit 03185f0c150ebc52d41dd5ea6f369c7b5ba9fc16) --- .github/CODEOWNERS | 2 +- Lib/test/test_zipfile/_path/__init__.py | 0 Lib/test/test_zipfile/{ => _path}/_functools.py | 0 Lib/test/test_zipfile/{ => _path}/_itertools.py | 0 Lib/test/test_zipfile/{ => _path}/_support.py | 0 Lib/test/test_zipfile/{ => _path}/_test_params.py | 0 Lib/test/test_zipfile/{ => _path}/test_complexity.py | 0 Lib/test/test_zipfile/{ => _path}/test_path.py | 0 Lib/zipfile/{_path.py => _path/__init__.py} | 0 Makefile.pre.in | 3 ++- .../next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst | 2 ++ 11 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Lib/test/test_zipfile/_path/__init__.py rename Lib/test/test_zipfile/{ => _path}/_functools.py (100%) rename Lib/test/test_zipfile/{ => _path}/_itertools.py (100%) rename Lib/test/test_zipfile/{ => _path}/_support.py (100%) rename Lib/test/test_zipfile/{ => _path}/_test_params.py (100%) rename Lib/test/test_zipfile/{ => _path}/test_complexity.py (100%) rename Lib/test/test_zipfile/{ => _path}/test_path.py (100%) rename Lib/zipfile/{_path.py => _path/__init__.py} (100%) create mode 100644 Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 32ba5355a5853f..95fd51b743cd33 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -164,4 +164,4 @@ Lib/ast.py @isidentical **/*pathlib* @barneygale # zipfile.Path -**/*zipfile/*_path.py @jaraco +**/*zipfile/_path/* @jaraco diff --git a/Lib/test/test_zipfile/_path/__init__.py b/Lib/test/test_zipfile/_path/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/Lib/test/test_zipfile/_functools.py b/Lib/test/test_zipfile/_path/_functools.py similarity index 100% rename from Lib/test/test_zipfile/_functools.py rename to Lib/test/test_zipfile/_path/_functools.py diff --git a/Lib/test/test_zipfile/_itertools.py b/Lib/test/test_zipfile/_path/_itertools.py similarity index 100% rename from Lib/test/test_zipfile/_itertools.py rename to Lib/test/test_zipfile/_path/_itertools.py diff --git a/Lib/test/test_zipfile/_support.py b/Lib/test/test_zipfile/_path/_support.py similarity index 100% rename from Lib/test/test_zipfile/_support.py rename to Lib/test/test_zipfile/_path/_support.py diff --git a/Lib/test/test_zipfile/_test_params.py b/Lib/test/test_zipfile/_path/_test_params.py similarity index 100% rename from Lib/test/test_zipfile/_test_params.py rename to Lib/test/test_zipfile/_path/_test_params.py diff --git a/Lib/test/test_zipfile/test_complexity.py b/Lib/test/test_zipfile/_path/test_complexity.py similarity index 100% rename from Lib/test/test_zipfile/test_complexity.py rename to Lib/test/test_zipfile/_path/test_complexity.py diff --git a/Lib/test/test_zipfile/test_path.py b/Lib/test/test_zipfile/_path/test_path.py similarity index 100% rename from Lib/test/test_zipfile/test_path.py rename to Lib/test/test_zipfile/_path/test_path.py diff --git a/Lib/zipfile/_path.py b/Lib/zipfile/_path/__init__.py similarity index 100% rename from Lib/zipfile/_path.py rename to Lib/zipfile/_path/__init__.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 12788d11d1d145..8dacb570ccafab 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2110,7 +2110,7 @@ LIBSUBDIRS= asyncio \ wsgiref \ $(XMLLIBSUBDIRS) \ xmlrpc \ - zipfile \ + zipfile zipfile/_path \ zoneinfo \ __phello__ TESTSUBDIRS= idlelib/idle_test \ @@ -2220,6 +2220,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_warnings \ test/test_warnings/data \ test/test_zipfile \ + test/test_zipfile/_path \ test/test_zoneinfo \ test/test_zoneinfo/data \ test/tracedmodules \ diff --git a/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst b/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst new file mode 100644 index 00000000000000..ba7257e3610808 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst @@ -0,0 +1,2 @@ +Moved tests for ``zipfile.Path`` into ``Lib/test/test_zipfile/_path``. Made +``zipfile._path`` a package. From 4f3edd6b535b6a0b7352df134c0f445ab279bfc0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 14 Jul 2023 19:15:14 -0700 Subject: [PATCH 0357/1206] [3.12] gh-105235: Prevent reading outside buffer during mmap.find() (GH-105252) (#106708) gh-105235: Prevent reading outside buffer during mmap.find() (GH-105252) * Add a special case for s[-m:] == p in _PyBytes_Find * Add tests for _PyBytes_Find * Make sure that start <= end in mmap.find (cherry picked from commit ab86426a3472ab68747815299d390b213793c3d1) Co-authored-by: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> --- Lib/test/test_mmap.py | 21 ++++ ...-06-02-19-37-29.gh-issue-105235.fgFGTi.rst | 1 + Modules/_testinternalcapi.c | 114 ++++++++++++++++++ Modules/mmapmodule.c | 7 +- Objects/bytesobject.c | 21 +++- 5 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 517cbe0cb115ab..bab868600895c1 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -299,6 +299,27 @@ def test_find_end(self): self.assertEqual(m.find(b'one', 1, -2), -1) self.assertEqual(m.find(bytearray(b'one')), 0) + for i in range(-n-1, n+1): + for j in range(-n-1, n+1): + for p in [b"o", b"on", b"two", b"ones", b"s"]: + expected = data.find(p, i, j) + self.assertEqual(m.find(p, i, j), expected, (p, i, j)) + + def test_find_does_not_access_beyond_buffer(self): + try: + flags = mmap.MAP_PRIVATE | mmap.MAP_ANONYMOUS + PAGESIZE = mmap.PAGESIZE + PROT_NONE = 0 + PROT_READ = mmap.PROT_READ + except AttributeError as e: + raise unittest.SkipTest("mmap flags unavailable") from e + for i in range(0, 2049): + with mmap.mmap(-1, PAGESIZE * (i + 1), + flags=flags, prot=PROT_NONE) as guard: + with mmap.mmap(-1, PAGESIZE * (i + 2048), + flags=flags, prot=PROT_READ) as fm: + fm.find(b"fo", -2) + def test_rfind(self): # test the new 'end' parameter works as expected diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst new file mode 100644 index 00000000000000..c28d0101cd4bad --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst @@ -0,0 +1 @@ +Prevent out-of-bounds memory access during ``mmap.find()`` calls. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 7e2def7c20b1bb..98f99e4d66cf1f 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -15,6 +15,7 @@ #include "frameobject.h" #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() +#include "pycore_bytesobject.h" // _PyBytes_Find() #include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble #include "pycore_ceval.h" // _PyEval_AddPendingCall #include "pycore_fileutils.h" // _Py_normpath @@ -441,6 +442,118 @@ test_edit_cost(PyObject *self, PyObject *Py_UNUSED(args)) } +static int +check_bytes_find(const char *haystack0, const char *needle0, + int offset, Py_ssize_t expected) +{ + Py_ssize_t len_haystack = strlen(haystack0); + Py_ssize_t len_needle = strlen(needle0); + Py_ssize_t result_1 = _PyBytes_Find(haystack0, len_haystack, + needle0, len_needle, offset); + if (result_1 != expected) { + PyErr_Format(PyExc_AssertionError, + "Incorrect result_1: '%s' in '%s' (offset=%zd)", + needle0, haystack0, offset); + return -1; + } + // Allocate new buffer with no NULL terminator. + char *haystack = PyMem_Malloc(len_haystack); + if (haystack == NULL) { + PyErr_NoMemory(); + return -1; + } + char *needle = PyMem_Malloc(len_needle); + if (needle == NULL) { + PyMem_Free(haystack); + PyErr_NoMemory(); + return -1; + } + memcpy(haystack, haystack0, len_haystack); + memcpy(needle, needle0, len_needle); + Py_ssize_t result_2 = _PyBytes_Find(haystack, len_haystack, + needle, len_needle, offset); + PyMem_Free(haystack); + PyMem_Free(needle); + if (result_2 != expected) { + PyErr_Format(PyExc_AssertionError, + "Incorrect result_2: '%s' in '%s' (offset=%zd)", + needle0, haystack0, offset); + return -1; + } + return 0; +} + +static int +check_bytes_find_large(Py_ssize_t len_haystack, Py_ssize_t len_needle, + const char *needle) +{ + char *zeros = PyMem_RawCalloc(len_haystack, 1); + if (zeros == NULL) { + PyErr_NoMemory(); + return -1; + } + Py_ssize_t res = _PyBytes_Find(zeros, len_haystack, needle, len_needle, 0); + PyMem_RawFree(zeros); + if (res != -1) { + PyErr_Format(PyExc_AssertionError, + "check_bytes_find_large(%zd, %zd) found %zd", + len_haystack, len_needle, res); + return -1; + } + return 0; +} + +static PyObject * +test_bytes_find(PyObject *self, PyObject *Py_UNUSED(args)) +{ + #define CHECK(H, N, O, E) do { \ + if (check_bytes_find(H, N, O, E) < 0) { \ + return NULL; \ + } \ + } while (0) + + CHECK("", "", 0, 0); + CHECK("Python", "", 0, 0); + CHECK("Python", "", 3, 3); + CHECK("Python", "", 6, 6); + CHECK("Python", "yth", 0, 1); + CHECK("ython", "yth", 1, 1); + CHECK("thon", "yth", 2, -1); + CHECK("Python", "thon", 0, 2); + CHECK("ython", "thon", 1, 2); + CHECK("thon", "thon", 2, 2); + CHECK("hon", "thon", 3, -1); + CHECK("Pytho", "zz", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ab", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ba", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bb", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", "ab", 0, 30); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaba", "ba", 0, 30); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb", "bb", 0, 30); + #undef CHECK + + // Hunt for segfaults + // n, m chosen here so that (n - m) % (m + 1) == 0 + // This would make default_find in fastsearch.h access haystack[n]. + if (check_bytes_find_large(2048, 2, "ab") < 0) { + return NULL; + } + if (check_bytes_find_large(4096, 16, "0123456789abcdef") < 0) { + return NULL; + } + if (check_bytes_find_large(8192, 2, "ab") < 0) { + return NULL; + } + if (check_bytes_find_large(16384, 4, "abcd") < 0) { + return NULL; + } + if (check_bytes_find_large(32768, 2, "ab") < 0) { + return NULL; + } + Py_RETURN_NONE; +} + + static PyObject * normalize_path(PyObject *self, PyObject *filename) { @@ -950,6 +1063,7 @@ static PyMethodDef module_functions[] = { {"reset_path_config", test_reset_path_config, METH_NOARGS}, {"test_atomic_funcs", test_atomic_funcs, METH_NOARGS}, {"test_edit_cost", test_edit_cost, METH_NOARGS}, + {"test_bytes_find", test_bytes_find, METH_NOARGS}, {"normalize_path", normalize_path, METH_O, NULL}, {"get_getpath_codeobject", get_getpath_codeobject, METH_NOARGS, NULL}, {"EncodeLocaleEx", encode_locale_ex, METH_VARARGS}, diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 6bde9939eaa2ca..1ffadccb916253 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -343,12 +343,17 @@ mmap_gfind(mmap_object *self, Py_ssize_t res; CHECK_VALID_OR_RELEASE(NULL, view); - if (reverse) { + if (end < start) { + res = -1; + } + else if (reverse) { + assert(0 <= start && start <= end && end <= self->size); res = _PyBytes_ReverseFind( self->data + start, end - start, view.buf, view.len, start); } else { + assert(0 <= start && start <= end && end <= self->size); res = _PyBytes_Find( self->data + start, end - start, view.buf, view.len, start); diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index abbf3eeb16c35c..f3a978c86c3606 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1274,8 +1274,25 @@ _PyBytes_Find(const char *haystack, Py_ssize_t len_haystack, const char *needle, Py_ssize_t len_needle, Py_ssize_t offset) { - return stringlib_find(haystack, len_haystack, - needle, len_needle, offset); + assert(len_haystack >= 0); + assert(len_needle >= 0); + // Extra checks because stringlib_find accesses haystack[len_haystack]. + if (len_needle == 0) { + return offset; + } + if (len_needle > len_haystack) { + return -1; + } + assert(len_haystack >= 1); + Py_ssize_t res = stringlib_find(haystack, len_haystack - 1, + needle, len_needle, offset); + if (res == -1) { + Py_ssize_t last_align = len_haystack - len_needle; + if (memcmp(haystack + last_align, needle, len_needle) == 0) { + return offset + last_align; + } + } + return res; } Py_ssize_t From 1fe841254e453679ffeb16aa48ef633e67b7c08d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 15 Jul 2023 02:55:25 -0700 Subject: [PATCH 0358/1206] [3.12] gh-106368: Increase Argument Clinic BlockParser test coverage (GH-106759) (#106769) (cherry picked from commit 2d7d1aa4bcd5da0177458b22b1b856db76aa20d4) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 100 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 975840333e5901..b5744f7013d6ad 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -18,6 +18,19 @@ from clinic import DSLParser +class _ParserBase(TestCase): + maxDiff = None + + def expect_parser_failure(self, parser, _input): + with support.captured_stdout() as stdout: + with self.assertRaises(SystemExit): + parser(_input) + return stdout.getvalue() + + def parse_function_should_fail(self, _input): + return self.expect_parser_failure(self.parse_function, _input) + + class FakeConverter: def __init__(self, name, args): self.name = name @@ -88,7 +101,15 @@ def directive(self, name, args): _module_and_class = clinic.Clinic._module_and_class -class ClinicWholeFileTest(TestCase): + +class ClinicWholeFileTest(_ParserBase): + def setUp(self): + self.clinic = clinic.Clinic(clinic.CLanguage(None), filename="test.c") + + def expect_failure(self, raw): + _input = dedent(raw).strip() + return self.expect_parser_failure(self.clinic.parse, _input) + def test_eol(self): # regression test: # clinic's block parser didn't recognize @@ -98,15 +119,86 @@ def test_eol(self): # so it would spit out an end line for you. # and since you really already had one, # the last line of the block got corrupted. - c = clinic.Clinic(clinic.CLanguage(None), filename="file") raw = "/*[clinic]\nfoo\n[clinic]*/" - cooked = c.parse(raw).splitlines() + cooked = self.clinic.parse(raw).splitlines() end_line = cooked[2].rstrip() # this test is redundant, it's just here explicitly to catch # the regression test so we don't forget what it looked like self.assertNotEqual(end_line, "[clinic]*/[clinic]*/") self.assertEqual(end_line, "[clinic]*/") + def test_mangled_marker_line(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/ + /*[clinic end generated code: foo]*/ + """ + msg = ( + 'Error in file "test.c" on line 3:\n' + "Mangled Argument Clinic marker line: '/*[clinic end generated code: foo]*/'\n" + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_checksum_mismatch(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/ + /*[clinic end generated code: output=0123456789abcdef input=fedcba9876543210]*/ + """ + msg = ( + 'Error in file "test.c" on line 3:\n' + 'Checksum mismatch!\n' + 'Expected: 0123456789abcdef\n' + 'Computed: da39a3ee5e6b4b0d\n' + ) + out = self.expect_failure(raw) + self.assertIn(msg, out) + + def test_garbage_after_stop_line(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/foobarfoobar! + """ + msg = ( + 'Error in file "test.c" on line 2:\n' + "Garbage after stop line: 'foobarfoobar!'\n" + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_whitespace_before_stop_line(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/ + """ + msg = ( + 'Error in file "test.c" on line 2:\n' + "Whitespace is not allowed before the stop line: ' [clinic start generated code]*/'\n" + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_parse_with_body_prefix(self): + clang = clinic.CLanguage(None) + clang.body_prefix = "//" + clang.start_line = "//[{dsl_name} start]" + clang.stop_line = "//[{dsl_name} stop]" + cl = clinic.Clinic(clang, filename="test.c") + raw = dedent(""" + //[clinic start] + //module test + //[clinic stop] + """).strip() + out = cl.parse(raw) + expected = dedent(""" + //[clinic start] + //module test + // + //[clinic stop] + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=65fab8adff58cf08]*/ + """).lstrip() # Note, lstrip() because of the newline + self.assertEqual(out, expected) class ClinicGroupPermuterTest(TestCase): @@ -285,7 +377,7 @@ def test_clinic_1(self): """) -class ClinicParserTest(TestCase): +class ClinicParserTest(_ParserBase): def checkDocstring(self, fn, expected): self.assertTrue(hasattr(fn, "docstring")) self.assertEqual(fn.docstring.strip(), From e99b69c5aea1aed6e3ea5f550b07698291fc8aeb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sat, 15 Jul 2023 11:31:12 +0100 Subject: [PATCH 0359/1206] [3.12] gh-106745: typing docs: Clarify that removal of PEP-585 aliases is not currently planned (#106748) (#106772) --- Doc/library/typing.rst | 71 ++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 2a712a4be58904..e1acbd83a41730 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3053,6 +3053,7 @@ Constant .. versionadded:: 3.5.2 .. _generic-concrete-collections: +.. _deprecated-aliases: Deprecated aliases ------------------ @@ -3061,16 +3062,21 @@ This module defines several deprecated aliases to pre-existing standard library classes. These were originally included in the typing module in order to support parameterizing these generic classes using ``[]``. However, the aliases became redundant in Python 3.9 when the -corresponding pre-existing classes were enhanced to support ``[]``. +corresponding pre-existing classes were enhanced to support ``[]`` (see +:pep:`585`). -The redundant types are deprecated as of Python 3.9 but no -deprecation warnings are issued by the interpreter. -It is expected that type checkers will flag the deprecated types -when the checked program targets Python 3.9 or newer. +The redundant types are deprecated as of Python 3.9. However, while the aliases +may be removed at some point, removal of these aliases is not currently +planned. As such, no deprecation warnings are currently issued by the +interpreter for these aliases. -The deprecated types will be removed from the :mod:`typing` module -no sooner than the first Python version released 5 years after the release of Python 3.9.0. -See details in :pep:`585`—*Type Hinting Generics In Standard Collections*. +If at some point it is decided to remove these deprecated aliases, a +deprecation warning will be issued by the interpreter for at least two releases +prior to removal. The aliases are guaranteed to remain in the typing module +without deprecation warnings until at least Python 3.14. + +Type checkers are encouraged to flag uses of the deprecated types if the +program they are checking targets a minimum Python version of 3.9 or newer. .. _corresponding-to-built-in-types: @@ -3611,21 +3617,34 @@ Certain features in ``typing`` are deprecated and may be removed in a future version of Python. The following table summarizes major deprecations for your convenience. This is subject to change, and not all deprecations are listed. -+----------------------------------+---------------+-------------------+----------------+ -| Feature | Deprecated in | Projected removal | PEP/issue | -+==================================+===============+===================+================+ -| ``typing.io`` and ``typing.re`` | 3.8 | 3.13 | :issue:`38291` | -| submodules | | | | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing`` versions of standard | 3.9 | Undecided | :pep:`585` | -| collections | | | | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.ByteString`` | 3.9 | 3.14 | :gh:`91896` | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.Text`` | 3.11 | Undecided | :gh:`92332` | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` | -| ``typing.Sized`` | | | | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.TypeAlias`` | 3.12 | Undecided | :pep:`695` | -+----------------------------------+---------------+-------------------+----------------+ +.. list-table:: + :header-rows: 1 + + * - Feature + - Deprecated in + - Projected removal + - PEP/issue + * - ``typing.io`` and ``typing.re`` submodules + - 3.8 + - 3.13 + - :issue:`38291` + * - ``typing`` versions of standard collections + - 3.9 + - Undecided (see :ref:`deprecated-aliases` for more information) + - :pep:`585` + * - :class:`typing.ByteString` + - 3.9 + - 3.14 + - :gh:`91896` + * - :data:`typing.Text` + - 3.11 + - Undecided + - :gh:`92332` + * - :class:`typing.Hashable` and :class:`typing.Sized` + - 3.12 + - Undecided + - :gh:`94309` + * - :data:`typing.TypeAlias` + - 3.12 + - Undecided + - :pep:`695` From 060f58d877d738cc8659194f82864985f08a94ef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 15 Jul 2023 07:15:24 -0700 Subject: [PATCH 0360/1206] [3.12] gh-106752: Sync with zipp 3.16.2 (GH-106757) (#106777) gh-106752: Sync with zipp 3.16.2 (GH-106757) * gh-106752: Sync with zipp 3.16.2 * Add blurb (cherry picked from commit 22980dc7c9dcec4b74fea815542601ef582c230e) Co-authored-by: Jason R. Coombs --- .../test_zipfile/_path/test_complexity.py | 81 ++++++++++++++++++- Lib/test/test_zipfile/_path/test_path.py | 70 ++++++++++++++-- Lib/test/test_zipfile/_path/write-alpharep.py | 4 + Lib/zipfile/_path/__init__.py | 31 +++---- Lib/zipfile/_path/glob.py | 40 +++++++++ ...-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst | 5 ++ 6 files changed, 204 insertions(+), 27 deletions(-) create mode 100644 Lib/test/test_zipfile/_path/write-alpharep.py create mode 100644 Lib/zipfile/_path/glob.py create mode 100644 Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst diff --git a/Lib/test/test_zipfile/_path/test_complexity.py b/Lib/test/test_zipfile/_path/test_complexity.py index 3432dc39e56c4e..7050937738af18 100644 --- a/Lib/test/test_zipfile/_path/test_complexity.py +++ b/Lib/test/test_zipfile/_path/test_complexity.py @@ -1,5 +1,9 @@ -import unittest +import io +import itertools +import math +import re import string +import unittest import zipfile from ._functools import compose @@ -9,9 +13,11 @@ big_o = import_or_skip('big_o') +pytest = import_or_skip('pytest') class TestComplexity(unittest.TestCase): + @pytest.mark.flaky def test_implied_dirs_performance(self): best, others = big_o.big_o( compose(consume, zipfile.CompleteDirs._implied_dirs), @@ -22,3 +28,76 @@ def test_implied_dirs_performance(self): min_n=1, ) assert best <= big_o.complexities.Linear + + def make_zip_path(self, depth=1, width=1) -> zipfile.Path: + """ + Construct a Path with width files at every level of depth. + """ + zf = zipfile.ZipFile(io.BytesIO(), mode='w') + pairs = itertools.product(self.make_deep_paths(depth), self.make_names(width)) + for path, name in pairs: + zf.writestr(f"{path}{name}.txt", b'') + zf.filename = "big un.zip" + return zipfile.Path(zf) + + @classmethod + def make_names(cls, width, letters=string.ascii_lowercase): + """ + >>> list(TestComplexity.make_names(2)) + ['a', 'b'] + >>> list(TestComplexity.make_names(30)) + ['aa', 'ab', ..., 'bd'] + """ + # determine how many products are needed to produce width + n_products = math.ceil(math.log(width, len(letters))) + inputs = (letters,) * n_products + combinations = itertools.product(*inputs) + names = map(''.join, combinations) + return itertools.islice(names, width) + + @classmethod + def make_deep_paths(cls, depth): + return map(cls.make_deep_path, range(depth)) + + @classmethod + def make_deep_path(cls, depth): + return ''.join(('d/',) * depth) + + def test_baseline_regex_complexity(self): + best, others = big_o.big_o( + lambda path: re.fullmatch(r'[^/]*\\.txt', path), + self.make_deep_path, + max_n=100, + min_n=1, + ) + assert best <= big_o.complexities.Constant + + @pytest.mark.flaky + def test_glob_depth(self): + best, others = big_o.big_o( + lambda path: consume(path.glob('*.txt')), + self.make_zip_path, + max_n=100, + min_n=1, + ) + assert best <= big_o.complexities.Quadratic + + @pytest.mark.flaky + def test_glob_width(self): + best, others = big_o.big_o( + lambda path: consume(path.glob('*.txt')), + lambda size: self.make_zip_path(width=size), + max_n=100, + min_n=1, + ) + assert best <= big_o.complexities.Linear + + @pytest.mark.flaky + def test_glob_width_and_depth(self): + best, others = big_o.big_o( + lambda path: consume(path.glob('*.txt')), + lambda size: self.make_zip_path(depth=size, width=size), + max_n=10, + min_n=1, + ) + assert best <= big_o.complexities.Linear diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py index aff91e53995875..c66cb3cba69ebd 100644 --- a/Lib/test/test_zipfile/_path/test_path.py +++ b/Lib/test/test_zipfile/_path/test_path.py @@ -41,9 +41,13 @@ def build_alpharep_fixture(): │ ├── d │ │ └── e.txt │ └── f.txt - └── g - └── h - └── i.txt + ├── g + │ └── h + │ └── i.txt + └── j + ├── k.bin + ├── l.baz + └── m.bar This fixture has the following key characteristics: @@ -51,6 +55,7 @@ def build_alpharep_fixture(): - a file two levels deep (b/d/e) - multiple files in a directory (b/c, b/f) - a directory containing only a directory (g/h) + - a directory with files of different extensions (j/klm) "alpha" because it uses alphabet "rep" because it's a representative example @@ -62,6 +67,9 @@ def build_alpharep_fixture(): zf.writestr("b/d/e.txt", b"content of e") zf.writestr("b/f.txt", b"content of f") zf.writestr("g/h/i.txt", b"content of i") + zf.writestr("j/k.bin", b"content of k") + zf.writestr("j/l.baz", b"content of l") + zf.writestr("j/m.bar", b"content of m") zf.filename = "alpharep.zip" return zf @@ -92,7 +100,7 @@ def zipfile_ondisk(self, alpharep): def test_iterdir_and_types(self, alpharep): root = zipfile.Path(alpharep) assert root.is_dir() - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() assert a.is_file() assert b.is_dir() assert g.is_dir() @@ -112,7 +120,7 @@ def test_is_file_missing(self, alpharep): @pass_alpharep def test_iterdir_on_file(self, alpharep): root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() with self.assertRaises(ValueError): a.iterdir() @@ -127,7 +135,7 @@ def test_subdir_is_dir(self, alpharep): @pass_alpharep def test_open(self, alpharep): root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() with a.open(encoding="utf-8") as strm: data = strm.read() self.assertEqual(data, "content of a") @@ -229,7 +237,7 @@ def test_open_missing_directory(self): @pass_alpharep def test_read(self, alpharep): root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() assert a.read_text(encoding="utf-8") == "content of a" # Also check positional encoding arg (gh-101144). assert a.read_text("utf-8") == "content of a" @@ -295,7 +303,7 @@ def test_mutability(self, alpharep): reflect that change. """ root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() alpharep.writestr('foo.txt', 'foo') alpharep.writestr('bar/baz.txt', 'baz') assert any(child.name == 'foo.txt' for child in root.iterdir()) @@ -394,6 +402,13 @@ def test_suffixes(self, alpharep): e = root / '.hgrc' assert e.suffixes == [] + @pass_alpharep + def test_suffix_no_filename(self, alpharep): + alpharep.filename = None + root = zipfile.Path(alpharep) + assert root.joinpath('example').suffix == "" + assert root.joinpath('example').suffixes == [] + @pass_alpharep def test_stem(self, alpharep): """ @@ -411,6 +426,8 @@ def test_stem(self, alpharep): d = root / "d" assert d.stem == "d" + assert (root / ".gitignore").stem == ".gitignore" + @pass_alpharep def test_root_parent(self, alpharep): root = zipfile.Path(alpharep) @@ -442,12 +459,49 @@ def test_match_and_glob(self, alpharep): assert not root.match("*.txt") assert list(root.glob("b/c.*")) == [zipfile.Path(alpharep, "b/c.txt")] + assert list(root.glob("b/*.txt")) == [ + zipfile.Path(alpharep, "b/c.txt"), + zipfile.Path(alpharep, "b/f.txt"), + ] + @pass_alpharep + def test_glob_recursive(self, alpharep): + root = zipfile.Path(alpharep) files = root.glob("**/*.txt") assert all(each.match("*.txt") for each in files) assert list(root.glob("**/*.txt")) == list(root.rglob("*.txt")) + @pass_alpharep + def test_glob_subdirs(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("*/i.txt")) == [] + assert list(root.rglob("*/i.txt")) == [zipfile.Path(alpharep, "g/h/i.txt")] + + @pass_alpharep + def test_glob_does_not_overmatch_dot(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("*.xt")) == [] + + @pass_alpharep + def test_glob_single_char(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("a?txt")) == [zipfile.Path(alpharep, "a.txt")] + assert list(root.glob("a[.]txt")) == [zipfile.Path(alpharep, "a.txt")] + assert list(root.glob("a[?]txt")) == [] + + @pass_alpharep + def test_glob_chars(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("j/?.b[ai][nz]")) == [ + zipfile.Path(alpharep, "j/k.bin"), + zipfile.Path(alpharep, "j/l.baz"), + ] + def test_glob_empty(self): root = zipfile.Path(zipfile.ZipFile(io.BytesIO(), 'w')) with self.assertRaises(ValueError): diff --git a/Lib/test/test_zipfile/_path/write-alpharep.py b/Lib/test/test_zipfile/_path/write-alpharep.py new file mode 100644 index 00000000000000..48c09b537179fd --- /dev/null +++ b/Lib/test/test_zipfile/_path/write-alpharep.py @@ -0,0 +1,4 @@ +from . import test_path + + +__name__ == '__main__' and test_path.build_alpharep_fixture().extractall('alpharep') diff --git a/Lib/zipfile/_path/__init__.py b/Lib/zipfile/_path/__init__.py index fd49a3ea91db59..78c413563bb2b1 100644 --- a/Lib/zipfile/_path/__init__.py +++ b/Lib/zipfile/_path/__init__.py @@ -5,7 +5,8 @@ import contextlib import pathlib import re -import fnmatch + +from .glob import translate __all__ = ['Path'] @@ -296,21 +297,24 @@ def open(self, mode='r', *args, pwd=None, **kwargs): encoding, args, kwargs = _extract_text_encoding(*args, **kwargs) return io.TextIOWrapper(stream, encoding, *args, **kwargs) + def _base(self): + return pathlib.PurePosixPath(self.at or self.root.filename) + @property def name(self): - return pathlib.Path(self.at).name or self.filename.name + return self._base().name @property def suffix(self): - return pathlib.Path(self.at).suffix or self.filename.suffix + return self._base().suffix @property def suffixes(self): - return pathlib.Path(self.at).suffixes or self.filename.suffixes + return self._base().suffixes @property def stem(self): - return pathlib.Path(self.at).stem or self.filename.stem + return self._base().stem @property def filename(self): @@ -347,7 +351,7 @@ def iterdir(self): return filter(self._is_child, subs) def match(self, path_pattern): - return pathlib.Path(self.at).match(path_pattern) + return pathlib.PurePosixPath(self.at).match(path_pattern) def is_symlink(self): """ @@ -355,22 +359,13 @@ def is_symlink(self): """ return False - def _descendants(self): - for child in self.iterdir(): - yield child - if child.is_dir(): - yield from child._descendants() - def glob(self, pattern): if not pattern: raise ValueError(f"Unacceptable pattern: {pattern!r}") - matches = re.compile(fnmatch.translate(pattern)).fullmatch - return ( - child - for child in self._descendants() - if matches(str(child.relative_to(self))) - ) + prefix = re.escape(self.at) + matches = re.compile(prefix + translate(pattern)).fullmatch + return map(self._next, filter(matches, self.root.namelist())) def rglob(self, pattern): return self.glob(f'**/{pattern}') diff --git a/Lib/zipfile/_path/glob.py b/Lib/zipfile/_path/glob.py new file mode 100644 index 00000000000000..4a2e665e27078a --- /dev/null +++ b/Lib/zipfile/_path/glob.py @@ -0,0 +1,40 @@ +import re + + +def translate(pattern): + r""" + Given a glob pattern, produce a regex that matches it. + + >>> translate('*.txt') + '[^/]*\\.txt' + >>> translate('a?txt') + 'a.txt' + >>> translate('**/*') + '.*/[^/]*' + """ + return ''.join(map(replace, separate(pattern))) + + +def separate(pattern): + """ + Separate out character sets to avoid translating their contents. + + >>> [m.group(0) for m in separate('*.txt')] + ['*.txt'] + >>> [m.group(0) for m in separate('a[?]txt')] + ['a', '[?]', 'txt'] + """ + return re.finditer(r'([^\[]+)|(?P[\[].*?[\]])|([\[][^\]]*$)', pattern) + + +def replace(match): + """ + Perform the replacements for a match from :func:`separate`. + """ + + return match.group('set') or ( + re.escape(match.group(0)) + .replace('\\*\\*', r'.*') + .replace('\\*', r'[^/]*') + .replace('\\?', r'.') + ) diff --git a/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst b/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst new file mode 100644 index 00000000000000..bbc53d76decbc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst @@ -0,0 +1,5 @@ +Fixed several bugs in zipfile.Path, including: in ``Path.match`, Windows +separators are no longer honored (and never were meant to be); Fixed +``name``/``suffix``/``suffixes``/``stem`` operations when no filename is +present and the Path is not at the root of the zipfile; Reworked glob for +performance and more correct matching behavior. From 18d98bacb62e4beb06e56deb18e7605bff499168 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 15 Jul 2023 13:09:20 -0700 Subject: [PATCH 0361/1206] [3.12] Add more examples to the recipe docs (GH-106782) (GH-106783) --- Doc/library/itertools.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index a2d1798a2c6da1..f88525456ff939 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1045,6 +1045,8 @@ The following recipes have a more mathematical flavor: def factor(n): "Prime factors of n." # factor(99) --> 3 3 11 + # factor(1_000_000_000_000_007) --> 47 59 360620266859 + # factor(1_000_000_000_000_403) --> 1000000000000403 for prime in sieve(math.isqrt(n) + 1): while True: quotient, remainder = divmod(n, prime) From 30c127fcec28898df424c390c283ed76652ef7fe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 15 Jul 2023 15:43:46 -0700 Subject: [PATCH 0362/1206] [3.12] Docs: Normalize Argument Clinic How-To section capitalization (GH-106788) (#106791) (cherry picked from commit 8c177294899b621fe04ae755abd41b4d319dd4b5) Co-authored-by: Erlend E. Aasland --- Doc/howto/clinic.rst | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 4620b4617e3450..0f99cb64994ab2 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -27,7 +27,8 @@ Argument Clinic How-To version of Argument Clinic that ships with the next version of CPython *could* be totally incompatible and break all your code. -The Goals Of Argument Clinic + +The goals of Argument Clinic ============================ Argument Clinic's primary goal @@ -78,7 +79,7 @@ and it should be able to do many interesting and smart things with all the information you give it. -Basic Concepts And Usage +Basic concepts and usage ======================== Argument Clinic ships with CPython; you'll find it in ``Tools/clinic/clinic.py``. @@ -141,7 +142,7 @@ For the sake of clarity, here's the terminology we'll use with Argument Clinic: a block.) -Converting Your First Function +Converting your first function ============================== The best way to get a sense of how Argument Clinic works is to @@ -558,7 +559,8 @@ Let's dive in! Congratulations, you've ported your first function to work with Argument Clinic! -Advanced Topics + +Advanced topics =============== Now that you've had some experience working with Argument Clinic, it's time @@ -636,7 +638,8 @@ after the last argument). Currently the generated code will use :c:func:`PyArg_ParseTuple`, but this will change soon. -Optional Groups + +Optional groups --------------- Some legacy functions have a tricky approach to parsing their arguments: @@ -899,6 +902,7 @@ available. For each converter it'll show you all the parameters it accepts, along with the default value for each parameter. Just run ``Tools/clinic/clinic.py --converters`` to see the full list. + Py_buffer --------- @@ -908,7 +912,6 @@ you *must* not call :c:func:`PyBuffer_Release` on the provided buffer. Argument Clinic generates code that does it for you (in the parsing function). - Advanced converters ------------------- @@ -975,6 +978,7 @@ value called ``NULL`` for just this reason: from Python's perspective it behaves like a default value of ``None``, but the C variable is initialized with ``NULL``. + Expressions specified as default values --------------------------------------- @@ -1032,7 +1036,6 @@ you're not permitted to use: * Tuple/list/set/dict literals. - Using a return converter ------------------------ @@ -1146,6 +1149,7 @@ then modifying it. Cloning is an all-or nothing proposition. Also, the function you are cloning from must have been previously defined in the current file. + Calling Python code ------------------- @@ -1380,6 +1384,7 @@ handle initialization and cleanup. You can see more examples of custom converters in the CPython source tree; grep the C files for the string ``CConverter``. + Writing a custom return converter --------------------------------- @@ -1394,8 +1399,9 @@ write your own return converter, please read ``Tools/clinic/clinic.py``, specifically the implementation of ``CReturnConverter`` and all its subclasses. + METH_O and METH_NOARGS ----------------------------------------------- +---------------------- To convert a function using ``METH_O``, make sure the function's single argument is using the ``object`` converter, and mark the @@ -1415,8 +1421,9 @@ any arguments. You can still use a self converter, a return converter, and specify a ``type`` argument to the object converter for ``METH_O``. + tp_new and tp_init functions ----------------------------------------------- +---------------------------- You can convert ``tp_new`` and ``tp_init`` functions. Just name them ``__new__`` or ``__init__`` as appropriate. Notes: @@ -1437,6 +1444,7 @@ them ``__new__`` or ``__init__`` as appropriate. Notes: (If your function doesn't support keywords, the parsing function generated will throw an exception if it receives any.) + Changing and redirecting Clinic's output ---------------------------------------- @@ -1721,7 +1729,7 @@ the file was not modified by hand before it gets overwritten. The #ifdef trick ----------------------------------------------- +---------------- If you're converting a function that isn't available on all platforms, there's a trick you can use to make life a little easier. The existing @@ -1801,7 +1809,6 @@ Argument Clinic added to your file (it'll be at the very bottom), then move it above the ``PyMethodDef`` structure where that macro is used. - Using Argument Clinic in Python files ------------------------------------- From f0df92a9ce433a700b7a464d1ca0615e9fe478b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 16 Jul 2023 00:10:39 -0700 Subject: [PATCH 0363/1206] wasm: do not use inline comment in .editorconfig (GH-106610) It is no longer valid since 0.15.0 https://github.com/editorconfig/specification/blob/v0.15/index.rstGH-no-inline-comments (cherry picked from commit 64c0890b697783db9b3f67e3bb4dcee1165a0b9b) Co-authored-by: Eisuke Kawashima --- Tools/wasm/.editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tools/wasm/.editorconfig b/Tools/wasm/.editorconfig index da1aa6acaccc7e..4de5fe5954d84b 100644 --- a/Tools/wasm/.editorconfig +++ b/Tools/wasm/.editorconfig @@ -1,4 +1,5 @@ -root = false # This extends the root .editorconfig +# This extends the root .editorconfig +root = false [*.{html,js}] trim_trailing_whitespace = true From e4658bf44ea5da5a2b8934a336c396d6815a4586 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 16 Jul 2023 00:32:26 -0700 Subject: [PATCH 0364/1206] Doc: devmode: add -Xdev option to example (GH-106253) Doc: devmode: add -Xdev option to example (GH-106253) (cherry picked from commit 83bd568d2b57337a91ef046c1f52f9ebb03a7803) Co-authored-by: Simone Rubino --- Doc/library/devmode.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/devmode.rst b/Doc/library/devmode.rst index 977735990ffe92..b2bad48a07e27e 100644 --- a/Doc/library/devmode.rst +++ b/Doc/library/devmode.rst @@ -198,7 +198,7 @@ descriptor" error when finalizing the file object: .. code-block:: shell-session - $ python script.py + $ python -X dev script.py import os script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'> main() From 30c8915a199690a74b0be4a83e377cf4c4ff9da4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 16 Jul 2023 01:38:08 -0700 Subject: [PATCH 0365/1206] [3.12] Docs search: Replace jQuery with vanilla JavaScript (GH-106743) (#106802) Docs search: Replace jQuery with vanilla JavaScript (GH-106743) * Replace jQuery with vanilla JavaScript * Switch 'var' to 'const' or 'let' (cherry picked from commit c02ee4503151105dc892018ebc7f633e7f3f62f8) Co-authored-by: Hugo van Kemenade --- Doc/tools/templates/search.html | 74 ++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/Doc/tools/templates/search.html b/Doc/tools/templates/search.html index f2ac2ea0f09873..852974461380f2 100644 --- a/Doc/tools/templates/search.html +++ b/Doc/tools/templates/search.html @@ -1,48 +1,62 @@ {% extends "!search.html" %} {% block extrahead %} {{ super() }} + -{% endblock %} \ No newline at end of file +{% endblock %} From 0afd5305056c0be37ccaf7b367f1ea70ad9b02e3 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sun, 16 Jul 2023 21:25:35 +0900 Subject: [PATCH 0366/1206] Doc: fix section levels of devmode doc (GH-106801) (cherry picked from commit e58960160fcb4fce63177fcd9ef605f887377767) --- Doc/library/devmode.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/devmode.rst b/Doc/library/devmode.rst index b2bad48a07e27e..80ac13b116c1d2 100644 --- a/Doc/library/devmode.rst +++ b/Doc/library/devmode.rst @@ -16,7 +16,7 @@ setting the :envvar:`PYTHONDEVMODE` environment variable to ``1``. See also :ref:`Python debug build `. Effects of the Python Development Mode -====================================== +-------------------------------------- Enabling the Python Development Mode is similar to the following command, but with additional effects described below:: @@ -107,7 +107,7 @@ value can be read from :data:`sys.flags.dev_mode `. ResourceWarning Example -======================= +----------------------- Example of a script counting the number of lines of the text file specified in the command line:: @@ -171,7 +171,7 @@ application more deterministic and more reliable. Bad file descriptor error example -================================= +--------------------------------- Script displaying the first line of itself:: From 9c00dc02cf87d6edecc47586a9aac1fde1517868 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 16 Jul 2023 19:47:58 -0700 Subject: [PATCH 0367/1206] [3.12] Add more recipe tests. Make the factor recipe a bit faster and clearer. (GH-106817) (GH-106818) --- Doc/library/itertools.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index f88525456ff939..730736bbb59ed9 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1049,11 +1049,10 @@ The following recipes have a more mathematical flavor: # factor(1_000_000_000_000_403) --> 1000000000000403 for prime in sieve(math.isqrt(n) + 1): while True: - quotient, remainder = divmod(n, prime) - if remainder: + if n % prime: break yield prime - n = quotient + n //= prime if n == 1: return if n > 1: @@ -1354,6 +1353,12 @@ The following recipes have a more mathematical flavor: >>> set(sieve(10_000)).isdisjoint(carmichael) True + >>> list(factor(99)) # Code example 1 + [3, 3, 11] + >>> list(factor(1_000_000_000_000_007)) # Code example 2 + [47, 59, 360620266859] + >>> list(factor(1_000_000_000_000_403)) # Code example 3 + [1000000000000403] >>> list(factor(0)) [] >>> list(factor(1)) From 11b3d38310e98d1fc079938c0ec1b3992a0c7c03 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 17 Jul 2023 01:15:35 -0700 Subject: [PATCH 0368/1206] [3.12] gh-106780: Add __match_args__ to tutorial example (GH-106784) (#106819) Add Point definition with this attribute before example that needs it. (cherry picked from commit 7aa89e505d893cd5e6f33b84d66e5fa769089931) Co-authored-by: Terry Jan Reedy --- Doc/tutorial/controlflow.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 4336bf50df40a7..e140f51f1dda78 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -343,7 +343,13 @@ Dotted names (like ``foo.bar``), attribute names (the ``x=`` and ``y=`` above) o (recognized by the "(...)" next to them like ``Point`` above) are never assigned to. Patterns can be arbitrarily nested. For example, if we have a short -list of points, we could match it like this:: +list of Points, with ``__match_args__`` added, we could match it like this:: + + class Point: + __match_args__ = ('x', 'y') + def __init__(self, x, y): + self.x = x + self.y = y match points: case []: From 497bfd5047d2088718d0b2d8f14fc8022abec502 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:32:17 -0700 Subject: [PATCH 0369/1206] [3.12] gh-106687: _ssl: use uint64_t for SSL options (GH-106700) (#106827) gh-106687: _ssl: use uint64_t for SSL options (GH-106700) SSL_CTX_get_options() uses uint64_t for options: https://www.openssl.org/docs/man3.1/man3/SSL_CTX_get_options.html Fix this compiler warning on Windows with MSC: conversion from 'uint64_t' to 'long', possible loss of data (cherry picked from commit ad95c7253a70e559e7d3f25d53f4772f28bb8b44) Co-authored-by: Victor Stinner --- Lib/test/test_ssl.py | 24 +++++++++++++ Modules/_ssl.c | 80 ++++++++++++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index d46ce5e60e2141..6117ca3fdba1b7 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -339,6 +339,15 @@ def test_constants(self): ssl.OP_NO_TLSv1_2 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23) + def test_options(self): + # gh-106687: SSL options values are unsigned integer (uint64_t) + for name in dir(ssl): + if not name.startswith('OP_'): + continue + with self.subTest(option=name): + value = getattr(ssl, name) + self.assertGreaterEqual(value, 0, f"ssl.{name}") + def test_ssl_types(self): ssl_types = [ _ssl._SSLContext, @@ -951,6 +960,7 @@ def test_get_ciphers(self): ) def test_options(self): + # Test default SSLContext options ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) @@ -959,16 +969,30 @@ def test_options(self): OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | OP_ENABLE_MIDDLEBOX_COMPAT) self.assertEqual(default, ctx.options) + + # disallow TLSv1 with warnings_helper.check_warnings(): ctx.options |= ssl.OP_NO_TLSv1 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options) + + # allow TLSv1 with warnings_helper.check_warnings(): ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1) self.assertEqual(default, ctx.options) + + # clear all options ctx.options = 0 # Ubuntu has OP_NO_SSLv3 forced on by default self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3) + # invalid options + with self.assertRaises(OverflowError): + ctx.options = -1 + with self.assertRaises(OverflowError): + ctx.options = 2 ** 100 + with self.assertRaises(TypeError): + ctx.options = "abc" + def test_verify_mode_protocol(self): with warnings_helper.check_warnings(): ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 7a13821f9d7b5c..5f90584a99c080 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2996,7 +2996,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) /*[clinic end generated code: output=2cf0d7a0741b6bd1 input=8d58a805b95fc534]*/ { PySSLContext *self; - long options; + uint64_t options; const SSL_METHOD *method = NULL; SSL_CTX *ctx = NULL; X509_VERIFY_PARAM *params; @@ -3594,20 +3594,32 @@ PyDoc_STRVAR(PySSLContext_security_level_doc, "The current security level"); static PyObject * get_options(PySSLContext *self, void *c) { - return PyLong_FromLong(SSL_CTX_get_options(self->ctx)); + uint64_t options = SSL_CTX_get_options(self->ctx); + Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(options)); + return PyLong_FromUnsignedLongLong(options); } static int set_options(PySSLContext *self, PyObject *arg, void *c) { - long new_opts, opts, set, clear; - long opt_no = ( + PyObject *new_opts_obj; + unsigned long long new_opts_arg; + uint64_t new_opts, opts, clear, set; + uint64_t opt_no = ( SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3 ); - if (!PyArg_Parse(arg, "l", &new_opts)) + if (!PyArg_Parse(arg, "O!", &PyLong_Type, &new_opts_obj)) { return -1; + } + new_opts_arg = PyLong_AsUnsignedLongLong(new_opts_obj); + if (new_opts_arg == (unsigned long long)-1 && PyErr_Occurred()) { + return -1; + } + Py_BUILD_ASSERT(sizeof(new_opts) >= sizeof(new_opts_arg)); + new_opts = (uint64_t)new_opts_arg; + opts = SSL_CTX_get_options(self->ctx); clear = opts & ~new_opts; set = ~opts & new_opts; @@ -3621,8 +3633,9 @@ set_options(PySSLContext *self, PyObject *arg, void *c) if (clear) { SSL_CTX_clear_options(self->ctx, clear); } - if (set) + if (set) { SSL_CTX_set_options(self->ctx, set); + } return 0; } @@ -5731,10 +5744,24 @@ sslmodule_init_socketapi(PyObject *module) return 0; } + static int -sslmodule_init_constants(PyObject *m) +sslmodule_add_option(PyObject *m, const char *name, uint64_t value) { + Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(value)); + PyObject *obj = PyLong_FromUnsignedLongLong(value); + if (obj == NULL) { + return -1; + } + int res = PyModule_AddObjectRef(m, name, obj); + Py_DECREF(obj); + return res; +} + +static int +sslmodule_init_constants(PyObject *m) +{ PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS", PY_SSL_DEFAULT_CIPHER_STRING); @@ -5854,46 +5881,47 @@ sslmodule_init_constants(PyObject *m) PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2", PY_SSL_VERSION_TLS1_2); +#define ADD_OPTION(NAME, VALUE) if (sslmodule_add_option(m, NAME, (VALUE)) < 0) return -1 + /* protocol options */ - PyModule_AddIntConstant(m, "OP_ALL", - SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); - PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); - PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); - PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); - PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); - PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); + ADD_OPTION("OP_ALL", SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + ADD_OPTION("OP_NO_SSLv2", SSL_OP_NO_SSLv2); + ADD_OPTION("OP_NO_SSLv3", SSL_OP_NO_SSLv3); + ADD_OPTION("OP_NO_TLSv1", SSL_OP_NO_TLSv1); + ADD_OPTION("OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); + ADD_OPTION("OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); #ifdef SSL_OP_NO_TLSv1_3 - PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3); + ADD_OPTION("OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3); #else - PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", 0); + ADD_OPTION("OP_NO_TLSv1_3", 0); #endif - PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE", + ADD_OPTION("OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE); - PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); - PyModule_AddIntConstant(m, "OP_NO_TICKET", SSL_OP_NO_TICKET); - PyModule_AddIntConstant(m, "OP_LEGACY_SERVER_CONNECT", + ADD_OPTION("OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); + ADD_OPTION("OP_NO_TICKET", SSL_OP_NO_TICKET); + ADD_OPTION("OP_LEGACY_SERVER_CONNECT", SSL_OP_LEGACY_SERVER_CONNECT); #ifdef SSL_OP_SINGLE_ECDH_USE - PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE); + ADD_OPTION("OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE); #endif #ifdef SSL_OP_NO_COMPRESSION - PyModule_AddIntConstant(m, "OP_NO_COMPRESSION", + ADD_OPTION("OP_NO_COMPRESSION", SSL_OP_NO_COMPRESSION); #endif #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT - PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT", + ADD_OPTION("OP_ENABLE_MIDDLEBOX_COMPAT", SSL_OP_ENABLE_MIDDLEBOX_COMPAT); #endif #ifdef SSL_OP_NO_RENEGOTIATION - PyModule_AddIntConstant(m, "OP_NO_RENEGOTIATION", + ADD_OPTION("OP_NO_RENEGOTIATION", SSL_OP_NO_RENEGOTIATION); #endif #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - PyModule_AddIntConstant(m, "OP_IGNORE_UNEXPECTED_EOF", + ADD_OPTION("OP_IGNORE_UNEXPECTED_EOF", SSL_OP_IGNORE_UNEXPECTED_EOF); #endif #ifdef SSL_OP_ENABLE_KTLS - PyModule_AddIntConstant(m, "OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS); + ADD_OPTION("OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS); #endif #ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT From 2eef81e05ece14796e8e922ecac8e572a6e6d5b0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 17 Jul 2023 13:40:15 -0700 Subject: [PATCH 0370/1206] [3.12] gh-106831: Fix NULL check of d2i_SSL_SESSION() result in _ssl.c (GH-106832) (#106835) gh-106831: Fix NULL check of d2i_SSL_SESSION() result in _ssl.c (GH-106832) (cherry picked from commit ebf2c56b33553a448da8f60fcd89a622f071b5f4) Co-authored-by: Nikita Sobolev --- .../Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst | 2 ++ Modules/_ssl.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst diff --git a/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst b/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst new file mode 100644 index 00000000000000..d3b98626845392 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst @@ -0,0 +1,2 @@ +Fix potential missing ``NULL`` check of ``d2i_SSL_SESSION`` result in +``_ssl.c``. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 5f90584a99c080..a3fb12e4837500 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2779,7 +2779,7 @@ _ssl_session_dup(SSL_SESSION *session) { /* get length */ slen = i2d_SSL_SESSION(session, NULL); if (slen == 0 || slen > 0xFF00) { - PyErr_SetString(PyExc_ValueError, "i2d() failed."); + PyErr_SetString(PyExc_ValueError, "i2d() failed"); goto error; } if ((senc = PyMem_Malloc(slen)) == NULL) { @@ -2788,12 +2788,13 @@ _ssl_session_dup(SSL_SESSION *session) { } p = senc; if (!i2d_SSL_SESSION(session, &p)) { - PyErr_SetString(PyExc_ValueError, "i2d() failed."); + PyErr_SetString(PyExc_ValueError, "i2d() failed"); goto error; } const_p = senc; newsession = d2i_SSL_SESSION(NULL, &const_p, slen); - if (session == NULL) { + if (newsession == NULL) { + PyErr_SetString(PyExc_ValueError, "d2i() failed"); goto error; } PyMem_Free(senc); From 941ac1e19df176b68537f3d952a70f0e52659bf6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:20:59 -0700 Subject: [PATCH 0371/1206] [3.12] gh-106368: Increase Argument Clinic test coverage for cpp.Monitor (GH-106833) (#106838) (cherry picked from commit 22379c60ab8f8b49e75da9bd032a8722af50b409) Co-authored-by: Erlend E. Aasland --- Lib/test/clinic.test.c | 132 +++++++++++++++++++++++++++++++++++++++- Lib/test/test_clinic.py | 49 +++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 1544599c29fa04..5748bbc71df5a8 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -3732,6 +3732,47 @@ test_preprocessor_guarded_else_impl(PyObject *module) /*[clinic end generated code: output=13af7670aac51b12 input=6657ab31d74c29fc]*/ #endif +#ifndef CONDITION_C +/*[clinic input] +test_preprocessor_guarded_ifndef_condition_c +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_ifndef_condition_c_impl(PyObject *module) +/*[clinic end generated code: output=ed422e8c895bb0a5 input=e9b50491cea2b668]*/ +#else +/*[clinic input] +test_preprocessor_guarded_ifndef_not_condition_c +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_ifndef_not_condition_c_impl(PyObject *module) +/*[clinic end generated code: output=de6f4c6a67f8c536 input=da74e30e01c6f2c5]*/ +#endif + +#if \ +CONDITION_D +/*[clinic input] +test_preprocessor_guarded_if_with_continuation +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_if_with_continuation_impl(PyObject *module) +/*[clinic end generated code: output=3d0712ca9e2d15b9 input=4a956fd91be30284]*/ +#endif + +#if CONDITION_E || CONDITION_F +#warning "different type of CPP directive" +/*[clinic input] +test_preprocessor_guarded_if_e_or_f +Makes sure cpp.Monitor handles other directives than preprocessor conditionals. +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_if_e_or_f_impl(PyObject *module) +/*[clinic end generated code: output=e49d24ff64ad88bc input=57b9c37f938bc4f1]*/ +#endif + /*[clinic input] dump buffer output pop @@ -3791,6 +3832,79 @@ test_preprocessor_guarded_else(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* !defined(CONDITION_A) && !(CONDITION_B) */ +#if !defined(CONDITION_C) + +PyDoc_STRVAR(test_preprocessor_guarded_ifndef_condition_c__doc__, +"test_preprocessor_guarded_ifndef_condition_c($module, /)\n" +"--\n" +"\n"); + +#define TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF \ + {"test_preprocessor_guarded_ifndef_condition_c", (PyCFunction)test_preprocessor_guarded_ifndef_condition_c, METH_NOARGS, test_preprocessor_guarded_ifndef_condition_c__doc__}, + +static PyObject * +test_preprocessor_guarded_ifndef_condition_c(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_ifndef_condition_c_impl(module); +} + +#endif /* !defined(CONDITION_C) */ + +#if defined(CONDITION_C) + +PyDoc_STRVAR(test_preprocessor_guarded_ifndef_not_condition_c__doc__, +"test_preprocessor_guarded_ifndef_not_condition_c($module, /)\n" +"--\n" +"\n"); + +#define TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF \ + {"test_preprocessor_guarded_ifndef_not_condition_c", (PyCFunction)test_preprocessor_guarded_ifndef_not_condition_c, METH_NOARGS, test_preprocessor_guarded_ifndef_not_condition_c__doc__}, + +static PyObject * +test_preprocessor_guarded_ifndef_not_condition_c(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_ifndef_not_condition_c_impl(module); +} + +#endif /* defined(CONDITION_C) */ + +#if (CONDITION_D) + +PyDoc_STRVAR(test_preprocessor_guarded_if_with_continuation__doc__, +"test_preprocessor_guarded_if_with_continuation($module, /)\n" +"--\n" +"\n"); + +#define TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF \ + {"test_preprocessor_guarded_if_with_continuation", (PyCFunction)test_preprocessor_guarded_if_with_continuation, METH_NOARGS, test_preprocessor_guarded_if_with_continuation__doc__}, + +static PyObject * +test_preprocessor_guarded_if_with_continuation(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_if_with_continuation_impl(module); +} + +#endif /* (CONDITION_D) */ + +#if (CONDITION_E || CONDITION_F) + +PyDoc_STRVAR(test_preprocessor_guarded_if_e_or_f__doc__, +"test_preprocessor_guarded_if_e_or_f($module, /)\n" +"--\n" +"\n" +"Makes sure cpp.Monitor handles other directives than preprocessor conditionals."); + +#define TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF \ + {"test_preprocessor_guarded_if_e_or_f", (PyCFunction)test_preprocessor_guarded_if_e_or_f, METH_NOARGS, test_preprocessor_guarded_if_e_or_f__doc__}, + +static PyObject * +test_preprocessor_guarded_if_e_or_f(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_if_e_or_f_impl(module); +} + +#endif /* (CONDITION_E || CONDITION_F) */ + #ifndef TEST_PREPROCESSOR_GUARDED_CONDITION_A_METHODDEF #define TEST_PREPROCESSOR_GUARDED_CONDITION_A_METHODDEF #endif /* !defined(TEST_PREPROCESSOR_GUARDED_CONDITION_A_METHODDEF) */ @@ -3802,7 +3916,23 @@ test_preprocessor_guarded_else(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF #define TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF #endif /* !defined(TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF) */ -/*[clinic end generated code: output=3804bb18d454038c input=3fc80c9989d2f2e1]*/ + +#ifndef TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF) */ + +#ifndef TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF) */ + +#ifndef TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF) */ + +#ifndef TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF) */ +/*[clinic end generated code: output=fcfae7cac7a99e62 input=3fc80c9989d2f2e1]*/ /*[clinic input] test_vararg_and_posonly diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index b5744f7013d6ad..e925ecca1b9c5d 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -200,6 +200,55 @@ def test_parse_with_body_prefix(self): """).lstrip() # Note, lstrip() because of the newline self.assertEqual(out, expected) + def test_cpp_monitor_fail_nested_block_comment(self): + raw = """ + /* start + /* nested + */ + */ + """ + msg = ( + 'Error in file "test.c" on line 2:\n' + 'Nested block comment!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_cpp_monitor_fail_invalid_format_noarg(self): + raw = """ + #if + a() + #endif + """ + msg = ( + 'Error in file "test.c" on line 1:\n' + 'Invalid format for #if line: no argument!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_cpp_monitor_fail_invalid_format_toomanyargs(self): + raw = """ + #ifdef A B + a() + #endif + """ + msg = ( + 'Error in file "test.c" on line 1:\n' + 'Invalid format for #ifdef line: should be exactly one argument!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_cpp_monitor_fail_no_matching_if(self): + raw = '#else' + msg = ( + 'Error in file "test.c" on line 1:\n' + '#else without matching #if / #ifdef / #ifndef!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + class ClinicGroupPermuterTest(TestCase): def _test(self, l, m, r, output): From e903c16a6c3fe0adb594f93acc56e719590c4790 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 17 Jul 2023 15:31:17 -0700 Subject: [PATCH 0372/1206] [3.12] gh-101538: Add experimental wasi-threads build (GH-101537) (#106834) (cherry picked from commit d8f87cdf94a6533c5cf2d25e09e6fa3eb06720b9) Co-authored-by: YAMAMOTO Takashi Co-authored-by: Brett Cannon Co-authored-by: Erlend E. Aasland --- ...-02-03-21-36-42.gh-issue-101538.sF5F6S.rst | 1 + Python/thread_pthread.h | 8 +++++++ Tools/wasm/wasm_build.py | 8 ++++++- configure | 21 ++++++++++++++++++- configure.ac | 18 +++++++++++++++- 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst diff --git a/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst b/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst new file mode 100644 index 00000000000000..4b83c303b3d2c5 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst @@ -0,0 +1 @@ +Add experimental wasi-threads support. Patch by Takashi Yamamoto. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 76d6f3bcdf9c40..f96c57da64636d 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -356,7 +356,15 @@ PyThread_exit_thread(void) { if (!initialized) exit(0); +#if defined(__wasi__) + /* + * wasi-threads doesn't have pthread_exit right now + * cf. https://github.com/WebAssembly/wasi-threads/issues/7 + */ + abort(); +#else pthread_exit(0); +#endif } #ifdef USE_SEMAPHORES diff --git a/Tools/wasm/wasm_build.py b/Tools/wasm/wasm_build.py index 241a5d4eed5ae8..c9947057a90754 100755 --- a/Tools/wasm/wasm_build.py +++ b/Tools/wasm/wasm_build.py @@ -480,7 +480,6 @@ def configure_cmd(self) -> List[str]: cmd.append(f"--{opt}-wasm-dynamic-linking") if self.pthreads is not None: - assert self.host.is_emscripten opt = "enable" if self.pthreads else "disable" cmd.append(f"--{opt}-wasm-pthreads") @@ -745,6 +744,13 @@ def build_emports(self, force: bool = False): support_level=SupportLevel.supported, host=Host.wasm32_wasi, ), + # wasm32-wasi-threads + BuildProfile( + "wasi-threads", + support_level=SupportLevel.experimental, + host=Host.wasm32_wasi, + pthreads=True, + ), # no SDK available yet # BuildProfile( # "wasm64-wasi", diff --git a/configure b/configure index 248b14e254f6db..91bf1d2c023702 100755 --- a/configure +++ b/configure @@ -6899,7 +6899,11 @@ cat > conftest.c <>confdefs.h LIBS="$LIBS -lwasi-emulated-signal -lwasi-emulated-getpid -lwasi-emulated-process-clocks" echo "#define _WASI_EMULATED_SIGNAL 1" >> confdefs.h + if test "x$enable_wasm_pthreads" = xyes +then : + + # Note: update CFLAGS because ac_compile/ac_link needs this too. + # without this, configure fails to find pthread_create, sem_init, + # etc because they are only available in the sysroot for + # wasm32-wasi-threads. + as_fn_append CFLAGS " -target wasm32-wasi-threads -pthread" + as_fn_append CFLAGS_NODIST " -target wasm32-wasi-threads -pthread" + as_fn_append LDFLAGS_NODIST " -target wasm32-wasi-threads -pthread" + as_fn_append LDFLAGS_NODIST " -Wl,--import-memory" + as_fn_append LDFLAGS_NODIST " -Wl,--max-memory=10485760" + +fi + as_fn_append LDFLAGS_NODIST " -z stack-size=524288 -Wl,--stack-first -Wl,--initial-memory=10485760" ;; #( diff --git a/configure.ac b/configure.ac index 96c96e4b0d735b..0770f68a23f61f 100644 --- a/configure.ac +++ b/configure.ac @@ -1079,7 +1079,11 @@ cat > conftest.c <> confdefs.h + AS_VAR_IF([enable_wasm_pthreads], [yes], [ + # Note: update CFLAGS because ac_compile/ac_link needs this too. + # without this, configure fails to find pthread_create, sem_init, + # etc because they are only available in the sysroot for + # wasm32-wasi-threads. + AS_VAR_APPEND([CFLAGS], [" -target wasm32-wasi-threads -pthread"]) + AS_VAR_APPEND([CFLAGS_NODIST], [" -target wasm32-wasi-threads -pthread"]) + AS_VAR_APPEND([LDFLAGS_NODIST], [" -target wasm32-wasi-threads -pthread"]) + AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--import-memory"]) + AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--max-memory=10485760"]) + ]) + dnl increase initial memory and stack size, move stack first dnl https://github.com/WebAssembly/wasi-libc/issues/233 AS_VAR_APPEND([LDFLAGS_NODIST], [" -z stack-size=524288 -Wl,--stack-first -Wl,--initial-memory=10485760"]) From d671c6567aa5b5c4478aadcd623f5c3b8261b5b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 18 Jul 2023 00:01:22 -0700 Subject: [PATCH 0373/1206] [3.12] gh-106719: Fix __annotations__ getter and setter in the type and module types (GH-106720) (GH-106848) gh-106719: Fix __annotations__ getter and setter in the type and module types (GH-106720) No longer suppress arbitrary errors. Simplify the code. (cherry picked from commit e1c295e3da9ff5a3eb6b009a1f821d80e564ac87) Co-authored-by: Serhiy Storchaka --- ...-07-13-15-59-07.gh-issue-106719.jmVrsv.rst | 2 + Objects/moduleobject.c | 48 ++++++++----------- Objects/typeobject.c | 32 +++++-------- 3 files changed, 35 insertions(+), 47 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst new file mode 100644 index 00000000000000..dc4bef193a3220 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst @@ -0,0 +1,2 @@ +No longer suppress arbitrary errors in the ``__annotations__`` getter and +setter in the type and module types. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 985be58d02c784..4daf1a929e0549 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -935,26 +935,20 @@ static PyObject * module_get_annotations(PyModuleObject *m, void *Py_UNUSED(ignored)) { PyObject *dict = PyObject_GetAttr((PyObject *)m, &_Py_ID(__dict__)); - - if ((dict == NULL) || !PyDict_Check(dict)) { + if (dict == NULL) { + return NULL; + } + if (!PyDict_Check(dict)) { PyErr_Format(PyExc_TypeError, ".__dict__ is not a dictionary"); - Py_XDECREF(dict); + Py_DECREF(dict); return NULL; } - PyObject *annotations; - /* there's no _PyDict_GetItemId without WithError, so let's LBYL. */ - if (PyDict_Contains(dict, &_Py_ID(__annotations__))) { - annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); - /* - ** _PyDict_GetItemIdWithError could still fail, - ** for instance with a well-timed Ctrl-C or a MemoryError. - ** so let's be totally safe. - */ - if (annotations) { - Py_INCREF(annotations); - } - } else { + PyObject *annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); + if (annotations) { + Py_INCREF(annotations); + } + else if (!PyErr_Occurred()) { annotations = PyDict_New(); if (annotations) { int result = PyDict_SetItem( @@ -973,8 +967,10 @@ module_set_annotations(PyModuleObject *m, PyObject *value, void *Py_UNUSED(ignor { int ret = -1; PyObject *dict = PyObject_GetAttr((PyObject *)m, &_Py_ID(__dict__)); - - if ((dict == NULL) || !PyDict_Check(dict)) { + if (dict == NULL) { + return -1; + } + if (!PyDict_Check(dict)) { PyErr_Format(PyExc_TypeError, ".__dict__ is not a dictionary"); goto exit; } @@ -982,19 +978,17 @@ module_set_annotations(PyModuleObject *m, PyObject *value, void *Py_UNUSED(ignor if (value != NULL) { /* set */ ret = PyDict_SetItem(dict, &_Py_ID(__annotations__), value); - goto exit; } - - /* delete */ - if (!PyDict_Contains(dict, &_Py_ID(__annotations__))) { - PyErr_Format(PyExc_AttributeError, "__annotations__"); - goto exit; + else { + /* delete */ + ret = PyDict_DelItem(dict, &_Py_ID(__annotations__)); + if (ret < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_SetString(PyExc_AttributeError, "__annotations__"); + } } - ret = PyDict_DelItem(dict, &_Py_ID(__annotations__)); - exit: - Py_XDECREF(dict); + Py_DECREF(dict); return ret; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6662379515f95d..40e187d4d8d22a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1449,24 +1449,17 @@ type_get_annotations(PyTypeObject *type, void *context) } PyObject *annotations; - /* there's no _PyDict_GetItemId without WithError, so let's LBYL. */ PyObject *dict = lookup_tp_dict(type); - if (PyDict_Contains(dict, &_Py_ID(__annotations__))) { - annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); - /* - ** PyDict_GetItemWithError could still fail, - ** for instance with a well-timed Ctrl-C or a MemoryError. - ** so let's be totally safe. - */ - if (annotations) { - if (Py_TYPE(annotations)->tp_descr_get) { - annotations = Py_TYPE(annotations)->tp_descr_get( - annotations, NULL, (PyObject *)type); - } else { - Py_INCREF(annotations); - } + annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); + if (annotations) { + if (Py_TYPE(annotations)->tp_descr_get) { + annotations = Py_TYPE(annotations)->tp_descr_get( + annotations, NULL, (PyObject *)type); + } else { + Py_INCREF(annotations); } - } else { + } + else if (!PyErr_Occurred()) { annotations = PyDict_New(); if (annotations) { int result = PyDict_SetItem( @@ -1498,11 +1491,10 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context) result = PyDict_SetItem(dict, &_Py_ID(__annotations__), value); } else { /* delete */ - if (!PyDict_Contains(dict, &_Py_ID(__annotations__))) { - PyErr_Format(PyExc_AttributeError, "__annotations__"); - return -1; - } result = PyDict_DelItem(dict, &_Py_ID(__annotations__)); + if (result < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_SetString(PyExc_AttributeError, "__annotations__"); + } } if (result == 0) { From 970cb8eabaaf5a8311f1aba4ca4968ef7385fce8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 18 Jul 2023 10:03:59 +0300 Subject: [PATCH 0374/1206] [3.12] gh-86493: Fix possible leaks in modules initialization: _curses_panel, _decimal, posix, xxsubtype (GH-106767) (#106849) (cherry picked from commit 745492355b94d109e47827e5865846f25ae42d26) --- Modules/_curses_panel.c | 3 +- Modules/_decimal/_decimal.c | 33 ++++++++++----------- Modules/posixmodule.c | 59 ++++++++++++++----------------------- Modules/xxsubtype.c | 6 ++-- 4 files changed, 41 insertions(+), 60 deletions(-) diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index a3124ff80551e0..292b57c083d0c8 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -662,8 +662,7 @@ _curses_panel_exec(PyObject *mod) state->PyCursesError = PyErr_NewException( "_curses_panel.error", NULL, NULL); - if (PyModule_AddObject(mod, "error", Py_NewRef(state->PyCursesError)) < 0) { - Py_DECREF(state->PyCursesError); + if (PyModule_AddObjectRef(mod, "error", state->PyCursesError) < 0) { return -1; } diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 0005081f7c5e80..70e18edb464538 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -5871,16 +5871,15 @@ PyInit__decimal(void) ASSIGN_PTR(m, PyModule_Create(&_decimal_module)); /* Add types to the module */ - CHECK_INT(PyModule_AddObject(m, "Decimal", Py_NewRef(&PyDec_Type))); - CHECK_INT(PyModule_AddObject(m, "Context", - Py_NewRef(&PyDecContext_Type))); - CHECK_INT(PyModule_AddObject(m, "DecimalTuple", Py_NewRef(DecimalTuple))); + CHECK_INT(PyModule_AddObjectRef(m, "Decimal", (PyObject *)&PyDec_Type)); + CHECK_INT(PyModule_AddObjectRef(m, "Context", (PyObject *)&PyDecContext_Type)); + CHECK_INT(PyModule_AddObjectRef(m, "DecimalTuple", (PyObject *)DecimalTuple)); /* Create top level exception */ ASSIGN_PTR(DecimalException, PyErr_NewException( "decimal.DecimalException", PyExc_ArithmeticError, NULL)); - CHECK_INT(PyModule_AddObject(m, "DecimalException", Py_NewRef(DecimalException))); + CHECK_INT(PyModule_AddObjectRef(m, "DecimalException", DecimalException)); /* Create signal tuple */ ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); @@ -5920,7 +5919,7 @@ PyInit__decimal(void) Py_DECREF(base); /* add to module */ - CHECK_INT(PyModule_AddObject(m, cm->name, Py_NewRef(cm->ex))); + CHECK_INT(PyModule_AddObjectRef(m, cm->name, cm->ex)); /* add to signal tuple */ PyTuple_SET_ITEM(SignalTuple, i, Py_NewRef(cm->ex)); @@ -5949,38 +5948,38 @@ PyInit__decimal(void) ASSIGN_PTR(cm->ex, PyErr_NewException(cm->fqname, base, NULL)); Py_DECREF(base); - CHECK_INT(PyModule_AddObject(m, cm->name, Py_NewRef(cm->ex))); + CHECK_INT(PyModule_AddObjectRef(m, cm->name, cm->ex)); } /* Init default context template first */ ASSIGN_PTR(default_context_template, PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); - CHECK_INT(PyModule_AddObject(m, "DefaultContext", - Py_NewRef(default_context_template))); + CHECK_INT(PyModule_AddObjectRef(m, "DefaultContext", + default_context_template)); #ifndef WITH_DECIMAL_CONTEXTVAR ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); - CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_False))); + CHECK_INT(PyModule_AddObjectRef(m, "HAVE_CONTEXTVAR", Py_False)); #else ASSIGN_PTR(current_context_var, PyContextVar_New("decimal_context", NULL)); - CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_True))); + CHECK_INT(PyModule_AddObjectRef(m, "HAVE_CONTEXTVAR", Py_True)); #endif - CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); + CHECK_INT(PyModule_AddObjectRef(m, "HAVE_THREADS", Py_True)); /* Init basic context template */ ASSIGN_PTR(basic_context_template, PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); init_basic_context(basic_context_template); - CHECK_INT(PyModule_AddObject(m, "BasicContext", - Py_NewRef(basic_context_template))); + CHECK_INT(PyModule_AddObjectRef(m, "BasicContext", + basic_context_template)); /* Init extended context template */ ASSIGN_PTR(extended_context_template, PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); init_extended_context(extended_context_template); - CHECK_INT(PyModule_AddObject(m, "ExtendedContext", - Py_NewRef(extended_context_template))); + CHECK_INT(PyModule_AddObjectRef(m, "ExtendedContext", + extended_context_template)); /* Init mpd_ssize_t constants */ @@ -5999,7 +5998,7 @@ PyInit__decimal(void) /* Init string constants */ for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { ASSIGN_PTR(round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); - CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(round_map[i]))); + CHECK_INT(PyModule_AddObjectRef(m, mpd_round_string[i], round_map[i])); } /* Add specification version number */ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 81c9990220893d..0f82f1afa07aa8 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -16790,57 +16790,49 @@ posixmodule_exec(PyObject *m) if (setup_confname_tables(m)) return -1; - PyModule_AddObject(m, "error", Py_NewRef(PyExc_OSError)); + if (PyModule_AddObjectRef(m, "error", PyExc_OSError) < 0) { + return -1; + } #if defined(HAVE_WAITID) && !defined(__APPLE__) waitid_result_desc.name = MODNAME ".waitid_result"; - PyObject *WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc); - if (WaitidResultType == NULL) { + state->WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc); + if (PyModule_AddObjectRef(m, "waitid_result", state->WaitidResultType) < 0) { return -1; } - PyModule_AddObject(m, "waitid_result", Py_NewRef(WaitidResultType)); - state->WaitidResultType = WaitidResultType; #endif stat_result_desc.name = "os.stat_result"; /* see issue #19209 */ stat_result_desc.fields[7].name = PyStructSequence_UnnamedField; stat_result_desc.fields[8].name = PyStructSequence_UnnamedField; stat_result_desc.fields[9].name = PyStructSequence_UnnamedField; - PyObject *StatResultType = (PyObject *)PyStructSequence_NewType(&stat_result_desc); - if (StatResultType == NULL) { + state->StatResultType = (PyObject *)PyStructSequence_NewType(&stat_result_desc); + if (PyModule_AddObjectRef(m, "stat_result", state->StatResultType) < 0) { return -1; } - PyModule_AddObject(m, "stat_result", Py_NewRef(StatResultType)); - state->StatResultType = StatResultType; - state->statresult_new_orig = ((PyTypeObject *)StatResultType)->tp_new; - ((PyTypeObject *)StatResultType)->tp_new = statresult_new; + state->statresult_new_orig = ((PyTypeObject *)state->StatResultType)->tp_new; + ((PyTypeObject *)state->StatResultType)->tp_new = statresult_new; statvfs_result_desc.name = "os.statvfs_result"; /* see issue #19209 */ - PyObject *StatVFSResultType = (PyObject *)PyStructSequence_NewType(&statvfs_result_desc); - if (StatVFSResultType == NULL) { + state->StatVFSResultType = (PyObject *)PyStructSequence_NewType(&statvfs_result_desc); + if (PyModule_AddObjectRef(m, "statvfs_result", state->StatVFSResultType) < 0) { return -1; } - PyModule_AddObject(m, "statvfs_result", Py_NewRef(StatVFSResultType)); - state->StatVFSResultType = StatVFSResultType; #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) sched_param_desc.name = MODNAME ".sched_param"; - PyObject *SchedParamType = (PyObject *)PyStructSequence_NewType(&sched_param_desc); - if (SchedParamType == NULL) { + state->SchedParamType = (PyObject *)PyStructSequence_NewType(&sched_param_desc); + if (PyModule_AddObjectRef(m, "sched_param", state->SchedParamType) < 0) { return -1; } - PyModule_AddObject(m, "sched_param", Py_NewRef(SchedParamType)); - state->SchedParamType = SchedParamType; - ((PyTypeObject *)SchedParamType)->tp_new = os_sched_param; + ((PyTypeObject *)state->SchedParamType)->tp_new = os_sched_param; #endif /* initialize TerminalSize_info */ - PyObject *TerminalSizeType = (PyObject *)PyStructSequence_NewType(&TerminalSize_desc); - if (TerminalSizeType == NULL) { + state->TerminalSizeType = (PyObject *)PyStructSequence_NewType(&TerminalSize_desc); + if (PyModule_AddObjectRef(m, "terminal_size", state->TerminalSizeType) < 0) { return -1; } - PyModule_AddObject(m, "terminal_size", Py_NewRef(TerminalSizeType)); - state->TerminalSizeType = TerminalSizeType; /* initialize scandir types */ PyObject *ScandirIteratorType = PyType_FromModuleAndSpec(m, &ScandirIteratorType_spec, NULL); @@ -16849,28 +16841,21 @@ posixmodule_exec(PyObject *m) } state->ScandirIteratorType = ScandirIteratorType; - PyObject *DirEntryType = PyType_FromModuleAndSpec(m, &DirEntryType_spec, NULL); - if (DirEntryType == NULL) { + state->DirEntryType = PyType_FromModuleAndSpec(m, &DirEntryType_spec, NULL); + if (PyModule_AddObjectRef(m, "DirEntry", state->DirEntryType) < 0) { return -1; } - PyModule_AddObject(m, "DirEntry", Py_NewRef(DirEntryType)); - state->DirEntryType = DirEntryType; times_result_desc.name = MODNAME ".times_result"; - PyObject *TimesResultType = (PyObject *)PyStructSequence_NewType(×_result_desc); - if (TimesResultType == NULL) { + state->TimesResultType = (PyObject *)PyStructSequence_NewType(×_result_desc); + if (PyModule_AddObjectRef(m, "times_result", state->TimesResultType) < 0) { return -1; } - PyModule_AddObject(m, "times_result", Py_NewRef(TimesResultType)); - state->TimesResultType = TimesResultType; - PyTypeObject *UnameResultType = PyStructSequence_NewType(&uname_result_desc); - if (UnameResultType == NULL) { + state->UnameResultType = (PyObject *)PyStructSequence_NewType(&uname_result_desc); + if (PyModule_AddObjectRef(m, "uname_result", state->UnameResultType) < 0) { return -1; } - ; - PyModule_AddObject(m, "uname_result", Py_NewRef(UnameResultType)); - state->UnameResultType = (PyObject *)UnameResultType; if ((state->billion = PyLong_FromLong(1000000000)) == NULL) return -1; diff --git a/Modules/xxsubtype.c b/Modules/xxsubtype.c index 744ba7bf5d28b6..9e4a3d66ef41bd 100644 --- a/Modules/xxsubtype.c +++ b/Modules/xxsubtype.c @@ -274,12 +274,10 @@ xxsubtype_exec(PyObject* m) if (PyType_Ready(&spamdict_type) < 0) return -1; - if (PyModule_AddObject(m, "spamlist", - Py_NewRef(&spamlist_type)) < 0) + if (PyModule_AddObjectRef(m, "spamlist", (PyObject *)&spamlist_type) < 0) return -1; - if (PyModule_AddObject(m, "spamdict", - Py_NewRef(&spamdict_type)) < 0) + if (PyModule_AddObjectRef(m, "spamdict", (PyObject *)&spamdict_type) < 0) return -1; return 0; } From b79f3b36c318be8b27d1737a819e33145193801c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 18 Jul 2023 03:24:44 -0700 Subject: [PATCH 0375/1206] [3.12] Docs: Normalise Argument Clinic advanced topics headings (GH-106842) (#106853) (cherry picked from commit 4cb0b9c0a9f6a4154238c98013d2679229b1f794) Co-authored-by: Erlend E. Aasland Co-authored-by: Ezio Melotti --- Doc/howto/clinic.rst | 95 +++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 0f99cb64994ab2..12d7a77d43209a 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -560,15 +560,12 @@ Let's dive in! Congratulations, you've ported your first function to work with Argument Clinic! -Advanced topics -=============== +How-to guides +============= -Now that you've had some experience working with Argument Clinic, it's time -for some advanced topics. - -Symbolic default values ------------------------ +How to use symbolic default values +---------------------------------- The default value you provide for a parameter can't be any arbitrary expression. Currently the following are explicitly supported: @@ -583,8 +580,8 @@ expression. Currently the following are explicitly supported: to allow full expressions like ``CONSTANT - 1``.) -Renaming the C functions and variables generated by Argument Clinic -------------------------------------------------------------------- +How to to rename C functions and variables generated by Argument Clinic +----------------------------------------------------------------------- Argument Clinic automatically names the functions it generates for you. Occasionally this may cause a problem, if the generated name collides with @@ -626,8 +623,8 @@ array) would be ``file``, but the C variable would be named ``file_obj``. You can use this to rename the ``self`` parameter too! -Converting functions using PyArg_UnpackTuple --------------------------------------------- +How to convert functions using ``PyArg_UnpackTuple`` +---------------------------------------------------- To convert a function parsing its arguments with :c:func:`PyArg_UnpackTuple`, simply write out all the arguments, specifying each as an ``object``. You @@ -639,8 +636,8 @@ Currently the generated code will use :c:func:`PyArg_ParseTuple`, but this will change soon. -Optional groups ---------------- +How to use optional groups +-------------------------- Some legacy functions have a tricky approach to parsing their arguments: they count the number of positional arguments, then use a ``switch`` statement @@ -732,8 +729,8 @@ Notes: use optional groups for new code. -Using real Argument Clinic converters, instead of "legacy converters" ---------------------------------------------------------------------- +How to use real Argument Clinic converters, instead of "legacy converters" +-------------------------------------------------------------------------- To save time, and to minimize how much you need to learn to achieve your first port to Argument Clinic, the walkthrough above tells @@ -903,8 +900,8 @@ it accepts, along with the default value for each parameter. Just run ``Tools/clinic/clinic.py --converters`` to see the full list. -Py_buffer ---------- +How to use the ``Py_buffer`` converter +-------------------------------------- When using the ``Py_buffer`` converter (or the ``'s*'``, ``'w*'``, ``'*y'``, or ``'z*'`` legacy converters), @@ -912,8 +909,8 @@ you *must* not call :c:func:`PyBuffer_Release` on the provided buffer. Argument Clinic generates code that does it for you (in the parsing function). -Advanced converters -------------------- +How to use advanced converters +------------------------------ Remember those format units you skipped for your first time because they were advanced? Here's how to handle those too. @@ -944,8 +941,8 @@ hard-coded encoding strings for parameters whose format units start with ``e``. .. _default_values: -Parameter default values ------------------------- +How to assign default values to parameter +----------------------------------------- Default values for parameters can be any of a number of values. At their simplest, they can be string, int, or float literals: @@ -968,8 +965,8 @@ There's also special support for a default value of ``NULL``, and for simple expressions, documented in the following sections. -The ``NULL`` default value --------------------------- +How to use the ``NULL`` default value +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For string and object parameters, you can set them to ``None`` to indicate that there's no default. However, that means the C variable will be @@ -979,8 +976,8 @@ behaves like a default value of ``None``, but the C variable is initialized with ``NULL``. -Expressions specified as default values ---------------------------------------- +How to use expressions as default values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The default value for a parameter can be more than just a literal value. It can be an entire expression, using math operators and looking up attributes @@ -1036,8 +1033,8 @@ you're not permitted to use: * Tuple/list/set/dict literals. -Using a return converter ------------------------- +How to use return converters +---------------------------- By default, the impl function Argument Clinic generates for you returns :c:type:`PyObject * `. @@ -1106,8 +1103,8 @@ their parameters (if any), just run ``Tools/clinic/clinic.py --converters`` for the full list. -Cloning existing functions --------------------------- +How to clone existing functions +------------------------------- If you have a number of functions that look similar, you may be able to use Clinic's "clone" feature. When you clone an existing function, @@ -1150,8 +1147,8 @@ Also, the function you are cloning from must have been previously defined in the current file. -Calling Python code -------------------- +How to call Python code +----------------------- The rest of the advanced topics require you to write Python code which lives inside your C file and modifies Argument Clinic's @@ -1178,8 +1175,8 @@ variable to the C code:: /*[python checksum:...]*/ -Using a "self converter" ------------------------- +How to use the "self converter" +------------------------------- Argument Clinic automatically adds a "self" parameter for you using a default converter. It automatically sets the ``type`` @@ -1230,8 +1227,8 @@ type for ``self``, it's best to create your own converter, subclassing [clinic start generated code]*/ -Using a "defining class" converter ----------------------------------- +How to use the "defining class" converter +----------------------------------------- Argument Clinic facilitates gaining access to the defining class of a method. This is useful for :ref:`heap type ` methods that need to fetch @@ -1293,8 +1290,8 @@ state. Example from the ``setattro`` slot method in See also :pep:`573`. -Writing a custom converter --------------------------- +How to write a custom converter +------------------------------- As we hinted at in the previous section... you can write your own converters! A converter is simply a Python class that inherits from ``CConverter``. @@ -1385,8 +1382,8 @@ You can see more examples of custom converters in the CPython source tree; grep the C files for the string ``CConverter``. -Writing a custom return converter ---------------------------------- +How to write a custom return converter +-------------------------------------- Writing a custom return converter is much like writing a custom converter. Except it's somewhat simpler, because return @@ -1400,8 +1397,8 @@ specifically the implementation of ``CReturnConverter`` and all its subclasses. -METH_O and METH_NOARGS ----------------------- +How to convert ``METH_O`` and ``METH_NOARGS`` functions +------------------------------------------------------- To convert a function using ``METH_O``, make sure the function's single argument is using the ``object`` converter, and mark the @@ -1422,8 +1419,8 @@ You can still use a self converter, a return converter, and specify a ``type`` argument to the object converter for ``METH_O``. -tp_new and tp_init functions ----------------------------- +How to convert ``tp_new`` and ``tp_init`` functions +--------------------------------------------------- You can convert ``tp_new`` and ``tp_init`` functions. Just name them ``__new__`` or ``__init__`` as appropriate. Notes: @@ -1445,8 +1442,8 @@ them ``__new__`` or ``__init__`` as appropriate. Notes: generated will throw an exception if it receives any.) -Changing and redirecting Clinic's output ----------------------------------------- +How to change and redirect Clinic's output +------------------------------------------ It can be inconvenient to have Clinic's output interspersed with your conventional hand-edited C code. Luckily, Clinic is configurable: @@ -1728,8 +1725,8 @@ it in a Clinic block lets Clinic use its existing checksum functionality to ensu the file was not modified by hand before it gets overwritten. -The #ifdef trick ----------------- +How to use the ``#ifdef`` trick +------------------------------- If you're converting a function that isn't available on all platforms, there's a trick you can use to make life a little easier. The existing @@ -1809,8 +1806,8 @@ Argument Clinic added to your file (it'll be at the very bottom), then move it above the ``PyMethodDef`` structure where that macro is used. -Using Argument Clinic in Python files -------------------------------------- +How to use Argument Clinic in Python files +------------------------------------------ It's actually possible to use Argument Clinic to preprocess Python files. There's no point to using Argument Clinic blocks, of course, as the output From a423ddbdeada8a2fd8657453b9e9f58ba0dd921d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 18 Jul 2023 15:14:10 +0300 Subject: [PATCH 0376/1206] [3.12] gh-86493: Fix possible leaks in some modules initialization (GH-106768) (GH-106855) Fix _ssl, _stat, _testinternalcapi, _threadmodule, cmath, math, posix, time. (cherry picked from commit 3e65baee72131b49f4ce8ca2da568a6f2001ce93) --- Include/cpython/modsupport.h | 1 + Modules/_ssl.c | 8 ++++---- Modules/_stat.c | 18 +++++++++--------- Modules/_testinternalcapi.c | 4 ++-- Modules/_threadmodule.c | 4 ++-- Modules/cmathmodule.c | 15 +++++++-------- Modules/mathmodule.c | 10 +++++----- Modules/posixmodule.c | 12 ++++-------- Modules/timemodule.c | 7 ++----- Python/modsupport.c | 29 ++++++++++------------------- 10 files changed, 46 insertions(+), 62 deletions(-) diff --git a/Include/cpython/modsupport.h b/Include/cpython/modsupport.h index 88f34fe7513bf2..2259291aff67d3 100644 --- a/Include/cpython/modsupport.h +++ b/Include/cpython/modsupport.h @@ -106,3 +106,4 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsWithVararg( (minpos), (maxpos), (minkw), (buf))) PyAPI_FUNC(PyObject *) _PyModule_CreateInitialized(PyModuleDef*, int apiver); +PyAPI_FUNC(int) _PyModule_Add(PyObject *, const char *, PyObject *); diff --git a/Modules/_ssl.c b/Modules/_ssl.c index a3fb12e4837500..619b4f4e94d06a 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -6095,22 +6095,22 @@ sslmodule_init_versioninfo(PyObject *m) */ libver = OpenSSL_version_num(); r = PyLong_FromUnsignedLong(libver); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) + if (_PyModule_Add(m, "OPENSSL_VERSION_NUMBER", r) < 0) return -1; parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) + if (_PyModule_Add(m, "OPENSSL_VERSION_INFO", r) < 0) return -1; r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION)); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) + if (_PyModule_Add(m, "OPENSSL_VERSION", r) < 0) return -1; libver = OPENSSL_VERSION_NUMBER; parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status); - if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) + if (_PyModule_Add(m, "_OPENSSL_API_VERSION", r) < 0) return -1; return 0; diff --git a/Modules/_stat.c b/Modules/_stat.c index 4218799103b59d..4ec2bd251831f4 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -592,17 +592,17 @@ stat_exec(PyObject *module) ADD_INT_MACRO(module, FILE_ATTRIBUTE_TEMPORARY); ADD_INT_MACRO(module, FILE_ATTRIBUTE_VIRTUAL); - if (PyModule_AddObject(module, "IO_REPARSE_TAG_SYMLINK", - PyLong_FromUnsignedLong(IO_REPARSE_TAG_SYMLINK)) < 0) { - return -1; + if (_PyModule_Add(module, "IO_REPARSE_TAG_SYMLINK", + PyLong_FromUnsignedLong(IO_REPARSE_TAG_SYMLINK)) < 0) { + return -1; } - if (PyModule_AddObject(module, "IO_REPARSE_TAG_MOUNT_POINT", - PyLong_FromUnsignedLong(IO_REPARSE_TAG_MOUNT_POINT)) < 0) { - return -1; + if (_PyModule_Add(module, "IO_REPARSE_TAG_MOUNT_POINT", + PyLong_FromUnsignedLong(IO_REPARSE_TAG_MOUNT_POINT)) < 0) { + return -1; } - if (PyModule_AddObject(module, "IO_REPARSE_TAG_APPEXECLINK", - PyLong_FromUnsignedLong(IO_REPARSE_TAG_APPEXECLINK)) < 0) { - return -1; + if (_PyModule_Add(module, "IO_REPARSE_TAG_APPEXECLINK", + PyLong_FromUnsignedLong(IO_REPARSE_TAG_APPEXECLINK)) < 0) { + return -1; } #endif diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 98f99e4d66cf1f..6fc31f61c144d8 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1092,8 +1092,8 @@ static PyMethodDef module_functions[] = { static int module_exec(PyObject *module) { - if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD", - PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) { + if (_PyModule_Add(module, "SIZEOF_PYGC_HEAD", + PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) { return 1; } diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index c553d039462af0..04f4400a9315ba 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1671,8 +1671,8 @@ thread_module_exec(PyObject *module) // Round towards minus infinity timeout_max = floor(timeout_max); - if (PyModule_AddObject(module, "TIMEOUT_MAX", - PyFloat_FromDouble(timeout_max)) < 0) { + if (_PyModule_Add(module, "TIMEOUT_MAX", + PyFloat_FromDouble(timeout_max)) < 0) { return -1; } diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 1a31bdc824bb03..25491e655849d6 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1216,30 +1216,29 @@ static PyMethodDef cmath_methods[] = { static int cmath_exec(PyObject *mod) { - if (PyModule_AddObject(mod, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { + if (_PyModule_Add(mod, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { return -1; } - if (PyModule_AddObject(mod, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { + if (_PyModule_Add(mod, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { return -1; } // 2pi - if (PyModule_AddObject(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { + if (_PyModule_Add(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_AddObject(mod, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { + if (_PyModule_Add(mod, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { return -1; } Py_complex infj = {0.0, Py_INFINITY}; - if (PyModule_AddObject(mod, "infj", - PyComplex_FromCComplex(infj)) < 0) { + if (_PyModule_Add(mod, "infj", PyComplex_FromCComplex(infj)) < 0) { return -1; } - if (PyModule_AddObject(mod, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { + if (_PyModule_Add(mod, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { return -1; } Py_complex nanj = {0.0, fabs(Py_NAN)}; - if (PyModule_AddObject(mod, "nanj", PyComplex_FromCComplex(nanj)) < 0) { + if (_PyModule_Add(mod, "nanj", PyComplex_FromCComplex(nanj)) < 0) { return -1; } diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index f5679fe3a6f362..7b1104ba5ac404 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -4037,20 +4037,20 @@ math_exec(PyObject *module) if (state->str___trunc__ == NULL) { return -1; } - if (PyModule_AddObject(module, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { + if (_PyModule_Add(module, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { return -1; } - if (PyModule_AddObject(module, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { + if (_PyModule_Add(module, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { return -1; } // 2pi - if (PyModule_AddObject(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { + if (_PyModule_Add(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_AddObject(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { + if (_PyModule_Add(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { return -1; } - if (PyModule_AddObject(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { + if (_PyModule_Add(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { return -1; } return 0; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0f82f1afa07aa8..fde1e4f461bc9e 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13463,7 +13463,7 @@ setup_confname_table(struct constdef *table, size_t tablesize, } Py_DECREF(o); } - return PyModule_AddObject(module, tablename, d); + return _PyModule_Add(module, tablename, d); } /* Return -1 on failure, 0 on success. */ @@ -16778,11 +16778,9 @@ posixmodule_exec(PyObject *m) #endif /* Initialize environ dictionary */ - PyObject *v = convertenviron(); - Py_XINCREF(v); - if (v == NULL || PyModule_AddObject(m, "environ", v) != 0) + if (_PyModule_Add(m, "environ", convertenviron()) != 0) { return -1; - Py_DECREF(v); + } if (all_ins(m)) return -1; @@ -16897,9 +16895,7 @@ posixmodule_exec(PyObject *m) Py_DECREF(unicode); } - PyModule_AddObject(m, "_have_functions", list); - - return 0; + return _PyModule_Add(m, "_have_functions", list); } diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 3607855dbd8f27..f5b0f39e14abc3 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1790,11 +1790,9 @@ init_timezone(PyObject *m) return -1; } #endif // MS_WINDOWS - PyObject *tzname_obj = Py_BuildValue("(NN)", otz0, otz1); - if (tzname_obj == NULL) { + if (_PyModule_Add(m, "tzname", Py_BuildValue("(NN)", otz0, otz1)) < 0) { return -1; } - PyModule_AddObject(m, "tzname", tzname_obj); #else // !HAVE_DECL_TZNAME static const time_t YEAR = (365 * 24 + 6) * 3600; time_t t; @@ -1837,10 +1835,9 @@ init_timezone(PyObject *m) PyModule_AddIntConstant(m, "daylight", janzone != julyzone); tzname_obj = Py_BuildValue("(zz)", janname, julyname); } - if (tzname_obj == NULL) { + if (_PyModule_Add(m, "tzname", tzname_obj) < 0) { return -1; } - PyModule_AddObject(m, "tzname", tzname_obj); #endif // !HAVE_DECL_TZNAME if (PyErr_Occurred()) { diff --git a/Python/modsupport.c b/Python/modsupport.c index be229c987b8a78..df4ae35a52576d 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -649,13 +649,16 @@ PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value) PyModule_GetName(mod)); return -1; } - - if (PyDict_SetItemString(dict, name, value)) { - return -1; - } - return 0; + return PyDict_SetItemString(dict, name, value); } +int +_PyModule_Add(PyObject *mod, const char *name, PyObject *value) +{ + int res = PyModule_AddObjectRef(mod, name, value); + Py_XDECREF(value); + return res; +} int PyModule_AddObject(PyObject *mod, const char *name, PyObject *value) @@ -670,25 +673,13 @@ PyModule_AddObject(PyObject *mod, const char *name, PyObject *value) int PyModule_AddIntConstant(PyObject *m, const char *name, long value) { - PyObject *obj = PyLong_FromLong(value); - if (!obj) { - return -1; - } - int res = PyModule_AddObjectRef(m, name, obj); - Py_DECREF(obj); - return res; + return _PyModule_Add(m, name, PyLong_FromLong(value)); } int PyModule_AddStringConstant(PyObject *m, const char *name, const char *value) { - PyObject *obj = PyUnicode_FromString(value); - if (!obj) { - return -1; - } - int res = PyModule_AddObjectRef(m, name, obj); - Py_DECREF(obj); - return res; + return _PyModule_Add(m, name, PyUnicode_FromString(value)); } int From 0c106a91e8e54bbf114cb54540dddb2a39a0e2be Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 18 Jul 2023 16:16:19 -0700 Subject: [PATCH 0377/1206] [3.12] Docs: Argument Clinic: Group guides about default values (GH-106872) (#106874) Docs: Argument Clinic: Group guides about default values (GH-106872) Previous ToC layout (excerpt): - How to use symbolic default values ... - How to assign default values to parameter - How to use the ``NULL`` default value - How to use expressions as default values New layout: - How to assign default values to parameter - The ``NULL`` default value - Symbolic default values - Expressions as default values (cherry picked from commit 505eede38d141d43e40e246319b157e3c77211d3) Co-authored-by: Erlend E. Aasland --- Doc/howto/clinic.rst | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 12d7a77d43209a..efeb22c618b512 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -564,22 +564,6 @@ How-to guides ============= -How to use symbolic default values ----------------------------------- - -The default value you provide for a parameter can't be any arbitrary -expression. Currently the following are explicitly supported: - -* Numeric constants (integer and float) -* String constants -* ``True``, ``False``, and ``None`` -* Simple symbolic constants like ``sys.maxsize``, which must - start with the name of the module - -(In the future, this may need to get even more elaborate, -to allow full expressions like ``CONSTANT - 1``.) - - How to to rename C functions and variables generated by Argument Clinic ----------------------------------------------------------------------- @@ -965,8 +949,8 @@ There's also special support for a default value of ``NULL``, and for simple expressions, documented in the following sections. -How to use the ``NULL`` default value -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The ``NULL`` default value +^^^^^^^^^^^^^^^^^^^^^^^^^^ For string and object parameters, you can set them to ``None`` to indicate that there's no default. However, that means the C variable will be @@ -976,8 +960,24 @@ behaves like a default value of ``None``, but the C variable is initialized with ``NULL``. -How to use expressions as default values -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Symbolic default values +^^^^^^^^^^^^^^^^^^^^^^^ + +The default value you provide for a parameter can't be any arbitrary +expression. Currently the following are explicitly supported: + +* Numeric constants (integer and float) +* String constants +* ``True``, ``False``, and ``None`` +* Simple symbolic constants like ``sys.maxsize``, which must + start with the name of the module + +(In the future, this may need to get even more elaborate, +to allow full expressions like ``CONSTANT - 1``.) + + +Expressions as default values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The default value for a parameter can be more than just a literal value. It can be an entire expression, using math operators and looking up attributes From b1c50b80a6197ba1e41539ec0984a9925956cc1d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 19 Jul 2023 04:34:54 -0700 Subject: [PATCH 0378/1206] [3.12] gh-104090: Fix unittest collectedDurations resources leak (GH-106795) (#106888) gh-104090: Fix unittest collectedDurations resources leak (GH-106795) (cherry picked from commit 70b961ed93f67e34d0624e178f6029c886afaeee) Co-authored-by: Yonatan Bitton --- Lib/unittest/result.py | 3 ++- .../next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py index 7757dba9670b43..3ace0a5b7bf2ef 100644 --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -166,7 +166,8 @@ def addDuration(self, test, elapsed): """ # support for a TextTestRunner using an old TestResult class if hasattr(self, "collectedDurations"): - self.collectedDurations.append((test, elapsed)) + # Pass test repr and not the test object itself to avoid resources leak + self.collectedDurations.append((str(test), elapsed)) def wasSuccessful(self): """Tells whether or not this result was a success.""" diff --git a/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst b/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst new file mode 100644 index 00000000000000..5cc6c5bbe15446 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst @@ -0,0 +1 @@ +Avoid creating a reference to the test object in :meth:`~unittest.TestResult.collectedDurations`. From c16cf9b6e59a4b9f374644edf463ec187c268c3d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 19 Jul 2023 13:03:56 -0700 Subject: [PATCH 0379/1206] [3.12] gh-106882: Note that `asyncio.Server` is only publicly exposed on 3.11+ (GH-106901) (#106902) gh-106882: Note that `asyncio.Server` is only publicly exposed on 3.11+ (GH-106901) And later versions of 3.10, 3.9 (cherry picked from commit 1e1f4e91a905bab3103250a3ceadac0693b926d9) Co-authored-by: Jack Nelson --- Doc/library/asyncio-eventloop.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 38f2e2f510c176..1ef8a5ab832e47 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1593,6 +1593,9 @@ Do not instantiate the :class:`Server` class directly. .. versionchanged:: 3.7 Server object is an asynchronous context manager since Python 3.7. + .. versionchanged:: 3.11 + This class was exposed publicly as ``asyncio.Server`` in Python 3.9.11, 3.10.3 and 3.11. + .. method:: close() Stop serving: close listening sockets and set the :attr:`sockets` From bc107e53d47c4b4ed242b04118bff7bb9ccf01c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 20 Jul 2023 02:29:31 -0700 Subject: [PATCH 0380/1206] [3.12] Fix typo in 3.11.4 changelog: urllib.request.Requst -> Request (GH-106830) (#106912) Fix typo in 3.11.4 changelog: urllib.request.Requst -> Request (GH-106830) (cherry picked from commit 009e8f084c4cbb1f43d40b24b7f71fb189bbe36b) Co-authored-by: Zach Brantmeier --- Misc/NEWS.d/3.12.0b1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index a1ea082b3a2119..3de3b703e9f4f6 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -1955,7 +1955,7 @@ introduced in :pep:`692`. .. section: Documentation Clarifying documentation about the url parameter to urllib.request.urlopen -and urllib.request.Requst needing to be encoded properly. +and urllib.request.Request needing to be encoded properly. .. From c1fd76e138c0acf4b90b08ded990d6521187fe63 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 20 Jul 2023 16:11:52 -0700 Subject: [PATCH 0381/1206] [3.12] Fix typo in tkinter docs (GH-106936) (#106937) Fix typo in tkinter docs (GH-106936) (cherry picked from commit 60e83968d555d53b97de04a0a00b2cdeb3187d39) Signed-off-by: Makonede <61922615+Makonede@users.noreply.github.com> Co-authored-by: Makonede <61922615+Makonede@users.noreply.github.com> --- Doc/library/tkinter.ttk.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 4ff2b2159c3622..9f2f9eb858afd4 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -102,7 +102,7 @@ themed widgets and is not supposed to be directly instantiated. Standard Options ^^^^^^^^^^^^^^^^ -All the :mod:`ttk` Widgets accepts the following options: +All the :mod:`ttk` Widgets accept the following options: .. tabularcolumns:: |l|L| From 656f62454bff35db8d630ca43c94bf6db44338ba Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 20 Jul 2023 21:05:46 -0700 Subject: [PATCH 0382/1206] [3.12] gh-106669: Revert "gh-102988: Detect email address parsing errors ... (GH-105127)" (GH-106733) (#106941) This reverts commit 18dfbd035775c15533d13a98e56b1d2bf5c65f00. Adds a regression test from the issue. See https://github.com/python/cpython/issues/106669.. (cherry picked from commit a31dea1feb61793e48fa9aa5014f358352205c1d) --- Doc/library/email.utils.rst | 26 +---- Doc/whatsnew/3.12.rst | 8 -- Lib/email/utils.py | 63 ++---------- Lib/test/test_email/test_email.py | 96 ++++--------------- ...-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst | 4 + 5 files changed, 30 insertions(+), 167 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index a87a0bd2e7de6b..345b64001c1ace 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -65,11 +65,6 @@ of the new API. *email address* parts. Returns a tuple of that information, unless the parse fails, in which case a 2-tuple of ``('', '')`` is returned. - .. versionchanged:: 3.12 - For security reasons, addresses that were ambiguous and could parse into - multiple different addresses now cause ``('', '')`` to be returned - instead of only one of the *potential* addresses. - .. function:: formataddr(pair, charset='utf-8') @@ -92,7 +87,7 @@ of the new API. This method returns a list of 2-tuples of the form returned by ``parseaddr()``. *fieldvalues* is a sequence of header field values as might be returned by :meth:`Message.get_all `. Here's a simple - example that gets all the recipients of a message: + example that gets all the recipients of a message:: from email.utils import getaddresses @@ -102,25 +97,6 @@ of the new API. resent_ccs = msg.get_all('resent-cc', []) all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) - When parsing fails for a single fieldvalue, a 2-tuple of ``('', '')`` - is returned in its place. Other errors in parsing the list of - addresses such as a fieldvalue seemingly parsing into multiple - addresses may result in a list containing a single empty 2-tuple - ``[('', '')]`` being returned rather than returning potentially - invalid output. - - Example malformed input parsing: - - .. doctest:: - - >>> from email.utils import getaddresses - >>> getaddresses(['alice@example.com ', 'me@example.com']) - [('', '')] - - .. versionchanged:: 3.12 - The 2-tuple of ``('', '')`` in the returned values when parsing - fails were added as to address a security issue. - .. function:: parsedate(date) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d6d7b7dac9a310..068618fe48e1b0 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -570,14 +570,6 @@ dis :data:`~dis.hasarg` collection instead. (Contributed by Irit Katriel in :gh:`94216`.) -email ------ - -* :func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now return - ``('', '')`` 2-tuples in more situations where invalid email addresses are - encountered instead of potentially inaccurate values. - (Contributed by Thomas Dwyer for :gh:`102988` to ameliorate CVE-2023-27043.) - fractions --------- diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 11ad75e94e9345..81da5394ea1695 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -106,54 +106,12 @@ def formataddr(pair, charset='utf-8'): return address -def _pre_parse_validation(email_header_fields): - accepted_values = [] - for v in email_header_fields: - s = v.replace('\\(', '').replace('\\)', '') - if s.count('(') != s.count(')'): - v = "('', '')" - accepted_values.append(v) - - return accepted_values - - -def _post_parse_validation(parsed_email_header_tuples): - accepted_values = [] - # The parser would have parsed a correctly formatted domain-literal - # The existence of an [ after parsing indicates a parsing failure - for v in parsed_email_header_tuples: - if '[' in v[1]: - v = ('', '') - accepted_values.append(v) - - return accepted_values - def getaddresses(fieldvalues): - """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue. - - When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in - its place. - - If the resulting list of parsed address is not the same as the number of - fieldvalues in the input list a parsing error has occurred. A list - containing a single empty 2-tuple [('', '')] is returned in its place. - This is done to avoid invalid output. - """ - fieldvalues = [str(v) for v in fieldvalues] - fieldvalues = _pre_parse_validation(fieldvalues) - all = COMMASPACE.join(v for v in fieldvalues) + """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" + all = COMMASPACE.join(str(v) for v in fieldvalues) a = _AddressList(all) - result = _post_parse_validation(a.addresslist) - - n = 0 - for v in fieldvalues: - n += v.count(',') + 1 - - if len(result) != n: - return [('', '')] - - return result + return a.addresslist def _format_timetuple_and_zone(timetuple, zone): @@ -254,18 +212,9 @@ def parseaddr(addr): Return a tuple of realname and email address, unless the parse fails, in which case return a 2-tuple of ('', ''). """ - if isinstance(addr, list): - addr = addr[0] - - if not isinstance(addr, str): - return ('', '') - - addr = _pre_parse_validation([addr])[0] - addrs = _post_parse_validation(_AddressList(addr).addresslist) - - if not addrs or len(addrs) > 1: - return ('', '') - + addrs = _AddressList(addr).addresslist + if not addrs: + return '', '' return addrs[0] diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 5238944d6b4788..b4f3a2481976e8 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3319,90 +3319,32 @@ def test_getaddresses(self): [('Al Person', 'aperson@dom.ain'), ('Bud Person', 'bperson@dom.ain')]) - def test_getaddresses_parsing_errors(self): - """Test for parsing errors from CVE-2023-27043""" - eq = self.assertEqual - eq(utils.getaddresses(['alice@example.org(']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org)']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org<']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org>']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org@']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org,']), - [('', 'alice@example.org'), ('', 'bob@example.com')]) - eq(utils.getaddresses(['alice@example.org;']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org:']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org.']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org"']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org[']), - [('', '')]) - eq(utils.getaddresses(['alice@example.org]']), - [('', '')]) - - def test_parseaddr_parsing_errors(self): - """Test for parsing errors from CVE-2023-27043""" - eq = self.assertEqual - eq(utils.parseaddr(['alice@example.org(']), - ('', '')) - eq(utils.parseaddr(['alice@example.org)']), - ('', '')) - eq(utils.parseaddr(['alice@example.org<']), - ('', '')) - eq(utils.parseaddr(['alice@example.org>']), - ('', '')) - eq(utils.parseaddr(['alice@example.org@']), - ('', '')) - eq(utils.parseaddr(['alice@example.org,']), - ('', '')) - eq(utils.parseaddr(['alice@example.org;']), - ('', '')) - eq(utils.parseaddr(['alice@example.org:']), - ('', '')) - eq(utils.parseaddr(['alice@example.org.']), - ('', '')) - eq(utils.parseaddr(['alice@example.org"']), - ('', '')) - eq(utils.parseaddr(['alice@example.org[']), - ('', '')) - eq(utils.parseaddr(['alice@example.org]']), - ('', '')) + def test_getaddresses_comma_in_name(self): + """GH-106669 regression test.""" + self.assertEqual( + utils.getaddresses( + [ + '"Bud, Person" ', + 'aperson@dom.ain (Al Person)', + '"Mariusz Felisiak" ', + ] + ), + [ + ('Bud, Person', 'bperson@dom.ain'), + ('Al Person', 'aperson@dom.ain'), + ('Mariusz Felisiak', 'to@example.com'), + ], + ) def test_getaddresses_nasty(self): eq = self.assertEqual eq(utils.getaddresses(['foo: ;']), [('', '')]) - eq(utils.getaddresses(['[]*-- =~$']), [('', '')]) + eq(utils.getaddresses( + ['[]*-- =~$']), + [('', ''), ('', ''), ('', '*--')]) eq(utils.getaddresses( ['foo: ;', '"Jason R. Mastaler" ']), [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) - eq(utils.getaddresses( - [r'Pete(A nice \) chap) ']), - [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]) - eq(utils.getaddresses( - ['(Empty list)(start)Undisclosed recipients :(nobody(I know))']), - [('', '')]) - eq(utils.getaddresses( - ['Mary <@machine.tld:mary@example.net>, , jdoe@test . example']), - [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]) - eq(utils.getaddresses( - ['John Doe ']), - [('John Doe (comment)', 'jdoe@machine.example')]) - eq(utils.getaddresses( - ['"Mary Smith: Personal Account" ']), - [('Mary Smith: Personal Account', 'smith@home.example')]) - eq(utils.getaddresses( - ['Undisclosed recipients:;']), - [('', '')]) - eq(utils.getaddresses( - [r', "Giant; \"Big\" Box" ']), - [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]) def test_getaddresses_embedded_comment(self): """Test proper handling of a nested comment""" diff --git a/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst new file mode 100644 index 00000000000000..c67ec45737b535 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst @@ -0,0 +1,4 @@ +Reverted the :mod:`email.utils` security improvement change released in +3.12beta4 that unintentionally caused :mod:`email.utils.getaddresses` to fail +to parse email addresses with a comma in the quoted name field. +See :gh:`106669`. From 1a3766bb3e5ad5cdd7c3e4c352eb0147ccc9a6ce Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 20 Jul 2023 23:18:18 -0700 Subject: [PATCH 0383/1206] [3.12] Docs: Argument Clinic: Add Background and Tutorial top-level sections (GH-106904) (#106945) Docs: Argument Clinic: Add Background and Tutorial top-level sections (GH-106904) Add Background as a toplevel section with the following subsections: - Background - The goals of Argument Clinic - Basic concepts and usage Rename "Converting your first function" to Tutorial. Add anchors for Background, Tutorial, and How-to Guides: - :ref:`clinic-background` - :ref:`clinic-tutorial` - :ref:`clinic-howtos` Link to these from within the Abstract. Break the compatibility paragraph out of Abstract and make it a note. (cherry picked from commit 81861fd90b4ae981e7881cd03a3c370713063525) Co-authored-by: Erlend E. Aasland Co-authored-by: Ezio Melotti --- Doc/howto/clinic.rst | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index efeb22c618b512..f6bf1d2234f88d 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -13,12 +13,20 @@ Argument Clinic How-To Argument Clinic is a preprocessor for CPython C files. Its purpose is to automate all the boilerplate involved - with writing argument parsing code for "builtins". - This document shows you how to convert your first C - function to work with Argument Clinic, and then introduces - some advanced topics on Argument Clinic usage. + with writing argument parsing code for "builtins", + module level functions, and class methods. + This document is divided in three major sections: - Currently Argument Clinic is considered internal-only + * :ref:`clinic-background` talks about the basic concepts and goals of + Argument Clinic. + * :ref:`clinic-tutorial` guides you through all the steps required to + adapt an existing C function to Argument Clinic. + * :ref:`clinic-howtos` details how to handle specific tasks. + + +.. note:: + + Argument Clinic is considered internal-only for CPython. Its use is not supported for files outside CPython, and no guarantees are made regarding backwards compatibility for future versions. In other words: if you @@ -28,8 +36,14 @@ Argument Clinic How-To of CPython *could* be totally incompatible and break all your code. +.. _clinic-background: + +Background +========== + + The goals of Argument Clinic -============================ +---------------------------- Argument Clinic's primary goal is to take over responsibility for all argument parsing code @@ -80,7 +94,7 @@ things with all the information you give it. Basic concepts and usage -======================== +------------------------ Argument Clinic ships with CPython; you'll find it in ``Tools/clinic/clinic.py``. If you run that script, specifying a C file as an argument: @@ -142,8 +156,10 @@ For the sake of clarity, here's the terminology we'll use with Argument Clinic: a block.) -Converting your first function -============================== +.. _clinic-tutorial: + +Tutorial +======== The best way to get a sense of how Argument Clinic works is to convert a function to work with it. Here, then, are the bare @@ -560,6 +576,8 @@ Let's dive in! Congratulations, you've ported your first function to work with Argument Clinic! +.. _clinic-howtos: + How-to guides ============= From 807afdac416356c5e4558f11a8e1cfc5f0c86dd7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 20 Jul 2023 23:32:30 -0700 Subject: [PATCH 0384/1206] [3.12] gh-106368: Increase Argument Clinic test coverage for IndentStack (GH-106933) (#106943) (cherry picked from commit 8d228cf66f316803e95685d6553084f3d60cd9c5) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index e925ecca1b9c5d..7c725e33f53928 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1035,6 +1035,25 @@ def test_function_not_at_column_0(self): Nested docstring here, goeth. """) + def test_indent_stack_no_tabs(self): + out = self.parse_function_should_fail(""" + module foo + foo.bar + *vararg1: object + \t*vararg2: object + """) + msg = "Tab characters are illegal in the Clinic DSL." + self.assertIn(msg, out) + + def test_indent_stack_illegal_outdent(self): + out = self.parse_function_should_fail(""" + module foo + foo.bar + a: object + b: object + """) + self.assertIn("Illegal outdent", out) + def test_directive(self): c = FakeClinic() parser = DSLParser(c) From ac9aa8a369e03784c5df7f2f8b598959fc9ef5f4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jul 2023 14:48:15 +0300 Subject: [PATCH 0385/1206] [3.12] gh-106919: Use role :c:macro: for referencing the C "constants" (GH-106920) (GH-106951) (cherry picked from commit fcc816dbff7ca66c26f57a506e4d2330fe41d0ff) --- Doc/c-api/arg.rst | 4 +- Doc/c-api/call.rst | 18 ++-- Doc/c-api/complex.rst | 4 +- Doc/c-api/exceptions.rst | 12 +-- Doc/c-api/file.rst | 2 +- Doc/c-api/float.rst | 4 +- Doc/c-api/gcsupport.rst | 12 +-- Doc/c-api/init.rst | 62 +++++------ Doc/c-api/long.rst | 8 +- Doc/c-api/memory.rst | 18 ++-- Doc/c-api/module.rst | 6 +- Doc/c-api/object.rst | 16 +-- Doc/c-api/slice.rst | 2 +- Doc/c-api/stable.rst | 2 +- Doc/c-api/structures.rst | 72 ++++++++----- Doc/c-api/sys.rst | 4 +- Doc/c-api/type.rst | 14 +-- Doc/c-api/typeobj.rst | 160 ++++++++++++++-------------- Doc/c-api/unicode.rst | 10 +- Doc/c-api/veryhigh.rst | 8 +- Doc/extending/extending.rst | 4 +- Doc/extending/newtypes_tutorial.rst | 8 +- Doc/howto/isolating-extensions.rst | 10 +- Doc/library/dis.rst | 4 +- Doc/library/os.rst | 14 +-- Doc/reference/compound_stmts.rst | 4 +- Doc/using/cmdline.rst | 8 +- Doc/whatsnew/2.2.rst | 6 +- Doc/whatsnew/2.3.rst | 8 +- Doc/whatsnew/2.4.rst | 2 +- Doc/whatsnew/2.6.rst | 6 +- Doc/whatsnew/2.7.rst | 2 +- Doc/whatsnew/3.10.rst | 10 +- Doc/whatsnew/3.11.rst | 4 +- Doc/whatsnew/3.12.rst | 24 ++--- Doc/whatsnew/3.6.rst | 10 +- Doc/whatsnew/3.8.rst | 2 +- Doc/whatsnew/3.9.rst | 2 +- Misc/NEWS.d/3.10.0a3.rst | 2 +- Misc/NEWS.d/3.10.0b1.rst | 8 +- Misc/NEWS.d/3.11.0a1.rst | 8 +- Misc/NEWS.d/3.11.0a7.rst | 2 +- Misc/NEWS.d/3.12.0a1.rst | 10 +- Misc/NEWS.d/3.12.0a2.rst | 2 +- Misc/NEWS.d/3.6.0a1.rst | 2 +- Misc/NEWS.d/3.9.0a1.rst | 2 +- 46 files changed, 310 insertions(+), 292 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 9713431688d499..eba8f2be70b458 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -343,7 +343,7 @@ Other objects *items*. Format units for sequences may be nested. It is possible to pass "long" integers (integers whose value exceeds the -platform's :const:`LONG_MAX`) however no proper range checking is done --- the +platform's :c:macro:`LONG_MAX`) however no proper range checking is done --- the most significant bits are silently truncated when the receiving field is too small to receive the value (actually, the semantics are inherited from downcasts in C --- your mileage may vary). @@ -455,7 +455,7 @@ API Functions A simpler form of parameter retrieval which does not use a format string to specify the types of the arguments. Functions which use this method to retrieve - their parameters should be declared as :const:`METH_VARARGS` in function or + their parameters should be declared as :c:macro:`METH_VARARGS` in function or method tables. The tuple containing the actual parameters should be passed as *args*; it must actually be a tuple. The length of the tuple must be at least *min* and no more than *max*; *min* and *max* may be equal. Additional diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index 4dc66e318cd12e..143fce3cdf477e 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -59,12 +59,12 @@ This bears repeating: .. versionchanged:: 3.12 - The :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class + The :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class when the class's :py:meth:`~object.__call__` method is reassigned. (This internally sets :c:member:`~PyTypeObject.tp_call` only, and thus may make it behave differently than the vectorcall function.) In earlier Python versions, vectorcall should only be used with - :const:`immutable ` or static types. + :c:macro:`immutable ` or static types. A class should not implement vectorcall if that would be slower than *tp_call*. For example, if the callee needs to convert @@ -72,7 +72,7 @@ the arguments to an args tuple and kwargs dict anyway, then there is no point in implementing vectorcall. Classes can implement the vectorcall protocol by enabling the -:const:`Py_TPFLAGS_HAVE_VECTORCALL` flag and setting +:c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag and setting :c:member:`~PyTypeObject.tp_vectorcall_offset` to the offset inside the object structure where a *vectorcallfunc* appears. This is a pointer to a function with the following signature: @@ -84,7 +84,7 @@ This is a pointer to a function with the following signature: values of the keyword arguments. This can be *NULL* if there are no arguments. - *nargsf* is the number of positional arguments plus possibly the - :const:`PY_VECTORCALL_ARGUMENTS_OFFSET` flag. + :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET` flag. To get the actual number of positional arguments from *nargsf*, use :c:func:`PyVectorcall_NARGS`. - *kwnames* is a tuple containing the names of the keyword arguments; @@ -93,7 +93,7 @@ This is a pointer to a function with the following signature: and they must be unique. If there are no keyword arguments, then *kwnames* can instead be *NULL*. -.. data:: PY_VECTORCALL_ARGUMENTS_OFFSET +.. c:macro:: PY_VECTORCALL_ARGUMENTS_OFFSET If this flag is set in a vectorcall *nargsf* argument, the callee is allowed to temporarily change ``args[-1]``. In other words, *args* points to @@ -104,7 +104,7 @@ This is a pointer to a function with the following signature: ``args[0]`` may be changed. Whenever they can do so cheaply (without additional allocation), callers - are encouraged to use :const:`PY_VECTORCALL_ARGUMENTS_OFFSET`. + are encouraged to use :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET`. Doing so will allow callables such as bound methods to make their onward calls (which include a prepended *self* argument) very efficiently. @@ -174,7 +174,7 @@ Vectorcall Support API This is a specialized function, intended to be put in the :c:member:`~PyTypeObject.tp_call` slot or be used in an implementation of ``tp_call``. - It does not check the :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag + It does not check the :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag and it does not fall back to ``tp_call``. .. versionadded:: 3.8 @@ -392,11 +392,11 @@ please see individual documentation for details. *args[0]*, and the *args* array starting at *args[1]* represents the arguments of the call. There must be at least one positional argument. *nargsf* is the number of positional arguments including *args[0]*, - plus :const:`PY_VECTORCALL_ARGUMENTS_OFFSET` if the value of ``args[0]`` may + plus :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET` if the value of ``args[0]`` may temporarily be changed. Keyword arguments can be passed just like in :c:func:`PyObject_Vectorcall`. - If the object has the :const:`Py_TPFLAGS_METHOD_DESCRIPTOR` feature, + If the object has the :c:macro:`Py_TPFLAGS_METHOD_DESCRIPTOR` feature, this will call the unbound method object with the full *args* vector as arguments. diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index cb8b270fcbab6e..6679ce76f1dc6f 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -64,7 +64,7 @@ pointers. This is consistent throughout the API. representation. If *divisor* is null, this method returns zero and sets - :c:data:`errno` to :c:data:`EDOM`. + :c:data:`errno` to :c:macro:`EDOM`. .. c:function:: Py_complex _Py_c_pow(Py_complex num, Py_complex exp) @@ -73,7 +73,7 @@ pointers. This is consistent throughout the API. representation. If *num* is null and *exp* is not a positive real number, - this method returns zero and sets :c:data:`errno` to :c:data:`EDOM`. + this method returns zero and sets :c:data:`errno` to :c:macro:`EDOM`. Complex Numbers as Python Objects diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index a24ecac861e76b..6e09f829da3043 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -165,7 +165,7 @@ For convenience, some of these functions will always return a tuple object whose first item is the integer :c:data:`errno` value and whose second item is the corresponding error message (gotten from :c:func:`strerror`), and then calls ``PyErr_SetObject(type, object)``. On Unix, when the - :c:data:`errno` value is :const:`EINTR`, indicating an interrupted system call, + :c:data:`errno` value is :c:macro:`EINTR`, indicating an interrupted system call, this calls :c:func:`PyErr_CheckSignals`, and if that set the error indicator, leaves it set to that. The function always returns ``NULL``, so a wrapper function around a system call can write ``return PyErr_SetFromErrno(type);`` @@ -631,7 +631,7 @@ Signal Handling be interruptible by user requests (such as by pressing Ctrl-C). .. note:: - The default Python signal handler for :const:`SIGINT` raises the + The default Python signal handler for :c:macro:`SIGINT` raises the :exc:`KeyboardInterrupt` exception. @@ -642,7 +642,7 @@ Signal Handling single: SIGINT single: KeyboardInterrupt (built-in exception) - Simulate the effect of a :const:`SIGINT` signal arriving. + Simulate the effect of a :c:macro:`SIGINT` signal arriving. This is equivalent to ``PyErr_SetInterruptEx(SIGINT)``. .. note:: @@ -754,7 +754,7 @@ Exception Objects .. c:function:: PyObject* PyException_GetCause(PyObject *ex) - Return the cause (either an exception instance, or :const:`None`, + Return the cause (either an exception instance, or ``None``, set by ``raise ... from ...``) associated with the exception as a new reference, as accessible from Python through :attr:`__cause__`. @@ -763,7 +763,7 @@ Exception Objects Set the cause associated with the exception to *cause*. Use ``NULL`` to clear it. There is no type check to make sure that *cause* is either an exception - instance or :const:`None`. This steals a reference to *cause*. + instance or ``None``. This steals a reference to *cause*. :attr:`__suppress_context__` is implicitly set to ``True`` by this function. @@ -874,7 +874,7 @@ because the :ref:`call protocol ` takes care of recursion handling. Marks a point where a recursive C-level call is about to be performed. - If :const:`USE_STACKCHECK` is defined, this function checks if the OS + If :c:macro:`USE_STACKCHECK` is defined, this function checks if the OS stack overflowed using :c:func:`PyOS_CheckStack`. In this is the case, it sets a :exc:`MemoryError` and returns a nonzero value. diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index f32ecba9f27029..b36c800e00444a 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -93,7 +93,7 @@ the :mod:`io` APIs instead. .. index:: single: Py_PRINT_RAW Write object *obj* to file object *p*. The only supported flag for *flags* is - :const:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written + :c:macro:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written instead of the :func:`repr`. Return ``0`` on success or ``-1`` on failure; the appropriate exception will be set. diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index fd0be1108c6300..4f6ac0d8175c6b 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -109,7 +109,7 @@ Pack functions The pack routines write 2, 4 or 8 bytes, starting at *p*. *le* is an :c:expr:`int` argument, non-zero if you want the bytes string in little-endian format (exponent last, at ``p+1``, ``p+3``, or ``p+6`` ``p+7``), zero if you -want big-endian format (exponent first, at *p*). The :c:data:`PY_BIG_ENDIAN` +want big-endian format (exponent first, at *p*). The :c:macro:`PY_BIG_ENDIAN` constant can be used to use the native endian: it is equal to ``1`` on big endian processor, or ``0`` on little endian processor. @@ -140,7 +140,7 @@ Unpack functions The unpack routines read 2, 4 or 8 bytes, starting at *p*. *le* is an :c:expr:`int` argument, non-zero if the bytes string is in little-endian format (exponent last, at ``p+1``, ``p+3`` or ``p+6`` and ``p+7``), zero if big-endian -(exponent first, at *p*). The :c:data:`PY_BIG_ENDIAN` constant can be used to +(exponent first, at *p*). The :c:macro:`PY_BIG_ENDIAN` constant can be used to use the native endian: it is equal to ``1`` on big endian processor, or ``0`` on little endian processor. diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index c3260a21bc7f8b..e56414ab9f754d 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -13,14 +13,12 @@ or strings), do not need to provide any explicit support for garbage collection. To create a container type, the :c:member:`~PyTypeObject.tp_flags` field of the type object must -include the :const:`Py_TPFLAGS_HAVE_GC` and provide an implementation of the +include the :c:macro:`Py_TPFLAGS_HAVE_GC` and provide an implementation of the :c:member:`~PyTypeObject.tp_traverse` handler. If instances of the type are mutable, a :c:member:`~PyTypeObject.tp_clear` implementation must also be provided. -.. data:: Py_TPFLAGS_HAVE_GC - :noindex: - +:c:macro:`Py_TPFLAGS_HAVE_GC` Objects with a type with this flag set must conform with the rules documented here. For convenience these objects will be referred to as container objects. @@ -52,17 +50,17 @@ rules: :c:member:`~PyTypeObject.tp_flags`, :c:member:`~PyTypeObject.tp_traverse` and :c:member:`~PyTypeObject.tp_clear` fields if the type inherits from a class that implements the garbage collector protocol and the child class - does *not* include the :const:`Py_TPFLAGS_HAVE_GC` flag. + does *not* include the :c:macro:`Py_TPFLAGS_HAVE_GC` flag. .. c:function:: TYPE* PyObject_GC_New(TYPE, PyTypeObject *type) Analogous to :c:func:`PyObject_New` but for container objects with the - :const:`Py_TPFLAGS_HAVE_GC` flag set. + :c:macro:`Py_TPFLAGS_HAVE_GC` flag set. .. c:function:: TYPE* PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size) Analogous to :c:func:`PyObject_NewVar` but for container objects with the - :const:`Py_TPFLAGS_HAVE_GC` flag set. + :c:macro:`Py_TPFLAGS_HAVE_GC` flag set. .. c:function:: PyObject* PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 26762969ef8eba..c99377fb45a6bc 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1396,7 +1396,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`. function does not steal any references to *exc*. To prevent naive misuse, you must write your own C extension to call this. Must be called with the GIL held. Returns the number of thread states modified; this is normally one, but will be - zero if the thread id isn't found. If *exc* is :const:`NULL`, the pending + zero if the thread id isn't found. If *exc* is ``NULL``, the pending exception (if any) for the thread is cleared. This raises no exceptions. .. versionchanged:: 3.7 @@ -1675,32 +1675,32 @@ Python-level trace functions in previous versions. The type of the trace function registered using :c:func:`PyEval_SetProfile` and :c:func:`PyEval_SetTrace`. The first parameter is the object passed to the registration function as *obj*, *frame* is the frame object to which the event - pertains, *what* is one of the constants :const:`PyTrace_CALL`, - :const:`PyTrace_EXCEPTION`, :const:`PyTrace_LINE`, :const:`PyTrace_RETURN`, - :const:`PyTrace_C_CALL`, :const:`PyTrace_C_EXCEPTION`, :const:`PyTrace_C_RETURN`, - or :const:`PyTrace_OPCODE`, and *arg* depends on the value of *what*: - - +------------------------------+----------------------------------------+ - | Value of *what* | Meaning of *arg* | - +==============================+========================================+ - | :const:`PyTrace_CALL` | Always :c:data:`Py_None`. | - +------------------------------+----------------------------------------+ - | :const:`PyTrace_EXCEPTION` | Exception information as returned by | - | | :func:`sys.exc_info`. | - +------------------------------+----------------------------------------+ - | :const:`PyTrace_LINE` | Always :c:data:`Py_None`. | - +------------------------------+----------------------------------------+ - | :const:`PyTrace_RETURN` | Value being returned to the caller, | - | | or ``NULL`` if caused by an exception. | - +------------------------------+----------------------------------------+ - | :const:`PyTrace_C_CALL` | Function object being called. | - +------------------------------+----------------------------------------+ - | :const:`PyTrace_C_EXCEPTION` | Function object being called. | - +------------------------------+----------------------------------------+ - | :const:`PyTrace_C_RETURN` | Function object being called. | - +------------------------------+----------------------------------------+ - | :const:`PyTrace_OPCODE` | Always :c:data:`Py_None`. | - +------------------------------+----------------------------------------+ + pertains, *what* is one of the constants :c:data:`PyTrace_CALL`, + :c:data:`PyTrace_EXCEPTION`, :c:data:`PyTrace_LINE`, :c:data:`PyTrace_RETURN`, + :c:data:`PyTrace_C_CALL`, :c:data:`PyTrace_C_EXCEPTION`, :c:data:`PyTrace_C_RETURN`, + or :c:data:`PyTrace_OPCODE`, and *arg* depends on the value of *what*: + + +-------------------------------+----------------------------------------+ + | Value of *what* | Meaning of *arg* | + +===============================+========================================+ + | :c:data:`PyTrace_CALL` | Always :c:data:`Py_None`. | + +-------------------------------+----------------------------------------+ + | :c:data:`PyTrace_EXCEPTION` | Exception information as returned by | + | | :func:`sys.exc_info`. | + +-------------------------------+----------------------------------------+ + | :c:data:`PyTrace_LINE` | Always :c:data:`Py_None`. | + +-------------------------------+----------------------------------------+ + | :c:data:`PyTrace_RETURN` | Value being returned to the caller, | + | | or ``NULL`` if caused by an exception. | + +-------------------------------+----------------------------------------+ + | :c:data:`PyTrace_C_CALL` | Function object being called. | + +-------------------------------+----------------------------------------+ + | :c:data:`PyTrace_C_EXCEPTION` | Function object being called. | + +-------------------------------+----------------------------------------+ + | :c:data:`PyTrace_C_RETURN` | Function object being called. | + +-------------------------------+----------------------------------------+ + | :c:data:`PyTrace_OPCODE` | Always :c:data:`Py_None`. | + +-------------------------------+----------------------------------------+ .. c:var:: int PyTrace_CALL @@ -1767,8 +1767,8 @@ Python-level trace functions in previous versions. function as its first parameter, and may be any Python object, or ``NULL``. If the profile function needs to maintain state, using a different value for *obj* for each thread provides a convenient and thread-safe place to store it. The - profile function is called for all monitored events except :const:`PyTrace_LINE` - :const:`PyTrace_OPCODE` and :const:`PyTrace_EXCEPTION`. + profile function is called for all monitored events except :c:data:`PyTrace_LINE` + :c:data:`PyTrace_OPCODE` and :c:data:`PyTrace_EXCEPTION`. See also the :func:`sys.setprofile` function. @@ -1793,8 +1793,8 @@ Python-level trace functions in previous versions. :c:func:`PyEval_SetProfile`, except the tracing function does receive line-number events and per-opcode events, but does not receive any event related to C function objects being called. Any trace function registered using :c:func:`PyEval_SetTrace` - will not receive :const:`PyTrace_C_CALL`, :const:`PyTrace_C_EXCEPTION` or - :const:`PyTrace_C_RETURN` as a value for the *what* parameter. + will not receive :c:data:`PyTrace_C_CALL`, :c:data:`PyTrace_C_EXCEPTION` or + :c:data:`PyTrace_C_RETURN` as a value for the *what* parameter. See also the :func:`sys.settrace` function. diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index fe379ffe912391..f1354a34f2b2d5 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -142,8 +142,8 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is greater than :const:`LONG_MAX` or less than - :const:`LONG_MIN`, set *\*overflow* to ``1`` or ``-1``, respectively, and + If the value of *obj* is greater than :c:macro:`LONG_MAX` or less than + :c:macro:`LONG_MIN`, set *\*overflow* to ``1`` or ``-1``, respectively, and return ``-1``; otherwise, set *\*overflow* to ``0``. If any other exception occurs set *\*overflow* to ``0`` and return ``-1`` as usual. @@ -183,8 +183,8 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. - If the value of *obj* is greater than :const:`LLONG_MAX` or less than - :const:`LLONG_MIN`, set *\*overflow* to ``1`` or ``-1``, respectively, + If the value of *obj* is greater than :c:macro:`LLONG_MAX` or less than + :c:macro:`LLONG_MIN`, set *\*overflow* to ``1`` or ``-1``, respectively, and return ``-1``; otherwise, set *\*overflow* to ``0``. If any other exception occurs set *\*overflow* to ``0`` and return ``-1`` as usual. diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 7041c15d23fb83..35c356f25c6c70 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -470,7 +470,7 @@ Customize Memory Allocators The new allocator must return a distinct non-``NULL`` pointer when requesting zero bytes. - For the :c:data:`PYMEM_DOMAIN_RAW` domain, the allocator must be + For the :c:macro:`PYMEM_DOMAIN_RAW` domain, the allocator must be thread-safe: the :term:`GIL ` is not held when the allocator is called. @@ -536,8 +536,8 @@ Runtime checks: - Detect write before the start of the buffer (buffer underflow). - Detect write after the end of the buffer (buffer overflow). - Check that the :term:`GIL ` is held when - allocator functions of :c:data:`PYMEM_DOMAIN_OBJ` (ex: - :c:func:`PyObject_Malloc`) and :c:data:`PYMEM_DOMAIN_MEM` (ex: + allocator functions of :c:macro:`PYMEM_DOMAIN_OBJ` (ex: + :c:func:`PyObject_Malloc`) and :c:macro:`PYMEM_DOMAIN_MEM` (ex: :c:func:`PyMem_Malloc`) domains are called. On error, the debug hooks use the :mod:`tracemalloc` module to get the @@ -557,9 +557,9 @@ that the treatment of negative indices differs from a Python slice): ``p[-S]`` API identifier (ASCII character): - * ``'r'`` for :c:data:`PYMEM_DOMAIN_RAW`. - * ``'m'`` for :c:data:`PYMEM_DOMAIN_MEM`. - * ``'o'`` for :c:data:`PYMEM_DOMAIN_OBJ`. + * ``'r'`` for :c:macro:`PYMEM_DOMAIN_RAW`. + * ``'m'`` for :c:macro:`PYMEM_DOMAIN_MEM`. + * ``'o'`` for :c:macro:`PYMEM_DOMAIN_OBJ`. ``p[-S+1:0]`` Copies of PYMEM_FORBIDDENBYTE. Used to catch under- writes and reads. @@ -601,7 +601,7 @@ PYMEM_CLEANBYTE (meaning uninitialized memory is getting used). compiled in release mode. On error, the debug hooks now use :mod:`tracemalloc` to get the traceback where a memory block was allocated. The debug hooks now also check if the GIL is held when functions of - :c:data:`PYMEM_DOMAIN_OBJ` and :c:data:`PYMEM_DOMAIN_MEM` domains are + :c:macro:`PYMEM_DOMAIN_OBJ` and :c:macro:`PYMEM_DOMAIN_MEM` domains are called. .. versionchanged:: 3.8 @@ -622,8 +622,8 @@ with a fixed size of 256 KiB. It falls back to :c:func:`PyMem_RawMalloc` and :c:func:`PyMem_RawRealloc` for allocations larger than 512 bytes. *pymalloc* is the :ref:`default allocator ` of the -:c:data:`PYMEM_DOMAIN_MEM` (ex: :c:func:`PyMem_Malloc`) and -:c:data:`PYMEM_DOMAIN_OBJ` (ex: :c:func:`PyObject_Malloc`) domains. +:c:macro:`PYMEM_DOMAIN_MEM` (ex: :c:func:`PyMem_Malloc`) and +:c:macro:`PYMEM_DOMAIN_OBJ` (ex: :c:func:`PyObject_Malloc`) domains. The arena allocator uses the following functions: diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 230b471d473be7..bc8e3b23b99579 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -145,7 +145,7 @@ or request "multi-phase initialization" by returning the definition struct itsel .. c:member:: PyModuleDef_Base m_base - Always initialize this member to :const:`PyModuleDef_HEAD_INIT`. + Always initialize this member to :c:data:`PyModuleDef_HEAD_INIT`. .. c:member:: const char *m_name @@ -256,7 +256,7 @@ of the following two module creation functions: Create a new module object, given the definition in *def*. This behaves like :c:func:`PyModule_Create2` with *module_api_version* set to - :const:`PYTHON_API_VERSION`. + :c:macro:`PYTHON_API_VERSION`. .. c:function:: PyObject* PyModule_Create2(PyModuleDef *def, int module_api_version) @@ -390,7 +390,7 @@ objects dynamically. Note that both ``PyModule_FromDefAndSpec`` and Create a new module object, given the definition in *def* and the ModuleSpec *spec*. This behaves like :c:func:`PyModule_FromDefAndSpec2` - with *module_api_version* set to :const:`PYTHON_API_VERSION`. + with *module_api_version* set to :c:macro:`PYTHON_API_VERSION`. .. versionadded:: 3.5 diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 22e7458013fb3d..3b922f3b810c72 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -23,7 +23,7 @@ Object Protocol Print an object *o*, on file *fp*. Returns ``-1`` on error. The flags argument is used to enable certain printing options. The only option currently supported - is :const:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written + is :c:macro:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written instead of the :func:`repr`. @@ -162,8 +162,8 @@ Object Protocol .. c:function:: PyObject* PyObject_RichCompare(PyObject *o1, PyObject *o2, int opid) Compare the values of *o1* and *o2* using the operation specified by *opid*, - which must be one of :const:`Py_LT`, :const:`Py_LE`, :const:`Py_EQ`, - :const:`Py_NE`, :const:`Py_GT`, or :const:`Py_GE`, corresponding to ``<``, + which must be one of :c:macro:`Py_LT`, :c:macro:`Py_LE`, :c:macro:`Py_EQ`, + :c:macro:`Py_NE`, :c:macro:`Py_GT`, or :c:macro:`Py_GE`, corresponding to ``<``, ``<=``, ``==``, ``!=``, ``>``, or ``>=`` respectively. This is the equivalent of the Python expression ``o1 op o2``, where ``op`` is the operator corresponding to *opid*. Returns the value of the comparison on success, or ``NULL`` on failure. @@ -172,8 +172,8 @@ Object Protocol .. c:function:: int PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid) Compare the values of *o1* and *o2* using the operation specified by *opid*, - which must be one of :const:`Py_LT`, :const:`Py_LE`, :const:`Py_EQ`, - :const:`Py_NE`, :const:`Py_GT`, or :const:`Py_GE`, corresponding to ``<``, + which must be one of :c:macro:`Py_LT`, :c:macro:`Py_LE`, :c:macro:`Py_EQ`, + :c:macro:`Py_NE`, :c:macro:`Py_GT`, or :c:macro:`Py_GE`, corresponding to ``<``, ``<=``, ``==``, ``!=``, ``>``, or ``>=`` respectively. Returns ``-1`` on error, ``0`` if the result is false, ``1`` otherwise. This is the equivalent of the Python expression ``o1 op o2``, where ``op`` is the operator corresponding to @@ -181,7 +181,7 @@ Object Protocol .. note:: If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` - will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. + will always return ``1`` for :c:macro:`Py_EQ` and ``0`` for :c:macro:`Py_NE`. .. c:function:: PyObject* PyObject_Format(PyObject *obj, PyObject *format_spec) @@ -431,10 +431,10 @@ Object Protocol .. c:function:: void *PyObject_GetItemData(PyObject *o) Get a pointer to per-item data for a class with - :const:`Py_TPFLAGS_ITEMS_AT_END`. + :c:macro:`Py_TPFLAGS_ITEMS_AT_END`. On error, set an exception and return ``NULL``. :py:exc:`TypeError` is raised if *o* does not have - :const:`Py_TPFLAGS_ITEMS_AT_END` set. + :c:macro:`Py_TPFLAGS_ITEMS_AT_END` set. .. versionadded:: 3.12 diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst index c54a659cf2ffd8..9e880c6b7f25ad 100644 --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -34,7 +34,7 @@ Slice Objects *length* as errors. Returns ``0`` on success and ``-1`` on error with no exception set (unless one of - the indices was not :const:`None` and failed to be converted to an integer, + the indices was not ``None`` and failed to be converted to an integer, in which case ``-1`` is returned with an exception set). You probably do not want to use this function. diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst index 149d4d6bac3ee4..c66b296d304adc 100644 --- a/Doc/c-api/stable.rst +++ b/Doc/c-api/stable.rst @@ -74,7 +74,7 @@ Contents of the Limited API are :ref:`listed below `. Define this macro before including ``Python.h`` to opt in to only use the Limited API, and to select the Limited API version. - Define ``Py_LIMITED_API`` to the value of :c:data:`PY_VERSION_HEX` + Define ``Py_LIMITED_API`` to the value of :c:macro:`PY_VERSION_HEX` corresponding to the lowest Python version your extension supports. The extension will work without recompilation with all Python 3 releases from the specified one onward, and can use Limited API introduced up to that diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 766f881463c00f..720ab31f3de856 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -179,7 +179,7 @@ Implementing functions and methods .. c:type:: PyCFunctionWithKeywords Type of the functions used to implement Python callables in C - with signature :const:`METH_VARARGS | METH_KEYWORDS`. + with signature :ref:`METH_VARARGS | METH_KEYWORDS `. The function signature is:: PyObject *PyCFunctionWithKeywords(PyObject *self, @@ -190,7 +190,7 @@ Implementing functions and methods .. c:type:: _PyCFunctionFast Type of the functions used to implement Python callables in C - with signature :const:`METH_FASTCALL`. + with signature :c:macro:`METH_FASTCALL`. The function signature is:: PyObject *_PyCFunctionFast(PyObject *self, @@ -200,7 +200,7 @@ Implementing functions and methods .. c:type:: _PyCFunctionFastWithKeywords Type of the functions used to implement Python callables in C - with signature :const:`METH_FASTCALL | METH_KEYWORDS`. + with signature :ref:`METH_FASTCALL | METH_KEYWORDS `. The function signature is:: PyObject *_PyCFunctionFastWithKeywords(PyObject *self, @@ -211,7 +211,7 @@ Implementing functions and methods .. c:type:: PyCMethod Type of the functions used to implement Python callables in C - with signature :const:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS`. + with signature :ref:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS `. The function signature is:: PyObject *PyCMethod(PyObject *self, @@ -257,7 +257,7 @@ convention. There are these calling conventions: -.. data:: METH_VARARGS +.. c:macro:: METH_VARARGS This is the typical calling convention, where the methods have the type :c:type:`PyCFunction`. The function expects two :c:expr:`PyObject*` values. @@ -267,8 +267,17 @@ There are these calling conventions: using :c:func:`PyArg_ParseTuple` or :c:func:`PyArg_UnpackTuple`. -.. data:: METH_VARARGS | METH_KEYWORDS +.. c:macro:: METH_KEYWORDS + Can only be used in certain combinations with other flags: + :ref:`METH_VARARGS | METH_KEYWORDS `, + :ref:`METH_FASTCALL | METH_KEYWORDS ` and + :ref:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS `. + + +.. _METH_VARARGS-METH_KEYWORDS: + +:c:expr:`METH_VARARGS | METH_KEYWORDS` Methods with these flags must be of type :c:type:`PyCFunctionWithKeywords`. The function expects three parameters: *self*, *args*, *kwargs* where *kwargs* is a dictionary of all the keyword arguments or possibly ``NULL`` @@ -276,7 +285,7 @@ There are these calling conventions: using :c:func:`PyArg_ParseTupleAndKeywords`. -.. data:: METH_FASTCALL +.. c:macro:: METH_FASTCALL Fast calling convention supporting only positional arguments. The methods have the type :c:type:`_PyCFunctionFast`. @@ -291,9 +300,10 @@ There are these calling conventions: ``METH_FASTCALL`` is now part of the :ref:`stable ABI `. -.. data:: METH_FASTCALL | METH_KEYWORDS +.. _METH_FASTCALL-METH_KEYWORDS: - Extension of :const:`METH_FASTCALL` supporting also keyword arguments, +:c:expr:`METH_FASTCALL | METH_KEYWORDS` + Extension of :c:macro:`METH_FASTCALL` supporting also keyword arguments, with methods of type :c:type:`_PyCFunctionFastWithKeywords`. Keyword arguments are passed the same way as in the :ref:`vectorcall protocol `: @@ -306,10 +316,18 @@ There are these calling conventions: .. versionadded:: 3.7 -.. data:: METH_METHOD | METH_FASTCALL | METH_KEYWORDS +.. c:macro:: METH_METHOD + + Can only be used in the combination with other flags: + :ref:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS `. + + +.. _METH_METHOD-METH_FASTCALL-METH_KEYWORDS: - Extension of :const:`METH_FASTCALL | METH_KEYWORDS` supporting the *defining - class*, that is, the class that contains the method in question. +:c:expr:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS` + Extension of :ref:`METH_FASTCALL | METH_KEYWORDS ` + supporting the *defining class*, that is, + the class that contains the method in question. The defining class might be a superclass of ``Py_TYPE(self)``. The method needs to be of type :c:type:`PyCMethod`, the same as for @@ -319,10 +337,10 @@ There are these calling conventions: .. versionadded:: 3.9 -.. data:: METH_NOARGS +.. c:macro:: METH_NOARGS Methods without parameters don't need to check whether arguments are given if - they are listed with the :const:`METH_NOARGS` flag. They need to be of type + they are listed with the :c:macro:`METH_NOARGS` flag. They need to be of type :c:type:`PyCFunction`. The first parameter is typically named *self* and will hold a reference to the module or object instance. In all cases the second parameter will be ``NULL``. @@ -331,9 +349,9 @@ There are these calling conventions: :c:macro:`Py_UNUSED` can be used to prevent a compiler warning. -.. data:: METH_O +.. c:macro:: METH_O - Methods with a single object argument can be listed with the :const:`METH_O` + Methods with a single object argument can be listed with the :c:macro:`METH_O` flag, instead of invoking :c:func:`PyArg_ParseTuple` with a ``"O"`` argument. They have the type :c:type:`PyCFunction`, with the *self* parameter, and a :c:expr:`PyObject*` parameter representing the single argument. @@ -345,7 +363,7 @@ defined for modules. At most one of these flags may be set for any given method. -.. data:: METH_CLASS +.. c:macro:: METH_CLASS .. index:: pair: built-in function; classmethod @@ -355,7 +373,7 @@ method. function. -.. data:: METH_STATIC +.. c:macro:: METH_STATIC .. index:: pair: built-in function; staticmethod @@ -367,7 +385,7 @@ One other constant controls whether a method is loaded in place of another definition with the same method name. -.. data:: METH_COEXIST +.. c:macro:: METH_COEXIST The method will be loaded in place of existing definitions. Without *METH_COEXIST*, the default is to skip repeated definitions. Since slot @@ -440,8 +458,8 @@ Accessing attributes of extension types The legacy offsets :c:member:`~PyTypeObject.tp_dictoffset` and :c:member:`~PyTypeObject.tp_weaklistoffset` can be defined similarly using ``"__dictoffset__"`` and ``"__weaklistoffset__"`` members, but extensions - are strongly encouraged to use :const:`Py_TPFLAGS_MANAGED_DICT` and - :const:`Py_TPFLAGS_MANAGED_WEAKREF` instead. + are strongly encouraged to use :c:macro:`Py_TPFLAGS_MANAGED_DICT` and + :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead. .. versionchanged:: 3.12 @@ -509,19 +527,19 @@ The following flags can be used with :c:member:`PyMemberDef.flags`: .. versionchanged:: 3.10 - The :const:`!RESTRICTED`, :const:`!READ_RESTRICTED` and - :const:`!WRITE_RESTRICTED` macros available with + The :c:macro:`!RESTRICTED`, :c:macro:`!READ_RESTRICTED` and + :c:macro:`!WRITE_RESTRICTED` macros available with ``#include "structmember.h"`` are deprecated. - :const:`!READ_RESTRICTED` and :const:`!RESTRICTED` are equivalent to - :const:`Py_AUDIT_READ`; :const:`!WRITE_RESTRICTED` does nothing. + :c:macro:`!READ_RESTRICTED` and :c:macro:`!RESTRICTED` are equivalent to + :c:macro:`Py_AUDIT_READ`; :c:macro:`!WRITE_RESTRICTED` does nothing. .. index:: single: READONLY .. versionchanged:: 3.12 - The :const:`!READONLY` macro was renamed to :const:`Py_READONLY`. - The :const:`!PY_AUDIT_READ` macro was renamed with the ``Py_`` prefix. + The :c:macro:`!READONLY` macro was renamed to :c:macro:`Py_READONLY`. + The :c:macro:`!PY_AUDIT_READ` macro was renamed with the ``Py_`` prefix. The new names are now always available. Previously, these required ``#include "structmember.h"``. The header is still available and it provides the old names. diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 6fc8a3aff95686..3550193c1af826 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -97,9 +97,9 @@ Operating System Utilities .. c:function:: int PyOS_CheckStack() Return true when the interpreter runs out of stack space. This is a reliable - check, but is only available when :const:`USE_STACKCHECK` is defined (currently + check, but is only available when :c:macro:`USE_STACKCHECK` is defined (currently on certain versions of Windows using the Microsoft Visual C++ compiler). - :const:`USE_STACKCHECK` will be defined automatically; you should never + :c:macro:`USE_STACKCHECK` will be defined automatically; you should never change the definition in your own code. diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index a5f333e2a31e03..d9dcd22a24839e 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -132,7 +132,7 @@ Type Objects .. c:function:: int PyType_IS_GC(PyTypeObject *o) Return true if the type object includes support for the cycle detector; this - tests the type flag :const:`Py_TPFLAGS_HAVE_GC`. + tests the type flag :c:macro:`Py_TPFLAGS_HAVE_GC`. .. c:function:: int PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) @@ -165,10 +165,10 @@ Type Objects .. note:: If some of the base classes implements the GC protocol and the provided - type does not include the :const:`Py_TPFLAGS_HAVE_GC` in its flags, then + type does not include the :c:macro:`Py_TPFLAGS_HAVE_GC` in its flags, then the GC protocol will be automatically implemented from its parents. On the contrary, if the type being created does include - :const:`Py_TPFLAGS_HAVE_GC` in its flags then it **must** implement the + :c:macro:`Py_TPFLAGS_HAVE_GC` in its flags then it **must** implement the GC protocol itself by at least implementing the :c:member:`~PyTypeObject.tp_traverse` handle. @@ -268,7 +268,7 @@ The following functions and structs are used to create .. c:function:: PyObject* PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases) Create and return a :ref:`heap type ` from the *spec* - (see :const:`Py_TPFLAGS_HEAPTYPE`). + (see :c:macro:`Py_TPFLAGS_HEAPTYPE`). The metaclass *metaclass* is used to construct the resulting type object. When *metaclass* is ``NULL``, the metaclass is derived from *bases* @@ -420,7 +420,7 @@ The following functions and structs are used to create - The requested :c:member:`PyType_Spec.basicsize` is zero, suggesting that the subclass does not access the instance's memory directly. - - With the :const:`Py_TPFLAGS_ITEMS_AT_END` flag. + - With the :c:macro:`Py_TPFLAGS_ITEMS_AT_END` flag. .. c:member:: unsigned int flags @@ -471,9 +471,9 @@ The following functions and structs are used to create * :c:member:`~PyTypeObject.tp_weaklist` * :c:member:`~PyTypeObject.tp_vectorcall` * :c:member:`~PyTypeObject.tp_weaklistoffset` - (use :const:`Py_TPFLAGS_MANAGED_WEAKREF` instead) + (use :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead) * :c:member:`~PyTypeObject.tp_dictoffset` - (use :const:`Py_TPFLAGS_MANAGED_DICT` instead) + (use :c:macro:`Py_TPFLAGS_MANAGED_DICT` instead) * :c:member:`~PyTypeObject.tp_vectorcall_offset` (see :ref:`PyMemberDef `) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 7249cfe79c32e9..33591ed14eaf13 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -669,7 +669,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) memory buffers owned by the instance (using the freeing function corresponding to the allocation function used to allocate the buffer), and call the type's :c:member:`~PyTypeObject.tp_free` function. If the type is not subtypable - (doesn't have the :const:`Py_TPFLAGS_BASETYPE` flag bit set), it is + (doesn't have the :c:macro:`Py_TPFLAGS_BASETYPE` flag bit set), it is permissible to call the object deallocator directly instead of via :c:member:`~PyTypeObject.tp_free`. The object deallocator should be the one used to allocate the instance; this is normally :c:func:`PyObject_Del` if the instance was allocated @@ -677,7 +677,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:func:`PyObject_GC_Del` if the instance was allocated using :c:func:`PyObject_GC_New` or :c:func:`PyObject_GC_NewVar`. - If the type supports garbage collection (has the :const:`Py_TPFLAGS_HAVE_GC` + If the type supports garbage collection (has the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit set), the destructor should call :c:func:`PyObject_GC_UnTrack` before clearing any member fields. @@ -689,7 +689,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) Py_TYPE(self)->tp_free((PyObject *)self); } - Finally, if the type is heap allocated (:const:`Py_TPFLAGS_HEAPTYPE`), the + Finally, if the type is heap allocated (:c:macro:`Py_TPFLAGS_HEAPTYPE`), the deallocator should decrement the reference count for its type object after calling the type deallocator. In order to avoid dangling pointers, the recommended way to achieve this is: @@ -716,12 +716,12 @@ and :c:type:`PyType_Type` effectively act as defaults.) a more efficient alternative of the simpler :c:member:`~PyTypeObject.tp_call`. - This field is only used if the flag :const:`Py_TPFLAGS_HAVE_VECTORCALL` + This field is only used if the flag :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` is set. If so, this must be a positive integer containing the offset in the instance of a :c:type:`vectorcallfunc` pointer. The *vectorcallfunc* pointer may be ``NULL``, in which case the instance behaves - as if :const:`Py_TPFLAGS_HAVE_VECTORCALL` was not set: calling the instance + as if :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` was not set: calling the instance falls back to :c:member:`~PyTypeObject.tp_call`. Any class that sets ``Py_TPFLAGS_HAVE_VECTORCALL`` must also set @@ -743,12 +743,12 @@ and :c:type:`PyType_Type` effectively act as defaults.) When a user sets :attr:`~type.__call__` in Python code, only *tp_call* is updated, likely making it inconsistent with the vectorcall function. Since 3.12, setting ``__call__`` will disable vectorcall optimization - by clearing the :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag. + by clearing the :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag. **Inheritance:** This field is always inherited. - However, the :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is not + However, the :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag is not always inherited. If it's not set, then the subclass won't use :ref:`vectorcall `, except when :c:func:`PyVectorcall_Call` is explicitly called. @@ -1022,9 +1022,9 @@ and :c:type:`PyType_Type` effectively act as defaults.) this flag bit. The flag bits that pertain to extension structures are strictly inherited if the extension structure is inherited, i.e. the base type's value of the flag bit is copied into the subtype together with a pointer to the extension - structure. The :const:`Py_TPFLAGS_HAVE_GC` flag bit is inherited together with + structure. The :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is inherited together with the :c:member:`~PyTypeObject.tp_traverse` and :c:member:`~PyTypeObject.tp_clear` fields, i.e. if the - :const:`Py_TPFLAGS_HAVE_GC` flag bit is clear in the subtype and the + :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is clear in the subtype and the :c:member:`~PyTypeObject.tp_traverse` and :c:member:`~PyTypeObject.tp_clear` fields in the subtype exist and have ``NULL`` values. .. XXX are most flag bits *really* inherited individually? @@ -1036,12 +1036,14 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Bit Masks:** + .. c:namespace:: NULL + The following bit masks are currently defined; these can be ORed together using the ``|`` operator to form the value of the :c:member:`~PyTypeObject.tp_flags` field. The macro :c:func:`PyType_HasFeature` takes a type and a flags value, *tp* and *f*, and checks whether ``tp->tp_flags & f`` is non-zero. - .. data:: Py_TPFLAGS_HEAPTYPE + .. c:macro:: Py_TPFLAGS_HEAPTYPE This bit is set when the type object itself is allocated on the heap, for example, types created dynamically using :c:func:`PyType_FromSpec`. In this @@ -1056,7 +1058,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) ??? - .. data:: Py_TPFLAGS_BASETYPE + .. c:macro:: Py_TPFLAGS_BASETYPE This bit is set when the type can be used as the base type of another type. If this bit is clear, the type cannot be subtyped (similar to a "final" class in @@ -1067,7 +1069,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) ??? - .. data:: Py_TPFLAGS_READY + .. c:macro:: Py_TPFLAGS_READY This bit is set when the type object has been fully initialized by :c:func:`PyType_Ready`. @@ -1077,7 +1079,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) ??? - .. data:: Py_TPFLAGS_READYING + .. c:macro:: Py_TPFLAGS_READYING This bit is set while :c:func:`PyType_Ready` is in the process of initializing the type object. @@ -1087,7 +1089,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) ??? - .. data:: Py_TPFLAGS_HAVE_GC + .. c:macro:: Py_TPFLAGS_HAVE_GC This bit is set when the object supports garbage collection. If this bit is set, instances must be created using :c:func:`PyObject_GC_New` and @@ -1098,28 +1100,28 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :const:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` + Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` - The :const:`Py_TPFLAGS_HAVE_GC` flag bit is inherited + The :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is inherited together with the :attr:`tp_traverse` and :attr:`tp_clear` - fields, i.e. if the :const:`Py_TPFLAGS_HAVE_GC` flag bit is + fields, i.e. if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is clear in the subtype and the :attr:`tp_traverse` and :attr:`tp_clear` fields in the subtype exist and have ``NULL`` values. - .. data:: Py_TPFLAGS_DEFAULT + .. c:macro:: Py_TPFLAGS_DEFAULT This is a bitmask of all the bits that pertain to the existence of certain fields in the type object and its extension structures. Currently, it includes - the following bits: :const:`Py_TPFLAGS_HAVE_STACKLESS_EXTENSION`. + the following bits: :c:macro:`Py_TPFLAGS_HAVE_STACKLESS_EXTENSION`. **Inheritance:** ??? - .. data:: Py_TPFLAGS_METHOD_DESCRIPTOR + .. c:macro:: Py_TPFLAGS_METHOD_DESCRIPTOR This bit indicates that objects behave like unbound methods. @@ -1140,15 +1142,15 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Inheritance:** This flag is never inherited by types without the - :const:`Py_TPFLAGS_IMMUTABLETYPE` flag set. For extension types, it is + :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` flag set. For extension types, it is inherited whenever :c:member:`~PyTypeObject.tp_descr_get` is inherited. - .. data:: Py_TPFLAGS_MANAGED_DICT + .. c:macro:: Py_TPFLAGS_MANAGED_DICT This bit indicates that instances of the class have a ``__dict__`` attribute, and that the space for the dictionary is managed by the VM. - If this flag is set, :const:`Py_TPFLAGS_HAVE_GC` should also be set. + If this flag is set, :c:macro:`Py_TPFLAGS_HAVE_GC` should also be set. .. versionadded:: 3.12 @@ -1158,7 +1160,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:member:`~PyTypeObject.tp_dictoffset` field is set in a superclass. - .. data:: Py_TPFLAGS_MANAGED_WEAKREF + .. c:macro:: Py_TPFLAGS_MANAGED_WEAKREF This bit indicates that instances of the class should be weakly referenceable. @@ -1171,7 +1173,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:member:`~PyTypeObject.tp_weaklistoffset` field is set in a superclass. - .. data:: Py_TPFLAGS_ITEMS_AT_END + .. c:macro:: Py_TPFLAGS_ITEMS_AT_END Only usable with variable-size types, i.e. ones with non-zero :c:member:`~PyObject.tp_itemsize`. @@ -1194,14 +1196,14 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. XXX Document more flags here? - .. data:: Py_TPFLAGS_LONG_SUBCLASS - .. data:: Py_TPFLAGS_LIST_SUBCLASS - .. data:: Py_TPFLAGS_TUPLE_SUBCLASS - .. data:: Py_TPFLAGS_BYTES_SUBCLASS - .. data:: Py_TPFLAGS_UNICODE_SUBCLASS - .. data:: Py_TPFLAGS_DICT_SUBCLASS - .. data:: Py_TPFLAGS_BASE_EXC_SUBCLASS - .. data:: Py_TPFLAGS_TYPE_SUBCLASS + .. c:macro:: Py_TPFLAGS_LONG_SUBCLASS + .. c:macro:: Py_TPFLAGS_LIST_SUBCLASS + .. c:macro:: Py_TPFLAGS_TUPLE_SUBCLASS + .. c:macro:: Py_TPFLAGS_BYTES_SUBCLASS + .. c:macro:: Py_TPFLAGS_UNICODE_SUBCLASS + .. c:macro:: Py_TPFLAGS_DICT_SUBCLASS + .. c:macro:: Py_TPFLAGS_BASE_EXC_SUBCLASS + .. c:macro:: Py_TPFLAGS_TYPE_SUBCLASS These flags are used by functions such as :c:func:`PyLong_Check` to quickly determine if a type is a subclass @@ -1212,7 +1214,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) will behave differently depending on what kind of check is used. - .. data:: Py_TPFLAGS_HAVE_FINALIZE + .. c:macro:: Py_TPFLAGS_HAVE_FINALIZE This bit is set when the :c:member:`~PyTypeObject.tp_finalize` slot is present in the type structure. @@ -1225,7 +1227,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) type structure. - .. data:: Py_TPFLAGS_HAVE_VECTORCALL + .. c:macro:: Py_TPFLAGS_HAVE_VECTORCALL This bit is set when the class implements the :ref:`vectorcall protocol `. @@ -1245,7 +1247,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) This flag can now be inherited by mutable classes. - .. data:: Py_TPFLAGS_IMMUTABLETYPE + .. c:macro:: Py_TPFLAGS_IMMUTABLETYPE This bit is set for type objects that are immutable: type attributes cannot be set nor deleted. @@ -1258,7 +1260,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. versionadded:: 3.10 - .. data:: Py_TPFLAGS_DISALLOW_INSTANTIATION + .. c:macro:: Py_TPFLAGS_DISALLOW_INSTANTIATION Disallow creating instances of the type: set :c:member:`~PyTypeObject.tp_new` to NULL and don't create the ``__new__`` @@ -1289,7 +1291,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. versionadded:: 3.10 - .. data:: Py_TPFLAGS_MAPPING + .. c:macro:: Py_TPFLAGS_MAPPING This bit indicates that instances of the class may match mapping patterns when used as the subject of a :keyword:`match` block. It is automatically @@ -1298,20 +1300,20 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. note:: - :const:`Py_TPFLAGS_MAPPING` and :const:`Py_TPFLAGS_SEQUENCE` are + :c:macro:`Py_TPFLAGS_MAPPING` and :c:macro:`Py_TPFLAGS_SEQUENCE` are mutually exclusive; it is an error to enable both flags simultaneously. **Inheritance:** This flag is inherited by types that do not already set - :const:`Py_TPFLAGS_SEQUENCE`. + :c:macro:`Py_TPFLAGS_SEQUENCE`. .. seealso:: :pep:`634` -- Structural Pattern Matching: Specification .. versionadded:: 3.10 - .. data:: Py_TPFLAGS_SEQUENCE + .. c:macro:: Py_TPFLAGS_SEQUENCE This bit indicates that instances of the class may match sequence patterns when used as the subject of a :keyword:`match` block. It is automatically @@ -1320,20 +1322,20 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. note:: - :const:`Py_TPFLAGS_MAPPING` and :const:`Py_TPFLAGS_SEQUENCE` are + :c:macro:`Py_TPFLAGS_MAPPING` and :c:macro:`Py_TPFLAGS_SEQUENCE` are mutually exclusive; it is an error to enable both flags simultaneously. **Inheritance:** This flag is inherited by types that do not already set - :const:`Py_TPFLAGS_MAPPING`. + :c:macro:`Py_TPFLAGS_MAPPING`. .. seealso:: :pep:`634` -- Structural Pattern Matching: Specification .. versionadded:: 3.10 - .. data:: Py_TPFLAGS_VALID_VERSION_TAG + .. c:macro:: Py_TPFLAGS_VALID_VERSION_TAG Internal. Do not set or unset this flag. To indicate that a class has changed call :c:func:`PyType_Modified` @@ -1357,7 +1359,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: traverseproc PyTypeObject.tp_traverse An optional pointer to a traversal function for the garbage collector. This is - only used if the :const:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is:: + only used if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is:: int tp_traverse(PyObject *self, visitproc visit, void *arg); @@ -1419,10 +1421,10 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :const:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` + Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_clear` and the - :const:`Py_TPFLAGS_HAVE_GC` flag bit: the flag bit, :c:member:`~PyTypeObject.tp_traverse`, and + :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit: the flag bit, :c:member:`~PyTypeObject.tp_traverse`, and :c:member:`~PyTypeObject.tp_clear` are all inherited from the base type if they are all zero in the subtype. @@ -1430,7 +1432,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: inquiry PyTypeObject.tp_clear An optional pointer to a clear function for the garbage collector. This is only - used if the :const:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is:: + used if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is set. The signature is:: int tp_clear(PyObject *); @@ -1486,10 +1488,10 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :const:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` + Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_traverse` and the - :const:`Py_TPFLAGS_HAVE_GC` flag bit: the flag bit, :c:member:`~PyTypeObject.tp_traverse`, and + :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit: the flag bit, :c:member:`~PyTypeObject.tp_traverse`, and :c:member:`~PyTypeObject.tp_clear` are all inherited from the base type if they are all zero in the subtype. @@ -1511,21 +1513,21 @@ and :c:type:`PyType_Type` effectively act as defaults.) The following constants are defined to be used as the third argument for :c:member:`~PyTypeObject.tp_richcompare` and for :c:func:`PyObject_RichCompare`: - +----------------+------------+ - | Constant | Comparison | - +================+============+ - | :const:`Py_LT` | ``<`` | - +----------------+------------+ - | :const:`Py_LE` | ``<=`` | - +----------------+------------+ - | :const:`Py_EQ` | ``==`` | - +----------------+------------+ - | :const:`Py_NE` | ``!=`` | - +----------------+------------+ - | :const:`Py_GT` | ``>`` | - +----------------+------------+ - | :const:`Py_GE` | ``>=`` | - +----------------+------------+ + +------------------+------------+ + | Constant | Comparison | + +==================+============+ + | :c:macro:`Py_LT` | ``<`` | + +------------------+------------+ + | :c:macro:`Py_LE` | ``<=`` | + +------------------+------------+ + | :c:macro:`Py_EQ` | ``==`` | + +------------------+------------+ + | :c:macro:`Py_NE` | ``!=`` | + +------------------+------------+ + | :c:macro:`Py_GT` | ``>`` | + +------------------+------------+ + | :c:macro:`Py_GE` | ``>=`` | + +------------------+------------+ The following macro is defined to ease writing rich comparison functions: @@ -1563,7 +1565,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: Py_ssize_t PyTypeObject.tp_weaklistoffset - While this field is still supported, :const:`Py_TPFLAGS_MANAGED_WEAKREF` + While this field is still supported, :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` should be used instead, if at all possible. If the instances of this type are weakly referenceable, this field is greater @@ -1576,7 +1578,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) Do not confuse this field with :c:member:`~PyTypeObject.tp_weaklist`; that is the list head for weak references to the type object itself. - It is an error to set both the :const:`Py_TPFLAGS_MANAGED_WEAKREF` bit and + It is an error to set both the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit and :c:member:`~PyTypeObject.tp_weaklist`. **Inheritance:** @@ -1588,7 +1590,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Default:** - If the :const:`Py_TPFLAGS_MANAGED_WEAKREF` bit is set in the + If the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit is set in the :c:member:`~PyTypeObject.tp_dict` field, then :c:member:`~PyTypeObject.tp_weaklistoffset` will be set to a negative value, to indicate that it is unsafe to use this field. @@ -1782,7 +1784,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: Py_ssize_t PyTypeObject.tp_dictoffset - While this field is still supported, :const:`Py_TPFLAGS_MANAGED_DICT` should be + While this field is still supported, :c:macro:`Py_TPFLAGS_MANAGED_DICT` should be used instead, if at all possible. If the instances of this type have a dictionary containing instance variables, @@ -1801,7 +1803,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) dictionary, so it is may be more efficient to call :c:func:`PyObject_GetAttr` when accessing an attribute on the object. - It is an error to set both the :const:`Py_TPFLAGS_MANAGED_WEAKREF` bit and + It is an error to set both the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit and :c:member:`~PyTypeObject.tp_dictoffset`. **Inheritance:** @@ -1809,14 +1811,14 @@ and :c:type:`PyType_Type` effectively act as defaults.) This field is inherited by subtypes. A subtype should not override this offset; doing so could be unsafe, if C code tries to access the dictionary at the previous offset. - To properly support inheritance, use :const:`Py_TPFLAGS_MANAGED_DICT`. + To properly support inheritance, use :c:macro:`Py_TPFLAGS_MANAGED_DICT`. **Default:** This slot has no default. For :ref:`static types `, if the field is ``NULL`` then no :attr:`__dict__` gets created for instances. - If the :const:`Py_TPFLAGS_MANAGED_DICT` bit is set in the + If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the :c:member:`~PyTypeObject.tp_dict` field, then :c:member:`~PyTypeObject.tp_dictoffset` will be set to ``-1``, to indicate that it is unsafe to use this field. @@ -1903,7 +1905,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) in :c:member:`~PyTypeObject.tp_new`, while for mutable types, most initialization should be deferred to :c:member:`~PyTypeObject.tp_init`. - Set the :const:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag to disallow creating + Set the :c:macro:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag to disallow creating instances of the type in Python. **Inheritance:** @@ -1937,7 +1939,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) In dynamic subtypes, this field is set to a deallocator suitable to match :c:func:`PyType_GenericAlloc` and the value of the - :const:`Py_TPFLAGS_HAVE_GC` flag bit. + :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit. For static subtypes, :c:type:`PyBaseObject_Type` uses PyObject_Del. @@ -1948,7 +1950,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) The garbage collector needs to know whether a particular object is collectible or not. Normally, it is sufficient to look at the object's type's - :c:member:`~PyTypeObject.tp_flags` field, and check the :const:`Py_TPFLAGS_HAVE_GC` flag bit. But + :c:member:`~PyTypeObject.tp_flags` field, and check the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit. But some types have a mixture of statically and dynamically allocated instances, and the statically allocated instances are not collectible. Such types should define this function; it should return ``1`` for a collectible instance, and @@ -1967,7 +1969,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Default:** This slot has no default. If this field is ``NULL``, - :const:`Py_TPFLAGS_HAVE_GC` is used as the functional equivalent. + :c:macro:`Py_TPFLAGS_HAVE_GC` is used as the functional equivalent. .. c:member:: PyObject* PyTypeObject.tp_bases @@ -2114,7 +2116,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. versionchanged:: 3.8 Before version 3.8 it was necessary to set the - :const:`Py_TPFLAGS_HAVE_FINALIZE` flags bit in order for this field to be + :c:macro:`Py_TPFLAGS_HAVE_FINALIZE` flags bit in order for this field to be used. This is no longer required. .. seealso:: "Safe object finalization" (:pep:`442`) @@ -2173,7 +2175,7 @@ Heap Types An alternative to :ref:`static types ` is *heap-allocated types*, or *heap types* for short, which correspond closely to classes created by -Python's ``class`` statement. Heap types have the :const:`Py_TPFLAGS_HEAPTYPE` +Python's ``class`` statement. Heap types have the :c:macro:`Py_TPFLAGS_HEAPTYPE` flag set. This is done by filling a :c:type:`PyType_Spec` structure and calling @@ -2781,7 +2783,7 @@ A type that supports weakrefs, instance dicts, and hashing:: A str subclass that cannot be subclassed and cannot be called to create instances (e.g. uses a separate factory func) using -:c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag:: +:c:macro:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag:: typedef struct { PyUnicodeObject raw; diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 33437b6193919a..8a989c2afe871c 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1299,7 +1299,7 @@ the user settings on the machine running the codec. Encode the Unicode object using the specified code page and return a Python bytes object. Return ``NULL`` if an exception was raised by the codec. Use - :c:data:`CP_ACP` code page to get the MBCS encoder. + :c:macro:`CP_ACP` code page to get the MBCS encoder. .. versionadded:: 3.3 @@ -1418,11 +1418,11 @@ They all return ``NULL`` or ``-1`` if an exception occurs. Rich compare two Unicode strings and return one of the following: * ``NULL`` in case an exception was raised - * :const:`Py_True` or :const:`Py_False` for successful comparisons - * :const:`Py_NotImplemented` in case the type combination is unknown + * :c:data:`Py_True` or :c:data:`Py_False` for successful comparisons + * :c:data:`Py_NotImplemented` in case the type combination is unknown - Possible values for *op* are :const:`Py_GT`, :const:`Py_GE`, :const:`Py_EQ`, - :const:`Py_NE`, :const:`Py_LT`, and :const:`Py_LE`. + Possible values for *op* are :c:macro:`Py_GT`, :c:macro:`Py_GE`, :c:macro:`Py_EQ`, + :c:macro:`Py_NE`, :c:macro:`Py_LT`, and :c:macro:`Py_LE`. .. c:function:: PyObject* PyUnicode_Format(PyObject *format, PyObject *args) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 000a2d3d8790bb..1e8a945512d78c 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -12,8 +12,8 @@ file or a buffer, but they will not let you interact in a more detailed way with the interpreter. Several of these functions accept a start symbol from the grammar as a -parameter. The available start symbols are :const:`Py_eval_input`, -:const:`Py_file_input`, and :const:`Py_single_input`. These are described +parameter. The available start symbols are :c:data:`Py_eval_input`, +:c:data:`Py_file_input`, and :c:data:`Py_single_input`. These are described following the functions which accept them as parameters. Note also that several of these functions take :c:expr:`FILE*` parameters. One @@ -256,8 +256,8 @@ the same library that the Python runtime is using. Parse and compile the Python source code in *str*, returning the resulting code object. The start token is given by *start*; this can be used to constrain the - code which can be compiled and should be :const:`Py_eval_input`, - :const:`Py_file_input`, or :const:`Py_single_input`. The filename specified by + code which can be compiled and should be :c:data:`Py_eval_input`, + :c:data:`Py_file_input`, or :c:data:`Py_single_input`. The filename specified by *filename* is used to construct the code object and may appear in tracebacks or :exc:`SyntaxError` exception messages. This returns ``NULL`` if the code cannot be parsed or compiled. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index d9bf4fd6c7ae0e..76e0490d0d22df 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -335,7 +335,7 @@ When using only ``METH_VARARGS``, the function should expect the Python-level parameters to be passed in as a tuple acceptable for parsing via :c:func:`PyArg_ParseTuple`; more information on this function is provided below. -The :const:`METH_KEYWORDS` bit may be set in the third field if keyword +The :c:macro:`METH_KEYWORDS` bit may be set in the third field if keyword arguments should be passed to the function. In this case, the C function should accept a third ``PyObject *`` parameter which will be a dictionary of keywords. Use :c:func:`PyArg_ParseTupleAndKeywords` to parse the arguments to such a @@ -527,7 +527,7 @@ be part of a module definition:: } This function must be registered with the interpreter using the -:const:`METH_VARARGS` flag; this is described in section :ref:`methodtable`. The +:c:macro:`METH_VARARGS` flag; this is described in section :ref:`methodtable`. The :c:func:`PyArg_ParseTuple` function and its arguments are documented in section :ref:`parsetuple`. diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index f89934a11f12a8..ba09fb1b05c0bf 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -151,7 +151,7 @@ only used for variable-sized objects and should otherwise be zero. base type will be :class:`object`, or else you will be adding data members to your base type, and therefore increasing its size. -We set the class flags to :const:`Py_TPFLAGS_DEFAULT`. :: +We set the class flags to :c:macro:`Py_TPFLAGS_DEFAULT`. :: .tp_flags = Py_TPFLAGS_DEFAULT, @@ -498,7 +498,7 @@ definitions:: {NULL} /* Sentinel */ }; -(note that we used the :const:`METH_NOARGS` flag to indicate that the method +(note that we used the :c:macro:`METH_NOARGS` flag to indicate that the method is expecting no arguments other than *self*) and assign it to the :c:member:`~PyTypeObject.tp_methods` slot:: @@ -508,7 +508,7 @@ and assign it to the :c:member:`~PyTypeObject.tp_methods` slot:: Finally, we'll make our type usable as a base class for subclassing. We've written our methods carefully so far so that they don't make any assumptions about the type of the object being created or used, so all we need to do is -to add the :const:`Py_TPFLAGS_BASETYPE` to our class flag definition:: +to add the :c:macro:`Py_TPFLAGS_BASETYPE` to our class flag definition:: .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, @@ -774,7 +774,7 @@ and ``Custom_clear``:: Py_TYPE(self)->tp_free((PyObject *) self); } -Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: +Finally, we add the :c:macro:`Py_TPFLAGS_HAVE_GC` flag to the class flags:: .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 8adb85f3a87401..f01801ea47212c 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -298,10 +298,10 @@ Watch out for the following two points in particular (but note that this is not a comprehensive list): * Unlike static types, heap type objects are mutable by default. - Use the :c:data:`Py_TPFLAGS_IMMUTABLETYPE` flag to prevent mutability. + Use the :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` flag to prevent mutability. * Heap types inherit :c:member:`~PyTypeObject.tp_new` by default, so it may become possible to instantiate them from Python code. - You can prevent this with the :c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag. + You can prevent this with the :c:macro:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag. Defining Heap Types @@ -333,12 +333,12 @@ To avoid memory leaks, instances of heap types must implement the garbage collection protocol. That is, heap types should: -- Have the :c:data:`Py_TPFLAGS_HAVE_GC` flag. +- Have the :c:macro:`Py_TPFLAGS_HAVE_GC` flag. - Define a traverse function using ``Py_tp_traverse``, which visits the type (e.g. using :c:expr:`Py_VISIT(Py_TYPE(self))`). Please refer to the :ref:`the documentation ` of -:c:data:`Py_TPFLAGS_HAVE_GC` and :c:member:`~PyTypeObject.tp_traverse` +:c:macro:`Py_TPFLAGS_HAVE_GC` and :c:member:`~PyTypeObject.tp_traverse` for additional considerations. If your traverse function delegates to the ``tp_traverse`` of its base class @@ -411,7 +411,7 @@ that subclass, which may be defined in different module than yours. pass For a method to get its "defining class", it must use the -:data:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS` +:ref:`METH_METHOD | METH_FASTCALL | METH_KEYWORDS ` :c:type:`calling convention ` and the corresponding :c:type:`PyCMethod` signature:: diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 3b31384edeb54b..97d5121c4e8a5e 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -818,7 +818,7 @@ iterations of the loop. .. opcode:: MATCH_MAPPING If ``STACK[-1]`` is an instance of :class:`collections.abc.Mapping` (or, more - technically: if it has the :const:`Py_TPFLAGS_MAPPING` flag set in its + technically: if it has the :c:macro:`Py_TPFLAGS_MAPPING` flag set in its :c:member:`~PyTypeObject.tp_flags`), push ``True`` onto the stack. Otherwise, push ``False``. @@ -829,7 +829,7 @@ iterations of the loop. If ``STACK[-1]`` is an instance of :class:`collections.abc.Sequence` and is *not* an instance of :class:`str`/:class:`bytes`/:class:`bytearray` (or, more technically: if it has - the :const:`Py_TPFLAGS_SEQUENCE` flag set in its :c:member:`~PyTypeObject.tp_flags`), + the :c:macro:`Py_TPFLAGS_SEQUENCE` flag set in its :c:member:`~PyTypeObject.tp_flags`), push ``True`` onto the stack. Otherwise, push ``False``. .. versionadded:: 3.10 diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 83abb5d5ca1e42..b35010498f2143 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -4308,7 +4308,7 @@ written in Python, such as a mail server's external command delivery program. specified. If the value specified is 0, the child's process group ID will be made the same as its process ID. If the value of *setpgroup* is not set, the child will inherit the parent's process group ID. This argument corresponds - to the C library :c:data:`POSIX_SPAWN_SETPGROUP` flag. + to the C library :c:macro:`POSIX_SPAWN_SETPGROUP` flag. If the *resetids* argument is ``True`` it will reset the effective UID and GID of the child to the real UID and GID of the parent process. If the @@ -4316,27 +4316,27 @@ written in Python, such as a mail server's external command delivery program. the parent. In either case, if the set-user-ID and set-group-ID permission bits are enabled on the executable file, their effect will override the setting of the effective UID and GID. This argument corresponds to the C - library :c:data:`POSIX_SPAWN_RESETIDS` flag. + library :c:macro:`POSIX_SPAWN_RESETIDS` flag. If the *setsid* argument is ``True``, it will create a new session ID - for ``posix_spawn``. *setsid* requires :c:data:`POSIX_SPAWN_SETSID` - or :c:data:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError` + for ``posix_spawn``. *setsid* requires :c:macro:`POSIX_SPAWN_SETSID` + or :c:macro:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError` is raised. The *setsigmask* argument will set the signal mask to the signal set specified. If the parameter is not used, then the child inherits the parent's signal mask. This argument corresponds to the C library - :c:data:`POSIX_SPAWN_SETSIGMASK` flag. + :c:macro:`POSIX_SPAWN_SETSIGMASK` flag. The *sigdef* argument will reset the disposition of all signals in the set specified. This argument corresponds to the C library - :c:data:`POSIX_SPAWN_SETSIGDEF` flag. + :c:macro:`POSIX_SPAWN_SETSIGDEF` flag. The *scheduler* argument must be a tuple containing the (optional) scheduler policy and an instance of :class:`sched_param` with the scheduler parameters. A value of ``None`` in the place of the scheduler policy indicates that is not being provided. This argument is a combination of the C library - :c:data:`POSIX_SPAWN_SETSCHEDPARAM` and :c:data:`POSIX_SPAWN_SETSCHEDULER` + :c:macro:`POSIX_SPAWN_SETSCHEDPARAM` and :c:macro:`POSIX_SPAWN_SETSCHEDULER` flags. .. audit-event:: os.posix_spawn path,argv,env os.posix_spawn diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 6d30eccab1990f..12ad18d4119617 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -1840,7 +1840,7 @@ like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime. * a class that inherits from :class:`collections.abc.Sequence` * a Python class that has been registered as :class:`collections.abc.Sequence` - * a builtin class that has its (CPython) :data:`Py_TPFLAGS_SEQUENCE` bit set + * a builtin class that has its (CPython) :c:macro:`Py_TPFLAGS_SEQUENCE` bit set * a class that inherits from any of the above The following standard library classes are sequences: @@ -1859,7 +1859,7 @@ like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime. * a class that inherits from :class:`collections.abc.Mapping` * a Python class that has been registered as :class:`collections.abc.Mapping` - * a builtin class that has its (CPython) :data:`Py_TPFLAGS_MAPPING` bit set + * a builtin class that has its (CPython) :c:macro:`Py_TPFLAGS_MAPPING` bit set * a class that inherits from any of the above The standard library classes :class:`dict` and :class:`types.MappingProxyType` diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 1b470d395d6d58..4bf67eb439ec6c 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -897,11 +897,11 @@ conflict. * ``default``: use the :ref:`default memory allocators `. * ``malloc``: use the :c:func:`malloc` function of the C library - for all domains (:c:data:`PYMEM_DOMAIN_RAW`, :c:data:`PYMEM_DOMAIN_MEM`, - :c:data:`PYMEM_DOMAIN_OBJ`). + for all domains (:c:macro:`PYMEM_DOMAIN_RAW`, :c:macro:`PYMEM_DOMAIN_MEM`, + :c:macro:`PYMEM_DOMAIN_OBJ`). * ``pymalloc``: use the :ref:`pymalloc allocator ` for - :c:data:`PYMEM_DOMAIN_MEM` and :c:data:`PYMEM_DOMAIN_OBJ` domains and use - the :c:func:`malloc` function for the :c:data:`PYMEM_DOMAIN_RAW` domain. + :c:macro:`PYMEM_DOMAIN_MEM` and :c:macro:`PYMEM_DOMAIN_OBJ` domains and use + the :c:func:`malloc` function for the :c:macro:`PYMEM_DOMAIN_RAW` domain. Install :ref:`debug hooks `: diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 82aff0be1ed3b3..44e9bd8d492bfc 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -1105,11 +1105,11 @@ code, none of the changes described here will affect you very much. expected, and a set of pointers to :c:expr:`PyObject*` variables that will be filled in with argument values. -* Two new flags :const:`METH_NOARGS` and :const:`METH_O` are available in method +* Two new flags :c:macro:`METH_NOARGS` and :c:macro:`METH_O` are available in method definition tables to simplify implementation of methods with no arguments or a single untyped argument. Calling such methods is more efficient than calling a - corresponding method that uses :const:`METH_VARARGS`. Also, the old - :const:`METH_OLDARGS` style of writing C methods is now officially deprecated. + corresponding method that uses :c:macro:`METH_VARARGS`. Also, the old + :c:macro:`METH_OLDARGS` style of writing C methods is now officially deprecated. * Two new wrapper functions, :c:func:`PyOS_snprintf` and :c:func:`PyOS_vsnprintf` were added to provide cross-platform implementations for the relatively new diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index 4eb864f5092d30..14f951174ba545 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1474,7 +1474,7 @@ complete list of changes, or look through the CVS logs for all the details. * On Windows, the :mod:`socket` module now ships with Secure Sockets Layer (SSL) support. -* The value of the C :const:`PYTHON_API_VERSION` macro is now exposed at the +* The value of the C :c:macro:`PYTHON_API_VERSION` macro is now exposed at the Python level as ``sys.api_version``. The current exception can be cleared by calling the new :func:`sys.exc_clear` function. @@ -1899,10 +1899,10 @@ Changes to Python's build process and to the C API include: * The :c:func:`PyArg_NoArgs` macro is now deprecated, and code that uses it should be changed. For Python 2.2 and later, the method definition table can - specify the :const:`METH_NOARGS` flag, signalling that there are no arguments, + specify the :c:macro:`METH_NOARGS` flag, signalling that there are no arguments, and the argument checking can then be removed. If compatibility with pre-2.2 versions of Python is important, the code could use ``PyArg_ParseTuple(args, - "")`` instead, but this will be slower than using :const:`METH_NOARGS`. + "")`` instead, but this will be slower than using :c:macro:`METH_NOARGS`. * :c:func:`PyArg_ParseTuple` accepts new format characters for various sizes of unsigned integers: ``B`` for :c:expr:`unsigned char`, ``H`` for :c:expr:`unsigned @@ -1918,7 +1918,7 @@ Changes to Python's build process and to the C API include: seconds, according to one measurement). * It's now possible to define class and static methods for a C extension type by - setting either the :const:`METH_CLASS` or :const:`METH_STATIC` flags in a + setting either the :c:macro:`METH_CLASS` or :c:macro:`METH_STATIC` flags in a method's :c:type:`PyMethodDef` structure. * Python now includes a copy of the Expat XML parser's source code, removing any diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 98dc83fe935d5e..d68f600ba44f65 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1476,7 +1476,7 @@ Some of the changes to Python's build process and to the C API are: :c:func:`PyArg_ParseTupleAndKeywords` but takes a :c:type:`va_list` instead of a number of arguments. (Contributed by Greg Chapman.) -* A new method flag, :const:`METH_COEXISTS`, allows a function defined in slots +* A new method flag, :c:macro:`METH_COEXISTS`, allows a function defined in slots to co-exist with a :c:type:`PyCFunction` having the same name. This can halve the access time for a method such as :meth:`set.__contains__`. (Contributed by Raymond Hettinger.) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 84bb651e68eed5..72a273fdd8d122 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1138,11 +1138,11 @@ indicate that the external caller is done. The *flags* argument to :c:func:`PyObject_GetBuffer` specifies constraints upon the memory returned. Some examples are: - * :const:`PyBUF_WRITABLE` indicates that the memory must be writable. + * :c:macro:`PyBUF_WRITABLE` indicates that the memory must be writable. - * :const:`PyBUF_LOCK` requests a read-only or exclusive lock on the memory. + * :c:macro:`PyBUF_LOCK` requests a read-only or exclusive lock on the memory. - * :const:`PyBUF_C_CONTIGUOUS` and :const:`PyBUF_F_CONTIGUOUS` + * :c:macro:`PyBUF_C_CONTIGUOUS` and :c:macro:`PyBUF_F_CONTIGUOUS` requests a C-contiguous (last dimension varies the fastest) or Fortran-contiguous (first dimension varies the fastest) array layout. diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 36afcb163f1afc..e6bc9a21b365d4 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2231,7 +2231,7 @@ Changes to Python's build process and to the C API include: * When using the :c:type:`PyMemberDef` structure to define attributes of a type, Python will no longer let you try to delete or set a - :const:`T_STRING_INPLACE` attribute. + :c:macro:`T_STRING_INPLACE` attribute. .. rev 79644 diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 661eeaedbfc0d0..7f80852c49548f 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -2124,11 +2124,11 @@ New Features These functions allow to activate, deactivate and query the state of the garbage collector from C code without having to import the :mod:`gc` module. -* Add a new :c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` type flag to disallow +* Add a new :c:macro:`Py_TPFLAGS_DISALLOW_INSTANTIATION` type flag to disallow creating type instances. (Contributed by Victor Stinner in :issue:`43916`.) -* Add a new :c:data:`Py_TPFLAGS_IMMUTABLETYPE` type flag for creating immutable +* Add a new :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` type flag for creating immutable type objects: type attributes cannot be set nor deleted. (Contributed by Victor Stinner and Erlend E. Aasland in :issue:`43908`.) @@ -2187,9 +2187,9 @@ Porting to Python 3.10 been included directly, consider including ``Python.h`` instead. (Contributed by Nicholas Sim in :issue:`35134`.) -* Use the :c:data:`Py_TPFLAGS_IMMUTABLETYPE` type flag to create immutable type - objects. Do not rely on :c:data:`Py_TPFLAGS_HEAPTYPE` to decide if a type - object is mutable or not; check if :c:data:`Py_TPFLAGS_IMMUTABLETYPE` is set +* Use the :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` type flag to create immutable type + objects. Do not rely on :c:macro:`Py_TPFLAGS_HEAPTYPE` to decide if a type + object is mutable or not; check if :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` is set instead. (Contributed by Victor Stinner and Erlend E. Aasland in :issue:`43908`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index c06ce783689857..5ff99fc2d3f616 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2347,11 +2347,11 @@ Porting to Python 3.11 #endif * The :c:func:`PyType_Ready` function now raises an error if a type is defined - with the :const:`Py_TPFLAGS_HAVE_GC` flag set but has no traverse function + with the :c:macro:`Py_TPFLAGS_HAVE_GC` flag set but has no traverse function (:c:member:`PyTypeObject.tp_traverse`). (Contributed by Victor Stinner in :issue:`44263`.) -* Heap types with the :const:`Py_TPFLAGS_IMMUTABLETYPE` flag can now inherit +* Heap types with the :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` flag can now inherit the :pep:`590` vectorcall protocol. Previously, this was only possible for :ref:`static types `. (Contributed by Erlend E. Aasland in :issue:`43908`) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 068618fe48e1b0..03d559e4553930 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1110,7 +1110,7 @@ Pending Removal in Python 3.14 * :class:`typing.ByteString`, deprecated since Python 3.9, now causes a :exc:`DeprecationWarning` to be emitted when it is used. -* Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable +* Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases using the C API. * Deprecated the *isdst* parameter in :func:`email.utils.localtime`. @@ -1621,7 +1621,7 @@ New Features inheriting or extending the base class size. - :c:func:`PyObject_GetTypeData` and :c:func:`PyType_GetTypeDataSize` added to allow access to subclass-specific instance data. - - :const:`Py_TPFLAGS_ITEMS_AT_END` and :c:func:`PyObject_GetItemData` + - :c:macro:`Py_TPFLAGS_ITEMS_AT_END` and :c:func:`PyObject_GetItemData` added to allow safely extending certain variable-sized types, including :c:var:`PyType_Type`. - :c:macro:`Py_RELATIVE_OFFSET` added to allow defining @@ -1638,20 +1638,20 @@ New Features :ref:`the vectorcall protocol ` was added to the :ref:`Limited API `: - * :const:`Py_TPFLAGS_HAVE_VECTORCALL` + * :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` * :c:func:`PyVectorcall_NARGS` * :c:func:`PyVectorcall_Call` * :c:type:`vectorcallfunc` - The :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class + The :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class when the class's :py:meth:`~object.__call__` method is reassigned. This makes vectorcall safe to use with mutable types (i.e. heap types - without the immutable flag, :const:`Py_TPFLAGS_IMMUTABLETYPE`). + without the immutable flag, :c:macro:`Py_TPFLAGS_IMMUTABLETYPE`). Mutable types that do not override :c:member:`~PyTypeObject.tp_call` now inherit the ``Py_TPFLAGS_HAVE_VECTORCALL`` flag. (Contributed by Petr Viktorin in :gh:`93274`.) - The :const:`Py_TPFLAGS_MANAGED_DICT` and :const:`Py_TPFLAGS_MANAGED_WEAKREF` + The :c:macro:`Py_TPFLAGS_MANAGED_DICT` and :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` flags have been added. This allows extensions classes to support object ``__dict__`` and weakrefs with less bookkeeping, using less memory and with faster access. @@ -1662,7 +1662,7 @@ New Features * :c:func:`PyObject_Vectorcall` * :c:func:`PyObject_VectorcallMethod` - * :const:`PY_VECTORCALL_ARGUMENTS_OFFSET` + * :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET` This means that both the incoming and outgoing ends of the vector call protocol are now available in the :ref:`Limited API `. (Contributed @@ -1784,13 +1784,13 @@ Porting to Python 3.12 (Contributed by Philip Georgi in :gh:`95504`.) * Extension classes wanting to add a ``__dict__`` or weak reference slot - should use :const:`Py_TPFLAGS_MANAGED_DICT` and - :const:`Py_TPFLAGS_MANAGED_WEAKREF` instead of ``tp_dictoffset`` and + should use :c:macro:`Py_TPFLAGS_MANAGED_DICT` and + :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead of ``tp_dictoffset`` and ``tp_weaklistoffset``, respectively. The use of ``tp_dictoffset`` and ``tp_weaklistoffset`` is still supported, but does not fully support multiple inheritance (:gh:`95589`), and performance may be worse. - Classes declaring :const:`Py_TPFLAGS_MANAGED_DICT` should call + Classes declaring :c:macro:`Py_TPFLAGS_MANAGED_DICT` should call :c:func:`!_PyObject_VisitManagedDict` and :c:func:`!_PyObject_ClearManagedDict` to traverse and clear their instance's dictionaries. To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before. @@ -1844,7 +1844,7 @@ Porting to Python 3.12 :c:member:`~PyTypeObject.tp_init` instead. - If the metaclass doesn't need to be instantiated from Python, set its ``tp_new`` to ``NULL`` using - the :const:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag. + the :c:macro:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag. This makes it acceptable for ``PyType_From*`` functions. - Avoid ``PyType_From*`` functions: if you don't need C-specific features @@ -1895,7 +1895,7 @@ Deprecated :c:type:`PyConfig` instead. (Contributed by Victor Stinner in :gh:`77782`.) -* Creating immutable types (:const:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable +* Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases is deprecated and will be disabled in Python 3.14. * The ``structmember.h`` header is deprecated, though it continues to be diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 3a681754e25dd7..07a65d264c4359 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -650,8 +650,8 @@ compiled in release mode using ``PYTHONMALLOC=debug``. Effects of debug hooks: * Detect writes before the start of a buffer (buffer underflows) * Detect writes after the end of a buffer (buffer overflows) * Check that the :term:`GIL ` is held when allocator - functions of :c:data:`PYMEM_DOMAIN_OBJ` (ex: :c:func:`PyObject_Malloc`) and - :c:data:`PYMEM_DOMAIN_MEM` (ex: :c:func:`PyMem_Malloc`) domains are called. + functions of :c:macro:`PYMEM_DOMAIN_OBJ` (ex: :c:func:`PyObject_Malloc`) and + :c:macro:`PYMEM_DOMAIN_MEM` (ex: :c:func:`PyMem_Malloc`) domains are called. Checking if the GIL is held is also a new feature of Python 3.6. @@ -1822,7 +1822,7 @@ Optimizations up to 80% faster. (Contributed by Josh Snider in :issue:`26574`). * Allocator functions of the :c:func:`PyMem_Malloc` domain - (:c:data:`PYMEM_DOMAIN_MEM`) now use the :ref:`pymalloc memory allocator + (:c:macro:`PYMEM_DOMAIN_MEM`) now use the :ref:`pymalloc memory allocator ` instead of :c:func:`malloc` function of the C library. The pymalloc allocator is optimized for objects smaller or equal to 512 bytes with a short lifetime, and use :c:func:`malloc` for larger memory blocks. @@ -1874,8 +1874,8 @@ Build and C API Changes (Original patch by Alecsandru Patrascu of Intel in :issue:`26359`.) * The :term:`GIL ` must now be held when allocator - functions of :c:data:`PYMEM_DOMAIN_OBJ` (ex: :c:func:`PyObject_Malloc`) and - :c:data:`PYMEM_DOMAIN_MEM` (ex: :c:func:`PyMem_Malloc`) domains are called. + functions of :c:macro:`PYMEM_DOMAIN_OBJ` (ex: :c:func:`PyObject_Malloc`) and + :c:macro:`PYMEM_DOMAIN_MEM` (ex: :c:func:`PyMem_Malloc`) domains are called. * New :c:func:`Py_FinalizeEx` API which indicates if flushing buffered data failed. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 85e088b64acb2d..61249d479fa044 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2116,7 +2116,7 @@ Changes in the C API extension types across feature releases, anymore. A :c:type:`PyTypeObject` exported by a third-party extension module is supposed to have all the slots expected in the current Python version, including - :c:member:`~PyTypeObject.tp_finalize` (:const:`Py_TPFLAGS_HAVE_FINALIZE` + :c:member:`~PyTypeObject.tp_finalize` (:c:macro:`Py_TPFLAGS_HAVE_FINALIZE` is not checked anymore before reading :c:member:`~PyTypeObject.tp_finalize`). (Contributed by Antoine Pitrou in :issue:`32388`.) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index fd86db96302356..49c8bd2f3e07d5 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1276,7 +1276,7 @@ New Features * :pep:`573`: Added :c:func:`PyType_FromModuleAndSpec` to associate a module with a class; :c:func:`PyType_GetModule` and :c:func:`PyType_GetModuleState` to retrieve the module and its state; and - :c:data:`PyCMethod` and :c:data:`METH_METHOD` to allow a method to + :c:data:`PyCMethod` and :c:macro:`METH_METHOD` to allow a method to access the class it was defined in. (Contributed by Marcel Plch and Petr Viktorin in :issue:`38787`.) diff --git a/Misc/NEWS.d/3.10.0a3.rst b/Misc/NEWS.d/3.10.0a3.rst index 699a0dd9e8d7c4..70b79f5f250a18 100644 --- a/Misc/NEWS.d/3.10.0a3.rst +++ b/Misc/NEWS.d/3.10.0a3.rst @@ -1466,7 +1466,7 @@ success. Patch by Victor Stinner. .. nonce: S3FWTP .. section: C API -The :c:data:`METH_FASTCALL` calling convention is added to the limited API. +The :c:macro:`METH_FASTCALL` calling convention is added to the limited API. The functions :c:func:`PyModule_AddType`, :c:func:`PyType_FromModuleAndSpec`, :c:func:`PyType_GetModule` and :c:func:`PyType_GetModuleState` are added to the limited API on Windows. diff --git a/Misc/NEWS.d/3.10.0b1.rst b/Misc/NEWS.d/3.10.0b1.rst index f29fc6632db26c..38e0af17a2c66b 100644 --- a/Misc/NEWS.d/3.10.0b1.rst +++ b/Misc/NEWS.d/3.10.0b1.rst @@ -1375,8 +1375,8 @@ Add "Annotations Best Practices" document as a new HOWTO. .. nonce: K5aSl1 .. section: Documentation -Document the new :const:`Py_TPFLAGS_MAPPING` and -:const:`Py_TPFLAGS_SEQUENCE` type flags. +Document the new :c:macro:`Py_TPFLAGS_MAPPING` and +:c:macro:`Py_TPFLAGS_SEQUENCE` type flags. .. @@ -1711,7 +1711,7 @@ IDLE's shell now shows prompts in a separate side-bar. .. nonce: wvWt23 .. section: C API -Add a new :c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` type flag to disallow +Add a new :c:macro:`Py_TPFLAGS_DISALLOW_INSTANTIATION` type flag to disallow creating type instances. Patch by Victor Stinner. .. @@ -1759,7 +1759,7 @@ module. .. nonce: Co3YhZ .. section: C API -Introduce :const:`Py_TPFLAGS_IMMUTABLETYPE` flag for immutable type objects, +Introduce :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` flag for immutable type objects, and modify :c:func:`PyType_Ready` to set it for static types. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index 447d5c0e7d9032..fb60ac55601022 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -888,7 +888,7 @@ zlib.decompress on input data that expands that large. .. nonce: YHuV_s .. section: Core and Builtins -Heap types with the :const:`Py_TPFLAGS_IMMUTABLETYPE` flag can now inherit +Heap types with the :c:macro:`Py_TPFLAGS_IMMUTABLETYPE` flag can now inherit the :pep:`590` vectorcall protocol. Previously, this was only possible for :ref:`static types `. Patch by Erlend E. Aasland. @@ -2575,7 +2575,7 @@ E. Aasland. .. nonce: bamAGF .. section: Library -Set the proper :const:`Py_TPFLAGS_MAPPING` and :const:`Py_TPFLAGS_SEQUENCE` +Set the proper :c:macro:`Py_TPFLAGS_MAPPING` and :c:macro:`Py_TPFLAGS_SEQUENCE` flags for subclasses created before a parent has been registered as a :class:`collections.abc.Mapping` or :class:`collections.abc.Sequence`. @@ -2693,7 +2693,7 @@ libgcc_s.so file (ex: EMFILE error). Patch by Victor Stinner. .. section: Library The _thread.RLock type now fully implement the GC protocol: add a traverse -function and the :const:`Py_TPFLAGS_HAVE_GC` flag. Patch by Victor Stinner. +function and the :c:macro:`Py_TPFLAGS_HAVE_GC` flag. Patch by Victor Stinner. .. @@ -5014,7 +5014,7 @@ must now be used to set an object type and size. Patch by Victor Stinner. .. section: C API The :c:func:`PyType_Ready` function now raises an error if a type is defined -with the :const:`Py_TPFLAGS_HAVE_GC` flag set but has no traverse function +with the :c:macro:`Py_TPFLAGS_HAVE_GC` flag set but has no traverse function (:c:member:`PyTypeObject.tp_traverse`). Patch by Victor Stinner. .. diff --git a/Misc/NEWS.d/3.11.0a7.rst b/Misc/NEWS.d/3.11.0a7.rst index 8e7ccd4d6771ee..2172c02e2fc847 100644 --- a/Misc/NEWS.d/3.11.0a7.rst +++ b/Misc/NEWS.d/3.11.0a7.rst @@ -275,7 +275,7 @@ initializing to ``list_extend``. Patch by Jeremiah Pascual. .. nonce: cnaIK3 .. section: Core and Builtins -Speed up throwing exception in generator with :const:`METH_FASTCALL` calling +Speed up throwing exception in generator with :c:macro:`METH_FASTCALL` calling convention. Patch by Kumar Aditya. .. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index ff5064f89d8dd8..9afeba25263514 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -5856,8 +5856,8 @@ Configuration for the :ref:`integer string conversion length limitation Extensions classes that set ``tp_dictoffset`` and ``tp_weaklistoffset`` lose the support for multiple inheritance, but are now safe. Extension classes -should use :const:`Py_TPFLAGS_MANAGED_DICT` and -:const:`Py_TPFLAGS_MANAGED_WEAKREF` instead. +should use :c:macro:`Py_TPFLAGS_MANAGED_DICT` and +:c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead. .. @@ -5898,7 +5898,7 @@ Support C extensions using managed dictionaries by setting the .. nonce: QoDHEu .. section: C API -API for implementing vectorcall (:c:data:`Py_TPFLAGS_HAVE_VECTORCALL`, +API for implementing vectorcall (:c:macro:`Py_TPFLAGS_HAVE_VECTORCALL`, :c:func:`PyVectorcall_NARGS` and :c:func:`PyVectorcall_Call`) was added to the limited API and stable ABI. @@ -5920,12 +5920,12 @@ Philip Georgi. .. nonce: -DdGEy .. section: C API -The :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class +The :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class when the class's :py:meth:`~object.__call__` method is reassigned. This makes vectorcall safe to use with mutable types (i.e. heap types without the :const:`immutable ` flag). Mutable types that do not override :c:member:`~PyTypeObject.tp_call` now inherit the -:const:`Py_TPFLAGS_HAVE_VECTORCALL` flag. +:c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag. .. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index d871384903e7cd..5a3ccab02016f5 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -279,7 +279,7 @@ Fix source locations of :keyword:`match` sub-patterns. Added the methods :c:func:`PyObject_Vectorcall` and :c:func:`PyObject_VectorcallMethod` to the :ref:`Limited API ` along -with the auxiliary macro constant :const:`PY_VECTORCALL_ARGUMENTS_OFFSET`. +with the auxiliary macro constant :c:macro:`PY_VECTORCALL_ARGUMENTS_OFFSET`. The availability of these functions enables more efficient :PEP:`590` vector calls from binary extension modules that avoid argument boxing/unboxing diff --git a/Misc/NEWS.d/3.6.0a1.rst b/Misc/NEWS.d/3.6.0a1.rst index 53f09b3dfe3363..98f1215fb91873 100644 --- a/Misc/NEWS.d/3.6.0a1.rst +++ b/Misc/NEWS.d/3.6.0a1.rst @@ -125,7 +125,7 @@ Setuptools 19.0. .. section: Core and Builtins Memory functions of the :c:func:`PyMem_Malloc` domain -(:c:data:`PYMEM_DOMAIN_MEM`) now use the :ref:`pymalloc allocator +(:c:macro:`PYMEM_DOMAIN_MEM`) now use the :ref:`pymalloc allocator ` rather than system :c:func:`malloc`. Applications calling :c:func:`PyMem_Malloc` without holding the GIL can now crash: use ``PYTHONMALLOC=debug`` environment variable to validate the usage of memory diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 0888a5c43087b5..7af7f2e4120534 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -5706,7 +5706,7 @@ and :c:func:`_PyObject_CallMethodOneArg`. .. nonce: qZC0N_ .. section: C API -The :const:`METH_FASTCALL` calling convention has been documented. +The :c:macro:`METH_FASTCALL` calling convention has been documented. .. From 4be0f157ea7000ded8d4a3ae818a74b026f1fed3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 21 Jul 2023 04:48:50 -0700 Subject: [PATCH 0386/1206] [3.12] gh-47146: Fix reference counting in _testcapi.structmember initializer (GH-106862) (GH-106953) (cherry picked from commit 8d397ee8259fa0f81598a452438fc335267ca260) Co-authored-by: Serhiy Storchaka --- Modules/_testcapi/structmember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_testcapi/structmember.c b/Modules/_testcapi/structmember.c index 0fb872a4328d60..641b003e56d329 100644 --- a/Modules/_testcapi/structmember.c +++ b/Modules/_testcapi/structmember.c @@ -194,7 +194,7 @@ _PyTestCapi_Init_Structmember(PyObject *m) if (res < 0) { return -1; } - res = PyModule_AddObject( + res = PyModule_AddObjectRef( m, "_test_structmembersType_OldAPI", (PyObject *)&test_structmembersType_OldAPI); From 84e52171b541ecc01f2d738cf82f5d4199a4bce7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jul 2023 14:49:39 +0300 Subject: [PATCH 0387/1206] [3.12] gh-106909: Use role :const: for referencing module constants (GH-106910) (GH-106956) (cherry picked from commit 4b9948617f91175783609769aa6160e5b49b9ccc) --- Doc/c-api/exceptions.rst | 2 +- Doc/faq/library.rst | 2 +- Doc/install/index.rst | 4 +- Doc/library/_thread.rst | 4 +- Doc/library/asyncio-dev.rst | 4 +- Doc/library/asyncio-eventloop.rst | 36 ++++++------- Doc/library/asyncio-platforms.rst | 2 +- Doc/library/asyncio-subprocess.rst | 2 +- Doc/library/exceptions.rst | 34 ++++++------ Doc/library/fcntl.rst | 8 +-- Doc/library/ftplib.rst | 4 +- Doc/library/http.client.rst | 2 +- Doc/library/imaplib.rst | 4 +- Doc/library/io.rst | 2 +- Doc/library/multiprocessing.rst | 2 +- Doc/library/optparse.rst | 8 +-- Doc/library/os.rst | 86 +++++++++++++++--------------- Doc/library/poplib.rst | 4 +- Doc/library/shelve.rst | 8 +-- Doc/library/smtplib.rst | 4 +- Doc/library/socket.rst | 2 +- Doc/library/sqlite3.rst | 10 ++-- Doc/library/ssl.rst | 8 +-- Doc/library/sys.rst | 4 +- Doc/library/tempfile.rst | 4 +- Doc/library/test.rst | 2 +- Doc/library/unittest.mock.rst | 2 +- Doc/library/urllib.request.rst | 2 +- Doc/library/xml.rst | 2 +- Doc/using/configure.rst | 4 +- Doc/whatsnew/2.7.rst | 6 +-- Doc/whatsnew/3.10.rst | 16 +++--- Doc/whatsnew/3.11.rst | 8 +-- Doc/whatsnew/3.12.rst | 4 +- Doc/whatsnew/3.2.rst | 6 +-- Doc/whatsnew/3.3.rst | 16 +++--- Doc/whatsnew/3.4.rst | 18 +++---- Doc/whatsnew/3.5.rst | 10 ++-- Doc/whatsnew/3.6.rst | 4 +- Doc/whatsnew/3.7.rst | 18 +++---- Doc/whatsnew/3.8.rst | 2 +- Doc/whatsnew/3.9.rst | 14 ++--- Misc/NEWS.d/3.10.0a1.rst | 4 +- Misc/NEWS.d/3.10.0a2.rst | 2 +- Misc/NEWS.d/3.10.0a6.rst | 6 +-- Misc/NEWS.d/3.10.0a7.rst | 2 +- Misc/NEWS.d/3.10.0b1.rst | 2 +- Misc/NEWS.d/3.11.0a1.rst | 8 +-- Misc/NEWS.d/3.11.0a4.rst | 2 +- Misc/NEWS.d/3.11.0b1.rst | 4 +- Misc/NEWS.d/3.12.0a1.rst | 10 ++-- Misc/NEWS.d/3.12.0a2.rst | 2 +- Misc/NEWS.d/3.12.0a3.rst | 2 +- Misc/NEWS.d/3.12.0a4.rst | 4 +- Misc/NEWS.d/3.12.0a6.rst | 2 +- Misc/NEWS.d/3.12.0a7.rst | 2 +- Misc/NEWS.d/3.12.0b1.rst | 4 +- Misc/NEWS.d/3.6.0rc1.rst | 4 +- Misc/NEWS.d/3.7.0a1.rst | 6 +-- Misc/NEWS.d/3.7.0a3.rst | 4 +- Misc/NEWS.d/3.8.0a1.rst | 2 +- Misc/NEWS.d/3.8.0a4.rst | 2 +- Misc/NEWS.d/3.9.0a1.rst | 14 ++--- Misc/NEWS.d/3.9.0a6.rst | 4 +- 64 files changed, 238 insertions(+), 238 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 6e09f829da3043..3d4ceb360f5b18 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -666,7 +666,7 @@ Signal Handling to interrupt an operation). If the given signal isn't handled by Python (it was set to - :data:`signal.SIG_DFL` or :data:`signal.SIG_IGN`), it will be ignored. + :py:const:`signal.SIG_DFL` or :py:const:`signal.SIG_IGN`), it will be ignored. If *signum* is outside of the allowed range of signal numbers, ``-1`` is returned. Otherwise, ``0`` is returned. The error indicator is diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index 597caaa778e1c8..b43c7505c0401c 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -566,7 +566,7 @@ use ``p.read(n)``. Note on a bug in popen2: unless your program calls ``wait()`` or ``waitpid()``, finished child processes are never removed, and eventually calls to popen2 will fail because of a limit on the number of child - processes. Calling :func:`os.waitpid` with the :data:`os.WNOHANG` option can + processes. Calling :func:`os.waitpid` with the :const:`os.WNOHANG` option can prevent this; a good place to insert such a call would be before calling ``popen2`` again. diff --git a/Doc/install/index.rst b/Doc/install/index.rst index beb34f0cf21b22..34d47fdb6a2f0e 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -313,9 +313,9 @@ install into it. It is enabled with a simple option:: python setup.py install --user -Files will be installed into subdirectories of :data:`site.USER_BASE` (written +Files will be installed into subdirectories of :const:`site.USER_BASE` (written as :file:`{userbase}` hereafter). This scheme installs pure Python modules and -extension modules in the same location (also known as :data:`site.USER_SITE`). +extension modules in the same location (also known as :const:`site.USER_SITE`). Here are the values for UNIX, including macOS: =============== =========================================================== diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index ba9314e46ab6ea..3ff6b48b083b51 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -70,10 +70,10 @@ This module defines the following constants and functions: there is no guarantee that the interruption will happen immediately. If given, *signum* is the number of the signal to simulate. - If *signum* is not given, :data:`signal.SIGINT` is simulated. + If *signum* is not given, :const:`signal.SIGINT` is simulated. If the given signal isn't handled by Python (it was set to - :data:`signal.SIG_DFL` or :data:`signal.SIG_IGN`), this function does + :const:`signal.SIG_DFL` or :const:`signal.SIG_IGN`), this function does nothing. .. versionchanged:: 3.10 diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index 921a394a59fec7..c7d97008fb490e 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -34,7 +34,7 @@ There are several ways to enable asyncio debug mode: In addition to enabling the debug mode, consider also: * setting the log level of the :ref:`asyncio logger ` to - :py:data:`logging.DEBUG`, for example the following snippet of code + :py:const:`logging.DEBUG`, for example the following snippet of code can be run at startup of the application:: logging.basicConfig(level=logging.DEBUG) @@ -142,7 +142,7 @@ Logging asyncio uses the :mod:`logging` module and all logging is performed via the ``"asyncio"`` logger. -The default log level is :py:data:`logging.INFO`, which can be easily +The default log level is :py:const:`logging.INFO`, which can be easily adjusted:: logging.getLogger("asyncio").setLevel(logging.WARNING) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 1ef8a5ab832e47..8f2d8f336c82bb 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -403,11 +403,11 @@ Opening network connections Open a streaming transport connection to a given address specified by *host* and *port*. - The socket family can be either :py:data:`~socket.AF_INET` or - :py:data:`~socket.AF_INET6` depending on *host* (or the *family* + The socket family can be either :py:const:`~socket.AF_INET` or + :py:const:`~socket.AF_INET6` depending on *host* (or the *family* argument, if provided). - The socket type will be :py:data:`~socket.SOCK_STREAM`. + The socket type will be :py:const:`~socket.SOCK_STREAM`. *protocol_factory* must be a callable returning an :ref:`asyncio protocol ` implementation. @@ -509,7 +509,7 @@ Opening network connections .. versionchanged:: 3.6 - The socket option :py:data:`~socket.TCP_NODELAY` is set by default + The socket option :py:const:`~socket.TCP_NODELAY` is set by default for all TCP connections. .. versionchanged:: 3.7 @@ -552,11 +552,11 @@ Opening network connections Create a datagram connection. - The socket family can be either :py:data:`~socket.AF_INET`, - :py:data:`~socket.AF_INET6`, or :py:data:`~socket.AF_UNIX`, + The socket family can be either :py:const:`~socket.AF_INET`, + :py:const:`~socket.AF_INET6`, or :py:const:`~socket.AF_UNIX`, depending on *host* (or the *family* argument, if provided). - The socket type will be :py:data:`~socket.SOCK_DGRAM`. + The socket type will be :py:const:`~socket.SOCK_DGRAM`. *protocol_factory* must be a callable returning a :ref:`protocol ` implementation. @@ -581,7 +581,7 @@ Opening network connections * *reuse_port* tells the kernel to allow this endpoint to be bound to the same port as other existing endpoints are bound to, so long as they all set this flag when being created. This option is not supported on Windows - and some Unixes. If the :py:data:`~socket.SO_REUSEPORT` constant is not + and some Unixes. If the :py:const:`~socket.SO_REUSEPORT` constant is not defined then this capability is unsupported. * *allow_broadcast* tells the kernel to allow this endpoint to send @@ -607,7 +607,7 @@ Opening network connections .. versionchanged:: 3.8.1 The *reuse_address* parameter is no longer supported, as using - :py:data:`~sockets.SO_REUSEADDR` poses a significant security concern for + :py:const:`~sockets.SO_REUSEADDR` poses a significant security concern for UDP. Explicitly passing ``reuse_address=True`` will raise an exception. When multiple processes with differing UIDs assign sockets to an @@ -616,7 +616,7 @@ Opening network connections For supported platforms, *reuse_port* can be used as a replacement for similar functionality. With *reuse_port*, - :py:data:`~sockets.SO_REUSEPORT` is used instead, which specifically + :py:const:`~sockets.SO_REUSEPORT` is used instead, which specifically prevents processes with differing UIDs from assigning sockets to the same socket address. @@ -634,8 +634,8 @@ Opening network connections Create a Unix connection. - The socket family will be :py:data:`~socket.AF_UNIX`; socket - type will be :py:data:`~socket.SOCK_STREAM`. + The socket family will be :py:const:`~socket.AF_UNIX`; socket + type will be :py:const:`~socket.SOCK_STREAM`. A tuple of ``(transport, protocol)`` is returned on success. @@ -671,7 +671,7 @@ Creating network servers ssl_shutdown_timeout=None, \ start_serving=True) - Create a TCP server (socket type :data:`~socket.SOCK_STREAM`) listening + Create a TCP server (socket type :const:`~socket.SOCK_STREAM`) listening on *port* of the *host* address. Returns a :class:`Server` object. @@ -699,10 +699,10 @@ Creating network servers be selected (note that if *host* resolves to multiple network interfaces, a different random port will be selected for each interface). - * *family* can be set to either :data:`socket.AF_INET` or - :data:`~socket.AF_INET6` to force the socket to use IPv4 or IPv6. + * *family* can be set to either :const:`socket.AF_INET` or + :const:`~socket.AF_INET6` to force the socket to use IPv4 or IPv6. If not set, the *family* will be determined from host name - (defaults to :data:`~socket.AF_UNSPEC`). + (defaults to :const:`~socket.AF_UNSPEC`). * *flags* is a bitmask for :meth:`getaddrinfo`. @@ -756,7 +756,7 @@ Creating network servers .. versionchanged:: 3.6 Added *ssl_handshake_timeout* and *start_serving* parameters. - The socket option :py:data:`~socket.TCP_NODELAY` is set by default + The socket option :py:const:`~socket.TCP_NODELAY` is set by default for all TCP connections. .. versionchanged:: 3.11 @@ -777,7 +777,7 @@ Creating network servers start_serving=True) Similar to :meth:`loop.create_server` but works with the - :py:data:`~socket.AF_UNIX` socket family. + :py:const:`~socket.AF_UNIX` socket family. *path* is the name of a Unix domain socket, and is required, unless a *sock* argument is provided. Abstract Unix sockets, diff --git a/Doc/library/asyncio-platforms.rst b/Doc/library/asyncio-platforms.rst index 50ad8a2ab70324..19ec726c1be060 100644 --- a/Doc/library/asyncio-platforms.rst +++ b/Doc/library/asyncio-platforms.rst @@ -37,7 +37,7 @@ All event loops on Windows do not support the following methods: * :meth:`loop.create_unix_connection` and :meth:`loop.create_unix_server` are not supported. - The :data:`socket.AF_UNIX` socket family is specific to Unix. + The :const:`socket.AF_UNIX` socket family is specific to Unix. * :meth:`loop.add_signal_handler` and :meth:`loop.remove_signal_handler` are not supported. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst index b7c83aa04c09f1..afade9b0b50706 100644 --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -249,7 +249,7 @@ their completion. Stop the child process. - On POSIX systems this method sends :py:data:`signal.SIGTERM` to the + On POSIX systems this method sends :py:const:`signal.SIGTERM` to the child process. On Windows the Win32 API function :c:func:`TerminateProcess` is diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index d54c49fff6b62a..dcfbc486eeb358 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -659,8 +659,8 @@ depending on the system error code. Raised when an operation would block on an object (e.g. socket) set for non-blocking operation. - Corresponds to :c:data:`errno` :py:data:`~errno.EAGAIN`, :py:data:`~errno.EALREADY`, - :py:data:`~errno.EWOULDBLOCK` and :py:data:`~errno.EINPROGRESS`. + Corresponds to :c:data:`errno` :py:const:`~errno.EAGAIN`, :py:const:`~errno.EALREADY`, + :py:const:`~errno.EWOULDBLOCK` and :py:const:`~errno.EINPROGRESS`. In addition to those of :exc:`OSError`, :exc:`BlockingIOError` can have one more attribute: @@ -674,7 +674,7 @@ depending on the system error code. .. exception:: ChildProcessError Raised when an operation on a child process failed. - Corresponds to :c:data:`errno` :py:data:`~errno.ECHILD`. + Corresponds to :c:data:`errno` :py:const:`~errno.ECHILD`. .. exception:: ConnectionError @@ -688,40 +688,40 @@ depending on the system error code. A subclass of :exc:`ConnectionError`, raised when trying to write on a pipe while the other end has been closed, or trying to write on a socket which has been shutdown for writing. - Corresponds to :c:data:`errno` :py:data:`~errno.EPIPE` and :py:data:`~errno.ESHUTDOWN`. + Corresponds to :c:data:`errno` :py:const:`~errno.EPIPE` and :py:const:`~errno.ESHUTDOWN`. .. exception:: ConnectionAbortedError A subclass of :exc:`ConnectionError`, raised when a connection attempt is aborted by the peer. - Corresponds to :c:data:`errno` :py:data:`~errno.ECONNABORTED`. + Corresponds to :c:data:`errno` :py:const:`~errno.ECONNABORTED`. .. exception:: ConnectionRefusedError A subclass of :exc:`ConnectionError`, raised when a connection attempt is refused by the peer. - Corresponds to :c:data:`errno` :py:data:`~errno.ECONNREFUSED`. + Corresponds to :c:data:`errno` :py:const:`~errno.ECONNREFUSED`. .. exception:: ConnectionResetError A subclass of :exc:`ConnectionError`, raised when a connection is reset by the peer. - Corresponds to :c:data:`errno` :py:data:`~errno.ECONNRESET`. + Corresponds to :c:data:`errno` :py:const:`~errno.ECONNRESET`. .. exception:: FileExistsError Raised when trying to create a file or directory which already exists. - Corresponds to :c:data:`errno` :py:data:`~errno.EEXIST`. + Corresponds to :c:data:`errno` :py:const:`~errno.EEXIST`. .. exception:: FileNotFoundError Raised when a file or directory is requested but doesn't exist. - Corresponds to :c:data:`errno` :py:data:`~errno.ENOENT`. + Corresponds to :c:data:`errno` :py:const:`~errno.ENOENT`. .. exception:: InterruptedError Raised when a system call is interrupted by an incoming signal. - Corresponds to :c:data:`errno` :py:data:`~errno.EINTR`. + Corresponds to :c:data:`errno` :py:const:`~errno.EINTR`. .. versionchanged:: 3.5 Python now retries system calls when a syscall is interrupted by a @@ -732,7 +732,7 @@ depending on the system error code. Raised when a file operation (such as :func:`os.remove`) is requested on a directory. - Corresponds to :c:data:`errno` :py:data:`~errno.EISDIR`. + Corresponds to :c:data:`errno` :py:const:`~errno.EISDIR`. .. exception:: NotADirectoryError @@ -740,28 +740,28 @@ depending on the system error code. something which is not a directory. On most POSIX platforms, it may also be raised if an operation attempts to open or traverse a non-directory file as if it were a directory. - Corresponds to :c:data:`errno` :py:data:`~errno.ENOTDIR`. + Corresponds to :c:data:`errno` :py:const:`~errno.ENOTDIR`. .. exception:: PermissionError Raised when trying to run an operation without the adequate access rights - for example filesystem permissions. - Corresponds to :c:data:`errno` :py:data:`~errno.EACCES`, - :py:data:`~errno.EPERM`, and :py:data:`~errno.ENOTCAPABLE`. + Corresponds to :c:data:`errno` :py:const:`~errno.EACCES`, + :py:const:`~errno.EPERM`, and :py:const:`~errno.ENOTCAPABLE`. .. versionchanged:: 3.11.1 - WASI's :py:data:`~errno.ENOTCAPABLE` is now mapped to + WASI's :py:const:`~errno.ENOTCAPABLE` is now mapped to :exc:`PermissionError`. .. exception:: ProcessLookupError Raised when a given process doesn't exist. - Corresponds to :c:data:`errno` :py:data:`~errno.ESRCH`. + Corresponds to :c:data:`errno` :py:const:`~errno.ESRCH`. .. exception:: TimeoutError Raised when a system function timed out at the system level. - Corresponds to :c:data:`errno` :py:data:`~errno.ETIMEDOUT`. + Corresponds to :c:data:`errno` :py:const:`~errno.ETIMEDOUT`. .. versionadded:: 3.3 All the above :exc:`OSError` subclasses were added. diff --git a/Doc/library/fcntl.rst b/Doc/library/fcntl.rst index 997c7ea571fc03..5a27646a96f591 100644 --- a/Doc/library/fcntl.rst +++ b/Doc/library/fcntl.rst @@ -172,9 +172,9 @@ The module defines the following functions: which the lock starts, relative to *whence*, and *whence* is as with :func:`io.IOBase.seek`, specifically: - * :const:`0` -- relative to the start of the file (:data:`os.SEEK_SET`) - * :const:`1` -- relative to the current buffer position (:data:`os.SEEK_CUR`) - * :const:`2` -- relative to the end of the file (:data:`os.SEEK_END`) + * :const:`0` -- relative to the start of the file (:const:`os.SEEK_SET`) + * :const:`1` -- relative to the current buffer position (:const:`os.SEEK_CUR`) + * :const:`2` -- relative to the end of the file (:const:`os.SEEK_END`) The default for *start* is 0, which means to start at the beginning of the file. The default for *len* is 0 which means to lock to the end of the file. The @@ -201,7 +201,7 @@ using the :func:`flock` call may be better. .. seealso:: Module :mod:`os` - If the locking flags :data:`~os.O_SHLOCK` and :data:`~os.O_EXLOCK` are + If the locking flags :const:`~os.O_SHLOCK` and :const:`~os.O_EXLOCK` are present in the :mod:`os` module (on BSD only), the :func:`os.open` function provides an alternative to the :func:`lockf` and :func:`flock` functions. diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index e7fb5b1ae26960..cd6e2d38b02868 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -105,7 +105,7 @@ The module defines the following items: .. versionchanged:: 3.4 The class now supports hostname check with :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see - :data:`ssl.HAS_SNI`). + :const:`ssl.HAS_SNI`). .. versionchanged:: 3.9 If the *timeout* parameter is set to be zero, it will raise a @@ -441,7 +441,7 @@ FTP_TLS Objects .. versionchanged:: 3.4 The method now supports hostname check with :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see - :data:`ssl.HAS_SNI`). + :const:`ssl.HAS_SNI`). .. method:: FTP_TLS.ccc() diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index b9ceab699cef63..c46314fc5e253b 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -83,7 +83,7 @@ The module provides the following classes: .. versionchanged:: 3.2 This class now supports HTTPS virtual hosts if possible (that is, - if :data:`ssl.HAS_SNI` is true). + if :const:`ssl.HAS_SNI` is true). .. versionchanged:: 3.4 The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 59d7711f9cbd3c..1f774e64b0eae3 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -106,7 +106,7 @@ There's also a subclass for secure connections: .. versionchanged:: 3.4 The class now supports hostname check with :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see - :data:`ssl.HAS_SNI`). + :const:`ssl.HAS_SNI`). .. versionchanged:: 3.9 The optional *timeout* parameter was added. @@ -503,7 +503,7 @@ An :class:`IMAP4` instance has the following methods: .. versionchanged:: 3.4 The method now supports hostname check with :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see - :data:`ssl.HAS_SNI`). + :const:`ssl.HAS_SNI`). .. method:: IMAP4.status(mailbox, names) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index c9249da1c3c3d2..7eec1f87583b87 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -423,7 +423,7 @@ I/O Base Classes .. versionadded:: 3.3 Some operating systems could support additional values, like - :data:`os.SEEK_HOLE` or :data:`os.SEEK_DATA`. The valid values + :const:`os.SEEK_HOLE` or :const:`os.SEEK_DATA`. The valid values for a file could depend on it being open in text or binary mode. .. method:: seekable() diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 8454296b815b41..2efc08f130af32 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2707,7 +2707,7 @@ handler type) for messages from different processes to get mixed up. Returns the logger used by :mod:`multiprocessing`. If necessary, a new one will be created. - When first created the logger has level :data:`logging.NOTSET` and no + When first created the logger has level :const:`logging.NOTSET` and no default handler. Messages sent to this logger will not by default propagate to the root logger. diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst index 0cff3817452364..846b8e031f7492 100644 --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -812,7 +812,7 @@ The first step in using :mod:`optparse` is to create an OptionParser instance. help option. When :mod:`optparse` prints the usage string, it expands ``%prog`` to ``os.path.basename(sys.argv[0])`` (or to ``prog`` if you passed that keyword argument). To suppress a usage message, pass the - special value :data:`optparse.SUPPRESS_USAGE`. + special value :const:`optparse.SUPPRESS_USAGE`. ``option_list`` (default: ``[]``) A list of Option objects to populate the parser with. The options in @@ -1078,7 +1078,7 @@ relevant to a particular option, or fail to pass a required option attribute, Help text to print for this option when listing all available options after the user supplies a :attr:`~Option.help` option (such as ``--help``). If no help text is supplied, the option will be listed without help text. To - hide this option, use the special value :data:`optparse.SUPPRESS_HELP`. + hide this option, use the special value :const:`optparse.SUPPRESS_HELP`. .. attribute:: Option.metavar @@ -1250,7 +1250,7 @@ must specify for any option using that action. If no :attr:`~Option.help` string is supplied for an option, it will still be listed in the help message. To omit an option entirely, use the special value - :data:`optparse.SUPPRESS_HELP`. + :const:`optparse.SUPPRESS_HELP`. :mod:`optparse` automatically adds a :attr:`~Option.help` option to all OptionParsers, so you do not normally need to create one. @@ -1521,7 +1521,7 @@ OptionParser supports several other public methods: Set the usage string according to the rules described above for the ``usage`` constructor keyword argument. Passing ``None`` sets the default usage - string; use :data:`optparse.SUPPRESS_USAGE` to suppress a usage message. + string; use :const:`optparse.SUPPRESS_USAGE` to suppress a usage message. .. method:: OptionParser.print_usage(file=None) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index b35010498f2143..76f797ac2c4cb4 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -233,7 +233,7 @@ process and user. :data:`environ` and :data:`environb` are synchronized (modifying :data:`environb` updates :data:`environ`, and vice versa). - :data:`environb` is only available if :data:`supports_bytes_environ` is + :data:`environb` is only available if :const:`supports_bytes_environ` is ``True``. .. versionadded:: 3.2 @@ -331,7 +331,7 @@ process and user. future environment changes. - :func:`getenvb` is only available if :data:`supports_bytes_environ` + :func:`getenvb` is only available if :const:`supports_bytes_environ` is ``True``. .. availability:: Unix. @@ -923,7 +923,7 @@ as internal buffering of data. In Linux kernel older than 5.3, the files pointed by *src* and *dst* must reside in the same filesystem, otherwise an :exc:`OSError` is - raised with :attr:`~OSError.errno` set to :data:`errno.EXDEV`. + raised with :attr:`~OSError.errno` set to :const:`errno.EXDEV`. This copy is done without the additional cost of transferring data from the kernel to user space and then back into the kernel. Additionally, @@ -1181,7 +1181,7 @@ as internal buffering of data. .. versionadded:: 3.3 Some operating systems could support additional values, like - :data:`os.SEEK_HOLE` or :data:`os.SEEK_DATA`. + :const:`os.SEEK_HOLE` or :const:`os.SEEK_DATA`. .. function:: open(path, flags, mode=0o777, *, dir_fd=None) @@ -1422,7 +1422,7 @@ or `the MSDN `_ on Windo If some data was successfully read, it will return the number of bytes read. If no bytes were read, it will return ``-1`` and set errno to - :data:`errno.EAGAIN`. + :const:`errno.EAGAIN`. .. availability:: Linux >= 4.14. @@ -1627,7 +1627,7 @@ or `the MSDN `_ on Windo *offset_dst*. The offset associated to the file descriptor that refers to a pipe must be ``None``. The files pointed by *src* and *dst* must reside in the same filesystem, otherwise an :exc:`OSError` is raised with - :attr:`~OSError.errno` set to :data:`errno.EXDEV`. + :attr:`~OSError.errno` set to :const:`errno.EXDEV`. This copy is done without the additional cost of transferring data from the kernel to user space and then back into the kernel. Additionally, @@ -1960,18 +1960,18 @@ features: Set the flags of *path* to the numeric *flags*. *flags* may take a combination (bitwise OR) of the following values (as defined in the :mod:`stat` module): - * :data:`stat.UF_NODUMP` - * :data:`stat.UF_IMMUTABLE` - * :data:`stat.UF_APPEND` - * :data:`stat.UF_OPAQUE` - * :data:`stat.UF_NOUNLINK` - * :data:`stat.UF_COMPRESSED` - * :data:`stat.UF_HIDDEN` - * :data:`stat.SF_ARCHIVED` - * :data:`stat.SF_IMMUTABLE` - * :data:`stat.SF_APPEND` - * :data:`stat.SF_NOUNLINK` - * :data:`stat.SF_SNAPSHOT` + * :const:`stat.UF_NODUMP` + * :const:`stat.UF_IMMUTABLE` + * :const:`stat.UF_APPEND` + * :const:`stat.UF_OPAQUE` + * :const:`stat.UF_NOUNLINK` + * :const:`stat.UF_COMPRESSED` + * :const:`stat.UF_HIDDEN` + * :const:`stat.SF_ARCHIVED` + * :const:`stat.SF_IMMUTABLE` + * :const:`stat.SF_APPEND` + * :const:`stat.SF_NOUNLINK` + * :const:`stat.SF_SNAPSHOT` This function can support :ref:`not following symlinks `. @@ -1992,25 +1992,25 @@ features: following values (as defined in the :mod:`stat` module) or bitwise ORed combinations of them: - * :data:`stat.S_ISUID` - * :data:`stat.S_ISGID` - * :data:`stat.S_ENFMT` - * :data:`stat.S_ISVTX` - * :data:`stat.S_IREAD` - * :data:`stat.S_IWRITE` - * :data:`stat.S_IEXEC` - * :data:`stat.S_IRWXU` - * :data:`stat.S_IRUSR` - * :data:`stat.S_IWUSR` - * :data:`stat.S_IXUSR` - * :data:`stat.S_IRWXG` - * :data:`stat.S_IRGRP` - * :data:`stat.S_IWGRP` - * :data:`stat.S_IXGRP` - * :data:`stat.S_IRWXO` - * :data:`stat.S_IROTH` - * :data:`stat.S_IWOTH` - * :data:`stat.S_IXOTH` + * :const:`stat.S_ISUID` + * :const:`stat.S_ISGID` + * :const:`stat.S_ENFMT` + * :const:`stat.S_ISVTX` + * :const:`stat.S_IREAD` + * :const:`stat.S_IWRITE` + * :const:`stat.S_IEXEC` + * :const:`stat.S_IRWXU` + * :const:`stat.S_IRUSR` + * :const:`stat.S_IWUSR` + * :const:`stat.S_IXUSR` + * :const:`stat.S_IRWXG` + * :const:`stat.S_IRGRP` + * :const:`stat.S_IWGRP` + * :const:`stat.S_IXGRP` + * :const:`stat.S_IRWXO` + * :const:`stat.S_IROTH` + * :const:`stat.S_IWOTH` + * :const:`stat.S_IXOTH` This function can support :ref:`specifying a file descriptor `, :ref:`paths relative to directory descriptors ` and :ref:`not @@ -4151,8 +4151,8 @@ written in Python, such as a mail server's external command delivery program. Send signal *sig* to the process *pid*. Constants for the specific signals available on the host platform are defined in the :mod:`signal` module. - Windows: The :data:`signal.CTRL_C_EVENT` and - :data:`signal.CTRL_BREAK_EVENT` signals are special signals which can + Windows: The :const:`signal.CTRL_C_EVENT` and + :const:`signal.CTRL_BREAK_EVENT` signals are special signals which can only be sent to console processes which share a common console window, e.g., some subprocesses. Any other value for *sig* will cause the process to be unconditionally killed by the TerminateProcess API, and the exit code @@ -4205,7 +4205,7 @@ written in Python, such as a mail server's external command delivery program. This flag indicates that the file descriptor will be non-blocking. If the process referred to by the file descriptor has not yet terminated, then an attempt to wait on the file descriptor using :manpage:`waitid(2)` - will immediately return the error :data:`~errno.EAGAIN` rather than blocking. + will immediately return the error :const:`~errno.EAGAIN` rather than blocking. .. availability:: Linux >= 5.10 .. versionadded:: 3.12 @@ -4654,7 +4654,7 @@ written in Python, such as a mail server's external command delivery program. * :attr:`!si_pid` (process ID) * :attr:`!si_uid` (real user ID of the child) - * :attr:`!si_signo` (always :data:`~signal.SIGCHLD`) + * :attr:`!si_signo` (always :const:`~signal.SIGCHLD`) * :attr:`!si_status` (the exit status or signal number, depending on :attr:`!si_code`) * :attr:`!si_code` (see :data:`CLD_EXITED` for possible values) @@ -4892,7 +4892,7 @@ used to determine the disposition of a process. .. function:: WIFCONTINUED(status) Return ``True`` if a stopped child has been resumed by delivery of - :data:`~signal.SIGCONT` (if the process has been continued from a job + :const:`~signal.SIGCONT` (if the process has been continued from a job control stop), otherwise return ``False``. See :data:`WCONTINUED` option. @@ -5264,7 +5264,7 @@ Random numbers ``/dev/urandom`` devices. The flags argument is a bit mask that can contain zero or more of the - following values ORed together: :py:data:`os.GRND_RANDOM` and + following values ORed together: :py:const:`os.GRND_RANDOM` and :py:data:`GRND_NONBLOCK`. See also the `Linux getrandom() manual page diff --git a/Doc/library/poplib.rst b/Doc/library/poplib.rst index 260c4a63d12031..fbd5e150b4cd54 100644 --- a/Doc/library/poplib.rst +++ b/Doc/library/poplib.rst @@ -77,7 +77,7 @@ The :mod:`poplib` module provides two classes: .. versionchanged:: 3.4 The class now supports hostname check with :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see - :data:`ssl.HAS_SNI`). + :const:`ssl.HAS_SNI`). .. versionchanged:: 3.9 If the *timeout* parameter is set to be zero, it will raise a @@ -240,7 +240,7 @@ A :class:`POP3` instance has the following methods: This method supports hostname checking via :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see - :data:`ssl.HAS_SNI`). + :const:`ssl.HAS_SNI`). .. versionadded:: 3.4 diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index dc87af398ed757..01314f491f47a7 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -25,7 +25,7 @@ lots of shared sub-objects. The keys are ordinary strings. database file is opened for reading and writing. The optional *flag* parameter has the same interpretation as the *flag* parameter of :func:`dbm.open`. - By default, pickles created with :data:`pickle.DEFAULT_PROTOCOL` are used + By default, pickles created with :const:`pickle.DEFAULT_PROTOCOL` are used to serialize values. The version of the pickle protocol can be specified with the *protocol* parameter. @@ -42,7 +42,7 @@ lots of shared sub-objects. The keys are ordinary strings. mutated). .. versionchanged:: 3.10 - :data:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle + :const:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle protocol. .. versionchanged:: 3.11 @@ -119,7 +119,7 @@ Restrictions A subclass of :class:`collections.abc.MutableMapping` which stores pickled values in the *dict* object. - By default, pickles created with :data:`pickle.DEFAULT_PROTOCOL` are used + By default, pickles created with :const:`pickle.DEFAULT_PROTOCOL` are used to serialize values. The version of the pickle protocol can be specified with the *protocol* parameter. See the :mod:`pickle` documentation for a discussion of the pickle protocols. @@ -143,7 +143,7 @@ Restrictions Added context manager support. .. versionchanged:: 3.10 - :data:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle + :const:`pickle.DEFAULT_PROTOCOL` is now used as the default pickle protocol. diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index f90274feb6bf9a..aaec2aa1ef1dbe 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -98,7 +98,7 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). .. versionchanged:: 3.4 The class now supports hostname check with :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see - :data:`ssl.HAS_SNI`). + :const:`ssl.HAS_SNI`). .. versionchanged:: 3.9 If the *timeout* parameter is set to be zero, it will raise a @@ -418,7 +418,7 @@ An :class:`SMTP` instance has the following methods: .. versionchanged:: 3.4 The method now supports hostname check with :attr:`SSLContext.check_hostname` and *Server Name Indicator* (see - :data:`~ssl.HAS_SNI`). + :const:`~ssl.HAS_SNI`). .. versionchanged:: 3.5 The error raised for lack of STARTTLS support is now the diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index f2408cb95ff314..4f220e8a098979 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -2252,7 +2252,7 @@ This is because the previous execution has left the socket in a ``TIME_WAIT`` state, and can't be immediately reused. There is a :mod:`socket` flag to set, in order to prevent this, -:data:`socket.SO_REUSEADDR`:: +:const:`socket.SO_REUSEADDR`:: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 2e2c28b1e5fe73..23a22e637c0a93 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -299,7 +299,7 @@ Module functions Can be ``"DEFERRED"`` (default), ``"EXCLUSIVE"`` or ``"IMMEDIATE"``; or ``None`` to disable opening transactions implicitly. Has no effect unless :attr:`Connection.autocommit` is set to - :data:`~sqlite3.LEGACY_TRANSACTION_CONTROL` (the default). + :const:`~sqlite3.LEGACY_TRANSACTION_CONTROL` (the default). :type isolation_level: str | None :param bool check_same_thread: @@ -334,7 +334,7 @@ Module functions See :attr:`Connection.autocommit` and :ref:`sqlite3-transaction-control-autocommit` for more information. *autocommit* currently defaults to - :data:`~sqlite3.LEGACY_TRANSACTION_CONTROL`. + :const:`~sqlite3.LEGACY_TRANSACTION_CONTROL`. The default will change to ``False`` in a future Python release. :type autocommit: bool @@ -1821,9 +1821,9 @@ Blob objects .. method:: seek(offset, origin=os.SEEK_SET, /) Set the current access position of the blob to *offset*. The *origin* - argument defaults to :data:`os.SEEK_SET` (absolute blob positioning). - Other values for *origin* are :data:`os.SEEK_CUR` (seek relative to the - current position) and :data:`os.SEEK_END` (seek relative to the blob’s + argument defaults to :const:`os.SEEK_SET` (absolute blob positioning). + Other values for *origin* are :const:`os.SEEK_CUR` (seek relative to the + current position) and :const:`os.SEEK_END` (seek relative to the blob’s end). diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 18a6c5ab4858a4..7f095526327685 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -139,7 +139,7 @@ purposes. The settings are: :data:`PROTOCOL_TLS_CLIENT` or :data:`PROTOCOL_TLS_SERVER`, :data:`OP_NO_SSLv2`, and :data:`OP_NO_SSLv3` with high encryption cipher suites without RC4 and - without unauthenticated cipher suites. Passing :data:`~Purpose.SERVER_AUTH` + without unauthenticated cipher suites. Passing :const:`~Purpose.SERVER_AUTH` as *purpose* sets :data:`~SSLContext.verify_mode` to :data:`CERT_REQUIRED` and either loads CA certificates (when at least one of *cafile*, *capath* or *cadata* is given) or uses :meth:`SSLContext.load_default_certs` to load @@ -1484,9 +1484,9 @@ to speed up repeated connections from the same clients. load CA certificates from other locations, too. The *purpose* flag specifies what kind of CA certificates are loaded. The - default settings :data:`Purpose.SERVER_AUTH` loads certificates, that are + default settings :const:`Purpose.SERVER_AUTH` loads certificates, that are flagged and trusted for TLS web server authentication (client side - sockets). :data:`Purpose.CLIENT_AUTH` loads CA certificates for client + sockets). :const:`Purpose.CLIENT_AUTH` loads CA certificates for client certificate verification on the server side. .. versionadded:: 3.4 @@ -1729,7 +1729,7 @@ to speed up repeated connections from the same clients. Wrap an existing Python socket *sock* and return an instance of :attr:`SSLContext.sslsocket_class` (default :class:`SSLSocket`). The returned SSL socket is tied to the context, its settings and certificates. - *sock* must be a :data:`~socket.SOCK_STREAM` socket; other + *sock* must be a :const:`~socket.SOCK_STREAM` socket; other socket types are unsupported. The parameter ``server_side`` is a boolean which identifies whether diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index bacf8ceac5041e..911d73b546b5cc 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -697,7 +697,7 @@ always available. Return the current value of the flags that are used for :c:func:`dlopen` calls. Symbolic names for the flag values can be found in the :mod:`os` module (``RTLD_xxx`` constants, e.g. - :data:`os.RTLD_LAZY`). + :const:`os.RTLD_LAZY`). .. availability:: Unix. @@ -1368,7 +1368,7 @@ always available. ``sys.setdlopenflags(0)``. To share symbols across extension modules, call as ``sys.setdlopenflags(os.RTLD_GLOBAL)``. Symbolic names for the flag values can be found in the :mod:`os` module (``RTLD_xxx`` constants, e.g. - :data:`os.RTLD_LAZY`). + :const:`os.RTLD_LAZY`). .. availability:: Unix. diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index fd4c294613fd31..097f7087eccab9 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -59,7 +59,7 @@ The module defines the following user-callable items: platforms, it is a file-like object whose :attr:`!file` attribute is the underlying true file object. - The :py:data:`os.O_TMPFILE` flag is used if it is available and works + The :py:const:`os.O_TMPFILE` flag is used if it is available and works (Linux-specific, requires Linux kernel 3.11 or later). On platforms that are neither Posix nor Cygwin, TemporaryFile is an alias @@ -69,7 +69,7 @@ The module defines the following user-callable items: .. versionchanged:: 3.5 - The :py:data:`os.O_TMPFILE` flag is now used if available. + The :py:const:`os.O_TMPFILE` flag is now used if available. .. versionchanged:: 3.8 Added *errors* parameter. diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 1b045c7de83a80..d69a3e326a411b 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -472,7 +472,7 @@ The :mod:`test.support` module defines the following functions: .. function:: with_pymalloc() - Return :data:`_testcapi.WITH_PYMALLOC`. + Return :const:`_testcapi.WITH_PYMALLOC`. .. function:: requires(resource, msg=None) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 6c4d801f69f5a9..13cd593f9549a2 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2438,7 +2438,7 @@ behaviour you can switch it off by setting the module level switch Alternatively you can just use ``vars(my_mock)`` (instance members) and ``dir(type(my_mock))`` (type members) to bypass the filtering irrespective of -:data:`mock.FILTER_DIR`. +:const:`mock.FILTER_DIR`. mock_open diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 1b05458280d896..35b8f5b471dd96 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -99,7 +99,7 @@ The :mod:`urllib.request` module defines the following functions: .. versionchanged:: 3.2 HTTPS virtual hosts are now supported if possible (that is, if - :data:`ssl.HAS_SNI` is true). + :const:`ssl.HAS_SNI` is true). .. versionadded:: 3.2 *data* can be an iterable object. diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst index 20b0905bb1093a..cf30de67719b93 100644 --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -73,7 +73,7 @@ decompression bomb Safe Safe Safe 1. Expat 2.4.1 and newer is not vulnerable to the "billion laughs" and "quadratic blowup" vulnerabilities. Items still listed as vulnerable due to potential reliance on system-provided libraries. Check - :data:`pyexpat.EXPAT_VERSION`. + :const:`pyexpat.EXPAT_VERSION`. 2. :mod:`xml.etree.ElementTree` doesn't expand external entities and raises a :exc:`ParserError` when an entity occurs. 3. :mod:`xml.dom.minidom` doesn't expand external entities and simply returns diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index fbe280d6413170..924e73dc54da2e 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -97,7 +97,7 @@ General Options .. cmdoption:: --with-tzpath= - Select the default time zone search path for :data:`zoneinfo.TZPATH`. + Select the default time zone search path for :const:`zoneinfo.TZPATH`. See the :ref:`Compile-time configuration ` of the :mod:`zoneinfo` module. @@ -112,7 +112,7 @@ General Options Build the ``_decimal`` extension module using a thread-local context rather than a coroutine-local context (default), see the :mod:`decimal` module. - See :data:`decimal.HAVE_CONTEXTVAR` and the :mod:`contextvars` module. + See :const:`decimal.HAVE_CONTEXTVAR` and the :mod:`contextvars` module. .. versionadded:: 3.9 diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index e6bc9a21b365d4..a1d522b7ce6da1 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -1556,9 +1556,9 @@ changes, or look through the Subversion logs for all the details. :issue:`8484`.) The version of OpenSSL being used is now available as the module - attributes :data:`ssl.OPENSSL_VERSION` (a string), - :data:`ssl.OPENSSL_VERSION_INFO` (a 5-tuple), and - :data:`ssl.OPENSSL_VERSION_NUMBER` (an integer). (Added by Antoine + attributes :const:`ssl.OPENSSL_VERSION` (a string), + :const:`ssl.OPENSSL_VERSION_INFO` (a 5-tuple), and + :const:`ssl.OPENSSL_VERSION_NUMBER` (an integer). (Added by Antoine Pitrou; :issue:`8321`.) * The :mod:`struct` module will no longer silently ignore overflow diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 7f80852c49548f..bb271d0a455681 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1253,8 +1253,8 @@ descriptors without copying between kernel address space and user address space, where one of the file descriptors must refer to a pipe. (Contributed by Pablo Galindo in :issue:`41625`.) -Add :data:`~os.O_EVTONLY`, :data:`~os.O_FSYNC`, :data:`~os.O_SYMLINK` -and :data:`~os.O_NOFOLLOW_ANY` for macOS. +Add :const:`~os.O_EVTONLY`, :const:`~os.O_FSYNC`, :const:`~os.O_SYMLINK` +and :const:`~os.O_NOFOLLOW_ANY` for macOS. (Contributed by Dong-hee Na in :issue:`43106`.) os.path @@ -1319,7 +1319,7 @@ objects in the tree returned by :func:`pyclbr.readline` and shelve ------ -The :mod:`shelve` module now uses :data:`pickle.DEFAULT_PROTOCOL` by default +The :mod:`shelve` module now uses :const:`pickle.DEFAULT_PROTOCOL` by default instead of :mod:`pickle` protocol ``3`` when creating shelves. (Contributed by Zackery Spytz in :issue:`34204`.) @@ -1356,7 +1356,7 @@ The ssl module requires OpenSSL 1.1.1 or newer. (Contributed by Christian Heimes in :pep:`644` and :issue:`43669`.) The ssl module has preliminary support for OpenSSL 3.0.0 and new option -:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF`. +:const:`~ssl.OP_IGNORE_UNEXPECTED_EOF`. (Contributed by Christian Heimes in :issue:`38820`, :issue:`43794`, :issue:`43788`, :issue:`43791`, :issue:`43799`, :issue:`43920`, :issue:`43789`, and :issue:`43811`.) @@ -1387,7 +1387,7 @@ Add a *timeout* parameter to the :func:`ssl.get_server_certificate` function. The ssl module uses heap-types and multi-phase initialization. (Contributed by Christian Heimes in :issue:`42333`.) -A new verify flag :data:`~ssl.VERIFY_X509_PARTIAL_CHAIN` has been added. +A new verify flag :const:`~ssl.VERIFY_X509_PARTIAL_CHAIN` has been added. (Contributed by l0x in :issue:`40849`.) sqlite3 @@ -1413,7 +1413,7 @@ _thread ------- :func:`_thread.interrupt_main` now takes an optional signal number to -simulate (the default is still :data:`signal.SIGINT`). +simulate (the default is still :const:`signal.SIGINT`). (Contributed by Antoine Pitrou in :issue:`43356`.) threading @@ -1757,8 +1757,8 @@ Deprecated * :data:`~ssl.PROTOCOL_SSLv2`, :data:`~ssl.PROTOCOL_SSLv3`, :data:`~ssl.PROTOCOL_SSLv23`, :data:`~ssl.PROTOCOL_TLSv1`, :data:`~ssl.PROTOCOL_TLSv1_1`, :data:`~ssl.PROTOCOL_TLSv1_2`, and - :data:`~ssl.PROTOCOL_TLS` are deprecated in favor of - :data:`~ssl.PROTOCOL_TLS_CLIENT` and :data:`~ssl.PROTOCOL_TLS_SERVER` + :const:`~ssl.PROTOCOL_TLS` are deprecated in favor of + :const:`~ssl.PROTOCOL_TLS_CLIENT` and :const:`~ssl.PROTOCOL_TLS_SERVER` * :func:`~ssl.wrap_socket` is replaced by :meth:`ssl.SSLContext.wrap_socket` diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 5ff99fc2d3f616..0585eccf198e8d 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -690,7 +690,7 @@ enum * Added the :func:`~enum.global_enum` enum decorator, which adjusts :meth:`~object.__repr__` and :meth:`~object.__str__` to show values as members of their module rather than the enum class. - For example, ``'re.ASCII'`` for the :data:`~re.ASCII` member + For example, ``'re.ASCII'`` for the :const:`~re.ASCII` member of :class:`re.RegexFlag` rather than ``'RegexFlag.ASCII'``. * Enhanced :class:`~enum.Flag` to support @@ -1063,8 +1063,8 @@ threading * On Unix, if the ``sem_clockwait()`` function is available in the C library (glibc 2.30 and newer), the :meth:`threading.Lock.acquire` method now uses - the monotonic clock (:data:`time.CLOCK_MONOTONIC`) for the timeout, rather - than using the system clock (:data:`time.CLOCK_REALTIME`), to not be affected + the monotonic clock (:const:`time.CLOCK_MONOTONIC`) for the timeout, rather + than using the system clock (:const:`time.CLOCK_REALTIME`), to not be affected by system clock changes. (Contributed by Victor Stinner in :issue:`41710`.) @@ -1812,7 +1812,7 @@ Standard Library (Contributed by Serhiy Storchaka in :gh:`91760`.) * In the :mod:`re` module, the :func:`!re.template` function - and the corresponding :data:`!re.TEMPLATE` and :data:`!re.T` flags + and the corresponding :const:`!re.TEMPLATE` and :const:`!re.T` flags are deprecated, as they were undocumented and lacked an obvious purpose. They will be removed in Python 3.13. (Contributed by Serhiy Storchaka and Miro HronÄok in :gh:`92728`.) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 03d559e4553930..b4a3fd5c982916 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -555,7 +555,7 @@ calendar csv --- -* Add :data:`~csv.QUOTE_NOTNULL` and :data:`~csv.QUOTE_STRINGS` flags to +* Add :const:`~csv.QUOTE_NOTNULL` and :const:`~csv.QUOTE_STRINGS` flags to provide finer grained control of ``None`` and empty strings by :class:`~csv.writer` objects. @@ -612,7 +612,7 @@ math os -- -* Add :data:`os.PIDFD_NONBLOCK` to open a file descriptor +* Add :const:`os.PIDFD_NONBLOCK` to open a file descriptor for a process with :func:`os.pidfd_open` in non-blocking mode. (Contributed by Kumar Aditya in :gh:`93312`.) diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 7af0c0288376fd..504bbf6deda7ce 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -1666,9 +1666,9 @@ for secure (encrypted, authenticated) internet connections: algorithm" error. * The version of OpenSSL being used is now accessible using the module - attributes :data:`ssl.OPENSSL_VERSION` (a string), - :data:`ssl.OPENSSL_VERSION_INFO` (a 5-tuple), and - :data:`ssl.OPENSSL_VERSION_NUMBER` (an integer). + attributes :const:`ssl.OPENSSL_VERSION` (a string), + :const:`ssl.OPENSSL_VERSION_INFO` (a 5-tuple), and + :const:`ssl.OPENSSL_VERSION_NUMBER` (an integer). (Contributed by Antoine Pitrou in :issue:`8850`, :issue:`1589`, :issue:`8322`, :issue:`5639`, :issue:`4870`, :issue:`8484`, and :issue:`8321`.) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index f121652ba51cbc..b3f4e9ac743fb2 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -842,7 +842,7 @@ Builtin functions and types * :func:`open` gets a new *opener* parameter: the underlying file descriptor for the file object is then obtained by calling *opener* with (*file*, - *flags*). It can be used to use custom flags like :data:`os.O_CLOEXEC` for + *flags*). It can be used to use custom flags like :const:`os.O_CLOEXEC` for example. The ``'x'`` mode was added: open for exclusive creation, failing if the file already exists. * :func:`print`: added the *flush* keyword argument. If the *flush* keyword @@ -1127,7 +1127,7 @@ Features * If Python is compiled without threads, the C version automatically disables the expensive thread local context machinery. In this case, - the variable :data:`~decimal.HAVE_THREADS` is set to ``False``. + the variable :const:`~decimal.HAVE_THREADS` is set to ``False``. API changes ~~~~~~~~~~~ @@ -1576,8 +1576,8 @@ os -- * The :mod:`os` module has a new :func:`~os.pipe2` function that makes it - possible to create a pipe with :data:`~os.O_CLOEXEC` or - :data:`~os.O_NONBLOCK` flags set atomically. This is especially useful to + possible to create a pipe with :const:`~os.O_CLOEXEC` or + :const:`~os.O_NONBLOCK` flags set atomically. This is especially useful to avoid race conditions in multi-threaded programs. * The :mod:`os` module has a new :func:`~os.sendfile` function which provides @@ -1691,9 +1691,9 @@ os * Some platforms now support additional constants for the :func:`~os.lseek` function, such as ``os.SEEK_HOLE`` and ``os.SEEK_DATA``. -* New constants :data:`~os.RTLD_LAZY`, :data:`~os.RTLD_NOW`, - :data:`~os.RTLD_GLOBAL`, :data:`~os.RTLD_LOCAL`, :data:`~os.RTLD_NODELETE`, - :data:`~os.RTLD_NOLOAD`, and :data:`~os.RTLD_DEEPBIND` are available on +* New constants :const:`~os.RTLD_LAZY`, :const:`~os.RTLD_NOW`, + :const:`~os.RTLD_GLOBAL`, :const:`~os.RTLD_LOCAL`, :const:`~os.RTLD_NODELETE`, + :const:`~os.RTLD_NOLOAD`, and :const:`~os.RTLD_DEEPBIND` are available on platforms that support them. These are for use with the :func:`sys.setdlopenflags` function, and supersede the similar constants defined in :mod:`ctypes` and :mod:`DLFCN`. (Contributed by Victor Stinner @@ -1995,7 +1995,7 @@ subprocess Command strings can now be bytes objects on posix platforms. (Contributed by Victor Stinner in :issue:`8513`.) -A new constant :data:`~subprocess.DEVNULL` allows suppressing output in a +A new constant :const:`~subprocess.DEVNULL` allows suppressing output in a platform-independent fashion. (Contributed by Ross Lagerwall in :issue:`5870`.) diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 45bb91833a352b..d72163b249041a 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -775,7 +775,7 @@ of a given opcode and argument, information that is not otherwise available. doctest ------- -A new :ref:`option flag `, :data:`~doctest.FAIL_FAST`, halts +A new :ref:`option flag `, :const:`~doctest.FAIL_FAST`, halts test running as soon as the first failure is detected. (Contributed by R. David Murray and Daniel Urban in :issue:`16522`.) @@ -841,7 +841,7 @@ for example, if the file might have been changed and re-checked in less time than the resolution of a particular filesystem's file modification time field. (Contributed by Mark Levitt in :issue:`18149`.) -New module attribute :data:`~filecmp.DEFAULT_IGNORES` provides the list of +New module attribute :const:`~filecmp.DEFAULT_IGNORES` provides the list of directories that are used as the default value for the *ignore* parameter of the :func:`~filecmp.dircmp` function. (Contributed by Eli Bendersky in :issue:`15442`.) @@ -1189,7 +1189,7 @@ Windows). (Contributed by Brian Curtin in :issue:`11939`.) root on Windows. (Contributed by Tim Golden in :issue:`9035`.) :func:`os.open` supports two new flags on platforms that provide them, -:data:`~os.O_PATH` (un-opened file descriptor), and :data:`~os.O_TMPFILE` +:const:`~os.O_PATH` (un-opened file descriptor), and :const:`~os.O_TMPFILE` (unnamed temporary file; as of 3.4.0 release available only on Linux systems with a kernel version of 3.11 or newer that have uapi headers). (Contributed by Christian Heimes in :issue:`18673` and Benjamin Peterson, respectively.) @@ -1238,8 +1238,8 @@ plistlib stdlib serialization protocols, with new :func:`~plistlib.load`, :func:`~plistlib.dump`, :func:`~plistlib.loads`, and :func:`~plistlib.dumps` functions. (The older API is now deprecated.) In addition to the already -supported XML plist format (:data:`~plistlib.FMT_XML`), it also now supports -the binary plist format (:data:`~plistlib.FMT_BINARY`). (Contributed by Ronald +supported XML plist format (:const:`~plistlib.FMT_XML`), it also now supports +the binary plist format (:const:`~plistlib.FMT_BINARY`). (Contributed by Ronald Oussoren and others in :issue:`14455`.) @@ -1388,7 +1388,7 @@ try/except statement by code that only cares whether or not an error occurred. socket ------ -The socket module now supports the :data:`~socket.CAN_BCM` protocol on +The socket module now supports the :const:`~socket.CAN_BCM` protocol on platforms that support it. (Contributed by Brian Thorne in :issue:`15359`.) Socket objects have new methods to get or set their :ref:`inheritable flag @@ -1399,7 +1399,7 @@ The ``socket.AF_*`` and ``socket.SOCK_*`` constants are now enumeration values using the new :mod:`enum` module. This allows meaningful names to be printed during debugging, instead of integer "magic numbers". -The :data:`~socket.AF_LINK` constant is now available on BSD and OSX. +The :const:`~socket.AF_LINK` constant is now available on BSD and OSX. :func:`~socket.inet_pton` and :func:`~socket.inet_ntop` are now supported on Windows. (Contributed by Atsuo Ishimoto in :issue:`7171`.) @@ -1460,8 +1460,8 @@ Heimes in :issue:`18147`.) If OpenSSL 0.9.8 or later is available, :class:`~ssl.SSLContext` has a new attribute :attr:`~ssl.SSLContext.verify_flags` that can be used to control the certificate verification process by setting it to some combination of the new -constants :data:`~ssl.VERIFY_DEFAULT`, :data:`~ssl.VERIFY_CRL_CHECK_LEAF`, -:data:`~ssl.VERIFY_CRL_CHECK_CHAIN`, or :data:`~ssl.VERIFY_X509_STRICT`. +constants :const:`~ssl.VERIFY_DEFAULT`, :const:`~ssl.VERIFY_CRL_CHECK_LEAF`, +:const:`~ssl.VERIFY_CRL_CHECK_CHAIN`, or :const:`~ssl.VERIFY_X509_STRICT`. OpenSSL does not do any CRL verification by default. (Contributed by Christien Heimes in :issue:`8813`.) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 14b6425cea699e..86c2905e5fad91 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -478,7 +478,7 @@ not make an additional system call:: PEP 475: Retry system calls failing with EINTR ---------------------------------------------- -An :py:data:`errno.EINTR` error code is returned whenever a system call, that +An :py:const:`errno.EINTR` error code is returned whenever a system call, that is waiting for I/O, is interrupted by a signal. Previously, Python would raise :exc:`InterruptedError` in such cases. This meant that, when writing a Python application, the developer had two choices: @@ -527,7 +527,7 @@ by a signal: :func:`~os.writev`; * special cases: :func:`os.close` and :func:`os.dup2` now ignore - :py:data:`~errno.EINTR` errors; the syscall is not retried (see the PEP + :py:const:`~errno.EINTR` errors; the syscall is not retried (see the PEP for the rationale); * :mod:`select` functions: :func:`devpoll.poll() `, @@ -1498,7 +1498,7 @@ use ``/dev/urandom`` and avoiding failures due to potential file descriptor exhaustion. (Contributed by Victor Stinner in :issue:`22181`.) New :func:`~os.get_blocking` and :func:`~os.set_blocking` functions allow -getting and setting a file descriptor's blocking mode (:data:`~os.O_NONBLOCK`.) +getting and setting a file descriptor's blocking mode (:const:`~os.O_NONBLOCK`.) (Contributed by Victor Stinner in :issue:`22054`.) The :func:`~os.truncate` and :func:`~os.ftruncate` functions are now supported @@ -1783,7 +1783,7 @@ the TLS handshake. The new :meth:`SSLSocket.selected_alpn_protocol() ` returns the protocol that was selected during the TLS handshake. -The :data:`~ssl.HAS_ALPN` flag indicates whether ALPN support is present. +The :const:`~ssl.HAS_ALPN` flag indicates whether ALPN support is present. Other Changes @@ -2476,7 +2476,7 @@ Changes in the Python API in Python 3.5, all old ``.pyo`` files from previous versions of Python are invalid regardless of this PEP. -* The :mod:`socket` module now exports the :data:`~socket.CAN_RAW_FD_FRAMES` +* The :mod:`socket` module now exports the :const:`~socket.CAN_RAW_FD_FRAMES` constant on linux 3.6 and greater. * The :func:`ssl.cert_time_to_seconds` function now interprets the input time diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 07a65d264c4359..84b043856ed013 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -1404,7 +1404,7 @@ socket ------ The :func:`~socket.socket.ioctl` function now supports the -:data:`~socket.SIO_LOOPBACK_FAST_PATH` control code. +:const:`~socket.SIO_LOOPBACK_FAST_PATH` control code. (Contributed by Daniel Stokes in :issue:`26536`.) The :meth:`~socket.socket.getsockopt` constants ``SO_DOMAIN``, @@ -1416,7 +1416,7 @@ The :meth:`~socket.socket.setsockopt` now supports the (Contributed by Christian Heimes in :issue:`27744`.) The socket module now supports the address family -:data:`~socket.AF_ALG` to interface with Linux Kernel crypto API. ``ALG_*``, +:const:`~socket.AF_ALG` to interface with Linux Kernel crypto API. ``ALG_*``, ``SOL_ALG`` and :meth:`~socket.socket.sendmsg_afalg` were added. (Contributed by Christian Heimes in :issue:`27744` with support from Victor Stinner.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 28f22836d8d09e..eda8bf0137bffe 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -1280,13 +1280,13 @@ This function should be used instead of :func:`os.close` for better compatibility across platforms. (Contributed by Christian Heimes in :issue:`32454`.) -The :mod:`socket` module now exposes the :data:`socket.TCP_CONGESTION` -(Linux 2.6.13), :data:`socket.TCP_USER_TIMEOUT` (Linux 2.6.37), and -:data:`socket.TCP_NOTSENT_LOWAT` (Linux 3.12) constants. +The :mod:`socket` module now exposes the :const:`socket.TCP_CONGESTION` +(Linux 2.6.13), :const:`socket.TCP_USER_TIMEOUT` (Linux 2.6.37), and +:const:`socket.TCP_NOTSENT_LOWAT` (Linux 3.12) constants. (Contributed by Omar Sandoval in :issue:`26273` and Nathaniel J. Smith in :issue:`29728`.) -Support for :data:`socket.AF_VSOCK` sockets has been added to allow +Support for :const:`socket.AF_VSOCK` sockets has been added to allow communication between virtual machines and their hosts. (Contributed by Cathy Avery in :issue:`27584`.) @@ -1394,7 +1394,7 @@ subprocess The :func:`subprocess.run` function accepts the new *capture_output* keyword argument. When true, stdout and stderr will be captured. -This is equivalent to passing :data:`subprocess.PIPE` as *stdout* and +This is equivalent to passing :const:`subprocess.PIPE` as *stdout* and *stderr* arguments. (Contributed by Bo Bayles in :issue:`32102`.) @@ -1453,12 +1453,12 @@ time New clock identifiers have been added: -* :data:`time.CLOCK_BOOTTIME` (Linux): Identical to - :data:`time.CLOCK_MONOTONIC`, except it also includes any time that the +* :const:`time.CLOCK_BOOTTIME` (Linux): Identical to + :const:`time.CLOCK_MONOTONIC`, except it also includes any time that the system is suspended. -* :data:`time.CLOCK_PROF` (FreeBSD, NetBSD and OpenBSD): High-resolution +* :const:`time.CLOCK_PROF` (FreeBSD, NetBSD and OpenBSD): High-resolution per-process CPU timer. -* :data:`time.CLOCK_UPTIME` (FreeBSD, OpenBSD): Time whose absolute value is +* :const:`time.CLOCK_UPTIME` (FreeBSD, OpenBSD): Time whose absolute value is the time the system has been running and not suspended, providing accurate uptime measurement. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 61249d479fa044..ba3d86118b9262 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1305,7 +1305,7 @@ Zackery Spytz in :issue:`25451`.) time ---- -Added new clock :data:`~time.CLOCK_UPTIME_RAW` for macOS 10.12. +Added new clock :const:`~time.CLOCK_UPTIME_RAW` for macOS 10.12. (Contributed by Joannah Nanjekye in :issue:`35702`.) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 49c8bd2f3e07d5..36d942e8c064fb 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -427,8 +427,8 @@ digests. It skips MD5 on platforms that block MD5 digest. fcntl ----- -Added constants :data:`~fcntl.F_OFD_GETLK`, :data:`~fcntl.F_OFD_SETLK` -and :data:`~fcntl.F_OFD_SETLKW`. +Added constants :const:`~fcntl.F_OFD_GETLK`, :const:`~fcntl.F_OFD_SETLK` +and :const:`~fcntl.F_OFD_SETLKW`. (Contributed by Dong-hee Na in :issue:`38602`.) ftplib @@ -593,11 +593,11 @@ a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.) os -- -Added :data:`~os.CLD_KILLED` and :data:`~os.CLD_STOPPED` for :attr:`si_code`. +Added :const:`~os.CLD_KILLED` and :const:`~os.CLD_STOPPED` for :attr:`si_code`. (Contributed by Dong-hee Na in :issue:`38493`.) Exposed the Linux-specific :func:`os.pidfd_open` (:issue:`38692`) and -:data:`os.P_PIDFD` (:issue:`38713`) for process management with file +:const:`os.P_PIDFD` (:issue:`38713`) for process management with file descriptors. The :func:`os.unsetenv` function is now also available on Windows. @@ -669,11 +669,11 @@ a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.) socket ------ -The :mod:`socket` module now exports the :data:`~socket.CAN_RAW_JOIN_FILTERS` +The :mod:`socket` module now exports the :const:`~socket.CAN_RAW_JOIN_FILTERS` constant on Linux 4.1 and greater. (Contributed by Stefan Tatschner and Zackery Spytz in :issue:`25780`.) -The socket module now supports the :data:`~socket.CAN_J1939` protocol on +The socket module now supports the :const:`~socket.CAN_J1939` protocol on platforms that support it. (Contributed by Karl Ding in :issue:`40291`.) The socket module now has the :func:`socket.send_fds` and @@ -1084,7 +1084,7 @@ Changes in the Python API ``__VENV_PROMPT__`` is set to ``""``. * The :meth:`select.epoll.unregister` method no longer ignores the - :data:`~errno.EBADF` error. + :const:`~errno.EBADF` error. (Contributed by Victor Stinner in :issue:`39239`.) * The *compresslevel* parameter of :class:`bz2.BZ2File` became keyword-only, diff --git a/Misc/NEWS.d/3.10.0a1.rst b/Misc/NEWS.d/3.10.0a1.rst index 471811662644bf..f7eb8036bc5cf2 100644 --- a/Misc/NEWS.d/3.10.0a1.rst +++ b/Misc/NEWS.d/3.10.0a1.rst @@ -2176,7 +2176,7 @@ None. .. nonce: YoYoYo .. section: Library -Add a new :data:`os.RWF_APPEND` flag for :func:`os.pwritev`. +Add a new :const:`os.RWF_APPEND` flag for :func:`os.pwritev`. .. @@ -2304,7 +2304,7 @@ Restored the deprecated :mod:`xml.etree.cElementTree` module. .. nonce: ZCk0_c .. section: Library -:data:`~mmap.MAP_POPULATE` constant has now been added to the list of +:const:`~mmap.MAP_POPULATE` constant has now been added to the list of exported :mod:`mmap` module flags. .. diff --git a/Misc/NEWS.d/3.10.0a2.rst b/Misc/NEWS.d/3.10.0a2.rst index 061a82e90afd6b..eeb179a980bb8c 100644 --- a/Misc/NEWS.d/3.10.0a2.rst +++ b/Misc/NEWS.d/3.10.0a2.rst @@ -604,7 +604,7 @@ changes the working directory. PR by Anthony Sottile. .. nonce: 9wXTtY .. section: Library -The :mod:`shelve` module now uses :data:`pickle.DEFAULT_PROTOCOL` by default +The :mod:`shelve` module now uses :const:`pickle.DEFAULT_PROTOCOL` by default instead of :mod:`pickle` protocol ``3``. .. diff --git a/Misc/NEWS.d/3.10.0a6.rst b/Misc/NEWS.d/3.10.0a6.rst index 803df6f51ce628..313aa689254040 100644 --- a/Misc/NEWS.d/3.10.0a6.rst +++ b/Misc/NEWS.d/3.10.0a6.rst @@ -294,8 +294,8 @@ actual dictionary. This created problems for introspection tools. .. nonce: SwcSuU .. section: Library -Added :data:`~os.O_EVTONLY`, :data:`~os.O_FSYNC`, :data:`~os.O_SYMLINK` and -:data:`~os.O_NOFOLLOW_ANY` for macOS. Patch by Dong-hee Na. +Added :const:`~os.O_EVTONLY`, :const:`~os.O_FSYNC`, :const:`~os.O_SYMLINK` and +:const:`~os.O_NOFOLLOW_ANY` for macOS. Patch by Dong-hee Na. .. @@ -304,7 +304,7 @@ Added :data:`~os.O_EVTONLY`, :data:`~os.O_FSYNC`, :data:`~os.O_SYMLINK` and .. nonce: a7Dote .. section: Library -Adds :data:`resource.RLIMIT_KQUEUES` constant from FreeBSD to the +Adds :const:`resource.RLIMIT_KQUEUES` constant from FreeBSD to the :mod:`resource` module. .. diff --git a/Misc/NEWS.d/3.10.0a7.rst b/Misc/NEWS.d/3.10.0a7.rst index 286d0a8a7e9190..ff01ee645c0a90 100644 --- a/Misc/NEWS.d/3.10.0a7.rst +++ b/Misc/NEWS.d/3.10.0a7.rst @@ -713,7 +713,7 @@ this situation. Also ensures that the :func:`tempfile.gettempdir()` and .. section: Library Expose ``X509_V_FLAG_ALLOW_PROXY_CERTS`` as -:data:`~ssl.VERIFY_ALLOW_PROXY_CERTS` to allow proxy certificate validation +:const:`~ssl.VERIFY_ALLOW_PROXY_CERTS` to allow proxy certificate validation as explained in https://www.openssl.org/docs/man1.1.1/man7/proxy-certificates.html. diff --git a/Misc/NEWS.d/3.10.0b1.rst b/Misc/NEWS.d/3.10.0b1.rst index 38e0af17a2c66b..3c71bc73b812a1 100644 --- a/Misc/NEWS.d/3.10.0b1.rst +++ b/Misc/NEWS.d/3.10.0b1.rst @@ -871,7 +871,7 @@ assert_called_once_with) will unconditionally pass. .. nonce: -1XPDH .. section: Library -Add :data:`ssl.OP_IGNORE_UNEXPECTED_EOF` constants (OpenSSL 3.0.0) +Add :const:`ssl.OP_IGNORE_UNEXPECTED_EOF` constants (OpenSSL 3.0.0) .. diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index fb60ac55601022..a9ff21149a87d0 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -1468,8 +1468,8 @@ an installed expat library <= 2.2.0. On Unix, if the ``sem_clockwait()`` function is available in the C library (glibc 2.30 and newer), the :meth:`threading.Lock.acquire` method now uses -the monotonic clock (:data:`time.CLOCK_MONOTONIC`) for the timeout, rather -than using the system clock (:data:`time.CLOCK_REALTIME`), to not be +the monotonic clock (:const:`time.CLOCK_MONOTONIC`) for the timeout, rather +than using the system clock (:const:`time.CLOCK_REALTIME`), to not be affected by system clock changes. Patch by Victor Stinner. .. @@ -2087,8 +2087,8 @@ Upgrade bundled pip to 21.2.3 and setuptools to 57.4.0 .. section: Library Fix the :func:`os.set_inheritable` function on FreeBSD 14 for file -descriptor opened with the :data:`~os.O_PATH` flag: ignore the -:data:`~errno.EBADF` error on ``ioctl()``, fallback on the ``fcntl()`` +descriptor opened with the :const:`~os.O_PATH` flag: ignore the +:const:`~errno.EBADF` error on ``ioctl()``, fallback on the ``fcntl()`` implementation. Patch by Victor Stinner. .. diff --git a/Misc/NEWS.d/3.11.0a4.rst b/Misc/NEWS.d/3.11.0a4.rst index bcb6e8b7bdde31..3dd335929d655f 100644 --- a/Misc/NEWS.d/3.11.0a4.rst +++ b/Misc/NEWS.d/3.11.0a4.rst @@ -839,7 +839,7 @@ patch by Kumar Aditya. .. nonce: jeiPiX .. section: Library -Added :data:`signal.SIGSTKFLT` on platforms where this signal is defined. +Added :const:`signal.SIGSTKFLT` on platforms where this signal is defined. .. diff --git a/Misc/NEWS.d/3.11.0b1.rst b/Misc/NEWS.d/3.11.0b1.rst index d8c2ec0a799711..ad52bd14dbfd1d 100644 --- a/Misc/NEWS.d/3.11.0b1.rst +++ b/Misc/NEWS.d/3.11.0b1.rst @@ -817,8 +817,8 @@ it is ever needed and document the existing mechanism for ``posix_spawn()``. .. nonce: HFtERN .. section: Library -Fix :data:`signal.NSIG` value on FreeBSD to accept signal numbers greater -than 32, like :data:`signal.SIGRTMIN` and :data:`signal.SIGRTMAX`. Patch by +Fix :const:`signal.NSIG` value on FreeBSD to accept signal numbers greater +than 32, like :const:`signal.SIGRTMIN` and :const:`signal.SIGRTMAX`. Patch by Victor Stinner. .. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 9afeba25263514..5b6aff4d51fd61 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -736,7 +736,7 @@ new types. .. nonce: 6eoc8k .. section: Core and Builtins -On WASI :data:`~errno.ENOTCAPABLE` is now mapped to :exc:`PermissionError`. +On WASI :const:`~errno.ENOTCAPABLE` is now mapped to :exc:`PermissionError`. The :mod:`errno` modules exposes the new error number. ``getpath.py`` now ignores :exc:`PermissionError` when it cannot open landmark files ``pybuilddir.txt`` and ``pyenv.cfg``. @@ -2649,7 +2649,7 @@ calling any callbacks. Patch by Kumar Aditya. .. nonce: i807-g .. section: Library -Fail gracefully if :data:`~errno.EPERM` or :data:`~errno.ENOSYS` is raised +Fail gracefully if :const:`~errno.EPERM` or :const:`~errno.ENOSYS` is raised when loading :mod:`crypt` methods. This may happen when trying to load ``MD5`` on a Linux kernel with :abbr:`FIPS (Federal Information Processing Standard)` enabled. @@ -2698,8 +2698,8 @@ Upgrade bundled pip to 22.2. .. nonce: VT34A5 .. section: Library -Fix check for existence of :data:`os.EFD_CLOEXEC`, :data:`os.EFD_NONBLOCK` -and :data:`os.EFD_SEMAPHORE` flags on older kernel versions where these +Fix check for existence of :const:`os.EFD_CLOEXEC`, :const:`os.EFD_NONBLOCK` +and :const:`os.EFD_SEMAPHORE` flags on older kernel versions where these flags are not present. Patch by Kumar Aditya. .. @@ -3553,7 +3553,7 @@ Make :class:`multiprocessing.Pool` raise an exception if .. nonce: HY0Uzj .. section: Library -Add :data:`os.PIDFD_NONBLOCK` flag to open a file descriptor for a process +Add :const:`os.PIDFD_NONBLOCK` flag to open a file descriptor for a process with :func:`os.pidfd_open` in non-blocking mode. Patch by Kumar Aditya. .. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 5a3ccab02016f5..f781e38665a8ea 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -397,7 +397,7 @@ longobject.c to speed up some operations. .. nonce: nSGEkG .. section: Core and Builtins -Expose :data:`~socket.ETH_P_ALL` and some of the :ref:`ETHERTYPE_* constants +Expose :const:`~socket.ETH_P_ALL` and some of the :ref:`ETHERTYPE_* constants ` in :mod:`socket`. Patch by Noam Cohen. .. diff --git a/Misc/NEWS.d/3.12.0a3.rst b/Misc/NEWS.d/3.12.0a3.rst index 3d1e43350d136e..3e6f8de5d911f2 100644 --- a/Misc/NEWS.d/3.12.0a3.rst +++ b/Misc/NEWS.d/3.12.0a3.rst @@ -505,7 +505,7 @@ return True from this method; now they correctly return False. .. nonce: ZoOY5G .. section: Library -Add an :data:`~ssl.OP_ENABLE_KTLS` option for enabling the use of the kernel +Add an :const:`~ssl.OP_ENABLE_KTLS` option for enabling the use of the kernel TLS (kTLS). Patch by Illia Volochii. .. diff --git a/Misc/NEWS.d/3.12.0a4.rst b/Misc/NEWS.d/3.12.0a4.rst index dd26d4d964d6b7..8951490f41b94c 100644 --- a/Misc/NEWS.d/3.12.0a4.rst +++ b/Misc/NEWS.d/3.12.0a4.rst @@ -317,7 +317,7 @@ Improve performance of ``list.pop`` for small lists. .. nonce: yP4Na0 .. section: Core and Builtins -Add :data:`ssl.OP_LEGACY_SERVER_CONNECT` +Add :const:`ssl.OP_LEGACY_SERVER_CONNECT` .. @@ -356,7 +356,7 @@ arrays. .. nonce: mHRdQn .. section: Library -Add :data:`socket.IP_PKTINFO` constant. +Add :const:`socket.IP_PKTINFO` constant. .. diff --git a/Misc/NEWS.d/3.12.0a6.rst b/Misc/NEWS.d/3.12.0a6.rst index f6beb5b7ec3dbc..07967028bdee70 100644 --- a/Misc/NEWS.d/3.12.0a6.rst +++ b/Misc/NEWS.d/3.12.0a6.rst @@ -303,7 +303,7 @@ Kim. .. nonce: Vxz0Mr .. section: Library -Add :data:`mmap.MAP_ALIGNED_SUPER` FreeBSD and :data:`mmap.MAP_CONCEAL` +Add :const:`mmap.MAP_ALIGNED_SUPER` FreeBSD and :const:`mmap.MAP_CONCEAL` OpenBSD constants to :mod:`mmap`. Patch by Yeojin Kim. .. diff --git a/Misc/NEWS.d/3.12.0a7.rst b/Misc/NEWS.d/3.12.0a7.rst index 8f078e50823a00..1ef81747558857 100644 --- a/Misc/NEWS.d/3.12.0a7.rst +++ b/Misc/NEWS.d/3.12.0a7.rst @@ -605,7 +605,7 @@ reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on :class:`~ssl.SSLContext` also no longer includes -:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +:const:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to specify the previous OpenSSL 3.0 behavior. .. diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index 3de3b703e9f4f6..8cd88e9b0f55e2 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -842,7 +842,7 @@ filesystem case. .. section: Library Improve performance of :meth:`pathlib.Path.glob` by using -:data:`re.IGNORECASE` to implement case-insensitive matching. +:const:`re.IGNORECASE` to implement case-insensitive matching. .. @@ -1882,7 +1882,7 @@ both cases. .. nonce: 564i32 .. section: Library -Add :data:`~csv.QUOTE_STRINGS` and :data:`~csv.QUOTE_NOTNULL` to the suite +Add :const:`~csv.QUOTE_STRINGS` and :const:`~csv.QUOTE_NOTNULL` to the suite of :mod:`csv` module quoting styles. .. diff --git a/Misc/NEWS.d/3.6.0rc1.rst b/Misc/NEWS.d/3.6.0rc1.rst index 15769f950db239..658f8c902d8704 100644 --- a/Misc/NEWS.d/3.6.0rc1.rst +++ b/Misc/NEWS.d/3.6.0rc1.rst @@ -69,8 +69,8 @@ supported. .. nonce: ilNIWN .. section: Library -Add new :data:`socket.TCP_CONGESTION` (Linux 2.6.13) and -:data:`socket.TCP_USER_TIMEOUT` (Linux 2.6.37) constants. Patch written by +Add new :const:`socket.TCP_CONGESTION` (Linux 2.6.13) and +:const:`socket.TCP_USER_TIMEOUT` (Linux 2.6.37) constants. Patch written by Omar Sandoval. .. diff --git a/Misc/NEWS.d/3.7.0a1.rst b/Misc/NEWS.d/3.7.0a1.rst index ef93454784b77f..712558bf98d018 100644 --- a/Misc/NEWS.d/3.7.0a1.rst +++ b/Misc/NEWS.d/3.7.0a1.rst @@ -3274,7 +3274,7 @@ Added support for bytes paths in os.fwalk(). .. nonce: 37jMwb .. section: Library -Add new :data:`socket.TCP_NOTSENT_LOWAT` (Linux 3.12) constant. Patch by +Add new :const:`socket.TCP_NOTSENT_LOWAT` (Linux 3.12) constant. Patch by Nathaniel J. Smith. .. @@ -3871,8 +3871,8 @@ as an integer. Function only available on Android. .. nonce: ilNIWN .. section: Library -Add new :data:`socket.TCP_CONGESTION` (Linux 2.6.13) and -:data:`socket.TCP_USER_TIMEOUT` (Linux 2.6.37) constants. Patch written by +Add new :const:`socket.TCP_CONGESTION` (Linux 2.6.13) and +:const:`socket.TCP_USER_TIMEOUT` (Linux 2.6.37) constants. Patch written by Omar Sandoval. .. diff --git a/Misc/NEWS.d/3.7.0a3.rst b/Misc/NEWS.d/3.7.0a3.rst index 6576c1fadbff6d..92b0f328851208 100644 --- a/Misc/NEWS.d/3.7.0a3.rst +++ b/Misc/NEWS.d/3.7.0a3.rst @@ -754,8 +754,8 @@ now accepts characters as arguments. Based on patch by Steve Fink. .. nonce: DYQL0g .. section: Library -Add 3 new clock identifiers: :data:`time.CLOCK_BOOTTIME`, -:data:`time.CLOCK_PROF` and :data:`time.CLOCK_UPTIME`. +Add 3 new clock identifiers: :const:`time.CLOCK_BOOTTIME`, +:const:`time.CLOCK_PROF` and :const:`time.CLOCK_UPTIME`. .. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index 854458f2d1a994..a3bf6ff3c54b4e 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -1934,7 +1934,7 @@ failure. .. nonce: _ct_0H .. section: Library -The :data:`time.CLOCK_UPTIME_RAW` constant is now available for macOS 10.12. +The :const:`time.CLOCK_UPTIME_RAW` constant is now available for macOS 10.12. .. diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst index 9841195210c9e7..efe7b4d2ff0ddf 100644 --- a/Misc/NEWS.d/3.8.0a4.rst +++ b/Misc/NEWS.d/3.8.0a4.rst @@ -955,7 +955,7 @@ Add a new :mod:`_testinternalcapi` module to test the internal C API. .. section: Tests Fix ``test_imap4_host_default_value()`` of ``test_imaplib``: catch also -:data:`errno.ENETUNREACH` error. +:const:`errno.ENETUNREACH` error. .. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 7af7f2e4120534..5e6fa6759d5779 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -1164,7 +1164,7 @@ defines them with eponymous methods. .. nonce: bmhquU .. section: Library -Add :data:`os.P_PIDFD` constant, which may be passed to :func:`os.waitid` to +Add :const:`os.P_PIDFD` constant, which may be passed to :func:`os.waitid` to wait on a Linux process file descriptor. .. @@ -1193,8 +1193,8 @@ Expose the Linux ``pidfd_open`` syscall as :func:`os.pidfd_open`. .. nonce: 7jvYFA .. section: Library -Added constants :data:`~fcntl.F_OFD_GETLK`, :data:`~fcntl.F_OFD_SETLK` and -:data:`~fcntl.F_OFD_SETLKW` to the :mod:`fcntl` module. Patch by Dong-hee +Added constants :const:`~fcntl.F_OFD_GETLK`, :const:`~fcntl.F_OFD_SETLK` and +:const:`~fcntl.F_OFD_SETLKW` to the :mod:`fcntl` module. Patch by Dong-hee Na. .. @@ -1283,7 +1283,7 @@ Fixed erroneous equality comparison in statistics.NormalDist(). .. nonce: 86ExWB .. section: Library -Added :data:`~os.CLD_KILLED` and :data:`~os.CLD_STOPPED` for +Added :const:`~os.CLD_KILLED` and :const:`~os.CLD_STOPPED` for :attr:`si_code`. Patch by Dong-hee Na. .. @@ -1355,8 +1355,8 @@ objects, patch by Samuel Colvin. .. nonce: 9w-IGF .. section: Library -Add missing :data:`stat.S_IFDOOR`, :data:`stat.S_IFPORT`, -:data:`stat.S_IFWHT`, :func:`stat.S_ISDOOR`, :func:`stat.S_ISPORT`, and +Add missing :const:`stat.S_IFDOOR`, :const:`stat.S_IFPORT`, +:const:`stat.S_IFWHT`, :func:`stat.S_ISDOOR`, :func:`stat.S_ISPORT`, and :func:`stat.S_ISWHT` values to the Python implementation of :mod:`stat`. .. @@ -4983,7 +4983,7 @@ set to CP_UTF7 or CP_UTF8. .. nonce: -0g2O3 .. section: Windows -Make :data:`winreg.REG_MULTI_SZ` support zero-length strings. +Make :const:`winreg.REG_MULTI_SZ` support zero-length strings. .. diff --git a/Misc/NEWS.d/3.9.0a6.rst b/Misc/NEWS.d/3.9.0a6.rst index af2cc7c3e97889..fec792a998bf94 100644 --- a/Misc/NEWS.d/3.9.0a6.rst +++ b/Misc/NEWS.d/3.9.0a6.rst @@ -680,7 +680,7 @@ child process, reset the lock to the unlocked state. Rename also the private .. nonce: kIjVge .. section: Library -Expose :data:`~socket.CAN_RAW_JOIN_FILTERS` in the :mod:`socket` module. +Expose :const:`~socket.CAN_RAW_JOIN_FILTERS` in the :mod:`socket` module. .. @@ -735,7 +735,7 @@ number of groups. For other implementations, double the group list size. .. nonce: HFpHZS .. section: Library -Add :data:`time.CLOCK_TAI` constant if the operating system support it. +Add :const:`time.CLOCK_TAI` constant if the operating system support it. .. From ffc7678f4683a63180c1321334c76e9b3e09b0a5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Jul 2023 14:51:00 +0300 Subject: [PATCH 0388/1206] [3.12] gh-106892: Use roles :data: and :const: for referencing module variables (GH-106894) (GH-106954) (cherry picked from commit d036db728ea3d54509cbad06df74e2d9a31fbec8) --- Doc/c-api/import.rst | 6 ++--- Doc/library/__main__.rst | 4 ++-- Doc/library/asyncio-subprocess.rst | 4 ++-- Doc/library/compileall.rst | 4 ++-- Doc/library/devmode.rst | 2 +- Doc/library/filecmp.rst | 2 +- Doc/library/ftplib.rst | 2 +- Doc/library/functions.rst | 2 +- Doc/library/gc.rst | 2 +- Doc/library/gzip.rst | 2 +- Doc/library/importlib.resources.abc.rst | 2 +- Doc/library/importlib.rst | 18 +++++++------- Doc/library/json.rst | 6 ++--- Doc/library/logging.handlers.rst | 4 ++-- Doc/library/os.path.rst | 2 +- Doc/library/os.rst | 2 +- Doc/library/platform.rst | 2 +- Doc/library/shutil.rst | 2 +- Doc/library/stdtypes.rst | 2 +- Doc/library/subprocess.rst | 4 ++-- Doc/library/sys.rst | 10 ++++---- Doc/library/tarfile.rst | 10 ++++---- Doc/library/test.rst | 2 +- Doc/library/tkinter.rst | 2 +- Doc/library/unittest.rst | 4 ++-- Doc/reference/datamodel.rst | 4 ++-- Doc/using/windows.rst | 2 +- Doc/whatsnew/2.5.rst | 8 +++---- Doc/whatsnew/3.1.rst | 4 ++-- Doc/whatsnew/3.11.rst | 2 +- Doc/whatsnew/3.12.rst | 2 +- Doc/whatsnew/3.2.rst | 32 ++++++++++++------------- Doc/whatsnew/3.3.rst | 30 +++++++++++------------ Doc/whatsnew/3.4.rst | 14 +++++------ Doc/whatsnew/3.6.rst | 4 ++-- Doc/whatsnew/3.8.rst | 2 +- Doc/whatsnew/3.9.rst | 8 +++---- Misc/NEWS.d/3.12.0a1.rst | 2 +- Misc/NEWS.d/3.8.0a4.rst | 2 +- Misc/NEWS.d/3.9.0a5.rst | 4 ++-- 40 files changed, 111 insertions(+), 111 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 79843ba521ab93..d32c09ef06c9e7 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -126,9 +126,9 @@ Importing Modules read from a Python bytecode file or obtained from the built-in function :func:`compile`, load the module. Return a new reference to the module object, or ``NULL`` with an exception set if an error occurred. *name* - is removed from :attr:`sys.modules` in error cases, even if *name* was already - in :attr:`sys.modules` on entry to :c:func:`PyImport_ExecCodeModule`. Leaving - incompletely initialized modules in :attr:`sys.modules` is dangerous, as imports of + is removed from :data:`sys.modules` in error cases, even if *name* was already + in :data:`sys.modules` on entry to :c:func:`PyImport_ExecCodeModule`. Leaving + incompletely initialized modules in :data:`sys.modules` is dangerous, as imports of such modules have no way to know that the module object is an unknown (and probably damaged with respect to the module author's intents) state. diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index d29cbdff7830c8..fd60d92d4eb0f9 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -336,12 +336,12 @@ Note that importing ``__main__`` doesn't cause any issues with unintentionally running top-level code meant for script use which is put in the ``if __name__ == "__main__"`` block of the ``start`` module. Why does this work? -Python inserts an empty ``__main__`` module in :attr:`sys.modules` at +Python inserts an empty ``__main__`` module in :data:`sys.modules` at interpreter startup, and populates it by running top-level code. In our example this is the ``start`` module which runs line by line and imports ``namely``. In turn, ``namely`` imports ``__main__`` (which is really ``start``). That's an import cycle! Fortunately, since the partially populated ``__main__`` -module is present in :attr:`sys.modules`, Python passes that to ``namely``. +module is present in :data:`sys.modules`, Python passes that to ``namely``. See :ref:`Special considerations for __main__ ` in the import system's reference for details on how this works. diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst index afade9b0b50706..bf35b1cb798aee 100644 --- a/Doc/library/asyncio-subprocess.rst +++ b/Doc/library/asyncio-subprocess.rst @@ -68,7 +68,7 @@ Creating Subprocesses The *limit* argument sets the buffer limit for :class:`StreamReader` wrappers for :attr:`Process.stdout` and :attr:`Process.stderr` - (if :attr:`subprocess.PIPE` is passed to *stdout* and *stderr* arguments). + (if :const:`subprocess.PIPE` is passed to *stdout* and *stderr* arguments). Return a :class:`~asyncio.subprocess.Process` instance. @@ -86,7 +86,7 @@ Creating Subprocesses The *limit* argument sets the buffer limit for :class:`StreamReader` wrappers for :attr:`Process.stdout` and :attr:`Process.stderr` - (if :attr:`subprocess.PIPE` is passed to *stdout* and *stderr* arguments). + (if :const:`subprocess.PIPE` is passed to *stdout* and *stderr* arguments). Return a :class:`~asyncio.subprocess.Process` instance. diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst index 180f5b81c2b615..4226348a17240a 100644 --- a/Doc/library/compileall.rst +++ b/Doc/library/compileall.rst @@ -141,9 +141,9 @@ There is no command-line option to control the optimization level used by the :func:`compile` function, because the Python interpreter itself already provides the option: :program:`python -O -m compileall`. -Similarly, the :func:`compile` function respects the :attr:`sys.pycache_prefix` +Similarly, the :func:`compile` function respects the :data:`sys.pycache_prefix` setting. The generated bytecode cache will only be useful if :func:`compile` is -run with the same :attr:`sys.pycache_prefix` (if any) that will be used at +run with the same :data:`sys.pycache_prefix` (if any) that will be used at runtime. Public functions diff --git a/Doc/library/devmode.rst b/Doc/library/devmode.rst index 80ac13b116c1d2..914aa45cf9cbc3 100644 --- a/Doc/library/devmode.rst +++ b/Doc/library/devmode.rst @@ -81,7 +81,7 @@ Effects of the Python Development Mode: ignored for empty strings. * The :class:`io.IOBase` destructor logs ``close()`` exceptions. -* Set the :attr:`~sys.flags.dev_mode` attribute of :attr:`sys.flags` to +* Set the :attr:`~sys.flags.dev_mode` attribute of :data:`sys.flags` to ``True``. The Python Development Mode does not enable the :mod:`tracemalloc` module by diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst index 83e9e14ddcacd8..0efb4897a1eb86 100644 --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -74,7 +74,7 @@ The :class:`dircmp` class Construct a new directory comparison object, to compare the directories *a* and *b*. *ignore* is a list of names to ignore, and defaults to - :attr:`filecmp.DEFAULT_IGNORES`. *hide* is a list of names to hide, and + :const:`filecmp.DEFAULT_IGNORES`. *hide* is a list of names to hide, and defaults to ``[os.curdir, os.pardir]``. The :class:`dircmp` class compares files by doing *shallow* comparisons diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index cd6e2d38b02868..d1fe6414ea020c 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -431,7 +431,7 @@ FTP_TLS Objects .. attribute:: FTP_TLS.ssl_version - The SSL version to use (defaults to :attr:`ssl.PROTOCOL_SSLv23`). + The SSL version to use (defaults to :data:`ssl.PROTOCOL_SSLv23`). .. method:: FTP_TLS.auth() diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index d8091f0b093aab..2688f43f9b4ffc 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1231,7 +1231,7 @@ are always available. They are listed here in alphabetical order. * Binary files are buffered in fixed-size chunks; the size of the buffer is chosen using a heuristic trying to determine the underlying device's "block - size" and falling back on :attr:`io.DEFAULT_BUFFER_SIZE`. On many systems, + size" and falling back on :const:`io.DEFAULT_BUFFER_SIZE`. On many systems, the buffer will typically be 4096 or 8192 bytes long. * "Interactive" text files (files for which :meth:`~io.IOBase.isatty` diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index 0961ca4aaa9422..331c071cda7692 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -260,7 +260,7 @@ values but should not rebind them): .. versionchanged:: 3.4 Following :pep:`442`, objects with a :meth:`~object.__del__` method don't end - up in :attr:`gc.garbage` anymore. + up in :data:`gc.garbage` anymore. .. data:: callbacks diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 06cbd2567a0bc6..979b39a3a5abbc 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -268,7 +268,7 @@ Command line options .. cmdoption:: file - If *file* is not specified, read from :attr:`sys.stdin`. + If *file* is not specified, read from :data:`sys.stdin`. .. cmdoption:: --fast diff --git a/Doc/library/importlib.resources.abc.rst b/Doc/library/importlib.resources.abc.rst index 2d0f137ffc7996..b0e75737137f2c 100644 --- a/Doc/library/importlib.resources.abc.rst +++ b/Doc/library/importlib.resources.abc.rst @@ -130,7 +130,7 @@ suitable for reading (same as :attr:`pathlib.Path.open`). When opening as text, accepts encoding parameters such as those - accepted by :attr:`io.TextIOWrapper`. + accepted by :class:`io.TextIOWrapper`. .. method:: read_bytes() diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 65aaad0df9ee66..a14e5a1a1a350f 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -372,7 +372,7 @@ ABC hierarchy:: The list of locations where the package's submodules will be found. Most of the time this is a single directory. The import system passes this attribute to ``__import__()`` and to finders - in the same way as :attr:`sys.path` but just for the package. + in the same way as :data:`sys.path` but just for the package. It is not set on non-package modules so it can be used as an indicator that the module is a package. @@ -609,7 +609,7 @@ ABC hierarchy:: automatically. When writing to the path fails because the path is read-only - (:attr:`errno.EACCES`/:exc:`PermissionError`), do not propagate the + (:const:`errno.EACCES`/:exc:`PermissionError`), do not propagate the exception. .. versionchanged:: 3.4 @@ -843,7 +843,7 @@ find and load modules. .. classmethod:: path_hook(*loader_details) - A class method which returns a closure for use on :attr:`sys.path_hooks`. + A class method which returns a closure for use on :data:`sys.path_hooks`. An instance of :class:`FileFinder` is returned by the closure using the path argument given to the closure directly and *loader_details* indirectly. @@ -1184,10 +1184,10 @@ an :term:`importer`. .. function:: find_spec(name, package=None) Find the :term:`spec ` for a module, optionally relative to - the specified **package** name. If the module is in :attr:`sys.modules`, + the specified **package** name. If the module is in :data:`sys.modules`, then ``sys.modules[name].__spec__`` is returned (unless the spec would be ``None`` or is not set, in which case :exc:`ValueError` is raised). - Otherwise a search using :attr:`sys.meta_path` is done. ``None`` is + Otherwise a search using :data:`sys.meta_path` is done. ``None`` is returned if no spec is found. If **name** is for a submodule (contains a dot), the parent module is @@ -1259,7 +1259,7 @@ an :term:`importer`. :meth:`~importlib.abc.Loader.create_module` method must return ``None`` or a type for which its ``__class__`` attribute can be mutated along with not using :term:`slots <__slots__>`. Finally, modules which substitute the object - placed into :attr:`sys.modules` will not work as there is no way to properly + placed into :data:`sys.modules` will not work as there is no way to properly replace the module references throughout the interpreter safely; :exc:`ValueError` is raised if such a substitution is detected. @@ -1383,9 +1383,9 @@ For deep customizations of import, you typically want to implement an :term:`importer`. This means managing both the :term:`finder` and :term:`loader` side of things. For finders there are two flavours to choose from depending on your needs: a :term:`meta path finder` or a :term:`path entry finder`. The -former is what you would put on :attr:`sys.meta_path` while the latter is what -you create using a :term:`path entry hook` on :attr:`sys.path_hooks` which works -with :attr:`sys.path` entries to potentially create a finder. This example will +former is what you would put on :data:`sys.meta_path` while the latter is what +you create using a :term:`path entry hook` on :data:`sys.path_hooks` which works +with :data:`sys.path` entries to potentially create a finder. This example will show you how to register your own importers so that import will use them (for creating an importer for yourself, read the documentation for the appropriate classes defined within this package):: diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 5383614575c213..35a08995487c1b 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -683,7 +683,7 @@ The :mod:`json.tool` module provides a simple command line interface to validate and pretty-print JSON objects. If the optional ``infile`` and ``outfile`` arguments are not -specified, :attr:`sys.stdin` and :attr:`sys.stdout` will be used respectively: +specified, :data:`sys.stdin` and :data:`sys.stdout` will be used respectively: .. code-block:: shell-session @@ -721,12 +721,12 @@ Command line options } ] - If *infile* is not specified, read from :attr:`sys.stdin`. + If *infile* is not specified, read from :data:`sys.stdin`. .. cmdoption:: outfile Write the output of the *infile* to the given *outfile*. Otherwise, write it - to :attr:`sys.stdout`. + to :data:`sys.stdout`. .. cmdoption:: --sort-keys diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index d4429d3d0a4f73..47bfe4ff7f90ed 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -1051,8 +1051,8 @@ possible, while any potentially slow operations (such as sending an email via occur (e.g. because a bounded queue has filled up), the :meth:`~logging.Handler.handleError` method is called to handle the error. This can result in the record silently being dropped (if - :attr:`logging.raiseExceptions` is ``False``) or a message printed to - ``sys.stderr`` (if :attr:`logging.raiseExceptions` is ``True``). + :data:`logging.raiseExceptions` is ``False``) or a message printed to + ``sys.stderr`` (if :data:`logging.raiseExceptions` is ``True``). .. method:: prepare(record) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index 3a668e28f2e268..6f9e0853bc8947 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -410,7 +410,7 @@ the :mod:`glob` module.) *start*. On Windows, :exc:`ValueError` is raised when *path* and *start* are on different drives. - *start* defaults to :attr:`os.curdir`. + *start* defaults to :data:`os.curdir`. .. availability:: Unix, Windows. diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 76f797ac2c4cb4..127d1616388b3e 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -60,7 +60,7 @@ Notes on the availability of these functions: ``'java'``. .. seealso:: - :attr:`sys.platform` has a finer granularity. :func:`os.uname` gives + :data:`sys.platform` has a finer granularity. :func:`os.uname` gives system-dependent version information. The :mod:`platform` module provides detailed checks for the diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst index 69c4dfc422c98e..ec2a7ebd5d6e0b 100644 --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -46,7 +46,7 @@ Cross Platform universal files containing multiple architectures. To get at the "64-bitness" of the current interpreter, it is more - reliable to query the :attr:`sys.maxsize` attribute:: + reliable to query the :data:`sys.maxsize` attribute:: is_64bits = sys.maxsize > 2**32 diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 7f408be2336824..5bd80b10a65806 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -431,7 +431,7 @@ Directory and files operations determining if the file exists and executable. When no *path* is specified, the results of :func:`os.environ` are used, - returning either the "PATH" value or a fallback of :attr:`os.defpath`. + returning either the "PATH" value or a fallback of :data:`os.defpath`. On Windows, the current directory is prepended to the *path* if *mode* does not include ``os.X_OK``. When the *mode* does include ``os.X_OK``, the diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 092f2719379e8a..d0233e3f35394e 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -5629,7 +5629,7 @@ From code, you can inspect the current limit and set a new one using these a getter and setter for the interpreter-wide limit. Subinterpreters have their own limit. -Information about the default and minimum can be found in :attr:`sys.int_info`: +Information about the default and minimum can be found in :data:`sys.int_info`: * :data:`sys.int_info.default_max_str_digits ` is the compiled-in default limit. diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 738e611c05adbf..db05cb294d93f4 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -1610,7 +1610,7 @@ improves performance. If you ever encounter a presumed highly unusual situation where you need to prevent ``vfork()`` from being used by Python, you can set the -:attr:`subprocess._USE_VFORK` attribute to a false value. +:const:`subprocess._USE_VFORK` attribute to a false value. :: @@ -1618,7 +1618,7 @@ prevent ``vfork()`` from being used by Python, you can set the Setting this has no impact on use of ``posix_spawn()`` which could use ``vfork()`` internally within its libc implementation. There is a similar -:attr:`subprocess._USE_POSIX_SPAWN` attribute if you need to prevent use of +:const:`subprocess._USE_POSIX_SPAWN` attribute if you need to prevent use of that. :: diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 911d73b546b5cc..c01d2d45271526 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -166,7 +166,7 @@ always available. Python interpreter. (This information is not available in any other way --- ``modules.keys()`` only lists the imported modules.) - See also the :attr:`sys.stdlib_module_names` list. + See also the :data:`sys.stdlib_module_names` list. .. function:: call_tracing(func, args) @@ -1287,20 +1287,20 @@ always available. ================ =========================== .. versionchanged:: 3.3 - On Linux, :attr:`sys.platform` doesn't contain the major version anymore. + On Linux, :data:`sys.platform` doesn't contain the major version anymore. It is always ``'linux'``, instead of ``'linux2'`` or ``'linux3'``. Since older Python versions include the version number, it is recommended to always use the ``startswith`` idiom presented above. .. versionchanged:: 3.8 - On AIX, :attr:`sys.platform` doesn't contain the major version anymore. + On AIX, :data:`sys.platform` doesn't contain the major version anymore. It is always ``'aix'``, instead of ``'aix5'`` or ``'aix7'``. Since older Python versions include the version number, it is recommended to always use the ``startswith`` idiom presented above. .. seealso:: - :attr:`os.name` has a coarser granularity. :func:`os.uname` gives + :data:`os.name` has a coarser granularity. :func:`os.uname` gives system-dependent version information. The :mod:`platform` module provides detailed checks for the @@ -1743,7 +1743,7 @@ always available. ``email.mime`` sub-package and the ``email.message`` sub-module are not listed. - See also the :attr:`sys.builtin_module_names` list. + See also the :data:`sys.builtin_module_names` list. .. versionadded:: 3.10 diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 6a5947b788fdae..7a5bdaaf065fe4 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -933,7 +933,7 @@ reused in custom filters: Implements the ``'tar'`` filter. - - Strip leading slashes (``/`` and :attr:`os.sep`) from filenames. + - Strip leading slashes (``/`` and :data:`os.sep`) from filenames. - :ref:`Refuse ` to extract files with absolute paths (in case the name is absolute even after stripping slashes, e.g. ``C:/foo`` on Windows). @@ -942,7 +942,7 @@ reused in custom filters: path (after following symlinks) would end up outside the destination. This raises :class:`~tarfile.OutsideDestinationError`. - Clear high mode bits (setuid, setgid, sticky) and group/other write bits - (:attr:`~stat.S_IWGRP`|:attr:`~stat.S_IWOTH`). + (:const:`~stat.S_IWGRP`|:const:`~stat.S_IWOTH`). Return the modified ``TarInfo`` member. @@ -967,10 +967,10 @@ reused in custom filters: - For regular files, including hard links: - Set the owner read and write permissions - (:attr:`~stat.S_IRUSR`|:attr:`~stat.S_IWUSR`). + (:const:`~stat.S_IRUSR`|:const:`~stat.S_IWUSR`). - Remove the group & other executable permission - (:attr:`~stat.S_IXGRP`|:attr:`~stat.S_IXOTH`) - if the owner doesn’t have it (:attr:`~stat.S_IXUSR`). + (:const:`~stat.S_IXGRP`|:const:`~stat.S_IXOTH`) + if the owner doesn’t have it (:const:`~stat.S_IXUSR`). - For other files (directories), set ``mode`` to ``None``, so that extraction methods skip applying permission bits. diff --git a/Doc/library/test.rst b/Doc/library/test.rst index d69a3e326a411b..de60151bb32ce1 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1040,7 +1040,7 @@ The :mod:`test.support` module defines the following classes: `SetErrorMode `_. On UNIX, :func:`resource.setrlimit` is used to set - :attr:`resource.RLIMIT_CORE`'s soft limit to 0 to prevent coredump file + :const:`resource.RLIMIT_CORE`'s soft limit to 0 to prevent coredump file creation. On both platforms, the old value is restored by :meth:`__exit__`. diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index c8e4317be75879..2aa34422703872 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -163,7 +163,7 @@ the modern themed widget set and API:: interpreter and calls :func:`exec` on the contents of :file:`.{className}.py` and :file:`.{baseName}.py`. The path for the profile files is the :envvar:`HOME` environment variable or, if that - isn't defined, then :attr:`os.curdir`. + isn't defined, then :data:`os.curdir`. .. attribute:: tk diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index b26e6c0e6bc024..518bf6b13bad54 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1134,7 +1134,7 @@ Test cases If given, *level* should be either a numeric logging level or its string equivalent (for example either ``"ERROR"`` or - :attr:`logging.ERROR`). The default is :attr:`logging.INFO`. + :const:`logging.ERROR`). The default is :const:`logging.INFO`. The test passes if at least one message emitted inside the ``with`` block matches the *logger* and *level* conditions, otherwise it fails. @@ -1175,7 +1175,7 @@ Test cases If given, *level* should be either a numeric logging level or its string equivalent (for example either ``"ERROR"`` or - :attr:`logging.ERROR`). The default is :attr:`logging.INFO`. + :const:`logging.ERROR`). The default is :const:`logging.INFO`. Unlike :meth:`assertLogs`, nothing will be returned by the context manager. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index e8f9775dd33ce1..ce36bff89424cd 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2499,8 +2499,8 @@ through the object's keys; for sequences, it should iterate through the values. .. impl-detail:: - In CPython, the length is required to be at most :attr:`sys.maxsize`. - If the length is larger than :attr:`!sys.maxsize` some features (such as + In CPython, the length is required to be at most :data:`sys.maxsize`. + If the length is larger than :data:`!sys.maxsize` some features (such as :func:`len`) may raise :exc:`OverflowError`. To prevent raising :exc:`!OverflowError` by truth value testing, an object must define a :meth:`__bool__` method. diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 43e3c72f3e1cde..b7e4b2b48a6012 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -1201,7 +1201,7 @@ non-standard paths in the registry and user site-packages. Modules specified in the registry under ``Modules`` (not ``PythonPath``) may be imported by :class:`importlib.machinery.WindowsRegistryFinder`. This finder is enabled on Windows in 3.6.0 and earlier, but may need to - be explicitly added to :attr:`sys.meta_path` in the future. + be explicitly added to :data:`sys.meta_path` in the future. Additional modules ================== diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index dcfaef6ed29494..b410fe1ce3f084 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1448,10 +1448,10 @@ complete list of changes, or look through the SVN logs for all the details. return times that are precise to fractions of a second; not all systems support such precision.) - Constants named :attr:`os.SEEK_SET`, :attr:`os.SEEK_CUR`, and - :attr:`os.SEEK_END` have been added; these are the parameters to the + Constants named :const:`os.SEEK_SET`, :const:`os.SEEK_CUR`, and + :const:`os.SEEK_END` have been added; these are the parameters to the :func:`os.lseek` function. Two new constants for locking are - :attr:`os.O_SHLOCK` and :attr:`os.O_EXLOCK`. + :const:`os.O_SHLOCK` and :const:`os.O_EXLOCK`. Two new functions, :func:`wait3` and :func:`wait4`, were added. They're similar the :func:`waitpid` function which waits for a child process to exit and returns @@ -1602,7 +1602,7 @@ complete list of changes, or look through the SVN logs for all the details. * The :mod:`unicodedata` module has been updated to use version 4.1.0 of the Unicode character database. Version 3.2.0 is required by some specifications, - so it's still available as :attr:`unicodedata.ucd_3_2_0`. + so it's still available as :data:`unicodedata.ucd_3_2_0`. * New module: the :mod:`uuid` module generates universally unique identifiers (UUIDs) according to :rfc:`4122`. The RFC defines several different UUID diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst index fba8816bb243a3..e4365d44928b5b 100644 --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -370,7 +370,7 @@ New, Improved, and Deprecated Modules * The :mod:`io` module has three new constants for the :meth:`seek` method :data:`SEEK_SET`, :data:`SEEK_CUR`, and :data:`SEEK_END`. -* The :attr:`sys.version_info` tuple is now a named tuple:: +* The :data:`sys.version_info` tuple is now a named tuple:: >>> sys.version_info sys.version_info(major=3, minor=1, micro=0, releaselevel='alpha', serial=2) @@ -486,7 +486,7 @@ Changes to Python's build process and to the C API include: Apart from the performance improvements this change should be invisible to end users, with one exception: for testing and debugging purposes there's a - new :attr:`sys.int_info` that provides information about the + new :data:`sys.int_info` that provides information about the internal format, giving the number of bits per digit and the size in bytes of the C type used to store each digit:: diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 0585eccf198e8d..4d9aed0d0f9cd0 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -640,7 +640,7 @@ dataclasses datetime -------- -* Add :attr:`datetime.UTC`, a convenience alias for +* Add :const:`datetime.UTC`, a convenience alias for :attr:`datetime.timezone.utc`. (Contributed by Kabir Kwatra in :gh:`91973`.) * :meth:`datetime.date.fromisoformat`, :meth:`datetime.time.fromisoformat` and diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b4a3fd5c982916..9d05352f3b887b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1042,7 +1042,7 @@ Deprecated datetimes in UTC: respectively, call :meth:`~datetime.datetime.now` and :meth:`~datetime.datetime.fromtimestamp` with the *tz* parameter set to - :attr:`datetime.UTC`. + :const:`datetime.UTC`. (Contributed by Paul Ganssle in :gh:`103857`.) Pending Removal in Python 3.13 diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 504bbf6deda7ce..a42775804637e2 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -424,7 +424,7 @@ protocols, the users must to be able access the environment using native strings even though the underlying platform may have a different convention. To bridge this gap, the :mod:`wsgiref` module has a new function, :func:`wsgiref.handlers.read_environ` for transcoding CGI variables from -:attr:`os.environ` into native strings and returning a new dictionary. +:data:`os.environ` into native strings and returning a new dictionary. .. seealso:: @@ -485,7 +485,7 @@ Some smaller changes made to the core Python language are: * The interpreter can now be started with a quiet option, ``-q``, to prevent the copyright and version information from being displayed in the interactive - mode. The option can be introspected using the :attr:`sys.flags` attribute: + mode. The option can be introspected using the :data:`sys.flags` attribute: .. code-block:: shell-session @@ -568,7 +568,7 @@ Some smaller changes made to the core Python language are: * The internal :c:type:`structsequence` tool now creates subclasses of tuple. This means that C structures like those returned by :func:`os.stat`, - :func:`time.gmtime`, and :attr:`sys.version_info` now work like a + :func:`time.gmtime`, and :data:`sys.version_info` now work like a :term:`named tuple` and now work with functions and methods that expect a tuple as an argument. This is a big step forward in making the C structures as flexible as their pure Python counterparts: @@ -598,7 +598,7 @@ Some smaller changes made to the core Python language are: module, or on the command line. A :exc:`ResourceWarning` is issued at interpreter shutdown if the - :data:`gc.garbage` list isn't empty, and if :attr:`gc.DEBUG_UNCOLLECTABLE` is + :data:`gc.garbage` list isn't empty, and if :const:`gc.DEBUG_UNCOLLECTABLE` is set, all uncollectable objects are printed. This is meant to make the programmer aware that their code contains object finalization issues. @@ -623,7 +623,7 @@ Some smaller changes made to the core Python language are: :class:`collections.Sequence` :term:`abstract base class`. As a result, the language will have a more uniform API. In addition, :class:`range` objects now support slicing and negative indices, even with values larger than - :attr:`sys.maxsize`. This makes *range* more interoperable with lists:: + :data:`sys.maxsize`. This makes *range* more interoperable with lists:: >>> range(0, 100, 2).count(10) 1 @@ -1007,13 +1007,13 @@ datetime and time after 1900. The new supported year range is from 1000 to 9999 inclusive. * Whenever a two-digit year is used in a time tuple, the interpretation has been - governed by :attr:`time.accept2dyear`. The default is ``True`` which means that + governed by :data:`time.accept2dyear`. The default is ``True`` which means that for a two-digit year, the century is guessed according to the POSIX rules governing the ``%y`` strptime format. Starting with Py3.2, use of the century guessing heuristic will emit a :exc:`DeprecationWarning`. Instead, it is recommended that - :attr:`time.accept2dyear` be set to ``False`` so that large date ranges + :data:`time.accept2dyear` be set to ``False`` so that large date ranges can be used without guesswork:: >>> import time, warnings @@ -1031,7 +1031,7 @@ datetime and time 'Fri Jan 1 12:34:56 11' Several functions now have significantly expanded date ranges. When - :attr:`time.accept2dyear` is false, the :func:`time.asctime` function will + :data:`time.accept2dyear` is false, the :func:`time.asctime` function will accept any year that fits in a C int, while the :func:`time.mktime` and :func:`time.strftime` functions will accept the full range supported by the corresponding operating system functions. @@ -1194,11 +1194,11 @@ can be set to "$" for the shell-style formatting provided by If no configuration is set-up before a logging event occurs, there is now a default configuration using a :class:`~logging.StreamHandler` directed to -:attr:`sys.stderr` for events of ``WARNING`` level or higher. Formerly, an +:data:`sys.stderr` for events of ``WARNING`` level or higher. Formerly, an event occurring before a configuration was set-up would either raise an exception or silently drop the event depending on the value of -:attr:`logging.raiseExceptions`. The new default handler is stored in -:attr:`logging.lastResort`. +:data:`logging.raiseExceptions`. The new default handler is stored in +:data:`logging.lastResort`. The use of filters has been simplified. Instead of creating a :class:`~logging.Filter` object, the predicate can be any Python callable that @@ -1300,7 +1300,7 @@ values are equal (:issue:`8188`):: hash(Decimal("1.5")) == hash(complex(1.5, 0)) Some of the hashing details are exposed through a new attribute, -:attr:`sys.hash_info`, which describes the bit width of the hash value, the +:data:`sys.hash_info`, which describes the bit width of the hash value, the prime modulus, the hash values for *infinity* and *nan*, and the multiplier used for the imaginary part of a number: @@ -1388,7 +1388,7 @@ select ------ The :mod:`select` module now exposes a new, constant attribute, -:attr:`~select.PIPE_BUF`, which gives the minimum number of bytes which are +:const:`~select.PIPE_BUF`, which gives the minimum number of bytes which are guaranteed not to block when :func:`select.select` says a pipe is ready for writing. @@ -1529,7 +1529,7 @@ filenames: b'Sehensw\xc3\xbcrdigkeiten' Some operating systems allow direct access to encoded bytes in the -environment. If so, the :attr:`os.supports_bytes_environ` constant will be +environment. If so, the :const:`os.supports_bytes_environ` constant will be true. For direct access to encoded environment variables (if available), @@ -2302,7 +2302,7 @@ turtledemo The demonstration code for the :mod:`turtle` module was moved from the *Demo* directory to main library. It includes over a dozen sample scripts with -lively displays. Being on :attr:`sys.path`, it can now be run directly +lively displays. Being on :data:`sys.path`, it can now be run directly from the command-line: .. code-block:: shell-session @@ -2566,7 +2566,7 @@ Changes to Python's build process and to the C API include: (:issue:`2443`). * A new C API function :c:func:`PySys_SetArgvEx` allows an embedded interpreter - to set :attr:`sys.argv` without also modifying :attr:`sys.path` + to set :data:`sys.argv` without also modifying :data:`sys.path` (:issue:`5753`). * :c:macro:`PyEval_CallObject` is now only available in macro form. The diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index b3f4e9ac743fb2..765ba60d28c3a6 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -648,7 +648,7 @@ PEP 421: Adding sys.implementation A new attribute on the :mod:`sys` module exposes details specific to the implementation of the currently running interpreter. The initial set of -attributes on :attr:`sys.implementation` are ``name``, ``version``, +attributes on :data:`sys.implementation` are ``name``, ``version``, ``hexversion``, and ``cache_tag``. The intention of ``sys.implementation`` is to consolidate into one namespace @@ -719,7 +719,7 @@ and does not enforce any method requirements. In terms of finders, :class:`importlib.machinery.FileFinder` exposes the mechanism used to search for source and bytecode files of a module. Previously -this class was an implicit member of :attr:`sys.path_hooks`. +this class was an implicit member of :data:`sys.path_hooks`. For loaders, the new abstract base class :class:`importlib.abc.FileLoader` helps write a loader that uses the file system as the storage mechanism for a module's @@ -735,7 +735,7 @@ provide the full name of the module now instead of just the tail end of the module's name. The :func:`importlib.invalidate_caches` function will now call the method with -the same name on all finders cached in :attr:`sys.path_importer_cache` to help +the same name on all finders cached in :data:`sys.path_importer_cache` to help clean up any stored state as necessary. Visible Changes @@ -745,8 +745,8 @@ For potential required changes to code, see the `Porting Python code`_ section. Beyond the expanse of what :mod:`importlib` now exposes, there are other -visible changes to import. The biggest is that :attr:`sys.meta_path` and -:attr:`sys.path_hooks` now store all of the meta path finders and path entry +visible changes to import. The biggest is that :data:`sys.meta_path` and +:data:`sys.path_hooks` now store all of the meta path finders and path entry hooks used by import. Previously the finders were implicit and hidden within the C code of import instead of being directly exposed. This means that one can now easily remove or change the order of the various finders to fit one's needs. @@ -761,9 +761,9 @@ Loaders are also now expected to set the ``__package__`` attribute from :pep:`366`. Once again, import itself is already setting this on all loaders from :mod:`importlib` and import itself is setting the attribute post-load. -``None`` is now inserted into :attr:`sys.path_importer_cache` when no finder -can be found on :attr:`sys.path_hooks`. Since :class:`!imp.NullImporter` is not -directly exposed on :attr:`sys.path_hooks` it could no longer be relied upon to +``None`` is now inserted into :data:`sys.path_importer_cache` when no finder +can be found on :data:`sys.path_hooks`. Since :class:`!imp.NullImporter` is not +directly exposed on :data:`sys.path_hooks` it could no longer be relied upon to always be available to use as a value representing no finder found. All other changes relate to semantic changes which should be taken into @@ -1952,7 +1952,7 @@ ssl * You can query the SSL compression algorithm used by an SSL socket, thanks to its new :meth:`~ssl.SSLSocket.compression` method. The new attribute - :attr:`~ssl.OP_NO_COMPRESSION` can be used to disable compression. + :const:`~ssl.OP_NO_COMPRESSION` can be used to disable compression. (Contributed by Antoine Pitrou in :issue:`13634`.) * Support has been added for the Next Protocol Negotiation extension using @@ -1966,7 +1966,7 @@ ssl * The :func:`~ssl.get_server_certificate` function now supports IPv6. (Contributed by Charles-François Natali in :issue:`11811`.) -* New attribute :attr:`~ssl.OP_CIPHER_SERVER_PREFERENCE` allows setting +* New attribute :const:`~ssl.OP_CIPHER_SERVER_PREFERENCE` allows setting SSLv3 server sockets to use the server's cipher ordering preference rather than the client's (:issue:`13635`). @@ -2141,7 +2141,7 @@ New attribute :attr:`zlib.Decompress.eof` makes it possible to distinguish between a properly formed compressed stream and an incomplete or truncated one. (Contributed by Nadeem Vawda in :issue:`12646`.) -New attribute :attr:`zlib.ZLIB_RUNTIME_VERSION` reports the version string of +New attribute :const:`zlib.ZLIB_RUNTIME_VERSION` reports the version string of the underlying ``zlib`` library that is loaded at runtime. (Contributed by Torsten Landschoff in :issue:`12306`.) @@ -2378,16 +2378,16 @@ Porting Python code * :func:`__import__` no longer allows one to use an index value other than 0 for top-level modules. E.g. ``__import__('sys', level=1)`` is now an error. -* Because :attr:`sys.meta_path` and :attr:`sys.path_hooks` now have finders on +* Because :data:`sys.meta_path` and :data:`sys.path_hooks` now have finders on them by default, you will most likely want to use :meth:`list.insert` instead of :meth:`list.append` to add to those lists. -* Because ``None`` is now inserted into :attr:`sys.path_importer_cache`, if you +* Because ``None`` is now inserted into :data:`sys.path_importer_cache`, if you are clearing out entries in the dictionary of paths that do not have a finder, you will need to remove keys paired with values of ``None`` **and** :class:`!imp.NullImporter` to be backwards-compatible. This will lead to extra overhead on older versions of Python that re-insert ``None`` into - :attr:`sys.path_importer_cache` where it represents the use of implicit + :data:`sys.path_importer_cache` where it represents the use of implicit finders, but semantically it should not change anything. * :class:`!importlib.abc.Finder` no longer specifies a ``find_module()`` abstract @@ -2445,7 +2445,7 @@ Porting Python code error instead of sleeping forever. It has always raised an error on posix. * The ``ast.__version__`` constant has been removed. If you need to - make decisions affected by the AST version, use :attr:`sys.version_info` + make decisions affected by the AST version, use :data:`sys.version_info` to make the decision. * Code that used to work around the fact that the :mod:`threading` module used diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index d72163b249041a..acb662188b05ac 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -1323,14 +1323,14 @@ ability to query or set the resource limits for processes other than the one making the call. (Contributed by Christian Heimes in :issue:`16595`.) On Linux kernel version 2.6.36 or later, there are also some new -Linux specific constants: :attr:`~resource.RLIMIT_MSGQUEUE`, -:attr:`~resource.RLIMIT_NICE`, :attr:`~resource.RLIMIT_RTPRIO`, -:attr:`~resource.RLIMIT_RTTIME`, and :attr:`~resource.RLIMIT_SIGPENDING`. +Linux specific constants: :const:`~resource.RLIMIT_MSGQUEUE`, +:const:`~resource.RLIMIT_NICE`, :const:`~resource.RLIMIT_RTPRIO`, +:const:`~resource.RLIMIT_RTTIME`, and :const:`~resource.RLIMIT_SIGPENDING`. (Contributed by Christian Heimes in :issue:`19324`.) On FreeBSD version 9 and later, there some new FreeBSD specific constants: -:attr:`~resource.RLIMIT_SBSIZE`, :attr:`~resource.RLIMIT_SWAP`, and -:attr:`~resource.RLIMIT_NPTS`. (Contributed by Claudiu Popa in +:const:`~resource.RLIMIT_SBSIZE`, :const:`~resource.RLIMIT_SWAP`, and +:const:`~resource.RLIMIT_NPTS`. (Contributed by Claudiu Popa in :issue:`19343`.) @@ -1500,7 +1500,7 @@ implementation is required as most of the values aren't standardized and are platform-dependent. (Contributed by Christian Heimes in :issue:`11016`.) The module supports new :mod:`~stat.ST_MODE` flags, :mod:`~stat.S_IFDOOR`, -:attr:`~stat.S_IFPORT`, and :attr:`~stat.S_IFWHT`. (Contributed by +:const:`~stat.S_IFPORT`, and :const:`~stat.S_IFWHT`. (Contributed by Christian Hiemes in :issue:`11016`.) @@ -1849,7 +1849,7 @@ Python's default implementation to a SipHash implementation on platforms that have a 64 bit data type. Any performance differences in comparison with the older FNV algorithm are trivial. -The PEP adds additional fields to the :attr:`sys.hash_info` named tuple to +The PEP adds additional fields to the :data:`sys.hash_info` named tuple to describe the hash algorithm in use by the currently executing binary. Otherwise, the PEP does not alter any existing CPython APIs. diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 84b043856ed013..1093d24531505b 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -1388,7 +1388,7 @@ are treated as punctuation. site ---- -When specifying paths to add to :attr:`sys.path` in a ``.pth`` file, +When specifying paths to add to :data:`sys.path` in a ``.pth`` file, you may now specify file paths on top of directories (e.g. zip files). (Contributed by Wolfgang Langner in :issue:`26587`). @@ -2010,7 +2010,7 @@ been deprecated in previous versions of Python in favour of :meth:`importlib.abc.Loader.exec_module`. The :class:`importlib.machinery.WindowsRegistryFinder` class is now -deprecated. As of 3.6.0, it is still added to :attr:`sys.meta_path` by +deprecated. As of 3.6.0, it is still added to :data:`sys.meta_path` by default (on Windows), but this may change in future releases. os diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index ba3d86118b9262..5df2cef7e898aa 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1839,7 +1839,7 @@ Changes in Python behavior classes will affect their string representation. (Contributed by Serhiy Storchaka in :issue:`36793`.) -* On AIX, :attr:`sys.platform` doesn't contain the major version anymore. +* On AIX, :data:`sys.platform` doesn't contain the major version anymore. It is always ``'aix'``, instead of ``'aix3'`` .. ``'aix7'``. Since older Python versions include the version number, so it is recommended to always use ``sys.platform.startswith('aix')``. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 36d942e8c064fb..1f0fbbc2196664 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -692,13 +692,13 @@ which has nanosecond resolution, rather than sys --- -Added a new :attr:`sys.platlibdir` attribute: name of the platform-specific +Added a new :data:`sys.platlibdir` attribute: name of the platform-specific library directory. It is used to build the path of standard library and the paths of installed extension modules. It is equal to ``"lib"`` on most platforms. On Fedora and SuSE, it is equal to ``"lib64"`` on 64-bit platforms. (Contributed by Jan MatÄ›jek, MatÄ›j Cepl, Charalampos Stratakis and Victor Stinner in :issue:`1294959`.) -Previously, :attr:`sys.stderr` was block-buffered when non-interactive. Now +Previously, :data:`sys.stderr` was block-buffered when non-interactive. Now ``stderr`` defaults to always being line-buffered. (Contributed by Jendrik Seipp in :issue:`13601`.) @@ -1226,8 +1226,8 @@ Build Changes ============= * Added ``--with-platlibdir`` option to the ``configure`` script: name of the - platform-specific library directory, stored in the new :attr:`sys.platlibdir` - attribute. See :attr:`sys.platlibdir` attribute for more information. + platform-specific library directory, stored in the new :data:`sys.platlibdir` + attribute. See :data:`sys.platlibdir` attribute for more information. (Contributed by Jan MatÄ›jek, MatÄ›j Cepl, Charalampos Stratakis and Victor Stinner in :issue:`1294959`.) diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 5b6aff4d51fd61..d37ce84eadbcbb 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -4171,7 +4171,7 @@ Add an index_pages parameter to support using non-default index page names. .. nonce: qtT3CE .. section: Library -Drop support for :class:`bytes` on :attr:`sys.path`. +Drop support for :class:`bytes` on :data:`sys.path`. .. diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst index efe7b4d2ff0ddf..524a05a7ae9704 100644 --- a/Misc/NEWS.d/3.8.0a4.rst +++ b/Misc/NEWS.d/3.8.0a4.rst @@ -92,7 +92,7 @@ the field. .. nonce: wejLoC .. section: Core and Builtins -On AIX, :attr:`sys.platform` doesn't contain the major version anymore. +On AIX, :data:`sys.platform` doesn't contain the major version anymore. Always return ``'aix'``, instead of ``'aix3'`` .. ``'aix7'``. Since older Python versions include the version number, it is recommended to always use ``sys.platform.startswith('aix')``. Contributed by M. Felt. diff --git a/Misc/NEWS.d/3.9.0a5.rst b/Misc/NEWS.d/3.9.0a5.rst index 25342d21d8f0b1..8a1219501e81bf 100644 --- a/Misc/NEWS.d/3.9.0a5.rst +++ b/Misc/NEWS.d/3.9.0a5.rst @@ -582,7 +582,7 @@ Fix :mod:`json.tool` to catch :exc:`BrokenPipeError`. Patch by Dong-hee Na. Avoid a possible *"RuntimeError: dictionary changed size during iteration"* from :func:`inspect.getmodule` when it tried to loop through -:attr:`sys.modules`. +:data:`sys.modules`. .. @@ -989,7 +989,7 @@ modules are built. Add ``--with-platlibdir`` option to the configure script: name of the platform-specific library directory, stored in the new -:attr:`sys.platlibdir` attribute. It is used to build the path of +:data:`sys.platlibdir` attribute. It is used to build the path of platform-specific extension modules and the path of the standard library. It is equal to ``"lib"`` on most platforms. On Fedora and SuSE, it is equal to ``"lib64"`` on 64-bit platforms. Patch by Jan MatÄ›jek, MatÄ›j Cepl, From 957f14d0decb7aa5723d5ed8c4d16abad40547b0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 21 Jul 2023 13:27:52 -0700 Subject: [PATCH 0389/1206] [3.12] gh-105699: Fix a Crasher Related to a Deprecated Global Variable (gh-106923) (#106964) gh-105699: Fix a Crasher Related to a Deprecated Global Variable (gh-106923) There was a slight race in _Py_ClearFileSystemEncoding() (when called from _Py_SetFileSystemEncoding()), between freeing the value and setting the variable to NULL, which occasionally caused crashes when multiple isolated interpreters were used. (Notably, I saw at least 10 different, seemingly unrelated spooky-action-at-a-distance, ways this crashed. Yay, free threading!) We avoid the problem by only setting the global variables with the main interpreter (i.e. runtime init). (cherry picked from commit 0ba07b2108d4763273f3fb85544dde34c5acd40a) Co-authored-by: Eric Snow --- .../2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst | 4 ++++ Objects/unicodeobject.c | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst new file mode 100644 index 00000000000000..82312718cd047e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst @@ -0,0 +1,4 @@ +Python no longer crashes due to an infrequent race in setting +``Py_FileSystemDefaultEncoding`` and ``Py_FileSystemDefaultEncodeErrors`` +(both deprecated), when simultaneously initializing two isolated +subinterpreters. Now they are only set during runtime initialization. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index a0be85718119de..cd196f5b11cd9a 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -15177,10 +15177,13 @@ init_fs_codec(PyInterpreterState *interp) /* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors global configuration variables. */ - if (_Py_SetFileSystemEncoding(fs_codec->encoding, - fs_codec->errors) < 0) { - PyErr_NoMemory(); - return -1; + if (_Py_IsMainInterpreter(interp)) { + + if (_Py_SetFileSystemEncoding(fs_codec->encoding, + fs_codec->errors) < 0) { + PyErr_NoMemory(); + return -1; + } } return 0; } From d0176ed911e7c1717b21e276d1ff2c109e62356a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 21 Jul 2023 13:28:22 -0700 Subject: [PATCH 0390/1206] [3.12] gh-105699: Fix an Interned Strings Crasher (gh-106930) (#106963) gh-105699: Fix an Interned Strings Crasher (gh-106930) A static (process-global) str object must only have its "interned" state cleared when no longer interned in any interpreters. They are the only ones that can be shared by interpreters so we don't have to worry about any other str objects. We trigger clearing the state with the main interpreter, since no other interpreters may exist at that point and _PyUnicode_ClearInterned() is only called during interpreter finalization. We do not address here the fact that a string will only be interned in the first interpreter that interns it. In any subsequent interpreters str.state.interned is already set so _PyUnicode_InternInPlace() will skip it. That needs to be addressed separately from fixing the crasher. (cherry picked from commit 87e7cb09e4258c4deb01a07dc52c1021907195d7) Co-authored-by: Eric Snow --- .../2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst | 3 +++ Objects/unicodeobject.c | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst new file mode 100644 index 00000000000000..4a257c6282220f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst @@ -0,0 +1,3 @@ +Python no longer crashes due an infrequent race when initialzing +per-interpreter interned strings. The crash would manifest when the +interpreter was finalized. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index cd196f5b11cd9a..7ead65bf98d1f1 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14817,6 +14817,7 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) PyObject *s, *ignored_value; while (PyDict_Next(interned, &pos, &s, &ignored_value)) { assert(PyUnicode_IS_READY(s)); + int shared = 0; switch (PyUnicode_CHECK_INTERNED(s)) { case SSTATE_INTERNED_IMMORTAL: // Skip the Immortal Instance check and restore @@ -14828,6 +14829,14 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) #endif break; case SSTATE_INTERNED_IMMORTAL_STATIC: + /* It is shared between interpreters, so we should unmark it + only when this is the last interpreter in which it's + interned. We immortalize all the statically initialized + strings during startup, so we can rely on the + main interpreter to be the last one. */ + if (!_Py_IsMainInterpreter(interp)) { + shared = 1; + } break; case SSTATE_INTERNED_MORTAL: /* fall through */ @@ -14836,7 +14845,9 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) default: Py_UNREACHABLE(); } - _PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED; + if (!shared) { + _PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED; + } } #ifdef INTERNED_STATS fprintf(stderr, From 9cbde7c6ce6f7b93301a37f03dfa0c0d45e00a39 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 01:40:37 -0700 Subject: [PATCH 0391/1206] [3.12] gh-106973: Change non-integral to non-integer in "3.12 What's New" (GH-106984) (#106986) Co-authored-by: Sebastiaan Zeeff <33516116+SebastiaanZ@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 9d05352f3b887b..a119f77bdceb4e 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1455,7 +1455,7 @@ Changes in the Python API * Removed ``randrange()`` functionality deprecated since Python 3.10. Formerly, ``randrange(10.0)`` losslessly converted to ``randrange(10)``. Now, it raises a - :exc:`TypeError`. Also, the exception raised for non-integral values such as + :exc:`TypeError`. Also, the exception raised for non-integer values such as ``randrange(10.5)`` or ``randrange('10')`` has been changed from :exc:`ValueError` to :exc:`TypeError`. This also prevents bugs where ``randrange(1e25)`` would silently select from a larger range than ``randrange(10**25)``. From 67748f18c9b53def23f7614759fb632165f50d6a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 02:06:46 -0700 Subject: [PATCH 0392/1206] [3.12] gh-106970: Fix Argument Clinic 'destination clear' command (GH-106972) (#106983) Add test for the 'destination clear' command, and the 'destination' directive in general. Fix two bugs in 'destination clear' command: 1. The text attribute of the allocator is called 'text', not '_text' 2. Return after processing the 'clear' command, instead of proceeding directly to the fail(). (cherry picked from commit 3372bcba9893030e4063a9264ec0b4d1b6166883) Co-authored-by: Erlend E. Aasland --- Lib/test/clinic.test.c | 56 +++++++++++++++++++ Lib/test/test_clinic.py | 9 +++ ...-07-21-23-16-05.gh-issue-106970.NLRnml.rst | 4 ++ Tools/clinic/clinic.py | 16 +++--- 4 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 5748bbc71df5a8..04227e41a4d50c 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -4954,3 +4954,59 @@ Test_meth_coexist(TestObj *self, PyObject *Py_UNUSED(ignored)) static PyObject * Test_meth_coexist_impl(TestObj *self) /*[clinic end generated code: output=808a293d0cd27439 input=2a1d75b5e6fec6dd]*/ + + +/*[clinic input] +output push +output preset buffer +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=5bff3376ee0df0b5]*/ + +/*[clinic input] +buffer_clear + a: int +We'll call 'destination buffer clear' after this. + +Argument Clinic's buffer preset puts most generated code into the +'buffer' destination, except from 'impl_definition', which is put into +the 'block' destination, so we should expect everything but +'impl_definition' to be cleared. +[clinic start generated code]*/ + +static PyObject * +buffer_clear_impl(PyObject *module, int a) +/*[clinic end generated code: output=f14bba74677e1846 input=a4c308a6fdab043c]*/ + +/*[clinic input] +destination buffer clear +output pop +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f20d06adb8252084]*/ + + +/*[clinic input] +output push +destination test1 new buffer +output everything suppress +output docstring_definition test1 +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=5a77c454970992fc]*/ + +/*[clinic input] +new_dest + a: int +Only this docstring should be outputted to test1. +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=da5af421ed8996ed]*/ + +/*[clinic input] +dump test1 +output pop +[clinic start generated code]*/ + +PyDoc_STRVAR(new_dest__doc__, +"new_dest($module, /, a)\n" +"--\n" +"\n" +"Only this docstring should be outputted to test1."); +/*[clinic end generated code: output=9cac703f51d90e84 input=090db8df4945576d]*/ diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 7c725e33f53928..e40579b0041cf3 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -249,6 +249,15 @@ def test_cpp_monitor_fail_no_matching_if(self): out = self.expect_failure(raw) self.assertEqual(out, msg) + def test_unknown_destination_command(self): + out = self.expect_failure(""" + /*[clinic input] + destination buffer nosuchcommand + [clinic start generated code]*/ + """) + msg = "unknown destination command 'nosuchcommand'" + self.assertIn(msg, out) + class ClinicGroupPermuterTest(TestCase): def _test(self, l, m, r, output): diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst b/Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst new file mode 100644 index 00000000000000..194e3351b0470c --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst @@ -0,0 +1,4 @@ +Fix bugs in the Argument Clinic ``destination clear`` command; the +destination buffers would never be cleared, and the ``destination`` +directive parser would simply continue to the fault handler after processing +the command. Patch by Erlend E. Aasland. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 04951e97bbd808..3e60328082d66c 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1906,7 +1906,7 @@ def __getitem__(self, i): def clear(self): for ta in self._array: - ta._text.clear() + ta.text.clear() def dump(self): texts = [ta.output() for ta in self._array] @@ -4366,13 +4366,13 @@ def directive_destination( command: str, *args ) -> None: - if command == 'new': - self.clinic.add_destination(name, *args) - return - - if command == 'clear': - self.clinic.get_destination(name).clear() - fail("unknown destination command", repr(command)) + match command: + case "new": + self.clinic.add_destination(name, *args) + case "clear": + self.clinic.get_destination(name).clear() + case _: + fail("unknown destination command", repr(command)) def directive_output( From 76fd98a675d0c1a4f61735f9038e1f8282b60177 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 03:48:35 -0700 Subject: [PATCH 0393/1206] [3.12] gh-106368: Increase coverage for Argument Clinic output directive (GH-106979) (#106994) (cherry picked from commit ee5c01b473eeadb007b9f330db3143e34e46038b) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index e40579b0041cf3..c24b8cd3899f28 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -249,6 +249,59 @@ def test_cpp_monitor_fail_no_matching_if(self): out = self.expect_failure(raw) self.assertEqual(out, msg) + def test_directive_output_unknown_preset(self): + out = self.expect_failure(""" + /*[clinic input] + output preset nosuchpreset + [clinic start generated code]*/ + """) + msg = "Unknown preset 'nosuchpreset'" + self.assertIn(msg, out) + + def test_directive_output_cant_pop(self): + out = self.expect_failure(""" + /*[clinic input] + output pop + [clinic start generated code]*/ + """) + msg = "Can't 'output pop', stack is empty" + self.assertIn(msg, out) + + def test_directive_output_print(self): + raw = dedent(""" + /*[clinic input] + output print 'I told you once.' + [clinic start generated code]*/ + """) + out = self.clinic.parse(raw) + # The generated output will differ for every run, but we can check that + # it starts with the clinic block, we check that it contains all the + # expected fields, and we check that it contains the checksum line. + self.assertTrue(out.startswith(dedent(""" + /*[clinic input] + output print 'I told you once.' + [clinic start generated code]*/ + """))) + fields = { + "cpp_endif", + "cpp_if", + "docstring_definition", + "docstring_prototype", + "impl_definition", + "impl_prototype", + "methoddef_define", + "methoddef_ifndef", + "parser_definition", + "parser_prototype", + } + for field in fields: + with self.subTest(field=field): + self.assertIn(field, out) + last_line = out.rstrip().split("\n")[-1] + self.assertTrue( + last_line.startswith("/*[clinic end generated code: output=") + ) + def test_unknown_destination_command(self): out = self.expect_failure(""" /*[clinic input] From 713590f9b2bef0641511b5195bdbb4c9253e9b8c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 05:48:41 -0700 Subject: [PATCH 0394/1206] [3.12] gh-106714: Fix test_capi to not write a coredump (GH-107007) (#107009) gh-106714: Fix test_capi to not write a coredump (GH-107007) test_capi: Fix test_no_FatalError_infinite_loop() to no longer write a coredump, by using test.support.SuppressCrashReport. (cherry picked from commit 4a1026d7647c084b0dc80dd49163d16ba12a2e55) Co-authored-by: Victor Stinner --- Lib/test/test_capi/test_misc.py | 12 +++++++++--- .../2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 61947cb7945193..cd37fc71aa966e 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -85,9 +85,15 @@ def test_instancemethod(self): @support.requires_subprocess() def test_no_FatalError_infinite_loop(self): - run_result, _cmd_line = run_python_until_end( - '-c', 'import _testcapi; _testcapi.crash_no_current_thread()', - ) + code = textwrap.dedent(""" + import _testcapi + from test import support + + with support.SuppressCrashReport(): + _testcapi.crash_no_current_thread() + """) + + run_result, _cmd_line = run_python_until_end('-c', code) _rc, out, err = run_result self.assertEqual(out, b'') # This used to cause an infinite loop. diff --git a/Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst b/Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst new file mode 100644 index 00000000000000..955620521c8f68 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst @@ -0,0 +1,3 @@ +test_capi: Fix test_no_FatalError_infinite_loop() to no longer write a +coredump, by using test.support.SuppressCrashReport. Patch by Victor +Stinner. From e7757ab9e13b88a37c4490751782d010b0b44015 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 05:54:13 -0700 Subject: [PATCH 0395/1206] [3.12] Reformat code block to make it easier to read (GH-106965) (#107010) (cherry picked from commit ed491d9f782480fb00535abcf667027e0e323287) Co-authored-by: Joe Kaufeld --- Doc/tutorial/errors.rst | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 6419ff621f1b31..8a207c385c6ab7 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -535,11 +535,20 @@ of a certain type while letting all other exceptions propagate to other clauses and eventually to be reraised. :: >>> def f(): - ... raise ExceptionGroup("group1", - ... [OSError(1), - ... SystemError(2), - ... ExceptionGroup("group2", - ... [OSError(3), RecursionError(4)])]) + ... raise ExceptionGroup( + ... "group1", + ... [ + ... OSError(1), + ... SystemError(2), + ... ExceptionGroup( + ... "group2", + ... [ + ... OSError(3), + ... RecursionError(4) + ... ] + ... ) + ... ] + ... ) ... >>> try: ... f() From b6ace7516b032068a8b539a6b312c50bdde7c012 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 06:01:36 -0700 Subject: [PATCH 0396/1206] [3.12] gh-106989: Remove tok report warnings (GH-106993) (#107013) Co-authored-by: Menelaos Kotoglou --- Parser/tokenizer.c | 5 ----- Parser/tokenizer.h | 1 - 2 files changed, 6 deletions(-) diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 115b497cc24090..7e246d2f56481c 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -117,7 +117,6 @@ tok_new(void) tok->implicit_newline = 0; tok->tok_mode_stack[0] = (tokenizer_mode){.kind =TOK_REGULAR_MODE, .f_string_quote='\0', .f_string_quote_size = 0, .f_string_debug=0}; tok->tok_mode_stack_index = 0; - tok->tok_report_warnings = 1; #ifdef Py_DEBUG tok->debug = _Py_GetConfig()->parser_debug; #endif @@ -1546,10 +1545,6 @@ static int warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_char) { - if (!tok->tok_report_warnings) { - return 0; - } - PyObject *msg = PyUnicode_FromFormat( "invalid escape sequence '\\%c'", (char) first_invalid_escape_char diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index cb44845c1d306e..1e1daa3648f5d0 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -128,7 +128,6 @@ struct tok_state { // TODO: Factor this into its own thing tokenizer_mode tok_mode_stack[MAXFSTRINGLEVEL]; int tok_mode_stack_index; - int tok_report_warnings; int tok_extra_tokens; int comment_newline; int implicit_newline; From beb5e4fba7fa8118e47523999e1a129382984614 Mon Sep 17 00:00:00 2001 From: Sven Arends <88426829+picnic-sven@users.noreply.github.com> Date: Sat, 22 Jul 2023 15:41:38 +0200 Subject: [PATCH 0397/1206] [3.12] Bump sphinx-lint to 0.6.8 (gh-106978) (#107023) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d62c57c044728f..85a6de4abe0146 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: types_or: [c, python, rst] - repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v0.6.7 + rev: v0.6.8 hooks: - id: sphinx-lint args: [--enable=default-role] From c8a0296901f0266fad269306b56c66f3a9d5479d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 07:30:28 -0700 Subject: [PATCH 0398/1206] [3.12] gh-105090: Replace incorrect TLSv1.2 with TLSv1.3 (GH-105404) (#107040) Co-authored-by: Jocelyn Castellano --- Doc/library/ssl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 7f095526327685..1f8bbe1e3de3ee 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -2592,7 +2592,7 @@ disabled by default. >>> client_context.maximum_version = ssl.TLSVersion.TLSv1_3 -The SSL context created above will only allow TLSv1.2 and later (if +The SSL context created above will only allow TLSv1.3 and later (if supported by your system) connections to a server. :const:`PROTOCOL_TLS_CLIENT` implies certificate validation and hostname checks by default. You have to load certificates into the context. From 844bdce712574feb339c3f91696930a38ad656a9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 08:54:02 -0700 Subject: [PATCH 0399/1206] [3.12] Fix Sphinx warnings in `re` module docs (GH-107044) (#107046) Fix Sphinx warnings in `re` module docs (GH-107044) (cherry picked from commit 149748ea4f552e6fe43a1d6d69bd65910a7c4813) Co-authored-by: wulmer --- Doc/library/re.rst | 23 ++++++++++++++++++----- Doc/tools/.nitignore | 1 - 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index b7510b93d75427..629ee472cca681 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -501,6 +501,8 @@ The special characters are: in the ASCII range (``b'\x00'``-``b'\x7f'``). +.. _re-special-sequences: + The special sequences consist of ``'\'`` and a character from the list below. If the ordinary character is not an ASCII digit or an ASCII letter, then the resulting RE will match the second character. For example, ``\$`` matches the @@ -779,6 +781,17 @@ Flags Corresponds to the inline flag ``(?s)``. +.. data:: U + UNICODE + + In Python 2, this flag made :ref:`special sequences ` + include Unicode characters in matches. Since Python 3, Unicode characters + are matched by default. + + See :const:`A` for restricting matching on ASCII characters instead. + + This flag is only kept for backward compatibility. + .. data:: X VERBOSE @@ -1520,14 +1533,14 @@ Simulating scanf() .. index:: single: scanf() -Python does not currently have an equivalent to :c:func:`scanf`. Regular +Python does not currently have an equivalent to :c:func:`!scanf`. Regular expressions are generally more powerful, though also more verbose, than -:c:func:`scanf` format strings. The table below offers some more-or-less -equivalent mappings between :c:func:`scanf` format tokens and regular +:c:func:`!scanf` format strings. The table below offers some more-or-less +equivalent mappings between :c:func:`!scanf` format tokens and regular expressions. +--------------------------------+---------------------------------------------+ -| :c:func:`scanf` Token | Regular Expression | +| :c:func:`!scanf` Token | Regular Expression | +================================+=============================================+ | ``%c`` | ``.`` | +--------------------------------+---------------------------------------------+ @@ -1552,7 +1565,7 @@ To extract the filename and numbers from a string like :: /usr/sbin/sendmail - 0 errors, 4 warnings -you would use a :c:func:`scanf` format like :: +you would use a :c:func:`!scanf` format like :: %s - %d errors, %d warnings diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 3a34c0b2cbfff5..66b68305c5c69b 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -188,7 +188,6 @@ Doc/library/pyclbr.rst Doc/library/pydoc.rst Doc/library/pyexpat.rst Doc/library/random.rst -Doc/library/re.rst Doc/library/readline.rst Doc/library/reprlib.rst Doc/library/resource.rst From 3889d39471d626baf35b12511ba949a233a36106 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 11:12:58 -0700 Subject: [PATCH 0400/1206] [3.12] gh-107008: Document the curses module variables LINES and COLS (GH-107011) (GH-107057) LINES and COLS referred in curses.update_lines_cols() documentations are the module variables, not the environment variables. (cherry picked from commit 26e08dfdd7ac1b3d567d30cd35e4898121580390) Co-authored-by: Serhiy Storchaka --- Doc/library/curses.rst | 20 ++++++++++++++++++- Doc/whatsnew/3.5.rst | 4 ++-- ...-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst | 2 ++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index cf208f3ba0db36..391c81a844d3e0 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -641,7 +641,8 @@ The module :mod:`curses` defines the following functions: .. function:: update_lines_cols() - Update :envvar:`LINES` and :envvar:`COLS`. Useful for detecting manual screen resize. + Update the :const:`LINES` and :const:`COLS` module variables. + Useful for detecting manual screen resize. .. versionadded:: 3.5 @@ -1342,10 +1343,27 @@ The :mod:`curses` module defines the following data members: .. data:: COLORS The maximum number of colors the terminal can support. + It is defined only after the call to :func:`start_color`. .. data:: COLOR_PAIRS The maximum number of color pairs the terminal can support. + It is defined only after the call to :func:`start_color`. + +.. data:: COLS + + The width of the screen, i.e., the number of columns. + It is defined only after the call to :func:`initscr`. + Updated by :func:`update_lines_cols`, :func:`resizeterm` and + :func:`resize_term`. + +.. data:: LINES + + The height of the screen, i.e., the number of lines. + It is defined only after the call to :func:`initscr`. + Updated by :func:`update_lines_cols`, :func:`resizeterm` and + :func:`resize_term`. + Some constants are available to specify character cell attributes. The exact constants available are system dependent. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 86c2905e5fad91..83ce591c30ee6c 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -1045,8 +1045,8 @@ not just sequences. (Contributed by Serhiy Storchaka in :issue:`23171`.) curses ------ -The new :func:`~curses.update_lines_cols` function updates the :envvar:`LINES` -and :envvar:`COLS` environment variables. This is useful for detecting +The new :func:`~curses.update_lines_cols` function updates the :data:`LINES` +and :data:`COLS` module variables. This is useful for detecting manual screen resizing. (Contributed by Arnon Yaari in :issue:`4254`.) diff --git a/Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst b/Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst new file mode 100644 index 00000000000000..a0fa27ec10303e --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst @@ -0,0 +1,2 @@ +Document the :mod:`curses` module variables :const:`~curses.LINES` and +:const:`~curses.COLS`. From 0fff068181d1ad69907c06c1e0b30d5467a80f39 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 11:25:03 -0700 Subject: [PATCH 0401/1206] [3.12] gh-83006: Document behavior of `shutil.disk_usage` for non-mounted filesystems on Unix (GH-107031) (#107047) (cherry picked from commit 6e5f2235f3754307292c7d8d3698958136b5e311) Co-authored-by: Matthieu Caneill --- Doc/library/shutil.rst | 6 ++++++ .../Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 5bd80b10a65806..7699d22a72aaff 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -399,6 +399,12 @@ Directory and files operations total, used and free space, in bytes. *path* may be a file or a directory. + .. note:: + + On Unix filesystems, *path* must point to a path within a **mounted** + filesystem partition. On those platforms, CPython doesn't attempt to + retrieve disk usage information from non-mounted filesystems. + .. versionadded:: 3.3 .. versionchanged:: 3.8 diff --git a/Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst b/Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst new file mode 100644 index 00000000000000..e64d1860828430 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst @@ -0,0 +1,2 @@ +Document behavior of :func:`shutil.disk_usage` for non-mounted filesystems +on Unix. From dd431d791f2f6bd8b5746edec01ec402fe04345d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 14:11:29 -0700 Subject: [PATCH 0402/1206] [3.12] gh-107028: tiny textual changes in logging docs and docstrings (GH-107029) (GH-107065) (cherry picked from commit 5e5a34ac3a827e040cd89426b1774fec2123336a) --- Doc/library/logging.handlers.rst | 9 +++++---- Lib/logging/handlers.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 47bfe4ff7f90ed..72e5ffb3a1218e 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -917,8 +917,9 @@ should, then :meth:`flush` is expected to do the flushing. .. method:: flush() - You can override this to implement custom flushing behavior. This version - just zaps the buffer to empty. + For a :class:`BufferingHandler` instance, flushing means that it sets the + buffer to an empty list. This method can be overwritten to implement more useful + flushing behavior. .. method:: shouldFlush(record) @@ -950,9 +951,9 @@ should, then :meth:`flush` is expected to do the flushing. .. method:: flush() - For a :class:`MemoryHandler`, flushing means just sending the buffered + For a :class:`MemoryHandler` instance, flushing means just sending the buffered records to the target, if there is one. The buffer is also cleared when - this happens. Override if you want different behavior. + buffered records are sent to the target. Override if you want different behavior. .. method:: setTarget(target) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 9847104446eaf6..671cc9596b02dd 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1399,7 +1399,7 @@ def flush(self): records to the target, if there is one. Override if you want different behaviour. - The record buffer is also cleared by this operation. + The record buffer is only cleared if a target has been set. """ self.acquire() try: From bd907dcc50860d4730798ef48dcc30c165aa76c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 14:15:19 -0700 Subject: [PATCH 0403/1206] gh-106847: Add -X warn_default_encoding in sys.flags Doc (GH-106854) gh-106847: Add -X warn_default_encoding in sys.flags Doc (GH-106854) (cherry picked from commit fd84ac0ee0a8d5e34e0a106eed7e50539b61c5f8) Co-authored-by: qqwqqw689 <114795525+qqwqqw689@users.noreply.github.com> Co-authored-by: Nikita Sobolev --- Doc/library/sys.rst | 46 ++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index c01d2d45271526..f6b67dc57c1873 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -515,27 +515,28 @@ always available. The :term:`named tuple` *flags* exposes the status of command line flags. The attributes are read only. - ============================= ============================================================================================================== - attribute flag - ============================= ============================================================================================================== - :const:`debug` :option:`-d` - :const:`inspect` :option:`-i` - :const:`interactive` :option:`-i` - :const:`isolated` :option:`-I` - :const:`optimize` :option:`-O` or :option:`-OO` - :const:`dont_write_bytecode` :option:`-B` - :const:`no_user_site` :option:`-s` - :const:`no_site` :option:`-S` - :const:`ignore_environment` :option:`-E` - :const:`verbose` :option:`-v` - :const:`bytes_warning` :option:`-b` - :const:`quiet` :option:`-q` - :const:`hash_randomization` :option:`-R` - :const:`dev_mode` :option:`-X dev <-X>` (:ref:`Python Development Mode `) - :const:`utf8_mode` :option:`-X utf8 <-X>` - :const:`safe_path` :option:`-P` - :const:`int_max_str_digits` :option:`-X int_max_str_digits <-X>` (:ref:`integer string conversion length limitation `) - ============================= ============================================================================================================== + ============================== ============================================================================================================== + attribute flag + ============================== ============================================================================================================== + :const:`debug` :option:`-d` + :const:`inspect` :option:`-i` + :const:`interactive` :option:`-i` + :const:`isolated` :option:`-I` + :const:`optimize` :option:`-O` or :option:`-OO` + :const:`dont_write_bytecode` :option:`-B` + :const:`no_user_site` :option:`-s` + :const:`no_site` :option:`-S` + :const:`ignore_environment` :option:`-E` + :const:`verbose` :option:`-v` + :const:`bytes_warning` :option:`-b` + :const:`quiet` :option:`-q` + :const:`hash_randomization` :option:`-R` + :const:`dev_mode` :option:`-X dev <-X>` (:ref:`Python Development Mode `) + :const:`utf8_mode` :option:`-X utf8 <-X>` + :const:`safe_path` :option:`-P` + :const:`int_max_str_digits` :option:`-X int_max_str_digits <-X>` (:ref:`integer string conversion length limitation `) + :const:`warn_default_encoding` :option:`-X warn_default_encoding <-X>` + ============================== ============================================================================================================== .. versionchanged:: 3.2 Added ``quiet`` attribute for the new :option:`-q` flag. @@ -554,6 +555,9 @@ always available. Mode ` and the ``utf8_mode`` attribute for the new :option:`-X` ``utf8`` flag. + .. versionchanged:: 3.10 + Added ``warn_default_encoding`` attribute for :option:`-X` ``warn_default_encoding`` flag. + .. versionchanged:: 3.11 Added the ``safe_path`` attribute for :option:`-P` option. From 0d4a76654f755d091c14cfa1e57bcfa6333ae05a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 23 Jul 2023 00:20:38 +0200 Subject: [PATCH 0404/1206] [3.12] GH-103082: Rename PY_MONITORING_EVENTS to _PY_MONITORING_EVENTS (#107069) (#107075) GH-103082: Rename PY_MONITORING_EVENTS to _PY_MONITORING_EVENTS (#107069) Rename private C API constants: * Rename PY_MONITORING_UNGROUPED_EVENTS to _PY_MONITORING_UNGROUPED_EVENTS * Rename PY_MONITORING_EVENTS to _PY_MONITORING_EVENTS (cherry picked from commit 0927a2b25c059988e237108605ed8ab0c5459c53) --- Include/cpython/code.h | 6 ++--- Include/internal/pycore_interp.h | 4 ++-- Python/ceval.c | 2 +- Python/instrumentation.c | 38 ++++++++++++++++---------------- Python/pystate.c | 8 +++---- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 6bead361c79245..7449a98e4326e8 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -10,13 +10,13 @@ extern "C" { /* Count of all "real" monitoring events (not derived from other events) */ -#define PY_MONITORING_UNGROUPED_EVENTS 14 +#define _PY_MONITORING_UNGROUPED_EVENTS 14 /* Count of all monitoring events */ -#define PY_MONITORING_EVENTS 16 +#define _PY_MONITORING_EVENTS 16 /* Table of which tools are active for each monitored event. */ typedef struct _Py_Monitors { - uint8_t tools[PY_MONITORING_UNGROUPED_EVENTS]; + uint8_t tools[_PY_MONITORING_UNGROUPED_EVENTS]; } _Py_Monitors; /* Each instruction in a code object is a fixed-width value, diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 619225c939664e..6109e934098989 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -25,7 +25,7 @@ extern "C" { #include "pycore_gc.h" // struct _gc_runtime_state #include "pycore_global_objects.h" // struct _Py_interp_static_objects #include "pycore_import.h" // struct _import_state -#include "pycore_instruments.h" // PY_MONITORING_EVENTS +#include "pycore_instruments.h" // _PY_MONITORING_EVENTS #include "pycore_list.h" // struct _Py_list_state #include "pycore_object_state.h" // struct _py_object_state #include "pycore_obmalloc.h" // struct obmalloc_state @@ -188,7 +188,7 @@ struct _is { bool sys_trace_initialized; Py_ssize_t sys_profiling_threads; /* Count of threads with c_profilefunc set */ Py_ssize_t sys_tracing_threads; /* Count of threads with c_tracefunc set */ - PyObject *monitoring_callables[PY_MONITORING_TOOL_IDS][PY_MONITORING_EVENTS]; + PyObject *monitoring_callables[PY_MONITORING_TOOL_IDS][_PY_MONITORING_EVENTS]; PyObject *monitoring_tool_names[PY_MONITORING_TOOL_IDS]; struct _Py_interp_cached_objects cached_objects; diff --git a/Python/ceval.c b/Python/ceval.c index c883a903e964f8..72d679a4e3f537 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1997,7 +1997,7 @@ static int do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, int event) { - assert(event < PY_MONITORING_UNGROUPED_EVENTS); + assert(event < _PY_MONITORING_UNGROUPED_EVENTS); PyObject *exc = PyErr_GetRaisedException(); assert(exc != NULL); int err = _Py_call_instrumentation_arg(tstate, event, frame, instr, exc); diff --git a/Python/instrumentation.c b/Python/instrumentation.c index c70668e8295ae5..2fd3344b555a93 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -138,7 +138,7 @@ is_instrumented(int opcode) static inline bool monitors_equals(_Py_Monitors a, _Py_Monitors b) { - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { if (a.tools[i] != b.tools[i]) { return false; } @@ -151,7 +151,7 @@ static inline _Py_Monitors monitors_sub(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] & ~b.tools[i]; } return res; @@ -162,7 +162,7 @@ static inline _Py_Monitors monitors_and(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] & b.tools[i]; } return res; @@ -173,7 +173,7 @@ static inline _Py_Monitors monitors_or(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] | b.tools[i]; } return res; @@ -182,7 +182,7 @@ monitors_or(_Py_Monitors a, _Py_Monitors b) static inline bool monitors_are_empty(_Py_Monitors m) { - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { if (m.tools[i]) { return false; } @@ -193,7 +193,7 @@ monitors_are_empty(_Py_Monitors m) static inline bool multiple_tools(_Py_Monitors *m) { - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { if (_Py_popcount32(m->tools[i]) > 1) { return true; } @@ -205,7 +205,7 @@ static inline _PyMonitoringEventSet get_events(_Py_Monitors *m, int tool_id) { _PyMonitoringEventSet result = 0; - for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { + for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { if ((m->tools[e] >> tool_id) & 1) { result |= (1 << e); } @@ -340,7 +340,7 @@ static void dump_monitors(const char *prefix, _Py_Monitors monitors, FILE*out) { fprintf(out, "%s monitors:\n", prefix); - for (int event = 0; event < PY_MONITORING_UNGROUPED_EVENTS; event++) { + for (int event = 0; event < _PY_MONITORING_UNGROUPED_EVENTS; event++) { fprintf(out, " Event %d: Tools %x\n", event, monitors.tools[event]); } } @@ -910,7 +910,7 @@ get_tools_for_instruction(PyCodeObject * code, int i, int event) assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(instrumentation_cross_checks(PyThreadState_GET()->interp, code)); _PyCoMonitoringData *monitoring = code->_co_monitoring; - if (event >= PY_MONITORING_UNGROUPED_EVENTS) { + if (event >= _PY_MONITORING_UNGROUPED_EVENTS) { assert(event == PY_MONITORING_EVENT_C_RAISE || event == PY_MONITORING_EVENT_C_RETURN); event = PY_MONITORING_EVENT_CALL; @@ -1216,7 +1216,7 @@ _PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) { PyInterpreterState *is = _PyInterpreterState_Get(); assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); - assert(0 <= event_id && event_id < PY_MONITORING_EVENTS); + assert(0 <= event_id && event_id < _PY_MONITORING_EVENTS); PyObject *callback = is->monitoring_callables[tool_id][event_id]; is->monitoring_callables[tool_id][event_id] = Py_XNewRef(obj); return callback; @@ -1667,7 +1667,7 @@ static void set_events(_Py_Monitors *m, int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); - for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { + for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { uint8_t *tools = &m->tools[e]; int val = (events >> e) & 1; *tools &= ~(1 << tool_id); @@ -1692,7 +1692,7 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_Get(); - assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); + assert(events < (1 << _PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; } @@ -1710,7 +1710,7 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_Get(); - assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); + assert(events < (1 << _PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; } @@ -1849,7 +1849,7 @@ monitoring_register_callback_impl(PyObject *module, int tool_id, int event, return NULL; } int event_id = _Py_bit_length(event)-1; - if (event_id < 0 || event_id >= PY_MONITORING_EVENTS) { + if (event_id < 0 || event_id >= _PY_MONITORING_EVENTS) { PyErr_Format(PyExc_ValueError, "invalid event %d", event); return NULL; } @@ -1899,7 +1899,7 @@ monitoring_set_events_impl(PyObject *module, int tool_id, int event_set) if (check_valid_tool(tool_id)) { return NULL; } - if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { + if (event_set < 0 || event_set >= (1 << _PY_MONITORING_EVENTS)) { PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); return NULL; } @@ -1941,7 +1941,7 @@ monitoring_get_local_events_impl(PyObject *module, int tool_id, _PyMonitoringEventSet event_set = 0; _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring; if (data != NULL) { - for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { + for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { if ((data->local_monitors.tools[e] >> tool_id) & 1) { event_set |= (1 << e); } @@ -1975,7 +1975,7 @@ monitoring_set_local_events_impl(PyObject *module, int tool_id, if (check_valid_tool(tool_id)) { return NULL; } - if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { + if (event_set < 0 || event_set >= (1 << _PY_MONITORING_EVENTS)) { PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); return NULL; } @@ -2056,7 +2056,7 @@ monitoring__all_events_impl(PyObject *module) if (res == NULL) { return NULL; } - for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { + for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { uint8_t tools = interp->monitors.tools[e]; if (tools == 0) { continue; @@ -2115,7 +2115,7 @@ PyObject *_Py_CreateMonitoringObject(void) if (err) { goto error; } - for (int i = 0; i < PY_MONITORING_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_EVENTS; i++) { if (add_power2_constant(events, event_names[i], i)) { goto error; } diff --git a/Python/pystate.c b/Python/pystate.c index da0e1c42d7275f..e1261bf2acf958 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -678,11 +678,11 @@ init_interpreter(PyInterpreterState *interp, _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { interp->monitors.tools[i] = 0; } for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { - for (int e = 0; e < PY_MONITORING_EVENTS; e++) { + for (int e = 0; e < _PY_MONITORING_EVENTS; e++) { interp->monitoring_callables[t][e] = NULL; } @@ -832,11 +832,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) Py_CLEAR(interp->audit_hooks); - for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { interp->monitors.tools[i] = 0; } for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { - for (int e = 0; e < PY_MONITORING_EVENTS; e++) { + for (int e = 0; e < _PY_MONITORING_EVENTS; e++) { Py_CLEAR(interp->monitoring_callables[t][e]); } } From d87d67b9e65c38dd6d1d378a5c013eccf50756f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 22 Jul 2023 17:01:44 -0700 Subject: [PATCH 0405/1206] [3.12] gh-106962: Detect mpicc in configure.ac (GH-106961) (#107081) Don't let autoconf mistake MPI compilers for Intel compilers; filter out the MPI case to prevent Intel specific options from being applied. (cherry picked from commit 9a6b278769b9f24e0650283f6c347db8ae52b7b3) Co-authored-by: Lukas van de Wiel <30800501+LukasvdWiel@users.noreply.github.com> --- .../next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst | 1 + configure | 3 +++ configure.ac | 3 +++ 3 files changed, 7 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst diff --git a/Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst b/Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst new file mode 100644 index 00000000000000..32e196fe26d3b7 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst @@ -0,0 +1 @@ +Detect MPI compilers in :file:`configure`. diff --git a/configure b/configure index 91bf1d2c023702..3806da7723fdaf 100755 --- a/configure +++ b/configure @@ -10179,6 +10179,9 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ esac case "$CC" in +*mpicc*) + CFLAGS_NODIST="$CFLAGS_NODIST" + ;; *icc*) # ICC needs -fp-model strict or floats behave badly CFLAGS_NODIST="$CFLAGS_NODIST -fp-model strict" diff --git a/configure.ac b/configure.ac index 0770f68a23f61f..630db4bfbd53cc 100644 --- a/configure.ac +++ b/configure.ac @@ -2656,6 +2656,9 @@ yes) esac case "$CC" in +*mpicc*) + CFLAGS_NODIST="$CFLAGS_NODIST" + ;; *icc*) # ICC needs -fp-model strict or floats behave badly CFLAGS_NODIST="$CFLAGS_NODIST -fp-model strict" From 52804b38016d304754e3fc6fcfbb69d761176f00 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 01:59:16 -0700 Subject: [PATCH 0406/1206] [3.12] gh-102111: Add link to string escape sequences in re module (GH-106995) (#107096) Co-authored-by: wulmer Co-authored-by: Alex Waygood --- Doc/library/re.rst | 4 ++-- Doc/reference/lexical_analysis.rst | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 629ee472cca681..3f03f0341d8166 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -634,8 +634,8 @@ character ``'$'``. single: \x; in regular expressions single: \\; in regular expressions -Most of the standard escapes supported by Python string literals are also -accepted by the regular expression parser:: +Most of the :ref:`escape sequences ` supported by Python +string literals are also accepted by the regular expression parser:: \a \b \f \n \N \r \t \u diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 47062f86810e91..dde7ba1d941dce 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -549,6 +549,10 @@ retained), except that three unescaped quotes in a row terminate the literal. ( .. _escape-sequences: + +Escape sequences +^^^^^^^^^^^^^^^^ + Unless an ``'r'`` or ``'R'`` prefix is present, escape sequences in string and bytes literals are interpreted according to rules similar to those used by Standard C. The recognized escape sequences are: From a80721b83d6dceffdea9520832f68f0e1bcb82ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 02:01:24 -0700 Subject: [PATCH 0407/1206] [3.12] gh-71261: Add paragraph on shadowing submodules with star imports (GH-107004) (#107100) Co-authored-by: wulmer --- Doc/tutorial/modules.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index 3bd034bcc9703f..734dd1cfe6871a 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -512,6 +512,22 @@ code:: This would mean that ``from sound.effects import *`` would import the three named submodules of the :mod:`sound.effects` package. +Be aware that submodules might become shadowed by locally defined names. For +example, if you added a ``reverse`` function to the +:file:`sound/effects/__init__.py` file, the ``from sound.effects import *`` +would only import the two submodules ``echo`` and ``surround``, but *not* the +``reverse`` submodule, because it is shadowed by the locally defined +``reverse`` function:: + + __all__ = [ + "echo", # refers to the 'echo.py' file + "surround", # refers to the 'surround.py' file + "reverse", # !!! refers to the 'reverse' function now !!! + ] + + def reverse(msg: str): # <-- this name shadows the 'reverse.py' submodule + return msg[::-1] # in the case of a 'from sound.effects import *' + If ``__all__`` is not defined, the statement ``from sound.effects import *`` does *not* import all submodules from the package :mod:`sound.effects` into the current namespace; it only ensures that the package :mod:`sound.effects` has From 98626c3c71f88707d7297d18e01801f27192ab5c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 02:11:26 -0700 Subject: [PATCH 0408/1206] [3.12] gh-107017: removed mention that C does it the same way (GH-107020) (#107097) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub ÄŒervinka --- Doc/tutorial/controlflow.rst | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index e140f51f1dda78..138d87f892e891 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -4,8 +4,8 @@ More Control Flow Tools *********************** -Besides the :keyword:`while` statement just introduced, Python uses the usual -flow control statements known from other languages, with some twists. +As well as the :keyword:`while` statement just introduced, Python uses a few more +that we will encounter in this chapter. .. _tut-if: @@ -163,14 +163,21 @@ arguments. In chapter :ref:`tut-structures`, we will discuss in more detail abo :keyword:`!break` and :keyword:`!continue` Statements, and :keyword:`!else` Clauses on Loops ============================================================================================ -The :keyword:`break` statement, like in C, breaks out of the innermost enclosing +The :keyword:`break` statement breaks out of the innermost enclosing :keyword:`for` or :keyword:`while` loop. -Loop statements may have an :keyword:`!else` clause; it is executed when the loop -terminates through exhaustion of the iterable (with :keyword:`for`) or when the -condition becomes false (with :keyword:`while`), but not when the loop is -terminated by a :keyword:`break` statement. This is exemplified by the -following loop, which searches for prime numbers:: +A :keyword:`!for` or :keyword:`!while` loop can include an :keyword:`!else` clause. + +In a :keyword:`for` loop, the :keyword:`!else` clause is executed +after the loop reaches its final iteration. + +In a :keyword:`while` loop, it's executed after the loop's condition becomes false. + +In either kind of loop, the :keyword:`!else` clause is **not** executed +if the loop was terminated by a :keyword:`break`. + +This is exemplified in the following :keyword:`!for` loop, +which searches for prime numbers:: >>> for n in range(2, 10): ... for x in range(2, n): From 456cf8b0972bedf035c648fcd5e384ead937f9db Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Jul 2023 12:24:51 +0300 Subject: [PATCH 0409/1206] [3.12] gh-106948: Add standard external names to nitpick_ignore (GH-106949) (#107060) * [3.12] gh-106948: Add standard external names to nitpick_ignore (GH-106949) It includes standard C types, macros and variables like "size_t", "LONG_MAX" and "errno", and standard environment variables like "PATH". (cherry picked from commit f8b7fe2f2647813ae8249675a80e59c117d30fe1) Co-authored-by: Serhiy Storchaka * Delete 2023-05-31-18-37-57.gh-issue-105156.R4El5V.rst --- Doc/c-api/arg.rst | 2 +- Doc/c-api/memory.rst | 2 +- Doc/c-api/unicode.rst | 22 ++++---- Doc/c-api/veryhigh.rst | 2 +- Doc/conf.py | 52 +++++++++++++++++++ Doc/library/array.rst | 4 +- Doc/library/ctypes.rst | 12 ++--- Doc/library/os.rst | 2 +- Doc/library/struct.rst | 4 +- Doc/library/venv.rst | 6 +-- Doc/tools/.nitignore | 8 --- Doc/whatsnew/3.12.rst | 2 +- Doc/whatsnew/3.3.rst | 2 +- Doc/whatsnew/3.5.rst | 2 +- Doc/whatsnew/3.9.rst | 4 +- Misc/NEWS.d/3.10.0a5.rst | 2 +- Misc/NEWS.d/3.12.0a1.rst | 2 +- Misc/NEWS.d/3.12.0b1.rst | 2 +- ...-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst | 1 + 19 files changed, 89 insertions(+), 44 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index eba8f2be70b458..ea176bd7d6a51b 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -547,7 +547,7 @@ Building values Same as ``s#``. ``u`` (:class:`str`) [const wchar_t \*] - Convert a null-terminated :c:expr:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) + Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4) data to a Python Unicode object. If the Unicode buffer pointer is ``NULL``, ``None`` is returned. diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 35c356f25c6c70..4ca3b8804427f8 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -581,7 +581,7 @@ that the treatment of negative indices differs from a Python slice): default). A serial number, incremented by 1 on each call to a malloc-like or - realloc-like function. Big-endian ``size_t``. If "bad memory" is detected + realloc-like function. Big-endian :c:type:`size_t`. If "bad memory" is detected later, the serial number gives an excellent way to set a breakpoint on the next run, to capture the instant at which this block was passed out. The static function bumpserialno() in obmalloc.c is the only place the serial diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 8a989c2afe871c..957934c78595ec 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -44,7 +44,7 @@ Python: .. c:type:: Py_UNICODE - This is a typedef of :c:expr:`wchar_t`, which is a 16-bit type or 32-bit type + This is a typedef of :c:type:`wchar_t`, which is a 16-bit type or 32-bit type depending on the platform. .. versionchanged:: 3.3 @@ -444,11 +444,11 @@ APIs: +----------+-----------------------------------------------------+ | ``ll`` | :c:expr:`long long` or :c:expr:`unsigned long long` | +----------+-----------------------------------------------------+ - | ``j`` | :c:expr:`intmax_t` or :c:expr:`uintmax_t` | + | ``j`` | :c:type:`intmax_t` or :c:type:`uintmax_t` | +----------+-----------------------------------------------------+ - | ``z`` | :c:expr:`size_t` or :c:expr:`ssize_t` | + | ``z`` | :c:type:`size_t` or :c:type:`ssize_t` | +----------+-----------------------------------------------------+ - | ``t`` | :c:expr:`ptrdiff_t` | + | ``t`` | :c:type:`ptrdiff_t` | +----------+-----------------------------------------------------+ The length modifier ``l`` for following conversions ``s`` or ``V`` specify @@ -527,7 +527,7 @@ APIs: .. note:: The width formatter unit is number of characters rather than bytes. - The precision formatter unit is number of bytes or :c:expr:`wchar_t` + The precision formatter unit is number of bytes or :c:type:`wchar_t` items (if the length modifier ``l`` is used) for ``"%s"`` and ``"%V"`` (if the ``PyObject*`` argument is ``NULL``), and a number of characters for ``"%A"``, ``"%U"``, ``"%S"``, ``"%R"`` and ``"%V"`` @@ -846,11 +846,11 @@ conversion function: wchar_t Support """"""""""""""" -:c:expr:`wchar_t` support for platforms which support it: +:c:type:`wchar_t` support for platforms which support it: .. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) - Create a Unicode object from the :c:expr:`wchar_t` buffer *w* of the given *size*. + Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given *size*. Passing ``-1`` as the *size* indicates that the function must itself compute the length, using wcslen. Return ``NULL`` on failure. @@ -858,9 +858,9 @@ wchar_t Support .. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, Py_ssize_t size) - Copy the Unicode object contents into the :c:expr:`wchar_t` buffer *w*. At most - *size* :c:expr:`wchar_t` characters are copied (excluding a possibly trailing - null termination character). Return the number of :c:expr:`wchar_t` characters + Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most + *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing + null termination character). Return the number of :c:type:`wchar_t` characters copied or ``-1`` in case of an error. Note that the resulting :c:expr:`wchar_t*` string may or may not be null-terminated. It is the responsibility of the caller to make sure that the :c:expr:`wchar_t*` string is null-terminated in case this is @@ -874,7 +874,7 @@ wchar_t Support Convert the Unicode object to a wide character string. The output string always ends with a null character. If *size* is not ``NULL``, write the number of wide characters (excluding the trailing null termination character) into - *\*size*. Note that the resulting :c:expr:`wchar_t` string might contain + *\*size*. Note that the resulting :c:type:`wchar_t` string might contain null characters, which would cause the string to be truncated when used with most C functions. If *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters a :exc:`ValueError` is raised. diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 1e8a945512d78c..56fa2d6abd9139 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -17,7 +17,7 @@ parameter. The available start symbols are :c:data:`Py_eval_input`, following the functions which accept them as parameters. Note also that several of these functions take :c:expr:`FILE*` parameters. One -particular issue which needs to be handled carefully is that the :c:expr:`FILE` +particular issue which needs to be handled carefully is that the :c:type:`FILE` structure for different C libraries can be different and incompatible. Under Windows (at least), it is possible for dynamically linked extensions to actually use different libraries, so care should be taken that :c:expr:`FILE*` parameters diff --git a/Doc/conf.py b/Doc/conf.py index 485c0bdf84df2e..48d43736bfbc20 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -77,6 +77,58 @@ exclude_patterns.append(venvdir + '/*') nitpick_ignore = [ + # Standard C types + ('c:type', 'FILE'), + ('c:type', '__int'), + ('c:type', 'intmax_t'), + ('c:type', 'off_t'), + ('c:type', 'ptrdiff_t'), + ('c:type', 'siginfo_t'), + ('c:type', 'size_t'), + ('c:type', 'ssize_t'), + ('c:type', 'time_t'), + ('c:type', 'uintmax_t'), + ('c:type', 'va_list'), + ('c:type', 'wchar_t'), + # Standard C macros + ('c:macro', 'LLONG_MAX'), + ('c:macro', 'LLONG_MIN'), + ('c:macro', 'LONG_MAX'), + ('c:macro', 'LONG_MIN'), + # Standard C variables + ('c:data', 'errno'), + # Standard environment variables + ('envvar', 'BROWSER'), + ('envvar', 'COLUMNS'), + ('envvar', 'COMSPEC'), + ('envvar', 'DISPLAY'), + ('envvar', 'HOME'), + ('envvar', 'HOMEDRIVE'), + ('envvar', 'HOMEPATH'), + ('envvar', 'IDLESTARTUP'), + ('envvar', 'LANG'), + ('envvar', 'LANGUAGE'), + ('envvar', 'LC_ALL'), + ('envvar', 'LC_CTYPE'), + ('envvar', 'LC_COLLATE'), + ('envvar', 'LC_MESSAGES'), + ('envvar', 'LC_MONETARY'), + ('envvar', 'LC_NUMERIC'), + ('envvar', 'LC_TIME'), + ('envvar', 'LINES'), + ('envvar', 'LOGNAME'), + ('envvar', 'PAGER'), + ('envvar', 'PATH'), + ('envvar', 'PATHEXT'), + ('envvar', 'SOURCE_DATE_EPOCH'), + ('envvar', 'TEMP'), + ('envvar', 'TERM'), + ('envvar', 'TMP'), + ('envvar', 'TMPDIR'), + ('envvar', 'TZ'), + ('envvar', 'USER'), + ('envvar', 'USERNAME'), + ('envvar', 'USERPROFILE'), # Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot # be resolved, as the method is currently undocumented. For context, see # https://github.com/python/cpython/pull/103289. diff --git a/Doc/library/array.rst b/Doc/library/array.rst index 75c49e0f6d1ebe..d6cb8c623adbf1 100644 --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -51,9 +51,9 @@ Notes: It can be 16 bits or 32 bits depending on the platform. .. versionchanged:: 3.9 - ``array('u')`` now uses ``wchar_t`` as C type instead of deprecated + ``array('u')`` now uses :c:type:`wchar_t` as C type instead of deprecated ``Py_UNICODE``. This change doesn't affect its behavior because - ``Py_UNICODE`` is alias of ``wchar_t`` since Python 3.3. + ``Py_UNICODE`` is alias of :c:type:`wchar_t` since Python 3.3. .. deprecated-removed:: 3.3 4.0 diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 81509c0920bb6e..c253a45e1a8b54 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -220,7 +220,7 @@ Fundamental data types +----------------------+------------------------------------------+----------------------------+ | :class:`c_char` | :c:expr:`char` | 1-character bytes object | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_wchar` | :c:expr:`wchar_t` | 1-character string | +| :class:`c_wchar` | :c:type:`wchar_t` | 1-character string | +----------------------+------------------------------------------+----------------------------+ | :class:`c_byte` | :c:expr:`char` | int | +----------------------+------------------------------------------+----------------------------+ @@ -243,9 +243,9 @@ Fundamental data types | :class:`c_ulonglong` | :c:expr:`unsigned __int64` or | int | | | :c:expr:`unsigned long long` | | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_size_t` | :c:expr:`size_t` | int | +| :class:`c_size_t` | :c:type:`size_t` | int | +----------------------+------------------------------------------+----------------------------+ -| :class:`c_ssize_t` | :c:expr:`ssize_t` or | int | +| :class:`c_ssize_t` | :c:type:`ssize_t` or | int | | | :c:expr:`Py_ssize_t` | | +----------------------+------------------------------------------+----------------------------+ | :class:`c_time_t` | :c:type:`time_t` | int | @@ -335,7 +335,7 @@ property:: The :func:`create_string_buffer` function replaces the old :func:`c_buffer` function (which is still available as an alias). To create a mutable memory -block containing unicode characters of the C type :c:expr:`wchar_t`, use the +block containing unicode characters of the C type :c:type:`wchar_t`, use the :func:`create_unicode_buffer` function. @@ -478,7 +478,7 @@ By default functions are assumed to return the C :c:expr:`int` type. Other return types can be specified by setting the :attr:`restype` attribute of the function object. -The C prototype of ``time()`` is ``time_t time(time_t *)``. Because ``time_t`` +The C prototype of ``time()`` is ``time_t time(time_t *)``. Because :c:type:`time_t` might be of a different type than the default return type ``int``, you should specify the ``restype``:: @@ -2407,7 +2407,7 @@ These are the fundamental ctypes data types: .. class:: c_wchar - Represents the C :c:expr:`wchar_t` datatype, and interprets the value as a + Represents the C :c:type:`wchar_t` datatype, and interprets the value as a single character unicode string. The constructor accepts an optional string initializer, the length of the string must be exactly one character. diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 127d1616388b3e..57405916ed7b31 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -4650,7 +4650,7 @@ written in Python, such as a mail server's external command delivery program. :data:`WNOHANG` and :data:`WNOWAIT` are additional optional flags. The return value is an object representing the data contained in the - :c:type:`!siginfo_t` structure with the following attributes: + :c:type:`siginfo_t` structure with the following attributes: * :attr:`!si_pid` (process ID) * :attr:`!si_uid` (real user ID of the child) diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 6d2739b4557fbf..c94dfde4d55763 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -231,9 +231,9 @@ platform-dependent. | ``Q`` | :c:expr:`unsigned long | integer | 8 | \(2) | | | long` | | | | +--------+--------------------------+--------------------+----------------+------------+ -| ``n`` | :c:expr:`ssize_t` | integer | | \(3) | +| ``n`` | :c:type:`ssize_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ -| ``N`` | :c:expr:`size_t` | integer | | \(3) | +| ``N`` | :c:type:`size_t` | integer | | \(3) | +--------+--------------------------+--------------------+----------------+------------+ | ``e`` | \(6) | float | 2 | \(4) | +--------+--------------------------+--------------------+----------------+------------+ diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 9e5672545dea35..2482441d649790 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -60,7 +60,7 @@ running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory (``bin`` on POSIX; ``Scripts`` on Windows). -This will prepend that directory to your :envvar:`!PATH`, so that running +This will prepend that directory to your :envvar:`PATH`, so that running :program:`python` will invoke the environment's Python interpreter and you can run installed scripts without having to use their full path. The invocation of the activation script is platform-specific @@ -100,10 +100,10 @@ In order to achieve this, scripts installed into virtual environments have a "shebang" line which points to the environment's Python interpreter, i.e. :samp:`#!/{}/bin/python`. This means that the script will run with that interpreter regardless of the -value of :envvar:`!PATH`. On Windows, "shebang" line processing is supported if +value of :envvar:`PATH`. On Windows, "shebang" line processing is supported if you have the :ref:`launcher` installed. Thus, double-clicking an installed script in a Windows Explorer window should run it with the correct interpreter -without the environment needing to be activated or on the :envvar:`!PATH`. +without the environment needing to be activated or on the :envvar:`PATH`. When a virtual environment has been activated, the :envvar:`!VIRTUAL_ENV` environment variable is set to the path of the environment. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 66b68305c5c69b..0403cb34751ca8 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -100,7 +100,6 @@ Doc/library/codecs.rst Doc/library/codeop.rst Doc/library/collections.abc.rst Doc/library/collections.rst -Doc/library/compileall.rst Doc/library/concurrent.futures.rst Doc/library/concurrent.rst Doc/library/configparser.rst @@ -109,8 +108,6 @@ Doc/library/contextlib.rst Doc/library/copy.rst Doc/library/csv.rst Doc/library/ctypes.rst -Doc/library/curses.ascii.rst -Doc/library/curses.rst Doc/library/datetime.rst Doc/library/dbm.rst Doc/library/decimal.rst @@ -148,7 +145,6 @@ Doc/library/http.client.rst Doc/library/http.cookiejar.rst Doc/library/http.cookies.rst Doc/library/http.server.rst -Doc/library/idle.rst Doc/library/importlib.resources.abc.rst Doc/library/importlib.resources.rst Doc/library/importlib.rst @@ -179,11 +175,9 @@ Doc/library/pickletools.rst Doc/library/platform.rst Doc/library/plistlib.rst Doc/library/poplib.rst -Doc/library/posix.rst Doc/library/pprint.rst Doc/library/profile.rst Doc/library/pty.rst -Doc/library/py_compile.rst Doc/library/pyclbr.rst Doc/library/pydoc.rst Doc/library/pyexpat.rst @@ -206,7 +200,6 @@ Doc/library/ssl.rst Doc/library/stat.rst Doc/library/stdtypes.rst Doc/library/string.rst -Doc/library/struct.rst Doc/library/subprocess.rst Doc/library/sunau.rst Doc/library/sys.rst @@ -273,7 +266,6 @@ Doc/tutorial/modules.rst Doc/tutorial/stdlib2.rst Doc/using/cmdline.rst Doc/using/configure.rst -Doc/using/unix.rst Doc/using/windows.rst Doc/whatsnew/2.0.rst Doc/whatsnew/2.1.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a119f77bdceb4e..6d5fae1d6fcc61 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1768,7 +1768,7 @@ Porting to Python 3.12 for example). * Add support of more formatting options (left aligning, octals, uppercase - hexadecimals, ``intmax_t``, ``ptrdiff_t``, ``wchar_t`` C + hexadecimals, :c:type:`intmax_t`, :c:type:`ptrdiff_t`, :c:type:`wchar_t` C strings, variable width and precision) in :c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`. (Contributed by Serhiy Storchaka in :gh:`98836`.) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 765ba60d28c3a6..aaa4e873fddd8f 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1984,7 +1984,7 @@ the form '-rwxrwxrwx'. struct ------ -The :mod:`struct` module now supports ``ssize_t`` and ``size_t`` via the +The :mod:`struct` module now supports :c:type:`ssize_t` and :c:type:`size_t` via the new codes ``n`` and ``N``, respectively. (Contributed by Antoine Pitrou in :issue:`3163`.) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 83ce591c30ee6c..d23644b5093cb3 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -2192,7 +2192,7 @@ encode error with ``\N{...}`` escapes. (Contributed by Serhiy Storchaka in :issue:`19676`.) A new :c:func:`PyErr_FormatV` function similar to :c:func:`PyErr_Format`, -but accepts a ``va_list`` argument. +but accepts a :c:type:`va_list` argument. (Contributed by Antoine Pitrou in :issue:`18711`.) A new :c:data:`PyExc_RecursionError` exception. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 1f0fbbc2196664..23db4022dc06a0 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1115,9 +1115,9 @@ Changes in the Python API ``PyCF_ALLOW_TOP_LEVEL_AWAIT`` was clashing with ``CO_FUTURE_DIVISION``. (Contributed by Batuhan Taskaya in :issue:`39562`) -* ``array('u')`` now uses ``wchar_t`` as C type instead of ``Py_UNICODE``. +* ``array('u')`` now uses :c:type:`wchar_t` as C type instead of ``Py_UNICODE``. This change doesn't affect to its behavior because ``Py_UNICODE`` is alias - of ``wchar_t`` since Python 3.3. + of :c:type:`wchar_t` since Python 3.3. (Contributed by Inada Naoki in :issue:`34538`.) * The :func:`logging.getLogger` API now returns the root logger when passed diff --git a/Misc/NEWS.d/3.10.0a5.rst b/Misc/NEWS.d/3.10.0a5.rst index 497e3849171831..dc95e8ce072fd9 100644 --- a/Misc/NEWS.d/3.10.0a5.rst +++ b/Misc/NEWS.d/3.10.0a5.rst @@ -667,4 +667,4 @@ exception (if an exception is set). Patch by Victor Stinner. .. section: C API Fixed a compiler warning in :c:func:`Py_UNICODE_ISSPACE()` on platforms with -signed ``wchar_t``. +signed :c:type:`wchar_t`. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index d37ce84eadbcbb..ddd4b73275ec4b 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -5308,7 +5308,7 @@ parameter. Patch by Kumar Aditya. .. section: Build Python now always use the ``%zu`` and ``%zd`` printf formats to format a -``size_t`` or ``Py_ssize_t`` number. Building Python 3.12 requires a C11 +:c:type:`size_t` or ``Py_ssize_t`` number. Building Python 3.12 requires a C11 compiler, so these printf formats are now always supported. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index 8cd88e9b0f55e2..acb68db2db912b 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -2382,7 +2382,7 @@ Patch by Dong-hee Na. .. section: C API Add support of more formatting options (left aligning, octals, uppercase -hexadecimals, :c:expr:`intmax_t`, :c:expr:`ptrdiff_t`, :c:expr:`wchar_t` C +hexadecimals, :c:type:`intmax_t`, :c:type:`ptrdiff_t`, :c:type:`wchar_t` C strings, variable width and precision) in :c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`. diff --git a/Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst b/Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst new file mode 100644 index 00000000000000..42b6348153b56a --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst @@ -0,0 +1 @@ +Add a number of standard external names to ``nitpick_ignore``. From ac6b0fbdb870c002633bffc21d04e621abc962fb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 02:34:28 -0700 Subject: [PATCH 0410/1206] [3.12] gh-75371: reformat Makefile.pre.in to accommodate for empty FRAMEWORKALTINSTALLLAST (GH-107035) (#107049) gh-75371: reformat Makefile.pre.in to accommodate for empty FRAMEWORKALTINSTALLLAST (GH-107035) in the case of an empty FRAMEWORKALTINSTALLLAST, this patch prevents leaving an astray linebreak and two tabs in the resulting Makefile. Before change: ``` .PHONY: commoninstall commoninstall: check-clean-src \ altbininstall libinstall inclinstall libainstall \ sharedinstall altmaninstall \ ``` After change (with empty FRAMEWORKALTINSTALLLAST): ``` .PHONY: commoninstall commoninstall: check-clean-src \ altbininstall libinstall inclinstall libainstall \ sharedinstall altmaninstall ``` (cherry picked from commit 9c38206925246ab919cf558ac069ae9458720ba7) Co-authored-by: Moritz Neeb --- Makefile.pre.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 8dacb570ccafab..393eec7b8d324c 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1918,8 +1918,7 @@ altinstall: commoninstall .PHONY: commoninstall commoninstall: check-clean-src @FRAMEWORKALTINSTALLFIRST@ \ altbininstall libinstall inclinstall libainstall \ - sharedinstall altmaninstall \ - @FRAMEWORKALTINSTALLLAST@ + sharedinstall altmaninstall @FRAMEWORKALTINSTALLLAST@ # Install shared libraries enabled by Setup DESTDIRS= $(exec_prefix) $(LIBDIR) $(BINLIBDEST) $(DESTSHARED) From 1703262c0a7ee9307f7104900f024cfc5235d01d Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Sun, 23 Jul 2023 11:35:17 +0200 Subject: [PATCH 0411/1206] [3.12] Convert `doc.yml` workflow to be reusable (GH-103914 + GH-105151) (#107042) Co-authored-by: Sviatoslav Sydorenko Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade (cherry picked from commit 88d14da76f579fe014cbd7c15e42be4234135fe9) (cherry picked from commit eaa670228066220f08c8d73f80365c50058d40b8) --- .github/workflows/build.yml | 26 ++++++++++++++- .../workflows/{doc.yml => reusable-docs.yml} | 29 +++------------- Doc/tools/touch-clean-files.py | 33 +++++++++++++++---- 3 files changed, 56 insertions(+), 32 deletions(-) rename .github/workflows/{doc.yml => reusable-docs.yml} (89%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 197953b513f06f..d6504e6ca8cf3a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ permissions: contents: read concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-reusable cancel-in-progress: true jobs: @@ -37,6 +37,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 outputs: + run-docs: ${{ steps.docs-changes.outputs.run-docs || false }} run_tests: ${{ steps.check.outputs.run_tests }} run_hypothesis: ${{ steps.check.outputs.run_hypothesis }} config_hash: ${{ steps.config_hash.outputs.hash }} @@ -79,6 +80,29 @@ jobs: id: config_hash run: | echo "hash=${{ hashFiles('configure', 'configure.ac', '.github/workflows/build.yml') }}" >> $GITHUB_OUTPUT + - name: Get a list of the changed documentation-related files + if: github.event_name == 'pull_request' + id: changed-docs-files + uses: Ana06/get-changed-files@v2.2.0 + with: + filter: | + Doc/** + Misc/** + .github/workflows/reusable-docs.yml + format: csv # works for paths with spaces + - name: Check for docs changes + if: >- + github.event_name == 'pull_request' + && steps.changed-docs-files.outputs.added_modified_renamed != '' + id: docs-changes + run: | + echo "run-docs=true" >> "${GITHUB_OUTPUT}" + + check-docs: + name: Docs + needs: check_source + if: fromJSON(needs.check_source.outputs.run-docs) + uses: ./.github/workflows/reusable-docs.yml check_abi: name: 'Check if the ABI has changed' diff --git a/.github/workflows/doc.yml b/.github/workflows/reusable-docs.yml similarity index 89% rename from .github/workflows/doc.yml rename to .github/workflows/reusable-docs.yml index 3211b526efc7a5..b39d8cea6421ea 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/reusable-docs.yml @@ -1,31 +1,8 @@ name: Docs on: + workflow_call: workflow_dispatch: - #push: - # branches: - # - 'main' - # - '3.12' - # - '3.11' - # - '3.10' - # - '3.9' - # - '3.8' - # - '3.7' - # paths: - # - 'Doc/**' - pull_request: - branches: - - 'main' - - '3.12' - - '3.11' - - '3.10' - - '3.9' - - '3.8' - - '3.7' - paths: - - 'Doc/**' - - 'Misc/**' - - '.github/workflows/doc.yml' permissions: contents: read @@ -61,12 +38,14 @@ jobs: uses: Ana06/get-changed-files@v2.2.0 with: filter: "Doc/**" + format: csv # works for paths with spaces - name: 'Build changed files in nit-picky mode' if: github.event_name == 'pull_request' continue-on-error: true run: | + set -Eeuo pipefail # Mark files the pull request modified - touch ${{ steps.changed_files.outputs.added_modified }} + python Doc/tools/touch-clean-files.py --clean '${{ steps.changed_files.outputs.added_modified }}' # Build docs with the '-n' (nit-picky) option; convert warnings to annotations make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n --keep-going" html 2>&1 | python Doc/tools/warnings-to-gh-actions.py diff --git a/Doc/tools/touch-clean-files.py b/Doc/tools/touch-clean-files.py index 19bc1be31deb26..2b045bd68a0cf0 100644 --- a/Doc/tools/touch-clean-files.py +++ b/Doc/tools/touch-clean-files.py @@ -3,7 +3,9 @@ Touch files that must pass Sphinx nit-picky mode so they are rebuilt and we can catch regressions. """ - +import argparse +import csv +import sys from pathlib import Path wrong_directory_msg = "Must run this script from the repo root" @@ -28,14 +30,33 @@ rst for rst in Path("Doc/").rglob("*.rst") if rst.parts[1] not in EXCLUDE_SUBDIRS } -with Path("Doc/tools/.nitignore").open() as clean_files: - DIRTY = { + +parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument("-c", "--clean", help="Comma-separated list of clean files") +args = parser.parse_args() + +if args.clean: + clean_files = next(csv.reader([args.clean])) + CLEAN = { Path(filename.strip()) for filename in clean_files - if filename.strip() and not filename.startswith("#") + if Path(filename.strip()).is_file() } - -CLEAN = ALL_RST - DIRTY - EXCLUDE_FILES +elif args.clean is not None: + print( + "Not touching any files: an empty string `--clean` arg value passed.", + ) + sys.exit(0) +else: + with Path("Doc/tools/.nitignore").open() as ignored_files: + IGNORED = { + Path(filename.strip()) + for filename in ignored_files + if filename.strip() and not filename.startswith("#") + } + CLEAN = ALL_RST - IGNORED - EXCLUDE_FILES print("Touching:") for filename in sorted(CLEAN): From 63ae7edd3518ecc6364e51d1f2a5748d8fa36b85 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 02:36:10 -0700 Subject: [PATCH 0412/1206] [3.12] gh-54738: Add argparse i18n howto (GH-104562) (#107102) (cherry picked from commit dcd7acb04a719d8d30c8d03b80d3d48b6c035e14) Co-authored-by: Tomas R --- Doc/howto/argparse.rst | 53 +++++++++++++++++++ Doc/library/gettext.rst | 1 + ...3-05-16-22-08-24.gh-issue-54738.mJvCnj.rst | 1 + 3 files changed, 55 insertions(+) create mode 100644 Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst index 52e98fa9620194..ae5bab90bf8131 100644 --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -788,6 +788,59 @@ but not both at the same time: -q, --quiet +How to translate the argparse output +==================================== + +The output of the :mod:`argparse` module such as its help text and error +messages are all made translatable using the :mod:`gettext` module. This +allows applications to easily localize messages produced by +:mod:`argparse`. See also :ref:`i18n-howto`. + +For instance, in this :mod:`argparse` output: + +.. code-block:: shell-session + + $ python prog.py --help + usage: prog.py [-h] [-v | -q] x y + + calculate X to the power of Y + + positional arguments: + x the base + y the exponent + + options: + -h, --help show this help message and exit + -v, --verbose + -q, --quiet + +The strings ``usage:``, ``positional arguments:``, ``options:`` and +``show this help message and exit`` are all translatable. + +In order to translate these strings, they must first be extracted +into a ``.po`` file. For example, using `Babel `__, +run this command: + +.. code-block:: shell-session + + $ pybabel extract -o messages.po /usr/lib/python3.12/argparse.py + +This command will extract all translatable strings from the :mod:`argparse` +module and output them into a file named ``messages.po``. This command assumes +that your Python installation is in ``/usr/lib``. + +You can find out the location of the :mod:`argparse` module on your system +using this script:: + + import argparse + print(argparse.__file__) + +Once the messages in the ``.po`` file are translated and the translations are +installed using :mod:`gettext`, :mod:`argparse` will be able to display the +translated messages. + +To translate your own strings in the :mod:`argparse` output, use :mod:`gettext`. + Conclusion ========== diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index 747f8703b750ec..88a65b980d310f 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -411,6 +411,7 @@ One difference between this module and Henstridge's: his catalog objects supported access through a mapping API, but this appears to be unused and so is not currently supported. +.. _i18n-howto: Internationalizing your programs and modules -------------------------------------------- diff --git a/Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst b/Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst new file mode 100644 index 00000000000000..4da58fc982b6d7 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst @@ -0,0 +1 @@ +Add documentation on how to localize the :mod:`argparse` module. From a73d5c5e2e0529642adc896f9ae4d3987ec5374a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 02:44:39 -0700 Subject: [PATCH 0413/1206] [3.12] gh-106976: alphabetise bullets by module name task2-3 (GH-107005) (#107106) Co-authored-by: littlebutt's workshop Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 474 +++++++++++++++++++++--------------------- 1 file changed, 237 insertions(+), 237 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 6d5fae1d6fcc61..d1b10dbd1999dd 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -967,67 +967,76 @@ Demos and Tools Deprecated ========== -* :class:`typing.Hashable` and :class:`typing.Sized` aliases for :class:`collections.abc.Hashable` - and :class:`collections.abc.Sized`. (:gh:`94309`.) - -* The :mod:`sqlite3` :ref:`default adapters and converters - ` are now deprecated. - Instead, use the :ref:`sqlite3-adapter-converter-recipes` - and tailor them to your needs. - (Contributed by Erlend E. Aasland in :gh:`90016`.) - -* In :meth:`~sqlite3.Cursor.execute`, :exc:`DeprecationWarning` is now emitted - when :ref:`named placeholders ` are used together with - parameters supplied as a :term:`sequence` instead of as a :class:`dict`. - Starting from Python 3.14, using named placeholders with parameters supplied - as a sequence will raise a :exc:`~sqlite3.ProgrammingError`. - (Contributed by Erlend E. Aasland in :gh:`101698`.) - -* The 3-arg signatures (type, value, traceback) of :meth:`~coroutine.throw`, - :meth:`~generator.throw` and :meth:`~agen.athrow` are deprecated and - may be removed in a future version of Python. Use the single-arg versions - of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.) - -* :exc:`DeprecationWarning` is now raised when ``__package__`` on a - module differs from ``__spec__.parent`` (previously it was - :exc:`ImportWarning`). - (Contributed by Brett Cannon in :gh:`65961`.) - -* The :meth:`~asyncio.get_event_loop` method of the +* :mod:`asyncio`: The :meth:`~asyncio.get_event_loop` method of the default event loop policy now emits a :exc:`DeprecationWarning` if there is no current event loop set and it decides to create one. (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) -* The :mod:`xml.etree.ElementTree` module now emits :exc:`DeprecationWarning` - when testing the truth value of an :class:`xml.etree.ElementTree.Element`. - Before, the Python implementation emitted :exc:`FutureWarning`, and the C - implementation emitted nothing. +* :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are deprecated and + replaced by :data:`calendar.Month.JANUARY` and :data:`calendar.Month.FEBRUARY`. + (Contributed by Prince Roshan in :gh:`103636`.) -* In accordance with :pep:`699`, the ``ma_version_tag`` field in :c:type:`PyDictObject` - is deprecated for extension modules. Accessing this field will generate a compiler - warning at compile time. This field will be removed in Python 3.14. - (Contributed by Ramvikrams and Kumar Aditya in :gh:`101193`. PEP by Ken Jin.) +* :mod:`datetime`: :class:`datetime.datetime`'s :meth:`~datetime.datetime.utcnow` and + :meth:`~datetime.datetime.utcfromtimestamp` are deprecated and will be + removed in a future version. Instead, use timezone-aware objects to represent + datetimes in UTC: respectively, call :meth:`~datetime.datetime.now` and + :meth:`~datetime.datetime.fromtimestamp` with the *tz* parameter set to + :const:`datetime.UTC`. + (Contributed by Paul Ganssle in :gh:`103857`.) -* The ``st_ctime`` fields return by :func:`os.stat` and :func:`os.lstat` on +* :mod:`os`: The ``st_ctime`` fields return by :func:`os.stat` and :func:`os.lstat` on Windows are deprecated. In a future release, they will contain the last metadata change time, consistent with other platforms. For now, they still contain the creation time, which is also available in the new ``st_birthtime`` field. (Contributed by Steve Dower in :gh:`99726`.) -* The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` +* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed + in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) + +* :mod:`sqlite3`: + * :ref:`default adapters and converters + ` are now deprecated. + Instead, use the :ref:`sqlite3-adapter-converter-recipes` + and tailor them to your needs. + (Contributed by Erlend E. Aasland in :gh:`90016`.) + + * In :meth:`~sqlite3.Cursor.execute`, :exc:`DeprecationWarning` is now emitted + when :ref:`named placeholders ` are used together with + parameters supplied as a :term:`sequence` instead of as a :class:`dict`. + Starting from Python 3.14, using named placeholders with parameters supplied + as a sequence will raise a :exc:`~sqlite3.ProgrammingError`. + (Contributed by Erlend E. Aasland in :gh:`101698`.) + +* :mod:`sys`: The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` fields are deprecated. Use :data:`sys.last_exc` instead. (Contributed by Irit Katriel in :gh:`102778`.) -* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed - in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) - -* Extracting tar archives without specifying *filter* is deprecated until +* :mod:`tarfile`: Extracting tar archives without specifying *filter* is deprecated until Python 3.14, when ``'data'`` filter will become the default. See :ref:`tarfile-extraction-filter` for details. -* ``calendar.January`` and ``calendar.February`` constants are deprecated and - replaced by :data:`calendar.Month.JANUARY` and :data:`calendar.Month.FEBRUARY`. - (Contributed by Prince Roshan in :gh:`103636`.) +* :mod:`typing`: :class:`typing.Hashable` and :class:`typing.Sized` aliases for :class:`collections.abc.Hashable` + and :class:`collections.abc.Sized`. (:gh:`94309`.) + +* :mod:`xml.etree.ElementTree`: The module now emits :exc:`DeprecationWarning` + when testing the truth value of an :class:`xml.etree.ElementTree.Element`. + Before, the Python implementation emitted :exc:`FutureWarning`, and the C + implementation emitted nothing. + +* The 3-arg signatures (type, value, traceback) of :meth:`~coroutine.throw`, + :meth:`~generator.throw` and :meth:`~agen.athrow` are deprecated and + may be removed in a future version of Python. Use the single-arg versions + of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.) + +* :exc:`DeprecationWarning` is now raised when ``__package__`` on a + module differs from ``__spec__.parent`` (previously it was + :exc:`ImportWarning`). + (Contributed by Brett Cannon in :gh:`65961`.) + +* In accordance with :pep:`699`, the ``ma_version_tag`` field in :c:type:`PyDictObject` + is deprecated for extension modules. Accessing this field will generate a compiler + warning at compile time. This field will be removed in Python 3.14. + (Contributed by Ramvikrams and Kumar Aditya in :gh:`101193`. PEP by Ken Jin.) * The bitwise inversion operator (``~``) on bool is deprecated. It will throw an error in Python 3.14. Use ``not`` for logical negation of bools instead. @@ -1035,16 +1044,6 @@ Deprecated ``int``, convert to int explicitly with ``~int(x)``. (Contributed by Tim Hoffmann in :gh:`103487`.) -* :class:`datetime.datetime`'s - :meth:`~datetime.datetime.utcnow` and - :meth:`~datetime.datetime.utcfromtimestamp` are deprecated and will be - removed in a future version. Instead, use timezone-aware objects to represent - datetimes in UTC: respectively, call - :meth:`~datetime.datetime.now` and - :meth:`~datetime.datetime.fromtimestamp` with the *tz* parameter set to - :const:`datetime.UTC`. - (Contributed by Paul Ganssle in :gh:`103857`.) - Pending Removal in Python 3.13 ------------------------------ @@ -1088,7 +1087,33 @@ APIs: Pending Removal in Python 3.14 ------------------------------ -* Deprecated the following :mod:`importlib.abc` classes, scheduled for removal in +* :mod:`argparse`: The *type*, *choices*, and *metavar* parameters + of :class:`!argparse.BooleanOptionalAction` are deprecated + and will be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`92248`.) + +* :mod:`ast`: The following :mod:`ast` features have been deprecated in documentation since + Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at runtime + when they are accessed or used, and will be removed in Python 3.14: + + * :class:`!ast.Num` + * :class:`!ast.Str` + * :class:`!ast.Bytes` + * :class:`!ast.NameConstant` + * :class:`!ast.Ellipsis` + + Use :class:`ast.Constant` instead. + (Contributed by Serhiy Storchaka in :gh:`90953`.) + +* :mod:`collections.abc`: Deprecated :class:`collections.abc.ByteString`. + Prefer :class:`Sequence` or :class:`collections.abc.Buffer`. + For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. + (Contributed by Shantanu Jain in :gh:`91896`.) + +* :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`. + (Contributed by Alan Williams in :gh:`72346`.) + +* :mod:`importlib.abc`: Deprecated the following classes, scheduled for removal in Python 3.14: * :class:`!importlib.abc.ResourceReader` @@ -1102,27 +1127,13 @@ Pending Removal in Python 3.14 (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) -* Deprecated :class:`collections.abc.ByteString`. - Prefer :class:`Sequence` or :class:`collections.abc.Buffer`. - For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. - (Contributed by Shantanu Jain in :gh:`91896`.) - -* :class:`typing.ByteString`, deprecated since Python 3.9, now causes a - :exc:`DeprecationWarning` to be emitted when it is used. - -* Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable - bases using the C API. - -* Deprecated the *isdst* parameter in :func:`email.utils.localtime`. - (Contributed by Alan Williams in :gh:`72346`.) - -* ``__package__`` and ``__cached__`` will cease to be set or taken - into consideration by the import system (:gh:`97879`). - -* Testing the truth value of an :class:`xml.etree.ElementTree.Element` - is deprecated and will raise an exception in Python 3.14. +* :mod:`itertools`: The module had undocumented, inefficient, historically buggy, + and inconsistent support for copy, deepcopy, and pickle operations. + This will be removed in 3.14 for a significant reduction in code + volume and maintenance burden. + (Contributed by Raymond Hettinger in :gh:`101588`.) -* The default :mod:`multiprocessing` start method will change to a safer one on +* :mod:`multiprocessing`: The default :mod:`multiprocessing` start method will change to a safer one on Linux, BSDs, and other non-macOS POSIX platforms where ``'fork'`` is currently the default (:gh:`84559`). Adding a runtime warning about this was deemed too disruptive as the majority of code is not expected to care. Use the @@ -1130,47 +1141,35 @@ Pending Removal in Python 3.14 :func:`~multiprocessing.set_start_method` APIs to explicitly specify when your code *requires* ``'fork'``. See :ref:`multiprocessing-start-methods`. -* :mod:`pty` has two undocumented ``master_open()`` and ``slave_open()`` +* :mod:`pkgutil`: :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` + now raise :exc:`DeprecationWarning`; + use :func:`importlib.util.find_spec` instead. + (Contributed by Nikita Sobolev in :gh:`97850`.) + +* :mod:`pty`: The module has two undocumented ``master_open()`` and ``slave_open()`` functions that have been deprecated since Python 2 but only gained a proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. -* :mod:`itertools` had undocumented, inefficient, historically buggy, - and inconsistent support for copy, deepcopy, and pickle operations. - This will be removed in 3.14 for a significant reduction in code - volume and maintenance burden. - (Contributed by Raymond Hettinger in :gh:`101588`.) - -* Accessing ``co_lnotab`` was deprecated in :pep:`626` since 3.10 - and was planned to be removed in 3.12 - but it only got a proper :exc:`DeprecationWarning` in 3.12. - May be removed in 3.14. - (Contributed by Nikita Sobolev in :gh:`101866`.) - -* The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, +* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, and will be removed in 3.14. -* The *type*, *choices*, and *metavar* parameters - of :class:`!argparse.BooleanOptionalAction` are deprecated - and will be removed in 3.14. - (Contributed by Nikita Sobolev in :gh:`92248`.) +* :mod:`typing`: :class:`typing.ByteString`, deprecated since Python 3.9, now causes a + :exc:`DeprecationWarning` to be emitted when it is used. -* :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` - now raise :exc:`DeprecationWarning`; - use :func:`importlib.util.find_spec` instead. - (Contributed by Nikita Sobolev in :gh:`97850`.) +* :mod:`xml.etree.ElementTree`: Testing the truth value of an :class:`xml.etree.ElementTree.Element` + is deprecated and will raise an exception in Python 3.14. -* The following :mod:`ast` features have been deprecated in documentation since - Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at runtime - when they are accessed or used, and will be removed in Python 3.14: +* Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable + bases using the C API. - * :class:`!ast.Num` - * :class:`!ast.Str` - * :class:`!ast.Bytes` - * :class:`!ast.NameConstant` - * :class:`!ast.Ellipsis` +* ``__package__`` and ``__cached__`` will cease to be set or taken + into consideration by the import system (:gh:`97879`). - Use :class:`ast.Constant` instead. - (Contributed by Serhiy Storchaka in :gh:`90953`.) +* Accessing ``co_lnotab`` was deprecated in :pep:`626` since 3.10 + and was planned to be removed in 3.12 + but it only got a proper :exc:`DeprecationWarning` in 3.12. + May be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`101866`.) Pending Removal in Future Versions ---------------------------------- @@ -1193,13 +1192,29 @@ although there is currently no date scheduled for their removal. Removed ======= -* Remove the ``distutils`` package. It was deprecated in Python 3.10 by +* ``asynchat`` and ``asyncore``: These two modules have been removed + according to the schedule in :pep:`594`, + having been deprecated in Python 3.6. + Use :mod:`asyncio` instead. + (Contributed by Nikita Sobolev in :gh:`96580`.) + +* :mod:`configparser`: Several names deprecated in the :mod:`configparser` way back in 3.2 have + been removed per :gh:`89336`: + + * :class:`configparser.ParsingError` no longer has a ``filename`` attribute + or argument. Use the ``source`` attribute and argument instead. + * :mod:`configparser` no longer has a ``SafeConfigParser`` class. Use the + shorter :class:`~configparser.ConfigParser` name instead. + * :class:`configparser.ConfigParser` no longer has a ``readfp`` method. + Use :meth:`~configparser.ConfigParser.read_file` instead. + +* ``distutils``: Remove the ``distutils`` package. It was deprecated in Python 3.10 by :pep:`632` "Deprecate distutils module". For projects still using ``distutils`` and cannot be updated to something else, the ``setuptools`` project can be installed: it still provides ``distutils``. (Contributed by Victor Stinner in :gh:`92584`.) -* Remove the bundled setuptools wheel from :mod:`ensurepip`, +* :mod:`ensurepip`: Remove the bundled setuptools wheel from :mod:`ensurepip`, and stop installing setuptools in environments created by :mod:`venv`. ``pip (>= 22.1)`` does not require setuptools to be installed in the @@ -1217,94 +1232,9 @@ Removed (Contributed by Pradyun Gedam in :gh:`95299`.) -* Removed many old deprecated :mod:`unittest` features: - - - A number of :class:`~unittest.TestCase` method aliases: - - ============================ =============================== =============== - Deprecated alias Method Name Deprecated in - ============================ =============================== =============== - ``failUnless`` :meth:`.assertTrue` 3.1 - ``failIf`` :meth:`.assertFalse` 3.1 - ``failUnlessEqual`` :meth:`.assertEqual` 3.1 - ``failIfEqual`` :meth:`.assertNotEqual` 3.1 - ``failUnlessAlmostEqual`` :meth:`.assertAlmostEqual` 3.1 - ``failIfAlmostEqual`` :meth:`.assertNotAlmostEqual` 3.1 - ``failUnlessRaises`` :meth:`.assertRaises` 3.1 - ``assert_`` :meth:`.assertTrue` 3.2 - ``assertEquals`` :meth:`.assertEqual` 3.2 - ``assertNotEquals`` :meth:`.assertNotEqual` 3.2 - ``assertAlmostEquals`` :meth:`.assertAlmostEqual` 3.2 - ``assertNotAlmostEquals`` :meth:`.assertNotAlmostEqual` 3.2 - ``assertRegexpMatches`` :meth:`.assertRegex` 3.2 - ``assertRaisesRegexp`` :meth:`.assertRaisesRegex` 3.2 - ``assertNotRegexpMatches`` :meth:`.assertNotRegex` 3.5 - ============================ =============================== =============== - - You can use https://github.com/isidentical/teyit to automatically modernise - your unit tests. - - - Undocumented and broken :class:`~unittest.TestCase` method - ``assertDictContainsSubset`` (deprecated in Python 3.2). - - - Undocumented :meth:`TestLoader.loadTestsFromModule - ` parameter *use_load_tests* - (deprecated and ignored since Python 3.2). - - - An alias of the :class:`~unittest.TextTestResult` class: - ``_TextTestResult`` (deprecated in Python 3.2). - - (Contributed by Serhiy Storchaka in :issue:`45162`.) - -* Several names deprecated in the :mod:`configparser` way back in 3.2 have - been removed per :gh:`89336`: - - * :class:`configparser.ParsingError` no longer has a ``filename`` attribute - or argument. Use the ``source`` attribute and argument instead. - * :mod:`configparser` no longer has a ``SafeConfigParser`` class. Use the - shorter :class:`~configparser.ConfigParser` name instead. - * :class:`configparser.ConfigParser` no longer has a ``readfp`` method. - Use :meth:`~configparser.ConfigParser.read_file` instead. - -* The following undocumented :mod:`sqlite3` features, deprecated in Python - 3.10, are now removed: - - * ``sqlite3.enable_shared_cache()`` - * ``sqlite3.OptimizedUnicode`` - - If a shared cache must be used, open the database in URI mode using the - ``cache=shared`` query parameter. - - The ``sqlite3.OptimizedUnicode`` text factory has been an alias for - :class:`str` since Python 3.3. Code that previously set the text factory to - ``OptimizedUnicode`` can either use ``str`` explicitly, or rely on the - default value which is also ``str``. - - (Contributed by Erlend E. Aasland in :gh:`92548`.) - -* ``smtpd`` has been removed according to the schedule in :pep:`594`, - having been deprecated in Python 3.4.7 and 3.5.4. - Use aiosmtpd_ PyPI module or any other - :mod:`asyncio`-based server instead. - (Contributed by Oleg Iarygin in :gh:`93243`.) - -.. _aiosmtpd: https://pypi.org/project/aiosmtpd/ - -* ``asynchat`` and ``asyncore`` have been removed - according to the schedule in :pep:`594`, - having been deprecated in Python 3.6. - Use :mod:`asyncio` instead. - (Contributed by Nikita Sobolev in :gh:`96580`.) - -* Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python - 3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) - function is a built-in function. Since Python 3.10, :func:`!_pyio.open` is - also a static method. - (Contributed by Victor Stinner in :gh:`94169`.) - -* Remove the :func:`!ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: - use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. - (Contributed by Victor Stinner in :gh:`94199`.) +* :mod:`ftplib`: Remove the ``FTP_TLS.ssl_version`` class attribute: use the + *context* parameter instead. + (Contributed by Victor Stinner in :gh:`94172`.) * :mod:`gzip`: Remove the ``filename`` attribute of :class:`gzip.GzipFile`, deprecated since Python 2.6, use the :attr:`~gzip.GzipFile.name` attribute @@ -1312,43 +1242,13 @@ Removed extension if it was not present. (Contributed by Victor Stinner in :gh:`94196`.) -* Remove the :func:`!ssl.match_hostname` function. - It was deprecated in Python 3.7. OpenSSL performs - hostname matching since Python 3.7, Python no longer uses the - :func:`!ssl.match_hostname` function. - (Contributed by Victor Stinner in :gh:`94199`.) - -* Remove the :func:`!locale.format` function, deprecated in Python 3.7: - use :func:`locale.format_string` instead. - (Contributed by Victor Stinner in :gh:`94226`.) - * :mod:`hashlib`: Remove the pure Python implementation of :func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. (Contributed by Victor Stinner in :gh:`94199`.) -* :mod:`xml.etree.ElementTree`: Remove the ``ElementTree.Element.copy()`` method of the - pure Python implementation, deprecated in Python 3.10, use the - :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree.ElementTree` - has no ``copy()`` method, only a ``__copy__()`` method. - (Contributed by Victor Stinner in :gh:`94383`.) - -* :mod:`zipimport`: Remove ``find_loader()`` and ``find_module()`` methods, - deprecated in Python 3.10: use the ``find_spec()`` method instead. See - :pep:`451` for the rationale. - (Contributed by Victor Stinner in :gh:`94379`.) - -* Remove the :func:`!ssl.wrap_socket` function, deprecated in Python 3.7: - instead, create a :class:`ssl.SSLContext` object and call its - :class:`ssl.SSLContext.wrap_socket` method. Any package that still uses - :func:`!ssl.wrap_socket` is broken and insecure. The function neither sends a - SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 - `_: Improper Certificate - Validation. - (Contributed by Victor Stinner in :gh:`94199`.) - -* Many previously deprecated cleanups in :mod:`importlib` have now been +* :mod:`importlib`: Many previously deprecated cleanups in :mod:`importlib` have now been completed: * References to, and support for :meth:`!module_repr()` has been removed. @@ -1413,6 +1313,115 @@ Removed ``PY_COMPILED``, ``C_EXTENSION``, ``PY_RESOURCE``, ``PKG_DIRECTORY``, ``C_BUILTIN``, ``PY_FROZEN``, ``PY_CODERESOURCE``, ``IMP_HOOK``. +* :mod:`io`: Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python + 3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) + function is a built-in function. Since Python 3.10, :func:`!_pyio.open` is + also a static method. + (Contributed by Victor Stinner in :gh:`94169`.) + +* :mod:`locale`: Remove the :func:`!locale.format` function, deprecated in Python 3.7: + use :func:`locale.format_string` instead. + (Contributed by Victor Stinner in :gh:`94226`.) + +* ``smtpd``: The module has been removed according to the schedule in :pep:`594`, + having been deprecated in Python 3.4.7 and 3.5.4. + Use aiosmtpd_ PyPI module or any other + :mod:`asyncio`-based server instead. + (Contributed by Oleg Iarygin in :gh:`93243`.) + +.. _aiosmtpd: https://pypi.org/project/aiosmtpd/ + +* :mod:`sqlite3`: The following undocumented :mod:`sqlite3` features, deprecated in Python + 3.10, are now removed: + + * ``sqlite3.enable_shared_cache()`` + * ``sqlite3.OptimizedUnicode`` + + If a shared cache must be used, open the database in URI mode using the + ``cache=shared`` query parameter. + + The ``sqlite3.OptimizedUnicode`` text factory has been an alias for + :class:`str` since Python 3.3. Code that previously set the text factory to + ``OptimizedUnicode`` can either use ``str`` explicitly, or rely on the + default value which is also ``str``. + + (Contributed by Erlend E. Aasland in :gh:`92548`.) + +* :mod:`ssl`: + + * Remove the :func:`!ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: + use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. + (Contributed by Victor Stinner in :gh:`94199`.) + + * Remove the :func:`!ssl.match_hostname` function. + It was deprecated in Python 3.7. OpenSSL performs + hostname matching since Python 3.7, Python no longer uses the + :func:`!ssl.match_hostname` function. + (Contributed by Victor Stinner in :gh:`94199`.) + + * Remove the :func:`!ssl.wrap_socket` function, deprecated in Python 3.7: + instead, create a :class:`ssl.SSLContext` object and call its + :class:`ssl.SSLContext.wrap_socket` method. Any package that still uses + :func:`!ssl.wrap_socket` is broken and insecure. The function neither sends a + SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 + `_: Improper Certificate + Validation. + (Contributed by Victor Stinner in :gh:`94199`.) + +* :mod:`unittest`: Removed many old deprecated :mod:`unittest` features: + + - A number of :class:`~unittest.TestCase` method aliases: + + ============================ =============================== =============== + Deprecated alias Method Name Deprecated in + ============================ =============================== =============== + ``failUnless`` :meth:`.assertTrue` 3.1 + ``failIf`` :meth:`.assertFalse` 3.1 + ``failUnlessEqual`` :meth:`.assertEqual` 3.1 + ``failIfEqual`` :meth:`.assertNotEqual` 3.1 + ``failUnlessAlmostEqual`` :meth:`.assertAlmostEqual` 3.1 + ``failIfAlmostEqual`` :meth:`.assertNotAlmostEqual` 3.1 + ``failUnlessRaises`` :meth:`.assertRaises` 3.1 + ``assert_`` :meth:`.assertTrue` 3.2 + ``assertEquals`` :meth:`.assertEqual` 3.2 + ``assertNotEquals`` :meth:`.assertNotEqual` 3.2 + ``assertAlmostEquals`` :meth:`.assertAlmostEqual` 3.2 + ``assertNotAlmostEquals`` :meth:`.assertNotAlmostEqual` 3.2 + ``assertRegexpMatches`` :meth:`.assertRegex` 3.2 + ``assertRaisesRegexp`` :meth:`.assertRaisesRegex` 3.2 + ``assertNotRegexpMatches`` :meth:`.assertNotRegex` 3.5 + ============================ =============================== =============== + + You can use https://github.com/isidentical/teyit to automatically modernise + your unit tests. + + - Undocumented and broken :class:`~unittest.TestCase` method + ``assertDictContainsSubset`` (deprecated in Python 3.2). + + - Undocumented :meth:`TestLoader.loadTestsFromModule + ` parameter *use_load_tests* + (deprecated and ignored since Python 3.2). + + - An alias of the :class:`~unittest.TextTestResult` class: + ``_TextTestResult`` (deprecated in Python 3.2). + + (Contributed by Serhiy Storchaka in :issue:`45162`.) + +* :mod:`webbrowser`: Remove support for obsolete browsers from :mod:`webbrowser`. + Removed browsers include: Grail, Mosaic, Netscape, Galeon, Skipstone, + Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). + +* :mod:`xml.etree.ElementTree`: Remove the ``ElementTree.Element.copy()`` method of the + pure Python implementation, deprecated in Python 3.10, use the + :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree.ElementTree` + has no ``copy()`` method, only a ``__copy__()`` method. + (Contributed by Victor Stinner in :gh:`94383`.) + +* :mod:`zipimport`: Remove ``find_loader()`` and ``find_module()`` methods, + deprecated in Python 3.10: use the ``find_spec()`` method instead. See + :pep:`451` for the rationale. + (Contributed by Victor Stinner in :gh:`94379`.) + * Removed the ``suspicious`` rule from the documentation Makefile, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint `_. @@ -1426,15 +1435,6 @@ Removed (*ssl_context* in :mod:`imaplib`) instead. (Contributed by Victor Stinner in :gh:`94172`.) -* :mod:`ftplib`: Remove the ``FTP_TLS.ssl_version`` class attribute: use the - *context* parameter instead. - (Contributed by Victor Stinner in :gh:`94172`.) - -* Remove support for obsolete browsers from :mod:`webbrowser`. - Removed browsers include: Grail, Mosaic, Netscape, Galeon, Skipstone, - Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). - - .. _whatsnew312-porting-to-python312: Porting to Python 3.12 From 332db37835c403a0939aa46527736a9ea898c819 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 03:00:31 -0700 Subject: [PATCH 0414/1206] [3.12] gh-101100: Fix some broken sphinx references (GH-107095) (#107103) (cherry picked from commit f5147c0cfbd7943ff10917225448c36a53f9828d) Co-authored-by: wulmer --- Doc/c-api/iterator.rst | 2 +- Doc/c-api/mapping.rst | 6 +++--- Doc/c-api/refcounting.rst | 2 +- Doc/c-api/sequence.rst | 2 +- Doc/howto/functional.rst | 4 ++-- Doc/howto/regex.rst | 2 ++ Doc/howto/sorting.rst | 6 +++--- Doc/howto/unicode.rst | 8 ++++---- Doc/library/_thread.rst | 9 +++++---- Doc/library/codeop.rst | 4 ++-- Doc/library/constants.rst | 6 +++--- Doc/tools/.nitignore | 10 ---------- 12 files changed, 27 insertions(+), 34 deletions(-) diff --git a/Doc/c-api/iterator.rst b/Doc/c-api/iterator.rst index 3fcf099134d4dd..95952237ca746f 100644 --- a/Doc/c-api/iterator.rst +++ b/Doc/c-api/iterator.rst @@ -6,7 +6,7 @@ Iterator Objects ---------------- Python provides two general-purpose iterator objects. The first, a sequence -iterator, works with an arbitrary sequence supporting the :meth:`__getitem__` +iterator, works with an arbitrary sequence supporting the :meth:`~object.__getitem__` method. The second works with a callable object and a sentinel value, calling the callable for each item in the sequence, and ending the iteration when the sentinel value is returned. diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst index cffb0ed50fb77d..d94a9dc45b5ebe 100644 --- a/Doc/c-api/mapping.rst +++ b/Doc/c-api/mapping.rst @@ -13,7 +13,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and Return ``1`` if the object provides the mapping protocol or supports slicing, and ``0`` otherwise. Note that it returns ``1`` for Python classes with - a :meth:`__getitem__` method, since in general it is impossible to + a :meth:`~object.__getitem__` method, since in general it is impossible to determine what type of keys the class supports. This function always succeeds. @@ -60,7 +60,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and This is equivalent to the Python expression ``key in o``. This function always succeeds. - Note that exceptions which occur while calling the :meth:`__getitem__` + Note that exceptions which occur while calling the :meth:`~object.__getitem__` method will get suppressed. To get error reporting use :c:func:`PyObject_GetItem()` instead. @@ -71,7 +71,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and This is equivalent to the Python expression ``key in o``. This function always succeeds. - Note that exceptions which occur while calling the :meth:`__getitem__` + Note that exceptions which occur while calling the :meth:`~object.__getitem__` method and creating a temporary string object will get suppressed. To get error reporting use :c:func:`PyMapping_GetItemString()` instead. diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst index d8e9c2da6f3ff3..640c5c610899f8 100644 --- a/Doc/c-api/refcounting.rst +++ b/Doc/c-api/refcounting.rst @@ -101,7 +101,7 @@ of Python objects. .. warning:: The deallocation function can cause arbitrary Python code to be invoked (e.g. - when a class instance with a :meth:`__del__` method is deallocated). While + when a class instance with a :meth:`~object.__del__` method is deallocated). While exceptions in such code are not propagated, the executed code has free access to all Python global variables. This means that any object that is reachable from a global variable should be in a consistent state before :c:func:`Py_DECREF` is diff --git a/Doc/c-api/sequence.rst b/Doc/c-api/sequence.rst index 402a3e5e09ff56..ce28839f5ba739 100644 --- a/Doc/c-api/sequence.rst +++ b/Doc/c-api/sequence.rst @@ -9,7 +9,7 @@ Sequence Protocol .. c:function:: int PySequence_Check(PyObject *o) Return ``1`` if the object provides the sequence protocol, and ``0`` otherwise. - Note that it returns ``1`` for Python classes with a :meth:`__getitem__` + Note that it returns ``1`` for Python classes with a :meth:`~object.__getitem__` method, unless they are :class:`dict` subclasses, since in general it is impossible to determine what type of keys the class supports. This function always succeeds. diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index 5cf12cc52bde4e..b0f9d22d74f0e3 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -1072,8 +1072,8 @@ write the obvious :keyword:`for` loop:: A related function is :func:`itertools.accumulate(iterable, func=operator.add) `. It performs the same calculation, but instead of -returning only the final result, :func:`accumulate` returns an iterator that -also yields each partial result:: +returning only the final result, :func:`~itertools.accumulate` returns an iterator +that also yields each partial result:: itertools.accumulate([1, 2, 3, 4, 5]) => 1, 3, 6, 10, 15 diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index 655df59e27b641..c19c48301f5848 100644 --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -518,6 +518,8 @@ cache. Compilation Flags ----------------- +.. currentmodule:: re + Compilation flags let you modify some aspects of how regular expressions work. Flags are available in the :mod:`re` module under two names, a long name such as :const:`IGNORECASE` and a short, one-letter form such as :const:`I`. (If you're diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index decce12bf3faf6..38dd09f0a721d2 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -273,7 +273,7 @@ Odds and Ends * The sort routines use ``<`` when making comparisons between two objects. So, it is easy to add a standard sort order to a class by - defining an :meth:`__lt__` method: + defining an :meth:`~object.__lt__` method: .. doctest:: @@ -281,8 +281,8 @@ Odds and Ends >>> sorted(student_objects) [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)] - However, note that ``<`` can fall back to using :meth:`__gt__` if - :meth:`__lt__` is not implemented (see :func:`object.__lt__`). + However, note that ``<`` can fall back to using :meth:`~object.__gt__` if + :meth:`~object.__lt__` is not implemented (see :func:`object.__lt__`). * Key functions need not depend directly on the objects being sorted. A key function can also access external resources. For instance, if the student grades diff --git a/Doc/howto/unicode.rst b/Doc/howto/unicode.rst index b0faa68d240896..254fe729355353 100644 --- a/Doc/howto/unicode.rst +++ b/Doc/howto/unicode.rst @@ -424,8 +424,8 @@ lowercase letters 'ss'. A second tool is the :mod:`unicodedata` module's :func:`~unicodedata.normalize` function that converts strings to one -of several normal forms, where letters followed by a combining -character are replaced with single characters. :func:`normalize` can +of several normal forms, where letters followed by a combining character are +replaced with single characters. :func:`~unicodedata.normalize` can be used to perform string comparisons that won't falsely report inequality if two strings use combining characters differently: @@ -474,8 +474,8 @@ The Unicode Standard also specifies how to do caseless comparisons:: print(compare_caseless(single_char, multiple_chars)) -This will print ``True``. (Why is :func:`NFD` invoked twice? Because -there are a few characters that make :meth:`casefold` return a +This will print ``True``. (Why is :func:`!NFD` invoked twice? Because +there are a few characters that make :meth:`~str.casefold` return a non-normalized string, so the result needs to be normalized again. See section 3.13 of the Unicode Standard for a discussion and an example.) diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 3ff6b48b083b51..0442c298c137ba 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -150,8 +150,8 @@ This module defines the following constants and functions: .. data:: TIMEOUT_MAX The maximum value allowed for the *timeout* parameter of - :meth:`Lock.acquire`. Specifying a timeout greater than this value will - raise an :exc:`OverflowError`. + :meth:`Lock.acquire `. Specifying a timeout greater + than this value will raise an :exc:`OverflowError`. .. versionadded:: 3.2 @@ -217,8 +217,9 @@ In addition to these methods, lock objects can also be used via the * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is equivalent to calling :func:`_thread.exit`. -* It is not possible to interrupt the :meth:`acquire` method on a lock --- the - :exc:`KeyboardInterrupt` exception will happen after the lock has been acquired. +* It is not possible to interrupt the :meth:`~threading.Lock.acquire` method on + a lock --- the :exc:`KeyboardInterrupt` exception will happen after the lock + has been acquired. * When the main thread exits, it is system defined whether the other threads survive. On most systems, they are killed without executing diff --git a/Doc/library/codeop.rst b/Doc/library/codeop.rst index 90df499f8207b7..55606e1c5f09ac 100644 --- a/Doc/library/codeop.rst +++ b/Doc/library/codeop.rst @@ -58,7 +58,7 @@ To do just the former: .. class:: Compile() - Instances of this class have :meth:`__call__` methods identical in signature to + Instances of this class have :meth:`~object.__call__` methods identical in signature to the built-in function :func:`compile`, but with the difference that if the instance compiles program text containing a :mod:`__future__` statement, the instance 'remembers' and compiles all subsequent program texts with the @@ -67,7 +67,7 @@ To do just the former: .. class:: CommandCompiler() - Instances of this class have :meth:`__call__` methods identical in signature to + Instances of this class have :meth:`~object.__call__` methods identical in signature to :func:`compile_command`; the difference is that if the instance compiles program text containing a :mod:`__future__` statement, the instance 'remembers' and compiles all subsequent program texts with the statement in force. diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst index 38dd552a0363ac..401dc9a320c5e0 100644 --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -22,16 +22,16 @@ A small number of constants live in the built-in namespace. They are: An object frequently used to represent the absence of a value, as when default arguments are not passed to a function. Assignments to ``None`` are illegal and raise a :exc:`SyntaxError`. - ``None`` is the sole instance of the :data:`NoneType` type. + ``None`` is the sole instance of the :data:`~types.NoneType` type. .. data:: NotImplemented A special value which should be returned by the binary special methods - (e.g. :meth:`__eq__`, :meth:`__lt__`, :meth:`__add__`, :meth:`__rsub__`, + (e.g. :meth:`~object.__eq__`, :meth:`~object.__lt__`, :meth:`~object.__add__`, :meth:`~object.__rsub__`, etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods - (e.g. :meth:`__imul__`, :meth:`__iand__`, etc.) for the same purpose. + (e.g. :meth:`~object.__imul__`, :meth:`~object.__iand__`, etc.) for the same purpose. It should not be evaluated in a boolean context. ``NotImplemented`` is the sole instance of the :data:`types.NotImplementedType` type. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 0403cb34751ca8..f333495017e2a1 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -29,15 +29,12 @@ Doc/c-api/init_config.rst Doc/c-api/intro.rst Doc/c-api/iterator.rst Doc/c-api/long.rst -Doc/c-api/mapping.rst Doc/c-api/marshal.rst Doc/c-api/memory.rst Doc/c-api/memoryview.rst Doc/c-api/module.rst Doc/c-api/none.rst Doc/c-api/object.rst -Doc/c-api/refcounting.rst -Doc/c-api/sequence.rst Doc/c-api/set.rst Doc/c-api/stable.rst Doc/c-api/structures.rst @@ -62,19 +59,14 @@ Doc/glossary.rst Doc/howto/curses.rst Doc/howto/descriptor.rst Doc/howto/enum.rst -Doc/howto/functional.rst Doc/howto/instrumentation.rst Doc/howto/isolating-extensions.rst Doc/howto/logging-cookbook.rst Doc/howto/logging.rst -Doc/howto/regex.rst -Doc/howto/sorting.rst -Doc/howto/unicode.rst Doc/howto/urllib2.rst Doc/install/index.rst Doc/library/2to3.rst Doc/library/__future__.rst -Doc/library/_thread.rst Doc/library/abc.rst Doc/library/aifc.rst Doc/library/ast.rst @@ -97,13 +89,11 @@ Doc/library/cmath.rst Doc/library/cmd.rst Doc/library/code.rst Doc/library/codecs.rst -Doc/library/codeop.rst Doc/library/collections.abc.rst Doc/library/collections.rst Doc/library/concurrent.futures.rst Doc/library/concurrent.rst Doc/library/configparser.rst -Doc/library/constants.rst Doc/library/contextlib.rst Doc/library/copy.rst Doc/library/csv.rst From f7e13002ff62ca31b24acae5d057874de7a967d5 Mon Sep 17 00:00:00 2001 From: Daniele Procida Date: Sun, 23 Jul 2023 12:22:05 +0200 Subject: [PATCH 0415/1206] [3.12] gh-106996: Add the basics of a turtle graphics tutorial (GH-107072) (#107109) --- Doc/includes/turtle-star.py | 10 --- Doc/library/turtle.rst | 153 +++++++++++++++++++++++++++++++++--- 2 files changed, 140 insertions(+), 23 deletions(-) delete mode 100644 Doc/includes/turtle-star.py diff --git a/Doc/includes/turtle-star.py b/Doc/includes/turtle-star.py deleted file mode 100644 index 1a5db761b32385..00000000000000 --- a/Doc/includes/turtle-star.py +++ /dev/null @@ -1,10 +0,0 @@ -from turtle import * -color('red', 'yellow') -begin_fill() -while True: - forward(200) - left(170) - if abs(pos()) < 1: - break -end_fill() -done() diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index c656f6d9cfdaad..a9c0fa96207ae9 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -19,14 +19,10 @@ Introduction ============ -Turtle graphics is a popular way for introducing programming to kids. It was -part of the original Logo programming language developed by Wally Feurzeig, -Seymour Papert and Cynthia Solomon in 1967. - -Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it the -command ``turtle.forward(15)``, and it moves (on-screen!) 15 pixels in the -direction it is facing, drawing a line as it moves. Give it the command -``turtle.right(25)``, and it rotates in-place 25 degrees clockwise. +Turtle graphics is an implementation of `the popular geometric drawing tools +introduced in Logo `_, developed by Wally Feurzeig, Seymour Papert and Cynthia Solomon +in 1967. .. sidebar:: Turtle star @@ -36,10 +32,141 @@ direction it is facing, drawing a line as it moves. Give it the command .. image:: turtle-star.* :align: center - .. literalinclude:: ../includes/turtle-star.py +In Python, turtle graphics provides a representation of a physical "turtle" +(a little robot with a pen) that draws on a sheet of paper on the floor. + +It's an effective and well-proven way for learners to encounter +programming concepts and interaction with software, as it provides instant, +visible feedback. It also provides convenient access to graphical output +in general. + +Turtle drawing was originally created as an educational tool, to be used by +teachers in the classroom. For the programmer who needs to produce some +graphical output it can be a way to do that without the overhead of +introducing more complex or external libraries into their work. + + +Tutorial +======== + +New users should start here. In this tutorial we'll explore some of the +basics of turtle drawing. + + +Starting a turtle environment +----------------------------- + +In a Python shell, import all the objects of the ``turtle`` module:: + + from turtle import * + +If you run into a ``No module named '_tkinter'`` error, you'll have to +install the :mod:`Tk interface package ` on your system. + + +Basic drawing +------------- + +Send the turtle forward 100 steps:: + + forward(100) + +You should see (most likely, in a new window on your display) a line +drawn by the turtle, heading East. Change the direction of the turtle, +so that it turns 120 degrees left (anti-clockwise):: + + left(120) + +Let's continue by drawing a triangle:: + + forward(100) + left(120) + forward(100) + +Notice how the turtle, represented by an arrow, points in different +directions as you steer it. + +Experiment with those commands, and also with ``backward()`` and +``right()``. + + +Pen control +~~~~~~~~~~~ + +Try changing the color - for example, ``color('blue')`` - and +width of the line - for example, ``width(3)`` - and then drawing again. + +You can also move the turtle around without drawing, by lifting up the pen: +``up()`` before moving. To start drawing again, use ``down()``. + + +The turtle's position +~~~~~~~~~~~~~~~~~~~~~ + +Send your turtle back to its starting-point (useful if it has disappeared +off-screen):: + + home() + +The home position is at the center of the turtle's screen. If you ever need to +know them, get the turtle's x-y co-ordinates with:: + + pos() + +Home is at ``(0, 0)``. + +And after a while, it will probably help to clear the window so we can start +anew:: + + clearscreen() + + +Making algorithmic patterns +--------------------------- + +Using loops, it's possible to build up geometric patterns:: + + for steps in range(100): + for c in ('blue', 'red', 'green'): + color(c) + forward(steps) + right(30) + + +\ - which of course, are limited only by the imagination! + +Let's draw the star shape at the top of this page. We want red lines, +filled in with yellow:: + + color('red') + fillcolor('yellow') + +Just as ``up()`` and ``down()`` determine whether lines will be drawn, +filling can be turned on and off:: + + begin_fill() + +Next we'll create a loop:: + + while True: + forward(200) + left(170) + if abs(pos()) < 1: + break + +``abs(pos()) < 1`` is a good way to know when the turtle is back at its +home position. + +Finally, complete the filling:: + + end_fill() + +(Note that filling only actually takes place when you give the +``end_fill()`` command.) + -By combining together these and similar commands, intricate shapes and pictures -can easily be drawn. +Explanation +=========== The :mod:`turtle` module is an extended reimplementation of the same-named module from the Python standard distribution up to version Python 2.5. @@ -94,8 +221,8 @@ To use multiple turtles on a screen one has to use the object-oriented interface omitted here. -Overview of available Turtle and Screen methods -================================================= +Turtle graphics reference +========================= Turtle methods -------------- From 074fcf15fa13f09c85e27f53951ef84d02d95454 Mon Sep 17 00:00:00 2001 From: Moritz Neeb Date: Sun, 23 Jul 2023 12:26:05 +0200 Subject: [PATCH 0416/1206] [3.12] gh-106969: Indicate no modules were added in 3.10 & 3.12 (GH-106988) (#107094) The "New Modules" section was left in place to ensure that the anchor link for new modules will still exist: /whatsnew/3.12.htmlGH-new-modules /whatsnew/3.10.htmlGH-new-modules This means that existing links to this section don't break. (cherry picked from commit 6dbffaed17d59079d6a2788d686009f762a3278f) Co-authored-by: Sebastiaan Zeeff <33516116+SebastiaanZ@users.noreply.github.com> --- Doc/whatsnew/3.10.rst | 2 +- Doc/whatsnew/3.12.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index bb271d0a455681..92d23462acc57c 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -887,7 +887,7 @@ Other Language Changes New Modules =========== -* None yet. +* None. Improved Modules diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d1b10dbd1999dd..a7db645657db1e 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -486,7 +486,7 @@ Other Language Changes New Modules =========== -* None yet. +* None. Improved Modules From 95a82dcbe74d1ed226a3df0763546f27bd5a6f61 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 04:50:21 -0700 Subject: [PATCH 0417/1206] [3.12] gh-107091: Fix the use of some C domain roles (GH-107092) (GH-107113) (cherry picked from commit 08a228da05a7aec937b65eea21f4091fa3c6b5cf) Co-authored-by: Serhiy Storchaka --- Doc/c-api/buffer.rst | 4 ++-- Doc/c-api/method.rst | 4 ++-- Doc/c-api/module.rst | 2 +- Doc/c-api/type.rst | 2 +- Doc/c-api/typeobj.rst | 4 ++-- Doc/extending/extending.rst | 10 +++++----- Doc/howto/isolating-extensions.rst | 4 ++-- Doc/whatsnew/3.11.rst | 2 +- Doc/whatsnew/3.9.rst | 2 +- Misc/NEWS.d/3.10.0a2.rst | 4 ++-- Misc/NEWS.d/3.12.0a1.rst | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 91d1edd9b2ec46..6e5443f0d6cdc5 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -225,7 +225,7 @@ object via :c:func:`PyObject_GetBuffer`. Since the complexity of the logical structure of the memory can vary drastically, the consumer uses the *flags* argument to specify the exact buffer type it can handle. -All :c:data:`Py_buffer` fields are unambiguously defined by the request +All :c:type:`Py_buffer` fields are unambiguously defined by the request type. request-independent fields @@ -464,7 +464,7 @@ Buffer-related functions .. c:function:: Py_ssize_t PyBuffer_SizeFromFormat(const char *format) - Return the implied :c:data:`~Py_buffer.itemsize` from :c:data:`~Py_buffer.format`. + Return the implied :c:member:`~Py_buffer.itemsize` from :c:member:`~Py_buffer.format`. On error, raise an exception and return -1. .. versionadded:: 3.9 diff --git a/Doc/c-api/method.rst b/Doc/c-api/method.rst index 93ad30cd4f7a8d..0d75ab8e1af111 100644 --- a/Doc/c-api/method.rst +++ b/Doc/c-api/method.rst @@ -7,8 +7,8 @@ Instance Method Objects .. index:: pair: object; instancemethod -An instance method is a wrapper for a :c:data:`PyCFunction` and the new way -to bind a :c:data:`PyCFunction` to a class object. It replaces the former call +An instance method is a wrapper for a :c:type:`PyCFunction` and the new way +to bind a :c:type:`PyCFunction` to a class object. It replaces the former call ``PyMethod_New(func, NULL, class)``. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index bc8e3b23b99579..e358c5da14a69f 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -145,7 +145,7 @@ or request "multi-phase initialization" by returning the definition struct itsel .. c:member:: PyModuleDef_Base m_base - Always initialize this member to :c:data:`PyModuleDef_HEAD_INIT`. + Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`. .. c:member:: const char *m_name diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index d9dcd22a24839e..553d86aa3d9975 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -215,7 +215,7 @@ Type Objects ``Py_TYPE(self)`` may be a *subclass* of the intended class, and subclasses are not necessarily defined in the same module as their superclass. See :c:type:`PyCMethod` to get the class that defines the method. - See :c:func:`PyType_GetModuleByDef` for cases when ``PyCMethod`` cannot + See :c:func:`PyType_GetModuleByDef` for cases when :c:type:`!PyCMethod` cannot be used. .. versionadded:: 3.9 diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 33591ed14eaf13..9aa076baaa977f 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2255,8 +2255,8 @@ Number Object Structures .. note:: - The :c:data:`nb_reserved` field should always be ``NULL``. It - was previously called :c:data:`nb_long`, and was renamed in + The :c:member:`~PyNumberMethods.nb_reserved` field should always be ``NULL``. It + was previously called :c:member:`!nb_long`, and was renamed in Python 3.0.1. .. c:member:: binaryfunc PyNumberMethods.nb_add diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 76e0490d0d22df..097d86e30269cc 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -235,10 +235,10 @@ Note that the Python name for the exception object is :exc:`spam.error`. The being :exc:`Exception` (unless another class is passed in instead of ``NULL``), described in :ref:`bltin-exceptions`. -Note also that the :c:data:`SpamError` variable retains a reference to the newly +Note also that the :c:data:`!SpamError` variable retains a reference to the newly created exception class; this is intentional! Since the exception could be removed from the module by external code, an owned reference to the class is -needed to ensure that it will not be discarded, causing :c:data:`SpamError` to +needed to ensure that it will not be discarded, causing :c:data:`!SpamError` to become a dangling pointer. Should it become a dangling pointer, C code which raises the exception could cause a core dump or other unintended side effects. @@ -279,9 +279,9 @@ statement:: It returns ``NULL`` (the error indicator for functions returning object pointers) if an error is detected in the argument list, relying on the exception set by :c:func:`PyArg_ParseTuple`. Otherwise the string value of the argument has been -copied to the local variable :c:data:`command`. This is a pointer assignment and +copied to the local variable :c:data:`!command`. This is a pointer assignment and you are not supposed to modify the string to which it points (so in Standard C, -the variable :c:data:`command` should properly be declared as ``const char +the variable :c:data:`!command` should properly be declared as ``const char *command``). The next statement is a call to the Unix function :c:func:`system`, passing it @@ -289,7 +289,7 @@ the string we just got from :c:func:`PyArg_ParseTuple`:: sts = system(command); -Our :func:`spam.system` function must return the value of :c:data:`sts` as a +Our :func:`!spam.system` function must return the value of :c:data:`!sts` as a Python object. This is done using the function :c:func:`PyLong_FromLong`. :: return PyLong_FromLong(sts); diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index f01801ea47212c..cc4a908febfb7f 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -483,14 +483,14 @@ to get the state:: return NULL; } -``PyType_GetModuleByDef`` works by searching the +:c:func:`!PyType_GetModuleByDef` works by searching the :term:`method resolution order` (i.e. all superclasses) for the first superclass that has a corresponding module. .. note:: In very exotic cases (inheritance chains spanning multiple modules - created from the same definition), ``PyType_GetModuleByDef`` might not + created from the same definition), :c:func:`!PyType_GetModuleByDef` might not return the module of the true defining class. However, it will always return a module with the same definition, ensuring a compatible C memory layout. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 4d9aed0d0f9cd0..712af6217b6a43 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2227,7 +2227,7 @@ New Features (Contributed by Christian Heimes in :issue:`45459`.) -* Added the :c:data:`PyType_GetModuleByDef` function, used to get the module +* Added the :c:func:`PyType_GetModuleByDef` function, used to get the module in which a method was defined, in cases where this information is not available directly (via :c:type:`PyCMethod`). (Contributed by Petr Viktorin in :issue:`46613`.) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 23db4022dc06a0..6de432d6c036bc 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1276,7 +1276,7 @@ New Features * :pep:`573`: Added :c:func:`PyType_FromModuleAndSpec` to associate a module with a class; :c:func:`PyType_GetModule` and :c:func:`PyType_GetModuleState` to retrieve the module and its state; and - :c:data:`PyCMethod` and :c:macro:`METH_METHOD` to allow a method to + :c:type:`PyCMethod` and :c:macro:`METH_METHOD` to allow a method to access the class it was defined in. (Contributed by Marcel Plch and Petr Viktorin in :issue:`38787`.) diff --git a/Misc/NEWS.d/3.10.0a2.rst b/Misc/NEWS.d/3.10.0a2.rst index eeb179a980bb8c..78b25779802d6e 100644 --- a/Misc/NEWS.d/3.10.0a2.rst +++ b/Misc/NEWS.d/3.10.0a2.rst @@ -847,8 +847,8 @@ Victor Stinner. .. section: C API Fix potential crash in deallocating method objects when dynamically -allocated `PyMethodDef`'s lifetime is managed through the ``self`` argument -of a `PyCFunction`. +allocated :c:type:`PyMethodDef`'s lifetime is managed through the ``self`` argument +of a :c:type:`PyCFunction`. .. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index ddd4b73275ec4b..51b5c6e35a4f27 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -5934,7 +5934,7 @@ not override :c:member:`~PyTypeObject.tp_call` now inherit the .. nonce: aiRSgr .. section: C API -Creating :c:data:`immutable types ` with mutable +Creating :c:macro:`immutable types ` with mutable bases is deprecated and is planned to be disabled in Python 3.14. .. From af95a1da465da82740541bf011a324fefaf53713 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 05:28:28 -0700 Subject: [PATCH 0418/1206] [3.12] gh-106186: Don't report MultipartInvariantViolationDefect for valid multipart emails when parsing header only (GH-107016) (#107111) (cherry picked from commit c65592c4d6d7552fb6284442906a96a6874cb266) Co-authored-by: htsedebenham <31847376+htsedebenham@users.noreply.github.com> --- Lib/email/feedparser.py | 2 +- Lib/test/test_email/data/msg_47.txt | 14 ++++++++++++++ Lib/test/test_email/test_email.py | 10 ++++++++++ .../2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst | 3 +++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_email/data/msg_47.txt create mode 100644 Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index 885097c7dda067..c2881d9bc52ba8 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -187,7 +187,7 @@ def close(self): assert not self._msgstack # Look for final set of defects if root.get_content_maintype() == 'multipart' \ - and not root.is_multipart(): + and not root.is_multipart() and not self._headersonly: defect = errors.MultipartInvariantViolationDefect() self.policy.handle_defect(root, defect) return root diff --git a/Lib/test/test_email/data/msg_47.txt b/Lib/test/test_email/data/msg_47.txt new file mode 100644 index 00000000000000..bb48b47d96baf8 --- /dev/null +++ b/Lib/test/test_email/data/msg_47.txt @@ -0,0 +1,14 @@ +Date: 01 Jan 2001 00:01+0000 +From: arthur@example.example +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary=foo + +--foo +Content-Type: text/plain +bar + +--foo +Content-Type: text/html +

baz

+ +--foo-- \ No newline at end of file diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index b4f3a2481976e8..cdb6ef1275e520 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3712,6 +3712,16 @@ def test_bytes_header_parser(self): self.assertIsInstance(msg.get_payload(), str) self.assertIsInstance(msg.get_payload(decode=True), bytes) + def test_header_parser_multipart_is_valid(self): + # Don't flag valid multipart emails as having defects + with openfile('msg_47.txt', encoding="utf-8") as fp: + msgdata = fp.read() + + parser = email.parser.Parser(policy=email.policy.default) + parsed_msg = parser.parsestr(msgdata, headersonly=True) + + self.assertEqual(parsed_msg.defects, []) + def test_bytes_parser_does_not_close_file(self): with openfile('msg_02.txt', 'rb') as fp: email.parser.BytesParser().parse(fp) diff --git a/Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst b/Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst new file mode 100644 index 00000000000000..07fdcc96fa38a6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst @@ -0,0 +1,3 @@ +Do not report ``MultipartInvariantViolationDefect`` defect +when the :class:`email.parser.Parser` class is used +to parse emails with ``headersonly=True``. From bd72fb19ef1a01fde067109288ecacc62121f0ae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 05:29:08 -0700 Subject: [PATCH 0419/1206] [3.12] bpo-18319: gettext() can retrieve a message even if a plural form exists (GH-19869) (#107108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 54632528eeba841e4a8cc95ecbd84c9aca8eef57) Co-authored-by: Gilles Bassière --- Lib/gettext.py | 10 ++++++---- Lib/test/test_gettext.py | 4 ++++ .../Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst diff --git a/Lib/gettext.py b/Lib/gettext.py index 6c5ec4e517f637..cc938e40028c24 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -422,10 +422,12 @@ def gettext(self, message): missing = object() tmsg = self._catalog.get(message, missing) if tmsg is missing: - if self._fallback: - return self._fallback.gettext(message) - return message - return tmsg + tmsg = self._catalog.get((message, self.plural(1)), missing) + if tmsg is not missing: + return tmsg + if self._fallback: + return self._fallback.gettext(message) + return message def ngettext(self, msgid1, msgid2, n): try: diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 1608d1b18e98fb..aa3520d2c142e4 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -320,6 +320,8 @@ def test_plural_forms1(self): eq(x, 'Hay %s fichero') x = gettext.ngettext('There is %s file', 'There are %s files', 2) eq(x, 'Hay %s ficheros') + x = gettext.gettext('There is %s file') + eq(x, 'Hay %s fichero') def test_plural_context_forms1(self): eq = self.assertEqual @@ -338,6 +340,8 @@ def test_plural_forms2(self): eq(x, 'Hay %s fichero') x = t.ngettext('There is %s file', 'There are %s files', 2) eq(x, 'Hay %s ficheros') + x = t.gettext('There is %s file') + eq(x, 'Hay %s fichero') def test_plural_context_forms2(self): eq = self.assertEqual diff --git a/Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst b/Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst new file mode 100644 index 00000000000000..a1a4cf6d63725a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst @@ -0,0 +1,2 @@ +Ensure `gettext(msg)` retrieve translations even if a plural form exists. In +other words: `gettext(msg) == ngettext(msg, '', 1)`. From 18c68ec81663bee058d28f9a223f5b28b0a8d4e4 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Sun, 23 Jul 2023 14:58:20 +0200 Subject: [PATCH 0420/1206] [3.12] Introduce a gate/check GHA job (GH-97533) (#107114) (cherry picked from commit e7cd557) --- .github/workflows/build.yml | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6504e6ca8cf3a..20208dbdd2f5f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -562,3 +562,60 @@ jobs: run: make pythoninfo - name: Tests run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu" + + all-required-green: # This job does nothing and is only used for the branch protection + name: All required checks pass + if: always() + + needs: + - check_source # Transitive dependency, needed to access `run_tests` value + - check-docs + - check_generated_files + - build_win32 + - build_win_amd64 + - build_macos + - build_ubuntu + - build_ubuntu_ssltests + - test_hypothesis + - build_asan + + runs-on: ubuntu-latest + + steps: + - name: Check whether the needed jobs succeeded or failed + uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe + with: + allowed-failures: >- + build_macos, + build_ubuntu_ssltests, + build_win32, + test_hypothesis, + allowed-skips: >- + ${{ + !fromJSON(needs.check_source.outputs.run-docs) + && ' + check-docs, + ' + || '' + }} + ${{ + needs.check_source.outputs.run_tests != 'true' + && ' + check_generated_files, + build_win32, + build_win_amd64, + build_macos, + build_ubuntu, + build_ubuntu_ssltests, + build_asan, + ' + || '' + }} + ${{ + !fromJSON(needs.check_source.outputs.run_hypothesis) + && ' + test_hypothesis, + ' + || '' + }} + jobs: ${{ toJSON(needs) }} From e02ddb33ce4b576e83170dd773e003a2936c7821 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 06:59:50 -0700 Subject: [PATCH 0421/1206] [3.12] gh-107017: Analolgy to Pascal and C replaced. (GH-107025) (#107124) (cherry picked from commit e59da0c4f283b966ccb175fb94460f58211a9704) Co-authored-by: TommyUnreal <45427816+TommyUnreal@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Doc/tutorial/introduction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index ebc2e9187534b4..4b886f604aca23 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -52,8 +52,8 @@ Numbers The interpreter acts as a simple calculator: you can type an expression at it and it will write the value. Expression syntax is straightforward: the -operators ``+``, ``-``, ``*`` and ``/`` work just like in most other languages -(for example, Pascal or C); parentheses (``()``) can be used for grouping. +operators ``+``, ``-``, ``*`` and ``/`` can be used to perform +arithmetic; parentheses (``()``) can be used for grouping. For example:: >>> 2 + 2 From 40a337fbaa820feb3198d55d8b4f389360e0b2b8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 14:13:23 -0700 Subject: [PATCH 0422/1206] [3.12] gh-106948: Docs: Disable links for C standard library functions, OS utility functions and system calls (GH-107062) (#107154) (cherry picked from commit b447e19e720e6781025432a40eb72b1cc93ac944) Co-authored-by: Erlend E. Aasland Co-authored-by: Serhiy Storchaka --- Doc/c-api/exceptions.rst | 2 +- Doc/c-api/sys.rst | 4 ++-- Doc/conf.py | 18 +++++++++++++++ Doc/howto/instrumentation.rst | 6 ++--- Doc/library/mailbox.rst | 8 +++---- Doc/library/os.rst | 6 ++--- Doc/library/select.rst | 42 +++++++++++++++++------------------ Doc/library/signal.rst | 2 +- Doc/tools/.nitignore | 1 - Doc/whatsnew/2.6.rst | 6 ++--- Doc/whatsnew/2.7.rst | 2 +- Misc/NEWS.d/3.10.0a1.rst | 4 ++-- 12 files changed, 59 insertions(+), 42 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 3d4ceb360f5b18..4d81b273638b14 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -163,7 +163,7 @@ For convenience, some of these functions will always return a This is a convenience function to raise an exception when a C library function has returned an error and set the C variable :c:data:`errno`. It constructs a tuple object whose first item is the integer :c:data:`errno` value and whose - second item is the corresponding error message (gotten from :c:func:`strerror`), + second item is the corresponding error message (gotten from :c:func:`!strerror`), and then calls ``PyErr_SetObject(type, object)``. On Unix, when the :c:data:`errno` value is :c:macro:`EINTR`, indicating an interrupted system call, this calls :c:func:`PyErr_CheckSignals`, and if that set the error indicator, diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 3550193c1af826..7e0e982a04ec3e 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -106,7 +106,7 @@ Operating System Utilities .. c:function:: PyOS_sighandler_t PyOS_getsig(int i) Return the current signal handler for signal *i*. This is a thin wrapper around - either :c:func:`sigaction` or :c:func:`signal`. Do not call those functions + either :c:func:`!sigaction` or :c:func:`!signal`. Do not call those functions directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:expr:`void (\*)(int)`. @@ -114,7 +114,7 @@ Operating System Utilities .. c:function:: PyOS_sighandler_t PyOS_setsig(int i, PyOS_sighandler_t h) Set the signal handler for signal *i* to be *h*; return the old signal handler. - This is a thin wrapper around either :c:func:`sigaction` or :c:func:`signal`. Do + This is a thin wrapper around either :c:func:`!sigaction` or :c:func:`!signal`. Do not call those functions directly! :c:type:`PyOS_sighandler_t` is a typedef alias for :c:expr:`void (\*)(int)`. diff --git a/Doc/conf.py b/Doc/conf.py index 48d43736bfbc20..067aa1d9e22918 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -77,6 +77,24 @@ exclude_patterns.append(venvdir + '/*') nitpick_ignore = [ + # Standard C functions + ('c:func', 'calloc'), + ('c:func', 'dlopen'), + ('c:func', 'exec'), + ('c:func', 'fcntl'), + ('c:func', 'fork'), + ('c:func', 'free'), + ('c:func', 'gmtime'), + ('c:func', 'localtime'), + ('c:func', 'main'), + ('c:func', 'malloc'), + ('c:func', 'printf'), + ('c:func', 'realloc'), + ('c:func', 'snprintf'), + ('c:func', 'sprintf'), + ('c:func', 'stat'), + ('c:func', 'system'), + ('c:func', 'vsnprintf'), # Standard C types ('c:type', 'FILE'), ('c:type', '__int'), diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst index 4ce15c69dac90b..875f846aad0051 100644 --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -292,11 +292,11 @@ Available static markers .. object:: function__return(str filename, str funcname, int lineno) - This marker is the converse of :c:func:`function__entry`, and indicates that + This marker is the converse of :c:func:`!function__entry`, and indicates that execution of a Python function has ended (either via ``return``, or via an exception). It is only triggered for pure-Python (bytecode) functions. - The arguments are the same as for :c:func:`function__entry` + The arguments are the same as for :c:func:`!function__entry` .. object:: line(str filename, str funcname, int lineno) @@ -304,7 +304,7 @@ Available static markers the equivalent of line-by-line tracing with a Python profiler. It is not triggered within C functions. - The arguments are the same as for :c:func:`function__entry`. + The arguments are the same as for :c:func:`!function__entry`. .. object:: gc__start(int generation) diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst index 56908dedea1b40..91df07d914cae2 100644 --- a/Doc/library/mailbox.rst +++ b/Doc/library/mailbox.rst @@ -477,7 +477,7 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. unlock() Three locking mechanisms are used---dot locking and, if available, the - :c:func:`flock` and :c:func:`lockf` system calls. + :c:func:`!flock` and :c:func:`!lockf` system calls. .. seealso:: @@ -588,7 +588,7 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. unlock() Three locking mechanisms are used---dot locking and, if available, the - :c:func:`flock` and :c:func:`lockf` system calls. For MH mailboxes, locking + :c:func:`!flock` and :c:func:`!lockf` system calls. For MH mailboxes, locking the mailbox means locking the :file:`.mh_sequences` file and, only for the duration of any operations that affect them, locking individual message files. @@ -686,7 +686,7 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. unlock() Three locking mechanisms are used---dot locking and, if available, the - :c:func:`flock` and :c:func:`lockf` system calls. + :c:func:`!flock` and :c:func:`!lockf` system calls. .. seealso:: @@ -737,7 +737,7 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. unlock() Three locking mechanisms are used---dot locking and, if available, the - :c:func:`flock` and :c:func:`lockf` system calls. + :c:func:`!flock` and :c:func:`!lockf` system calls. .. seealso:: diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 57405916ed7b31..bbf227aab649e2 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -714,14 +714,14 @@ process and user. .. function:: getsid(pid, /) - Call the system call :c:func:`getsid`. See the Unix manual for the semantics. + Call the system call :c:func:`!getsid`. See the Unix manual for the semantics. .. availability:: Unix, not Emscripten, not WASI. .. function:: setsid() - Call the system call :c:func:`setsid`. See the Unix manual for the semantics. + Call the system call :c:func:`!setsid`. See the Unix manual for the semantics. .. availability:: Unix, not Emscripten, not WASI. @@ -739,7 +739,7 @@ process and user. .. function:: strerror(code, /) Return the error message corresponding to the error code in *code*. - On platforms where :c:func:`strerror` returns ``NULL`` when given an unknown + On platforms where :c:func:`!strerror` returns ``NULL`` when given an unknown error number, :exc:`ValueError` is raised. diff --git a/Doc/library/select.rst b/Doc/library/select.rst index b0891b0c8f584a..c2941e628d9d78 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -6,10 +6,10 @@ -------------- -This module provides access to the :c:func:`select` and :c:func:`poll` functions -available in most operating systems, :c:func:`devpoll` available on -Solaris and derivatives, :c:func:`epoll` available on Linux 2.5+ and -:c:func:`kqueue` available on most BSD. +This module provides access to the :c:func:`!select` and :c:func:`!poll` functions +available in most operating systems, :c:func:`!devpoll` available on +Solaris and derivatives, :c:func:`!epoll` available on Linux 2.5+ and +:c:func:`!kqueue` available on most BSD. Note that on Windows, it only works for sockets; on other operating systems, it also works for other file types (in particular, on Unix, it works on pipes). It cannot be used on regular files to determine whether a file has grown since @@ -41,10 +41,10 @@ The module defines the following: polling object; see section :ref:`devpoll-objects` below for the methods supported by devpoll objects. - :c:func:`devpoll` objects are linked to the number of file + :c:func:`!devpoll` objects are linked to the number of file descriptors allowed at the time of instantiation. If your program - reduces this value, :c:func:`devpoll` will fail. If your program - increases this value, :c:func:`devpoll` may return an + reduces this value, :c:func:`!devpoll` will fail. If your program + increases this value, :c:func:`!devpoll` may return an incomplete list of active file descriptors. The new file descriptor is :ref:`non-inheritable `. @@ -62,7 +62,7 @@ The module defines the following: *sizehint* informs epoll about the expected number of events to be registered. It must be positive, or ``-1`` to use the default. It is only - used on older systems where :c:func:`epoll_create1` is not available; + used on older systems where :c:func:`!epoll_create1` is not available; otherwise it has no effect (though its value is still checked). *flags* is deprecated and completely ignored. However, when supplied, its @@ -117,7 +117,7 @@ The module defines the following: .. function:: select(rlist, wlist, xlist[, timeout]) - This is a straightforward interface to the Unix :c:func:`select` system call. + This is a straightforward interface to the Unix :c:func:`!select` system call. The first three arguments are iterables of 'waitable objects': either integers representing file descriptors or objects with a parameterless method named :meth:`~io.IOBase.fileno` returning such an integer: @@ -154,7 +154,7 @@ The module defines the following: .. index:: single: WinSock File objects on Windows are not acceptable, but sockets are. On Windows, - the underlying :c:func:`select` function is provided by the WinSock + the underlying :c:func:`!select` function is provided by the WinSock library, and does not handle file descriptors that don't originate from WinSock. @@ -169,7 +169,7 @@ The module defines the following: The minimum number of bytes which can be written without blocking to a pipe when the pipe has been reported as ready for writing by :func:`~select.select`, - :func:`poll` or another interface in this module. This doesn't apply + :func:`!poll` or another interface in this module. This doesn't apply to other kind of file-like objects such as sockets. This value is guaranteed by POSIX to be at least 512. @@ -184,11 +184,11 @@ The module defines the following: ``/dev/poll`` Polling Objects ----------------------------- -Solaris and derivatives have ``/dev/poll``. While :c:func:`select` is -O(highest file descriptor) and :c:func:`poll` is O(number of file +Solaris and derivatives have ``/dev/poll``. While :c:func:`!select` is +O(highest file descriptor) and :c:func:`!poll` is O(number of file descriptors), ``/dev/poll`` is O(active file descriptors). -``/dev/poll`` behaviour is very close to the standard :c:func:`poll` +``/dev/poll`` behaviour is very close to the standard :c:func:`!poll` object. @@ -222,7 +222,7 @@ object. implement :meth:`!fileno`, so they can also be used as the argument. *eventmask* is an optional bitmask describing the type of events you want to - check for. The constants are the same that with :c:func:`poll` + check for. The constants are the same that with :c:func:`!poll` object. The default value is a combination of the constants :const:`POLLIN`, :const:`POLLPRI`, and :const:`POLLOUT`. @@ -231,7 +231,7 @@ object. Registering a file descriptor that's already registered is not an error, but the result is undefined. The appropriate action is to unregister or modify it first. This is an important difference - compared with :c:func:`poll`. + compared with :c:func:`!poll`. .. method:: devpoll.modify(fd[, eventmask]) @@ -376,13 +376,13 @@ Edge and Level Trigger Polling (epoll) Objects Polling Objects --------------- -The :c:func:`poll` system call, supported on most Unix systems, provides better +The :c:func:`!poll` system call, supported on most Unix systems, provides better scalability for network servers that service many, many clients at the same -time. :c:func:`poll` scales better because the system call only requires listing -the file descriptors of interest, while :c:func:`select` builds a bitmap, turns +time. :c:func:`!poll` scales better because the system call only requires listing +the file descriptors of interest, while :c:func:`!select` builds a bitmap, turns on bits for the fds of interest, and then afterward the whole bitmap has to be -linearly scanned again. :c:func:`select` is O(highest file descriptor), while -:c:func:`poll` is O(number of file descriptors). +linearly scanned again. :c:func:`!select` is O(highest file descriptor), while +:c:func:`!poll` is O(number of file descriptors). .. method:: poll.register(fd[, eventmask]) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index 523d1ac5001360..e53315bee3ea3e 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -562,7 +562,7 @@ The :mod:`signal` module defines the following functions: Note that installing a signal handler with :func:`signal` will reset the restart behaviour to interruptible by implicitly calling - :c:func:`siginterrupt` with a true *flag* value for the given signal. + :c:func:`!siginterrupt` with a true *flag* value for the given signal. .. function:: signal(signalnum, handler) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index f333495017e2a1..b6adbcb34663e4 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -59,7 +59,6 @@ Doc/glossary.rst Doc/howto/curses.rst Doc/howto/descriptor.rst Doc/howto/enum.rst -Doc/howto/instrumentation.rst Doc/howto/isolating-extensions.rst Doc/howto/logging-cookbook.rst Doc/howto/logging.rst diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 72a273fdd8d122..2b8fa1546a5884 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -2289,7 +2289,7 @@ changes, or look through the Subversion logs for all the details. (Contributed by Raymond Hettinger; :issue:`1861`.) * The :mod:`select` module now has wrapper functions - for the Linux :c:func:`epoll` and BSD :c:func:`kqueue` system calls. + for the Linux :c:func:`!epoll` and BSD :c:func:`!kqueue` system calls. :meth:`modify` method was added to the existing :class:`poll` objects; ``pollobj.modify(fd, eventmask)`` takes a file descriptor or file object and an event mask, modifying the recorded event mask @@ -2328,7 +2328,7 @@ changes, or look through the Subversion logs for all the details. one for reading and one for writing. The writable descriptor will be passed to :func:`set_wakeup_fd`, and the readable descriptor will be added to the list of descriptors monitored by the event loop via - :c:func:`select` or :c:func:`poll`. + :c:func:`!select` or :c:func:`!poll`. On receiving a signal, a byte will be written and the main event loop will be woken up, avoiding the need to poll. @@ -2982,7 +2982,7 @@ Changes to Python's build process and to the C API include: * Python now must be compiled with C89 compilers (after 19 years!). This means that the Python source tree has dropped its - own implementations of :c:func:`memmove` and :c:func:`strerror`, which + own implementations of :c:func:`!memmove` and :c:func:`!strerror`, which are in the C89 standard library. * Python 2.6 can be built with Microsoft Visual Studio 2008 (version diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index a1d522b7ce6da1..cf8b00fd30979f 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -355,7 +355,7 @@ added as a more powerful replacement for the This means Python now supports three different modules for parsing command-line arguments: :mod:`getopt`, :mod:`optparse`, and :mod:`argparse`. The :mod:`getopt` module closely resembles the C -library's :c:func:`getopt` function, so it remains useful if you're writing a +library's :c:func:`!getopt` function, so it remains useful if you're writing a Python prototype that will eventually be rewritten in C. :mod:`optparse` becomes redundant, but there are no plans to remove it because there are many scripts still using it, and there's no diff --git a/Misc/NEWS.d/3.10.0a1.rst b/Misc/NEWS.d/3.10.0a1.rst index f7eb8036bc5cf2..c1437172a38be3 100644 --- a/Misc/NEWS.d/3.10.0a1.rst +++ b/Misc/NEWS.d/3.10.0a1.rst @@ -228,8 +228,8 @@ format string in f-string and :meth:`str.format`. .. section: Core and Builtins The implementation of :func:`signal.siginterrupt` now uses -:c:func:`sigaction` (if it is available in the system) instead of the -deprecated :c:func:`siginterrupt`. Patch by Pablo Galindo. +:c:func:`!sigaction` (if it is available in the system) instead of the +deprecated :c:func:`!siginterrupt`. Patch by Pablo Galindo. .. From 84c5676e91468642f64f137de85301a5b766b758 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 23 Jul 2023 15:00:51 -0700 Subject: [PATCH 0423/1206] [3.12] gh-105291: Add link to migration guide for distutils (GH-107130) (#107160) Co-authored-by: cLupus Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a7db645657db1e..71b9358323e3d0 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -84,7 +84,9 @@ Important deprecations, removals or restrictions: * :pep:`623`: Remove wstr from Unicode -* :pep:`632`: Remove the ``distutils`` package +* :pep:`632`: Remove the ``distutils`` package. See + `the migration guide `_ + for advice on its replacement. Improved Error Messages ======================= From 03271069afc494061c92efa8b8f792e3f2c0b6e4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 05:03:01 -0700 Subject: [PATCH 0424/1206] [3.12] Docs: Remove duplicate word in Argument Clinic howto heading (GH-107169) (#107171) (cherry picked from commit ebe44a5155e9abc70c4b8914ad26b27c2b84f72b) Co-authored-by: Hakan Celik --- Doc/howto/clinic.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index f6bf1d2234f88d..933fecab9ddd5a 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -582,8 +582,8 @@ How-to guides ============= -How to to rename C functions and variables generated by Argument Clinic ------------------------------------------------------------------------ +How to rename C functions and variables generated by Argument Clinic +-------------------------------------------------------------------- Argument Clinic automatically names the functions it generates for you. Occasionally this may cause a problem, if the generated name collides with From 4fd576478c99b999feac68b71f317fd9d320662f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 06:06:16 -0700 Subject: [PATCH 0425/1206] [3.12] Fix PyVectorcall_Function doc versionadded (GH-107140) (#107173) Fix PyVectorcall_Function doc versionadded (GH-107140) The documentation implies that PyVectorcall_Function() was available in Python 3.8. This is half-true - it was available under a different name. I think it's clearer to set the "version added" to 3.9. (cherry picked from commit 0a9b339363a59be1249189c767ed6f46fd71e1c7) Co-authored-by: da-woods --- Doc/c-api/call.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index 143fce3cdf477e..f4e401442c3d27 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -165,7 +165,7 @@ Vectorcall Support API This is mostly useful to check whether or not *op* supports vectorcall, which can be done by checking ``PyVectorcall_Function(op) != NULL``. - .. versionadded:: 3.8 + .. versionadded:: 3.9 .. c:function:: PyObject* PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict) From 5ff4dfa0cb6faf28368691c6291b02bd8a38ecb8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 08:32:51 -0700 Subject: [PATCH 0426/1206] [3.12] Docs: Add missing markup to Argument Clinic docs (GH-106876) (#107181) (cherry picked from commit ff5f94b72c8aad8e45c397c263dbe7f19221735f) Co-authored-by: Erlend E. Aasland Co-authored-by: Ezio Melotti Co-authored-by: Serhiy Storchaka --- Doc/howto/clinic.rst | 269 +++++++++++++++++++++++-------------------- 1 file changed, 143 insertions(+), 126 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 933fecab9ddd5a..98d3632ff02325 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -96,7 +96,8 @@ things with all the information you give it. Basic concepts and usage ------------------------ -Argument Clinic ships with CPython; you'll find it in ``Tools/clinic/clinic.py``. +Argument Clinic ships with CPython; you'll find it in +:source:`Tools/clinic/clinic.py`. If you run that script, specifying a C file as an argument: .. code-block:: shell-session @@ -178,9 +179,10 @@ Let's dive in! 1. Find a Python builtin that calls either :c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted to work with Argument Clinic yet. - For my example I'm using ``_pickle.Pickler.dump()``. + For my example I'm using + :py:meth:`_pickle.Pickler.dump `. -2. If the call to the ``PyArg_Parse`` function uses any of the +2. If the call to the :c:func:`!PyArg_Parse*` function uses any of the following format units: .. code-block:: none @@ -197,10 +199,10 @@ Let's dive in! support all of these scenarios. But these are advanced topics—let's do something simpler for your first function. - Also, if the function has multiple calls to :c:func:`PyArg_ParseTuple` + Also, if the function has multiple calls to :c:func:`!PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords` where it supports different types for the same argument, or if the function uses something besides - PyArg_Parse functions to parse its arguments, it probably + :c:func:`!PyArg_Parse*` functions to parse its arguments, it probably isn't suitable for conversion to Argument Clinic. Argument Clinic doesn't support generic functions or polymorphic parameters. @@ -217,7 +219,7 @@ Let's dive in! If the old docstring had a first line that looked like a function signature, throw that line away. (The docstring doesn't need it - anymore—when you use ``help()`` on your builtin in the future, + anymore—when you use :py:func:`help` on your builtin in the future, the first line will be built automatically based on the function's signature.) @@ -264,7 +266,7 @@ Let's dive in! When you declare a class, you must also specify two aspects of its type in C: the type declaration you'd use for a pointer to an instance of - this class, and a pointer to the :c:type:`PyTypeObject` for this class. + this class, and a pointer to the :c:type:`!PyTypeObject` for this class. Sample:: @@ -313,10 +315,10 @@ Let's dive in! Clinic easier. For each parameter, copy the "format unit" for that - parameter from the ``PyArg_Parse()`` format argument and + parameter from the :c:func:`PyArg_Parse` format argument and specify *that* as its converter, as a quoted string. ("format unit" is the formal name for the one-to-three - character substring of the ``format`` parameter that tells + character substring of the *format* parameter that tells the argument parsing function what the type of the variable is and how to convert it. For more on format units please see :ref:`arg-parsing`.) @@ -349,7 +351,7 @@ Let's dive in! itself before the first keyword-only argument, indented the same as the parameter lines. - (``_pickle.Pickler.dump`` has neither, so our sample is unchanged.) + (:py:meth:`!_pickle.Pickler.dump` has neither, so our sample is unchanged.) 10. If the existing C function calls :c:func:`PyArg_ParseTuple` @@ -410,7 +412,7 @@ Let's dive in! 12. Save and close the file, then run ``Tools/clinic/clinic.py`` on it. With luck everything worked---your block now has output, and - a ``.c.h`` file has been generated! Reopen the file in your + a :file:`.c.h` file has been generated! Reopen the file in your text editor to see:: /*[clinic input] @@ -431,8 +433,8 @@ Let's dive in! it found an error in your input. Keep fixing your errors and retrying until Argument Clinic processes your file without complaint. - For readability, most of the glue code has been generated to a ``.c.h`` - file. You'll need to include that in your original ``.c`` file, + For readability, most of the glue code has been generated to a :file:`.c.h` + file. You'll need to include that in your original :file:`.c` file, typically right after the clinic module block:: #include "clinic/_pickle.c.h" @@ -446,8 +448,8 @@ Let's dive in! ensure that the code generated by Argument Clinic calls the *exact* same function. - Second, the format string passed in to :c:func:`PyArg_ParseTuple` or - :c:func:`PyArg_ParseTupleAndKeywords` should be *exactly* the same + Second, the format string passed in to :c:func:`!PyArg_ParseTuple` or + :c:func:`!PyArg_ParseTupleAndKeywords` should be *exactly* the same as the hand-written one in the existing function, up to the colon or semi-colon. @@ -469,7 +471,7 @@ Let's dive in! {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, This static structure should be *exactly* the same as the existing static - :c:type:`PyMethodDef` structure for this builtin. + :c:type:`!PyMethodDef` structure for this builtin. If any of these items differ in *any way*, adjust your Argument Clinic function specification and rerun @@ -539,14 +541,14 @@ Let's dive in! ... 15. Remember the macro with the :c:type:`PyMethodDef` structure for this - function? Find the existing :c:type:`PyMethodDef` structure for this + function? Find the existing :c:type:`!PyMethodDef` structure for this function and replace it with a reference to the macro. (If the builtin is at module scope, this will probably be very near the end of the file; if the builtin is a class method, this will probably be below but relatively near to the implementation.) Note that the body of the macro contains a trailing comma. So when you - replace the existing static :c:type:`PyMethodDef` structure with the macro, + replace the existing static :c:type:`!PyMethodDef` structure with the macro, *don't* add a comma to the end. Sample:: @@ -562,7 +564,7 @@ Let's dive in! &_Py_ID(new_unique_py_id) - If it does, you'll have to run ``Tools/scripts/generate_global_objects.py`` + If it does, you'll have to run ``make regen-global-objects`` to regenerate the list of precompiled identifiers at this point. @@ -570,7 +572,7 @@ Let's dive in! This change should not introduce any new compile-time warnings or errors, and there should be no externally visible change to Python's behavior. - Well, except for one difference: ``inspect.signature()`` run on your function + Well, except for one difference: :py:func:`inspect.signature` run on your function should now provide a valid signature! Congratulations, you've ported your first function to work with Argument Clinic! @@ -594,15 +596,15 @@ Argument Clinic will use that function name for the base (generated) function, then add ``"_impl"`` to the end and use that for the name of the impl function. For example, if we wanted to rename the C function names generated for -``pickle.Pickler.dump``, it'd look like this:: +:py:meth:`pickle.Pickler.dump`, it'd look like this:: /*[clinic input] pickle.Pickler.dump as pickler_dumper ... -The base function would now be named ``pickler_dumper()``, -and the impl function would now be named ``pickler_dumper_impl()``. +The base function would now be named :c:func:`!pickler_dumper`, +and the impl function would now be named :c:func:`!pickler_dumper_impl`. Similarly, you may have a problem where you want to give a parameter @@ -620,9 +622,9 @@ using the same ``"as"`` syntax:: fix_imports: bool = True Here, the name used in Python (in the signature and the ``keywords`` -array) would be ``file``, but the C variable would be named ``file_obj``. +array) would be *file*, but the C variable would be named ``file_obj``. -You can use this to rename the ``self`` parameter too! +You can use this to rename the *self* parameter too! How to convert functions using ``PyArg_UnpackTuple`` @@ -630,7 +632,7 @@ How to convert functions using ``PyArg_UnpackTuple`` To convert a function parsing its arguments with :c:func:`PyArg_UnpackTuple`, simply write out all the arguments, specifying each as an ``object``. You -may specify the ``type`` argument to cast the type as appropriate. All +may specify the *type* argument to cast the type as appropriate. All arguments should be marked positional-only (add a ``/`` on a line by itself after the last argument). @@ -649,16 +651,16 @@ keyword-only arguments.) This approach was used to simulate optional arguments back before :c:func:`PyArg_ParseTupleAndKeywords` was created. While functions using this approach can often be converted to -use :c:func:`PyArg_ParseTupleAndKeywords`, optional arguments, and default values, +use :c:func:`!PyArg_ParseTupleAndKeywords`, optional arguments, and default values, it's not always possible. Some of these legacy functions have -behaviors :c:func:`PyArg_ParseTupleAndKeywords` doesn't directly support. -The most obvious example is the builtin function ``range()``, which has +behaviors :c:func:`!PyArg_ParseTupleAndKeywords` doesn't directly support. +The most obvious example is the builtin function :py:func:`range`, which has an optional argument on the *left* side of its required argument! -Another example is ``curses.window.addch()``, which has a group of two +Another example is :py:meth:`curses.window.addch`, which has a group of two arguments that must always be specified together. (The arguments are -called ``x`` and ``y``; if you call the function passing in ``x``, -you must also pass in ``y``—and if you don't pass in ``x`` you may not -pass in ``y`` either.) +called *x* and *y*; if you call the function passing in *x*, +you must also pass in *y* — and if you don't pass in *x* you may not +pass in *y* either.) In any case, the goal of Argument Clinic is to support argument parsing for all existing CPython builtins without changing their semantics. @@ -679,7 +681,7 @@ can *only* be used with positional-only parameters. To specify an optional group, add a ``[`` on a line by itself before the parameters you wish to group together, and a ``]`` on a line by itself -after these parameters. As an example, here's how ``curses.window.addch`` +after these parameters. As an example, here's how :py:meth:`curses.window.addch` uses optional groups to make the first two parameters and the last parameter optional:: @@ -765,25 +767,25 @@ the same converters. All arguments to Argument Clinic converters are keyword-only. All Argument Clinic converters accept the following arguments: - ``c_default`` + *c_default* The default value for this parameter when defined in C. Specifically, this will be the initializer for the variable declared in the "parse function". See :ref:`the section on default values ` for how to use this. Specified as a string. - ``annotation`` + *annotation* The annotation value for this parameter. Not currently supported, because :pep:`8` mandates that the Python library may not use annotations. - ``unused`` + *unused* Wrap the argument with :c:macro:`Py_UNUSED` in the impl function signature. In addition, some converters accept additional arguments. Here is a list of these arguments, along with their meanings: - ``accept`` + *accept* A set of Python types (and possibly pseudo-types); this restricts the allowable Python argument to values of these types. (This is not a general-purpose facility; as a rule it only supports @@ -791,38 +793,38 @@ of these arguments, along with their meanings: To accept ``None``, add ``NoneType`` to this set. - ``bitwise`` + *bitwise* Only supported for unsigned integers. The native integer value of this Python argument will be written to the parameter without any range checking, even for negative values. - ``converter`` + *converter* Only supported by the ``object`` converter. Specifies the name of a :ref:`C "converter function" ` to use to convert this object to a native type. - ``encoding`` + *encoding* Only supported for strings. Specifies the encoding to use when converting this string from a Python str (Unicode) value into a C ``char *`` value. - ``subclass_of`` + *subclass_of* Only supported for the ``object`` converter. Requires that the Python value be a subclass of a Python type, as expressed in C. - ``type`` + *type* Only supported for the ``object`` and ``self`` converters. Specifies the C type that will be used to declare the variable. Default value is ``"PyObject *"``. - ``zeroes`` + *zeroes* Only supported for strings. If true, embedded NUL bytes (``'\\0'``) are permitted inside the value. The length of the string will be passed in to the impl function, just after the string parameter, as a parameter named ``_length``. Please note, not every possible combination of arguments will work. -Usually these arguments are implemented by specific ``PyArg_ParseTuple`` +Usually these arguments are implemented by specific :c:func:`PyArg_ParseTuple` *format units*, with specific behavior. For example, currently you cannot call ``unsigned_short`` without also specifying ``bitwise=True``. Although it's perfectly reasonable to think this would work, these semantics don't @@ -922,19 +924,19 @@ conversion functions, or types, or strings specifying an encoding. (But "legacy converters" don't support arguments. That's why we skipped them for your first function.) The argument you specified to the format unit is now an argument to the converter; this -argument is either ``converter`` (for ``O&``), ``subclass_of`` (for ``O!``), -or ``encoding`` (for all the format units that start with ``e``). +argument is either *converter* (for ``O&``), *subclass_of* (for ``O!``), +or *encoding* (for all the format units that start with ``e``). -When using ``subclass_of``, you may also want to use the other -custom argument for ``object()``: ``type``, which lets you set the type +When using *subclass_of*, you may also want to use the other +custom argument for ``object()``: *type*, which lets you set the type actually used for the parameter. For example, if you want to ensure -that the object is a subclass of ``PyUnicode_Type``, you probably want +that the object is a subclass of :c:var:`PyUnicode_Type`, you probably want to use the converter ``object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type')``. One possible problem with using Argument Clinic: it takes away some possible flexibility for the format units starting with ``e``. When writing a -``PyArg_Parse`` call by hand, you could theoretically decide at runtime what -encoding string to pass in to :c:func:`PyArg_ParseTuple`. But now this string must +:c:func:`!PyArg_Parse*` call by hand, you could theoretically decide at runtime what +encoding string to pass to that call. But now this string must be hard-coded at Argument-Clinic-preprocessing-time. This limitation is deliberate; it made supporting this format unit much easier, and may allow for future optimizations. This restriction doesn't seem unreasonable; CPython itself always passes in static @@ -987,7 +989,7 @@ expression. Currently the following are explicitly supported: * Numeric constants (integer and float) * String constants * ``True``, ``False``, and ``None`` -* Simple symbolic constants like ``sys.maxsize``, which must +* Simple symbolic constants like :py:data:`sys.maxsize`, which must start with the name of the module (In the future, this may need to get even more elaborate, @@ -1008,28 +1010,28 @@ Consider the following example: foo: Py_ssize_t = sys.maxsize - 1 -``sys.maxsize`` can have different values on different platforms. Therefore +:py:data:`sys.maxsize` can have different values on different platforms. Therefore Argument Clinic can't simply evaluate that expression locally and hard-code it in C. So it stores the default in such a way that it will get evaluated at runtime, when the user asks for the function's signature. What namespace is available when the expression is evaluated? It's evaluated in the context of the module the builtin came from. So, if your module has an -attribute called "``max_widgets``", you may simply use it: +attribute called :py:attr:`!max_widgets`, you may simply use it: .. code-block:: none foo: Py_ssize_t = max_widgets If the symbol isn't found in the current module, it fails over to looking in -``sys.modules``. That's how it can find ``sys.maxsize`` for example. (Since you -don't know in advance what modules the user will load into their interpreter, +:py:data:`sys.modules`. That's how it can find :py:data:`sys.maxsize` for example. +(Since you don't know in advance what modules the user will load into their interpreter, it's best to restrict yourself to modules that are preloaded by Python itself.) Evaluating default values only at runtime means Argument Clinic can't compute the correct equivalent C default value. So you need to tell it explicitly. When you use an expression, you must also specify the equivalent expression -in C, using the ``c_default`` parameter to the converter: +in C, using the *c_default* parameter to the converter: .. code-block:: none @@ -1095,7 +1097,7 @@ indicate an error has occurred? Normally, a function returns a valid (non-``NUL pointer for success, and ``NULL`` for failure. But if you use an integer return converter, all integers are valid. How can Argument Clinic detect an error? Its solution: each return converter implicitly looks for a special value that indicates an error. If you return -that value, and an error has been set (``PyErr_Occurred()`` returns a true +that value, and an error has been set (c:func:`PyErr_Occurred` returns a true value), then the generated code will propagate the error. Otherwise it will encode the value you return like normal. @@ -1201,9 +1203,9 @@ using a default converter. It automatically sets the ``type`` of this parameter to the "pointer to an instance" you specified when you declared the type. However, you can override Argument Clinic's converter and specify one yourself. -Just add your own ``self`` parameter as the first parameter in a +Just add your own *self* parameter as the first parameter in a block, and ensure that its converter is an instance of -``self_converter`` or a subclass thereof. +:class:`!self_converter` or a subclass thereof. What's the point? This lets you override the type of ``self``, or give it a different default name. @@ -1211,7 +1213,7 @@ or give it a different default name. How do you specify the custom type you want to cast ``self`` to? If you only have one or two functions with the same type for ``self``, you can directly use Argument Clinic's existing ``self`` converter, -passing in the type you want to use as the ``type`` parameter:: +passing in the type you want to use as the *type* parameter:: /*[clinic input] @@ -1226,7 +1228,7 @@ passing in the type you want to use as the ``type`` parameter:: On the other hand, if you have a lot of functions that will use the same type for ``self``, it's best to create your own converter, subclassing -``self_converter`` but overwriting the ``type`` member:: +:class:`!self_converter` but overwriting the :py:attr:`!type` member:: /*[python input] class PicklerObject_converter(self_converter): @@ -1254,8 +1256,8 @@ module level state. Use :c:func:`PyType_FromModuleAndSpec` to associate a new heap type with a module. You can now use :c:func:`PyType_GetModuleState` on the defining class to fetch the module state, for example from a module method. -Example from ``Modules/zlibmodule.c``. First, ``defining_class`` is added to -the clinic input:: +Example from :source:`Modules/zlibmodule.c`. +First, ``defining_class`` is added to the clinic input:: /*[clinic input] zlib.Compress.compress @@ -1285,16 +1287,17 @@ module state:: Each method may only have one argument using this converter, and it must appear after ``self``, or, if ``self`` is not used, as the first argument. The argument will be of type ``PyTypeObject *``. The argument will not appear in the -``__text_signature__``. +:py:attr:`!__text_signature__`. -The ``defining_class`` converter is not compatible with ``__init__`` and ``__new__`` -methods, which cannot use the ``METH_METHOD`` convention. +The ``defining_class`` converter is not compatible with :py:meth:`!__init__` +and :py:meth:`!__new__` methods, which cannot use the :c:macro:`METH_METHOD` +convention. It is not possible to use ``defining_class`` with slot methods. In order to fetch the module state from such methods, use :c:func:`PyType_GetModuleByDef` to look up the module and then :c:func:`PyModule_GetState` to fetch the module state. Example from the ``setattro`` slot method in -``Modules/_threadmodule.c``:: +:source:`Modules/_threadmodule.c`:: static int local_setattro(localobject *self, PyObject *name, PyObject *v) @@ -1312,7 +1315,7 @@ How to write a custom converter ------------------------------- As we hinted at in the previous section... you can write your own converters! -A converter is simply a Python class that inherits from ``CConverter``. +A converter is simply a Python class that inherits from :py:class:`!CConverter`. The main purpose of a custom converter is if you have a parameter using the ``O&`` format unit—parsing this parameter means calling a :c:func:`PyArg_ParseTuple` "converter function". @@ -1323,61 +1326,74 @@ will be automatically registered with Argument Clinic; its name will be the name of your class with the ``_converter`` suffix stripped off. (This is accomplished with a metaclass.) -You shouldn't subclass ``CConverter.__init__``. Instead, you should -write a ``converter_init()`` function. ``converter_init()`` -always accepts a ``self`` parameter; after that, all additional +You shouldn't subclass :py:meth:`!CConverter.__init__`. Instead, you should +write a :py:meth:`!converter_init` function. :py:meth:`!converter_init` +always accepts a *self* parameter; after that, all additional parameters *must* be keyword-only. Any arguments passed in to the converter in Argument Clinic will be passed along to your -``converter_init()``. +:py:meth:`!converter_init`. -There are some additional members of ``CConverter`` you may wish +There are some additional members of :py:class:`!CConverter` you may wish to specify in your subclass. Here's the current list: -``type`` - The C type to use for this variable. - ``type`` should be a Python string specifying the type, e.g. ``int``. - If this is a pointer type, the type string should end with ``' *'``. +.. module:: clinic -``default`` - The Python default value for this parameter, as a Python value. - Or the magic value ``unspecified`` if there is no default. +.. class:: CConverter -``py_default`` - ``default`` as it should appear in Python code, - as a string. - Or ``None`` if there is no default. + .. attribute:: type -``c_default`` - ``default`` as it should appear in C code, - as a string. - Or ``None`` if there is no default. + The C type to use for this variable. + :attr:`!type` should be a Python string specifying the type, + e.g. ``'int'``. + If this is a pointer type, the type string should end with ``' *'``. -``c_ignored_default`` - The default value used to initialize the C variable when - there is no default, but not specifying a default may - result in an "uninitialized variable" warning. This can - easily happen when using option groups—although - properly written code will never actually use this value, - the variable does get passed in to the impl, and the - C compiler will complain about the "use" of the - uninitialized value. This value should always be a - non-empty string. + .. attribute:: default -``converter`` - The name of the C converter function, as a string. + The Python default value for this parameter, as a Python value. + Or the magic value ``unspecified`` if there is no default. -``impl_by_reference`` - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into the impl function. + .. attribute:: py_default -``parse_by_reference`` - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into :c:func:`PyArg_ParseTuple`. + :attr:`!default` as it should appear in Python code, + as a string. + Or ``None`` if there is no default. + .. attribute:: c_default -Here's the simplest example of a custom converter, from ``Modules/zlibmodule.c``:: + :attr:`!default` as it should appear in C code, + as a string. + Or ``None`` if there is no default. + + .. attribute:: c_ignored_default + + The default value used to initialize the C variable when + there is no default, but not specifying a default may + result in an "uninitialized variable" warning. This can + easily happen when using option groups—although + properly written code will never actually use this value, + the variable does get passed in to the impl, and the + C compiler will complain about the "use" of the + uninitialized value. This value should always be a + non-empty string. + + .. attribute:: converter + + The name of the C converter function, as a string. + + .. attribute:: impl_by_reference + + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into the impl function. + + .. attribute:: parse_by_reference + + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into :c:func:`PyArg_ParseTuple`. + + +Here's the simplest example of a custom converter, from :source:`Modules/zlibmodule.c`:: /*[python input] @@ -1397,7 +1413,7 @@ automatically support default values. More sophisticated custom converters can insert custom C code to handle initialization and cleanup. You can see more examples of custom converters in the CPython -source tree; grep the C files for the string ``CConverter``. +source tree; grep the C files for the string :py:class:`!CConverter`. How to write a custom return converter @@ -1407,18 +1423,18 @@ Writing a custom return converter is much like writing a custom converter. Except it's somewhat simpler, because return converters are themselves much simpler. -Return converters must subclass ``CReturnConverter``. +Return converters must subclass :py:class:`!CReturnConverter`. There are no examples yet of custom return converters, because they are not widely used yet. If you wish to -write your own return converter, please read ``Tools/clinic/clinic.py``, -specifically the implementation of ``CReturnConverter`` and +write your own return converter, please read :source:`Tools/clinic/clinic.py`, +specifically the implementation of :py:class:`!CReturnConverter` and all its subclasses. How to convert ``METH_O`` and ``METH_NOARGS`` functions ------------------------------------------------------- -To convert a function using ``METH_O``, make sure the function's +To convert a function using :c:macro:`METH_O`, make sure the function's single argument is using the ``object`` converter, and mark the arguments as positional-only:: @@ -1430,24 +1446,25 @@ arguments as positional-only:: [clinic start generated code]*/ -To convert a function using ``METH_NOARGS``, just don't specify +To convert a function using :c:macro:`METH_NOARGS`, just don't specify any arguments. You can still use a self converter, a return converter, and specify -a ``type`` argument to the object converter for ``METH_O``. +a *type* argument to the object converter for :c:macro:`METH_O`. How to convert ``tp_new`` and ``tp_init`` functions --------------------------------------------------- -You can convert ``tp_new`` and ``tp_init`` functions. Just name -them ``__new__`` or ``__init__`` as appropriate. Notes: +You can convert :c:member:`~PyTypeObject.tp_new` and +:c:member:`~PyTypeObject.tp_init` functions. +Just name them ``__new__`` or ``__init__`` as appropriate. Notes: * The function name generated for ``__new__`` doesn't end in ``__new__`` like it would by default. It's just the name of the class, converted into a valid C identifier. -* No ``PyMethodDef`` ``#define`` is generated for these functions. +* No :c:type:`PyMethodDef` ``#define`` is generated for these functions. * ``__init__`` functions return ``int``, not ``PyObject *``. @@ -1482,7 +1499,7 @@ Let's start with defining some terminology: *field* A field, in this context, is a subsection of Clinic's output. - For example, the ``#define`` for the ``PyMethodDef`` structure + For example, the ``#define`` for the :c:type:`PyMethodDef` structure is a field, called ``methoddef_define``. Clinic has seven different fields it can output per function definition: @@ -1526,8 +1543,8 @@ Let's start with defining some terminology: The filename chosen for the file is ``{basename}.clinic{extension}``, where ``basename`` and ``extension`` were assigned the output from ``os.path.splitext()`` run on the current file. (Example: - the ``file`` destination for ``_pickle.c`` would be written to - ``_pickle.clinic.c``.) + the ``file`` destination for :file:`_pickle.c` would be written to + :file:`_pickle.clinic.c`.) **Important: When using a** ``file`` **destination, you** *must check in* **the generated file!** @@ -1780,7 +1797,7 @@ like so:: } #endif /* HAVE_FUNCTIONNAME */ -Then, remove those three lines from the ``PyMethodDef`` structure, +Then, remove those three lines from the :c:type:`PyMethodDef` structure, replacing them with the macro Argument Clinic generated: .. code-block:: none @@ -1821,7 +1838,7 @@ This may mean that you get a complaint from Argument Clinic: When this happens, just open your file, find the ``dump buffer`` block that Argument Clinic added to your file (it'll be at the very bottom), then -move it above the ``PyMethodDef`` structure where that macro is used. +move it above the :c:type:`PyMethodDef` structure where that macro is used. How to use Argument Clinic in Python files From beb5514826e5e1fb2ec2cd1ad137b84091399f7a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 09:30:22 -0700 Subject: [PATCH 0427/1206] [3.12] gh-107017: Change Chapter Strings to Texts in the Introduction chapter. (GH-107104) (#107167) Co-authored-by: TommyUnreal <45427816+TommyUnreal@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/tutorial/introduction.rst | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 4b886f604aca23..0fc75c7d7532e2 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -138,16 +138,25 @@ and uses the ``j`` or ``J`` suffix to indicate the imaginary part .. _tut-strings: -Strings -------- +Text +---- -Besides numbers, Python can also manipulate strings, which can be expressed -in several ways. They can be enclosed in single quotes (``'...'``) or -double quotes (``"..."``) with the same result [#]_. ``\`` can be used -to escape quotes:: +Python can manipulate text (represented by type :class:`str`, so-called +"strings") as well as numbers. This includes characters "``!``", words +"``rabbit``", names "``Paris``", sentences "``Got your back.``", etc. +"``Yay! :)``". They can be enclosed in single quotes (``'...'``) or double +quotes (``"..."``) with the same result [#]_. >>> 'spam eggs' # single quotes 'spam eggs' + >>> "Paris rabbit got your back :)! Yay!" # double quotes + 'Paris rabbit got your back :)! Yay!' + >>> '1975' # digits and numerals enclosed in quotes are also strings + '1975' + +To quote a quote, we need to "escape" it, by preceding it with ``\``. +Alternatively, we can use the other type of quotation marks:: + >>> 'doesn\'t' # use \' to escape the single quote... "doesn't" >>> "doesn't" # ...or use double quotes instead @@ -159,23 +168,14 @@ to escape quotes:: >>> '"Isn\'t," they said.' '"Isn\'t," they said.' -In the interactive interpreter, the output string is enclosed in quotes and -special characters are escaped with backslashes. While this might sometimes -look different from the input (the enclosing quotes could change), the two -strings are equivalent. The string is enclosed in double quotes if -the string contains a single quote and no double quotes, otherwise it is -enclosed in single quotes. The :func:`print` function produces a more -readable output, by omitting the enclosing quotes and by printing escaped -and special characters:: +In the Python shell, the string definition and output string can look +different. The :func:`print` function produces a more readable output, by +omitting the enclosing quotes and by printing escaped and special characters:: - >>> '"Isn\'t," they said.' - '"Isn\'t," they said.' - >>> print('"Isn\'t," they said.') - "Isn't," they said. >>> s = 'First line.\nSecond line.' # \n means newline - >>> s # without print(), \n is included in the output + >>> s # without print(), special characters are included in the string 'First line.\nSecond line.' - >>> print(s) # with print(), \n produces a new line + >>> print(s) # with print(), special characters are interpreted, so \n produces new line First line. Second line. From 69d4e8c090efd4f3a958ba056580bc1ee9865d0e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:19:36 -0700 Subject: [PATCH 0428/1206] [3.12] gh-106368: Increase Argument Clinic CLI test coverage (GH-107156) (#107189) Instead of hacking into the Clinic class, use the Argument Clinic tool to run the ClinicExternalTest test suite. (cherry picked from commit 83a2837b328c58b243f7d97bec12c64ec66681c5) Co-authored-by: Erlend E. Aasland Co-authored-by: Nikita Sobolev --- Lib/test/test_clinic.py | 190 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index c24b8cd3899f28..f5271203362263 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -4,11 +4,14 @@ from test import support, test_tools from test.support import os_helper +from test.support import SHORT_TIMEOUT, requires_subprocess +from test.support.os_helper import TESTFN, unlink from textwrap import dedent from unittest import TestCase import collections import inspect import os.path +import subprocess import sys import unittest @@ -1346,31 +1349,190 @@ def test_scaffolding(self): class ClinicExternalTest(TestCase): maxDiff = None + def _do_test(self, *args, expect_success=True): + clinic_py = os.path.join(test_tools.toolsdir, "clinic", "clinic.py") + with subprocess.Popen( + [sys.executable, "-Xutf8", clinic_py, *args], + encoding="utf-8", + bufsize=0, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) as proc: + proc.wait() + if expect_success == bool(proc.returncode): + self.fail("".join(proc.stderr)) + stdout = proc.stdout.read() + stderr = proc.stderr.read() + # Clinic never writes to stderr. + self.assertEqual(stderr, "") + return stdout + + def expect_success(self, *args): + return self._do_test(*args) + + def expect_failure(self, *args): + return self._do_test(*args, expect_success=False) + def test_external(self): CLINIC_TEST = 'clinic.test.c' - # bpo-42398: Test that the destination file is left unchanged if the - # content does not change. Moreover, check also that the file - # modification time does not change in this case. source = support.findfile(CLINIC_TEST) with open(source, 'r', encoding='utf-8') as f: orig_contents = f.read() - with os_helper.temp_dir() as tmp_dir: - testfile = os.path.join(tmp_dir, CLINIC_TEST) - with open(testfile, 'w', encoding='utf-8') as f: - f.write(orig_contents) - old_mtime_ns = os.stat(testfile).st_mtime_ns - - clinic.parse_file(testfile) + # Run clinic CLI and verify that it does not complain. + self.addCleanup(unlink, TESTFN) + out = self.expect_success("-f", "-o", TESTFN, source) + self.assertEqual(out, "") - with open(testfile, 'r', encoding='utf-8') as f: - new_contents = f.read() - new_mtime_ns = os.stat(testfile).st_mtime_ns + with open(TESTFN, 'r', encoding='utf-8') as f: + new_contents = f.read() self.assertEqual(new_contents, orig_contents) + + def test_no_change(self): + # bpo-42398: Test that the destination file is left unchanged if the + # content does not change. Moreover, check also that the file + # modification time does not change in this case. + code = dedent(""" + /*[clinic input] + [clinic start generated code]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=da39a3ee5e6b4b0d]*/ + """) + with os_helper.temp_dir() as tmp_dir: + fn = os.path.join(tmp_dir, "test.c") + with open(fn, "w", encoding="utf-8") as f: + f.write(code) + pre_mtime = os.stat(fn).st_mtime_ns + self.expect_success(fn) + post_mtime = os.stat(fn).st_mtime_ns # Don't change the file modification time # if the content does not change - self.assertEqual(new_mtime_ns, old_mtime_ns) + self.assertEqual(pre_mtime, post_mtime) + + def test_cli_force(self): + invalid_input = dedent(""" + /*[clinic input] + output preset block + module test + test.fn + a: int + [clinic start generated code]*/ + + const char *hand_edited = "output block is overwritten"; + /*[clinic end generated code: output=bogus input=bogus]*/ + """) + fail_msg = dedent(""" + Checksum mismatch! + Expected: bogus + Computed: 2ed19 + Suggested fix: remove all generated code including the end marker, + or use the '-f' option. + """) + with os_helper.temp_dir() as tmp_dir: + fn = os.path.join(tmp_dir, "test.c") + with open(fn, "w", encoding="utf-8") as f: + f.write(invalid_input) + # First, run the CLI without -f and expect failure. + # Note, we cannot check the entire fail msg, because the path to + # the tmp file will change for every run. + out = self.expect_failure(fn) + self.assertTrue(out.endswith(fail_msg)) + # Then, force regeneration; success expected. + out = self.expect_success("-f", fn) + self.assertEqual(out, "") + # Verify by checking the checksum. + checksum = ( + "/*[clinic end generated code: " + "output=2124c291eb067d76 input=9543a8d2da235301]*/\n" + ) + with open(fn, 'r', encoding='utf-8') as f: + generated = f.read() + self.assertTrue(generated.endswith(checksum)) + + def test_cli_verbose(self): + with os_helper.temp_dir() as tmp_dir: + fn = os.path.join(tmp_dir, "test.c") + with open(fn, "w", encoding="utf-8") as f: + f.write("") + out = self.expect_success("-v", fn) + self.assertEqual(out.strip(), fn) + + def test_cli_help(self): + out = self.expect_success("-h") + self.assertIn("usage: clinic.py", out) + + def test_cli_converters(self): + prelude = dedent(""" + Legacy converters: + B C D L O S U Y Z Z# + b c d f h i l p s s# s* u u# w* y y# y* z z# z* + + Converters: + """) + expected_converters = ( + "bool", + "byte", + "char", + "defining_class", + "double", + "fildes", + "float", + "int", + "long", + "long_long", + "object", + "Py_buffer", + "Py_complex", + "Py_ssize_t", + "Py_UNICODE", + "PyByteArrayObject", + "PyBytesObject", + "self", + "short", + "size_t", + "slice_index", + "str", + "unicode", + "unsigned_char", + "unsigned_int", + "unsigned_long", + "unsigned_long_long", + "unsigned_short", + ) + finale = dedent(""" + Return converters: + bool() + double() + float() + init() + int() + long() + Py_ssize_t() + size_t() + unsigned_int() + unsigned_long() + + All converters also accept (c_default=None, py_default=None, annotation=None). + All return converters also accept (py_default=None). + """) + out = self.expect_success("--converters") + # We cannot simply compare the output, because the repr of the *accept* + # param may change (it's a set, thus unordered). So, let's compare the + # start and end of the expected output, and then assert that the + # converters appear lined up in alphabetical order. + self.assertTrue(out.startswith(prelude), out) + self.assertTrue(out.endswith(finale), out) + + out = out.removeprefix(prelude) + out = out.removesuffix(finale) + lines = out.split("\n") + for converter, line in zip(expected_converters, lines): + line = line.lstrip() + with self.subTest(converter=converter): + self.assertTrue( + line.startswith(converter), + f"expected converter {converter!r}, got {line!r}" + ) try: From f573a6a281e49560a1022a13c39e44a9207ef6d2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:54:42 -0700 Subject: [PATCH 0429/1206] [3.12] GH-96803: Move PyUnstable_InterpreterFrame_GetCode() to Python.h (GH-107188) (#107195) GH-96803: Move PyUnstable_InterpreterFrame_GetCode() to Python.h (GH-107188) Declare the following 3 PyUnstable functions in Include/cpython/pyframe.h rather than Include/cpython/frameobject.h, so they are now provided by the standard "GH-include ". (cherry picked from commit 837fa5c0cd92e70f625377c9ffb7ac31a23d7d63) Co-authored-by: Victor Stinner --- Include/cpython/frameobject.h | 17 ----------------- Include/cpython/pyframe.h | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h index a3dc6661786451..4e19535c656f2c 100644 --- a/Include/cpython/frameobject.h +++ b/Include/cpython/frameobject.h @@ -4,8 +4,6 @@ # error "this header file must not be included directly" #endif -struct _PyInterpreterFrame; - /* Standard object interface */ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *, @@ -29,18 +27,3 @@ PyAPI_FUNC(int) _PyFrame_IsEntryFrame(PyFrameObject *frame); PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f); PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); - -/* The following functions are for use by debuggers and other tools - * implementing custom frame evaluators with PEP 523. */ - -/* Returns the code object of the frame (strong reference). - * Does not raise an exception. */ -PyAPI_FUNC(PyObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); - -/* Returns a byte ofsset into the last executed instruction. - * Does not raise an exception. */ -PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame); - -/* Returns the currently executing line number, or -1 if there is no line number. - * Does not raise an exception. */ -PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame); diff --git a/Include/cpython/pyframe.h b/Include/cpython/pyframe.h index 6ec292718aff1a..0e2afff925e31f 100644 --- a/Include/cpython/pyframe.h +++ b/Include/cpython/pyframe.h @@ -16,3 +16,20 @@ PyAPI_FUNC(PyObject *) PyFrame_GetGenerator(PyFrameObject *frame); PyAPI_FUNC(int) PyFrame_GetLasti(PyFrameObject *frame); PyAPI_FUNC(PyObject*) PyFrame_GetVar(PyFrameObject *frame, PyObject *name); PyAPI_FUNC(PyObject*) PyFrame_GetVarString(PyFrameObject *frame, const char *name); + +/* The following functions are for use by debuggers and other tools + * implementing custom frame evaluators with PEP 523. */ + +struct _PyInterpreterFrame; + +/* Returns the code object of the frame (strong reference). + * Does not raise an exception. */ +PyAPI_FUNC(PyObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); + +/* Returns a byte ofsset into the last executed instruction. + * Does not raise an exception. */ +PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame); + +/* Returns the currently executing line number, or -1 if there is no line number. + * Does not raise an exception. */ +PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame); From 5bf7165e591f2e7502672cc591cea480a5b91a8f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 13:13:07 -0700 Subject: [PATCH 0430/1206] [3.12] gh-98608: Move PyInterpreterConfig to pylifecycle.h (GH-107191) (#107198) gh-98608: Move PyInterpreterConfig to pylifecycle.h (GH-107191) Move PyInterpreterConfig structure and associated macros from initconfig.h to pylifecycle.h: it's not related to the Python Initialization Configuration. (cherry picked from commit e717b47ed8ae7017f0bfb835fe673aa836e8fcca) Co-authored-by: Victor Stinner --- Include/cpython/initconfig.h | 39 ----------------------------------- Include/cpython/pylifecycle.h | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index c103c2026e40e9..cbae97f12f5377 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -242,45 +242,6 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config, Py_ssize_t length, wchar_t **items); -/* --- PyInterpreterConfig ------------------------------------ */ - -#define PyInterpreterConfig_DEFAULT_GIL (0) -#define PyInterpreterConfig_SHARED_GIL (1) -#define PyInterpreterConfig_OWN_GIL (2) - -typedef struct { - // XXX "allow_object_sharing"? "own_objects"? - int use_main_obmalloc; - int allow_fork; - int allow_exec; - int allow_threads; - int allow_daemon_threads; - int check_multi_interp_extensions; - int gil; -} PyInterpreterConfig; - -#define _PyInterpreterConfig_INIT \ - { \ - .use_main_obmalloc = 0, \ - .allow_fork = 0, \ - .allow_exec = 0, \ - .allow_threads = 1, \ - .allow_daemon_threads = 0, \ - .check_multi_interp_extensions = 1, \ - .gil = PyInterpreterConfig_OWN_GIL, \ - } - -#define _PyInterpreterConfig_LEGACY_INIT \ - { \ - .use_main_obmalloc = 1, \ - .allow_fork = 1, \ - .allow_exec = 1, \ - .allow_threads = 1, \ - .allow_daemon_threads = 1, \ - .check_multi_interp_extensions = 0, \ - .gil = PyInterpreterConfig_SHARED_GIL, \ - } - /* --- Helper functions --------------------------------------- */ /* Get the original command line arguments, before Python modified them. diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index 314a5cc5b942ac..4daea33bf80114 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -63,6 +63,45 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); +/* --- PyInterpreterConfig ------------------------------------ */ + +#define PyInterpreterConfig_DEFAULT_GIL (0) +#define PyInterpreterConfig_SHARED_GIL (1) +#define PyInterpreterConfig_OWN_GIL (2) + +typedef struct { + // XXX "allow_object_sharing"? "own_objects"? + int use_main_obmalloc; + int allow_fork; + int allow_exec; + int allow_threads; + int allow_daemon_threads; + int check_multi_interp_extensions; + int gil; +} PyInterpreterConfig; + +#define _PyInterpreterConfig_INIT \ + { \ + .use_main_obmalloc = 0, \ + .allow_fork = 0, \ + .allow_exec = 0, \ + .allow_threads = 1, \ + .allow_daemon_threads = 0, \ + .check_multi_interp_extensions = 1, \ + .gil = PyInterpreterConfig_OWN_GIL, \ + } + +#define _PyInterpreterConfig_LEGACY_INIT \ + { \ + .use_main_obmalloc = 1, \ + .allow_fork = 1, \ + .allow_exec = 1, \ + .allow_threads = 1, \ + .allow_daemon_threads = 1, \ + .check_multi_interp_extensions = 0, \ + .gil = PyInterpreterConfig_SHARED_GIL, \ + } + PyAPI_FUNC(PyStatus) Py_NewInterpreterFromConfig( PyThreadState **tstate_p, const PyInterpreterConfig *config); From 3923639a77656915c3499b0283a45da727308f2a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 24 Jul 2023 13:59:51 -0700 Subject: [PATCH 0431/1206] [3.12] gh-102304: Rename _Py_IncRefTotal_DO_NOT_USE_THIS() (GH-107193) (#107199) gh-102304: Rename _Py_IncRefTotal_DO_NOT_USE_THIS() (GH-107193) * Rename _Py_IncRefTotal_DO_NOT_USE_THIS() to _Py_INCREF_IncRefTotal() * Rename _Py_DecRefTotal_DO_NOT_USE_THIS() to _Py_DECREF_DecRefTotal() * Remove temporary _Py_INC_REFTOTAL() and _Py_DEC_REFTOTAL() macros (cherry picked from commit 8ebc9fc321ba1eeb3282c2170f351c54956893e6) Co-authored-by: Victor Stinner --- Include/object.h | 13 ++++--------- Objects/object.c | 4 ++-- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Include/object.h b/Include/object.h index 3ef64511399c66..7564b9623be79f 100644 --- a/Include/object.h +++ b/Include/object.h @@ -588,10 +588,8 @@ you can count such references to the type object.) #if defined(Py_REF_DEBUG) && !defined(Py_LIMITED_API) PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op); -PyAPI_FUNC(void) _Py_IncRefTotal_DO_NOT_USE_THIS(void); -PyAPI_FUNC(void) _Py_DecRefTotal_DO_NOT_USE_THIS(void); -# define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() -# define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS() +PyAPI_FUNC(void) _Py_INCREF_IncRefTotal(void); +PyAPI_FUNC(void) _Py_DECREF_DecRefTotal(void); #endif // Py_REF_DEBUG && !Py_LIMITED_API PyAPI_FUNC(void) _Py_Dealloc(PyObject *); @@ -640,7 +638,7 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) #endif _Py_INCREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_INC_REFTOTAL(); + _Py_INCREF_IncRefTotal(); #endif #endif } @@ -669,7 +667,7 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) return; } _Py_DECREF_STAT_INC(); - _Py_DEC_REFTOTAL(); + _Py_DECREF_DecRefTotal(); if (--op->ob_refcnt != 0) { if (op->ob_refcnt < 0) { _Py_NegativeRefcount(filename, lineno, op); @@ -697,9 +695,6 @@ static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op) #define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op)) #endif -#undef _Py_INC_REFTOTAL -#undef _Py_DEC_REFTOTAL - /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear * and tp_dealloc implementations. diff --git a/Objects/object.c b/Objects/object.c index b8bdf459201d9b..6a73c3588da798 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -206,14 +206,14 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) /* This is used strictly by Py_INCREF(). */ void -_Py_IncRefTotal_DO_NOT_USE_THIS(void) +_Py_INCREF_IncRefTotal(void) { reftotal_increment(_PyInterpreterState_GET()); } /* This is used strictly by Py_DECREF(). */ void -_Py_DecRefTotal_DO_NOT_USE_THIS(void) +_Py_DECREF_DecRefTotal(void) { reftotal_decrement(_PyInterpreterState_GET()); } From 5fd028b677ae1dd20a60fc2f43d4380b809d70f0 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Mon, 24 Jul 2023 15:13:17 -0600 Subject: [PATCH 0432/1206] [3.12] gh-106917: fix super classmethod calls to non-classmethods (GH-106977). (#107204) (cherry picked from commit e5d5522612e03af3941db1d270bf6caebf330b8a) --- Lib/test/test_super.py | 46 ++++++++++++++++++- ...-07-21-14-37-48.gh-issue-106917.1jWp_m.rst | 4 ++ Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 2 +- 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py index 664cf70b3cf0fa..43162c540b55ae 100644 --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -5,6 +5,9 @@ from test import shadowed_super +ADAPTIVE_WARMUP_DELAY = 2 + + class A: def f(self): return 'A' @@ -419,8 +422,47 @@ def test(name): super(MyType, type(mytype)).__setattr__(mytype, "bar", 1) self.assertEqual(mytype.bar, 1) - test("foo1") - test("foo2") + for _ in range(ADAPTIVE_WARMUP_DELAY): + test("foo1") + + def test_reassigned_new(self): + class A: + def __new__(cls): + pass + + def __init_subclass__(cls): + if "__new__" not in cls.__dict__: + cls.__new__ = cls.__new__ + + class B(A): + pass + + class C(B): + def __new__(cls): + return super().__new__(cls) + + for _ in range(ADAPTIVE_WARMUP_DELAY): + C() + + def test_mixed_staticmethod_hierarchy(self): + # This test is just a desugared version of `test_reassigned_new` + class A: + @staticmethod + def some(cls, *args, **kwargs): + self.assertFalse(args) + self.assertFalse(kwargs) + + class B(A): + def some(cls, *args, **kwargs): + return super().some(cls, *args, **kwargs) + + class C(B): + @staticmethod + def some(cls): + return super().some(cls) + + for _ in range(ADAPTIVE_WARMUP_DELAY): + C.some(C) if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst new file mode 100644 index 00000000000000..82c74d5465458a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst @@ -0,0 +1,4 @@ +Fix classmethod-style :func:`super` method calls (i.e., where the second +argument to :func:`super`, or the implied second argument drawn from +``self/cls`` in the case of zero-arg super, is a type) when the target of +the call is not a classmethod. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0baf2451ee4f8a..b914afa07fba40 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1663,7 +1663,7 @@ dummy_func( PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; res2 = _PySuper_Lookup(cls, self, name, - cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); + Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); if (res2 == NULL) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 103373ec0db018..281c8b5e5245bc 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2411,7 +2411,7 @@ PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; res2 = _PySuper_Lookup(cls, self, name, - cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); + Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); if (res2 == NULL) { From 2cdde10c5bb38f825c52af80b775b247fef24f07 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 03:32:45 -0700 Subject: [PATCH 0433/1206] [3.12] gh-106774: Update bundled pip version to 23.2.1 (GH-106775) (gh-107222) gh-106774: Update bundled pip version to 23.2.1 (GH-106775) --- Lib/ensurepip/__init__.py | 2 +- ...ne-any.whl => pip-23.2.1-py3-none-any.whl} | Bin 2064688 -> 2086091 bytes ...-07-15-10-24-56.gh-issue-106774.FJcqCj.rst | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) rename Lib/ensurepip/_bundled/{pip-23.1.2-py3-none-any.whl => pip-23.2.1-py3-none-any.whl} (74%) create mode 100644 Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 5f4f1d75b43e64..1fb1d505cfd0c5 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('pip',) -_PIP_VERSION = "23.1.2" +_PIP_VERSION = "23.2.1" _PROJECTS = [ ("pip", _PIP_VERSION, "py3"), ] diff --git a/Lib/ensurepip/_bundled/pip-23.1.2-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-23.2.1-py3-none-any.whl similarity index 74% rename from Lib/ensurepip/_bundled/pip-23.1.2-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-23.2.1-py3-none-any.whl index 6a2515615ccda3148bf0828450d9149ef13819ac..ba28ef02e265f032560e28e40b2be0bd6e2e964f 100644 GIT binary patch delta 526875 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 G7c`Eh_FtvxDpt){n@X+;qEBzrEzR>n^8Jy=A-{ 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%0A+Kk$=VpdcGl~KsPbe!!Z|5n$ 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

S{iXE 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 &({F4A#dlFmXi8h5WeD0fI8s_N^7N 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 RarJRUq_bEVAIXi~{{Rr(Am0E0 diff --git a/Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst b/Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst new file mode 100644 index 00000000000000..ed467573b89e14 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst @@ -0,0 +1 @@ +Update the bundled copy of pip to version 23.2.1. From fab36fb63eda4023097cb7f800d672ced26e338f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 05:20:30 -0700 Subject: [PATCH 0434/1206] [3.12] gh-106996: Add a how-to section to the turtle documentation (GH-107153) (#107233) Co-authored-by: Daniele Procida Co-authored-by: Hugo van Kemenade --- Doc/library/turtle.rst | 114 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index a9c0fa96207ae9..a85c3f466323f9 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -46,6 +46,8 @@ graphical output it can be a way to do that without the overhead of introducing more complex or external libraries into their work. +.. _turtle-tutorial: + Tutorial ======== @@ -165,6 +167,118 @@ Finally, complete the filling:: ``end_fill()`` command.) +.. _turtle-how-to: + +How to... +========= + +This section covers some typical turtle use-cases and approaches. + + +Get started as quickly as possible +---------------------------------- + +One of the joys of turtle graphics is the immediate, visual feedback that's +available from simple commands - it's an excellent way to introduce children +to programming ideas, with a minimum of overhead (not just children, of +course). + +The turtle module makes this possible by exposing all its basic functionality +as functions, available with ``from turtle import *``. The :ref:`turtle +graphics tutorial ` covers this approach. + +It's worth noting that many of the turtle commands also have even more terse +equivalents, such as ``fd()`` for :func:`forward`. These are especially +useful when working with learners for whom typing is not a skill. + +.. _note: + + You'll need to have the :mod:`Tk interface package ` installed on + your system for turtle graphics to work. Be warned that this is not + always straightforward, so check this in advance if you're planning to + use turtle graphics with a learner. + + +Use the ``turtle`` module namespace +----------------------------------- + +Using ``from turtle import *`` is convenient - but be warned that it imports a +rather large collection of objects, and if you're doing anything but turtle +graphics you run the risk of a name conflict (this becomes even more an issue +if you're using turtle graphics in a script where other modules might be +imported). + +The solution is to use ``import turtle`` - ``fd()`` becomes +``turtle.fd()``, ``width()`` becomes ``turtle.width()`` and so on. (If typing +"turtle" over and over again becomes tedious, use for example ``import turtle +as t`` instead.) + + +Use turtle graphics in a script +------------------------------- + +It's recommended to use the ``turtle`` module namespace as described +immediately above, for example:: + + import turtle as t + from random import random + + for i in range(100): + steps = int(random() * 100) + angle = int(random() * 360) + t.right(angle) + t.fd(steps) + +Another step is also required though - as soon as the script ends, Python +will also close the turtle's window. Add:: + + t.mainloop() + +to the end of the script. The script will now wait to be dismissed and +will not exit until it is terminated, for example by closing the turtle +graphics window. + + +Use object-oriented turtle graphics +----------------------------------- + +.. seealso:: :ref:`Explanation of the object-oriented interface ` + +Other than for very basic introductory purposes, or for trying things out +as quickly as possible, it's more usual and much more powerful to use the +object-oriented approach to turtle graphics. For example, this allows +multiple turtles on screen at once. + +In this approach, the various turtle commands are methods of objects (mostly of +``Turtle`` objects). You *can* use the object-oriented approach in the shell, +but it would be more typical in a Python script. + +The example above then becomes:: + + from turtle import Turtle + from random import random + + t = Turtle() + for i in range(100): + steps = int(random() * 100) + angle = int(random() * 360) + t.right(angle) + t.fd(steps) + + t.screen.mainloop() + +Note the last line. ``t.screen`` is an instance of the :class:`Screen` +that a Turtle instance exists on; it's created automatically along with +the turtle. + +The turtle's screen can be customised, for example:: + + t.screen.title('Object-oriented turtle demo') + t.screen.bgcolor("orange") + + +.. _turtle-explanation: + Explanation =========== From 0cf5f6a6db0c50e46687de1fd99f90d7f85f69ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 06:01:24 -0700 Subject: [PATCH 0435/1206] [3.12] gh-105059: Use GCC/clang extension for PyObject union (GH-107232) (#107236) gh-105059: Use GCC/clang extension for PyObject union (GH-107232) Anonymous union is new in C11. To prevent compiler warning when using -pedantic compiler option, use Clang and GCC extension on C99 and older. (cherry picked from commit 6261585d63a31835b65d445d99dc14cca3fe9cf5) Co-authored-by: Victor Stinner --- Include/object.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Include/object.h b/Include/object.h index 7564b9623be79f..542f8d8c15a7c7 100644 --- a/Include/object.h +++ b/Include/object.h @@ -165,6 +165,11 @@ check by comparing the reference count field to the immortality reference count. */ struct _object { _PyObject_HEAD_EXTRA +#if (defined(__GNUC__) || defined(__clang__)) \ + && !(defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) + // On C99 and older, anonymous union is a GCC and clang extension + __extension__ +#endif union { Py_ssize_t ob_refcnt; #if SIZEOF_VOID_P > 4 From e788c0aeeb46bdfa3c4d8a39fb9bbb505e6d27a8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 06:43:11 -0700 Subject: [PATCH 0436/1206] [3.12] gh-107237: Fix test_udp_reconnection() of test_logging (GH-107238) (#107242) gh-107237: Fix test_udp_reconnection() of test_logging (GH-107238) test_logging: Fix test_udp_reconnection() by increasing the timeout from 100 ms to 5 minutes (LONG_TIMEOUT). Replace also blocking wait() with wait(LONG_TIMEOUT) in test_output() to prevent the test to hang. (cherry picked from commit ed082383272c2c238e364e9cc83229234aee23cc) Co-authored-by: Victor Stinner --- Lib/test/test_logging.py | 8 ++++---- .../Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 18258c22874ae0..def976fbe96ba3 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2079,17 +2079,17 @@ def test_output(self): # The log message sent to the SysLogHandler is properly received. logger = logging.getLogger("slh") logger.error("sp\xe4m") - self.handled.wait() + self.handled.wait(support.LONG_TIMEOUT) self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00') self.handled.clear() self.sl_hdlr.append_nul = False logger.error("sp\xe4m") - self.handled.wait() + self.handled.wait(support.LONG_TIMEOUT) self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m') self.handled.clear() self.sl_hdlr.ident = "h\xe4m-" logger.error("sp\xe4m") - self.handled.wait() + self.handled.wait(support.LONG_TIMEOUT) self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m') def test_udp_reconnection(self): @@ -2097,7 +2097,7 @@ def test_udp_reconnection(self): self.sl_hdlr.close() self.handled.clear() logger.error("sp\xe4m") - self.handled.wait(0.1) + self.handled.wait(support.LONG_TIMEOUT) self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00') @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") diff --git a/Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst b/Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst new file mode 100644 index 00000000000000..a04f7eeddef174 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst @@ -0,0 +1,2 @@ +``test_logging``: Fix ``test_udp_reconnection()`` by increasing the timeout +from 100 ms to 5 minutes (LONG_TIMEOUT). Patch by Victor Stinner. From 9c31d9405027cea9c2d039ade672d604663ed5b0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 08:35:49 -0700 Subject: [PATCH 0437/1206] [3.12] gh-105059: Fix MSCV compiler warning on PyObject union (GH-107239) (#107248) gh-105059: Fix MSCV compiler warning on PyObject union (GH-107239) Use pragma to ignore the MSCV compiler warning on the PyObject nameless union. (cherry picked from commit 1c8fe9bdb624d356643ee569151a9e4f2963179a) Co-authored-by: Victor Stinner --- Include/object.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Include/object.h b/Include/object.h index 542f8d8c15a7c7..77434e3bc73c15 100644 --- a/Include/object.h +++ b/Include/object.h @@ -165,10 +165,17 @@ check by comparing the reference count field to the immortality reference count. */ struct _object { _PyObject_HEAD_EXTRA + #if (defined(__GNUC__) || defined(__clang__)) \ && !(defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) // On C99 and older, anonymous union is a GCC and clang extension __extension__ +#endif +#ifdef _MSC_VER + // Ignore MSC warning C4201: "nonstandard extension used: + // nameless struct/union" + __pragma(warning(push)) + __pragma(warning(disable: 4201)) #endif union { Py_ssize_t ob_refcnt; @@ -176,6 +183,10 @@ struct _object { PY_UINT32_T ob_refcnt_split[2]; #endif }; +#ifdef _MSC_VER + __pragma(warning(pop)) +#endif + PyTypeObject *ob_type; }; From ca42d6720850967698d6e298e37a4225f0c67d8e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 08:42:46 -0700 Subject: [PATCH 0438/1206] [3.12] gh-105699: Add some stress tests for subinterpreter creation (GH-106966) (gh-107012) gh-105699: Add some stress tests for subinterpreter creation (GH-106966) (cherry picked from commit adda43dc0bcea853cbfa33126e5549c584cef8be) Co-authored-by: Eric Snow --- Lib/test/test_interpreters.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Lib/test/test_interpreters.py b/Lib/test/test_interpreters.py index d1bebe47158322..5981d96de8de06 100644 --- a/Lib/test/test_interpreters.py +++ b/Lib/test/test_interpreters.py @@ -7,6 +7,7 @@ from test import support from test.support import import_helper +from test.support import threading_helper _interpreters = import_helper.import_module('_xxsubinterpreters') _channels = import_helper.import_module('_xxinterpchannels') from test.support import interpreters @@ -463,6 +464,27 @@ def test_bytes_for_script(self): # test_xxsubinterpreters covers the remaining Interpreter.run() behavior. +class StressTests(TestBase): + + # In these tests we generally want a lot of interpreters, + # but not so many that any test takes too long. + + def test_create_many_sequential(self): + alive = [] + for _ in range(100): + interp = interpreters.create() + alive.append(interp) + + def test_create_many_threaded(self): + alive = [] + def task(): + interp = interpreters.create() + alive.append(interp) + threads = (threading.Thread(target=task) for _ in range(200)) + with threading_helper.start_threads(threads): + pass + + class TestIsShareable(TestBase): def test_default_shareables(self): From 313284aa423252ebd5d4e761220e0f4fdeac626d Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Tue, 25 Jul 2023 18:25:07 +0200 Subject: [PATCH 0439/1206] [3.12] Remove superflous whitespaces in `layout.html`. (#107251) Remove superflous whitespaces in layout.html. --- Doc/tools/templates/layout.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index 10cb6fd880fa1a..9832feba141675 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -4,16 +4,16 @@ {%- if outdated %}

{%- endif %} {%- if is_deployment_preview %}
{% trans %}This is a deploy preview created from a pull request. - For authoritative documentation, see the {% endtrans %} - {% trans %} the current stable release{% endtrans %}. + For authoritative documentation, see{% endtrans %} + {% trans %}the current stable release{% endtrans %}.
{%- endif %} {% endblock %} From 11d86c5c339abd52d1ab5ce0af4d25c44898d046 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 11:48:59 -0700 Subject: [PATCH 0440/1206] [3.12] gh-62519: Make pgettext search plurals when translation is not found (GH-107118) (GH-107134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit b3c34e55c053846beb35f5e4253ef237b3494bd0) Co-authored-by: Tomas R Co-authored-by: Åukasz Langa --- Lib/gettext.py | 10 ++++++---- Lib/test/test_gettext.py | 4 ++++ .../2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst diff --git a/Lib/gettext.py b/Lib/gettext.py index cc938e40028c24..b72b15f82d4355 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -446,10 +446,12 @@ def pgettext(self, context, message): missing = object() tmsg = self._catalog.get(ctxt_msg_id, missing) if tmsg is missing: - if self._fallback: - return self._fallback.pgettext(context, message) - return message - return tmsg + tmsg = self._catalog.get((ctxt_msg_id, self.plural(1)), missing) + if tmsg is not missing: + return tmsg + if self._fallback: + return self._fallback.pgettext(context, message) + return message def npgettext(self, context, msgid1, msgid2, n): ctxt_msg_id = self.CONTEXT % (context, msgid1) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index aa3520d2c142e4..8430fc234d00ee 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -331,6 +331,8 @@ def test_plural_context_forms1(self): x = gettext.npgettext('With context', 'There is %s file', 'There are %s files', 2) eq(x, 'Hay %s ficheros (context)') + x = gettext.pgettext('With context', 'There is %s file') + eq(x, 'Hay %s fichero (context)') def test_plural_forms2(self): eq = self.assertEqual @@ -353,6 +355,8 @@ def test_plural_context_forms2(self): x = t.npgettext('With context', 'There is %s file', 'There are %s files', 2) eq(x, 'Hay %s ficheros (context)') + x = gettext.pgettext('With context', 'There is %s file') + eq(x, 'Hay %s fichero (context)') # Examples from http://www.gnu.org/software/gettext/manual/gettext.html diff --git a/Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst b/Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst new file mode 100644 index 00000000000000..96e2a3dcc24fb0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst @@ -0,0 +1,2 @@ +Make :func:`gettext.pgettext` search plural definitions when +translation is not found. From c3c8916dea0142736efb087ea08bf667dfcf3c50 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 13:01:18 -0700 Subject: [PATCH 0441/1206] [3.12] gh-107226: PyModule_AddObjectRef() should only be in the limited API 3.10 (GH-107227) (GH-107260) (cherry picked from commit 698b01513550798886add5e06a1c3f9a89d7dfc6) Co-authored-by: Serhiy Storchaka --- Include/modsupport.h | 2 ++ .../next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst diff --git a/Include/modsupport.h b/Include/modsupport.h index 4e369bd56b4d20..1592bd0db4ffd6 100644 --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -39,10 +39,12 @@ PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030a0000 // Add an attribute with name 'name' and value 'obj' to the module 'mod. // On success, return 0 on success. // On error, raise an exception and return -1. PyAPI_FUNC(int) PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value); +#endif /* Py_LIMITED_API */ // Similar to PyModule_AddObjectRef() but steal a reference to 'obj' // (Py_DECREF(obj)) on success (if it returns 0). diff --git a/Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst b/Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst new file mode 100644 index 00000000000000..6178f18517d48f --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst @@ -0,0 +1,2 @@ +:c:func:`PyModule_AddObjectRef` is now only available in the limited API +version 3.10 or later. From 0107731a06db13cf93fc56cc72524f0493c6a04f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 14:19:25 -0700 Subject: [PATCH 0442/1206] [3.12] gh-106939: document ShareableList nul-strip quirk. (GH-107266) (#107269) gh-106939: document ShareableList nul-strip quirk. (GH-107266) * gh-106939: document ShareableList nul-strip quirk. * Mention the `int` size constraint. (cherry picked from commit 70dc00946938027d5a79bcb7b65038319040144e) Co-authored-by: Gregory P. Smith --- Doc/library/multiprocessing.shared_memory.rst | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/Doc/library/multiprocessing.shared_memory.rst b/Doc/library/multiprocessing.shared_memory.rst index 76046b34610abe..f453e6403d932d 100644 --- a/Doc/library/multiprocessing.shared_memory.rst +++ b/Doc/library/multiprocessing.shared_memory.rst @@ -255,16 +255,17 @@ shared memory blocks created using that manager are all released when the :keyword:`with` statement's code block finishes execution. -.. class:: ShareableList(sequence=None, *, name=None) +.. class:: ShareableList(sequence=None, \*, name=None) Provides a mutable list-like object where all values stored within are stored in a shared memory block. This constrains storable values to - only the ``int``, ``float``, ``bool``, ``str`` (less than 10M bytes each), - ``bytes`` (less than 10M bytes each), and ``None`` built-in data types. - It also notably differs from the built-in ``list`` type in that these - lists can not change their overall length (i.e. no append, insert, etc.) - and do not support the dynamic creation of new :class:`ShareableList` - instances via slicing. + only the ``int`` (signed 64-bit), ``float``, ``bool``, ``str`` (less + than 10M bytes each when encoded as utf-8), ``bytes`` (less than 10M + bytes each), and ``None`` built-in data types. It also notably + differs from the built-in ``list`` type in that these lists can not + change their overall length (i.e. no append, insert, etc.) and do not + support the dynamic creation of new :class:`ShareableList` instances + via slicing. *sequence* is used in populating a new ``ShareableList`` full of values. Set to ``None`` to instead attach to an already existing @@ -275,6 +276,35 @@ shared memory blocks created using that manager are all released when the existing ``ShareableList``, specify its shared memory block's unique name while leaving ``sequence`` set to ``None``. + .. note:: + + A known issue exists for :class:`bytes` and :class:`str` values. + If they end with ``\x00`` nul bytes or characters, those may be + *silently stripped* when fetching them by index from the + :class:`ShareableList`. This ``.rstrip(b'\x00')`` behavior is + considered a bug and may go away in the future. See :gh:`106939`. + + For applications where rstripping of trailing nulls is a problem, + work around it by always unconditionally appending an extra non-0 + byte to the end of such values when storing and unconditionally + removing it when fetching: + + .. doctest:: + + >>> from multiprocessing import shared_memory + >>> nul_bug_demo = shared_memory.ShareableList(['?\x00', b'\x03\x02\x01\x00\x00\x00']) + >>> nul_bug_demo[0] + '?' + >>> nul_bug_demo[1] + b'\x03\x02\x01' + >>> nul_bug_demo.shm.unlink() + >>> padded = shared_memory.ShareableList(['?\x00\x07', b'\x03\x02\x01\x00\x00\x00\x07']) + >>> padded[0][:-1] + '?\x00' + >>> padded[1][:-1] + b'\x03\x02\x01\x00\x00\x00' + >>> padded.shm.unlink() + .. method:: count(value) Returns the number of occurrences of ``value``. From 3d15c8b84b334658a5476a9cbf2626fe15fc7344 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 25 Jul 2023 14:23:33 -0700 Subject: [PATCH 0443/1206] [3.12] gh-106185: Deduplicate `CPythonTracebackErrorCaretTests` in `test_traceback` (GH-106187) (GH-107268) (cherry picked from commit 7c89f1189229c5c67a3766e24ecf00cde658b7fd) Co-authored-by: Nikita Sobolev --- Lib/test/test_traceback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 19a2be88d2c1bc..9476e2c89def49 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -918,7 +918,7 @@ class CPythonTracebackErrorCaretTests( @cpython_only @requires_debug_ranges() -class CPythonTracebackErrorCaretTests( +class CPythonTracebackLegacyErrorCaretTests( CAPIExceptionFormattingLegacyMixin, TracebackErrorLocationCaretTestBase, unittest.TestCase, From ef808517f499b25f9f847c813067f24d73af051f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 00:13:22 -0700 Subject: [PATCH 0444/1206] [3.12] gh-106368: Increase Argument Clinic CLI test coverage (GH-107277) (#107282) (cherry picked from commit 579100f6d75a27429e7f8de74935d7bc3a3e44e6) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 78 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index f5271203362263..d1c61b1d401b98 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1348,18 +1348,18 @@ def test_scaffolding(self): class ClinicExternalTest(TestCase): maxDiff = None + clinic_py = os.path.join(test_tools.toolsdir, "clinic", "clinic.py") def _do_test(self, *args, expect_success=True): - clinic_py = os.path.join(test_tools.toolsdir, "clinic", "clinic.py") with subprocess.Popen( - [sys.executable, "-Xutf8", clinic_py, *args], + [sys.executable, "-Xutf8", self.clinic_py, *args], encoding="utf-8", bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) as proc: proc.wait() - if expect_success == bool(proc.returncode): + if expect_success and proc.returncode: self.fail("".join(proc.stderr)) stdout = proc.stdout.read() stderr = proc.stderr.read() @@ -1449,6 +1449,49 @@ def test_cli_force(self): generated = f.read() self.assertTrue(generated.endswith(checksum)) + def test_cli_make(self): + c_code = dedent(""" + /*[clinic input] + [clinic start generated code]*/ + """) + py_code = "pass" + c_files = "file1.c", "file2.c" + py_files = "file1.py", "file2.py" + + def create_files(files, srcdir, code): + for fn in files: + path = os.path.join(srcdir, fn) + with open(path, "w", encoding="utf-8") as f: + f.write(code) + + with os_helper.temp_dir() as tmp_dir: + # add some folders, some C files and a Python file + create_files(c_files, tmp_dir, c_code) + create_files(py_files, tmp_dir, py_code) + + # create C files in externals/ dir + ext_path = os.path.join(tmp_dir, "externals") + with os_helper.temp_dir(path=ext_path) as externals: + create_files(c_files, externals, c_code) + + # run clinic in verbose mode with --make on tmpdir + out = self.expect_success("-v", "--make", "--srcdir", tmp_dir) + + # expect verbose mode to only mention the C files in tmp_dir + for filename in c_files: + with self.subTest(filename=filename): + path = os.path.join(tmp_dir, filename) + self.assertIn(path, out) + for filename in py_files: + with self.subTest(filename=filename): + path = os.path.join(tmp_dir, filename) + self.assertNotIn(path, out) + # don't expect C files from the externals dir + for filename in c_files: + with self.subTest(filename=filename): + path = os.path.join(ext_path, filename) + self.assertNotIn(path, out) + def test_cli_verbose(self): with os_helper.temp_dir() as tmp_dir: fn = os.path.join(tmp_dir, "test.c") @@ -1534,6 +1577,35 @@ def test_cli_converters(self): f"expected converter {converter!r}, got {line!r}" ) + def test_cli_fail_converters_and_filename(self): + out = self.expect_failure("--converters", "test.c") + msg = ( + "Usage error: can't specify --converters " + "and a filename at the same time" + ) + self.assertIn(msg, out) + + def test_cli_fail_no_filename(self): + out = self.expect_failure() + self.assertIn("usage: clinic.py", out) + + def test_cli_fail_output_and_multiple_files(self): + out = self.expect_failure("-o", "out.c", "input.c", "moreinput.c") + msg = "Usage error: can't use -o with multiple filenames" + self.assertIn(msg, out) + + def test_cli_fail_filename_or_output_and_make(self): + for opts in ("-o", "out.c"), ("filename.c",): + with self.subTest(opts=opts): + out = self.expect_failure("--make", *opts) + msg = "Usage error: can't use -o or filenames with --make" + self.assertIn(msg, out) + + def test_cli_fail_make_without_srcdir(self): + out = self.expect_failure("--make", "--srcdir", "") + msg = "Usage error: --srcdir must not be empty with --make" + self.assertIn(msg, out) + try: import _testclinic as ac_tester From d2355426d688eb9c84b3db15bbae21921858afbf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 00:58:33 -0700 Subject: [PATCH 0445/1206] [3.12] gh-106350: Tkinter: do not ignore return value of `mp_init()` (GH-106351) (GH-107258) (cherry picked from commit b5ae7c498438657a6ba0bf4cc216b9c2c93a06c7) Co-authored-by: Christopher Chavez --- .../Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst | 2 ++ Modules/_tkinter.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst diff --git a/Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst b/Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst new file mode 100644 index 00000000000000..681d63a6668be8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst @@ -0,0 +1,2 @@ +Detect possible memory allocation failure in the libtommath function :c:func:`mp_init` +used by the ``_tkinter`` module. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 15f9c0465fb043..5abde84ebc2efd 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -876,8 +876,9 @@ asBignumObj(PyObject *value) return NULL; } hexchars += neg + 2; /* skip sign and "0x" */ - mp_init(&bigValue); - if (mp_read_radix(&bigValue, hexchars, 16) != MP_OKAY) { + if (mp_init(&bigValue) != MP_OKAY || + mp_read_radix(&bigValue, hexchars, 16) != MP_OKAY) + { mp_clear(&bigValue); Py_DECREF(hexstr); PyErr_NoMemory(); From 0d2e1317bd4d13c1652a08c3ad8199c03387f73b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 09:16:04 -0700 Subject: [PATCH 0446/1206] [3.12] gh-106948: Update documentation nitpick_ignore for c:identifer domain (GH-107295) (#107297) gh-106948: Update documentation nitpick_ignore for c:identifer domain (GH-107295) Update the nitpick_ignore of the documentation configuration to fix Sphinx warnings about standard C types when declaring functions with the "c:function" markups. Copy standard C types declared in the "c:type" domain to the "c:identifier" domain, since "c:function" markup looks for types in the "c:identifier" domain. (cherry picked from commit b1de3807b832b72dfeb66dd5646159d08d2cc74a) Co-authored-by: Victor Stinner Co-authored-by: Serhiy Storchaka --- Doc/conf.py | 9 +++++++++ Doc/tools/.nitignore | 3 --- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index 067aa1d9e22918..209656be4ad433 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -153,6 +153,15 @@ ('py:meth', '_SubParsersAction.add_parser'), ] +# gh-106948: Copy standard C types declared in the "c:type" domain to the +# "c:identifier" domain, since "c:function" markup looks for types in the +# "c:identifier" domain. Use list() to not iterate on items which are being +# added +for role, name in list(nitpick_ignore): + if role == 'c:type': + nitpick_ignore.append(('c:identifier', name)) +del role, name + # Disable Docutils smartquotes for several translations smartquotes_excludes = { 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], 'builders': ['man', 'text'], diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index b6adbcb34663e4..849ef1168b4554 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -9,7 +9,6 @@ Doc/c-api/arg.rst Doc/c-api/bool.rst Doc/c-api/buffer.rst Doc/c-api/bytes.rst -Doc/c-api/call.rst Doc/c-api/capsule.rst Doc/c-api/cell.rst Doc/c-api/code.rst @@ -28,8 +27,6 @@ Doc/c-api/init.rst Doc/c-api/init_config.rst Doc/c-api/intro.rst Doc/c-api/iterator.rst -Doc/c-api/long.rst -Doc/c-api/marshal.rst Doc/c-api/memory.rst Doc/c-api/memoryview.rst Doc/c-api/module.rst From 9f5a5f0b33479abcd1619fcc5ea3b8d0a31818f4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:30:46 -0700 Subject: [PATCH 0447/1206] [3.12] gh-107091: Fix some uses of :c:member: role (GH-107129) (GH-107310) (cherry picked from commit af61cb9c7837ff3c11da79e3ee1cab3fdd0ba4da) Co-authored-by: Serhiy Storchaka --- Doc/c-api/import.rst | 2 +- Doc/c-api/init_config.rst | 2 +- Doc/c-api/module.rst | 8 ++++---- Doc/c-api/structures.rst | 10 ++++++---- Doc/c-api/typeobj.rst | 2 +- Doc/howto/isolating-extensions.rst | 2 +- Doc/whatsnew/3.5.rst | 2 +- Doc/whatsnew/3.7.rst | 2 +- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index d32c09ef06c9e7..905cab9034bec6 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -138,7 +138,7 @@ Importing Modules :class:`SourceFileLoader` otherwise. The module's :attr:`__file__` attribute will be set to the code object's - :c:member:`co_filename`. If applicable, :attr:`__cached__` will also + :attr:`co_filename`. If applicable, :attr:`__cached__` will also be set. This function will reload the module if it was already imported. See diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 161def0b4baf3a..18f17e2059b102 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -522,7 +522,7 @@ PyConfig Moreover, if :c:func:`PyConfig_SetArgv` or :c:func:`PyConfig_SetBytesArgv` is used, this method must be called before other methods, since the preinitialization configuration depends on command line arguments (if - :c:member:`parse_argv` is non-zero). + :c:member:`~PyConfig.parse_argv` is non-zero). The caller of these methods is responsible to handle exceptions (error or exit) using ``PyStatus_Exception()`` and ``Py_ExitStatusException()``. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index e358c5da14a69f..6abd550ab80b21 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -164,7 +164,7 @@ or request "multi-phase initialization" by returning the definition struct itsel This memory area is allocated based on *m_size* on module creation, and freed when the module object is deallocated, after the - :c:member:`m_free` function has been called, if present. + :c:member:`~PyModuleDef.m_free` function has been called, if present. Setting ``m_size`` to ``-1`` means that the module does not support sub-interpreters, because it has global state. @@ -202,7 +202,7 @@ or request "multi-phase initialization" by returning the definition struct itsel This function is not called if the module state was requested but is not allocated yet. This is the case immediately after the module is created and before the module is executed (:c:data:`Py_mod_exec` function). More - precisely, this function is not called if :c:member:`m_size` is greater + precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater than 0 and the module state (as returned by :c:func:`PyModule_GetState`) is ``NULL``. @@ -217,7 +217,7 @@ or request "multi-phase initialization" by returning the definition struct itsel This function is not called if the module state was requested but is not allocated yet. This is the case immediately after the module is created and before the module is executed (:c:data:`Py_mod_exec` function). More - precisely, this function is not called if :c:member:`m_size` is greater + precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater than 0 and the module state (as returned by :c:func:`PyModule_GetState`) is ``NULL``. @@ -238,7 +238,7 @@ or request "multi-phase initialization" by returning the definition struct itsel This function is not called if the module state was requested but is not allocated yet. This is the case immediately after the module is created and before the module is executed (:c:data:`Py_mod_exec` function). More - precisely, this function is not called if :c:member:`m_size` is greater + precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater than 0 and the module state (as returned by :c:func:`PyModule_GetState`) is ``NULL``. diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 720ab31f3de856..75e325e8fa83f7 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -244,14 +244,16 @@ Implementing functions and methods points to the contents of the docstring -The :c:member:`ml_meth` is a C function pointer. The functions may be of different +The :c:member:`~PyMethodDef.ml_meth` is a C function pointer. +The functions may be of different types, but they always return :c:expr:`PyObject*`. If the function is not of the :c:type:`PyCFunction`, the compiler will require a cast in the method table. Even though :c:type:`PyCFunction` defines the first parameter as :c:expr:`PyObject*`, it is common that the method implementation uses the specific C type of the *self* object. -The :c:member:`ml_flags` field is a bitfield which can include the following flags. +The :c:member:`~PyMethodDef.ml_flags` field is a bitfield which can include +the following flags. The individual flags indicate either a calling convention or a binding convention. @@ -432,7 +434,7 @@ Accessing attributes of extension types The string should be static, no copy is made of it. Typically, it is defined using :c:macro:`PyDoc_STR`. - By default (when :c:member:`flags` is ``0``), members allow + By default (when :c:member:`~PyMemberDef.flags` is ``0``), members allow both read and write access. Use the :c:macro:`Py_READONLY` flag for read-only access. Certain types, like :c:macro:`Py_T_STRING`, imply :c:macro:`Py_READONLY`. @@ -512,7 +514,7 @@ The following flags can be used with :c:member:`PyMemberDef.flags`: Can only be used as part of :c:member:`Py_tp_members ` :c:type:`slot ` when creating a class using negative - :c:member:`~PyTypeDef.basicsize`. + :c:member:`~PyType_Spec.basicsize`. It is mandatory in that case. This flag is only used in :c:type:`PyTypeSlot`. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 9aa076baaa977f..de190f5ac39ad2 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1176,7 +1176,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:macro:: Py_TPFLAGS_ITEMS_AT_END Only usable with variable-size types, i.e. ones with non-zero - :c:member:`~PyObject.tp_itemsize`. + :c:member:`~PyTypeObject.tp_itemsize`. Indicates that the variable-sized portion of an instance of this type is at the end of the instance's memory area, at an offset of diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index cc4a908febfb7f..60854c3c034d73 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -467,7 +467,7 @@ Module State Access from Slot Methods, Getters and Setters Slot methods—the fast C equivalents for special methods, such as :c:member:`~PyNumberMethods.nb_add` for :py:attr:`~object.__add__` or -:c:member:`~PyType.tp_new` for initialization—have a very simple API that +:c:member:`~PyTypeObject.tp_new` for initialization—have a very simple API that doesn't allow passing in the defining class, unlike with :c:type:`PyCMethod`. The same goes for getters and setters defined with :c:type:`PyGetSetDef`. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index d23644b5093cb3..002d829e78bb3a 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -2533,7 +2533,7 @@ Changes in the C API * As part of the :pep:`492` implementation, the ``tp_reserved`` slot of :c:type:`PyTypeObject` was replaced with a - :c:member:`tp_as_async` slot. Refer to :ref:`coro-objects` for + :c:member:`~PyTypeObject.tp_as_async` slot. Refer to :ref:`coro-objects` for new types, structures and functions. diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index eda8bf0137bffe..56ffc3ef345706 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -1674,7 +1674,7 @@ The new :c:func:`import__find__load__start` and module imports. (Contributed by Christian Heimes in :issue:`31574`.) -The fields :c:member:`name` and :c:member:`doc` of structures +The fields :c:member:`!name` and :c:member:`!doc` of structures :c:type:`PyMemberDef`, :c:type:`PyGetSetDef`, :c:type:`PyStructSequence_Field`, :c:type:`PyStructSequence_Desc`, and :c:type:`wrapperbase` are now of type ``const char *`` rather of From da2097dffbf1573d34439166468012d8f79d8595 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:37:39 -0700 Subject: [PATCH 0448/1206] [3.12] gh-107091: Fix some uses of :c:type: role (GH-107138) (GH-107312) (cherry picked from commit 6d5b6e71c87fca7c5c26f5dd8f325087962215cc) Co-authored-by: Serhiy Storchaka --- Doc/c-api/tuple.rst | 2 ++ Doc/c-api/typeobj.rst | 20 ++++++++++---------- Doc/conf.py | 4 ++++ Doc/library/os.rst | 12 ++++++------ Doc/whatsnew/2.4.rst | 2 +- Doc/whatsnew/3.2.rst | 2 +- Doc/whatsnew/3.3.rst | 2 +- Doc/whatsnew/3.7.rst | 2 +- Misc/NEWS.d/3.10.0a7.rst | 4 ++-- 9 files changed, 28 insertions(+), 22 deletions(-) diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index ac62058676eeeb..01b8da6cb4e0e0 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -111,6 +111,8 @@ Tuple Objects raises :exc:`MemoryError` or :exc:`SystemError`. +.. _struct-sequence-objects: + Struct Sequence Objects ----------------------- diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index de190f5ac39ad2..a6cf8a03d03b9f 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -163,9 +163,9 @@ Quick Reference .. [#cols] Columns: - **"O"**: set on :c:type:`PyBaseObject_Type` + **"O"**: set on :c:data:`PyBaseObject_Type` - **"T"**: set on :c:type:`PyType_Type` + **"T"**: set on :c:data:`PyType_Type` **"D"**: default (if slot is set to ``NULL``) @@ -569,8 +569,8 @@ PyTypeObject Slots Each slot has a section describing inheritance. If :c:func:`PyType_Ready` may set a value when the field is set to ``NULL`` then there will also be -a "Default" section. (Note that many fields set on :c:type:`PyBaseObject_Type` -and :c:type:`PyType_Type` effectively act as defaults.) +a "Default" section. (Note that many fields set on :c:data:`PyBaseObject_Type` +and :c:data:`PyType_Type` effectively act as defaults.) .. c:member:: const char* PyTypeObject.tp_name @@ -964,7 +964,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Default:** - :c:type:`PyBaseObject_Type` uses :c:func:`PyObject_GenericGetAttr`. + :c:data:`PyBaseObject_Type` uses :c:func:`PyObject_GenericGetAttr`. .. c:member:: setattrofunc PyTypeObject.tp_setattro @@ -990,7 +990,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Default:** - :c:type:`PyBaseObject_Type` uses :c:func:`PyObject_GenericSetAttr`. + :c:data:`PyBaseObject_Type` uses :c:func:`PyObject_GenericSetAttr`. .. c:member:: PyBufferProcs* PyTypeObject.tp_as_buffer @@ -1031,7 +1031,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Default:** - :c:type:`PyBaseObject_Type` uses + :c:data:`PyBaseObject_Type` uses ``Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE``. **Bit Masks:** @@ -1556,7 +1556,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) **Default:** - :c:type:`PyBaseObject_Type` provides a :attr:`tp_richcompare` + :c:data:`PyBaseObject_Type` provides a :attr:`tp_richcompare` implementation, which may be inherited. However, if only :attr:`tp_hash` is defined, not even the inherited function is used and instances of the type will not be able to participate in any @@ -1878,7 +1878,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:func:`PyType_GenericAlloc`, to force a standard heap allocation strategy. - For static subtypes, :c:type:`PyBaseObject_Type` uses + For static subtypes, :c:data:`PyBaseObject_Type` uses :c:func:`PyType_GenericAlloc`. That is the recommended value for all statically defined types. @@ -1941,7 +1941,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) match :c:func:`PyType_GenericAlloc` and the value of the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit. - For static subtypes, :c:type:`PyBaseObject_Type` uses PyObject_Del. + For static subtypes, :c:data:`PyBaseObject_Type` uses :c:func:`PyObject_Del`. .. c:member:: inquiry PyTypeObject.tp_is_gc diff --git a/Doc/conf.py b/Doc/conf.py index 209656be4ad433..722831cdb54c3c 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -108,6 +108,10 @@ ('c:type', 'uintmax_t'), ('c:type', 'va_list'), ('c:type', 'wchar_t'), + ('c:struct', 'in6_addr'), + ('c:struct', 'in_addr'), + ('c:struct', 'stat'), + ('c:struct', 'statvfs'), # Standard C macros ('c:macro', 'LLONG_MAX'), ('c:macro', 'LLONG_MIN'), diff --git a/Doc/library/os.rst b/Doc/library/os.rst index bbf227aab649e2..55ebe7e6691622 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2420,13 +2420,13 @@ features: .. function:: major(device, /) Extract the device major number from a raw device number (usually the - :attr:`st_dev` or :attr:`st_rdev` field from :c:type:`stat`). + :attr:`st_dev` or :attr:`st_rdev` field from :c:struct:`stat`). .. function:: minor(device, /) Extract the device minor number from a raw device number (usually the - :attr:`st_dev` or :attr:`st_rdev` field from :c:type:`stat`). + :attr:`st_dev` or :attr:`st_rdev` field from :c:struct:`stat`). .. function:: makedev(major, minor, /) @@ -2937,7 +2937,7 @@ features: .. class:: stat_result Object whose attributes correspond roughly to the members of the - :c:type:`stat` structure. It is used for the result of :func:`os.stat`, + :c:struct:`stat` structure. It is used for the result of :func:`os.stat`, :func:`os.fstat` and :func:`os.lstat`. Attributes: @@ -3117,12 +3117,12 @@ features: See the ``IO_REPARSE_TAG_*`` constants in the :mod:`stat` module. The standard module :mod:`stat` defines functions and constants that are - useful for extracting information from a :c:type:`stat` structure. (On + useful for extracting information from a :c:struct:`stat` structure. (On Windows, some items are filled with dummy values.) For backward compatibility, a :class:`stat_result` instance is also accessible as a tuple of at least 10 integers giving the most important (and - portable) members of the :c:type:`stat` structure, in the order + portable) members of the :c:struct:`stat` structure, in the order :attr:`st_mode`, :attr:`st_ino`, :attr:`st_dev`, :attr:`st_nlink`, :attr:`st_uid`, :attr:`st_gid`, :attr:`st_size`, :attr:`st_atime`, :attr:`st_mtime`, :attr:`st_ctime`. More items may be added at the end by @@ -3174,7 +3174,7 @@ features: Perform a :c:func:`statvfs` system call on the given path. The return value is an object whose attributes describe the filesystem on the given path, and - correspond to the members of the :c:type:`statvfs` structure, namely: + correspond to the members of the :c:struct:`statvfs` structure, namely: :attr:`f_bsize`, :attr:`f_frsize`, :attr:`f_blocks`, :attr:`f_bfree`, :attr:`f_bavail`, :attr:`f_files`, :attr:`f_ffree`, :attr:`f_favail`, :attr:`f_flag`, :attr:`f_namemax`, :attr:`f_fsid`. diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index d68f600ba44f65..a00c4360b9c685 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1491,7 +1491,7 @@ Some of the changes to Python's build process and to the C API are: though that processor architecture doesn't call that register "the TSC register". (Contributed by Jeremy Hylton.) -* The :c:type:`tracebackobject` type has been renamed to +* The :c:type:`!tracebackobject` type has been renamed to :c:type:`PyTracebackObject`. .. ====================================================================== diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index a42775804637e2..ec4d8a0312b6b3 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -566,7 +566,7 @@ Some smaller changes made to the core Python language are: (See :issue:`4617`.) -* The internal :c:type:`structsequence` tool now creates subclasses of tuple. +* :ref:`Struct sequence types ` are now subclasses of tuple. This means that C structures like those returned by :func:`os.stat`, :func:`time.gmtime`, and :data:`sys.version_info` now work like a :term:`named tuple` and now work with functions and methods that diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index aaa4e873fddd8f..6eb5818c317d80 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2195,7 +2195,7 @@ Changes to Python's build process and to the C API include: * :c:func:`PyUnicode_AsUCS4`, :c:func:`PyUnicode_AsUCS4Copy` * :c:macro:`PyUnicode_DATA`, :c:macro:`PyUnicode_1BYTE_DATA`, :c:macro:`PyUnicode_2BYTE_DATA`, :c:macro:`PyUnicode_4BYTE_DATA` - * :c:macro:`PyUnicode_KIND` with :c:type:`PyUnicode_Kind` enum: + * :c:macro:`PyUnicode_KIND` with :c:enum:`PyUnicode_Kind` enum: :c:data:`PyUnicode_WCHAR_KIND`, :c:data:`PyUnicode_1BYTE_KIND`, :c:data:`PyUnicode_2BYTE_KIND`, :c:data:`PyUnicode_4BYTE_KIND` * :c:macro:`PyUnicode_READ`, :c:macro:`PyUnicode_READ_CHAR`, :c:macro:`PyUnicode_WRITE` diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 56ffc3ef345706..e82bb756b8485c 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -1677,7 +1677,7 @@ module imports. The fields :c:member:`!name` and :c:member:`!doc` of structures :c:type:`PyMemberDef`, :c:type:`PyGetSetDef`, :c:type:`PyStructSequence_Field`, :c:type:`PyStructSequence_Desc`, -and :c:type:`wrapperbase` are now of type ``const char *`` rather of +and :c:struct:`wrapperbase` are now of type ``const char *`` rather of ``char *``. (Contributed by Serhiy Storchaka in :issue:`28761`.) The result of :c:func:`PyUnicode_AsUTF8AndSize` and :c:func:`PyUnicode_AsUTF8` diff --git a/Misc/NEWS.d/3.10.0a7.rst b/Misc/NEWS.d/3.10.0a7.rst index ff01ee645c0a90..7933f71b01c14d 100644 --- a/Misc/NEWS.d/3.10.0a7.rst +++ b/Misc/NEWS.d/3.10.0a7.rst @@ -215,8 +215,8 @@ a non-Python signal handler. .. nonce: VouZjn .. section: Core and Builtins -Add ``__match_args__`` to :c:type:`structsequence` based classes. Patch by -Pablo Galindo. +Add ``__match_args__`` to :ref:`struct sequence objects `. +Patch by Pablo Galindo. .. From 58af565c5085c427203ee424585a2c3ed0db4981 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 13:00:40 -0700 Subject: [PATCH 0449/1206] [3.12] Document that `os.link()` is not available on Emscripten (GH-104822) (GH-107308) Document that `os.link()` is not available on Emscripten (GH-104822) (cherry picked from commit 737d1da0746053d515158eac5b115e8bd813f6d3) Co-authored-by: Roman Yurchak --- Doc/library/os.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 55ebe7e6691622..956eeffa1cd453 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2150,7 +2150,7 @@ features: .. audit-event:: os.link src,dst,src_dir_fd,dst_dir_fd os.link - .. availability:: Unix, Windows. + .. availability:: Unix, Windows, not Emscripten. .. versionchanged:: 3.2 Added Windows support. From 4f6d7a5890760434015d9e90a6e81bf9e9b5c52f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 13:17:31 -0700 Subject: [PATCH 0450/1206] [3.12] gh-105002: [pathlib] Fix relative_to with walk_up=True using ".." (GH-107014) (#107315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-105002: [pathlib] Fix relative_to with walk_up=True using ".." (GH-107014) It makes sense to raise an Error because ".." can not be resolved and the current working directory is unknown. (cherry picked from commit e7e6e4b035f51ab4a962b45a957254859f264f4f) Co-authored-by: János Kukovecz --- Lib/pathlib.py | 6 ++++-- Lib/test/test_pathlib.py | 12 ++++++++++++ .../2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst | 3 +++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index b99bf6e7dd2408..65631b70396315 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -679,10 +679,12 @@ def relative_to(self, other, /, *_deprecated, walk_up=False): for step, path in enumerate([other] + list(other.parents)): if self.is_relative_to(path): break + elif not walk_up: + raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") + elif path.name == '..': + raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") else: raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") - if step and not walk_up: - raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") parts = ['..'] * step + self._tail[len(path._tail):] return self.with_segments(*parts) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 1d28a782f44ab3..012dacf10ea805 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -626,8 +626,14 @@ def test_relative_to_common(self): self.assertRaises(ValueError, p.relative_to, P('a/b/c')) self.assertRaises(ValueError, p.relative_to, P('a/c')) self.assertRaises(ValueError, p.relative_to, P('/a')) + self.assertRaises(ValueError, p.relative_to, P("../a")) + self.assertRaises(ValueError, p.relative_to, P("a/..")) + self.assertRaises(ValueError, p.relative_to, P("/a/..")) self.assertRaises(ValueError, p.relative_to, P('/'), walk_up=True) self.assertRaises(ValueError, p.relative_to, P('/a'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) p = P('/a/b') self.assertEqual(p.relative_to(P('/')), P('a/b')) self.assertEqual(p.relative_to('/'), P('a/b')) @@ -656,8 +662,14 @@ def test_relative_to_common(self): self.assertRaises(ValueError, p.relative_to, P()) self.assertRaises(ValueError, p.relative_to, '') self.assertRaises(ValueError, p.relative_to, P('a')) + self.assertRaises(ValueError, p.relative_to, P("../a")) + self.assertRaises(ValueError, p.relative_to, P("a/..")) + self.assertRaises(ValueError, p.relative_to, P("/a/..")) self.assertRaises(ValueError, p.relative_to, P(''), walk_up=True) self.assertRaises(ValueError, p.relative_to, P('a'), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P("../a"), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P("a/.."), walk_up=True) + self.assertRaises(ValueError, p.relative_to, P("/a/.."), walk_up=True) def test_is_relative_to_common(self): P = self.cls diff --git a/Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst b/Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst new file mode 100644 index 00000000000000..b4c133a5cb1244 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst @@ -0,0 +1,3 @@ +Fix invalid result from :meth:`PurePath.relative_to` method when attempting to walk +a "``..``" segment in *other* with *walk_up* enabled. A :exc:`ValueError` exception +is now raised in this case. From 6bbcd792f74148273bf14ab2bad87f190d80b076 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 14:03:35 -0700 Subject: [PATCH 0451/1206] [3.12] Docs: Remove the numbered steps from the Argument Clinic tutorial (GH-107203) (#107317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead, order the tutorial as one body of prose, making it easier to align the tutorial according to Diátaxis principles. (cherry picked from commit 592395577c679543d899e68a3cff538b8b4df80d) Co-authored-by: Erlend E. Aasland --- Doc/howto/clinic.rst | 624 +++++++++++++++++++++---------------------- 1 file changed, 310 insertions(+), 314 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 98d3632ff02325..ea3b4537d4d53b 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -167,23 +167,23 @@ convert a function to work with it. Here, then, are the bare minimum steps you'd need to follow to convert a function to work with Argument Clinic. Note that for code you plan to check in to CPython, you really should take the conversion farther, -using some of the advanced concepts you'll see later on in -the document (like "return converters" and "self converters"). +using some of the :ref:`advanced concepts ` +you'll see later on in the document, +like :ref:`clinic-howto-return-converters` +and :ref:`clinic-howto-self-converter`. But we'll keep it simple for this walkthrough so you can learn. -Let's dive in! +First, make sure you're working with a freshly updated checkout +of the CPython trunk. -0. Make sure you're working with a freshly updated checkout - of the CPython trunk. +Next, find a Python builtin that calls either :c:func:`PyArg_ParseTuple` +or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted +to work with Argument Clinic yet. +For this tutorial, we'll be using +:py:meth:`_pickle.Pickler.dump `. -1. Find a Python builtin that calls either :c:func:`PyArg_ParseTuple` - or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted - to work with Argument Clinic yet. - For my example I'm using - :py:meth:`_pickle.Pickler.dump `. - -2. If the call to the :c:func:`!PyArg_Parse*` function uses any of the - following format units: +If the call to the :c:func:`!PyArg_Parse*` function uses any of the +following format units...: .. code-block:: none @@ -194,388 +194,377 @@ Let's dive in! et et# - or if it has multiple calls to :c:func:`PyArg_ParseTuple`, - you should choose a different function. Argument Clinic *does* - support all of these scenarios. But these are advanced - topics—let's do something simpler for your first function. - - Also, if the function has multiple calls to :c:func:`!PyArg_ParseTuple` - or :c:func:`PyArg_ParseTupleAndKeywords` where it supports different - types for the same argument, or if the function uses something besides - :c:func:`!PyArg_Parse*` functions to parse its arguments, it probably - isn't suitable for conversion to Argument Clinic. Argument Clinic - doesn't support generic functions or polymorphic parameters. - -3. Add the following boilerplate above the function, creating our block:: - - /*[clinic input] - [clinic start generated code]*/ - -4. Cut the docstring and paste it in between the ``[clinic]`` lines, - removing all the junk that makes it a properly quoted C string. - When you're done you should have just the text, based at the left - margin, with no line wider than 80 characters. - (Argument Clinic will preserve indents inside the docstring.) - - If the old docstring had a first line that looked like a function - signature, throw that line away. (The docstring doesn't need it - anymore—when you use :py:func:`help` on your builtin in the future, - the first line will be built automatically based on the function's - signature.) - - Sample:: +... or if it has multiple calls to :c:func:`PyArg_ParseTuple`, +you should choose a different function. +(See :ref:`clinic-howto-advanced-converters` for those scenarios.) - /*[clinic input] - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -5. If your docstring doesn't have a "summary" line, Argument Clinic will - complain. So let's make sure it has one. The "summary" line should - be a paragraph consisting of a single 80-column line - at the beginning of the docstring. - - (Our example docstring consists solely of a summary line, so the sample - code doesn't have to change for this step.) +Also, if the function has multiple calls to :c:func:`!PyArg_ParseTuple` +or :c:func:`PyArg_ParseTupleAndKeywords` where it supports different +types for the same argument, or if the function uses something besides +:c:func:`!PyArg_Parse*` functions to parse its arguments, it probably +isn't suitable for conversion to Argument Clinic. Argument Clinic +doesn't support generic functions or polymorphic parameters. -6. Above the docstring, enter the name of the function, followed - by a blank line. This should be the Python name of the function, - and should be the full dotted path - to the function—it should start with the name of the module, - include any sub-modules, and if the function is a method on - a class it should include the class name too. - - Sample:: +Next, add the following boilerplate above the function, +creating our input block:: /*[clinic input] - _pickle.Pickler.dump - - Write a pickled representation of obj to the open file. [clinic start generated code]*/ -7. If this is the first time that module or class has been used with Argument - Clinic in this C file, - you must declare the module and/or class. Proper Argument Clinic hygiene - prefers declaring these in a separate block somewhere near the - top of the C file, in the same way that include files and statics go at - the top. (In our sample code we'll just show the two blocks next to - each other.) +Cut the docstring and paste it in between the ``[clinic]`` lines, +removing all the junk that makes it a properly quoted C string. +When you're done you should have just the text, based at the left +margin, with no line wider than 80 characters. +Argument Clinic will preserve indents inside the docstring. - The name of the class and module should be the same as the one - seen by Python. Check the name defined in the :c:type:`PyModuleDef` - or :c:type:`PyTypeObject` as appropriate. +If the old docstring had a first line that looked like a function +signature, throw that line away; The docstring doesn't need it anymore --- +when you use :py:func:`help` on your builtin in the future, +the first line will be built automatically based on the function's signature. - When you declare a class, you must also specify two aspects of its type - in C: the type declaration you'd use for a pointer to an instance of - this class, and a pointer to the :c:type:`!PyTypeObject` for this class. +Example docstring summary line:: - Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - - - - -8. Declare each of the parameters to the function. Each parameter - should get its own line. All the parameter lines should be - indented from the function name and the docstring. - - The general form of these parameter lines is as follows: - - .. code-block:: none - - name_of_parameter: converter - - If the parameter has a default value, add that after the - converter: - - .. code-block:: none + /*[clinic input] + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ - name_of_parameter: converter = default_value +If your docstring doesn't have a "summary" line, Argument Clinic will +complain, so let's make sure it has one. The "summary" line should +be a paragraph consisting of a single 80-column line +at the beginning of the docstring. +(See :pep:`257` regarding docstring conventions.) - Argument Clinic's support for "default values" is quite sophisticated; - please see :ref:`the section below on default values ` - for more information. +Our example docstring consists solely of a summary line, so the sample +code doesn't have to change for this step. - Add a blank line below the parameters. +Now, above the docstring, enter the name of the function, followed +by a blank line. This should be the Python name of the function, +and should be the full dotted path to the function --- +it should start with the name of the module, +include any sub-modules, and if the function is a method on +a class it should include the class name too. - What's a "converter"? It establishes both the type - of the variable used in C, and the method to convert the Python - value into a C value at runtime. - For now you're going to use what's called a "legacy converter"—a - convenience syntax intended to make porting old code into Argument - Clinic easier. +In our example, :mod:`!_pickle` is the module, :py:class:`!Pickler` is the class, +and :py:meth:`!dump` is the method, so the name becomes +:py:meth:`!_pickle.Pickler.dump`:: - For each parameter, copy the "format unit" for that - parameter from the :c:func:`PyArg_Parse` format argument and - specify *that* as its converter, as a quoted - string. ("format unit" is the formal name for the one-to-three - character substring of the *format* parameter that tells - the argument parsing function what the type of the variable - is and how to convert it. For more on format units please - see :ref:`arg-parsing`.) + /*[clinic input] + _pickle.Pickler.dump - For multicharacter format units like ``z#``, use the - entire two-or-three character string. + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ - Sample:: +If this is the first time that module or class has been used with Argument +Clinic in this C file, +you must declare the module and/or class. Proper Argument Clinic hygiene +prefers declaring these in a separate block somewhere near the +top of the C file, in the same way that include files and statics go at +the top. +In our sample code we'll just show the two blocks next to each other. - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ +The name of the class and module should be the same as the one +seen by Python. Check the name defined in the :c:type:`PyModuleDef` +or :c:type:`PyTypeObject` as appropriate. - /*[clinic input] - _pickle.Pickler.dump +When you declare a class, you must also specify two aspects of its type +in C: the type declaration you'd use for a pointer to an instance of +this class, and a pointer to the :c:type:`!PyTypeObject` for this class:: - obj: 'O' + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ + /*[clinic input] + _pickle.Pickler.dump -9. If your function has ``|`` in the format string, meaning some - parameters have default values, you can ignore it. Argument - Clinic infers which parameters are optional based on whether - or not they have default values. + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ - If your function has ``$`` in the format string, meaning it - takes keyword-only arguments, specify ``*`` on a line by - itself before the first keyword-only argument, indented the - same as the parameter lines. +Declare each of the parameters to the function. Each parameter +should get its own line. All the parameter lines should be +indented from the function name and the docstring. +The general form of these parameter lines is as follows: - (:py:meth:`!_pickle.Pickler.dump` has neither, so our sample is unchanged.) +.. code-block:: none + name_of_parameter: converter -10. If the existing C function calls :c:func:`PyArg_ParseTuple` - (as opposed to :c:func:`PyArg_ParseTupleAndKeywords`), then all its - arguments are positional-only. +If the parameter has a default value, add that after the +converter: - To mark all parameters as positional-only in Argument Clinic, - add a ``/`` on a line by itself after the last parameter, - indented the same as the parameter lines. +.. code-block:: none - Currently this is all-or-nothing; either all parameters are - positional-only, or none of them are. (In the future Argument - Clinic may relax this restriction.) + name_of_parameter: converter = default_value - Sample:: +Argument Clinic's support for "default values" is quite sophisticated; +see :ref:`clinic-howto-default-values` for more information. - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ +Next, add a blank line below the parameters. - /*[clinic input] - _pickle.Pickler.dump +What's a "converter"? +It establishes both the type of the variable used in C, +and the method to convert the Python value into a C value at runtime. +For now you're going to use what's called a "legacy converter" --- +a convenience syntax intended to make porting old code into Argument +Clinic easier. - obj: 'O' - / +For each parameter, copy the "format unit" for that +parameter from the :c:func:`PyArg_Parse` format argument and +specify *that* as its converter, as a quoted string. +The "format unit" is the formal name for the one-to-three +character substring of the *format* parameter that tells +the argument parsing function what the type of the variable +is and how to convert it. +For more on format units please see :ref:`arg-parsing`. - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ +For multicharacter format units like ``z#``, +use the entire two-or-three character string. -11. It's helpful to write a per-parameter docstring for each parameter. - But per-parameter docstrings are optional; you can skip this step - if you prefer. +Sample:: - Here's how to add a per-parameter docstring. The first line - of the per-parameter docstring must be indented further than the - parameter definition. The left margin of this first line establishes - the left margin for the whole per-parameter docstring; all the text - you write will be outdented by this amount. You can write as much - text as you like, across multiple lines if you wish. + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ - Sample:: + /*[clinic input] + _pickle.Pickler.dump - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ + obj: 'O' - /*[clinic input] - _pickle.Pickler.dump + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ - obj: 'O' - The object to be pickled. - / +If your function has ``|`` in the format string, +meaning some parameters have default values, you can ignore it. +Argument Clinic infers which parameters are optional +based on whether or not they have default values. - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ +If your function has ``$`` in the format string, +meaning it takes keyword-only arguments, +specify ``*`` on a line by itself before the first keyword-only argument, +indented the same as the parameter lines. -12. Save and close the file, then run ``Tools/clinic/clinic.py`` on - it. With luck everything worked---your block now has output, and - a :file:`.c.h` file has been generated! Reopen the file in your - text editor to see:: +:py:meth:`!_pickle.Pickler.dump` has neither, so our sample is unchanged. - /*[clinic input] - _pickle.Pickler.dump +Next, if the existing C function calls :c:func:`PyArg_ParseTuple` +(as opposed to :c:func:`PyArg_ParseTupleAndKeywords`), then all its +arguments are positional-only. - obj: 'O' - The object to be pickled. - / +To mark parameters as positional-only in Argument Clinic, +add a ``/`` on a line by itself after the last positional-only parameter, +indented the same as the parameter lines. - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ +Sample:: - static PyObject * - _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ - Obviously, if Argument Clinic didn't produce any output, it's because - it found an error in your input. Keep fixing your errors and retrying - until Argument Clinic processes your file without complaint. + /*[clinic input] + _pickle.Pickler.dump - For readability, most of the glue code has been generated to a :file:`.c.h` - file. You'll need to include that in your original :file:`.c` file, - typically right after the clinic module block:: + obj: 'O' + / - #include "clinic/_pickle.c.h" + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ -13. Double-check that the argument-parsing code Argument Clinic generated - looks basically the same as the existing code. +It can be helpful to write a per-parameter docstring for each parameter. +Since per-parameter docstrings are optional, +you can skip this step if you prefer. - First, ensure both places use the same argument-parsing function. - The existing code must call either - :c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`; - ensure that the code generated by Argument Clinic calls the - *exact* same function. +Nevertheless, here's how to add a per-parameter docstring. +The first line of the per-parameter docstring +must be indented further than the parameter definition. +The left margin of this first line establishes +the left margin for the whole per-parameter docstring; +all the text you write will be outdented by this amount. +You can write as much text as you like, across multiple lines if you wish. - Second, the format string passed in to :c:func:`!PyArg_ParseTuple` or - :c:func:`!PyArg_ParseTupleAndKeywords` should be *exactly* the same - as the hand-written one in the existing function, up to the colon - or semi-colon. +Sample:: - (Argument Clinic always generates its format strings - with a ``:`` followed by the name of the function. If the - existing code's format string ends with ``;``, to provide - usage help, this change is harmless—don't worry about it.) + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ - Third, for parameters whose format units require two arguments - (like a length variable, or an encoding string, or a pointer - to a conversion function), ensure that the second argument is - *exactly* the same between the two invocations. + /*[clinic input] + _pickle.Pickler.dump - Fourth, inside the output portion of the block you'll find a preprocessor - macro defining the appropriate static :c:type:`PyMethodDef` structure for - this builtin:: + obj: 'O' + The object to be pickled. + / - #define __PICKLE_PICKLER_DUMP_METHODDEF \ - {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ - This static structure should be *exactly* the same as the existing static - :c:type:`!PyMethodDef` structure for this builtin. +Save and close the file, then run ``Tools/clinic/clinic.py`` on it. +With luck everything worked---your block now has output, +and a :file:`.c.h` file has been generated! +Reload the file in your text editor to see the generated code:: - If any of these items differ in *any way*, - adjust your Argument Clinic function specification and rerun - ``Tools/clinic/clinic.py`` until they *are* the same. + /*[clinic input] + _pickle.Pickler.dump + obj: 'O' + The object to be pickled. + / -14. Notice that the last line of its output is the declaration - of your "impl" function. This is where the builtin's implementation goes. - Delete the existing prototype of the function you're modifying, but leave - the opening curly brace. Now delete its argument parsing code and the - declarations of all the variables it dumps the arguments into. - Notice how the Python arguments are now arguments to this impl function; - if the implementation used different names for these variables, fix it. + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ - Let's reiterate, just because it's kind of weird. Your code should now - look like this:: + static PyObject * + _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) + /*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ - static return_type - your_function_impl(...) - /*[clinic end generated code: checksum=...]*/ - { - ... +Obviously, if Argument Clinic didn't produce any output, +it's because it found an error in your input. +Keep fixing your errors and retrying until Argument Clinic processes your file +without complaint. - Argument Clinic generated the checksum line and the function prototype just - above it. You should write the opening (and closing) curly braces for the - function, and the implementation inside. +For readability, most of the glue code has been generated to a :file:`.c.h` +file. You'll need to include that in your original :file:`.c` file, +typically right after the clinic module block:: - Sample:: + #include "clinic/_pickle.c.h" - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +Double-check that the argument-parsing code Argument Clinic generated +looks basically the same as the existing code. - /*[clinic input] - _pickle.Pickler.dump +First, ensure both places use the same argument-parsing function. +The existing code must call either +:c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`; +ensure that the code generated by Argument Clinic calls the +*exact* same function. - obj: 'O' - The object to be pickled. - / +Second, the format string passed in to :c:func:`!PyArg_ParseTuple` or +:c:func:`!PyArg_ParseTupleAndKeywords` should be *exactly* the same +as the hand-written one in the existing function, +up to the colon or semi-colon. - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ +Argument Clinic always generates its format strings +with a ``:`` followed by the name of the function. +If the existing code's format string ends with ``;``, +to provide usage help, this change is harmless --- don't worry about it. - PyDoc_STRVAR(__pickle_Pickler_dump__doc__, - "Write a pickled representation of obj to the open file.\n" - "\n" - ... - static PyObject * - _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ - { - /* Check whether the Pickler was initialized correctly (issue3664). - Developers often forget to call __init__() in their subclasses, which - would trigger a segfault without this check. */ - if (self->write == NULL) { - PyErr_Format(PicklingError, - "Pickler.__init__() was not called by %s.__init__()", - Py_TYPE(self)->tp_name); - return NULL; - } +Third, for parameters whose format units require two arguments, +like a length variable, an encoding string, or a pointer +to a conversion function, ensure that the second argument is +*exactly* the same between the two invocations. - if (_Pickler_ClearBuffer(self) < 0) - return NULL; +Fourth, inside the output portion of the block, +you'll find a preprocessor macro defining the appropriate static +:c:type:`PyMethodDef` structure for this builtin:: - ... + #define __PICKLE_PICKLER_DUMP_METHODDEF \ + {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, -15. Remember the macro with the :c:type:`PyMethodDef` structure for this - function? Find the existing :c:type:`!PyMethodDef` structure for this - function and replace it with a reference to the macro. (If the builtin - is at module scope, this will probably be very near the end of the file; - if the builtin is a class method, this will probably be below but relatively - near to the implementation.) +This static structure should be *exactly* the same as the existing static +:c:type:`!PyMethodDef` structure for this builtin. - Note that the body of the macro contains a trailing comma. So when you - replace the existing static :c:type:`!PyMethodDef` structure with the macro, - *don't* add a comma to the end. +If any of these items differ in *any way*, +adjust your Argument Clinic function specification and rerun +``Tools/clinic/clinic.py`` until they *are* the same. - Sample:: +Notice that the last line of its output is the declaration +of your "impl" function. This is where the builtin's implementation goes. +Delete the existing prototype of the function you're modifying, but leave +the opening curly brace. Now delete its argument parsing code and the +declarations of all the variables it dumps the arguments into. +Notice how the Python arguments are now arguments to this impl function; +if the implementation used different names for these variables, fix it. - static struct PyMethodDef Pickler_methods[] = { - __PICKLE_PICKLER_DUMP_METHODDEF - __PICKLE_PICKLER_CLEAR_MEMO_METHODDEF - {NULL, NULL} /* sentinel */ - }; +Let's reiterate, just because it's kind of weird. +Your code should now look like this:: + static return_type + your_function_impl(...) + /*[clinic end generated code: input=..., output=...]*/ + { + ... -16. Argument Clinic may generate new instances of ``_Py_ID``. For example:: +Argument Clinic generated the checksum line and the function prototype just +above it. You should write the opening and closing curly braces for the +function, and the implementation inside. - &_Py_ID(new_unique_py_id) +Sample:: - If it does, you'll have to run ``make regen-global-objects`` - to regenerate the list of precompiled identifiers at this point. + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ + /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + /*[clinic input] + _pickle.Pickler.dump -17. Compile, then run the relevant portions of the regression-test suite. - This change should not introduce any new compile-time warnings or errors, - and there should be no externally visible change to Python's behavior. + obj: 'O' + The object to be pickled. + / - Well, except for one difference: :py:func:`inspect.signature` run on your function - should now provide a valid signature! + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ - Congratulations, you've ported your first function to work with Argument Clinic! + PyDoc_STRVAR(__pickle_Pickler_dump__doc__, + "Write a pickled representation of obj to the open file.\n" + "\n" + ... + static PyObject * + _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) + /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + { + /* Check whether the Pickler was initialized correctly (issue3664). + Developers often forget to call __init__() in their subclasses, which + would trigger a segfault without this check. */ + if (self->write == NULL) { + PyErr_Format(PicklingError, + "Pickler.__init__() was not called by %s.__init__()", + Py_TYPE(self)->tp_name); + return NULL; + } + + if (_Pickler_ClearBuffer(self) < 0) { + return NULL; + } + + ... + +Remember the macro with the :c:type:`PyMethodDef` structure for this function? +Find the existing :c:type:`!PyMethodDef` structure for this +function and replace it with a reference to the macro. If the builtin +is at module scope, this will probably be very near the end of the file; +if the builtin is a class method, this will probably be below but relatively +near to the implementation. + +Note that the body of the macro contains a trailing comma; when you +replace the existing static :c:type:`!PyMethodDef` structure with the macro, +*don't* add a comma to the end. + +Sample:: + + static struct PyMethodDef Pickler_methods[] = { + __PICKLE_PICKLER_DUMP_METHODDEF + __PICKLE_PICKLER_CLEAR_MEMO_METHODDEF + {NULL, NULL} /* sentinel */ + }; + +Argument Clinic may generate new instances of ``_Py_ID``. For example:: + + &_Py_ID(new_unique_py_id) + +If it does, you'll have to run ``make regen-global-objects`` +to regenerate the list of precompiled identifiers at this point. + +Finally, compile, then run the relevant portions of the regression-test suite. +This change should not introduce any new compile-time warnings or errors, +and there should be no externally visible change to Python's behavior, +except for one difference: :py:func:`inspect.signature` run on your function +should now provide a valid signature! + +Congratulations, you've ported your first function to work with Argument Clinic! .. _clinic-howtos: @@ -913,6 +902,8 @@ you *must* not call :c:func:`PyBuffer_Release` on the provided buffer. Argument Clinic generates code that does it for you (in the parsing function). +.. _clinic-howto-advanced-converters: + How to use advanced converters ------------------------------ @@ -943,6 +934,7 @@ This restriction doesn't seem unreasonable; CPython itself always passes in stat hard-coded encoding strings for parameters whose format units start with ``e``. +.. _clinic-howto-default-values: .. _default_values: How to assign default values to parameter @@ -1053,6 +1045,8 @@ you're not permitted to use: * Tuple/list/set/dict literals. +.. _clinic-howto-return-converters: + How to use return converters ---------------------------- @@ -1195,6 +1189,8 @@ variable to the C code:: /*[python checksum:...]*/ +.. _clinic-howto-self-converter: + How to use the "self converter" ------------------------------- From 434e3b89a7dfc5a9cfc644327c1774a50332b126 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 27 Jul 2023 09:24:18 +0300 Subject: [PATCH 0452/1206] [3.12] gh-107091: Fix some uses of :attr: role (GH-107318) (GH-107330) Fix also formatting of PyMethodDef members. (cherry picked from commit d363eb5b0255c055e7b43f5e2c0847f555e1982e) --- Doc/c-api/import.rst | 20 +++++---- Doc/c-api/init.rst | 7 +++- Doc/c-api/structures.rst | 16 ++++---- Doc/c-api/tuple.rst | 3 +- Doc/c-api/typeobj.rst | 64 ++++++++++++++--------------- Doc/c-api/veryhigh.rst | 4 +- Doc/extending/newtypes.rst | 2 +- Doc/extending/newtypes_tutorial.rst | 4 +- Doc/whatsnew/2.5.rst | 2 +- 9 files changed, 64 insertions(+), 58 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 905cab9034bec6..57f94a7f97671d 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -294,23 +294,25 @@ Importing Modules .. c:struct:: _inittab - Structure describing a single entry in the list of built-in modules. Each of - these structures gives the name and initialization function for a module built - into the interpreter. The name is an ASCII encoded string. Programs which + Structure describing a single entry in the list of built-in modules. + Programs which embed Python may use an array of these structures in conjunction with :c:func:`PyImport_ExtendInittab` to provide additional built-in modules. - The structure is defined in :file:`Include/import.h` as:: + The structure consists of two members: - struct _inittab { - const char *name; /* ASCII encoded string */ - PyObject* (*initfunc)(void); - }; + .. c:member:: const char *name + + The module name, as an ASCII encoded string. + + .. c: member:: PyObject* (*initfunc)(void) + + Initialization function for a module built into the interpreter. .. c:function:: int PyImport_ExtendInittab(struct _inittab *newtab) Add a collection of modules to the table of built-in modules. The *newtab* - array must end with a sentinel entry which contains ``NULL`` for the :attr:`name` + array must end with a sentinel entry which contains ``NULL`` for the :c:member:`~_inittab.name` field; failure to provide the sentinel value can result in a memory fault. Returns ``0`` on success or ``-1`` if insufficient memory could be allocated to extend the internal table. In the event of failure, no modules are added to the diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index c99377fb45a6bc..4144f16f23bff6 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1023,8 +1023,11 @@ code, or when embedding the Python interpreter: .. c:type:: PyThreadState This data structure represents the state of a single thread. The only public - data member is :attr:`interp` (:c:expr:`PyInterpreterState *`), which points to - this thread's interpreter state. + data member is: + + .. c:member:: PyInterpreterState *interp + + This thread's interpreter state. .. c:function:: void PyEval_InitThreads() diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 75e325e8fa83f7..55f3410728bc3e 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -35,7 +35,7 @@ under :ref:`reference counting `. .. c:type:: PyVarObject - This is an extension of :c:type:`PyObject` that adds the :attr:`ob_size` + This is an extension of :c:type:`PyObject` that adds the :c:member:`~PyVarObject.ob_size` field. This is only used for objects that have some notion of *length*. This type does not often appear in the Python/C API. Access to the members must be done by using the macros @@ -152,7 +152,7 @@ under :ref:`reference counting `. .. c:macro:: PyVarObject_HEAD_INIT(type, size) This is a macro which expands to initialization values for a new - :c:type:`PyVarObject` type, including the :attr:`ob_size` field. + :c:type:`PyVarObject` type, including the :c:member:`~PyVarObject.ob_size` field. This macro expands to:: _PyObject_EXTRA_INIT @@ -228,21 +228,21 @@ Implementing functions and methods Structure used to describe a method of an extension type. This structure has four fields: - .. c:member:: const char* ml_name + .. c:member:: const char *ml_name - name of the method + Name of the method. .. c:member:: PyCFunction ml_meth - pointer to the C implementation + Pointer to the C implementation. .. c:member:: int ml_flags - flags bits indicating how the call should be constructed + Flags bits indicating how the call should be constructed. - .. c:member:: const char* ml_doc + .. c:member:: const char *ml_doc - points to the contents of the docstring + Points to the contents of the docstring. The :c:member:`~PyMethodDef.ml_meth` is a C function pointer. The functions may be of different diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 01b8da6cb4e0e0..c3415fdf03d0d5 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -164,7 +164,8 @@ type. Describes a field of a struct sequence. As a struct sequence is modeled as a tuple, all fields are typed as :c:expr:`PyObject*`. The index in the - :attr:`fields` array of the :c:type:`PyStructSequence_Desc` determines which + :c:member:`~PyStructSequence_Desc.fields` array of + the :c:type:`PyStructSequence_Desc` determines which field of the struct sequence is described. +-----------+------------------+-----------------------------------------+ diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index a6cf8a03d03b9f..8d3455c878545d 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -485,17 +485,17 @@ PyObject Slots -------------- The type object structure extends the :c:type:`PyVarObject` structure. The -:attr:`ob_size` field is used for dynamic types (created by :func:`type_new`, +:c:member:`~PyVarObject.ob_size` field is used for dynamic types (created by :func:`type_new`, usually called from a class statement). Note that :c:data:`PyType_Type` (the metatype) initializes :c:member:`~PyTypeObject.tp_itemsize`, which means that its instances (i.e. -type objects) *must* have the :attr:`ob_size` field. +type objects) *must* have the :c:member:`~PyVarObject.ob_size` field. .. c:member:: Py_ssize_t PyObject.ob_refcnt This is the type object's reference count, initialized to ``1`` by the ``PyObject_HEAD_INIT`` macro. Note that for :ref:`statically allocated type - objects `, the type's instances (objects whose :attr:`ob_type` + objects `, the type's instances (objects whose :c:member:`~PyObject.ob_type` points back to the type) do *not* count as references. But for :ref:`dynamically allocated type objects `, the instances *do* count as references. @@ -519,8 +519,8 @@ type objects) *must* have the :attr:`ob_size` field. Foo_Type.ob_type = &PyType_Type; This should be done before any instances of the type are created. - :c:func:`PyType_Ready` checks if :attr:`ob_type` is ``NULL``, and if so, - initializes it to the :attr:`ob_type` field of the base class. + :c:func:`PyType_Ready` checks if :c:member:`~PyObject.ob_type` is ``NULL``, and if so, + initializes it to the :c:member:`~PyObject.ob_type` field of the base class. :c:func:`PyType_Ready` will not change this field if it is non-zero. **Inheritance:** @@ -619,20 +619,20 @@ and :c:data:`PyType_Type` effectively act as defaults.) instances have the same size, given in :c:member:`~PyTypeObject.tp_basicsize`. For a type with variable-length instances, the instances must have an - :attr:`ob_size` field, and the instance size is :c:member:`~PyTypeObject.tp_basicsize` plus N + :c:member:`~PyVarObject.ob_size` field, and the instance size is :c:member:`~PyTypeObject.tp_basicsize` plus N times :c:member:`~PyTypeObject.tp_itemsize`, where N is the "length" of the object. The value of - N is typically stored in the instance's :attr:`ob_size` field. There are - exceptions: for example, ints use a negative :attr:`ob_size` to indicate a + N is typically stored in the instance's :c:member:`~PyVarObject.ob_size` field. There are + exceptions: for example, ints use a negative :c:member:`~PyVarObject.ob_size` to indicate a negative number, and N is ``abs(ob_size)`` there. Also, the presence of an - :attr:`ob_size` field in the instance layout doesn't mean that the instance + :c:member:`~PyVarObject.ob_size` field in the instance layout doesn't mean that the instance structure is variable-length (for example, the structure for the list type has - fixed-length instances, yet those instances have a meaningful :attr:`ob_size` + fixed-length instances, yet those instances have a meaningful :c:member:`~PyVarObject.ob_size` field). The basic size includes the fields in the instance declared by the macro :c:macro:`PyObject_HEAD` or :c:macro:`PyObject_VAR_HEAD` (whichever is used to - declare the instance struct) and this in turn includes the :attr:`_ob_prev` and - :attr:`_ob_next` fields if they are present. This means that the only correct + declare the instance struct) and this in turn includes the :c:member:`~PyObject._ob_prev` and + :c:member:`~PyObject._ob_next` fields if they are present. This means that the only correct way to get an initializer for the :c:member:`~PyTypeObject.tp_basicsize` is to use the ``sizeof`` operator on the struct used to declare the instance layout. The basic size does not include the GC header size. @@ -764,7 +764,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :attr:`tp_getattr`, :attr:`tp_getattro` + Group: :c:member:`~PyTypeObject.tp_getattr`, :c:member:`~PyTypeObject.tp_getattro` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_getattro`: a subtype inherits both :c:member:`~PyTypeObject.tp_getattr` and :c:member:`~PyTypeObject.tp_getattro` from its base type when @@ -781,7 +781,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :attr:`tp_setattr`, :attr:`tp_setattro` + Group: :c:member:`~PyTypeObject.tp_setattr`, :c:member:`~PyTypeObject.tp_setattro` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_setattro`: a subtype inherits both :c:member:`~PyTypeObject.tp_setattr` and :c:member:`~PyTypeObject.tp_setattro` from its base type when @@ -883,7 +883,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) normal return value; when an error occurs during the computation of the hash value, the function should set an exception and return ``-1``. - When this field is not set (*and* :attr:`tp_richcompare` is not set), + When this field is not set (*and* :c:member:`~PyTypeObject.tp_richcompare` is not set), an attempt to take the hash of the object raises :exc:`TypeError`. This is the same as setting it to :c:func:`PyObject_HashNotImplemented`. @@ -897,7 +897,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :attr:`tp_hash`, :attr:`tp_richcompare` + Group: :c:member:`~PyTypeObject.tp_hash`, :c:member:`~PyTypeObject.tp_richcompare` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_richcompare`: a subtype inherits both of @@ -956,7 +956,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :attr:`tp_getattr`, :attr:`tp_getattro` + Group: :c:member:`~PyTypeObject.tp_getattr`, :c:member:`~PyTypeObject.tp_getattro` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_getattr`: a subtype inherits both :c:member:`~PyTypeObject.tp_getattr` and :c:member:`~PyTypeObject.tp_getattro` from its base type when @@ -982,7 +982,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :attr:`tp_setattr`, :attr:`tp_setattro` + Group: :c:member:`~PyTypeObject.tp_setattr`, :c:member:`~PyTypeObject.tp_setattro` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_setattr`: a subtype inherits both :c:member:`~PyTypeObject.tp_setattr` and :c:member:`~PyTypeObject.tp_setattro` from its base type when @@ -1047,7 +1047,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) This bit is set when the type object itself is allocated on the heap, for example, types created dynamically using :c:func:`PyType_FromSpec`. In this - case, the :attr:`ob_type` field of its instances is considered a reference to + case, the :c:member:`~PyObject.ob_type` field of its instances is considered a reference to the type, and the type object is INCREF'ed when a new instance is created, and DECREF'ed when an instance is destroyed (this does not apply to instances of subtypes; only the type referenced by the instance's ob_type gets INCREF'ed or @@ -1100,13 +1100,13 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` + Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :c:member:`~PyTypeObject.tp_traverse`, :c:member:`~PyTypeObject.tp_clear` The :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is inherited - together with the :attr:`tp_traverse` and :attr:`tp_clear` + together with the :c:member:`~PyTypeObject.tp_traverse` and :c:member:`~PyTypeObject.tp_clear` fields, i.e. if the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit is - clear in the subtype and the :attr:`tp_traverse` and - :attr:`tp_clear` fields in the subtype exist and have ``NULL`` + clear in the subtype and the :c:member:`~PyTypeObject.tp_traverse` and + :c:member:`~PyTypeObject.tp_clear` fields in the subtype exist and have ``NULL`` values. @@ -1421,7 +1421,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` + Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :c:member:`~PyTypeObject.tp_traverse`, :c:member:`~PyTypeObject.tp_clear` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_clear` and the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit: the flag bit, :c:member:`~PyTypeObject.tp_traverse`, and @@ -1488,7 +1488,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :attr:`tp_traverse`, :attr:`tp_clear` + Group: :c:macro:`Py_TPFLAGS_HAVE_GC`, :c:member:`~PyTypeObject.tp_traverse`, :c:member:`~PyTypeObject.tp_clear` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_traverse` and the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit: the flag bit, :c:member:`~PyTypeObject.tp_traverse`, and @@ -1547,7 +1547,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Inheritance:** - Group: :attr:`tp_hash`, :attr:`tp_richcompare` + Group: :c:member:`~PyTypeObject.tp_hash`, :c:member:`~PyTypeObject.tp_richcompare` This field is inherited by subtypes together with :c:member:`~PyTypeObject.tp_hash`: a subtype inherits :c:member:`~PyTypeObject.tp_richcompare` and :c:member:`~PyTypeObject.tp_hash` when @@ -1556,9 +1556,9 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Default:** - :c:data:`PyBaseObject_Type` provides a :attr:`tp_richcompare` + :c:data:`PyBaseObject_Type` provides a :c:member:`~PyTypeObject.tp_richcompare` implementation, which may be inherited. However, if only - :attr:`tp_hash` is defined, not even the inherited function is used + :c:member:`~PyTypeObject.tp_hash` is defined, not even the inherited function is used and instances of the type will not be able to participate in any comparisons. @@ -2374,9 +2374,9 @@ Sequence Object Structures This slot must be filled for the :c:func:`PySequence_Check` function to return ``1``, it can be ``NULL`` otherwise. - Negative indexes are handled as follows: if the :attr:`sq_length` slot is + Negative indexes are handled as follows: if the :c:member:`~PySequenceMethods.sq_length` slot is filled, it is called and the sequence length is used to compute a positive - index which is passed to :attr:`sq_item`. If :attr:`sq_length` is ``NULL``, + index which is passed to :c:member:`~PySequenceMethods.sq_item`. If :c:member:`!sq_length` is ``NULL``, the index is passed as is to the function. .. c:member:: ssizeobjargproc PySequenceMethods.sq_ass_item @@ -2586,8 +2586,8 @@ Slot Type typedefs The purpose of this function is to separate memory allocation from memory initialization. It should return a pointer to a block of memory of adequate length for the instance, suitably aligned, and initialized to zeros, but with - :attr:`ob_refcnt` set to ``1`` and :attr:`ob_type` set to the type argument. If - the type's :c:member:`~PyTypeObject.tp_itemsize` is non-zero, the object's :attr:`ob_size` field + :c:member:`~PyObject.ob_refcnt` set to ``1`` and :c:member:`~PyObject.ob_type` set to the type argument. If + the type's :c:member:`~PyTypeObject.tp_itemsize` is non-zero, the object's :c:member:`~PyVarObject.ob_size` field should be initialized to *nitems* and the length of the allocated memory block should be ``tp_basicsize + nitems*tp_itemsize``, rounded up to a multiple of ``sizeof(void*)``; otherwise, *nitems* is not used and the length of the block diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 56fa2d6abd9139..324518c035096b 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -353,7 +353,7 @@ the same library that the Python runtime is using. executed, it is passed as ``PyCompilerFlags *flags``. In this case, ``from __future__ import`` can modify *flags*. - Whenever ``PyCompilerFlags *flags`` is ``NULL``, :attr:`cf_flags` is treated as + Whenever ``PyCompilerFlags *flags`` is ``NULL``, :c:member:`~PyCompilerFlags.cf_flags` is treated as equal to ``0``, and any modification due to ``from __future__ import`` is discarded. @@ -367,7 +367,7 @@ the same library that the Python runtime is using. initialized to ``PY_MINOR_VERSION``. The field is ignored by default, it is used if and only if - ``PyCF_ONLY_AST`` flag is set in *cf_flags*. + ``PyCF_ONLY_AST`` flag is set in :c:member:`~PyCompilerFlags.cf_flags`. .. versionchanged:: 3.8 Added *cf_feature_version* field. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 7f8f8ddaaaccd6..25822744125f80 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -270,7 +270,7 @@ structure:: One entry should be defined for each method provided by the type; no entries are needed for methods inherited from a base type. One additional entry is needed at the end; it is a sentinel that marks the end of the array. The -:attr:`ml_name` field of the sentinel must be ``NULL``. +:c:member:`~PyMethodDef.ml_name` field of the sentinel must be ``NULL``. The second table is used to define attributes which map directly to data stored in the instance. A variety of primitive C types are supported, and access may diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index ba09fb1b05c0bf..82671fdc447d9c 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -176,8 +176,8 @@ Everything else in the file should be familiar, except for some code in if (PyType_Ready(&CustomType) < 0) return; -This initializes the :class:`Custom` type, filling in a number of members -to the appropriate default values, including :attr:`ob_type` that we initially +This initializes the :class:`!Custom` type, filling in a number of members +to the appropriate default values, including :c:member:`~PyObject.ob_type` that we initially set to ``NULL``. :: Py_INCREF(&CustomType); diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index b410fe1ce3f084..162d2c342f50fd 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -954,7 +954,7 @@ The return value must be either a Python integer or long integer. The interpreter will check that the type returned is correct, and raises a :exc:`TypeError` if this requirement isn't met. -A corresponding :attr:`nb_index` slot was added to the C-level +A corresponding :c:member:`~PyNumberMethods.nb_index` slot was added to the C-level :c:type:`PyNumberMethods` structure to let C extensions implement this protocol. ``PyNumber_Index(obj)`` can be used in extension code to call the :meth:`__index__` function and retrieve its result. From 36e96baa33cb5aa6cb03a1555017dd66f4244183 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 26 Jul 2023 23:37:54 -0700 Subject: [PATCH 0453/1206] [3.12] gh-107298: Docs: add targets for some :c:member: and :c:macro: references (GH-107316) (GH-107332) Add targets for PyStructSequence_Desc and PyStructSequence_Field members and macros like Py_EQ. Fix target for Py_RETURN_RICHCOMPARE. (cherry picked from commit abec9a1b20b70d8ced401d59fc4f02b331c6568b) Co-authored-by: Serhiy Storchaka --- Doc/c-api/tuple.rst | 47 +++++++++++++++++++++---------------------- Doc/c-api/typeobj.rst | 32 +++++++++++++++-------------- Doc/tools/.nitignore | 1 - 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index c3415fdf03d0d5..9bc3dab0c9c12c 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -144,20 +144,21 @@ type. Contains the meta information of a struct sequence type to create. - +-------------------+------------------------------+--------------------------------------+ - | Field | C Type | Meaning | - +===================+==============================+======================================+ - | ``name`` | ``const char *`` | name of the struct sequence type | - +-------------------+------------------------------+--------------------------------------+ - | ``doc`` | ``const char *`` | pointer to docstring for the type | - | | | or ``NULL`` to omit | - +-------------------+------------------------------+--------------------------------------+ - | ``fields`` | ``PyStructSequence_Field *`` | pointer to ``NULL``-terminated array | - | | | with field names of the new type | - +-------------------+------------------------------+--------------------------------------+ - | ``n_in_sequence`` | ``int`` | number of fields visible to the | - | | | Python side (if used as tuple) | - +-------------------+------------------------------+--------------------------------------+ + .. c:member:: const char *name + + Name of the struct sequence type. + + .. c:member:: const char *doc + + Pointer to docstring for the type or ``NULL`` to omit. + + .. c:member:: PyStructSequence_Field *fields + + Pointer to ``NULL``-terminated array with field names of the new type. + + .. c:member:: int n_in_sequence + + Number of fields visible to the Python side (if used as tuple). .. c:type:: PyStructSequence_Field @@ -168,16 +169,14 @@ type. the :c:type:`PyStructSequence_Desc` determines which field of the struct sequence is described. - +-----------+------------------+-----------------------------------------+ - | Field | C Type | Meaning | - +===========+==================+=========================================+ - | ``name`` | ``const char *`` | name for the field or ``NULL`` to end | - | | | the list of named fields, set to | - | | | :c:data:`PyStructSequence_UnnamedField` | - | | | to leave unnamed | - +-----------+------------------+-----------------------------------------+ - | ``doc`` | ``const char *`` | field docstring or ``NULL`` to omit | - +-----------+------------------+-----------------------------------------+ + .. c:member:: const char *name + + Name for the field or ``NULL`` to end the list of named fields, + set to :c:data:`PyStructSequence_UnnamedField` to leave unnamed. + + .. c:member:: const char *doc + + Field docstring or ``NULL`` to omit. .. c:var:: const char * const PyStructSequence_UnnamedField diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 8d3455c878545d..e70b82405a4cf7 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1513,21 +1513,23 @@ and :c:data:`PyType_Type` effectively act as defaults.) The following constants are defined to be used as the third argument for :c:member:`~PyTypeObject.tp_richcompare` and for :c:func:`PyObject_RichCompare`: - +------------------+------------+ - | Constant | Comparison | - +==================+============+ - | :c:macro:`Py_LT` | ``<`` | - +------------------+------------+ - | :c:macro:`Py_LE` | ``<=`` | - +------------------+------------+ - | :c:macro:`Py_EQ` | ``==`` | - +------------------+------------+ - | :c:macro:`Py_NE` | ``!=`` | - +------------------+------------+ - | :c:macro:`Py_GT` | ``>`` | - +------------------+------------+ - | :c:macro:`Py_GE` | ``>=`` | - +------------------+------------+ + .. c:namespace:: NULL + + +--------------------+------------+ + | Constant | Comparison | + +====================+============+ + | .. c:macro:: Py_LT | ``<`` | + +--------------------+------------+ + | .. c:macro:: Py_LE | ``<=`` | + +--------------------+------------+ + | .. c:macro:: Py_EQ | ``==`` | + +--------------------+------------+ + | .. c:macro:: Py_NE | ``!=`` | + +--------------------+------------+ + | .. c:macro:: Py_GT | ``>`` | + +--------------------+------------+ + | .. c:macro:: Py_GE | ``>=`` | + +--------------------+------------+ The following macro is defined to ease writing rich comparison functions: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 849ef1168b4554..25d0f27e18311c 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -36,7 +36,6 @@ Doc/c-api/set.rst Doc/c-api/stable.rst Doc/c-api/structures.rst Doc/c-api/sys.rst -Doc/c-api/tuple.rst Doc/c-api/type.rst Doc/c-api/typehints.rst Doc/c-api/typeobj.rst From 5f3e371e2d837d4a06eaee43fbfdf589aca2fc0f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 00:07:55 -0700 Subject: [PATCH 0454/1206] [3.12] Docs: Argument Clinic: Restructure "Basic concepts and usage" (GH-106981) (#107325) Split "Basic concepts and usage" into: - Reference - Terminology - CLI reference - Background - Basic concepts (cherry picked from commit 2ad699002e3ce09e9fa41e333ac72f16a32d94de) Co-authored-by: Erlend E. Aasland Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Alex Waygood Co-authored-by: Ezio Melotti --- Doc/howto/clinic.rst | 172 ++++++++++++++++++++++++++++++----------- Tools/clinic/clinic.py | 20 +++-- 2 files changed, 142 insertions(+), 50 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index ea3b4537d4d53b..7aafd48711b58e 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -8,6 +8,7 @@ Argument Clinic How-To :author: Larry Hastings +**Source code:** :source:`Tools/clinic/clinic.py`. .. topic:: Abstract @@ -15,10 +16,12 @@ Argument Clinic How-To Its purpose is to automate all the boilerplate involved with writing argument parsing code for "builtins", module level functions, and class methods. - This document is divided in three major sections: + This document is divided in four major sections: * :ref:`clinic-background` talks about the basic concepts and goals of Argument Clinic. + * :ref:`clinic-reference` describes the command-line interface and Argument + Clinic terminology. * :ref:`clinic-tutorial` guides you through all the steps required to adapt an existing C function to Argument Clinic. * :ref:`clinic-howtos` details how to handle specific tasks. @@ -93,39 +96,29 @@ and it should be able to do many interesting and smart things with all the information you give it. -Basic concepts and usage ------------------------- +Basic concepts +-------------- -Argument Clinic ships with CPython; you'll find it in -:source:`Tools/clinic/clinic.py`. -If you run that script, specifying a C file as an argument: - -.. code-block:: shell-session - - $ python Tools/clinic/clinic.py foo.c - -Argument Clinic will scan over the file looking for lines that -look exactly like this: +When Argument Clinic is run on a file, either via the :ref:`clinic-cli` +or via ``make clinic``, it will scan over the input files looking for +:term:`start lines `: .. code-block:: none /*[clinic input] -When it finds one, it reads everything up to a line that looks -exactly like this: +When it finds one, it reads everything up to the :term:`end line`: .. code-block:: none [clinic start generated code]*/ -Everything in between these two lines is input for Argument Clinic. -All of these lines, including the beginning and ending comment -lines, are collectively called an Argument Clinic "block". - -When Argument Clinic parses one of these blocks, it -generates output. This output is rewritten into the C file -immediately after the block, followed by a comment containing a checksum. -The Argument Clinic block now looks like this: +Everything in between these two lines is Argument Clinic :term:`input`. +When Argument Clinic parses input, it generates :term:`output`. +The output is rewritten into the C file immediately after the input, +followed by a :term:`checksum line`. +All of these lines, including the :term:`start line` and :term:`checksum line`, +are collectively called an Argument Clinic :term:`block`: .. code-block:: none @@ -133,28 +126,121 @@ The Argument Clinic block now looks like this: ... clinic input goes here ... [clinic start generated code]*/ ... clinic output goes here ... - /*[clinic end generated code: checksum=...]*/ + /*[clinic end generated code: ...]*/ If you run Argument Clinic on the same file a second time, Argument Clinic -will discard the old output and write out the new output with a fresh checksum -line. However, if the input hasn't changed, the output won't change either. - -You should never modify the output portion of an Argument Clinic block. Instead, -change the input until it produces the output you want. (That's the purpose of the -checksum—to detect if someone changed the output, as these edits would be lost -the next time Argument Clinic writes out fresh output.) - -For the sake of clarity, here's the terminology we'll use with Argument Clinic: - -* The first line of the comment (``/*[clinic input]``) is the *start line*. -* The last line of the initial comment (``[clinic start generated code]*/``) is the *end line*. -* The last line (``/*[clinic end generated code: checksum=...]*/``) is the *checksum line*. -* In between the start line and the end line is the *input*. -* In between the end line and the checksum line is the *output*. -* All the text collectively, from the start line to the checksum line inclusively, - is the *block*. (A block that hasn't been successfully processed by Argument - Clinic yet doesn't have output or a checksum line, but it's still considered - a block.) +will discard the old :term:`output` and write out the new output with a fresh +:term:`checksum line`. +If the :term:`input` hasn't changed, the output won't change either. + +.. note:: + + You should never modify the output of an Argument Clinic block, + as any change will be lost in future Argument Clinic runs; + Argument Clinic will detect an output checksum mismatch and regenerate the + correct output. + If you are not happy with the generated output, + you should instead change the input until it produces the output you want. + + +.. _clinic-reference: + +Reference +========= + + +.. _clinic-terminology: + +Terminology +----------- + +.. glossary:: + + start line + The line ``/*[clinic input]``. + This line marks the beginning of Argument Clinic input. + Note that the *start line* opens a C block comment. + + end line + The line ``[clinic start generated code]*/``. + The *end line* marks the _end_ of Argument Clinic :term:`input`, + but at the same time marks the _start_ of Argument Clinic :term:`output`, + thus the text *"clinic start start generated code"* + Note that the *end line* closes the C block comment opened + by the *start line*. + + checksum + A hash to distinguish unique :term:`inputs ` + and :term:`outputs `. + + checksum line + A line that looks like ``/*[clinic end generated code: ...]*/``. + The three dots will be replaced by a :term:`checksum` generated from the + :term:`input`, and a :term:`checksum` generated from the :term:`output`. + The checksum line marks the end of Argument Clinic generated code, + and is used by Argument Clinic to determine if it needs to regenerate + output. + + input + The text between the :term:`start line` and the :term:`end line`. + Note that the start and end lines open and close a C block comment; + the *input* is thus a part of that same C block comment. + + output + The text between the :term:`end line` and the :term:`checksum line`. + + block + All text from the :term:`start line` to the :term:`checksum line` inclusively. + + +.. _clinic-cli: + +Command-line interface +---------------------- + +The Argument Clinic :abbr:`CLI (Command-Line Interface)` is typically used to +process a single source file, like this: + +.. code-block:: shell-session + + $ python3 ./Tools/clinic/clinic.py foo.c + +The CLI supports the following options: + +.. program:: ./Tools/clinic/clinic.py [-h] [-f] [-o OUTPUT] [-v] \ + [--converters] [--make] [--srcdir SRCDIR] [FILE ...] + +.. option:: -h, --help + + Print CLI usage. + +.. option:: -f, --force + + Force output regeneration. + +.. option:: -o, --output OUTPUT + + Redirect file output to OUTPUT + +.. option:: -v, --verbose + + Enable verbose mode. + +.. option:: --converters + + Print a list of all supported converters and return converters. + +.. option:: --make + + Walk :option:`--srcdir` to run over all relevant files. + +.. option:: --srcdir SRCDIR + + The directory tree to walk in :option:`--make` mode. + +.. option:: FILE ... + + The list of files to process. .. _clinic-tutorial: diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 3e60328082d66c..e775b012d0b6df 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5431,15 +5431,21 @@ def main(argv): signatures ("docstrings") for CPython builtins. For more information see https://docs.python.org/3/howto/clinic.html""") - cmdline.add_argument("-f", "--force", action='store_true') - cmdline.add_argument("-o", "--output", type=str) - cmdline.add_argument("-v", "--verbose", action='store_true') - cmdline.add_argument("--converters", action='store_true') + cmdline.add_argument("-f", "--force", action='store_true', + help="force output regeneration") + cmdline.add_argument("-o", "--output", type=str, + help="redirect file output to OUTPUT") + cmdline.add_argument("-v", "--verbose", action='store_true', + help="enable verbose mode") + cmdline.add_argument("--converters", action='store_true', + help=("print a list of all supported converters " + "and return converters")) cmdline.add_argument("--make", action='store_true', - help="Walk --srcdir to run over all relevant files.") + help="walk --srcdir to run over all relevant files") cmdline.add_argument("--srcdir", type=str, default=os.curdir, - help="The directory tree to walk in --make mode.") - cmdline.add_argument("filename", type=str, nargs="*") + help="the directory tree to walk in --make mode") + cmdline.add_argument("filename", metavar="FILE", type=str, nargs="*", + help="the list of files to process") ns = cmdline.parse_args(argv) if ns.converters: From 38c982d92eef1b2fa9418fc0127442690515cdbe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 01:11:50 -0700 Subject: [PATCH 0455/1206] [3.12] gh-106996: Rewrite turtle explanation (GH-107244) (#107335) Co-authored-by: Daniele Procida Co-authored-by: Hugo van Kemenade --- Doc/library/turtle.rst | 92 +++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index a85c3f466323f9..cd8254153f765a 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -277,67 +277,16 @@ The turtle's screen can be customised, for example:: t.screen.bgcolor("orange") -.. _turtle-explanation: - -Explanation -=========== - -The :mod:`turtle` module is an extended reimplementation of the same-named -module from the Python standard distribution up to version Python 2.5. - -It tries to keep the merits of the old turtle module and to be (nearly) 100% -compatible with it. This means in the first place to enable the learning -programmer to use all the commands, classes and methods interactively when using -the module from within IDLE run with the ``-n`` switch. - -The turtle module provides turtle graphics primitives, in both object-oriented -and procedure-oriented ways. Because it uses :mod:`tkinter` for the underlying -graphics, it needs a version of Python installed with Tk support. - -The object-oriented interface uses essentially two+two classes: - -1. The :class:`TurtleScreen` class defines graphics windows as a playground for - the drawing turtles. Its constructor needs a :class:`tkinter.Canvas` or a - :class:`ScrolledCanvas` as argument. It should be used when :mod:`turtle` is - used as part of some application. - - The function :func:`Screen` returns a singleton object of a - :class:`TurtleScreen` subclass. This function should be used when - :mod:`turtle` is used as a standalone tool for doing graphics. - As a singleton object, inheriting from its class is not possible. - - All methods of TurtleScreen/Screen also exist as functions, i.e. as part of - the procedure-oriented interface. - -2. :class:`RawTurtle` (alias: :class:`RawPen`) defines Turtle objects which draw - on a :class:`TurtleScreen`. Its constructor needs a Canvas, ScrolledCanvas - or TurtleScreen as argument, so the RawTurtle objects know where to draw. - - Derived from RawTurtle is the subclass :class:`Turtle` (alias: :class:`Pen`), - which draws on "the" :class:`Screen` instance which is automatically - created, if not already present. - - All methods of RawTurtle/Turtle also exist as functions, i.e. part of the - procedure-oriented interface. - -The procedural interface provides functions which are derived from the methods -of the classes :class:`Screen` and :class:`Turtle`. They have the same names as -the corresponding methods. A screen object is automatically created whenever a -function derived from a Screen method is called. An (unnamed) turtle object is -automatically created whenever any of the functions derived from a Turtle method -is called. - -To use multiple turtles on a screen one has to use the object-oriented interface. +Turtle graphics reference +========================= .. note:: + In the following documentation the argument list for functions is given. Methods, of course, have the additional first argument *self* which is omitted here. -Turtle graphics reference -========================= - Turtle methods -------------- @@ -2465,6 +2414,41 @@ Public classes * ``a.rotate(angle)`` rotation +.. _turtle-explanation: + +Explanation +=========== + +A turtle object draws on a screen object, and there a number of key classes in +the turtle object-oriented interface that can be used to create them and relate +them to each other. + +A :class:`Turtle` instance will automatically create a :class:`Screen` +instance if one is not already present. + +``Turtle`` is a subclass of :class:`RawTurtle`, which *doesn't* automatically +create a drawing surface - a *canvas* will need to be provided or created for +it. The *canvas* can be a :class:`tkinter.Canvas`, :class:`ScrolledCanvas` +or :class:`TurtleScreen`. + + +:class:`TurtleScreen` is the basic drawing surface for a +turtle. :class:`Screen` is a subclass of ``TurtleScreen``, and +includes :ref:`some additional methods ` for managing its +appearance (including size and title) and behaviour. ``TurtleScreen``'s +constructor needs a :class:`tkinter.Canvas` or a +:class:`ScrolledCanvas` as an argument. + +The functional interface for turtle graphics uses the various methods of +``Turtle`` and ``TurtleScreen``/``Screen``. Behind the scenes, a screen +object is automatically created whenever a function derived from a ``Screen`` +method is called. Similarly, a turtle object is automatically created +whenever any of the functions derived from a Turtle method is called. + +To use multiple turtles on a screen, the object-oriented interface must be +used. + + Help and configuration ====================== From 0063ad8189cd4ac84775eb9150b7f3373842568a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 05:13:02 -0700 Subject: [PATCH 0456/1206] [3.12] Bump some docs dependencies to resolve a Dependabot security alert (GH-107341) (#107342) Bump some docs dependencies to resolve a Dependabot security alert (GH-107341) (cherry picked from commit f84d77b4e07aeb6241c1ff9932627d3ba059efa8) Co-authored-by: Alex Waygood --- Doc/requirements-oldest-sphinx.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/requirements-oldest-sphinx.txt b/Doc/requirements-oldest-sphinx.txt index d0390a04ea6dd8..94611ca22f09fe 100644 --- a/Doc/requirements-oldest-sphinx.txt +++ b/Doc/requirements-oldest-sphinx.txt @@ -14,11 +14,10 @@ python-docs-theme>=2022.1 # Docutils<0.17, Jinja2<3, and MarkupSafe<2 are additionally specified as # Sphinx 3.2 is incompatible with newer releases of these packages. -Sphinx==3.2.1 alabaster==0.7.13 Babel==2.12.1 -certifi==2022.12.7 -charset-normalizer==3.1.0 +certifi==2023.7.22 +charset-normalizer==3.2.0 colorama==0.4.6 docutils==0.16 idna==3.4 @@ -27,12 +26,13 @@ Jinja2==2.11.3 MarkupSafe==1.1.1 packaging==23.1 Pygments==2.15.1 -requests==2.29.0 +requests==2.31.0 snowballstemmer==2.2.0 +Sphinx==3.2.1 sphinxcontrib-applehelp==1.0.4 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 -urllib3==1.26.15 +urllib3==2.0.4 From 57ef065eb3a9200aece38dfb6b90055500f076d3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:15:47 -0700 Subject: [PATCH 0457/1206] [3.12] gh-101524: Only Use Public C-API in the _xxsubinterpreters Module (gh-105258) (gh-107303) The _xxsubinterpreters module was meant to only use public API. Some internal C-API usage snuck in over the last few years (e.g. gh-28969). This fixes that. (cherry picked from commit e6373c0d8b59512aa7f0dea7f3fb162b6ed10fa4) Co-authored-by: Eric Snow --- .../interpreteridobject.h} | 17 +++-------------- Include/internal/pycore_pymem.h | 2 +- Include/interpreteridobject.h | 17 +++++++++++++++++ Makefile.pre.in | 3 ++- Modules/_testinternalcapi.c | 2 +- Modules/_xxinterpchannelsmodule.c | 6 +----- Modules/_xxsubinterpretersmodule.c | 12 +++--------- Objects/interpreteridobject.c | 2 +- Objects/object.c | 2 +- PCbuild/pythoncore.vcxproj | 3 ++- PCbuild/pythoncore.vcxproj.filters | 9 ++++++--- Tools/c-analyzer/cpython/_parser.py | 1 + 12 files changed, 39 insertions(+), 37 deletions(-) rename Include/{internal/pycore_interpreteridobject.h => cpython/interpreteridobject.h} (51%) create mode 100644 Include/interpreteridobject.h diff --git a/Include/internal/pycore_interpreteridobject.h b/Include/cpython/interpreteridobject.h similarity index 51% rename from Include/internal/pycore_interpreteridobject.h rename to Include/cpython/interpreteridobject.h index 804831e76deaea..5076584209b90b 100644 --- a/Include/internal/pycore_interpreteridobject.h +++ b/Include/cpython/interpreteridobject.h @@ -1,22 +1,11 @@ -/* Interpreter ID Object */ - -#ifndef Py_INTERNAL_INTERPRETERIDOBJECT_H -#define Py_INTERNAL_INTERPRETERIDOBJECT_H -#ifdef __cplusplus -extern "C" { +#ifndef Py_CPYTHON_INTERPRETERIDOBJECT_H +# error "this header file must not be included directly" #endif -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif +/* Interpreter ID Object */ PyAPI_DATA(PyTypeObject) _PyInterpreterID_Type; PyAPI_FUNC(PyObject *) _PyInterpreterID_New(int64_t); PyAPI_FUNC(PyObject *) _PyInterpreterState_GetIDObject(PyInterpreterState *); PyAPI_FUNC(PyInterpreterState *) _PyInterpreterID_LookUp(PyObject *); - -#ifdef __cplusplus -} -#endif -#endif // !Py_INTERNAL_INTERPRETERIDOBJECT_H diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h index c2f03254bb8760..81a707a0a5ddf3 100644 --- a/Include/internal/pycore_pymem.h +++ b/Include/internal/pycore_pymem.h @@ -95,4 +95,4 @@ PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator); #ifdef __cplusplus } #endif -#endif // !Py_INTERNAL_PYMEM_H +#endif /* !Py_INTERNAL_PYMEM_H */ diff --git a/Include/interpreteridobject.h b/Include/interpreteridobject.h new file mode 100644 index 00000000000000..8432632f339e92 --- /dev/null +++ b/Include/interpreteridobject.h @@ -0,0 +1,17 @@ +#ifndef Py_INTERPRETERIDOBJECT_H +#define Py_INTERPRETERIDOBJECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_LIMITED_API +# define Py_CPYTHON_INTERPRETERIDOBJECT_H +# include "cpython/interpreteridobject.h" +# undef Py_CPYTHON_INTERPRETERIDOBJECT_H +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERPRETERIDOBJECT_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 393eec7b8d324c..a74f4fd66d3235 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1616,6 +1616,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/floatobject.h \ $(srcdir)/Include/frameobject.h \ $(srcdir)/Include/import.h \ + $(srcdir)/Include/interpreteridobject.h \ $(srcdir)/Include/intrcheck.h \ $(srcdir)/Include/iterobject.h \ $(srcdir)/Include/listobject.h \ @@ -1686,6 +1687,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/genobject.h \ $(srcdir)/Include/cpython/import.h \ $(srcdir)/Include/cpython/initconfig.h \ + $(srcdir)/Include/cpython/interpreteridobject.h \ $(srcdir)/Include/cpython/listobject.h \ $(srcdir)/Include/cpython/longintrepr.h \ $(srcdir)/Include/cpython/longobject.h \ @@ -1754,7 +1756,6 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_import.h \ $(srcdir)/Include/internal/pycore_initconfig.h \ $(srcdir)/Include/internal/pycore_interp.h \ - $(srcdir)/Include/internal/pycore_interpreteridobject.h \ $(srcdir)/Include/internal/pycore_intrinsics.h \ $(srcdir)/Include/internal/pycore_list.h \ $(srcdir)/Include/internal/pycore_long.h \ diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 6fc31f61c144d8..4e063a86152931 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -13,6 +13,7 @@ #include "Python.h" #include "frameobject.h" +#include "interpreteridobject.h" // _PyInterpreterID_LookUp() #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_bytesobject.h" // _PyBytes_Find() @@ -24,7 +25,6 @@ #include "pycore_hashtable.h" // _Py_hashtable_new() #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() #include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy() -#include "pycore_interpreteridobject.h" // _PyInterpreterID_LookUp() #include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() #include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost() #include "pycore_pystate.h" // _PyThreadState_GET() diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c index 616dd577688116..1d7e7f1d71af3e 100644 --- a/Modules/_xxinterpchannelsmodule.c +++ b/Modules/_xxinterpchannelsmodule.c @@ -1,13 +1,9 @@ /* interpreters module */ /* low-level access to interpreter primitives */ -#ifndef Py_BUILD_CORE_BUILTIN -# define Py_BUILD_CORE_MODULE 1 -#endif #include "Python.h" -#include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_interpreteridobject.h" +#include "interpreteridobject.h" /* diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index d7daae254638ec..4801f37d6f6c5f 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1,15 +1,9 @@ /* interpreters module */ /* low-level access to interpreter primitives */ -#ifndef Py_BUILD_CORE_BUILTIN -# define Py_BUILD_CORE_MODULE 1 -#endif #include "Python.h" -// XXX This module should not rely on internal API. -#include "pycore_frame.h" -#include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_interpreteridobject.h" +#include "interpreteridobject.h" #define MODULE_NAME "_xxsubinterpreters" @@ -376,7 +370,7 @@ _is_running(PyInterpreterState *interp) } assert(!PyErr_Occurred()); - _PyInterpreterFrame *frame = tstate->cframe->current_frame; + struct _PyInterpreterFrame *frame = tstate->cframe->current_frame; if (frame == NULL) { return 0; } @@ -512,7 +506,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) } // Create and initialize the new interpreter. - PyThreadState *save_tstate = _PyThreadState_GET(); + PyThreadState *save_tstate = PyThreadState_Get(); assert(save_tstate != NULL); const PyInterpreterConfig config = isolated ? (PyInterpreterConfig)_PyInterpreterConfig_INIT diff --git a/Objects/interpreteridobject.c b/Objects/interpreteridobject.c index 7b3e31beded594..46239100dcb7b7 100644 --- a/Objects/interpreteridobject.c +++ b/Objects/interpreteridobject.c @@ -3,7 +3,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_interp.h" // _PyInterpreterState_LookUpID() -#include "pycore_interpreteridobject.h" +#include "interpreteridobject.h" typedef struct interpid { diff --git a/Objects/object.c b/Objects/object.c index 6a73c3588da798..bd0fa40bd2a851 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -17,7 +17,7 @@ #include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_initialize_generic #include "pycore_typeobject.h" // _PyBufferWrapper_Type #include "pycore_unionobject.h" // _PyUnion_Type -#include "pycore_interpreteridobject.h" // _PyInterpreterID_Type +#include "interpreteridobject.h" // _PyInterpreterID_Type #ifdef Py_LIMITED_API // Prevent recursive call _Py_IncRef() <=> Py_INCREF() diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 43716487f91bd5..b265264dc161ac 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -152,6 +152,7 @@ + @@ -234,7 +235,6 @@ - @@ -275,6 +275,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 22eb70a0f2dde4..67a32f653de1f8 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -315,6 +315,9 @@ Include + + Include + Modules @@ -459,6 +462,9 @@ Include + + Include\cpython + Include\cpython @@ -603,9 +609,6 @@ Include\internal - - Include\cpython - Include\cpython diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 2ee341f8dd137d..1587a19716fe0b 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -227,6 +227,7 @@ def clean_lines(text): Include/cpython/fileutils.h Py_CPYTHON_FILEUTILS_H 1 Include/cpython/frameobject.h Py_CPYTHON_FRAMEOBJECT_H 1 Include/cpython/import.h Py_CPYTHON_IMPORT_H 1 +Include/cpython/interpreteridobject.h Py_CPYTHON_INTERPRETERIDOBJECT_H 1 Include/cpython/listobject.h Py_CPYTHON_LISTOBJECT_H 1 Include/cpython/methodobject.h Py_CPYTHON_METHODOBJECT_H 1 Include/cpython/object.h Py_CPYTHON_OBJECT_H 1 From c580527d9230212e8f8d697a18b86120109aa653 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:09:05 -0700 Subject: [PATCH 0458/1206] [3.12] gh-105699: Disable the Interpreters Stress Tests (gh-107354) (gh-107357) gh-105699: Disable the Interpreters Stress Tests (gh-107354) The two tests are crashing periodically in CI and on buildbots. I suspect the problem is in the _xxsubinterpreters module. Regardless, I'm disabling the tests temporarily, to reduce the noise as we approach 3.12rc1. I'll be investigating the crashes separately. (cherry picked from commit 4f67921ad28194155e3d4c16255fb140a6a4d89a) Co-authored-by: Eric Snow --- Lib/test/test_interpreters.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_interpreters.py b/Lib/test/test_interpreters.py index 5981d96de8de06..662eafa3b7a104 100644 --- a/Lib/test/test_interpreters.py +++ b/Lib/test/test_interpreters.py @@ -464,6 +464,7 @@ def test_bytes_for_script(self): # test_xxsubinterpreters covers the remaining Interpreter.run() behavior. +@unittest.skip('these are crashing, likely just due just to _xxsubinterpreters (see gh-105699)') class StressTests(TestBase): # In these tests we generally want a lot of interpreters, From 5daf19d763826a977a596b6fbc035ee03c0deafc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:52:39 -0700 Subject: [PATCH 0459/1206] [3.12] gh-104432: Use `memcpy()` to avoid misaligned loads (GH-104433) (#107355) gh-104432: Use `memcpy()` to avoid misaligned loads (GH-104433) Fix potential unaligned memory access on C APIs involving returned sequences of `char *` pointers within the :mod:`grp` and :mod:`socket` modules. These were revealed using a ``-fsaniziter=alignment`` build on ARM macOS. (cherry picked from commit f01e4cedba1a17d321664834bb255d9d04ad16ce) Co-authored-by: Christopher Chavez --- ...-07-27-11-47-29.gh-issue-104432.oGHF-z.rst | 4 ++++ Modules/grpmodule.c | 10 +++++++-- Modules/socketmodule.c | 22 ++++++++++++++----- 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst new file mode 100644 index 00000000000000..e47927b4e11886 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst @@ -0,0 +1,4 @@ +Fix potential unaligned memory access on C APIs involving returned sequences +of `char *` pointers within the :mod:`grp` and :mod:`socket` modules. These +were revealed using a ``-fsaniziter=alignment`` build on ARM macOS. Patch by +Christopher Chavez. diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c index 57cdde6064c24e..f5709296334a8f 100644 --- a/Modules/grpmodule.c +++ b/Modules/grpmodule.c @@ -65,8 +65,14 @@ mkgrent(PyObject *module, struct group *p) Py_DECREF(v); return NULL; } - for (member = p->gr_mem; *member != NULL; member++) { - PyObject *x = PyUnicode_DecodeFSDefault(*member); + for (member = p->gr_mem; ; member++) { + char *group_member; + // member can be misaligned + memcpy(&group_member, member, sizeof(group_member)); + if (group_member == NULL) { + break; + } + PyObject *x = PyUnicode_DecodeFSDefault(group_member); if (x == NULL || PyList_Append(w, x) != 0) { Py_XDECREF(x); Py_DECREF(w); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index a86aaed501fa33..1ae7ab778290fe 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5783,9 +5783,15 @@ gethost_common(socket_state *state, struct hostent *h, struct sockaddr *addr, /* SF #1511317: h_aliases can be NULL */ if (h->h_aliases) { - for (pch = h->h_aliases; *pch != NULL; pch++) { + for (pch = h->h_aliases; ; pch++) { int status; - tmp = PyUnicode_FromString(*pch); + char *host_alias; + // pch can be misaligned + memcpy(&host_alias, pch, sizeof(host_alias)); + if (host_alias == NULL) { + break; + } + tmp = PyUnicode_FromString(host_alias); if (tmp == NULL) goto err; @@ -5797,8 +5803,14 @@ gethost_common(socket_state *state, struct hostent *h, struct sockaddr *addr, } } - for (pch = h->h_addr_list; *pch != NULL; pch++) { + for (pch = h->h_addr_list; ; pch++) { int status; + char *host_address; + // pch can be misaligned + memcpy(&host_address, pch, sizeof(host_address)); + if (host_address == NULL) { + break; + } switch (af) { @@ -5810,7 +5822,7 @@ gethost_common(socket_state *state, struct hostent *h, struct sockaddr *addr, #ifdef HAVE_SOCKADDR_SA_LEN sin.sin_len = sizeof(sin); #endif - memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr)); + memcpy(&sin.sin_addr, host_address, sizeof(sin.sin_addr)); tmp = make_ipv4_addr(&sin); if (pch == h->h_addr_list && alen >= sizeof(sin)) @@ -5827,7 +5839,7 @@ gethost_common(socket_state *state, struct hostent *h, struct sockaddr *addr, #ifdef HAVE_SOCKADDR_SA_LEN sin6.sin6_len = sizeof(sin6); #endif - memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr)); + memcpy(&sin6.sin6_addr, host_address, sizeof(sin6.sin6_addr)); tmp = make_ipv6_addr(&sin6); if (pch == h->h_addr_list && alen >= sizeof(sin6)) From abaf89d908304891c99c6a0450cf7e160c17cdd3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 14:51:34 -0700 Subject: [PATCH 0460/1206] [3.12] gh-104621: Check for Incompatible Extensions in import_find_extension() (gh-107184) (gh-107360) gh-104621: Check for Incompatible Extensions in import_find_extension() (gh-107184) This fixes a bug where incompatible modules could still be imported if attempted multiple times. (cherry picked from commit 75c974f5353685f338344618ad7344e64c2293d0) Co-authored-by: Eric Snow --- Lib/test/test_capi/check_config.py | 2 +- Lib/test/test_import/__init__.py | 42 ++++++++++++++++--- ...-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst | 1 + Python/import.c | 21 +++++----- 4 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst diff --git a/Lib/test/test_capi/check_config.py b/Lib/test/test_capi/check_config.py index aaedd82f39af50..eb99ae16f2b69e 100644 --- a/Lib/test/test_capi/check_config.py +++ b/Lib/test/test_capi/check_config.py @@ -12,7 +12,7 @@ def import_singlephase(): try: import _testsinglephase except ImportError: - sys.modules.pop('_testsinglephase') + sys.modules.pop('_testsinglephase', None) return False else: del sys.modules['_testsinglephase'] diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index ee9fe4d574dd42..cc6e8d4e640cd6 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -97,7 +97,6 @@ def require_frozen(module, *, skip=True): def require_pure_python(module, *, skip=False): _require_loader(module, SourceFileLoader, skip) - def remove_files(name): for f in (name + ".py", name + ".pyc", @@ -128,19 +127,34 @@ def _ready_to_import(name=None, source=""): del sys.modules[name] -def requires_subinterpreters(meth): - """Decorator to skip a test if subinterpreters are not supported.""" - return unittest.skipIf(_interpreters is None, - 'subinterpreters required')(meth) +if _testsinglephase is not None: + def restore__testsinglephase(*, _orig=_testsinglephase): + # We started with the module imported and want to restore + # it to its nominal state. + _orig._clear_globals() + _testinternalcapi.clear_extension('_testsinglephase', _orig.__file__) + import _testsinglephase def requires_singlephase_init(meth): """Decorator to skip if single-phase init modules are not supported.""" + if not isinstance(meth, type): + def meth(self, _meth=meth): + try: + return _meth(self) + finally: + restore__testsinglephase() meth = cpython_only(meth) return unittest.skipIf(_testsinglephase is None, 'test requires _testsinglephase module')(meth) +def requires_subinterpreters(meth): + """Decorator to skip a test if subinterpreters are not supported.""" + return unittest.skipIf(_interpreters is None, + 'subinterpreters required')(meth) + + class ModuleSnapshot(types.SimpleNamespace): """A representation of a module for testing. @@ -1943,6 +1957,20 @@ def test_isolated_config(self): with self.subTest(f'{module}: strict, fresh'): self.check_compatible_fresh(module, strict=True, isolated=True) + @requires_subinterpreters + @requires_singlephase_init + def test_disallowed_reimport(self): + # See https://github.com/python/cpython/issues/104621. + script = textwrap.dedent(''' + import _testsinglephase + print(_testsinglephase) + ''') + interpid = _interpreters.create() + with self.assertRaises(_interpreters.RunFailedError): + _interpreters.run_string(interpid, script) + with self.assertRaises(_interpreters.RunFailedError): + _interpreters.run_string(interpid, script) + class TestSinglePhaseSnapshot(ModuleSnapshot): @@ -2002,6 +2030,10 @@ def setUpClass(cls): # Start fresh. cls.clean_up() + @classmethod + def tearDownClass(cls): + restore__testsinglephase() + def tearDown(self): # Clean up the module. self.clean_up() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst new file mode 100644 index 00000000000000..86c976295f2620 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst @@ -0,0 +1 @@ +Unsupported modules now always fail to be imported. diff --git a/Python/import.c b/Python/import.c index d10c5ce63a2c8b..a93a6450285cc1 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1222,6 +1222,15 @@ import_find_extension(PyThreadState *tstate, PyObject *name, return NULL; } + /* It may have been successfully imported previously + in an interpreter that allows legacy modules + but is not allowed in the current interpreter. */ + const char *name_buf = PyUnicode_AsUTF8(name); + assert(name_buf != NULL); + if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { + return NULL; + } + PyObject *mod, *mdict; PyObject *modules = MODULES(tstate->interp); @@ -3712,16 +3721,8 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) PyThreadState *tstate = _PyThreadState_GET(); mod = import_find_extension(tstate, name, path); - if (mod != NULL) { - const char *name_buf = PyUnicode_AsUTF8(name); - assert(name_buf != NULL); - if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { - Py_DECREF(mod); - mod = NULL; - } - goto finally; - } - else if (PyErr_Occurred()) { + if (mod != NULL || _PyErr_Occurred(tstate)) { + assert(mod == NULL || !_PyErr_Occurred(tstate)); goto finally; } From 2827ad2f317fceaa618bbdb5900b76613af3aa69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 17:39:51 -0700 Subject: [PATCH 0461/1206] [3.12] gh-106368: Argument clinic tests: improve failure message when tests in `ClinicExternalTests` fail (GH-107364) (#107365) gh-106368: Argument clinic tests: improve failure message when tests in `ClinicExternalTests` fail (GH-107364) (cherry picked from commit 76c26eaca4147ba7e3e8d7379c5a828f0b512a46) Co-authored-by: Alex Waygood --- Lib/test/test_clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index d1c61b1d401b98..3d740910a57ae6 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1360,7 +1360,7 @@ def _do_test(self, *args, expect_success=True): ) as proc: proc.wait() if expect_success and proc.returncode: - self.fail("".join(proc.stderr)) + self.fail("".join([*proc.stdout, *proc.stderr])) stdout = proc.stdout.read() stderr = proc.stderr.read() # Clinic never writes to stderr. From 17ce87ba7f8e4f8c9a5620ebf24a968f742b6e28 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 23:17:49 -0700 Subject: [PATCH 0462/1206] [3.12] gh-107298: Fix doc references to undocumented modules (GH-107300) (GH-107370) Update also Doc/tools/.nitignore. (cherry picked from commit 87b39028e5f453a949a1675526c439f6479a04a8) Co-authored-by: Victor Stinner --- Doc/c-api/arg.rst | 2 +- Doc/c-api/codec.rst | 2 +- Doc/c-api/typeobj.rst | 2 +- Doc/c-api/unicode.rst | 2 +- Doc/extending/extending.rst | 4 ++-- Doc/extending/newtypes_tutorial.rst | 8 ++++---- Doc/install/index.rst | 2 +- Doc/tools/.nitignore | 1 - 8 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index ea176bd7d6a51b..c09c2d5261ca08 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -469,7 +469,7 @@ API Functions will be set if there was a failure. This is an example of the use of this function, taken from the sources for the - :mod:`_weakref` helper module for weak references:: + :mod:`!_weakref` helper module for weak references:: static PyObject * weakref_ref(PyObject *self, PyObject *args) diff --git a/Doc/c-api/codec.rst b/Doc/c-api/codec.rst index 235c77c945cc5b..8ae5c4fecd6248 100644 --- a/Doc/c-api/codec.rst +++ b/Doc/c-api/codec.rst @@ -7,7 +7,7 @@ Codec registry and support functions Register a new codec search function. - As side effect, this tries to load the :mod:`encodings` package, if not yet + As side effect, this tries to load the :mod:`!encodings` package, if not yet done, to make sure that it is always first in the list of search functions. .. c:function:: int PyCodec_Unregister(PyObject *search_function) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index e70b82405a4cf7..40d21050446e52 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -579,7 +579,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) name, followed by a dot, followed by the type name; for built-in types, it should be just the type name. If the module is a submodule of a package, the full package name is part of the full module name. For example, a type named - :class:`T` defined in module :mod:`M` in subpackage :mod:`Q` in package :mod:`P` + :class:`T` defined in module :mod:`!M` in subpackage :mod:`!Q` in package :mod:`!P` should have the :c:member:`~PyTypeObject.tp_name` initializer ``"P.Q.M.T"``. For :ref:`dynamically allocated type objects `, diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 957934c78595ec..6ae652e7e243c3 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1212,7 +1212,7 @@ Character Map Codecs This codec is special in that it can be used to implement many different codecs (and this is in fact what was done to obtain most of the standard codecs -included in the :mod:`encodings` package). The codec uses mappings to encode and +included in the :mod:`!encodings` package). The codec uses mappings to encode and decode characters. The mapping objects provided must support the :meth:`__getitem__` mapping interface; dictionaries and sequences work well. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 097d86e30269cc..068f6fcdcaccd1 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -367,7 +367,7 @@ Note that PyMODINIT_FUNC declares the function as ``PyObject *`` return type, declares any special linkage declarations required by the platform, and for C++ declares the function as ``extern "C"``. -When the Python program imports module :mod:`spam` for the first time, +When the Python program imports module :mod:`!spam` for the first time, :c:func:`PyInit_spam` is called. (See below for comments about embedding Python.) It calls :c:func:`PyModule_Create`, which returns a module object, and inserts built-in function objects into the newly created module based upon the @@ -1208,7 +1208,7 @@ file corresponding to the module provides a macro that takes care of importing the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API. -The exporting module is a modification of the :mod:`spam` module from section +The exporting module is a modification of the :mod:`!spam` module from section :ref:`extending-simpleexample`. The function :func:`spam.system` does not call the C library function :c:func:`system` directly, but a function :c:func:`PySpam_System`, which would of course do something more complicated in diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 82671fdc447d9c..80c8ea73e343ef 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -37,7 +37,7 @@ object. This sort of thing can only be explained by example, so here's a minimal, but complete, module that defines a new type named :class:`Custom` inside a C -extension module :mod:`custom`: +extension module :mod:`!custom`: .. note:: What we're showing here is the traditional way of defining *static* @@ -55,7 +55,7 @@ from the previous chapter. This file defines three things: #. How the :class:`Custom` **type** behaves: this is the ``CustomType`` struct, which defines a set of flags and function pointers that the interpreter inspects when specific operations are requested. -#. How to initialize the :mod:`custom` module: this is the ``PyInit_custom`` +#. How to initialize the :mod:`!custom` module: this is the ``PyInit_custom`` function and the associated ``custommodule`` struct. The first bit is:: @@ -127,7 +127,7 @@ our objects and in some error messages, for example: TypeError: can only concatenate str (not "custom.Custom") to str Note that the name is a dotted name that includes both the module name and the -name of the type within the module. The module in this case is :mod:`custom` and +name of the type within the module. The module in this case is :mod:`!custom` and the type is :class:`Custom`, so we set the type name to :class:`custom.Custom`. Using the real dotted import path is important to make your type compatible with the :mod:`pydoc` and :mod:`pickle` modules. :: @@ -231,7 +231,7 @@ Adding data and methods to the Basic example ============================================ Let's extend the basic example to add some data and methods. Let's also make -the type usable as a base class. We'll create a new module, :mod:`custom2` that +the type usable as a base class. We'll create a new module, :mod:`!custom2` that adds these capabilities: .. literalinclude:: ../includes/custom2.c diff --git a/Doc/install/index.rst b/Doc/install/index.rst index 34d47fdb6a2f0e..443c75b7684fb6 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -374,7 +374,7 @@ will expand this to your home directory:: To make Python find the distributions installed with this scheme, you may have to :ref:`modify Python's search path ` or edit -:mod:`sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit +:mod:`!sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit :data:`sys.path`. The :option:`!--home` option defines the installation base directory. Files are diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 25d0f27e18311c..6a165d626e0873 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -12,7 +12,6 @@ Doc/c-api/bytes.rst Doc/c-api/capsule.rst Doc/c-api/cell.rst Doc/c-api/code.rst -Doc/c-api/codec.rst Doc/c-api/complex.rst Doc/c-api/conversion.rst Doc/c-api/datetime.rst From 4f72a9a2e0b5b44a1a590b112cec2533ca182dff Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 27 Jul 2023 23:24:29 -0700 Subject: [PATCH 0463/1206] [3.12] gh-106723: forward -Xfrozen_modules option to spawned process interpreters (GH-106724) (#107367) gh-106723: forward -Xfrozen_modules option to spawned process interpreters (GH-106724) (cherry picked from commit 3dcac785810df4d9db50abe90847eaf03bbdaaf4) Co-authored-by: Felipe A. Hernandez Co-authored-by: Kumar Aditya Co-authored-by: Gregory P. Smith --- Lib/subprocess.py | 2 +- .../2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst diff --git a/Lib/subprocess.py b/Lib/subprocess.py index fbc76b8d0f14b2..6df5dd551ea67e 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -346,7 +346,7 @@ def _args_from_interpreter_flags(): if dev_mode: args.extend(('-X', 'dev')) for opt in ('faulthandler', 'tracemalloc', 'importtime', - 'showrefcount', 'utf8'): + 'frozen_modules', 'showrefcount', 'utf8'): if opt in xoptions: value = xoptions[opt] if value is True: diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst new file mode 100644 index 00000000000000..207f397f17d3f3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst @@ -0,0 +1 @@ +Propagate ``frozen_modules`` to multiprocessing spawned process interpreters. From ef7422a1b98a9c84db5d2d4e16eafe01f8b4680a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 28 Jul 2023 09:40:16 +0300 Subject: [PATCH 0464/1206] [3.12] gh-107298: Fix Sphinx warnings in the C API doc (GH-107302) (GH-107375) (cherry picked from commit 391e03fa05b80d17a14ac88d30c974fa2fa00adb) Co-authored-by: Victor Stinner --- Doc/c-api/apiabiversion.rst | 2 +- Doc/c-api/buffer.rst | 2 +- Doc/c-api/bytes.rst | 24 ++++++++++++------------ Doc/c-api/cell.rst | 2 +- Doc/c-api/code.rst | 6 +++--- Doc/c-api/gcsupport.rst | 2 +- Doc/c-api/iterator.rst | 4 ++-- Doc/c-api/type.rst | 2 +- Doc/c-api/typehints.rst | 2 +- Doc/c-api/unicode.rst | 4 ++-- Doc/c-api/weakref.rst | 8 ++++---- Doc/tools/.nitignore | 8 -------- 12 files changed, 29 insertions(+), 37 deletions(-) diff --git a/Doc/c-api/apiabiversion.rst b/Doc/c-api/apiabiversion.rst index 62d542966622ce..f6c8284daeacb0 100644 --- a/Doc/c-api/apiabiversion.rst +++ b/Doc/c-api/apiabiversion.rst @@ -60,7 +60,7 @@ See :ref:`stable` for a discussion of API and ABI stability across versions. Use this for numeric comparisons, e.g. ``#if PY_VERSION_HEX >= ...``. - This version is also available via the symbol :data:`Py_Version`. + This version is also available via the symbol :c:var:`Py_Version`. .. c:var:: const unsigned long Py_Version diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 6e5443f0d6cdc5..02b53ec149c733 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -44,7 +44,7 @@ the elements exposed by an :class:`array.array` can be multi-byte values. An example consumer of the buffer interface is the :meth:`~io.BufferedIOBase.write` method of file objects: any object that can export a series of bytes through -the buffer interface can be written to a file. While :meth:`write` only +the buffer interface can be written to a file. While :meth:`!write` only needs read-only access to the internal contents of the object passed to it, other methods such as :meth:`~io.BufferedIOBase.readinto` need write access to the contents of their argument. The buffer interface allows objects to diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index 9f48f2ffafe170..4e3ffc7e23e3f8 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -64,39 +64,39 @@ called with a non-bytes parameter. +-------------------+---------------+--------------------------------+ | Format Characters | Type | Comment | +===================+===============+================================+ - | :attr:`%%` | *n/a* | The literal % character. | + | ``%%`` | *n/a* | The literal % character. | +-------------------+---------------+--------------------------------+ - | :attr:`%c` | int | A single byte, | + | ``%c`` | int | A single byte, | | | | represented as a C int. | +-------------------+---------------+--------------------------------+ - | :attr:`%d` | int | Equivalent to | + | ``%d`` | int | Equivalent to | | | | ``printf("%d")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%u` | unsigned int | Equivalent to | + | ``%u`` | unsigned int | Equivalent to | | | | ``printf("%u")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%ld` | long | Equivalent to | + | ``%ld`` | long | Equivalent to | | | | ``printf("%ld")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%lu` | unsigned long | Equivalent to | + | ``%lu`` | unsigned long | Equivalent to | | | | ``printf("%lu")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%zd` | :c:type:`\ | Equivalent to | + | ``%zd`` | :c:type:`\ | Equivalent to | | | Py_ssize_t` | ``printf("%zd")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%zu` | size_t | Equivalent to | + | ``%zu`` | size_t | Equivalent to | | | | ``printf("%zu")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%i` | int | Equivalent to | + | ``%i`` | int | Equivalent to | | | | ``printf("%i")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%x` | int | Equivalent to | + | ``%x`` | int | Equivalent to | | | | ``printf("%x")``. [1]_ | +-------------------+---------------+--------------------------------+ - | :attr:`%s` | const char\* | A null-terminated C character | + | ``%s`` | const char\* | A null-terminated C character | | | | array. | +-------------------+---------------+--------------------------------+ - | :attr:`%p` | const void\* | The hex representation of a C | + | ``%p`` | const void\* | The hex representation of a C | | | | pointer. Mostly equivalent to | | | | ``printf("%p")`` except that | | | | it is guaranteed to start with | diff --git a/Doc/c-api/cell.rst b/Doc/c-api/cell.rst index ac4ef5adc5cc20..f8cd0344fdd1c0 100644 --- a/Doc/c-api/cell.rst +++ b/Doc/c-api/cell.rst @@ -25,7 +25,7 @@ Cell objects are not likely to be useful elsewhere. The type object corresponding to cell objects. -.. c:function:: int PyCell_Check(ob) +.. c:function:: int PyCell_Check(PyObject *ob) Return true if *ob* is a cell object; *ob* must not be ``NULL``. This function always succeeds. diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index a99de9904c0740..89fe42d1ff05f1 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -39,7 +39,7 @@ bound into a function. use :c:func:`PyCode_NewEmpty` instead. Since the definition of the bytecode changes often, calling - :c:func:`PyCode_New` directly can bind you to a precise Python version. + :c:func:`PyUnstable_Code_New` directly can bind you to a precise Python version. The many arguments of this function are inter-dependent in complex ways, meaning that subtle changes to values are likely to result in incorrect @@ -58,8 +58,8 @@ bound into a function. .. c:function:: PyCodeObject* PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *linetable, PyObject *exceptiontable) - Similar to :c:func:`PyCode_New`, but with an extra "posonlyargcount" for positional-only arguments. - The same caveats that apply to ``PyCode_New`` also apply to this function. + Similar to :c:func:`PyUnstable_Code_New`, but with an extra "posonlyargcount" for positional-only arguments. + The same caveats that apply to ``PyUnstable_Code_New`` also apply to this function. .. index:: single: PyCode_NewWithPosOnlyArgs diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index e56414ab9f754d..88709879d01634 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -143,7 +143,7 @@ rules: .. versionchanged:: 3.8 - The :c:func:`_PyObject_GC_TRACK` and :c:func:`_PyObject_GC_UNTRACK` macros + The :c:func:`!_PyObject_GC_TRACK` and :c:func:`!_PyObject_GC_UNTRACK` macros have been removed from the public C API. The :c:member:`~PyTypeObject.tp_traverse` handler accepts a function parameter of this type: diff --git a/Doc/c-api/iterator.rst b/Doc/c-api/iterator.rst index 95952237ca746f..6b7ba8c9979163 100644 --- a/Doc/c-api/iterator.rst +++ b/Doc/c-api/iterator.rst @@ -19,7 +19,7 @@ sentinel value is returned. types. -.. c:function:: int PySeqIter_Check(op) +.. c:function:: int PySeqIter_Check(PyObject *op) Return true if the type of *op* is :c:data:`PySeqIter_Type`. This function always succeeds. @@ -38,7 +38,7 @@ sentinel value is returned. two-argument form of the :func:`iter` built-in function. -.. c:function:: int PyCallIter_Check(op) +.. c:function:: int PyCallIter_Check(PyObject *op) Return true if the type of *op* is :c:data:`PyCallIter_Type`. This function always succeeds. diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 553d86aa3d9975..e7b35c43da32af 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -480,7 +480,7 @@ The following functions and structs are used to create Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be problematic on some platforms. To avoid issues, use the *bases* argument of - :py:func:`PyType_FromSpecWithBases` instead. + :c:func:`PyType_FromSpecWithBases` instead. .. versionchanged:: 3.9 diff --git a/Doc/c-api/typehints.rst b/Doc/c-api/typehints.rst index 4c1957a2a1dbca..98fe68737deb81 100644 --- a/Doc/c-api/typehints.rst +++ b/Doc/c-api/typehints.rst @@ -35,7 +35,7 @@ two types exist -- :ref:`GenericAlias ` and ... } - .. seealso:: The data model method :meth:`__class_getitem__`. + .. seealso:: The data model method :meth:`~object.__class_getitem__`. .. versionadded:: 3.9 diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 6ae652e7e243c3..fb4cfc64c8d00e 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1214,7 +1214,7 @@ This codec is special in that it can be used to implement many different codecs (and this is in fact what was done to obtain most of the standard codecs included in the :mod:`!encodings` package). The codec uses mappings to encode and decode characters. The mapping objects provided must support the -:meth:`__getitem__` mapping interface; dictionaries and sequences work well. +:meth:`~object.__getitem__` mapping interface; dictionaries and sequences work well. These are the mapping codec APIs: @@ -1257,7 +1257,7 @@ The following codec API is special in that maps Unicode to Unicode. The mapping table must map Unicode ordinal integers to Unicode ordinal integers or ``None`` (causing deletion of the character). - Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries + Mapping tables need only provide the :meth:`~object.__getitem__` interface; dictionaries and sequences work well. Unmapped character ordinals (ones which cause a :exc:`LookupError`) are left untouched and are copied as-is. diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index f27ec4411b4a26..f46507608606b9 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -11,18 +11,18 @@ simple reference object, and the second acts as a proxy for the original object as much as it can. -.. c:function:: int PyWeakref_Check(ob) +.. c:function:: int PyWeakref_Check(PyObject *ob) Return true if *ob* is either a reference or proxy object. This function always succeeds. -.. c:function:: int PyWeakref_CheckRef(ob) +.. c:function:: int PyWeakref_CheckRef(PyObject *ob) Return true if *ob* is a reference object. This function always succeeds. -.. c:function:: int PyWeakref_CheckProxy(ob) +.. c:function:: int PyWeakref_CheckProxy(PyObject *ob) Return true if *ob* is a proxy object. This function always succeeds. @@ -54,7 +54,7 @@ as much as it can. .. c:function:: PyObject* PyWeakref_GetObject(PyObject *ref) Return the referenced object from a weak reference, *ref*. If the referent is - no longer live, returns :const:`Py_None`. + no longer live, returns ``Py_None``. .. note:: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 6a165d626e0873..b02f6eaea13250 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -4,14 +4,10 @@ # to help avoid merge conflicts. Doc/c-api/allocation.rst -Doc/c-api/apiabiversion.rst Doc/c-api/arg.rst Doc/c-api/bool.rst Doc/c-api/buffer.rst -Doc/c-api/bytes.rst Doc/c-api/capsule.rst -Doc/c-api/cell.rst -Doc/c-api/code.rst Doc/c-api/complex.rst Doc/c-api/conversion.rst Doc/c-api/datetime.rst @@ -25,7 +21,6 @@ Doc/c-api/import.rst Doc/c-api/init.rst Doc/c-api/init_config.rst Doc/c-api/intro.rst -Doc/c-api/iterator.rst Doc/c-api/memory.rst Doc/c-api/memoryview.rst Doc/c-api/module.rst @@ -36,11 +31,8 @@ Doc/c-api/stable.rst Doc/c-api/structures.rst Doc/c-api/sys.rst Doc/c-api/type.rst -Doc/c-api/typehints.rst Doc/c-api/typeobj.rst Doc/c-api/unicode.rst -Doc/c-api/veryhigh.rst -Doc/c-api/weakref.rst Doc/extending/embedding.rst Doc/extending/extending.rst Doc/extending/newtypes.rst From e6a4b10820768f7a3ca9b919a8d8961bc92c6af4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 28 Jul 2023 09:56:52 +0300 Subject: [PATCH 0465/1206] [3.12] gh-107298: Fix more Sphinx warnings in the C API doc (GH-107329) (GH-107376) Declare the following functions as macros, since they are actually macros. It avoids a warning on "TYPE" or "macro" argument. * PyMem_New() * PyMem_Resize() * PyModule_AddIntMacro() * PyModule_AddStringMacro() * PyObject_GC_New() * PyObject_GC_NewVar() * PyObject_New() * PyObject_NewVar() Add C standard C types to nitpick_ignore in Doc/conf.py: * int64_t * uint64_t * uintptr_t No longer ignore non existing "__int" type in nitpick_ignore. Update Doc/tools/.nitignore. (cherry picked from commit 8d61a71f9c81619e34d4a30b625922ebc83c561b) Co-authored-by: Victor Stinner --- Doc/c-api/allocation.rst | 19 +++++---- Doc/c-api/capsule.rst | 2 +- Doc/c-api/complex.rst | 4 +- Doc/c-api/conversion.rst | 4 +- Doc/c-api/exceptions.rst | 18 ++++----- Doc/c-api/gcsupport.rst | 20 +++++----- Doc/c-api/import.rst | 6 +-- Doc/c-api/init.rst | 20 +++++----- Doc/c-api/init_config.rst | 4 +- Doc/c-api/memory.rst | 16 ++++---- Doc/c-api/module.rst | 8 ++-- Doc/c-api/set.rst | 2 +- Doc/c-api/structures.rst | 2 +- Doc/c-api/sys.rst | 2 +- Doc/c-api/typeobj.rst | 10 ++--- Doc/c-api/unicode.rst | 6 +-- Doc/conf.py | 5 ++- Doc/extending/extending.rst | 20 +++++----- Doc/extending/newtypes_tutorial.rst | 60 ++++++++++++++--------------- Doc/tools/.nitignore | 3 -- Doc/whatsnew/2.3.rst | 2 +- Doc/whatsnew/3.8.rst | 4 +- Doc/whatsnew/3.9.rst | 4 +- 23 files changed, 122 insertions(+), 119 deletions(-) diff --git a/Doc/c-api/allocation.rst b/Doc/c-api/allocation.rst index 0a8fcc5ae5fcdf..44747e29643661 100644 --- a/Doc/c-api/allocation.rst +++ b/Doc/c-api/allocation.rst @@ -27,22 +27,25 @@ Allocating Objects on the Heap length information for a variable-size object. -.. c:function:: TYPE* PyObject_New(TYPE, PyTypeObject *type) +.. c:macro:: PyObject_New(TYPE, typeobj) Allocate a new Python object using the C structure type *TYPE* and the - Python type object *type*. Fields not defined by the Python object header + Python type object *typeobj* (``PyTypeObject*``). + Fields not defined by the Python object header are not initialized; the object's reference count will be one. The size of the memory allocation is determined from the :c:member:`~PyTypeObject.tp_basicsize` field of the type object. -.. c:function:: TYPE* PyObject_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size) +.. c:macro:: PyObject_NewVar(TYPE, typeobj, size) Allocate a new Python object using the C structure type *TYPE* and the - Python type object *type*. Fields not defined by the Python object header + Python type object *typeobj* (``PyTypeObject*``). + Fields not defined by the Python object header are not initialized. The allocated memory allows for the *TYPE* structure - plus *size* fields of the size given by the :c:member:`~PyTypeObject.tp_itemsize` field of - *type*. This is useful for implementing objects like tuples, which are + plus *size* (``Py_ssize_t``) fields of the size + given by the :c:member:`~PyTypeObject.tp_itemsize` field of + *typeobj*. This is useful for implementing objects like tuples, which are able to determine their size at construction time. Embedding the array of fields into the same allocation decreases the number of allocations, improving the memory management efficiency. @@ -50,8 +53,8 @@ Allocating Objects on the Heap .. c:function:: void PyObject_Del(void *op) - Releases memory allocated to an object using :c:func:`PyObject_New` or - :c:func:`PyObject_NewVar`. This is normally called from the + Releases memory allocated to an object using :c:macro:`PyObject_New` or + :c:macro:`PyObject_NewVar`. This is normally called from the :c:member:`~PyTypeObject.tp_dealloc` handler specified in the object's type. The fields of the object should not be accessed after this call as the memory is no longer a valid Python object. diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 427ed959c58568..2a1b602dc79c0f 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -64,7 +64,7 @@ Refer to :ref:`using-capsules` for more information on using these objects. The *name* parameter must compare exactly to the name stored in the capsule. If the name stored in the capsule is ``NULL``, the *name* passed in must also - be ``NULL``. Python uses the C function :c:func:`strcmp` to compare capsule + be ``NULL``. Python uses the C function :c:func:`!strcmp` to compare capsule names. diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index 6679ce76f1dc6f..e3fd001c599c80 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -64,7 +64,7 @@ pointers. This is consistent throughout the API. representation. If *divisor* is null, this method returns zero and sets - :c:data:`errno` to :c:macro:`EDOM`. + :c:data:`errno` to :c:macro:`!EDOM`. .. c:function:: Py_complex _Py_c_pow(Py_complex num, Py_complex exp) @@ -73,7 +73,7 @@ pointers. This is consistent throughout the API. representation. If *num* is null and *exp* is not a positive real number, - this method returns zero and sets :c:data:`errno` to :c:macro:`EDOM`. + this method returns zero and sets :c:data:`errno` to :c:macro:`!EDOM`. Complex Numbers as Python Objects diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index fdb321fe7ab3f2..c5350123dfdfdc 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -119,10 +119,10 @@ The following functions provide locale-independent string to number conversions. .. c:function:: int PyOS_stricmp(const char *s1, const char *s2) Case insensitive comparison of strings. The function works almost - identically to :c:func:`strcmp` except that it ignores the case. + identically to :c:func:`!strcmp` except that it ignores the case. .. c:function:: int PyOS_strnicmp(const char *s1, const char *s2, Py_ssize_t size) Case insensitive comparison of strings. The function works almost - identically to :c:func:`strncmp` except that it ignores the case. + identically to :c:func:`!strncmp` except that it ignores the case. diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 4d81b273638b14..a2126ffc559aba 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -83,7 +83,7 @@ Printing and clearing This utility function prints a warning message to ``sys.stderr`` when an exception has been set but it is impossible for the interpreter to actually raise the exception. It is used, for example, when an exception occurs in an - :meth:`__del__` method. + :meth:`~object.__del__` method. The function is called with a single argument *obj* that identifies the context in which the unraisable exception occurred. If possible, @@ -165,7 +165,7 @@ For convenience, some of these functions will always return a tuple object whose first item is the integer :c:data:`errno` value and whose second item is the corresponding error message (gotten from :c:func:`!strerror`), and then calls ``PyErr_SetObject(type, object)``. On Unix, when the - :c:data:`errno` value is :c:macro:`EINTR`, indicating an interrupted system call, + :c:data:`errno` value is :c:macro:`!EINTR`, indicating an interrupted system call, this calls :c:func:`PyErr_CheckSignals`, and if that set the error indicator, leaves it set to that. The function always returns ``NULL``, so a wrapper function around a system call can write ``return PyErr_SetFromErrno(type);`` @@ -177,7 +177,7 @@ For convenience, some of these functions will always return a Similar to :c:func:`PyErr_SetFromErrno`, with the additional behavior that if *filenameObject* is not ``NULL``, it is passed to the constructor of *type* as a third parameter. In the case of :exc:`OSError` exception, - this is used to define the :attr:`filename` attribute of the + this is used to define the :attr:`!filename` attribute of the exception instance. @@ -200,12 +200,12 @@ For convenience, some of these functions will always return a .. c:function:: PyObject* PyErr_SetFromWindowsErr(int ierr) This is a convenience function to raise :exc:`WindowsError`. If called with - *ierr* of ``0``, the error code returned by a call to :c:func:`GetLastError` - is used instead. It calls the Win32 function :c:func:`FormatMessage` to retrieve - the Windows description of error code given by *ierr* or :c:func:`GetLastError`, + *ierr* of ``0``, the error code returned by a call to :c:func:`!GetLastError` + is used instead. It calls the Win32 function :c:func:`!FormatMessage` to retrieve + the Windows description of error code given by *ierr* or :c:func:`!GetLastError`, then it constructs a tuple object whose first item is the *ierr* value and whose second item is the corresponding error message (gotten from - :c:func:`FormatMessage`), and then calls ``PyErr_SetObject(PyExc_WindowsError, + :c:func:`!FormatMessage`), and then calls ``PyErr_SetObject(PyExc_WindowsError, object)``. This function always returns ``NULL``. .. availability:: Windows. @@ -631,7 +631,7 @@ Signal Handling be interruptible by user requests (such as by pressing Ctrl-C). .. note:: - The default Python signal handler for :c:macro:`SIGINT` raises the + The default Python signal handler for :c:macro:`!SIGINT` raises the :exc:`KeyboardInterrupt` exception. @@ -642,7 +642,7 @@ Signal Handling single: SIGINT single: KeyboardInterrupt (built-in exception) - Simulate the effect of a :c:macro:`SIGINT` signal arriving. + Simulate the effect of a :c:macro:`!SIGINT` signal arriving. This is equivalent to ``PyErr_SetInterruptEx(SIGINT)``. .. note:: diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 88709879d01634..6b2494ee4f0ed4 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -25,8 +25,8 @@ include the :c:macro:`Py_TPFLAGS_HAVE_GC` and provide an implementation of the Constructors for container types must conform to two rules: -#. The memory for the object must be allocated using :c:func:`PyObject_GC_New` - or :c:func:`PyObject_GC_NewVar`. +#. The memory for the object must be allocated using :c:macro:`PyObject_GC_New` + or :c:macro:`PyObject_GC_NewVar`. #. Once all the fields which may contain references to other containers are initialized, it must call :c:func:`PyObject_GC_Track`. @@ -52,19 +52,19 @@ rules: class that implements the garbage collector protocol and the child class does *not* include the :c:macro:`Py_TPFLAGS_HAVE_GC` flag. -.. c:function:: TYPE* PyObject_GC_New(TYPE, PyTypeObject *type) +.. c:macro:: PyObject_GC_New(TYPE, typeobj) - Analogous to :c:func:`PyObject_New` but for container objects with the + Analogous to :c:macro:`PyObject_New` but for container objects with the :c:macro:`Py_TPFLAGS_HAVE_GC` flag set. -.. c:function:: TYPE* PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size) +.. c:macro:: PyObject_GC_NewVar(TYPE, typeobj, size) - Analogous to :c:func:`PyObject_NewVar` but for container objects with the + Analogous to :c:macro:`PyObject_NewVar` but for container objects with the :c:macro:`Py_TPFLAGS_HAVE_GC` flag set. .. c:function:: PyObject* PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size) - Analogous to :c:func:`PyObject_GC_New` but allocates *extra_size* + Analogous to :c:macro:`PyObject_GC_New` but allocates *extra_size* bytes at the end of the object (at offset :c:member:`~PyTypeObject.tp_basicsize`). The allocated memory is initialized to zeros, @@ -85,7 +85,7 @@ rules: .. c:function:: TYPE* PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize) - Resize an object allocated by :c:func:`PyObject_NewVar`. Returns the + Resize an object allocated by :c:macro:`PyObject_NewVar`. Returns the resized object or ``NULL`` on failure. *op* must not be tracked by the collector yet. @@ -128,8 +128,8 @@ rules: .. c:function:: void PyObject_GC_Del(void *op) - Releases memory allocated to an object using :c:func:`PyObject_GC_New` or - :c:func:`PyObject_GC_NewVar`. + Releases memory allocated to an object using :c:macro:`PyObject_GC_New` or + :c:macro:`PyObject_GC_NewVar`. .. c:function:: void PyObject_GC_UnTrack(void *op) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 57f94a7f97671d..7bc93a81e2c780 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -135,10 +135,10 @@ Importing Modules The module's :attr:`__spec__` and :attr:`__loader__` will be set, if not set already, with the appropriate values. The spec's loader will be set to the module's ``__loader__`` (if set) and to an instance of - :class:`SourceFileLoader` otherwise. + :class:`~importlib.machinery.SourceFileLoader` otherwise. The module's :attr:`__file__` attribute will be set to the code object's - :attr:`co_filename`. If applicable, :attr:`__cached__` will also + :attr:`!co_filename`. If applicable, :attr:`__cached__` will also be set. This function will reload the module if it was already imported. See @@ -225,7 +225,7 @@ Importing Modules .. c:function:: PyObject* PyImport_GetImporter(PyObject *path) - Return a finder object for a :data:`sys.path`/:attr:`pkg.__path__` item + Return a finder object for a :data:`sys.path`/:attr:`!pkg.__path__` item *path*, possibly by fetching it from the :data:`sys.path_importer_cache` dict. If it wasn't yet cached, traverse :data:`sys.path_hooks` until a hook is found that can handle the path item. Return ``None`` if no hook could; diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 4144f16f23bff6..8a2543affc4d10 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -25,7 +25,7 @@ The following functions can be safely called before Python is initialized: * :c:func:`PyImport_AppendInittab` * :c:func:`PyImport_ExtendInittab` - * :c:func:`PyInitFrozenExtensions` + * :c:func:`!PyInitFrozenExtensions` * :c:func:`PyMem_SetAllocator` * :c:func:`PyMem_SetupDebugHooks` * :c:func:`PyObject_SetArenaAllocator` @@ -157,7 +157,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. :c:member:`PyConfig.use_environment` should be used instead, see :ref:`Python Initialization Configuration `. - Ignore all :envvar:`PYTHON*` environment variables, e.g. + Ignore all :envvar:`!PYTHON*` environment variables, e.g. :envvar:`PYTHONPATH` and :envvar:`PYTHONHOME`, that might be set. Set by the :option:`-E` and :option:`-I` options. @@ -230,7 +230,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. :ref:`Python Initialization Configuration `. If the flag is non-zero, use :class:`io.FileIO` instead of - :class:`WindowsConsoleIO` for :mod:`sys` standard streams. + :class:`!io._WindowsConsoleIO` for :mod:`sys` standard streams. Set to ``1`` if the :envvar:`PYTHONLEGACYWINDOWSSTDIO` environment variable is set to a non-empty string. @@ -401,7 +401,7 @@ Initializing and finalizing the interpreter the application. **Bugs and caveats:** The destruction of modules and objects in modules is done - in random order; this may cause destructors (:meth:`__del__` methods) to fail + in random order; this may cause destructors (:meth:`~object.__del__` methods) to fail when they depend on other objects (even functions) or modules. Dynamically loaded extension modules loaded by Python are not unloaded. Small amounts of memory allocated by the Python interpreter may not be freed (if you find a leak, @@ -485,12 +485,12 @@ Process-wide parameters interpreter will change the contents of this storage. Use :c:func:`Py_DecodeLocale` to decode a bytes string to get a - :c:expr:`wchar_*` string. + :c:expr:`wchar_t *` string. .. deprecated:: 3.11 -.. c:function:: wchar* Py_GetProgramName() +.. c:function:: wchar_t* Py_GetProgramName() .. index:: single: Py_SetProgramName() @@ -981,7 +981,7 @@ the fork, and releasing them afterwards. In addition, it resets any :ref:`lock-objects` in the child. When extending or embedding Python, there is no way to inform Python of additional (non-Python) locks that need to be acquired before or reset after a fork. OS facilities such as -:c:func:`pthread_atfork` would need to be used to accomplish the same thing. +:c:func:`!pthread_atfork` would need to be used to accomplish the same thing. Additionally, when extending or embedding Python, calling :c:func:`fork` directly rather than through :func:`os.fork` (and returning to or calling into Python) may result in a deadlock by one of Python's internal locks @@ -1087,7 +1087,7 @@ code, or when embedding the Python interpreter: .. note:: Calling this function from a thread when the runtime is finalizing will terminate the thread, even if the thread was not created by Python. - You can use :c:func:`_Py_IsFinalizing` or :func:`sys.is_finalizing` to + You can use :c:func:`!_Py_IsFinalizing` or :func:`sys.is_finalizing` to check if the interpreter is in process of being finalized before calling this function to avoid unwanted termination. @@ -1133,7 +1133,7 @@ with sub-interpreters: .. note:: Calling this function from a thread when the runtime is finalizing will terminate the thread, even if the thread was not created by Python. - You can use :c:func:`_Py_IsFinalizing` or :func:`sys.is_finalizing` to + You can use :c:func:`!_Py_IsFinalizing` or :func:`sys.is_finalizing` to check if the interpreter is in process of being finalized before calling this function to avoid unwanted termination. @@ -1415,7 +1415,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. note:: Calling this function from a thread when the runtime is finalizing will terminate the thread, even if the thread was not created by Python. - You can use :c:func:`_Py_IsFinalizing` or :func:`sys.is_finalizing` to + You can use :c:func:`!_Py_IsFinalizing` or :func:`sys.is_finalizing` to check if the interpreter is in process of being finalized before calling this function to avoid unwanted termination. diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 18f17e2059b102..cf7337f679e69f 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -871,7 +871,7 @@ PyConfig .. c:member:: int legacy_windows_stdio If non-zero, use :class:`io.FileIO` instead of - :class:`io.WindowsConsoleIO` for :data:`sys.stdin`, :data:`sys.stdout` + :class:`!io._WindowsConsoleIO` for :data:`sys.stdin`, :data:`sys.stdout` and :data:`sys.stderr`. Set to ``1`` if the :envvar:`PYTHONLEGACYWINDOWSSTDIO` environment @@ -1120,7 +1120,7 @@ PyConfig Set to ``0`` by the :option:`-S` command line option. - :data:`sys.flags.no_site` is set to the inverted value of + :data:`sys.flags.no_site ` is set to the inverted value of :c:member:`~PyConfig.site_import`. Default: ``1``. diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 4ca3b8804427f8..c51aba3f555367 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -136,7 +136,7 @@ need to be held. The :ref:`default raw memory allocator ` uses the following functions: :c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc` -and :c:func:`free`; call ``malloc(1)`` (or ``calloc(1, 1)``) when requesting +and :c:func:`!free`; call ``malloc(1)`` (or ``calloc(1, 1)``) when requesting zero bytes. .. versionadded:: 3.4 @@ -264,14 +264,14 @@ The following type-oriented macros are provided for convenience. Note that *TYPE* refers to any C type. -.. c:function:: TYPE* PyMem_New(TYPE, size_t n) +.. c:macro:: PyMem_New(TYPE, n) Same as :c:func:`PyMem_Malloc`, but allocates ``(n * sizeof(TYPE))`` bytes of memory. Returns a pointer cast to :c:expr:`TYPE*`. The memory will not have been initialized in any way. -.. c:function:: TYPE* PyMem_Resize(void *p, TYPE, size_t n) +.. c:macro:: PyMem_Resize(p, TYPE, n) Same as :c:func:`PyMem_Realloc`, but the memory block is resized to ``(n * sizeof(TYPE))`` bytes. Returns a pointer cast to :c:expr:`TYPE*`. On return, @@ -423,7 +423,7 @@ Customize Memory Allocators +----------------------------------------------------------+---------------------------------------+ .. versionchanged:: 3.5 - The :c:type:`PyMemAllocator` structure was renamed to + The :c:type:`!PyMemAllocator` structure was renamed to :c:type:`PyMemAllocatorEx` and a new ``calloc`` field was added. @@ -627,8 +627,8 @@ with a fixed size of 256 KiB. It falls back to :c:func:`PyMem_RawMalloc` and The arena allocator uses the following functions: -* :c:func:`VirtualAlloc` and :c:func:`VirtualFree` on Windows, -* :c:func:`mmap` and :c:func:`munmap` if available, +* :c:func:`!VirtualAlloc` and :c:func:`!VirtualFree` on Windows, +* :c:func:`!mmap` and :c:func:`!munmap` if available, * :c:func:`malloc` and :c:func:`free` otherwise. This allocator is disabled if Python is configured with the @@ -732,8 +732,8 @@ allocators operating on different heaps. :: free(buf1); /* Fatal -- should be PyMem_Del() */ In addition to the functions aimed at handling raw memory blocks from the Python -heap, objects in Python are allocated and released with :c:func:`PyObject_New`, -:c:func:`PyObject_NewVar` and :c:func:`PyObject_Del`. +heap, objects in Python are allocated and released with :c:macro:`PyObject_New`, +:c:macro:`PyObject_NewVar` and :c:func:`PyObject_Del`. These will be explained in the next chapter on defining and implementing new object types in C. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 6abd550ab80b21..fc4dd4ce053e68 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -282,7 +282,7 @@ An alternate way to specify extensions is to request "multi-phase initialization Extension modules created this way behave more like Python modules: the initialization is split between the *creation phase*, when the module object is created, and the *execution phase*, when it is populated. -The distinction is similar to the :py:meth:`__new__` and :py:meth:`__init__` methods +The distinction is similar to the :py:meth:`!__new__` and :py:meth:`!__init__` methods of classes. Unlike modules created using single-phase initialization, these modules are not @@ -293,7 +293,7 @@ By default, multiple modules created from the same definition should be independent: changes to one should not affect the others. This means that all state should be specific to the module object (using e.g. using :c:func:`PyModule_GetState`), or its contents (such as the module's -:attr:`__dict__` or individual classes created with :c:func:`PyType_FromSpec`). +:attr:`~object.__dict__` or individual classes created with :c:func:`PyType_FromSpec`). All modules created using multi-phase initialization are expected to support :ref:`sub-interpreters `. Making sure multiple modules @@ -555,7 +555,7 @@ state: ``NULL``-terminated. Return ``-1`` on error, ``0`` on success. -.. c:function:: int PyModule_AddIntMacro(PyObject *module, macro) +.. c:macro:: PyModule_AddIntMacro(module, macro) Add an int constant to *module*. The name and the value are taken from *macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int @@ -563,7 +563,7 @@ state: Return ``-1`` on error, ``0`` on success. -.. c:function:: int PyModule_AddStringMacro(PyObject *module, macro) +.. c:macro:: PyModule_AddStringMacro(module, macro) Add a string constant to *module*. diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index d642a5f1902e2e..7e0ebd2f791a4d 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -122,7 +122,7 @@ or :class:`frozenset` or instances of their subtypes. .. c:function:: int PySet_Contains(PyObject *anyset, PyObject *key) Return ``1`` if found, ``0`` if not found, and ``-1`` if an error is encountered. Unlike - the Python :meth:`__contains__` method, this function does not automatically + the Python :meth:`~object.__contains__` method, this function does not automatically convert unhashable sets into temporary frozensets. Raise a :exc:`TypeError` if the *key* is unhashable. Raise :exc:`PyExc_SystemError` if *anyset* is not a :class:`set`, :class:`frozenset`, or an instance of a subtype. diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 55f3410728bc3e..747cfa62294c21 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -393,7 +393,7 @@ definition with the same method name. *METH_COEXIST*, the default is to skip repeated definitions. Since slot wrappers are loaded before the method table, the existence of a *sq_contains* slot, for example, would generate a wrapped method named - :meth:`__contains__` and preclude the loading of a corresponding + :meth:`~object.__contains__` and preclude the loading of a corresponding PyCFunction with the same name. With the flag defined, the PyCFunction will be loaded in place of the wrapper object and will co-exist with the slot. This is helpful because calls to PyCFunctions are optimized more diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 7e0e982a04ec3e..2c45ea1427a119 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -414,7 +414,7 @@ Process Control This function should only be invoked when a condition is detected that would make it dangerous to continue using the Python interpreter; e.g., when the object administration appears to be corrupted. On Unix, the standard C library - function :c:func:`abort` is called which will attempt to produce a :file:`core` + function :c:func:`!abort` is called which will attempt to produce a :file:`core` file. The ``Py_FatalError()`` function is replaced with a macro which logs diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 40d21050446e52..99b025dc41fc2e 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -579,7 +579,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) name, followed by a dot, followed by the type name; for built-in types, it should be just the type name. If the module is a submodule of a package, the full package name is part of the full module name. For example, a type named - :class:`T` defined in module :mod:`!M` in subpackage :mod:`!Q` in package :mod:`!P` + :class:`!T` defined in module :mod:`!M` in subpackage :mod:`!Q` in package :mod:`!P` should have the :c:member:`~PyTypeObject.tp_name` initializer ``"P.Q.M.T"``. For :ref:`dynamically allocated type objects `, @@ -673,9 +673,9 @@ and :c:data:`PyType_Type` effectively act as defaults.) permissible to call the object deallocator directly instead of via :c:member:`~PyTypeObject.tp_free`. The object deallocator should be the one used to allocate the instance; this is normally :c:func:`PyObject_Del` if the instance was allocated - using :c:func:`PyObject_New` or :c:func:`PyObject_VarNew`, or + using :c:macro:`PyObject_New` or :c:macro:`PyObject_NewVar`, or :c:func:`PyObject_GC_Del` if the instance was allocated using - :c:func:`PyObject_GC_New` or :c:func:`PyObject_GC_NewVar`. + :c:macro:`PyObject_GC_New` or :c:macro:`PyObject_GC_NewVar`. If the type supports garbage collection (has the :c:macro:`Py_TPFLAGS_HAVE_GC` flag bit set), the destructor should call :c:func:`PyObject_GC_UnTrack` @@ -1092,7 +1092,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. c:macro:: Py_TPFLAGS_HAVE_GC This bit is set when the object supports garbage collection. If this bit - is set, instances must be created using :c:func:`PyObject_GC_New` and + is set, instances must be created using :c:macro:`PyObject_GC_New` and destroyed using :c:func:`PyObject_GC_Del`. More information in section :ref:`supporting-cycle-detection`. This bit also implies that the GC-related fields :c:member:`~PyTypeObject.tp_traverse` and :c:member:`~PyTypeObject.tp_clear` are present in @@ -1180,7 +1180,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) Indicates that the variable-sized portion of an instance of this type is at the end of the instance's memory area, at an offset of - :c:expr:`Py_TYPE(obj)->tp_basicsize` (which may be different in each + ``Py_TYPE(obj)->tp_basicsize`` (which may be different in each subclass). When setting this flag, be sure that all superclasses either diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index fb4cfc64c8d00e..02f9597c345a02 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -608,7 +608,7 @@ APIs: Py_ssize_t how_many) Copy characters from one Unicode object into another. This function performs - character conversion when necessary and falls back to :c:func:`memcpy` if + character conversion when necessary and falls back to :c:func:`!memcpy` if possible. Returns ``-1`` and sets an exception on error, otherwise returns the number of copied characters. @@ -721,7 +721,7 @@ system. .. c:function:: PyObject* PyUnicode_DecodeLocale(const char *str, const char *errors) Similar to :c:func:`PyUnicode_DecodeLocaleAndSize`, but compute the string - length using :c:func:`strlen`. + length using :c:func:`!strlen`. .. versionadded:: 3.3 @@ -879,7 +879,7 @@ wchar_t Support most C functions. If *size* is ``NULL`` and the :c:expr:`wchar_t*` string contains null characters a :exc:`ValueError` is raised. - Returns a buffer allocated by :c:func:`PyMem_New` (use + Returns a buffer allocated by :c:macro:`PyMem_New` (use :c:func:`PyMem_Free` to free it) on success. On error, returns ``NULL`` and *\*size* is undefined. Raises a :exc:`MemoryError` if memory allocation is failed. diff --git a/Doc/conf.py b/Doc/conf.py index 722831cdb54c3c..a8fd853ebb1f06 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -97,7 +97,7 @@ ('c:func', 'vsnprintf'), # Standard C types ('c:type', 'FILE'), - ('c:type', '__int'), + ('c:type', 'int64_t'), ('c:type', 'intmax_t'), ('c:type', 'off_t'), ('c:type', 'ptrdiff_t'), @@ -105,9 +105,12 @@ ('c:type', 'size_t'), ('c:type', 'ssize_t'), ('c:type', 'time_t'), + ('c:type', 'uint64_t'), ('c:type', 'uintmax_t'), + ('c:type', 'uintptr_t'), ('c:type', 'va_list'), ('c:type', 'wchar_t'), + # Standard C structures ('c:struct', 'in6_addr'), ('c:struct', 'in_addr'), ('c:struct', 'stat'), diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 068f6fcdcaccd1..c13b9371297ee6 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -230,7 +230,7 @@ with an exception object:: return m; } -Note that the Python name for the exception object is :exc:`spam.error`. The +Note that the Python name for the exception object is :exc:`!spam.error`. The :c:func:`PyErr_NewException` function may create a class with the base class being :exc:`Exception` (unless another class is passed in instead of ``NULL``), described in :ref:`bltin-exceptions`. @@ -245,7 +245,7 @@ raises the exception could cause a core dump or other unintended side effects. We discuss the use of ``PyMODINIT_FUNC`` as a function return type later in this sample. -The :exc:`spam.error` exception can be raised in your extension module using a +The :exc:`!spam.error` exception can be raised in your extension module using a call to :c:func:`PyErr_SetString` as shown below:: static PyObject * @@ -315,7 +315,7 @@ contexts, as we have seen. The Module's Method Table and Initialization Function ===================================================== -I promised to show how :c:func:`spam_system` is called from Python programs. +I promised to show how :c:func:`!spam_system` is called from Python programs. First, we need to list its name and address in a "method table":: static PyMethodDef SpamMethods[] = { @@ -1030,13 +1030,13 @@ Let's follow the control flow into :c:func:`PyList_SetItem`. The list owns references to all its items, so when item 1 is replaced, it has to dispose of the original item 1. Now let's suppose the original item 1 was an instance of a user-defined class, and let's further suppose that the class defined a -:meth:`__del__` method. If this class instance has a reference count of 1, -disposing of it will call its :meth:`__del__` method. +:meth:`!__del__` method. If this class instance has a reference count of 1, +disposing of it will call its :meth:`!__del__` method. -Since it is written in Python, the :meth:`__del__` method can execute arbitrary +Since it is written in Python, the :meth:`!__del__` method can execute arbitrary Python code. Could it perhaps do something to invalidate the reference to -``item`` in :c:func:`bug`? You bet! Assuming that the list passed into -:c:func:`bug` is accessible to the :meth:`__del__` method, it could execute a +``item`` in :c:func:`!bug`? You bet! Assuming that the list passed into +:c:func:`!bug` is accessible to the :meth:`!__del__` method, it could execute a statement to the effect of ``del list[0]``, and assuming this was the last reference to that object, it would free the memory associated with it, thereby invalidating ``item``. @@ -1057,7 +1057,7 @@ increment the reference count. The correct version of the function reads:: This is a true story. An older version of Python contained variants of this bug and someone spent a considerable amount of time in a C debugger to figure out -why his :meth:`__del__` methods would fail... +why his :meth:`!__del__` methods would fail... The second case of problems with a borrowed reference is a variant involving threads. Normally, multiple threads in the Python interpreter can't get in each @@ -1224,7 +1224,7 @@ The function :c:func:`PySpam_System` is a plain C function, declared return system(command); } -The function :c:func:`spam_system` is modified in a trivial way:: +The function :c:func:`!spam_system` is modified in a trivial way:: static PyObject * spam_system(PyObject *self, PyObject *args) diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 80c8ea73e343ef..7180191d40f181 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -36,7 +36,7 @@ So, if you want to define a new extension type, you need to create a new type object. This sort of thing can only be explained by example, so here's a minimal, but -complete, module that defines a new type named :class:`Custom` inside a C +complete, module that defines a new type named :class:`!Custom` inside a C extension module :mod:`!custom`: .. note:: @@ -50,9 +50,9 @@ extension module :mod:`!custom`: Now that's quite a bit to take in at once, but hopefully bits will seem familiar from the previous chapter. This file defines three things: -#. What a :class:`Custom` **object** contains: this is the ``CustomObject`` - struct, which is allocated once for each :class:`Custom` instance. -#. How the :class:`Custom` **type** behaves: this is the ``CustomType`` struct, +#. What a :class:`!Custom` **object** contains: this is the ``CustomObject`` + struct, which is allocated once for each :class:`!Custom` instance. +#. How the :class:`!Custom` **type** behaves: this is the ``CustomType`` struct, which defines a set of flags and function pointers that the interpreter inspects when specific operations are requested. #. How to initialize the :mod:`!custom` module: this is the ``PyInit_custom`` @@ -128,7 +128,7 @@ our objects and in some error messages, for example: Note that the name is a dotted name that includes both the module name and the name of the type within the module. The module in this case is :mod:`!custom` and -the type is :class:`Custom`, so we set the type name to :class:`custom.Custom`. +the type is :class:`!Custom`, so we set the type name to :class:`!custom.Custom`. Using the real dotted import path is important to make your type compatible with the :mod:`pydoc` and :mod:`pickle` modules. :: @@ -136,7 +136,7 @@ with the :mod:`pydoc` and :mod:`pickle` modules. :: .tp_itemsize = 0, This is so that Python knows how much memory to allocate when creating -new :class:`Custom` instances. :c:member:`~PyTypeObject.tp_itemsize` is +new :class:`!Custom` instances. :c:member:`~PyTypeObject.tp_itemsize` is only used for variable-sized objects and should otherwise be zero. .. note:: @@ -188,7 +188,7 @@ set to ``NULL``. :: } This adds the type to the module dictionary. This allows us to create -:class:`Custom` instances by calling the :class:`Custom` class: +:class:`!Custom` instances by calling the :class:`!Custom` class: .. code-block:: pycon @@ -239,7 +239,7 @@ adds these capabilities: This version of the module has a number of changes. -The :class:`Custom` type now has three data attributes in its C struct, +The :class:`!Custom` type now has three data attributes in its C struct, *first*, *last*, and *number*. The *first* and *last* variables are Python strings containing first and last names. The *number* attribute is a C integer. @@ -314,7 +314,7 @@ The ``tp_new`` handler is responsible for creating (as opposed to initializing) objects of the type. It is exposed in Python as the :meth:`__new__` method. It is not required to define a ``tp_new`` member, and indeed many extension types will simply reuse :c:func:`PyType_GenericNew` as done in the first -version of the ``Custom`` type above. In this case, we use the ``tp_new`` +version of the :class:`!Custom` type above. In this case, we use the ``tp_new`` handler to initialize the ``first`` and ``last`` attributes to non-``NULL`` default values. @@ -453,7 +453,7 @@ Further, the attributes can be deleted, setting the C pointers to ``NULL``. Eve though we can make sure the members are initialized to non-``NULL`` values, the members can be set to ``NULL`` if the attributes are deleted. -We define a single method, :meth:`Custom.name()`, that outputs the objects name as the +We define a single method, :meth:`!Custom.name()`, that outputs the objects name as the concatenation of the first and last names. :: static PyObject * @@ -470,8 +470,8 @@ concatenation of the first and last names. :: return PyUnicode_FromFormat("%S %S", self->first, self->last); } -The method is implemented as a C function that takes a :class:`Custom` (or -:class:`Custom` subclass) instance as the first argument. Methods always take an +The method is implemented as a C function that takes a :class:`!Custom` (or +:class:`!Custom` subclass) instance as the first argument. Methods always take an instance as the first argument. Methods often take positional and keyword arguments as well, but in this case we don't take any and don't need to accept a positional argument tuple or keyword argument dictionary. This method is @@ -482,8 +482,8 @@ equivalent to the Python method: def name(self): return "%s %s" % (self.first, self.last) -Note that we have to check for the possibility that our :attr:`first` and -:attr:`last` members are ``NULL``. This is because they can be deleted, in which +Note that we have to check for the possibility that our :attr:`!first` and +:attr:`!last` members are ``NULL``. This is because they can be deleted, in which case they are set to ``NULL``. It would be better to prevent deletion of these attributes and to restrict the attribute values to be strings. We'll see how to do that in the next section. @@ -512,7 +512,7 @@ to add the :c:macro:`Py_TPFLAGS_BASETYPE` to our class flag definition:: .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, -We rename :c:func:`PyInit_custom` to :c:func:`PyInit_custom2`, update the +We rename :c:func:`!PyInit_custom` to :c:func:`!PyInit_custom2`, update the module name in the :c:type:`PyModuleDef` struct, and update the full class name in the :c:type:`PyTypeObject` struct. @@ -531,18 +531,18 @@ Finally, we update our :file:`setup.py` file to build the new module: Providing finer control over data attributes ============================================ -In this section, we'll provide finer control over how the :attr:`first` and -:attr:`last` attributes are set in the :class:`Custom` example. In the previous -version of our module, the instance variables :attr:`first` and :attr:`last` +In this section, we'll provide finer control over how the :attr:`!first` and +:attr:`!last` attributes are set in the :class:`!Custom` example. In the previous +version of our module, the instance variables :attr:`!first` and :attr:`!last` could be set to non-string values or even deleted. We want to make sure that these attributes always contain strings. .. literalinclude:: ../includes/custom3.c -To provide greater control, over the :attr:`first` and :attr:`last` attributes, +To provide greater control, over the :attr:`!first` and :attr:`!last` attributes, we'll use custom getter and setter functions. Here are the functions for -getting and setting the :attr:`first` attribute:: +getting and setting the :attr:`!first` attribute:: static PyObject * Custom_getfirst(CustomObject *self, void *closure) @@ -571,13 +571,13 @@ getting and setting the :attr:`first` attribute:: return 0; } -The getter function is passed a :class:`Custom` object and a "closure", which is +The getter function is passed a :class:`!Custom` object and a "closure", which is a void pointer. In this case, the closure is ignored. (The closure supports an advanced usage in which definition data is passed to the getter and setter. This could, for example, be used to allow a single set of getter and setter functions that decide the attribute to get or set based on data in the closure.) -The setter function is passed the :class:`Custom` object, the new value, and the +The setter function is passed the :class:`!Custom` object, the new value, and the closure. The new value may be ``NULL``, in which case the attribute is being deleted. In our setter, we raise an error if the attribute is deleted or if its new value is not a string. @@ -666,11 +666,11 @@ still has a reference from itself. Its reference count doesn't drop to zero. Fortunately, Python's cyclic garbage collector will eventually figure out that the list is garbage and free it. -In the second version of the :class:`Custom` example, we allowed any kind of -object to be stored in the :attr:`first` or :attr:`last` attributes [#]_. +In the second version of the :class:`!Custom` example, we allowed any kind of +object to be stored in the :attr:`!first` or :attr:`!last` attributes [#]_. Besides, in the second and third versions, we allowed subclassing -:class:`Custom`, and subclasses may add arbitrary attributes. For any of -those two reasons, :class:`Custom` objects can participate in cycles: +:class:`!Custom`, and subclasses may add arbitrary attributes. For any of +those two reasons, :class:`!Custom` objects can participate in cycles: .. code-block:: pycon @@ -680,8 +680,8 @@ those two reasons, :class:`Custom` objects can participate in cycles: >>> n = Derived() >>> n.some_attribute = n -To allow a :class:`Custom` instance participating in a reference cycle to -be properly detected and collected by the cyclic GC, our :class:`Custom` type +To allow a :class:`!Custom` instance participating in a reference cycle to +be properly detected and collected by the cyclic GC, our :class:`!Custom` type needs to fill two additional slots and to enable a flag that enables these slots: .. literalinclude:: ../includes/custom4.c @@ -811,7 +811,7 @@ increases an internal counter: .. literalinclude:: ../includes/sublist.c -As you can see, the source code closely resembles the :class:`Custom` examples in +As you can see, the source code closely resembles the :class:`!Custom` examples in previous sections. We will break down the main differences between them. :: typedef struct { @@ -879,7 +879,7 @@ slot with :c:func:`PyType_GenericNew` -- the allocation function from the base type will be inherited. After that, calling :c:func:`PyType_Ready` and adding the type object to the -module is the same as with the basic :class:`Custom` examples. +module is the same as with the basic :class:`!Custom` examples. .. rubric:: Footnotes diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index b02f6eaea13250..ab906b3817670b 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -3,13 +3,10 @@ # Add blank lines between files and keep them sorted lexicographically # to help avoid merge conflicts. -Doc/c-api/allocation.rst Doc/c-api/arg.rst Doc/c-api/bool.rst Doc/c-api/buffer.rst Doc/c-api/capsule.rst -Doc/c-api/complex.rst -Doc/c-api/conversion.rst Doc/c-api/datetime.rst Doc/c-api/descriptor.rst Doc/c-api/dict.rst diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index 14f951174ba545..3dfe509e1d1c08 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1847,7 +1847,7 @@ specifically for allocating Python objects. :c:func:`PyObject_Malloc`, :c:func:`PyObject_Realloc`, and :c:func:`PyObject_Free`. * To allocate and free Python objects, use the "object" family - :c:func:`PyObject_New`, :c:func:`PyObject_NewVar`, and :c:func:`PyObject_Del`. + :c:macro:`PyObject_New`, :c:macro:`PyObject_NewVar`, and :c:func:`PyObject_Del`. Thanks to lots of work by Tim Peters, pymalloc in 2.3 also provides debugging features to catch memory overwrites and doubled frees in both extension modules diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 5df2cef7e898aa..98d97268b59013 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2061,8 +2061,8 @@ Changes in the C API * Remove :c:macro:`Py_INCREF` on the type object after allocating an instance - if any. - This may happen after calling :c:func:`PyObject_New`, - :c:func:`PyObject_NewVar`, :c:func:`PyObject_GC_New`, + This may happen after calling :c:macro:`PyObject_New`, + :c:macro:`PyObject_NewVar`, :c:func:`PyObject_GC_New`, :c:func:`PyObject_GC_NewVar`, or any other custom allocator that uses :c:func:`PyObject_Init` or :c:func:`PyObject_INIT`. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 6de432d6c036bc..666d53ed6da7ba 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1389,8 +1389,8 @@ Porting to Python 3.9 * :c:func:`PyObject_IS_GC` macro was converted to a function. * The :c:func:`PyObject_NEW` macro becomes an alias to the - :c:func:`PyObject_New` macro, and the :c:func:`PyObject_NEW_VAR` macro - becomes an alias to the :c:func:`PyObject_NewVar` macro. They no longer + :c:macro:`PyObject_New` macro, and the :c:func:`PyObject_NEW_VAR` macro + becomes an alias to the :c:macro:`PyObject_NewVar` macro. They no longer access directly the :c:member:`PyTypeObject.tp_basicsize` member. * :c:func:`PyObject_GET_WEAKREFS_LISTPTR` macro was converted to a function: From 4014869b4b2456b3da1118a37332f9e9e851aebf Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 28 Jul 2023 11:20:53 +0300 Subject: [PATCH 0466/1206] [3.12] gh-107298: Fix yet more Sphinx warnings in the C API doc (GH-107345) (GH-107380) (cherry picked from commit 983305268e2291b0a7835621b81bf40cba7c27f3) --- Doc/c-api/capsule.rst | 2 +- Doc/c-api/init_config.rst | 12 ++++++++++- Doc/c-api/intro.rst | 2 +- Doc/c-api/memory.rst | 2 ++ Doc/c-api/module.rst | 2 +- Doc/c-api/none.rst | 2 +- Doc/c-api/object.rst | 6 +++--- Doc/c-api/set.rst | 6 +++--- Doc/c-api/sys.rst | 4 ++-- Doc/c-api/type.rst | 2 +- Doc/c-api/typeobj.rst | 33 +++++++++++++++-------------- Doc/extending/embedding.rst | 2 +- Doc/extending/extending.rst | 24 ++++++++++----------- Doc/extending/newtypes.rst | 16 +++++++------- Doc/extending/newtypes_tutorial.rst | 32 ++++++++++++++-------------- Doc/howto/descriptor.rst | 10 ++++----- Doc/tools/.nitignore | 4 ---- Doc/whatsnew/2.5.rst | 4 ++-- Doc/whatsnew/3.8.rst | 2 +- 19 files changed, 88 insertions(+), 79 deletions(-) diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 2a1b602dc79c0f..cdb8aa33e9fd32 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -121,7 +121,7 @@ Refer to :ref:`using-capsules` for more information on using these objects. compared.) In other words, if :c:func:`PyCapsule_IsValid` returns a true value, calls to - any of the accessors (any function starting with :c:func:`PyCapsule_Get`) are + any of the accessors (any function starting with ``PyCapsule_Get``) are guaranteed to succeed. Return a nonzero value if the object is valid and matches the name passed in. diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index cf7337f679e69f..9da9f873e74484 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -135,6 +135,8 @@ PyStatus Name of the function which created an error, can be ``NULL``. + .. c:namespace:: NULL + Functions to create a status: .. c:function:: PyStatus PyStatus_Ok(void) @@ -210,6 +212,8 @@ PyPreConfig Structure used to preinitialize Python. + .. c:namespace:: NULL + Function to initialize a preconfiguration: .. c:function:: void PyPreConfig_InitPythonConfig(PyPreConfig *preconfig) @@ -222,6 +226,8 @@ PyPreConfig Initialize the preconfiguration with :ref:`Isolated Configuration `. + .. c:namespace:: PyPreConfig + Structure fields: .. c:member:: int allocator @@ -429,6 +435,8 @@ PyConfig When done, the :c:func:`PyConfig_Clear` function must be used to release the configuration memory. + .. c:namespace:: NULL + Structure methods: .. c:function:: void PyConfig_InitPythonConfig(PyConfig *config) @@ -527,6 +535,8 @@ PyConfig The caller of these methods is responsible to handle exceptions (error or exit) using ``PyStatus_Exception()`` and ``Py_ExitStatusException()``. + .. c:namespace:: PyConfig + Structure fields: .. c:member:: PyWideStringList argv @@ -920,7 +930,7 @@ PyConfig .. c:member:: wchar_t* pythonpath_env Module search paths (:data:`sys.path`) as a string separated by ``DELIM`` - (:data:`os.path.pathsep`). + (:data:`os.pathsep`). Set by the :envvar:`PYTHONPATH` environment variable. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 8de76e55cd0586..42a5db1893472e 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -616,7 +616,7 @@ and lose important information about the exact cause of the error. .. index:: single: sum_sequence() A simple example of detecting exceptions and passing them on is shown in the -:c:func:`sum_sequence` example above. It so happens that this example doesn't +:c:func:`!sum_sequence` example above. It so happens that this example doesn't need to clean up any owned references when it detects an error. The following example function shows some error cleanup. First, to remind you why you like Python, we show the equivalent Python code:: diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index c51aba3f555367..8968b26b64320a 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -431,6 +431,8 @@ Customize Memory Allocators Enum used to identify an allocator domain. Domains: + .. c:namespace:: NULL + .. c:macro:: PYMEM_DOMAIN_RAW Functions: diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index fc4dd4ce053e68..8ca48c852d4e6f 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -119,7 +119,7 @@ Module Objects encoded to 'utf-8'. .. deprecated:: 3.2 - :c:func:`PyModule_GetFilename` raises :c:type:`UnicodeEncodeError` on + :c:func:`PyModule_GetFilename` raises :exc:`UnicodeEncodeError` on unencodable filenames, use :c:func:`PyModule_GetFilenameObject` instead. diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst index 1a497652ac5655..dd8bfb56104251 100644 --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -9,7 +9,7 @@ The ``None`` Object Note that the :c:type:`PyTypeObject` for ``None`` is not directly exposed in the Python/C API. Since ``None`` is a singleton, testing for object identity (using -``==`` in C) is sufficient. There is no :c:func:`PyNone_Check` function for the +``==`` in C) is sufficient. There is no :c:func:`!PyNone_Check` function for the same reason. diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 3b922f3b810c72..5b3c3615f75818 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -256,7 +256,7 @@ Object Protocol Normally only class objects, i.e. instances of :class:`type` or a derived class, are considered classes. However, objects can override this by having - a :attr:`__bases__` attribute (which must be a tuple of base classes). + a :attr:`~class.__bases__` attribute (which must be a tuple of base classes). .. c:function:: int PyObject_IsInstance(PyObject *inst, PyObject *cls) @@ -273,10 +273,10 @@ Object Protocol is an instance of *cls* if its class is a subclass of *cls*. An instance *inst* can override what is considered its class by having a - :attr:`__class__` attribute. + :attr:`~instance.__class__` attribute. An object *cls* can override if it is considered a class, and what its base - classes are, by having a :attr:`__bases__` attribute (which must be a tuple + classes are, by having a :attr:`~class.__bases__` attribute (which must be a tuple of base classes). diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index 7e0ebd2f791a4d..1e8a09509032f5 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -110,7 +110,7 @@ or :class:`frozenset` or instances of their subtypes. .. index:: pair: built-in function; len Return the length of a :class:`set` or :class:`frozenset` object. Equivalent to - ``len(anyset)``. Raises a :exc:`PyExc_SystemError` if *anyset* is not a + ``len(anyset)``. Raises a :exc:`SystemError` if *anyset* is not a :class:`set`, :class:`frozenset`, or an instance of a subtype. @@ -124,7 +124,7 @@ or :class:`frozenset` or instances of their subtypes. Return ``1`` if found, ``0`` if not found, and ``-1`` if an error is encountered. Unlike the Python :meth:`~object.__contains__` method, this function does not automatically convert unhashable sets into temporary frozensets. Raise a :exc:`TypeError` if - the *key* is unhashable. Raise :exc:`PyExc_SystemError` if *anyset* is not a + the *key* is unhashable. Raise :exc:`SystemError` if *anyset* is not a :class:`set`, :class:`frozenset`, or an instance of a subtype. @@ -149,7 +149,7 @@ subtypes but not for instances of :class:`frozenset` or its subtypes. error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a :exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard` method, this function does not automatically convert unhashable sets into - temporary frozensets. Raise :exc:`PyExc_SystemError` if *set* is not an + temporary frozensets. Raise :exc:`SystemError` if *set* is not an instance of :class:`set` or its subtype. diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 2c45ea1427a119..1cec0666f5319b 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -167,7 +167,7 @@ Operating System Utilities .. versionchanged:: 3.8 The function now uses the UTF-8 encoding on Windows if - :c:member:`PyConfig.legacy_windows_fs_encoding` is zero; + :c:member:`PyPreConfig.legacy_windows_fs_encoding` is zero; .. c:function:: char* Py_EncodeLocale(const wchar_t *text, size_t *error_pos) @@ -209,7 +209,7 @@ Operating System Utilities .. versionchanged:: 3.8 The function now uses the UTF-8 encoding on Windows if - :c:member:`PyConfig.legacy_windows_fs_encoding` is zero. + :c:member:`PyPreConfig.legacy_windows_fs_encoding` is zero. .. _systemfunctions: diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index e7b35c43da32af..0f58326f6c06b7 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -103,7 +103,7 @@ Type Objects :c:func:`PyType_AddWatcher` will be called whenever :c:func:`PyType_Modified` reports a change to *type*. (The callback may be called only once for a series of consecutive modifications to *type*, if - :c:func:`PyType_Lookup` is not called on *type* between the modifications; + :c:func:`!_PyType_Lookup` is not called on *type* between the modifications; this is an implementation detail and subject to change.) An extension should never call ``PyType_Watch`` with a *watcher_id* that was diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 99b025dc41fc2e..26e6133aebaa8f 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -485,7 +485,7 @@ PyObject Slots -------------- The type object structure extends the :c:type:`PyVarObject` structure. The -:c:member:`~PyVarObject.ob_size` field is used for dynamic types (created by :func:`type_new`, +:c:member:`~PyVarObject.ob_size` field is used for dynamic types (created by :c:func:`!type_new`, usually called from a class statement). Note that :c:data:`PyType_Type` (the metatype) initializes :c:member:`~PyTypeObject.tp_itemsize`, which means that its instances (i.e. type objects) *must* have the :c:member:`~PyVarObject.ob_size` field. @@ -740,7 +740,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) Before version 3.12, it was not recommended for :ref:`mutable heap types ` to implement the vectorcall protocol. - When a user sets :attr:`~type.__call__` in Python code, only *tp_call* is + When a user sets :attr:`~object.__call__` in Python code, only *tp_call* is updated, likely making it inconsistent with the vectorcall function. Since 3.12, setting ``__call__`` will disable vectorcall optimization by clearing the :c:macro:`Py_TPFLAGS_HAVE_VECTORCALL` flag. @@ -1369,8 +1369,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) The :c:member:`~PyTypeObject.tp_traverse` pointer is used by the garbage collector to detect reference cycles. A typical implementation of a :c:member:`~PyTypeObject.tp_traverse` function simply calls :c:func:`Py_VISIT` on each of the instance's members that are Python - objects that the instance owns. For example, this is function :c:func:`local_traverse` from the - :mod:`_thread` extension module:: + objects that the instance owns. For example, this is function :c:func:`!local_traverse` from the + :mod:`!_thread` extension module:: static int local_traverse(localobject *self, visitproc visit, void *arg) @@ -1721,7 +1721,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) called; it may also be initialized to a dictionary containing initial attributes for the type. Once :c:func:`PyType_Ready` has initialized the type, extra attributes for the type may be added to this dictionary only if they don't - correspond to overloaded operations (like :meth:`__add__`). Once + correspond to overloaded operations (like :meth:`~object.__add__`). Once initialization for the type has finished, this field should be treated as read-only. @@ -1818,7 +1818,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) **Default:** This slot has no default. For :ref:`static types `, if the - field is ``NULL`` then no :attr:`__dict__` gets created for instances. + field is ``NULL`` then no :attr:`~object.__dict__` gets created for instances. If the :c:macro:`Py_TPFLAGS_MANAGED_DICT` bit is set in the :c:member:`~PyTypeObject.tp_dict` field, then @@ -1830,10 +1830,10 @@ and :c:data:`PyType_Type` effectively act as defaults.) An optional pointer to an instance initialization function. - This function corresponds to the :meth:`__init__` method of classes. Like - :meth:`__init__`, it is possible to create an instance without calling - :meth:`__init__`, and it is possible to reinitialize an instance by calling its - :meth:`__init__` method again. + This function corresponds to the :meth:`~object.__init__` method of classes. Like + :meth:`!__init__`, it is possible to create an instance without calling + :meth:`!__init__`, and it is possible to reinitialize an instance by calling its + :meth:`!__init__` method again. The function signature is:: @@ -1841,7 +1841,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) The self argument is the instance to be initialized; the *args* and *kwds* arguments represent positional and keyword arguments of the call to - :meth:`__init__`. + :meth:`~object.__init__`. The :c:member:`~PyTypeObject.tp_init` function, if not ``NULL``, is called when an instance is created normally by calling its type, after the type's :c:member:`~PyTypeObject.tp_new` function @@ -2130,7 +2130,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) In other words, it is used to implement :ref:`vectorcall ` for ``type.__call__``. If ``tp_vectorcall`` is ``NULL``, the default call implementation - using :attr:`__new__` and :attr:`__init__` is used. + using :meth:`~object.__new__` and :meth:`~object.__init__` is used. **Inheritance:** @@ -2329,8 +2329,8 @@ Mapping Object Structures .. c:member:: objobjargproc PyMappingMethods.mp_ass_subscript This function is used by :c:func:`PyObject_SetItem`, - :c:func:`PyObject_DelItem`, :c:func:`PyObject_SetSlice` and - :c:func:`PyObject_DelSlice`. It has the same signature as + :c:func:`PyObject_DelItem`, :c:func:`PySequence_SetSlice` and + :c:func:`PySequence_DelSlice`. It has the same signature as :c:func:`!PyObject_SetItem`, but *v* can also be set to ``NULL`` to delete an item. If this slot is ``NULL``, the object does not support item assignment and deletion. @@ -2552,7 +2552,7 @@ Async Object Structures PyObject *am_aiter(PyObject *self); Must return an :term:`asynchronous iterator` object. - See :meth:`__anext__` for details. + See :meth:`~object.__anext__` for details. This slot may be set to ``NULL`` if an object does not implement asynchronous iteration protocol. @@ -2563,7 +2563,8 @@ Async Object Structures PyObject *am_anext(PyObject *self); - Must return an :term:`awaitable` object. See :meth:`__anext__` for details. + Must return an :term:`awaitable` object. + See :meth:`~object.__anext__` for details. This slot may be set to ``NULL``. .. c:member:: sendfunc PyAsyncMethods.am_send diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst index e64db373344038..4c7c7ec98a6c95 100644 --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -250,7 +250,7 @@ following two statements before the call to :c:func:`Py_Initialize`:: PyImport_AppendInittab("emb", &PyInit_emb); These two lines initialize the ``numargs`` variable, and make the -:func:`emb.numargs` function accessible to the embedded Python interpreter. +:func:`!emb.numargs` function accessible to the embedded Python interpreter. With these extensions, the Python script can do things like .. code-block:: python diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index c13b9371297ee6..72e30a68828072 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -195,7 +195,7 @@ The choice of which exception to raise is entirely yours. There are predeclared C objects corresponding to all built-in Python exceptions, such as :c:data:`PyExc_ZeroDivisionError`, which you can use directly. Of course, you should choose exceptions wisely --- don't use :c:data:`PyExc_TypeError` to mean -that a file couldn't be opened (that should probably be :c:data:`PyExc_IOError`). +that a file couldn't be opened (that should probably be :c:data:`PyExc_OSError`). If something's wrong with the argument list, the :c:func:`PyArg_ParseTuple` function usually raises :c:data:`PyExc_TypeError`. If you have an argument whose value must be in a particular range or must satisfy other conditions, @@ -206,7 +206,7 @@ usually declare a static object variable at the beginning of your file:: static PyObject *SpamError; -and initialize it in your module's initialization function (:c:func:`PyInit_spam`) +and initialize it in your module's initialization function (:c:func:`!PyInit_spam`) with an exception object:: PyMODINIT_FUNC @@ -354,7 +354,7 @@ The method table must be referenced in the module definition structure:: This structure, in turn, must be passed to the interpreter in the module's initialization function. The initialization function must be named -:c:func:`PyInit_name`, where *name* is the name of the module, and should be the +:c:func:`!PyInit_name`, where *name* is the name of the module, and should be the only non-\ ``static`` item defined in the module file:: PyMODINIT_FUNC @@ -368,7 +368,7 @@ declares any special linkage declarations required by the platform, and for C++ declares the function as ``extern "C"``. When the Python program imports module :mod:`!spam` for the first time, -:c:func:`PyInit_spam` is called. (See below for comments about embedding Python.) +:c:func:`!PyInit_spam` is called. (See below for comments about embedding Python.) It calls :c:func:`PyModule_Create`, which returns a module object, and inserts built-in function objects into the newly created module based upon the table (an array of :c:type:`PyMethodDef` structures) found in the module definition. @@ -378,7 +378,7 @@ certain errors, or return ``NULL`` if the module could not be initialized satisfactorily. The init function must return the module object to its caller, so that it then gets inserted into ``sys.modules``. -When embedding Python, the :c:func:`PyInit_spam` function is not called +When embedding Python, the :c:func:`!PyInit_spam` function is not called automatically unless there's an entry in the :c:data:`PyImport_Inittab` table. To add the module to the initialization table, use :c:func:`PyImport_AppendInittab`, optionally followed by an import of the module:: @@ -1209,13 +1209,13 @@ the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API. The exporting module is a modification of the :mod:`!spam` module from section -:ref:`extending-simpleexample`. The function :func:`spam.system` does not call +:ref:`extending-simpleexample`. The function :func:`!spam.system` does not call the C library function :c:func:`system` directly, but a function -:c:func:`PySpam_System`, which would of course do something more complicated in +:c:func:`!PySpam_System`, which would of course do something more complicated in reality (such as adding "spam" to every command). This function -:c:func:`PySpam_System` is also exported to other extension modules. +:c:func:`!PySpam_System` is also exported to other extension modules. -The function :c:func:`PySpam_System` is a plain C function, declared +The function :c:func:`!PySpam_System` is a plain C function, declared ``static`` like everything else:: static int @@ -1278,7 +1278,7 @@ function must take care of initializing the C API pointer array:: } Note that ``PySpam_API`` is declared ``static``; otherwise the pointer -array would disappear when :func:`PyInit_spam` terminates! +array would disappear when :c:func:`!PyInit_spam` terminates! The bulk of the work is in the header file :file:`spammodule.h`, which looks like this:: @@ -1332,8 +1332,8 @@ like this:: #endif /* !defined(Py_SPAMMODULE_H) */ All that a client module must do in order to have access to the function -:c:func:`PySpam_System` is to call the function (or rather macro) -:c:func:`import_spam` in its initialization function:: +:c:func:`!PySpam_System` is to call the function (or rather macro) +:c:func:`!import_spam` in its initialization function:: PyMODINIT_FUNC PyInit_client(void) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 25822744125f80..386b3c8f4452c3 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -286,9 +286,9 @@ be read-only or read-write. The structures in the table are defined as:: For each entry in the table, a :term:`descriptor` will be constructed and added to the type which will be able to extract a value from the instance structure. The -:attr:`type` field should contain a type code like :c:macro:`Py_T_INT` or +:c:member:`~PyMemberDef.type` field should contain a type code like :c:macro:`Py_T_INT` or :c:macro:`Py_T_DOUBLE`; the value will be used to determine how to -convert Python values to and from C values. The :attr:`flags` field is used to +convert Python values to and from C values. The :c:member:`~PyMemberDef.flags` field is used to store flags which control how the attribute can be accessed: you can set it to :c:macro:`Py_READONLY` to prevent Python code from setting it. @@ -298,7 +298,7 @@ have an associated doc string simply by providing the text in the table. An application can use the introspection API to retrieve the descriptor from the class object, and get the doc string using its :attr:`__doc__` attribute. -As with the :c:member:`~PyTypeObject.tp_methods` table, a sentinel entry with a :attr:`name` value +As with the :c:member:`~PyTypeObject.tp_methods` table, a sentinel entry with a :c:member:`~PyMethodDef.name` value of ``NULL`` is required. .. XXX Descriptors need to be explained in more detail somewhere, but not here. @@ -323,7 +323,7 @@ called, so that if you do need to extend their functionality, you'll understand what needs to be done. The :c:member:`~PyTypeObject.tp_getattr` handler is called when the object requires an attribute -look-up. It is called in the same situations where the :meth:`__getattr__` +look-up. It is called in the same situations where the :meth:`~object.__getattr__` method of a class would be called. Here is an example:: @@ -342,8 +342,8 @@ Here is an example:: return NULL; } -The :c:member:`~PyTypeObject.tp_setattr` handler is called when the :meth:`__setattr__` or -:meth:`__delattr__` method of a class instance would be called. When an +The :c:member:`~PyTypeObject.tp_setattr` handler is called when the :meth:`~object.__setattr__` or +:meth:`~object.__delattr__` method of a class instance would be called. When an attribute should be deleted, the third parameter will be ``NULL``. Here is an example that simply raises an exception; if this were really all you wanted, the :c:member:`~PyTypeObject.tp_setattr` handler should be set to ``NULL``. :: @@ -364,7 +364,7 @@ Object Comparison The :c:member:`~PyTypeObject.tp_richcompare` handler is called when comparisons are needed. It is analogous to the :ref:`rich comparison methods `, like -:meth:`__lt__`, and also called by :c:func:`PyObject_RichCompare` and +:meth:`!__lt__`, and also called by :c:func:`PyObject_RichCompare` and :c:func:`PyObject_RichCompareBool`. This function is called with two Python objects and the operator as arguments, @@ -505,7 +505,7 @@ These functions provide support for the iterator protocol. Both handlers take exactly one parameter, the instance for which they are being called, and return a new reference. In the case of an error, they should set an exception and return ``NULL``. :c:member:`~PyTypeObject.tp_iter` corresponds -to the Python :meth:`__iter__` method, while :c:member:`~PyTypeObject.tp_iternext` +to the Python :meth:`~object.__iter__` method, while :c:member:`~PyTypeObject.tp_iternext` corresponds to the Python :meth:`~iterator.__next__` method. Any :term:`iterable` object must implement the :c:member:`~PyTypeObject.tp_iter` diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 7180191d40f181..f8684df5dd8299 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -145,7 +145,7 @@ only used for variable-sized objects and should otherwise be zero. :c:member:`~PyTypeObject.tp_basicsize` as its base type, you may have problems with multiple inheritance. A Python subclass of your type will have to list your type first in its :attr:`~class.__bases__`, or else it will not be able to call your type's - :meth:`__new__` method without getting an error. You can avoid this problem by + :meth:`~object.__new__` method without getting an error. You can avoid this problem by ensuring that your type has a larger value for :c:member:`~PyTypeObject.tp_basicsize` than its base type does. Most of the time, this will be true anyway, because either your base type will be :class:`object`, or else you will be adding data members to @@ -164,14 +164,14 @@ We provide a doc string for the type in :c:member:`~PyTypeObject.tp_doc`. :: .tp_doc = PyDoc_STR("Custom objects"), To enable object creation, we have to provide a :c:member:`~PyTypeObject.tp_new` -handler. This is the equivalent of the Python method :meth:`__new__`, but +handler. This is the equivalent of the Python method :meth:`~object.__new__`, but has to be specified explicitly. In this case, we can just use the default implementation provided by the API function :c:func:`PyType_GenericNew`. :: .tp_new = PyType_GenericNew, Everything else in the file should be familiar, except for some code in -:c:func:`PyInit_custom`:: +:c:func:`!PyInit_custom`:: if (PyType_Ready(&CustomType) < 0) return; @@ -220,7 +220,7 @@ Of course, the current Custom type is pretty uninteresting. It has no data and doesn't do anything. It can't even be subclassed. .. note:: - While this documentation showcases the standard :mod:`distutils` module + While this documentation showcases the standard :mod:`!distutils` module for building C extensions, it is recommended in real-world use cases to use the newer and better-maintained ``setuptools`` library. Documentation on how to do this is out of scope for this document and can be found in @@ -272,7 +272,7 @@ This method first clears the reference counts of the two Python attributes. ``NULL`` (which might happen here if ``tp_new`` failed midway). It then calls the :c:member:`~PyTypeObject.tp_free` member of the object's type (computed by ``Py_TYPE(self)``) to free the object's memory. Note that -the object's type might not be :class:`CustomType`, because the object may +the object's type might not be :class:`!CustomType`, because the object may be an instance of a subclass. .. note:: @@ -311,7 +311,7 @@ and install it in the :c:member:`~PyTypeObject.tp_new` member:: .tp_new = Custom_new, The ``tp_new`` handler is responsible for creating (as opposed to initializing) -objects of the type. It is exposed in Python as the :meth:`__new__` method. +objects of the type. It is exposed in Python as the :meth:`~object.__new__` method. It is not required to define a ``tp_new`` member, and indeed many extension types will simply reuse :c:func:`PyType_GenericNew` as done in the first version of the :class:`!Custom` type above. In this case, we use the ``tp_new`` @@ -345,7 +345,7 @@ result against ``NULL`` before proceeding. .. note:: If you are creating a co-operative :c:member:`~PyTypeObject.tp_new` (one - that calls a base type's :c:member:`~PyTypeObject.tp_new` or :meth:`__new__`), + that calls a base type's :c:member:`~PyTypeObject.tp_new` or :meth:`~object.__new__`), you must *not* try to determine what method to call using method resolution order at runtime. Always statically determine what type you are going to call, and call its :c:member:`~PyTypeObject.tp_new` directly, or via @@ -388,14 +388,14 @@ by filling the :c:member:`~PyTypeObject.tp_init` slot. :: .tp_init = (initproc) Custom_init, The :c:member:`~PyTypeObject.tp_init` slot is exposed in Python as the -:meth:`__init__` method. It is used to initialize an object after it's +:meth:`~object.__init__` method. It is used to initialize an object after it's created. Initializers always accept positional and keyword arguments, and they should return either ``0`` on success or ``-1`` on error. Unlike the ``tp_new`` handler, there is no guarantee that ``tp_init`` is called at all (for example, the :mod:`pickle` module by default -doesn't call :meth:`__init__` on unpickled instances). It can also be -called multiple times. Anyone can call the :meth:`__init__` method on +doesn't call :meth:`~object.__init__` on unpickled instances). It can also be +called multiple times. Anyone can call the :meth:`!__init__` method on our objects. For this reason, we have to be extra careful when assigning the new attribute values. We might be tempted, for example to assign the ``first`` member like this:: @@ -708,8 +708,8 @@ participate in cycles:: } For each subobject that can participate in cycles, we need to call the -:c:func:`visit` function, which is passed to the traversal method. The -:c:func:`visit` function takes as arguments the subobject and the extra argument +:c:func:`!visit` function, which is passed to the traversal method. The +:c:func:`!visit` function takes as arguments the subobject and the extra argument *arg* passed to the traversal method. It returns an integer value that must be returned if it is non-zero. @@ -791,9 +791,9 @@ types. It is easiest to inherit from the built in types, since an extension can easily use the :c:type:`PyTypeObject` it needs. It can be difficult to share these :c:type:`PyTypeObject` structures between extension modules. -In this example we will create a :class:`SubList` type that inherits from the +In this example we will create a :class:`!SubList` type that inherits from the built-in :class:`list` type. The new type will be completely compatible with -regular lists, but will have an additional :meth:`increment` method that +regular lists, but will have an additional :meth:`!increment` method that increases an internal counter: .. code-block:: pycon @@ -823,7 +823,7 @@ The primary difference for derived type objects is that the base type's object structure must be the first value. The base type will already include the :c:func:`PyObject_HEAD` at the beginning of its structure. -When a Python object is a :class:`SubList` instance, its ``PyObject *`` pointer +When a Python object is a :class:`!SubList` instance, its ``PyObject *`` pointer can be safely cast to both ``PyListObject *`` and ``SubListObject *``:: static int @@ -835,7 +835,7 @@ can be safely cast to both ``PyListObject *`` and ``SubListObject *``:: return 0; } -We see above how to call through to the :attr:`__init__` method of the base +We see above how to call through to the :meth:`~object.__init__` method of the base type. This pattern is important when writing a type with custom diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 3688c47f0d6ec9..1d9424cb735a46 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -779,8 +779,8 @@ by a search through the class's :term:`method resolution order`. If a descriptor is found, it is invoked with ``desc.__get__(None, A)``. -The full C implementation can be found in :c:func:`type_getattro()` and -:c:func:`_PyType_Lookup()` in :source:`Objects/typeobject.c`. +The full C implementation can be found in :c:func:`!type_getattro` and +:c:func:`!_PyType_Lookup` in :source:`Objects/typeobject.c`. Invocation from super @@ -794,7 +794,7 @@ for the base class ``B`` immediately following ``A`` and then returns ``B.__dict__['m'].__get__(obj, A)``. If not a descriptor, ``m`` is returned unchanged. -The full C implementation can be found in :c:func:`super_getattro()` in +The full C implementation can be found in :c:func:`!super_getattro` in :source:`Objects/typeobject.c`. A pure Python equivalent can be found in `Guido's Tutorial `_. @@ -836,8 +836,8 @@ and if they define :meth:`__set_name__`, that method is called with two arguments. The *owner* is the class where the descriptor is used, and the *name* is the class variable the descriptor was assigned to. -The implementation details are in :c:func:`type_new()` and -:c:func:`set_names()` in :source:`Objects/typeobject.c`. +The implementation details are in :c:func:`!type_new` and +:c:func:`!set_names` in :source:`Objects/typeobject.c`. Since the update logic is in :meth:`type.__new__`, notifications only take place at the time of class creation. If descriptors are added to the class diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index ab906b3817670b..63223de613ff76 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -6,7 +6,6 @@ Doc/c-api/arg.rst Doc/c-api/bool.rst Doc/c-api/buffer.rst -Doc/c-api/capsule.rst Doc/c-api/datetime.rst Doc/c-api/descriptor.rst Doc/c-api/dict.rst @@ -21,7 +20,6 @@ Doc/c-api/intro.rst Doc/c-api/memory.rst Doc/c-api/memoryview.rst Doc/c-api/module.rst -Doc/c-api/none.rst Doc/c-api/object.rst Doc/c-api/set.rst Doc/c-api/stable.rst @@ -30,10 +28,8 @@ Doc/c-api/sys.rst Doc/c-api/type.rst Doc/c-api/typeobj.rst Doc/c-api/unicode.rst -Doc/extending/embedding.rst Doc/extending/extending.rst Doc/extending/newtypes.rst -Doc/extending/newtypes_tutorial.rst Doc/faq/design.rst Doc/faq/extending.rst Doc/faq/gui.rst diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index 162d2c342f50fd..a15eefc2953f40 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -2151,8 +2151,8 @@ Changes to Python's build process and to the C API include: Previously these different families all reduced to the platform's :c:func:`malloc` and :c:func:`free` functions. This meant it didn't matter if - you got things wrong and allocated memory with the :c:func:`PyMem` function but - freed it with the :c:func:`PyObject` function. With 2.5's changes to obmalloc, + you got things wrong and allocated memory with the ``PyMem`` function but + freed it with the ``PyObject`` function. With 2.5's changes to obmalloc, these families now do different things and mismatches will probably result in a segfault. You should carefully test your C extension modules with Python 2.5. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 98d97268b59013..3397de5d3e8c47 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1850,7 +1850,7 @@ Changes in Python behavior finalizing, making them consistent with :c:func:`PyEval_RestoreThread`, :c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`. If this behavior is not desired, guard the call by checking :c:func:`_Py_IsFinalizing` - or :c:func:`sys.is_finalizing`. + or :func:`sys.is_finalizing`. (Contributed by Joannah Nanjekye in :issue:`36475`.) From 3b1a4c18426c78a2fda0d59728bfe9eb92889722 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 28 Jul 2023 09:48:35 +0100 Subject: [PATCH 0467/1206] [3.12] GH-106897: Add `RERAISE` event to `sys.monitoring`. (GH-107291) (GH-107346) * Ensures that exception handling events are balanced. Each [re]raise event has a matching unwind/handled event. --- Doc/data/python3.12.abi | 1574 +++++++++-------- Include/cpython/code.h | 4 +- Include/internal/pycore_instruments.h | 5 +- Lib/test/test_monitoring.py | 230 ++- ...-07-26-12-18-10.gh-issue-106897.EsGurc.rst | 3 + Python/bytecodes.c | 9 +- Python/ceval.c | 14 +- Python/generated_cases.c.h | 767 ++++---- Python/instrumentation.c | 1 + 9 files changed, 1404 insertions(+), 1203 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 4cd130f86e2f7e..4c92e1d43c965e 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -739,6 +739,7 @@ + @@ -1165,6 +1166,7 @@ + @@ -1703,7 +1705,7 @@ - + @@ -1721,7 +1723,7 @@ - + @@ -1731,10 +1733,10 @@ - + - + @@ -1822,11 +1824,11 @@
- + - + @@ -1838,14 +1840,14 @@ - + - + @@ -1864,7 +1866,7 @@ - + @@ -1874,7 +1876,7 @@
- + @@ -1916,13 +1918,13 @@ - + - + @@ -1930,7 +1932,7 @@ - + @@ -2010,7 +2012,7 @@
- + @@ -2041,7 +2043,7 @@
- + @@ -2069,7 +2071,7 @@ - + @@ -3366,7 +3368,7 @@ - + @@ -3420,7 +3422,7 @@
- + @@ -3526,7 +3528,7 @@
- + @@ -3535,7 +3537,7 @@ - + @@ -3591,7 +3593,7 @@
- + @@ -3613,12 +3615,12 @@
- + - + @@ -3635,7 +3637,7 @@ - + @@ -3718,58 +3720,58 @@ - - - - + + + + - + - - + + - - + + - + - - + + - + - + - - + + - - - - + + + + - - - + + + - - + + - - + + @@ -3777,7 +3779,7 @@ - + @@ -3848,7 +3850,7 @@
- + @@ -3907,7 +3909,7 @@ - + @@ -3930,7 +3932,7 @@
- + @@ -3984,13 +3986,13 @@
- + - + @@ -4085,18 +4087,18 @@ - + - + - + @@ -4659,7 +4661,7 @@ - + @@ -4687,13 +4689,13 @@ - + - + @@ -4900,27 +4902,27 @@ - + - + - + - + - + @@ -5034,7 +5036,7 @@ - + @@ -5131,7 +5133,7 @@ - + @@ -5189,7 +5191,7 @@ - + @@ -5249,77 +5251,77 @@ - - - - - - + + + + + + - - - + + + - - - + + + - - + + - - - + + + - - - + + + - - + + - - + + - - - - + + + + - - - - + + + + - - - + + + - - - + + + - - - - - + + + + + - + @@ -5346,12 +5348,12 @@ - + - + @@ -5411,12 +5413,12 @@ - + - + @@ -5573,7 +5575,7 @@ - + @@ -5638,9 +5640,9 @@ - + - + @@ -5660,7 +5662,7 @@ - + @@ -5672,21 +5674,21 @@ - + - + - + - + @@ -5716,7 +5718,7 @@ - + @@ -5970,12 +5972,12 @@ - - + + - + @@ -6092,7 +6094,7 @@ - + @@ -6114,24 +6116,24 @@ - + - + - + - + - + @@ -6169,11 +6171,11 @@ - + - + @@ -6229,8 +6231,8 @@ - - + + @@ -6300,6 +6302,11 @@ + + + + + @@ -6374,22 +6381,12 @@ - - - - - - - - - - @@ -6529,7 +6526,7 @@ - + @@ -6538,7 +6535,7 @@ - + @@ -6600,11 +6597,11 @@ - + - + @@ -6891,7 +6888,7 @@ - + @@ -6980,7 +6977,7 @@ - + @@ -7022,7 +7019,7 @@ - + @@ -7173,7 +7170,7 @@ - + @@ -7213,6 +7210,16 @@ + + + + + + + + + + @@ -7248,71 +7255,66 @@ - - - + + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - - - - @@ -7326,80 +7328,80 @@ - - - - + + + + - - - + + + - - + + - - + + - - + + - - + + - - - + + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - + + - + @@ -7419,7 +7421,7 @@ - + @@ -7428,7 +7430,7 @@ - + @@ -7474,10 +7476,6 @@ - - - - @@ -7485,10 +7483,14 @@ - + + + + + @@ -7569,7 +7571,7 @@ - + @@ -7625,7 +7627,7 @@ - + @@ -7639,7 +7641,7 @@ - + @@ -7653,15 +7655,15 @@ - + - + - + @@ -7696,7 +7698,7 @@ - + @@ -7721,8 +7723,8 @@ - - + + @@ -7851,7 +7853,7 @@ - + @@ -7879,7 +7881,7 @@ - + @@ -7906,7 +7908,7 @@ - + @@ -7967,7 +7969,7 @@ - + @@ -7998,7 +8000,7 @@ - + @@ -8088,7 +8090,7 @@ - + @@ -8100,7 +8102,7 @@ - + @@ -8138,12 +8140,9 @@ - - - - - - + + + @@ -8162,6 +8161,9 @@ + + + @@ -8226,8 +8228,8 @@ - - + + @@ -8369,41 +8371,41 @@ - - + + - - + + - - + + - - + + - - - + + + - - + + - - + + - - + + - + @@ -8538,7 +8540,7 @@ - + @@ -8583,7 +8585,7 @@ - + @@ -8598,7 +8600,7 @@ - + @@ -8611,7 +8613,7 @@ - + @@ -8639,7 +8641,7 @@ - + @@ -8667,41 +8669,41 @@ - - + + - + - + - - + + - + - + - + - + - + - + - + @@ -8738,7 +8740,7 @@ - + @@ -8757,7 +8759,7 @@ - + @@ -8849,9 +8851,9 @@ - - - + + + @@ -8869,116 +8871,120 @@ - + + + + + - - + + - - + + - - - + + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - - + + + - - - - - + + + + + - - - - + + + + - - + + - - + + - - - + + + - - + + - - + + - - - + + + - - - + + + - - + + - - + + - - - + + + - + - + @@ -8994,7 +9000,7 @@ - + @@ -9016,7 +9022,7 @@ - + @@ -9345,10 +9351,6 @@ - - - - @@ -9681,11 +9683,11 @@ - + - + @@ -9699,7 +9701,7 @@ - + @@ -9717,7 +9719,7 @@ - + @@ -10803,6 +10805,10 @@ + + + + @@ -10837,7 +10843,7 @@
- + @@ -10868,61 +10874,61 @@ - + - + - - + + - + - + - + - + - + - + - + - - + + - - + + - - + + - + - + - - - + + + - - + + - + - - + + @@ -10954,69 +10960,69 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + @@ -11028,7 +11034,7 @@ - + @@ -11046,7 +11052,7 @@ - + @@ -11058,7 +11064,7 @@ - + @@ -11099,9 +11105,9 @@ - + - + @@ -11150,7 +11156,7 @@ - + @@ -11659,7 +11665,7 @@ - + @@ -11703,7 +11709,7 @@ - + @@ -11743,7 +11749,7 @@ - + @@ -12759,13 +12765,13 @@ - + - + @@ -12830,7 +12836,7 @@ - + @@ -12839,7 +12845,7 @@ - + @@ -12987,7 +12993,7 @@ - + @@ -13005,7 +13011,7 @@ - + @@ -13016,7 +13022,7 @@ - + @@ -13247,7 +13253,7 @@ - + @@ -13258,7 +13264,7 @@ - + @@ -13283,16 +13289,16 @@ - + - + - + @@ -13312,7 +13318,7 @@ - + @@ -13363,7 +13369,7 @@ - + @@ -13384,7 +13390,7 @@ - + @@ -13406,7 +13412,7 @@ - + @@ -13454,10 +13460,10 @@ - + - + @@ -13486,7 +13492,7 @@ - + @@ -13501,7 +13507,7 @@ - + @@ -13522,13 +13528,13 @@ - + - + - + @@ -13545,7 +13551,7 @@ - + @@ -13553,7 +13559,7 @@ - + @@ -13564,7 +13570,7 @@ - + @@ -13593,7 +13599,7 @@ - + @@ -13601,7 +13607,7 @@ - + @@ -13609,7 +13615,7 @@ - + @@ -13665,7 +13671,7 @@ - + @@ -14265,7 +14271,7 @@ - + @@ -14325,7 +14331,7 @@ - + @@ -14379,7 +14385,7 @@ - + @@ -14538,7 +14544,7 @@ - + @@ -14622,7 +14628,7 @@ - + @@ -15105,7 +15111,7 @@ - + @@ -15240,7 +15246,7 @@ - + @@ -15324,7 +15330,7 @@ - + @@ -15396,7 +15402,7 @@ - + @@ -15702,7 +15708,7 @@ - + @@ -15716,7 +15722,7 @@ - + @@ -15740,7 +15746,7 @@ - + @@ -15780,7 +15786,7 @@ - + @@ -15839,7 +15845,7 @@ - + @@ -16031,7 +16037,7 @@ - + @@ -16126,7 +16132,7 @@ - + @@ -16150,7 +16156,7 @@ - + @@ -16212,14 +16218,14 @@ - - - - + - + + + + @@ -16230,16 +16236,16 @@ - + - + - + - + @@ -16325,7 +16331,7 @@ - + @@ -16343,32 +16349,32 @@ - + - + - + - + - + - + - + @@ -16383,7 +16389,7 @@ - + @@ -16391,20 +16397,20 @@ - + - + - + - + @@ -16551,7 +16557,7 @@ - + @@ -16755,7 +16761,7 @@ - + @@ -16774,7 +16780,7 @@ - + @@ -16828,10 +16834,10 @@ - + - + @@ -16839,7 +16845,7 @@ - + @@ -16852,7 +16858,7 @@ - + @@ -16887,7 +16893,7 @@ - + @@ -17004,7 +17010,7 @@ - + @@ -17017,7 +17023,7 @@ - + @@ -17029,7 +17035,7 @@ - + @@ -17169,7 +17175,7 @@ - + @@ -17304,7 +17310,7 @@ - + @@ -17325,10 +17331,10 @@ - + - + @@ -17352,15 +17358,15 @@ - - - + + + - + @@ -17380,7 +17386,7 @@ - + @@ -17396,13 +17402,13 @@ - + - - - + + + @@ -17628,7 +17634,7 @@ - + @@ -17754,7 +17760,7 @@ - + @@ -17900,16 +17906,13 @@ - + - + - - - - + @@ -18929,7 +18932,7 @@ - + @@ -18967,7 +18970,7 @@
- + @@ -18975,10 +18978,10 @@
- + - + @@ -19012,7 +19015,7 @@
- + @@ -19941,61 +19944,61 @@ - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -20374,7 +20377,7 @@ - + @@ -20520,16 +20523,13 @@ - + - + - - - - + @@ -20702,7 +20702,7 @@
- + @@ -20835,38 +20835,38 @@ - + - + - + - + - + - + - + @@ -20981,7 +20981,7 @@ - + @@ -20993,7 +20993,7 @@ - + @@ -21049,7 +21049,7 @@ - + @@ -21104,7 +21104,7 @@ - + @@ -21129,7 +21129,7 @@ - + @@ -21189,7 +21189,7 @@ - + @@ -21273,30 +21273,30 @@ - - + + - + - + - + - + @@ -21307,7 +21307,7 @@ - + @@ -21335,7 +21335,7 @@ - + @@ -21375,7 +21375,7 @@ - + @@ -21395,7 +21395,7 @@ - + @@ -21408,7 +21408,7 @@ - + @@ -21509,13 +21509,13 @@ - + - + @@ -21564,7 +21564,7 @@ - + @@ -21734,16 +21734,21 @@ - + + + + + + - + - + @@ -21757,27 +21762,27 @@ - + - + - + - + @@ -21785,7 +21790,7 @@ - + @@ -21793,7 +21798,7 @@ - + @@ -21802,14 +21807,14 @@ - + - + @@ -21885,81 +21890,84 @@ - + - - + + - - + + - - - + + + - - + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - + - - + + + + + - - + + - - + + - - + + - - + + - + - + - + @@ -22124,7 +22132,7 @@ - + @@ -22215,7 +22223,7 @@ - + @@ -22771,17 +22779,17 @@ - + - + - + @@ -22870,7 +22878,7 @@ - + @@ -22881,7 +22889,7 @@ - + @@ -23033,7 +23041,7 @@ - + @@ -23047,7 +23055,7 @@ - + @@ -23171,7 +23179,7 @@ - + @@ -23181,7 +23189,7 @@ - + @@ -23267,7 +23275,7 @@ - + @@ -23281,7 +23289,7 @@ - + @@ -23386,7 +23394,7 @@ - + @@ -23458,7 +23466,7 @@ - + @@ -23563,21 +23571,21 @@ - + - + - + - + @@ -23586,7 +23594,7 @@ - + @@ -23660,7 +23668,7 @@ - + @@ -23876,7 +23884,7 @@ - + @@ -24217,13 +24225,13 @@
- - - + + + - + - + @@ -24240,7 +24248,7 @@ - + @@ -24296,28 +24304,28 @@ - - - + + + - + - + - + - + @@ -24397,32 +24405,32 @@ - - + + - - + + - - + + - - + + - - - + + + - + - + @@ -24438,20 +24446,26 @@ - - - - + + + + + + + + + + - - - - + + + + - + @@ -24467,7 +24481,7 @@ - + @@ -24539,7 +24553,7 @@ - + @@ -24548,7 +24562,7 @@ - + @@ -24584,7 +24598,7 @@ - + @@ -24596,7 +24610,7 @@ - + @@ -24681,31 +24695,31 @@ - - + + - + - + - + - + - + - + - + - + @@ -25405,7 +25419,7 @@
- + @@ -25612,14 +25626,14 @@
- + - + @@ -25638,7 +25652,7 @@ - + @@ -25875,7 +25889,7 @@ - + @@ -26132,7 +26146,7 @@
- + @@ -26163,7 +26177,7 @@ - + @@ -26175,10 +26189,10 @@ - + - + @@ -26358,33 +26372,33 @@
- - - - + + + + - + - - - - - + - + - + + + + + - - + + - + @@ -26392,7 +26406,7 @@ - + @@ -26418,7 +26432,7 @@ - + diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 7449a98e4326e8..565b3942ad2d45 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -10,9 +10,9 @@ extern "C" { /* Count of all "real" monitoring events (not derived from other events) */ -#define _PY_MONITORING_UNGROUPED_EVENTS 14 +#define _PY_MONITORING_UNGROUPED_EVENTS 15 /* Count of all monitoring events */ -#define _PY_MONITORING_EVENTS 16 +#define _PY_MONITORING_EVENTS 17 /* Table of which tools are active for each monitored event. */ typedef struct _Py_Monitors { diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index 9fb3952227af18..cfa5d09a4704f8 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -36,12 +36,13 @@ extern "C" { #define PY_MONITORING_EVENT_EXCEPTION_HANDLED 11 #define PY_MONITORING_EVENT_PY_UNWIND 12 #define PY_MONITORING_EVENT_PY_THROW 13 +#define PY_MONITORING_EVENT_RERAISE 14 /* Ancilliary events */ -#define PY_MONITORING_EVENT_C_RETURN 14 -#define PY_MONITORING_EVENT_C_RAISE 15 +#define PY_MONITORING_EVENT_C_RETURN 15 +#define PY_MONITORING_EVENT_C_RAISE 16 typedef uint32_t _PyMonitoringEventSet; diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index ef4a79aefd646b..8bf95a73d7db93 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -8,7 +8,7 @@ import textwrap import types import unittest - +import asyncio PAIR = (0,1) @@ -243,7 +243,6 @@ def check_events(self, func, expected=None): expected = func.events self.assertEqual(events, expected) - class MonitoringEventsTest(MonitoringEventsBase, unittest.TestCase): def test_just_pass(self): @@ -632,7 +631,7 @@ def __call__(self, code, offset, exc): class CheckEvents(MonitoringTestBase, unittest.TestCase): - def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): + def get_events(self, func, tool, recorders): try: self.assertEqual(sys.monitoring._all_events(), {}) event_list = [] @@ -646,19 +645,63 @@ def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecor sys.monitoring.set_events(tool, 0) for recorder in recorders: sys.monitoring.register_callback(tool, recorder.event_type, None) - self.assertEqual(event_list, expected) + return event_list finally: sys.monitoring.set_events(tool, 0) for recorder in recorders: sys.monitoring.register_callback(tool, recorder.event_type, None) + def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): + events = self.get_events(func, tool, recorders) + if events != expected: + print(events, file = sys.stderr) + self.assertEqual(events, expected) + + def check_balanced(self, func, recorders): + events = self.get_events(func, TEST_TOOL, recorders) + self.assertEqual(len(events)%2, 0) + for r, h in zip(events[::2],events[1::2]): + r0 = r[0] + self.assertIn(r0, ("raise", "reraise")) + h0 = h[0] + self.assertIn(h0, ("handled", "unwind")) + + + class StopiterationRecorder(ExceptionRecorder): event_type = E.STOP_ITERATION -class ExceptionMontoringTest(CheckEvents): +class ReraiseRecorder(ExceptionRecorder): + + event_type = E.RERAISE + + def __call__(self, code, offset, exc): + self.events.append(("reraise", type(exc))) + +class UnwindRecorder(ExceptionRecorder): + + event_type = E.PY_UNWIND + + def __call__(self, *args): + self.events.append(("unwind", None)) + +class ExceptionHandledRecorder(ExceptionRecorder): + + event_type = E.EXCEPTION_HANDLED + + def __call__(self, code, offset, exc): + self.events.append(("handled", type(exc))) - recorder = ExceptionRecorder +class ExceptionMonitoringTest(CheckEvents): + + + exception_recorders = ( + ExceptionRecorder, + ReraiseRecorder, + ExceptionHandledRecorder, + UnwindRecorder + ) def test_simple_try_except(self): @@ -672,6 +715,8 @@ def func1(): self.check_events(func1, [("raise", KeyError)]) + def test_implicit_stop_iteration(self): + def gen(): yield 1 return 2 @@ -682,6 +727,117 @@ def implicit_stop_iteration(): self.check_events(implicit_stop_iteration, [("raise", StopIteration)], recorders=(StopiterationRecorder,)) + initial = [ + ("raise", ZeroDivisionError), + ("handled", ZeroDivisionError) + ] + + reraise = [ + ("reraise", ZeroDivisionError), + ("handled", ZeroDivisionError) + ] + + def test_explicit_reraise(self): + + def func(): + try: + try: + 1/0 + except: + raise + except: + pass + + self.check_balanced( + func, + recorders = self.exception_recorders) + + def test_explicit_reraise_named(self): + + def func(): + try: + try: + 1/0 + except Exception as ex: + raise + except: + pass + + self.check_balanced( + func, + recorders = self.exception_recorders) + + def test_implicit_reraise(self): + + def func(): + try: + try: + 1/0 + except ValueError: + pass + except: + pass + + self.check_balanced( + func, + recorders = self.exception_recorders) + + + def test_implicit_reraise_named(self): + + def func(): + try: + try: + 1/0 + except ValueError as ex: + pass + except: + pass + + self.check_balanced( + func, + recorders = self.exception_recorders) + + def test_try_finally(self): + + def func(): + try: + try: + 1/0 + finally: + pass + except: + pass + + self.check_balanced( + func, + recorders = self.exception_recorders) + + def test_async_for(self): + + def func(): + + async def async_generator(): + for i in range(1): + raise ZeroDivisionError + yield i + + async def async_loop(): + try: + async for item in async_generator(): + pass + except Exception: + pass + + try: + async_loop().send(None) + except StopIteration: + pass + + self.check_balanced( + func, + recorders = self.exception_recorders) + class LineRecorder: event_type = E.LINE @@ -733,12 +889,12 @@ def func1(): line3 = 3 self.check_events(func1, recorders = MANY_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('call', 'func1', sys.monitoring.MISSING), ('line', 'func1', 1), ('line', 'func1', 2), ('line', 'func1', 3), - ('line', 'check_events', 11), + ('line', 'get_events', 11), ('call', 'set_events', 2)]) def test_c_call(self): @@ -749,14 +905,14 @@ def func2(): line3 = 3 self.check_events(func2, recorders = MANY_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('call', 'func2', sys.monitoring.MISSING), ('line', 'func2', 1), ('line', 'func2', 2), ('call', 'append', [2]), ('C return', 'append', [2]), ('line', 'func2', 3), - ('line', 'check_events', 11), + ('line', 'get_events', 11), ('call', 'set_events', 2)]) def test_try_except(self): @@ -770,7 +926,7 @@ def func3(): line = 6 self.check_events(func3, recorders = MANY_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('call', 'func3', sys.monitoring.MISSING), ('line', 'func3', 1), ('line', 'func3', 2), @@ -779,7 +935,7 @@ def func3(): ('line', 'func3', 4), ('line', 'func3', 5), ('line', 'func3', 6), - ('line', 'check_events', 11), + ('line', 'get_events', 11), ('call', 'set_events', 2)]) class InstructionRecorder: @@ -791,7 +947,7 @@ def __init__(self, events): def __call__(self, code, offset): # Filter out instructions in check_events to lower noise - if code.co_name != "check_events": + if code.co_name != "get_events": self.events.append(("instruction", code.co_name, offset)) @@ -808,7 +964,7 @@ def func1(): line3 = 3 self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func1', 1), ('instruction', 'func1', 2), ('instruction', 'func1', 4), @@ -819,7 +975,7 @@ def func1(): ('instruction', 'func1', 10), ('instruction', 'func1', 12), ('instruction', 'func1', 14), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) def test_c_call(self): @@ -829,7 +985,7 @@ def func2(): line3 = 3 self.check_events(func2, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func2', 1), ('instruction', 'func2', 2), ('instruction', 'func2', 4), @@ -843,7 +999,7 @@ def func2(): ('instruction', 'func2', 40), ('instruction', 'func2', 42), ('instruction', 'func2', 44), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) def test_try_except(self): @@ -856,7 +1012,7 @@ def func3(): line = 6 self.check_events(func3, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func3', 1), ('instruction', 'func3', 2), ('line', 'func3', 2), @@ -876,7 +1032,7 @@ def func3(): ('instruction', 'func3', 30), ('instruction', 'func3', 32), ('instruction', 'func3', 34), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) def test_with_restart(self): def func1(): @@ -885,7 +1041,7 @@ def func1(): line3 = 3 self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func1', 1), ('instruction', 'func1', 2), ('instruction', 'func1', 4), @@ -896,12 +1052,12 @@ def func1(): ('instruction', 'func1', 10), ('instruction', 'func1', 12), ('instruction', 'func1', 14), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) sys.monitoring.restart_events() self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func1', 1), ('instruction', 'func1', 2), ('instruction', 'func1', 4), @@ -912,7 +1068,7 @@ def func1(): ('instruction', 'func1', 10), ('instruction', 'func1', 12), ('instruction', 'func1', 14), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase): @@ -1114,7 +1270,7 @@ def func(): ('branch', 'func', 2, 2)]) self.check_events(func, recorders = JUMP_BRANCH_AND_LINE_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func', 1), ('line', 'func', 2), ('branch', 'func', 2, 2), @@ -1130,7 +1286,7 @@ def func(): ('jump', 'func', 4, 2), ('line', 'func', 2), ('branch', 'func', 2, 2), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) def test_except_star(self): @@ -1149,7 +1305,7 @@ def func(): self.check_events(func, recorders = JUMP_BRANCH_AND_LINE_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func', 1), ('line', 'func', 2), ('line', 'func', 3), @@ -1160,10 +1316,10 @@ def func(): ('jump', 'func', 5, 5), ('jump', 'func', 5, '[offset=114]'), ('branch', 'func', '[offset=120]', '[offset=122]'), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('line', 'func', 1), ('line', 'func', 2), ('line', 'func', 3), @@ -1177,7 +1333,7 @@ def func(): ('jump', 'func', 5, '[offset=114]'), ('branch', 'func', '[offset=120]', '[offset=122]'), ('return', None), - ('line', 'check_events', 11)]) + ('line', 'get_events', 11)]) class TestLoadSuperAttr(CheckEvents): RECORDERS = CallRecorder, LineRecorder, CRaiseRecorder, CReturnRecorder @@ -1229,7 +1385,7 @@ def f(): """ d = self._exec_super(codestr, optimized) expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('call', 'f', sys.monitoring.MISSING), ('line', 'f', 1), ('call', 'method', d["b"]), @@ -1242,7 +1398,7 @@ def f(): ('call', 'method', 1), ('line', 'method', 1), ('line', 'method', 1), - ('line', 'check_events', 11), + ('line', 'get_events', 11), ('call', 'set_events', 2), ] return d["f"], expected @@ -1280,7 +1436,7 @@ def f(): """ d = self._exec_super(codestr, optimized) expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('call', 'f', sys.monitoring.MISSING), ('line', 'f', 1), ('line', 'f', 2), @@ -1293,7 +1449,7 @@ def f(): ('C raise', 'super', 1), ('line', 'f', 3), ('line', 'f', 4), - ('line', 'check_events', 11), + ('line', 'get_events', 11), ('call', 'set_events', 2), ] return d["f"], expected @@ -1321,7 +1477,7 @@ def f(): """ d = self._exec_super(codestr, optimized) expected = [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('call', 'f', sys.monitoring.MISSING), ('line', 'f', 1), ('call', 'method', d["b"]), @@ -1330,7 +1486,7 @@ def f(): ('C return', 'super', sys.monitoring.MISSING), ('line', 'method', 2), ('line', 'method', 1), - ('line', 'check_events', 11), + ('line', 'get_events', 11), ('call', 'set_events', 2) ] return d["f"], expected @@ -1355,7 +1511,7 @@ def f(): def get_expected(name, call_method, ns): repr_arg = 0 if name == "int" else sys.monitoring.MISSING return [ - ('line', 'check_events', 10), + ('line', 'get_events', 10), ('call', 'f', sys.monitoring.MISSING), ('line', 'f', 1), ('call', 'method', ns["c"]), @@ -1368,7 +1524,7 @@ def get_expected(name, call_method, ns): ('C return', '__repr__', repr_arg), ] if call_method else [] ), - ('line', 'check_events', 11), + ('line', 'get_events', 11), ('call', 'set_events', 2), ] diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst new file mode 100644 index 00000000000000..52c49c3c0f5e7b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst @@ -0,0 +1,3 @@ +Add a ``RERAISE`` event to ``sys.monitoring``, which occurs when an +exception is reraised, either explicitly by a plain ``raise`` statement, or +implicitly in an ``except`` or ``finally`` block. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b914afa07fba40..adfa5ce00b6a04 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -612,7 +612,11 @@ dummy_func( exc = args[0]; /* fall through */ case 0: - ERROR_IF(do_raise(tstate, exc, cause), exception_unwind); + if (do_raise(tstate, exc, cause)) { + assert(oparg == 0); + monitor_reraise(tstate, frame, next_instr-1); + goto exception_unwind; + } break; default: _PyErr_SetString(tstate, PyExc_SystemError, @@ -944,6 +948,7 @@ dummy_func( assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); + monitor_reraise(tstate, frame, next_instr-1); goto exception_unwind; } @@ -955,6 +960,7 @@ dummy_func( else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); + monitor_reraise(tstate, frame, next_instr-1); goto exception_unwind; } } @@ -969,6 +975,7 @@ dummy_func( } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); + monitor_reraise(tstate, frame, next_instr-1); goto exception_unwind; } } diff --git a/Python/ceval.c b/Python/ceval.c index 72d679a4e3f537..899f135bdd635a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -185,6 +185,9 @@ lltrace_resume_frame(_PyInterpreterFrame *frame) static void monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); +static void monitor_reraise(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr); static int monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); @@ -923,7 +926,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } } monitor_raise(tstate, frame, next_instr-1); - exception_unwind: { /* We can't use frame->f_lasti here, as RERAISE may have set it */ @@ -2037,6 +2039,16 @@ monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame, do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RAISE); } +static void +monitor_reraise(PyThreadState *tstate, _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr) +{ + if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_RERAISE)) { + return; + } + do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RERAISE); +} + static int monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 281c8b5e5245bc..d5c048a881235e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -896,7 +896,11 @@ exc = args[0]; /* fall through */ case 0: - if (do_raise(tstate, exc, cause)) { STACK_SHRINK(oparg); goto exception_unwind; } + if (do_raise(tstate, exc, cause)) { + assert(oparg == 0); + monitor_reraise(tstate, frame, next_instr-1); + goto exception_unwind; + } break; default: _PyErr_SetString(tstate, PyExc_SystemError, @@ -904,12 +908,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 908 "Python/generated_cases.c.h" + #line 912 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 626 "Python/bytecodes.c" + #line 630 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -920,12 +924,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 924 "Python/generated_cases.c.h" + #line 928 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 639 "Python/bytecodes.c" + #line 643 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -938,12 +942,12 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 942 "Python/generated_cases.c.h" + #line 946 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 654 "Python/bytecodes.c" + #line 658 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -960,11 +964,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 964 "Python/generated_cases.c.h" + #line 968 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 673 "Python/bytecodes.c" + #line 677 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -978,11 +982,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 982 "Python/generated_cases.c.h" + #line 986 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 689 "Python/bytecodes.c" + #line 693 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1000,13 +1004,13 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1004 "Python/generated_cases.c.h" + #line 1008 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 709 "Python/bytecodes.c" + #line 713 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1019,16 +1023,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1023 "Python/generated_cases.c.h" + #line 1027 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 722 "Python/bytecodes.c" + #line 726 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1030 "Python/generated_cases.c.h" + #line 1034 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 727 "Python/bytecodes.c" + #line 731 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1041,7 +1045,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1045 "Python/generated_cases.c.h" + #line 1049 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1049,7 +1053,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 742 "Python/bytecodes.c" + #line 746 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1093,7 +1097,7 @@ } } - #line 1097 "Python/generated_cases.c.h" + #line 1101 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -1104,16 +1108,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 789 "Python/bytecodes.c" + #line 793 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1115 "Python/generated_cases.c.h" + #line 1119 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 796 "Python/bytecodes.c" + #line 800 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1131,7 +1135,7 @@ if (iter == NULL) goto pop_1_error; - #line 1135 "Python/generated_cases.c.h" + #line 1139 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -1143,7 +1147,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 822 "Python/bytecodes.c" + #line 826 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1190,7 +1194,7 @@ } } Py_DECREF(v); - #line 1194 "Python/generated_cases.c.h" + #line 1198 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1199,7 +1203,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 871 "Python/bytecodes.c" + #line 875 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1215,12 +1219,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1219 "Python/generated_cases.c.h" + #line 1223 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 889 "Python/bytecodes.c" + #line 893 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1237,12 +1241,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1241 "Python/generated_cases.c.h" + #line 1245 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 908 "Python/bytecodes.c" + #line 912 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1258,15 +1262,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1262 "Python/generated_cases.c.h" + #line 1266 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 926 "Python/bytecodes.c" + #line 930 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1270 "Python/generated_cases.c.h" + #line 1274 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1274,7 +1278,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 931 "Python/bytecodes.c" + #line 935 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1291,27 +1295,29 @@ assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); + monitor_reraise(tstate, frame, next_instr-1); goto exception_unwind; - #line 1296 "Python/generated_cases.c.h" + #line 1301 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 951 "Python/bytecodes.c" + #line 956 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1305 "Python/generated_cases.c.h" + #line 1310 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 954 "Python/bytecodes.c" + #line 959 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); + monitor_reraise(tstate, frame, next_instr-1); goto exception_unwind; } - #line 1315 "Python/generated_cases.c.h" + #line 1321 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1322,23 +1328,24 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 963 "Python/bytecodes.c" + #line 969 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1331 "Python/generated_cases.c.h" + #line 1337 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 968 "Python/bytecodes.c" + #line 974 "Python/bytecodes.c" none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); + monitor_reraise(tstate, frame, next_instr-1); goto exception_unwind; } - #line 1342 "Python/generated_cases.c.h" + #line 1349 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1347,9 +1354,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 977 "Python/bytecodes.c" + #line 984 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1353 "Python/generated_cases.c.h" + #line 1360 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1357,7 +1364,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 981 "Python/bytecodes.c" + #line 988 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1379,7 +1386,7 @@ if (true) goto error; } } - #line 1383 "Python/generated_cases.c.h" + #line 1390 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1387,33 +1394,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1006 "Python/bytecodes.c" + #line 1013 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1398 "Python/generated_cases.c.h" + #line 1405 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1013 "Python/bytecodes.c" + #line 1020 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1407 "Python/generated_cases.c.h" + #line 1414 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1020 "Python/bytecodes.c" + #line 1027 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1411 "Python/generated_cases.c.h" + #line 1418 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1024 "Python/bytecodes.c" + #line 1031 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1430,7 +1437,7 @@ name); goto error; } - #line 1434 "Python/generated_cases.c.h" + #line 1441 "Python/generated_cases.c.h" DISPATCH(); } @@ -1438,7 +1445,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1050 "Python/bytecodes.c" + #line 1057 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1451,11 +1458,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1455 "Python/generated_cases.c.h" + #line 1462 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1063 "Python/bytecodes.c" + #line 1070 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1459 "Python/generated_cases.c.h" + #line 1466 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1465,14 +1472,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1067 "Python/bytecodes.c" + #line 1074 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1476 "Python/generated_cases.c.h" + #line 1483 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1483,7 +1490,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1077 "Python/bytecodes.c" + #line 1084 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1491,7 +1498,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1495 "Python/generated_cases.c.h" + #line 1502 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1502,7 +1509,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1088 "Python/bytecodes.c" + #line 1095 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1510,7 +1517,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1514 "Python/generated_cases.c.h" + #line 1521 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1520,15 +1527,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1099 "Python/bytecodes.c" + #line 1106 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1528 "Python/generated_cases.c.h" + #line 1535 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1103 "Python/bytecodes.c" + #line 1110 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1532 "Python/generated_cases.c.h" + #line 1539 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1539,7 +1546,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1114 "Python/bytecodes.c" + #line 1121 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1555,12 +1562,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1559 "Python/generated_cases.c.h" + #line 1566 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1130 "Python/bytecodes.c" + #line 1137 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1564 "Python/generated_cases.c.h" + #line 1571 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1568,34 +1575,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1134 "Python/bytecodes.c" + #line 1141 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1575 "Python/generated_cases.c.h" + #line 1582 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1137 "Python/bytecodes.c" + #line 1144 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1579 "Python/generated_cases.c.h" + #line 1586 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1141 "Python/bytecodes.c" + #line 1148 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1589 "Python/generated_cases.c.h" + #line 1596 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1144 "Python/bytecodes.c" + #line 1151 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1593 "Python/generated_cases.c.h" + #line 1600 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1148 "Python/bytecodes.c" + #line 1155 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1607,7 +1614,7 @@ } goto error; } - #line 1611 "Python/generated_cases.c.h" + #line 1618 "Python/generated_cases.c.h" DISPATCH(); } @@ -1615,7 +1622,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1162 "Python/bytecodes.c" + #line 1169 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1623,7 +1630,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1627 "Python/generated_cases.c.h" + #line 1634 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1635,7 +1642,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1162 "Python/bytecodes.c" + #line 1169 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1643,13 +1650,13 @@ if (true) goto error; } Py_INCREF(locals); - #line 1647 "Python/generated_cases.c.h" + #line 1654 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1174 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1706,7 +1713,7 @@ } } } - #line 1710 "Python/generated_cases.c.h" + #line 1717 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1719,7 +1726,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1174 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1776,7 +1783,7 @@ } } } - #line 1780 "Python/generated_cases.c.h" + #line 1787 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1788,7 +1795,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1243 "Python/bytecodes.c" + #line 1250 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1840,7 +1847,7 @@ } } null = NULL; - #line 1844 "Python/generated_cases.c.h" + #line 1851 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1854,7 +1861,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1297 "Python/bytecodes.c" + #line 1304 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1865,7 +1872,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1869 "Python/generated_cases.c.h" + #line 1876 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1880,7 +1887,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1310 "Python/bytecodes.c" + #line 1317 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1895,7 +1902,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1899 "Python/generated_cases.c.h" + #line 1906 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1905,16 +1912,16 @@ } TARGET(DELETE_FAST) { - #line 1327 "Python/bytecodes.c" + #line 1334 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1913 "Python/generated_cases.c.h" + #line 1920 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1333 "Python/bytecodes.c" + #line 1340 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1923,12 +1930,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1927 "Python/generated_cases.c.h" + #line 1934 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1344 "Python/bytecodes.c" + #line 1351 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1939,14 +1946,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1943 "Python/generated_cases.c.h" + #line 1950 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1357 "Python/bytecodes.c" + #line 1364 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1981,14 +1988,14 @@ } Py_INCREF(value); } - #line 1985 "Python/generated_cases.c.h" + #line 1992 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1394 "Python/bytecodes.c" + #line 1401 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1996,7 +2003,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2000 "Python/generated_cases.c.h" + #line 2007 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2004,18 +2011,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1404 "Python/bytecodes.c" + #line 1411 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2013 "Python/generated_cases.c.h" + #line 2020 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1411 "Python/bytecodes.c" + #line 1418 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -2026,22 +2033,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2030 "Python/generated_cases.c.h" + #line 2037 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1424 "Python/bytecodes.c" + #line 1431 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2039 "Python/generated_cases.c.h" + #line 2046 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1426 "Python/bytecodes.c" + #line 1433 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2045 "Python/generated_cases.c.h" + #line 2052 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2051,10 +2058,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1430 "Python/bytecodes.c" + #line 1437 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2058 "Python/generated_cases.c.h" + #line 2065 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2064,10 +2071,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1435 "Python/bytecodes.c" + #line 1442 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2071 "Python/generated_cases.c.h" + #line 2078 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2077,7 +2084,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1440 "Python/bytecodes.c" + #line 1447 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2088,13 +2095,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2092 "Python/generated_cases.c.h" + #line 2099 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1451 "Python/bytecodes.c" + #line 1458 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2098 "Python/generated_cases.c.h" + #line 2105 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2103,13 +2110,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1458 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2109 "Python/generated_cases.c.h" + #line 2116 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1460 "Python/bytecodes.c" + #line 1467 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2113 "Python/generated_cases.c.h" + #line 2120 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2117,7 +2124,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1464 "Python/bytecodes.c" + #line 1471 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2132,7 +2139,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2136 "Python/generated_cases.c.h" + #line 2143 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2142,7 +2149,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1481 "Python/bytecodes.c" + #line 1488 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2150,13 +2157,13 @@ if (map == NULL) goto error; - #line 2154 "Python/generated_cases.c.h" + #line 2161 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1489 "Python/bytecodes.c" + #line 1496 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2160 "Python/generated_cases.c.h" + #line 2167 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2164,7 +2171,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1493 "Python/bytecodes.c" + #line 1500 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2204,7 +2211,7 @@ Py_DECREF(ann_dict); } } - #line 2208 "Python/generated_cases.c.h" + #line 2215 "Python/generated_cases.c.h" DISPATCH(); } @@ -2212,7 +2219,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1535 "Python/bytecodes.c" + #line 1542 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2222,14 +2229,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2226 "Python/generated_cases.c.h" + #line 2233 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1545 "Python/bytecodes.c" + #line 1552 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2233 "Python/generated_cases.c.h" + #line 2240 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2237,7 +2244,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1549 "Python/bytecodes.c" + #line 1556 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2245,12 +2252,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2249 "Python/generated_cases.c.h" + #line 2256 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1557 "Python/bytecodes.c" + #line 1564 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2254 "Python/generated_cases.c.h" + #line 2261 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2258,17 +2265,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1563 "Python/bytecodes.c" + #line 1570 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2267 "Python/generated_cases.c.h" + #line 2274 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1568 "Python/bytecodes.c" + #line 1575 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2272 "Python/generated_cases.c.h" + #line 2279 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2278,26 +2285,26 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1575 "Python/bytecodes.c" + #line 1582 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2288 "Python/generated_cases.c.h" + #line 2295 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1584 "Python/bytecodes.c" + #line 1591 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2301 "Python/generated_cases.c.h" + #line 2308 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2308,7 +2315,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1598 "Python/bytecodes.c" + #line 1605 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2350,16 +2357,16 @@ } } } - #line 2354 "Python/generated_cases.c.h" + #line 2361 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1640 "Python/bytecodes.c" + #line 1647 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2363 "Python/generated_cases.c.h" + #line 2370 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2374,20 +2381,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1647 "Python/bytecodes.c" + #line 1654 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2385 "Python/generated_cases.c.h" + #line 2392 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1654 "Python/bytecodes.c" + #line 1661 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2391 "Python/generated_cases.c.h" + #line 2398 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2402,7 +2409,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1658 "Python/bytecodes.c" + #line 1665 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2425,7 +2432,7 @@ res = res2; res2 = NULL; } - #line 2429 "Python/generated_cases.c.h" + #line 2436 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2439,7 +2446,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1697 "Python/bytecodes.c" + #line 1704 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2473,9 +2480,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2477 "Python/generated_cases.c.h" + #line 2484 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1731 "Python/bytecodes.c" + #line 1738 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2484,12 +2491,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2488 "Python/generated_cases.c.h" + #line 2495 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1740 "Python/bytecodes.c" + #line 1747 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2493 "Python/generated_cases.c.h" + #line 2500 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2503,7 +2510,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1745 "Python/bytecodes.c" + #line 1752 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2516,7 +2523,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2520 "Python/generated_cases.c.h" + #line 2527 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2531,7 +2538,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1761 "Python/bytecodes.c" + #line 1768 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2544,7 +2551,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2548 "Python/generated_cases.c.h" + #line 2555 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2559,7 +2566,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1777 "Python/bytecodes.c" + #line 1784 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2586,7 +2593,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2590 "Python/generated_cases.c.h" + #line 2597 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2601,7 +2608,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1807 "Python/bytecodes.c" + #line 1814 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2611,7 +2618,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2615 "Python/generated_cases.c.h" + #line 2622 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2626,7 +2633,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1820 "Python/bytecodes.c" + #line 1827 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2638,7 +2645,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2642 "Python/generated_cases.c.h" + #line 2649 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2652,7 +2659,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1835 "Python/bytecodes.c" + #line 1842 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2676,7 +2683,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2680 "Python/generated_cases.c.h" + #line 2687 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2684,7 +2691,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1861 "Python/bytecodes.c" + #line 1868 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2710,7 +2717,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2714 "Python/generated_cases.c.h" + #line 2721 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2718,7 +2725,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1889 "Python/bytecodes.c" + #line 1896 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2736,7 +2743,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2740 "Python/generated_cases.c.h" + #line 2747 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2747,7 +2754,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1909 "Python/bytecodes.c" + #line 1916 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2786,7 +2793,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2790 "Python/generated_cases.c.h" + #line 2797 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2797,7 +2804,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1950 "Python/bytecodes.c" + #line 1957 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2807,7 +2814,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2811 "Python/generated_cases.c.h" + #line 2818 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2819,7 +2826,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1969 "Python/bytecodes.c" + #line 1976 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2832,12 +2839,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2836 "Python/generated_cases.c.h" + #line 2843 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1982 "Python/bytecodes.c" + #line 1989 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2841 "Python/generated_cases.c.h" + #line 2848 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2848,7 +2855,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1986 "Python/bytecodes.c" + #line 1993 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2859,7 +2866,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2863 "Python/generated_cases.c.h" + #line 2870 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2870,7 +2877,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2000 "Python/bytecodes.c" + #line 2007 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2885,7 +2892,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2889 "Python/generated_cases.c.h" + #line 2896 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2896,7 +2903,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2018 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2908,7 +2915,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2912 "Python/generated_cases.c.h" + #line 2919 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2919,14 +2926,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2032 "Python/bytecodes.c" + #line 2039 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2925 "Python/generated_cases.c.h" + #line 2932 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2034 "Python/bytecodes.c" + #line 2041 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2930 "Python/generated_cases.c.h" + #line 2937 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2936,15 +2943,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2038 "Python/bytecodes.c" + #line 2045 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2942 "Python/generated_cases.c.h" + #line 2949 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2040 "Python/bytecodes.c" + #line 2047 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2948 "Python/generated_cases.c.h" + #line 2955 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2955,12 +2962,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2045 "Python/bytecodes.c" + #line 2052 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2961 "Python/generated_cases.c.h" + #line 2968 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2047 "Python/bytecodes.c" + #line 2054 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2968,10 +2975,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2972 "Python/generated_cases.c.h" + #line 2979 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2055 "Python/bytecodes.c" + #line 2062 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2980,7 +2987,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2984 "Python/generated_cases.c.h" + #line 2991 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2990,21 +2997,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2066 "Python/bytecodes.c" + #line 2073 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2997 "Python/generated_cases.c.h" + #line 3004 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2069 "Python/bytecodes.c" + #line 2076 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3004 "Python/generated_cases.c.h" + #line 3011 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2074 "Python/bytecodes.c" + #line 2081 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3008 "Python/generated_cases.c.h" + #line 3015 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3013,15 +3020,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2078 "Python/bytecodes.c" + #line 2085 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3020 "Python/generated_cases.c.h" + #line 3027 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2081 "Python/bytecodes.c" + #line 2088 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3025 "Python/generated_cases.c.h" + #line 3032 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3030,29 +3037,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2085 "Python/bytecodes.c" + #line 2092 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3038 "Python/generated_cases.c.h" + #line 3045 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2091 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" JUMPBY(oparg); - #line 3047 "Python/generated_cases.c.h" + #line 3054 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2095 "Python/bytecodes.c" + #line 2102 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3056 "Python/generated_cases.c.h" + #line 3063 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3060,15 +3067,15 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2101 "Python/bytecodes.c" + #line 2108 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3070 "Python/generated_cases.c.h" + #line 3077 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2107 "Python/bytecodes.c" + #line 2114 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3076,22 +3083,22 @@ if (err < 0) goto pop_1_error; } } - #line 3080 "Python/generated_cases.c.h" + #line 3087 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2117 "Python/bytecodes.c" + #line 2124 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3093 "Python/generated_cases.c.h" + #line 3100 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2123 "Python/bytecodes.c" + #line 2130 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3099,63 +3106,63 @@ if (err < 0) goto pop_1_error; } } - #line 3103 "Python/generated_cases.c.h" + #line 3110 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2133 "Python/bytecodes.c" + #line 2140 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3112 "Python/generated_cases.c.h" + #line 3119 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2135 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3117 "Python/generated_cases.c.h" + #line 3124 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2140 "Python/bytecodes.c" + #line 2147 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3129 "Python/generated_cases.c.h" + #line 3136 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2145 "Python/bytecodes.c" + #line 2152 "Python/bytecodes.c" } - #line 3133 "Python/generated_cases.c.h" + #line 3140 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2149 "Python/bytecodes.c" + #line 2156 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3146 "Python/generated_cases.c.h" + #line 3153 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2158 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3159 "Python/generated_cases.c.h" + #line 3166 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3166,16 +3173,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2166 "Python/bytecodes.c" + #line 2173 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3175 "Python/generated_cases.c.h" + #line 3182 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2171 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3183,7 +3190,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3187 "Python/generated_cases.c.h" + #line 3194 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3192,10 +3199,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2181 "Python/bytecodes.c" + #line 2188 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3199 "Python/generated_cases.c.h" + #line 3206 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3205,10 +3212,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2187 "Python/bytecodes.c" + #line 2194 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3212 "Python/generated_cases.c.h" + #line 3219 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3219,11 +3226,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2193 "Python/bytecodes.c" + #line 2200 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3227 "Python/generated_cases.c.h" + #line 3234 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3232,14 +3239,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2199 "Python/bytecodes.c" + #line 2206 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3239 "Python/generated_cases.c.h" + #line 3246 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2202 "Python/bytecodes.c" + #line 2209 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3243 "Python/generated_cases.c.h" + #line 3250 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3247,7 +3254,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2206 "Python/bytecodes.c" + #line 2213 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3270,11 +3277,11 @@ if (iter == NULL) { goto error; } - #line 3274 "Python/generated_cases.c.h" + #line 3281 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2229 "Python/bytecodes.c" + #line 2236 "Python/bytecodes.c" } - #line 3278 "Python/generated_cases.c.h" + #line 3285 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3285,7 +3292,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2248 "Python/bytecodes.c" + #line 2255 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3316,7 +3323,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3320 "Python/generated_cases.c.h" + #line 3327 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3324,7 +3331,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2281 "Python/bytecodes.c" + #line 2288 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3350,14 +3357,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3354 "Python/generated_cases.c.h" + #line 3361 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2309 "Python/bytecodes.c" + #line 2316 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3377,7 +3384,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3381 "Python/generated_cases.c.h" + #line 3388 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3387,7 +3394,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2331 "Python/bytecodes.c" + #line 2338 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3407,7 +3414,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3411 "Python/generated_cases.c.h" + #line 3418 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3417,7 +3424,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2353 "Python/bytecodes.c" + #line 2360 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3435,7 +3442,7 @@ if (next == NULL) { goto error; } - #line 3439 "Python/generated_cases.c.h" + #line 3446 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3444,7 +3451,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2373 "Python/bytecodes.c" + #line 2380 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3460,14 +3467,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3464 "Python/generated_cases.c.h" + #line 3471 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2391 "Python/bytecodes.c" + #line 2398 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3490,16 +3497,16 @@ Py_DECREF(enter); goto error; } - #line 3494 "Python/generated_cases.c.h" + #line 3501 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2414 "Python/bytecodes.c" + #line 2421 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3503 "Python/generated_cases.c.h" + #line 3510 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3511,7 +3518,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2424 "Python/bytecodes.c" + #line 2431 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3537,16 +3544,16 @@ Py_DECREF(enter); goto error; } - #line 3541 "Python/generated_cases.c.h" + #line 3548 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2450 "Python/bytecodes.c" + #line 2457 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3550 "Python/generated_cases.c.h" + #line 3557 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3558,7 +3565,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2459 "Python/bytecodes.c" + #line 2466 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3579,7 +3586,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3583 "Python/generated_cases.c.h" + #line 3590 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3588,7 +3595,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2482 "Python/bytecodes.c" + #line 2489 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3598,7 +3605,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3602 "Python/generated_cases.c.h" + #line 3609 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3612,7 +3619,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2494 "Python/bytecodes.c" + #line 2501 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3629,7 +3636,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3633 "Python/generated_cases.c.h" + #line 3640 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3643,7 +3650,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2513 "Python/bytecodes.c" + #line 2520 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3653,7 +3660,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3657 "Python/generated_cases.c.h" + #line 3664 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3667,7 +3674,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2525 "Python/bytecodes.c" + #line 2532 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3681,7 +3688,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3685 "Python/generated_cases.c.h" + #line 3692 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3690,16 +3697,16 @@ } TARGET(KW_NAMES) { - #line 2541 "Python/bytecodes.c" + #line 2548 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3698 "Python/generated_cases.c.h" + #line 3705 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2547 "Python/bytecodes.c" + #line 2554 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3712,7 +3719,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3716 "Python/generated_cases.c.h" + #line 3723 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3722,7 +3729,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2592 "Python/bytecodes.c" + #line 2599 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3804,7 +3811,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3808 "Python/generated_cases.c.h" + #line 3815 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3816,7 +3823,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2680 "Python/bytecodes.c" + #line 2687 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3826,7 +3833,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3830 "Python/generated_cases.c.h" + #line 3837 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3835,7 +3842,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2692 "Python/bytecodes.c" + #line 2699 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3861,7 +3868,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3865 "Python/generated_cases.c.h" + #line 3872 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3869,7 +3876,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2720 "Python/bytecodes.c" + #line 2727 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3905,7 +3912,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3909 "Python/generated_cases.c.h" + #line 3916 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3913,7 +3920,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2758 "Python/bytecodes.c" + #line 2765 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3923,7 +3930,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3927 "Python/generated_cases.c.h" + #line 3934 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3936,7 +3943,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2770 "Python/bytecodes.c" + #line 2777 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3947,7 +3954,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3951 "Python/generated_cases.c.h" + #line 3958 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3961,7 +3968,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2784 "Python/bytecodes.c" + #line 2791 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3972,7 +3979,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3976 "Python/generated_cases.c.h" + #line 3983 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3986,7 +3993,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2798 "Python/bytecodes.c" + #line 2805 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4008,7 +4015,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4012 "Python/generated_cases.c.h" + #line 4019 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4022,7 +4029,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2823 "Python/bytecodes.c" + #line 2830 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4050,7 +4057,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4054 "Python/generated_cases.c.h" + #line 4061 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4064,7 +4071,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2854 "Python/bytecodes.c" + #line 2861 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4096,7 +4103,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4100 "Python/generated_cases.c.h" + #line 4107 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4110,7 +4117,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2889 "Python/bytecodes.c" + #line 2896 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4142,7 +4149,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4146 "Python/generated_cases.c.h" + #line 4153 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4156,7 +4163,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2924 "Python/bytecodes.c" + #line 2931 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4181,7 +4188,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4185 "Python/generated_cases.c.h" + #line 4192 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4194,7 +4201,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2951 "Python/bytecodes.c" + #line 2958 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4221,7 +4228,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4225 "Python/generated_cases.c.h" + #line 4232 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4233,7 +4240,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2981 "Python/bytecodes.c" + #line 2988 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4251,14 +4258,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4255 "Python/generated_cases.c.h" + #line 4262 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3001 "Python/bytecodes.c" + #line 3008 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4289,7 +4296,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4293 "Python/generated_cases.c.h" + #line 4300 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4302,7 +4309,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3035 "Python/bytecodes.c" + #line 3042 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4331,7 +4338,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4335 "Python/generated_cases.c.h" + #line 4342 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4344,7 +4351,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3067 "Python/bytecodes.c" + #line 3074 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4373,7 +4380,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4377 "Python/generated_cases.c.h" + #line 4384 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4386,7 +4393,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3099 "Python/bytecodes.c" + #line 3106 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4414,7 +4421,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4418 "Python/generated_cases.c.h" + #line 4425 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4424,9 +4431,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3130 "Python/bytecodes.c" + #line 3137 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4430 "Python/generated_cases.c.h" + #line 4437 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4435,7 +4442,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3134 "Python/bytecodes.c" + #line 3141 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4497,14 +4504,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4501 "Python/generated_cases.c.h" + #line 4508 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3196 "Python/bytecodes.c" + #line 3203 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4508 "Python/generated_cases.c.h" + #line 4515 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4519,7 +4526,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3206 "Python/bytecodes.c" + #line 3213 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4548,14 +4555,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4552 "Python/generated_cases.c.h" + #line 4559 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3237 "Python/bytecodes.c" + #line 3244 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4576,7 +4583,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4580 "Python/generated_cases.c.h" + #line 4587 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4584,15 +4591,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3260 "Python/bytecodes.c" + #line 3267 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4590 "Python/generated_cases.c.h" + #line 4597 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3262 "Python/bytecodes.c" + #line 3269 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4596 "Python/generated_cases.c.h" + #line 4603 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4603,7 +4610,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3266 "Python/bytecodes.c" + #line 3273 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4638,7 +4645,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4642 "Python/generated_cases.c.h" + #line 4649 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4647,10 +4654,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3303 "Python/bytecodes.c" + #line 3310 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4654 "Python/generated_cases.c.h" + #line 4661 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4662,7 +4669,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3308 "Python/bytecodes.c" + #line 3315 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4677,12 +4684,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4681 "Python/generated_cases.c.h" + #line 4688 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3323 "Python/bytecodes.c" + #line 3330 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4686 "Python/generated_cases.c.h" + #line 4693 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4692,16 +4699,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3328 "Python/bytecodes.c" + #line 3335 "Python/bytecodes.c" assert(oparg >= 2); - #line 4698 "Python/generated_cases.c.h" + #line 4705 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3332 "Python/bytecodes.c" + #line 3339 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4713,26 +4720,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4717 "Python/generated_cases.c.h" + #line 4724 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3346 "Python/bytecodes.c" + #line 3353 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4723 "Python/generated_cases.c.h" + #line 4730 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3350 "Python/bytecodes.c" + #line 3357 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4730 "Python/generated_cases.c.h" + #line 4737 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3355 "Python/bytecodes.c" + #line 3362 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4741,12 +4748,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4745 "Python/generated_cases.c.h" + #line 4752 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3366 "Python/bytecodes.c" + #line 3373 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4755,12 +4762,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4759 "Python/generated_cases.c.h" + #line 4766 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3377 "Python/bytecodes.c" + #line 3384 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4772,12 +4779,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4776 "Python/generated_cases.c.h" + #line 4783 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3391 "Python/bytecodes.c" + #line 3398 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4789,30 +4796,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4793 "Python/generated_cases.c.h" + #line 4800 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3405 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4804 "Python/generated_cases.c.h" + #line 4811 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3413 "Python/bytecodes.c" + #line 3420 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4811 "Python/generated_cases.c.h" + #line 4818 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3418 "Python/bytecodes.c" + #line 3425 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4818 "Python/generated_cases.c.h" + #line 4825 "Python/generated_cases.c.h" } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 2fd3344b555a93..37933ffbd89b59 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -2037,6 +2037,7 @@ static const char *const event_names [] = { [PY_MONITORING_EVENT_C_RETURN] = "C_RETURN", [PY_MONITORING_EVENT_PY_THROW] = "PY_THROW", [PY_MONITORING_EVENT_RAISE] = "RAISE", + [PY_MONITORING_EVENT_RERAISE] = "RERAISE", [PY_MONITORING_EVENT_EXCEPTION_HANDLED] = "EXCEPTION_HANDLED", [PY_MONITORING_EVENT_C_RAISE] = "C_RAISE", [PY_MONITORING_EVENT_PY_UNWIND] = "PY_UNWIND", From 0902afbae29ef88bf9d212a7e11f9f17b6cbdeb5 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 28 Jul 2023 10:53:33 +0100 Subject: [PATCH 0468/1206] [3.12] GH-106895: Raise a `ValueError` when attempting to disable events that cannot be disabled. (GH-107337) (GH-107351) --- Include/internal/pycore_instruments.h | 3 +- Lib/test/test_monitoring.py | 52 ++++- ...-07-26-18-53-34.gh-issue-106895.DdEwV8.rst | 2 + Objects/classobject.c | 2 + Python/bytecodes.c | 7 +- Python/ceval.c | 13 +- Python/generated_cases.c.h | 193 +++++++++--------- Python/instrumentation.c | 79 ++++--- 8 files changed, 207 insertions(+), 144 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index cfa5d09a4704f8..ccccd54a2f70a2 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -28,7 +28,8 @@ extern "C" { #define PY_MONITORING_EVENT_BRANCH 8 #define PY_MONITORING_EVENT_STOP_ITERATION 9 -#define PY_MONITORING_INSTRUMENTED_EVENTS 10 +#define PY_MONITORING_IS_INSTRUMENTED_EVENT(ev) \ + ((ev) <= PY_MONITORING_EVENT_STOP_ITERATION) /* Other events, mainly exceptions */ diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 8bf95a73d7db93..9685a43810136c 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -136,20 +136,27 @@ def test_c_return_count(self): E = sys.monitoring.events -SIMPLE_EVENTS = [ +INSTRUMENTED_EVENTS = [ (E.PY_START, "start"), (E.PY_RESUME, "resume"), (E.PY_RETURN, "return"), (E.PY_YIELD, "yield"), (E.JUMP, "jump"), (E.BRANCH, "branch"), +] + +EXCEPT_EVENTS = [ (E.RAISE, "raise"), (E.PY_UNWIND, "unwind"), (E.EXCEPTION_HANDLED, "exception_handled"), +] + +SIMPLE_EVENTS = INSTRUMENTED_EVENTS + EXCEPT_EVENTS + [ (E.C_RAISE, "c_raise"), (E.C_RETURN, "c_return"), ] + SIMPLE_EVENT_SET = functools.reduce(operator.or_, [ev for (ev, _) in SIMPLE_EVENTS], 0) | E.CALL @@ -618,6 +625,49 @@ def func2(): self.check_lines(func2, [1,2,3,4,5,6]) +class TestDisable(MonitoringTestBase, unittest.TestCase): + + def gen(self, cond): + for i in range(10): + if cond: + yield 1 + else: + yield 2 + + def raise_handle_reraise(self): + try: + 1/0 + except: + raise + + def test_disable_legal_events(self): + for event, name in INSTRUMENTED_EVENTS: + try: + counter = CounterWithDisable() + counter.disable = True + sys.monitoring.register_callback(TEST_TOOL, event, counter) + sys.monitoring.set_events(TEST_TOOL, event) + for _ in self.gen(1): + pass + self.assertLess(counter.count, 4) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.register_callback(TEST_TOOL, event, None) + + + def test_disable_illegal_events(self): + for event, name in EXCEPT_EVENTS: + try: + counter = CounterWithDisable() + counter.disable = True + sys.monitoring.register_callback(TEST_TOOL, event, counter) + sys.monitoring.set_events(TEST_TOOL, event) + with self.assertRaises(ValueError): + self.raise_handle_reraise() + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.register_callback(TEST_TOOL, event, None) + class ExceptionRecorder: diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst new file mode 100644 index 00000000000000..370a29d34c860a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst @@ -0,0 +1,2 @@ +Raise a ``ValueError`` when a monitoring callback funtion returns +``DISABLE`` for events that cannot be disabled locally. diff --git a/Objects/classobject.c b/Objects/classobject.c index 71c4a4e5d0f8ab..12dc276f28976b 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -48,6 +48,7 @@ method_vectorcall(PyObject *method, PyObject *const *args, PyObject *self = PyMethod_GET_SELF(method); PyObject *func = PyMethod_GET_FUNCTION(method); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + assert(nargs == 0 || args[nargs-1]); PyObject *result; if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET) { @@ -56,6 +57,7 @@ method_vectorcall(PyObject *method, PyObject *const *args, nargs += 1; PyObject *tmp = newargs[0]; newargs[0] = self; + assert(newargs[nargs-1]); result = _PyObject_VectorcallTstate(tstate, func, newargs, nargs, kwnames); newargs[0] = tmp; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index adfa5ce00b6a04..7ee48c70b00054 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2476,7 +2476,12 @@ dummy_func( assert(val && PyExceptionInstance_Check(val)); exc = PyExceptionInstance_Class(val); tb = PyException_GetTraceback(val); - Py_XDECREF(tb); + if (tb == NULL) { + tb = Py_None; + } + else { + Py_DECREF(tb); + } assert(PyLong_Check(lasti)); (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[4] = {NULL, exc, val, tb}; diff --git a/Python/ceval.c b/Python/ceval.c index 899f135bdd635a..27dea27e812009 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -194,7 +194,7 @@ static int monitor_stop_iteration(PyThreadState *tstate, static void monitor_unwind(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); -static void monitor_handled(PyThreadState *tstate, +static int monitor_handled(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *exc); static void monitor_throw(PyThreadState *tstate, @@ -969,7 +969,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject *exc = _PyErr_GetRaisedException(tstate); PUSH(exc); JUMPTO(handler); - monitor_handled(tstate, frame, next_instr, exc); + if (monitor_handled(tstate, frame, next_instr, exc) < 0) { + goto exception_unwind; + } /* Resume normal execution */ DISPATCH(); } @@ -2007,6 +2009,7 @@ do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame, PyErr_SetRaisedException(exc); } else { + assert(PyErr_Occurred()); Py_DECREF(exc); } return err; @@ -2071,15 +2074,15 @@ monitor_unwind(PyThreadState *tstate, } -static void +static int monitor_handled(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *exc) { if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) { - return; + return 0; } - _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc); + return _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc); } static void diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d5c048a881235e..eabb9fe5fac4d5 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3579,14 +3579,19 @@ assert(val && PyExceptionInstance_Check(val)); exc = PyExceptionInstance_Class(val); tb = PyException_GetTraceback(val); - Py_XDECREF(tb); + if (tb == NULL) { + tb = Py_None; + } + else { + Py_DECREF(tb); + } assert(PyLong_Check(lasti)); (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[4] = {NULL, exc, val, tb}; res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3590 "Python/generated_cases.c.h" + #line 3595 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3595,7 +3600,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2489 "Python/bytecodes.c" + #line 2494 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3605,7 +3610,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3609 "Python/generated_cases.c.h" + #line 3614 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3619,7 +3624,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2501 "Python/bytecodes.c" + #line 2506 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3636,7 +3641,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3640 "Python/generated_cases.c.h" + #line 3645 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3650,7 +3655,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2520 "Python/bytecodes.c" + #line 2525 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3660,7 +3665,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3664 "Python/generated_cases.c.h" + #line 3669 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3674,7 +3679,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2532 "Python/bytecodes.c" + #line 2537 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3688,7 +3693,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3692 "Python/generated_cases.c.h" + #line 3697 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3697,16 +3702,16 @@ } TARGET(KW_NAMES) { - #line 2548 "Python/bytecodes.c" + #line 2553 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3705 "Python/generated_cases.c.h" + #line 3710 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2554 "Python/bytecodes.c" + #line 2559 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3719,7 +3724,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3723 "Python/generated_cases.c.h" + #line 3728 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3729,7 +3734,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2599 "Python/bytecodes.c" + #line 2604 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3811,7 +3816,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3815 "Python/generated_cases.c.h" + #line 3820 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3823,7 +3828,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2687 "Python/bytecodes.c" + #line 2692 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3833,7 +3838,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3837 "Python/generated_cases.c.h" + #line 3842 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3842,7 +3847,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2699 "Python/bytecodes.c" + #line 2704 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3868,7 +3873,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3872 "Python/generated_cases.c.h" + #line 3877 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3876,7 +3881,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2727 "Python/bytecodes.c" + #line 2732 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3912,7 +3917,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3916 "Python/generated_cases.c.h" + #line 3921 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3920,7 +3925,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2765 "Python/bytecodes.c" + #line 2770 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3930,7 +3935,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3934 "Python/generated_cases.c.h" + #line 3939 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3943,7 +3948,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2777 "Python/bytecodes.c" + #line 2782 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3954,7 +3959,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3958 "Python/generated_cases.c.h" + #line 3963 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3968,7 +3973,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2791 "Python/bytecodes.c" + #line 2796 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3979,7 +3984,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3983 "Python/generated_cases.c.h" + #line 3988 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3993,7 +3998,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2805 "Python/bytecodes.c" + #line 2810 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4015,7 +4020,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4019 "Python/generated_cases.c.h" + #line 4024 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4029,7 +4034,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2830 "Python/bytecodes.c" + #line 2835 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4057,7 +4062,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4061 "Python/generated_cases.c.h" + #line 4066 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4071,7 +4076,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2861 "Python/bytecodes.c" + #line 2866 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4103,7 +4108,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4107 "Python/generated_cases.c.h" + #line 4112 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4117,7 +4122,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2896 "Python/bytecodes.c" + #line 2901 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4149,7 +4154,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4153 "Python/generated_cases.c.h" + #line 4158 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4163,7 +4168,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2931 "Python/bytecodes.c" + #line 2936 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4188,7 +4193,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4192 "Python/generated_cases.c.h" + #line 4197 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4201,7 +4206,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2958 "Python/bytecodes.c" + #line 2963 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4228,7 +4233,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4232 "Python/generated_cases.c.h" + #line 4237 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4240,7 +4245,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2988 "Python/bytecodes.c" + #line 2993 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4258,14 +4263,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4262 "Python/generated_cases.c.h" + #line 4267 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3008 "Python/bytecodes.c" + #line 3013 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4296,7 +4301,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4300 "Python/generated_cases.c.h" + #line 4305 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4309,7 +4314,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3042 "Python/bytecodes.c" + #line 3047 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4338,7 +4343,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4342 "Python/generated_cases.c.h" + #line 4347 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4351,7 +4356,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3074 "Python/bytecodes.c" + #line 3079 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4380,7 +4385,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4384 "Python/generated_cases.c.h" + #line 4389 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4393,7 +4398,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3106 "Python/bytecodes.c" + #line 3111 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4421,7 +4426,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4425 "Python/generated_cases.c.h" + #line 4430 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4431,9 +4436,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3137 "Python/bytecodes.c" + #line 3142 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4437 "Python/generated_cases.c.h" + #line 4442 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4442,7 +4447,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3141 "Python/bytecodes.c" + #line 3146 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4504,14 +4509,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4508 "Python/generated_cases.c.h" + #line 4513 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3203 "Python/bytecodes.c" + #line 3208 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4515 "Python/generated_cases.c.h" + #line 4520 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4526,7 +4531,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3213 "Python/bytecodes.c" + #line 3218 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4555,14 +4560,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4559 "Python/generated_cases.c.h" + #line 4564 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3244 "Python/bytecodes.c" + #line 3249 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4583,7 +4588,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4587 "Python/generated_cases.c.h" + #line 4592 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4591,15 +4596,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3267 "Python/bytecodes.c" + #line 3272 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4597 "Python/generated_cases.c.h" + #line 4602 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3269 "Python/bytecodes.c" + #line 3274 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4603 "Python/generated_cases.c.h" + #line 4608 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4610,7 +4615,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3273 "Python/bytecodes.c" + #line 3278 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4645,7 +4650,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4649 "Python/generated_cases.c.h" + #line 4654 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4654,10 +4659,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3310 "Python/bytecodes.c" + #line 3315 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4661 "Python/generated_cases.c.h" + #line 4666 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4669,7 +4674,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3315 "Python/bytecodes.c" + #line 3320 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4684,12 +4689,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4688 "Python/generated_cases.c.h" + #line 4693 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3330 "Python/bytecodes.c" + #line 3335 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4693 "Python/generated_cases.c.h" + #line 4698 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4699,16 +4704,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3335 "Python/bytecodes.c" + #line 3340 "Python/bytecodes.c" assert(oparg >= 2); - #line 4705 "Python/generated_cases.c.h" + #line 4710 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3339 "Python/bytecodes.c" + #line 3344 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4720,26 +4725,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4724 "Python/generated_cases.c.h" + #line 4729 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3353 "Python/bytecodes.c" + #line 3358 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4730 "Python/generated_cases.c.h" + #line 4735 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3357 "Python/bytecodes.c" + #line 3362 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4737 "Python/generated_cases.c.h" + #line 4742 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3362 "Python/bytecodes.c" + #line 3367 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4748,12 +4753,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4752 "Python/generated_cases.c.h" + #line 4757 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3373 "Python/bytecodes.c" + #line 3378 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4762,12 +4767,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4766 "Python/generated_cases.c.h" + #line 4771 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3384 "Python/bytecodes.c" + #line 3389 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4779,12 +4784,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4783 "Python/generated_cases.c.h" + #line 4788 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3398 "Python/bytecodes.c" + #line 3403 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4796,30 +4801,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4800 "Python/generated_cases.c.h" + #line 4805 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3412 "Python/bytecodes.c" + #line 3417 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4811 "Python/generated_cases.c.h" + #line 4816 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3420 "Python/bytecodes.c" + #line 3425 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4818 "Python/generated_cases.c.h" + #line 4823 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3425 "Python/bytecodes.c" + #line 3430 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4825 "Python/generated_cases.c.h" + #line 4830 "Python/generated_cases.c.h" } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 37933ffbd89b59..05a53d04bf3cc4 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -696,29 +696,13 @@ instrument_per_instruction(PyCodeObject *code, int i) *opcode_ptr = INSTRUMENTED_INSTRUCTION; } -#ifndef NDEBUG -static bool -instruction_has_event(PyCodeObject *code, int offset) -{ - _Py_CODEUNIT instr = _PyCode_CODE(code)[offset]; - int opcode = instr.op.code; - if (opcode == INSTRUMENTED_LINE) { - opcode = code->_co_monitoring->lines[offset].original_opcode; - } - if (opcode == INSTRUMENTED_INSTRUCTION) { - opcode = code->_co_monitoring->per_instruction_opcodes[offset]; - } - return opcode_has_event(opcode); -} -#endif - static void remove_tools(PyCodeObject * code, int offset, int event, int tools) { assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); - assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); - assert(instruction_has_event(code, offset)); + assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event)); + assert(opcode_has_event(_Py_GetBaseOpcode(code, offset))); _PyCoMonitoringData *monitoring = code->_co_monitoring; if (monitoring && monitoring->tools) { monitoring->tools[offset] &= ~tools; @@ -773,7 +757,7 @@ add_tools(PyCodeObject * code, int offset, int event, int tools) { assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); - assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); + assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event)); assert(code->_co_monitoring); if (code->_co_monitoring && code->_co_monitoring->tools @@ -915,7 +899,7 @@ get_tools_for_instruction(PyCodeObject * code, int i, int event) event == PY_MONITORING_EVENT_C_RETURN); event = PY_MONITORING_EVENT_CALL; } - if (event < PY_MONITORING_INSTRUMENTED_EVENTS && monitoring->tools) { + if (PY_MONITORING_IS_INSTRUMENTED_EVENT(event) && monitoring->tools) { tools = monitoring->tools[i]; } else { @@ -926,6 +910,26 @@ get_tools_for_instruction(PyCodeObject * code, int i, int event) return tools; } +static const char *const event_names [] = { + [PY_MONITORING_EVENT_PY_START] = "PY_START", + [PY_MONITORING_EVENT_PY_RESUME] = "PY_RESUME", + [PY_MONITORING_EVENT_PY_RETURN] = "PY_RETURN", + [PY_MONITORING_EVENT_PY_YIELD] = "PY_YIELD", + [PY_MONITORING_EVENT_CALL] = "CALL", + [PY_MONITORING_EVENT_LINE] = "LINE", + [PY_MONITORING_EVENT_INSTRUCTION] = "INSTRUCTION", + [PY_MONITORING_EVENT_JUMP] = "JUMP", + [PY_MONITORING_EVENT_BRANCH] = "BRANCH", + [PY_MONITORING_EVENT_C_RETURN] = "C_RETURN", + [PY_MONITORING_EVENT_PY_THROW] = "PY_THROW", + [PY_MONITORING_EVENT_RAISE] = "RAISE", + [PY_MONITORING_EVENT_RERAISE] = "RERAISE", + [PY_MONITORING_EVENT_EXCEPTION_HANDLED] = "EXCEPTION_HANDLED", + [PY_MONITORING_EVENT_C_RAISE] = "C_RAISE", + [PY_MONITORING_EVENT_PY_UNWIND] = "PY_UNWIND", + [PY_MONITORING_EVENT_STOP_ITERATION] = "STOP_ITERATION", +}; + static int call_instrumentation_vector( PyThreadState *tstate, int event, @@ -973,7 +977,18 @@ call_instrumentation_vector( } else { /* DISABLE */ - remove_tools(code, offset, event, 1 << tool); + if (!PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) { + PyErr_Format(PyExc_ValueError, + "Cannot disable %s events. Callback removed.", + event_names[event]); + /* Clear tool to prevent infinite loop */ + Py_CLEAR(interp->monitoring_callables[tool][event]); + err = -1; + break; + } + else { + remove_tools(code, offset, event, 1 << tool); + } } } Py_DECREF(offset_obj); @@ -1251,7 +1266,7 @@ initialize_tools(PyCodeObject *code) assert(event > 0); } assert(event >= 0); - assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); + assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event)); tools[i] = code->_co_monitoring->active_monitors.tools[event]; CHECK(tools[i] != 0); } @@ -2024,26 +2039,6 @@ add_power2_constant(PyObject *obj, const char *name, int i) return err; } -static const char *const event_names [] = { - [PY_MONITORING_EVENT_PY_START] = "PY_START", - [PY_MONITORING_EVENT_PY_RESUME] = "PY_RESUME", - [PY_MONITORING_EVENT_PY_RETURN] = "PY_RETURN", - [PY_MONITORING_EVENT_PY_YIELD] = "PY_YIELD", - [PY_MONITORING_EVENT_CALL] = "CALL", - [PY_MONITORING_EVENT_LINE] = "LINE", - [PY_MONITORING_EVENT_INSTRUCTION] = "INSTRUCTION", - [PY_MONITORING_EVENT_JUMP] = "JUMP", - [PY_MONITORING_EVENT_BRANCH] = "BRANCH", - [PY_MONITORING_EVENT_C_RETURN] = "C_RETURN", - [PY_MONITORING_EVENT_PY_THROW] = "PY_THROW", - [PY_MONITORING_EVENT_RAISE] = "RAISE", - [PY_MONITORING_EVENT_RERAISE] = "RERAISE", - [PY_MONITORING_EVENT_EXCEPTION_HANDLED] = "EXCEPTION_HANDLED", - [PY_MONITORING_EVENT_C_RAISE] = "C_RAISE", - [PY_MONITORING_EVENT_PY_UNWIND] = "PY_UNWIND", - [PY_MONITORING_EVENT_STOP_ITERATION] = "STOP_ITERATION", -}; - /*[clinic input] monitoring._all_events [clinic start generated code]*/ From 3f167de440f65eb03f795e33b98cf3e84627e213 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 28 Jul 2023 11:30:16 +0100 Subject: [PATCH 0469/1206] [3.12] GH-106898: Add the exception as an argument to the `PY_UNWIND` event callback function. (GH-107347) (GH-107382) --- Lib/test/test_monitoring.py | 6 ++--- ...-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst | 3 +++ Python/ceval.c | 2 +- Python/legacy_tracing.c | 24 +++++++++++++++++-- 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 9685a43810136c..9d0ad6fa834bc7 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -715,7 +715,7 @@ def check_balanced(self, func, recorders): self.assertIn(r0, ("raise", "reraise")) h0 = h[0] self.assertIn(h0, ("handled", "unwind")) - + self.assertEqual(r[1], h[1]) class StopiterationRecorder(ExceptionRecorder): @@ -733,8 +733,8 @@ class UnwindRecorder(ExceptionRecorder): event_type = E.PY_UNWIND - def __call__(self, *args): - self.events.append(("unwind", None)) + def __call__(self, code, offset, exc): + self.events.append(("unwind", type(exc))) class ExceptionHandledRecorder(ExceptionRecorder): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst new file mode 100644 index 00000000000000..f1b1c4c64b4aca --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst @@ -0,0 +1,3 @@ +Add the exception as the third argument to ``PY_UNIND`` callbacks in +``sys.monitoring``. This makes the ``PY_UNWIND`` callback consistent with +the other exception hanlding callbacks. diff --git a/Python/ceval.c b/Python/ceval.c index 27dea27e812009..49474206162130 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2070,7 +2070,7 @@ monitor_unwind(PyThreadState *tstate, if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_UNWIND)) { return; } - _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_UNWIND, frame, instr); + do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_UNWIND); } diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index 5143b79b0864d8..c1c70f667ccd29 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -64,6 +64,16 @@ sys_profile_func3( return call_profile_func(self, args[2]); } +static PyObject * +sys_profile_unwind( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 3); + return call_profile_func(self, Py_None); +} + static PyObject * sys_profile_call_or_return( _PyLegacyEventHandler *self, PyObject *const *args, @@ -152,6 +162,16 @@ sys_trace_func2( return call_trace_func(self, Py_None); } +static PyObject * +sys_trace_unwind( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 3); + return call_trace_func(self, Py_None); +} + static PyObject * sys_trace_return( _PyLegacyEventHandler *self, PyObject *const *args, @@ -363,7 +383,7 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) return -1; } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, - (vectorcallfunc)sys_profile_func2, PyTrace_RETURN, + (vectorcallfunc)sys_profile_unwind, PyTrace_RETURN, PY_MONITORING_EVENT_PY_UNWIND, -1)) { return -1; } @@ -451,7 +471,7 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, - (vectorcallfunc)sys_trace_func2, PyTrace_RETURN, + (vectorcallfunc)sys_trace_unwind, PyTrace_RETURN, PY_MONITORING_EVENT_PY_UNWIND, -1)) { return -1; } From 0f42f41ea804e76bdb72c012d13b45a048e46c36 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 28 Jul 2023 03:35:20 -0700 Subject: [PATCH 0470/1206] [3.12] gh-107091: Fix some uses of :const: role (GH-107379) (GH-107384) It is for references, not for literals. (cherry picked from commit 0aa58fa7a62cd0ee7ec27fa87122425aeff0467d) Co-authored-by: Serhiy Storchaka --- Doc/library/fcntl.rst | 6 +++--- Doc/library/fractions.rst | 2 +- Doc/library/logging.handlers.rst | 4 ++-- Doc/library/os.rst | 4 ++-- Doc/library/signal.rst | 2 +- Doc/library/ssl.rst | 2 +- Doc/library/subprocess.rst | 10 +++++----- Doc/library/sys.rst | 8 ++++---- Doc/tools/.nitignore | 1 - Doc/whatsnew/3.3.rst | 20 ++++++++++---------- 10 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Doc/library/fcntl.rst b/Doc/library/fcntl.rst index 5a27646a96f591..969a79fa873395 100644 --- a/Doc/library/fcntl.rst +++ b/Doc/library/fcntl.rst @@ -172,9 +172,9 @@ The module defines the following functions: which the lock starts, relative to *whence*, and *whence* is as with :func:`io.IOBase.seek`, specifically: - * :const:`0` -- relative to the start of the file (:const:`os.SEEK_SET`) - * :const:`1` -- relative to the current buffer position (:const:`os.SEEK_CUR`) - * :const:`2` -- relative to the end of the file (:const:`os.SEEK_END`) + * ``0`` -- relative to the start of the file (:const:`os.SEEK_SET`) + * ``1`` -- relative to the current buffer position (:const:`os.SEEK_CUR`) + * ``2`` -- relative to the end of the file (:const:`os.SEEK_END`) The default for *start* is 0, which means to start at the beginning of the file. The default for *len* is 0 which means to lock to the end of the file. The diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst index fe2e8ab655edf8..509c63686f5a7f 100644 --- a/Doc/library/fractions.rst +++ b/Doc/library/fractions.rst @@ -25,7 +25,7 @@ another rational number, or from a string. The first version requires that *numerator* and *denominator* are instances of :class:`numbers.Rational` and returns a new :class:`Fraction` instance - with value ``numerator/denominator``. If *denominator* is :const:`0`, it + with value ``numerator/denominator``. If *denominator* is ``0``, it raises a :exc:`ZeroDivisionError`. The second version requires that *other_fraction* is an instance of :class:`numbers.Rational` and returns a :class:`Fraction` instance with the same value. The next two versions accept diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 72e5ffb3a1218e..2a825db54aed5c 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -97,7 +97,7 @@ sends logging output to a disk file. It inherits the output functionality from Returns a new instance of the :class:`FileHandler` class. The specified file is opened and used as the stream for logging. If *mode* is not specified, - :const:`'a'` is used. If *encoding* is not ``None``, it is used to open the file + ``'a'`` is used. If *encoding* is not ``None``, it is used to open the file with that encoding. If *delay* is true, then file opening is deferred until the first call to :meth:`emit`. By default, the file grows indefinitely. If *errors* is specified, it's used to determine how encoding errors are handled. @@ -182,7 +182,7 @@ for this value. Returns a new instance of the :class:`WatchedFileHandler` class. The specified file is opened and used as the stream for logging. If *mode* is not specified, - :const:`'a'` is used. If *encoding* is not ``None``, it is used to open the file + ``'a'`` is used. If *encoding* is not ``None``, it is used to open the file with that encoding. If *delay* is true, then file opening is deferred until the first call to :meth:`emit`. By default, the file grows indefinitely. If *errors* is provided, it determines how encoding errors are handled. diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 956eeffa1cd453..9735baa5bc0f3a 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -401,11 +401,11 @@ process and user. On macOS, :func:`getgroups` behavior differs somewhat from other Unix platforms. If the Python interpreter was built with a - deployment target of :const:`10.5` or earlier, :func:`getgroups` returns + deployment target of ``10.5`` or earlier, :func:`getgroups` returns the list of effective group ids associated with the current user process; this list is limited to a system-defined number of entries, typically 16, and may be modified by calls to :func:`setgroups` if suitably privileged. - If built with a deployment target greater than :const:`10.5`, + If built with a deployment target greater than ``10.5``, :func:`getgroups` returns the current group access list for the user associated with the effective user id of the process; the group access list may change over the lifetime of the process, it is not affected by diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst index e53315bee3ea3e..7ee5ece8859825 100644 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -656,7 +656,7 @@ The :mod:`signal` module defines the following functions: .. function:: sigtimedwait(sigset, timeout) Like :func:`sigwaitinfo`, but takes an additional *timeout* argument - specifying a timeout. If *timeout* is specified as :const:`0`, a poll is + specifying a timeout. If *timeout* is specified as ``0``, a poll is performed. Returns :const:`None` if a timeout occurs. .. availability:: Unix. diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 1f8bbe1e3de3ee..5d6bc829d68878 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -320,7 +320,7 @@ Random generation Mix the given *bytes* into the SSL pseudo-random number generator. The parameter *entropy* (a float) is a lower bound on the entropy contained in - string (so you can always use :const:`0.0`). See :rfc:`1750` for more + string (so you can always use ``0.0``). See :rfc:`1750` for more information on sources of entropy. .. versionchanged:: 3.5 diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index db05cb294d93f4..04340cca9e4a59 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -465,9 +465,9 @@ functions. :func:`open` function when creating the stdin/stdout/stderr pipe file objects: - - :const:`0` means unbuffered (read and write are one + - ``0`` means unbuffered (read and write are one system call and can return short) - - :const:`1` means line buffered + - ``1`` means line buffered (only usable if ``text=True`` or ``universal_newlines=True``) - any other positive value means use a buffer of approximately that size @@ -477,7 +477,7 @@ functions. .. versionchanged:: 3.3.1 *bufsize* now defaults to -1 to enable buffering by default to match the behavior that most code expects. In versions prior to Python 3.2.4 and - 3.3.1 it incorrectly defaulted to :const:`0` which was unbuffered + 3.3.1 it incorrectly defaulted to ``0`` which was unbuffered and allowed short reads. This was unintentional and did not match the behavior of Python 2 as most code expected. @@ -541,8 +541,8 @@ functions. :exc:`RuntimeError`. The new restriction may affect applications that are deployed in mod_wsgi, uWSGI, and other embedded environments. - If *close_fds* is true, all file descriptors except :const:`0`, :const:`1` and - :const:`2` will be closed before the child process is executed. Otherwise + If *close_fds* is true, all file descriptors except ``0``, ``1`` and + ``2`` will be closed before the child process is executed. Otherwise when *close_fds* is false, file descriptors obey their inheritable flag as described in :ref:`fd_inheritance`. diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index f6b67dc57c1873..a61737383e3939 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -877,19 +877,19 @@ always available. ``sys.getwindowsversion().major``. For compatibility with prior versions, only the first 5 elements are retrievable by indexing. - *platform* will be :const:`2 (VER_PLATFORM_WIN32_NT)`. + *platform* will be ``2`` (VER_PLATFORM_WIN32_NT). *product_type* may be one of the following values: +---------------------------------------+---------------------------------+ | Constant | Meaning | +=======================================+=================================+ - | :const:`1 (VER_NT_WORKSTATION)` | The system is a workstation. | + | ``1`` (VER_NT_WORKSTATION) | The system is a workstation. | +---------------------------------------+---------------------------------+ - | :const:`2 (VER_NT_DOMAIN_CONTROLLER)` | The system is a domain | + | ``2`` (VER_NT_DOMAIN_CONTROLLER) | The system is a domain | | | controller. | +---------------------------------------+---------------------------------+ - | :const:`3 (VER_NT_SERVER)` | The system is a server, but not | + | ``3`` (VER_NT_SERVER) | The system is a server, but not | | | a domain controller. | +---------------------------------------+---------------------------------+ diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 63223de613ff76..899e98acec8adf 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -100,7 +100,6 @@ Doc/library/faulthandler.rst Doc/library/fcntl.rst Doc/library/filecmp.rst Doc/library/fileinput.rst -Doc/library/fractions.rst Doc/library/ftplib.rst Doc/library/functions.rst Doc/library/functools.rst diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 6eb5818c317d80..1414b2f79a67d0 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1135,20 +1135,20 @@ API changes * The C module has the following context limits, depending on the machine architecture: - +-------------------+---------------------+------------------------------+ - | | 32-bit | 64-bit | - +===================+=====================+==============================+ - | :const:`MAX_PREC` | :const:`425000000` | :const:`999999999999999999` | - +-------------------+---------------------+------------------------------+ - | :const:`MAX_EMAX` | :const:`425000000` | :const:`999999999999999999` | - +-------------------+---------------------+------------------------------+ - | :const:`MIN_EMIN` | :const:`-425000000` | :const:`-999999999999999999` | - +-------------------+---------------------+------------------------------+ + +-------------------+----------------+-------------------------+ + | | 32-bit | 64-bit | + +===================+================+=========================+ + | :const:`MAX_PREC` | ``425000000`` | ``999999999999999999`` | + +-------------------+----------------+-------------------------+ + | :const:`MAX_EMAX` | ``425000000`` | ``999999999999999999`` | + +-------------------+----------------+-------------------------+ + | :const:`MIN_EMIN` | ``-425000000`` | ``-999999999999999999`` | + +-------------------+----------------+-------------------------+ * In the context templates (:class:`~decimal.DefaultContext`, :class:`~decimal.BasicContext` and :class:`~decimal.ExtendedContext`) the magnitude of :attr:`~decimal.Context.Emax` and - :attr:`~decimal.Context.Emin` has changed to :const:`999999`. + :attr:`~decimal.Context.Emin` has changed to ``999999``. * The :class:`~decimal.Decimal` constructor in decimal.py does not observe the context limits and converts values with arbitrary exponents or precision From 32502da987549a6bfe52c80a21244ab18f663e2b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 28 Jul 2023 12:54:57 -0700 Subject: [PATCH 0471/1206] [3.12] gh-107305: Update the C-API Docs for PEP 684 (gh-107324) (gh-107402) gh-107305: Update the C-API Docs for PEP 684 (gh-107324) (cherry picked from commit c0b81c4b5438a3565fadd9d6f5bc69f989a3fdee) Co-authored-by: Eric Snow --- Doc/c-api/init.rst | 209 ++++++++++++++++-- ...-07-26-16-33-04.gh-issue-107305.qB2LS4.rst | 3 + 2 files changed, 197 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 8a2543affc4d10..52824b6d88afda 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1494,7 +1494,95 @@ You can switch between sub-interpreters using the :c:func:`PyThreadState_Swap` function. You can create and destroy them using the following functions: -.. c:function:: PyThreadState* Py_NewInterpreter() +.. c:type:: PyInterpreterConfig + + Structure containing most parameters to configure a sub-interpreter. + Its values are used only in :c:func:`Py_NewInterpreterFromConfig` and + never modified by the runtime. + + .. versionadded:: 3.12 + + Structure fields: + + .. c:member:: int use_main_obmalloc + + If this is ``0`` then the sub-interpreter will use its own + "object" allocator state. + Otherwise it will use (share) the main interpreter's. + + If this is ``0`` then + :c:member:`~PyInterpreterConfig.check_multi_interp_extensions` + must be ``1`` (non-zero). + If this is ``1`` then :c:member:`~PyInterpreterConfig.gil` + must not be :c:macro:`PyInterpreterConfig_OWN_GIL`. + + .. c:member:: int allow_fork + + If this is ``0`` then the runtime will not support forking the + process in any thread where the sub-interpreter is currently active. + Otherwise fork is unrestricted. + + Note that the :mod:`subprocess` module still works + when fork is disallowed. + + .. c:member:: int allow_exec + + If this is ``0`` then the runtime will not support replacing the + current process via exec (e.g. :func:`os.execv`) in any thread + where the sub-interpreter is currently active. + Otherwise exec is unrestricted. + + Note that the :mod:`subprocess` module still works + when exec is disallowed. + + .. c:member:: int allow_threads + + If this is ``0`` then the sub-interpreter's :mod:`threading` module + won't create threads. + Otherwise threads are allowed. + + .. c:member:: int allow_daemon_threads + + If this is ``0`` then the sub-interpreter's :mod:`threading` module + won't create daemon threads. + Otherwise daemon threads are allowed (as long as + :c:member:`~PyInterpreterConfig.allow_threads` is non-zero). + + .. c:member:: int check_multi_interp_extensions + + If this is ``0`` then all extension modules may be imported, + including legacy (single-phase init) modules, + in any thread where the sub-interpreter is currently active. + Otherwise only multi-phase init extension modules + (see :pep:`489`) may be imported. + + This must be ``1`` (non-zero) if + :c:member:`~PyInterpreterConfig.use_main_obmalloc` is ``0``. + + .. c:member:: int gil + + This determines the operation of the GIL for the sub-interpreter. + It may be one of the following: + + .. c:namespace:: NULL + + .. c:macro:: PyInterpreterConfig_DEFAULT_GIL + + Use the default selection (:c:macro:`PyInterpreterConfig_SHARED_GIL`). + + .. c:macro:: PyInterpreterConfig_SHARED_GIL + + Use (share) the main interpreter's GIL. + + .. c:macro:: PyInterpreterConfig_OWN_GIL + + Use the sub-interpreter's own GIL. + + If this is :c:macro:`PyInterpreterConfig_OWN_GIL` then + :c:member:`PyInterpreterConfig.use_main_obmalloc` must be ``0``. + + +.. c:function:: PyStatus Py_NewInterpreterFromConfig(PyThreadState **tstate_p, const PyInterpreterConfig *config) .. index:: pair: module; builtins @@ -1514,16 +1602,47 @@ function. You can create and destroy them using the following functions: ``sys.stdout`` and ``sys.stderr`` (however these refer to the same underlying file descriptors). - The return value points to the first thread state created in the new + The given *config* controls the options with which the interpreter + is initialized. + + Upon success, *tstate_p* will be set to the first thread state + created in the new sub-interpreter. This thread state is made in the current thread state. Note that no actual thread is created; see the discussion of thread states - below. If creation of the new interpreter is unsuccessful, ``NULL`` is - returned; no exception is set since the exception state is stored in the - current thread state and there may not be a current thread state. (Like all - other Python/C API functions, the global interpreter lock must be held before - calling this function and is still held when it returns; however, unlike most - other Python/C API functions, there needn't be a current thread state on - entry.) + below. If creation of the new interpreter is unsuccessful, + *tstate_p* is set to ``NULL``; + no exception is set since the exception state is stored in the + current thread state and there may not be a current thread state. + + Like all other Python/C API functions, the global interpreter lock + must be held before calling this function and is still held when it + returns. Likewise a current thread state must be set on entry. On + success, the returned thread state will be set as current. If the + sub-interpreter is created with its own GIL then the GIL of the + calling interpreter will be released. When the function returns, + the new interpreter's GIL will be held by the current thread and + the previously interpreter's GIL will remain released here. + + .. versionadded:: 3.12 + + Sub-interpreters are most effective when isolated from each other, + with certain functionality restricted:: + + PyInterpreterConfig config = { + .use_main_obmalloc = 0, + .allow_fork = 0, + .allow_exec = 0, + .allow_threads = 1, + .allow_daemon_threads = 0, + .check_multi_interp_extensions = 1, + .gil = PyInterpreterConfig_OWN_GIL, + }; + PyThreadState *tstate = Py_NewInterpreterFromConfig(&config); + + Note that the config is used only briefly and does not get modified. + During initialization the config's values are converted into various + :c:type:`PyInterpreterState` values. A read-only copy of the config + may be stored internally on the :c:type:`PyInterpreterState`. .. index:: single: Py_FinalizeEx() @@ -1558,19 +1677,79 @@ function. You can create and destroy them using the following functions: .. index:: single: close() (in module os) +.. c:function:: PyThreadState* Py_NewInterpreter(void) + + .. index:: + pair: module; builtins + pair: module; __main__ + pair: module; sys + single: stdout (in module sys) + single: stderr (in module sys) + single: stdin (in module sys) + + Create a new sub-interpreter. This is essentially just a wrapper + around :c:func:`Py_NewInterpreterFromConfig` with a config that + preserves the existing behavior. The result is an unisolated + sub-interpreter that shares the main interpreter's GIL, allows + fork/exec, allows daemon threads, and allows single-phase init + modules. + + .. c:function:: void Py_EndInterpreter(PyThreadState *tstate) .. index:: single: Py_FinalizeEx() - Destroy the (sub-)interpreter represented by the given thread state. The given - thread state must be the current thread state. See the discussion of thread - states below. When the call returns, the current thread state is ``NULL``. All - thread states associated with this interpreter are destroyed. (The global - interpreter lock must be held before calling this function and is still held - when it returns.) :c:func:`Py_FinalizeEx` will destroy all sub-interpreters that + Destroy the (sub-)interpreter represented by the given thread state. + The given thread state must be the current thread state. See the + discussion of thread states below. When the call returns, + the current thread state is ``NULL``. All thread states associated + with this interpreter are destroyed. The global interpreter lock + used by the target interpreter must be held before calling this + function. No GIL is held when it returns. + + :c:func:`Py_FinalizeEx` will destroy all sub-interpreters that haven't been explicitly destroyed at that point. +A Per-Interpreter GIL +--------------------- + +Using :c:func:`Py_NewInterpreterFromConfig` you can create +a sub-interpreter that is completely isolated from other interpreters, +including having its own GIL. The most important benefit of this +isolation is that such an interpreter can execute Python code without +being blocked by other interpreters or blocking any others. Thus a +single Python process can truly take advantage of multiple CPU cores +when running Python code. The isolation also encourages a different +approach to concurrency than that of just using threads. +(See :pep:`554`.) + +Using an isolated interpreter requires vigilance in preserving that +isolation. That especially means not sharing any objects or mutable +state without guarantees about thread-safety. Even objects that are +otherwise immutable (e.g. ``None``, ``(1, 5)``) can't normally be shared +because of the refcount. One simple but less-efficient approach around +this is to use a global lock around all use of some state (or object). +Alternately, effectively immutable objects (like integers or strings) +can be made safe in spite of their refcounts by making them "immortal". +In fact, this has been done for the builtin singletons, small integers, +and a number of other builtin objects. + +If you preserve isolation then you will have access to proper multi-core +computing without the complications that come with free-threading. +Failure to preserve isolation will expose you to the full consequences +of free-threading, including races and hard-to-debug crashes. + +Aside from that, one of the main challenges of using multiple isolated +interpreters is how to communicate between them safely (not break +isolation) and efficiently. The runtime and stdlib do not provide +any standard approach to this yet. A future stdlib module would help +mitigate the effort of preserving isolation and expose effective tools +for communicating (and sharing) data between interpreters. + +.. versionadded:: 3.12 + + Bugs and caveats ---------------- diff --git a/Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst b/Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst new file mode 100644 index 00000000000000..038f9e68a5422a --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst @@ -0,0 +1,3 @@ +Add documentation for :c:type:`PyInterpreterConfig` and +:c:func:`Py_NewInterpreterFromConfig`. Also clarify some of the nearby docs +relative to per-interpreter GIL. From b4355de94705362a0b83b6ce92572f45273f64b9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 28 Jul 2023 13:57:26 -0700 Subject: [PATCH 0472/1206] [3.12] gh-104629: Build _testclinic extension module on Windows (GH-104723) (#107393) (cherry picked from commit 3a1d819ebc36189e086198212822c9b29384f242) Co-authored-by: Erlend E. Aasland --- PCbuild/_testclinic.vcxproj | 110 ++++++++++++++++++++++++++++ PCbuild/_testclinic.vcxproj.filters | 21 ++++++ PCbuild/pcbuild.proj | 2 +- PCbuild/pcbuild.sln | 35 +++++++++ PCbuild/readme.txt | 1 + Tools/msi/test/test_files.wxs | 2 +- 6 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 PCbuild/_testclinic.vcxproj create mode 100644 PCbuild/_testclinic.vcxproj.filters diff --git a/PCbuild/_testclinic.vcxproj b/PCbuild/_testclinic.vcxproj new file mode 100644 index 00000000000000..e319b3c0f42e0f --- /dev/null +++ b/PCbuild/_testclinic.vcxproj @@ -0,0 +1,110 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + ARM + + + PGInstrument + ARM64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + ARM + + + PGUpdate + ARM64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {A840DDFB-ED50-484B-B527-B32E7CF90FD5} + _testclinic + Win32Proj + false + + + + + DynamicLibrary + NotSet + + + + .pyd + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + + + + + {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} + false + + + + + + \ No newline at end of file diff --git a/PCbuild/_testclinic.vcxproj.filters b/PCbuild/_testclinic.vcxproj.filters new file mode 100644 index 00000000000000..4a2987eb27b223 --- /dev/null +++ b/PCbuild/_testclinic.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + {5b0a9282-a01c-4b83-9fd4-6deb6c558f9c} + + + {6a89c8a9-5b51-4525-ac5c-7d0a22f9657e} + + + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj index e13a0d409293f4..28269f08b42442 100644 --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -77,7 +77,7 @@ - + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln index 848d59504381cc..bdddec60daa82f 100644 --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -46,6 +46,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python", "python.vcxproj", {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E} = {EB6E69DD-04BF-4543-9B92-49FAABCEAC2E} {16BFE6F0-22EF-40B5-B831-7E937119EF10} = {16BFE6F0-22EF-40B5-B831-7E937119EF10} {FCBE1EF2-E0F0-40B1-88B5-00A35D378742} = {FCBE1EF2-E0F0-40B1-88B5-00A35D378742} + {A840DDFB-ED50-484B-B527-B32E7CF90FD5} = {A840DDFB-ED50-484B-B527-B32E7CF90FD5} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythoncore", "pythoncore.vcxproj", "{CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26}" @@ -78,6 +79,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ssl", "_ssl.vcxproj", "{C6 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testcapi", "_testcapi.vcxproj", "{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testclinic", "_testclinic.vcxproj", "{A840DDFB-ED50-484B-B527-B32E7CF90FD5}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testinternalcapi", "_testinternalcapi.vcxproj", "{900342D7-516A-4469-B1AD-59A66E49A25F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testimportmultiple", "_testimportmultiple.vcxproj", "{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}" @@ -592,6 +595,38 @@ Global {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|Win32.Build.0 = Release|Win32 {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.ActiveCfg = Release|x64 {6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Release|x64.Build.0 = Release|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|ARM.ActiveCfg = Debug|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|ARM.Build.0 = Debug|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|ARM64.Build.0 = Debug|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|Win32.ActiveCfg = Debug|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|Win32.Build.0 = Debug|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|x64.ActiveCfg = Debug|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Debug|x64.Build.0 = Debug|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|ARM.Build.0 = PGInstrument|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGInstrument|x64.Build.0 = PGInstrument|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|ARM.Build.0 = PGUpdate|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.PGUpdate|x64.Build.0 = PGUpdate|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|ARM.ActiveCfg = Release|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|ARM.Build.0 = Release|ARM + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|ARM64.ActiveCfg = Release|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|ARM64.Build.0 = Release|ARM64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|Win32.ActiveCfg = Release|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|Win32.Build.0 = Release|Win32 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|x64.ActiveCfg = Release|x64 + {A840DDFB-ED50-484B-B527-B32E7CF90FD5}.Release|x64.Build.0 = Release|x64 {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|ARM.ActiveCfg = Debug|ARM {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|ARM.Build.0 = Debug|ARM {900342D7-516A-4469-B1AD-59A66E49A25F}.Debug|ARM64.ActiveCfg = Debug|ARM64 diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 2ab4537b99882e..fe44ca40f4a0e1 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -144,6 +144,7 @@ _overlapped _socket _testbuffer _testcapi +_testclinic _testconsole _testimportmultiple _testmultiphase diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs index b5f68faef30e02..87e164cb6759f6 100644 --- a/Tools/msi/test/test_files.wxs +++ b/Tools/msi/test/test_files.wxs @@ -1,6 +1,6 @@ - + From e5ca2aa2c6d86842183565606afcd0f85ed3eac9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:09:34 -0700 Subject: [PATCH 0473/1206] [3.12] gh-107307: Update the importlib Docs for PEP 684 (gh-107400) (gh-107413) gh-107307: Update the importlib Docs for PEP 684 (gh-107400) (cherry picked from commit cf63df88d38ec3e6ebd44ed184312df9f07f9782) Co-authored-by: Eric Snow --- Doc/library/importlib.rst | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index a14e5a1a1a350f..1d378dbbdace5d 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -941,8 +941,15 @@ find and load modules. The *fullname* argument specifies the name of the module the loader is to support. The *path* argument is the path to the extension module's file. + Note that, by default, importing an extension module will fail + in subinterpreters if it doesn't implement multi-phase init + (see :pep:`489`), even if it would otherwise import successfully. + .. versionadded:: 3.3 + .. versionchanged:: 3.12 + Multi-phase init is now required for use in subinterpreters. + .. attribute:: name Name of the module the loader supports. @@ -1248,6 +1255,30 @@ an :term:`importer`. .. versionadded:: 3.7 +.. function:: _incompatible_extension_module_restrictions(*, disable_check) + + A context manager that can temporarily skip the compatibility check + for extension modules. By default the check is enabled and will fail + when a single-phase init module is imported in a subinterpreter. + It will also fail for a multi-phase init module that doesn't + explicitly support a per-interpreter GIL, when imported + in an interpreter with its own GIL. + + Note that this function is meant to accommodate an unusual case; + one which is likely to eventually go away. There's is a pretty good + chance this is not what you were looking for. + + You can get the same effect as this function by implementing the + basic interface of multi-phase init (:pep:`489`) and lying about + support for mulitple interpreters (or per-interpreter GIL). + + .. warning:: + Using this function to disable the check can lead to + unexpected behavior and even crashes. It should only be used during + extension module development. + + .. versionadded:: 3.12 + .. class:: LazyLoader(loader) A class which postpones the execution of the loader of a module until the From da151fdc7ac4a6d30740e4ef18071936a136790d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 28 Jul 2023 17:16:12 -0600 Subject: [PATCH 0474/1206] [3.12] gh-105699: Use a _Py_hashtable_t for the PyModuleDef Cache (gh-106974) (gh-107412) gh-105699: Use a _Py_hashtable_t for the PyModuleDef Cache (gh-106974) This fixes a crasher due to a race condition, triggered infrequently when two isolated (own GIL) subinterpreters simultaneously initialize their sys or builtins modules. The crash happened due the combination of the "detached" thread state we were using and the "last holder" logic we use for the GIL. It turns out it's tricky to use the same thread state for different threads. Who could have guessed? We solve the problem by eliminating the one object we were still sharing between interpreters. We replace it with a low-level hashtable, using the "raw" allocator to avoid tying it to the main interpreter. We also remove the accommodations for "detached" thread states, which were a dubious idea to start with. (cherry picked from commit 8ba4df91ae60833723d8d3b9afeb2b642f7176d5) --- Doc/data/python3.12.abi | 52948 +++++++++++------------ Include/internal/pycore_import.h | 13 +- Include/internal/pycore_pystate.h | 5 - Include/internal/pycore_runtime_init.h | 5 - Python/import.c | 224 +- Python/pystate.c | 69 - 6 files changed, 26592 insertions(+), 26672 deletions(-) diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 4c92e1d43c965e..5eec83faf1679b 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1,26484 +1,26464 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 0a9f24efbdb908..376957bdc99872 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -5,6 +5,9 @@ extern "C" { #endif +#include "pycore_hashtable.h" // _Py_hashtable_t +#include "pycore_time.h" // _PyTime_t + struct _import_runtime_state { /* The builtin modules (defined in config.c). */ @@ -15,19 +18,15 @@ struct _import_runtime_state { See PyInterpreterState.modules_by_index for more info. */ Py_ssize_t last_module_index; struct { - /* A thread state tied to the main interpreter, - used exclusively for when the extensions dict is access/modified - from an arbitrary thread. */ - PyThreadState main_tstate; - /* A lock to guard the dict. */ + /* A lock to guard the cache. */ PyThread_type_lock mutex; - /* A dict mapping (filename, name) to PyModuleDef for modules. + /* The actual cache of (filename, name, PyModuleDef) for modules. Only legacy (single-phase init) extension modules are added and only if they support multiple initialization (m_size >- 0) or are imported in the main interpreter. This is initialized lazily in _PyImport_FixupExtensionObject(). Modules are added there and looked up in _imp.find_extension(). */ - PyObject *dict; + _Py_hashtable_t *hashtable; } extensions; /* Package context -- the full module name for package imports */ const char * pkgcontext; diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 43652c4405ec1a..ccfc2586f0f235 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -128,11 +128,6 @@ PyAPI_FUNC(void) _PyThreadState_Init( PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); -extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); -extern void _PyThreadState_ClearDetached(PyThreadState *); -extern void _PyThreadState_BindDetached(PyThreadState *); -extern void _PyThreadState_UnbindDetached(PyThreadState *); - /* Other */ diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index b507de0437d9aa..4130188079cffa 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -41,11 +41,6 @@ extern PyTypeObject _PyExc_MemoryError; in accordance with the specification. */ \ .autoTSSkey = Py_tss_NEEDS_INIT, \ .parser = _parser_runtime_state_INIT, \ - .imports = { \ - .extensions = { \ - .main_tstate = _PyThreadState_INIT, \ - }, \ - }, \ .ceval = { \ .perf = _PyEval_RUNTIME_PERF_INIT, \ }, \ diff --git a/Python/import.c b/Python/import.c index a93a6450285cc1..f8f01f1bcd8c62 100644 --- a/Python/import.c +++ b/Python/import.c @@ -2,10 +2,12 @@ #include "Python.h" +#include "pycore_hashtable.h" // _Py_hashtable_new_full() #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // struct _import_runtime_state #include "pycore_namespace.h" // _PyNamespace_Type +#include "pycore_object.h" // _Py_SetImmortal() #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_pyhash.h" // _Py_KeyedHash() #include "pycore_pylifecycle.h" @@ -912,35 +914,79 @@ extensions_lock_release(void) dictionary, to avoid loading shared libraries twice. */ +static void * +hashtable_key_from_2_strings(PyObject *str1, PyObject *str2, const char sep) +{ + Py_ssize_t str1_len, str2_len; + const char *str1_data = PyUnicode_AsUTF8AndSize(str1, &str1_len); + const char *str2_data = PyUnicode_AsUTF8AndSize(str2, &str2_len); + if (str1_data == NULL || str2_data == NULL) { + return NULL; + } + /* Make sure sep and the NULL byte won't cause an overflow. */ + assert(SIZE_MAX - str1_len - str2_len > 2); + size_t size = str1_len + 1 + str2_len + 1; + + char *key = PyMem_RawMalloc(size); + if (key == NULL) { + PyErr_NoMemory(); + return NULL; + } + + strncpy(key, str1_data, str1_len); + key[str1_len] = sep; + strncpy(key + str1_len + 1, str2_data, str2_len + 1); + assert(strlen(key) == size - 1); + return key; +} + +static Py_uhash_t +hashtable_hash_str(const void *key) +{ + return _Py_HashBytes(key, strlen((const char *)key)); +} + +static int +hashtable_compare_str(const void *key1, const void *key2) +{ + return strcmp((const char *)key1, (const char *)key2) == 0; +} + static void -_extensions_cache_init(void) +hashtable_destroy_str(void *ptr) { - /* The runtime (i.e. main interpreter) must be initializing, - so we don't need to worry about the lock. */ - _PyThreadState_InitDetached(&EXTENSIONS.main_tstate, - _PyInterpreterState_Main()); + PyMem_RawFree(ptr); } +#define HTSEP ':' + static PyModuleDef * _extensions_cache_get(PyObject *filename, PyObject *name) { PyModuleDef *def = NULL; + void *key = NULL; extensions_lock_acquire(); - PyObject *key = PyTuple_Pack(2, filename, name); - if (key == NULL) { + if (EXTENSIONS.hashtable == NULL) { goto finally; } - PyObject *extensions = EXTENSIONS.dict; - if (extensions == NULL) { + key = hashtable_key_from_2_strings(filename, name, HTSEP); + if (key == NULL) { + goto finally; + } + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( + EXTENSIONS.hashtable, key); + if (entry == NULL) { goto finally; } - def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); + def = (PyModuleDef *)entry->value; finally: - Py_XDECREF(key); extensions_lock_release(); + if (key != NULL) { + PyMem_RawFree(key); + } return def; } @@ -948,124 +994,99 @@ static int _extensions_cache_set(PyObject *filename, PyObject *name, PyModuleDef *def) { int res = -1; - PyThreadState *oldts = NULL; extensions_lock_acquire(); - /* Swap to the main interpreter, if necessary. This matters if - the dict hasn't been created yet or if the item isn't in the - dict yet. In both cases we must ensure the relevant objects - are created using the main interpreter. */ - PyThreadState *main_tstate = &EXTENSIONS.main_tstate; - PyInterpreterState *interp = _PyInterpreterState_GET(); - if (!_Py_IsMainInterpreter(interp)) { - _PyThreadState_BindDetached(main_tstate); - oldts = _PyThreadState_Swap(interp->runtime, main_tstate); - assert(!_Py_IsMainInterpreter(oldts->interp)); - - /* Make sure the name and filename objects are owned - by the main interpreter. */ - name = PyUnicode_InternFromString(PyUnicode_AsUTF8(name)); - assert(name != NULL); - filename = PyUnicode_InternFromString(PyUnicode_AsUTF8(filename)); - assert(filename != NULL); + if (EXTENSIONS.hashtable == NULL) { + _Py_hashtable_allocator_t alloc = {PyMem_RawMalloc, PyMem_RawFree}; + EXTENSIONS.hashtable = _Py_hashtable_new_full( + hashtable_hash_str, + hashtable_compare_str, + hashtable_destroy_str, // key + /* There's no need to decref the def since it's immortal. */ + NULL, // value + &alloc + ); + if (EXTENSIONS.hashtable == NULL) { + PyErr_NoMemory(); + goto finally; + } } - PyObject *key = PyTuple_Pack(2, filename, name); + void *key = hashtable_key_from_2_strings(filename, name, HTSEP); if (key == NULL) { goto finally; } - PyObject *extensions = EXTENSIONS.dict; - if (extensions == NULL) { - extensions = PyDict_New(); - if (extensions == NULL) { + int already_set = 0; + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( + EXTENSIONS.hashtable, key); + if (entry == NULL) { + if (_Py_hashtable_set(EXTENSIONS.hashtable, key, def) < 0) { + PyMem_RawFree(key); + PyErr_NoMemory(); goto finally; } - EXTENSIONS.dict = extensions; - } - - PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); - if (PyErr_Occurred()) { - goto finally; } - else if (actual != NULL) { - /* We expect it to be static, so it must be the same pointer. */ - assert(def == actual); - res = 0; - goto finally; + else { + if (entry->value == NULL) { + entry->value = def; + } + else { + /* We expect it to be static, so it must be the same pointer. */ + assert((PyModuleDef *)entry->value == def); + already_set = 1; + } + PyMem_RawFree(key); } - - /* This might trigger a resize, which is why we must switch - to the main interpreter. */ - res = PyDict_SetItem(extensions, key, (PyObject *)def); - if (res < 0) { - res = -1; - goto finally; + if (!already_set) { + /* We assume that all module defs are statically allocated + and will never be freed. Otherwise, we would incref here. */ + _Py_SetImmortal(def); } res = 0; finally: - Py_XDECREF(key); - if (oldts != NULL) { - _PyThreadState_Swap(interp->runtime, oldts); - _PyThreadState_UnbindDetached(main_tstate); - Py_DECREF(name); - Py_DECREF(filename); - } extensions_lock_release(); return res; } -static int +static void _extensions_cache_delete(PyObject *filename, PyObject *name) { - int res = -1; - PyThreadState *oldts = NULL; + void *key = NULL; extensions_lock_acquire(); - PyObject *key = PyTuple_Pack(2, filename, name); - if (key == NULL) { + if (EXTENSIONS.hashtable == NULL) { + /* It was never added. */ goto finally; } - PyObject *extensions = EXTENSIONS.dict; - if (extensions == NULL) { - res = 0; + key = hashtable_key_from_2_strings(filename, name, HTSEP); + if (key == NULL) { goto finally; } - PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); - if (PyErr_Occurred()) { + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry( + EXTENSIONS.hashtable, key); + if (entry == NULL) { + /* It was never added. */ goto finally; } - else if (actual == NULL) { - /* It was already removed or never added. */ - res = 0; + if (entry->value == NULL) { + /* It was already removed. */ goto finally; } - - /* Swap to the main interpreter, if necessary. */ - PyThreadState *main_tstate = &EXTENSIONS.main_tstate; - PyInterpreterState *interp = _PyInterpreterState_GET(); - if (!_Py_IsMainInterpreter(interp)) { - _PyThreadState_BindDetached(main_tstate); - oldts = _PyThreadState_Swap(interp->runtime, main_tstate); - assert(!_Py_IsMainInterpreter(oldts->interp)); - } - - if (PyDict_DelItem(extensions, key) < 0) { - goto finally; - } - res = 0; + /* If we hadn't made the stored defs immortal, we would decref here. + However, this decref would be problematic if the module def were + dynamically allocated, it were the last ref, and this function + were called with an interpreter other than the def's owner. */ + entry->value = NULL; finally: - if (oldts != NULL) { - _PyThreadState_Swap(interp->runtime, oldts); - _PyThreadState_UnbindDetached(main_tstate); - } - Py_XDECREF(key); extensions_lock_release(); - return res; + if (key != NULL) { + PyMem_RawFree(key); + } } static void @@ -1073,11 +1094,12 @@ _extensions_cache_clear_all(void) { /* The runtime (i.e. main interpreter) must be finalizing, so we don't need to worry about the lock. */ - // XXX assert(_Py_IsMainInterpreter(_PyInterpreterState_GET())); - Py_CLEAR(EXTENSIONS.dict); - _PyThreadState_ClearDetached(&EXTENSIONS.main_tstate); + _Py_hashtable_destroy(EXTENSIONS.hashtable); + EXTENSIONS.hashtable = NULL; } +#undef HTSEP + static bool check_multi_interp_extensions(PyInterpreterState *interp) @@ -1238,6 +1260,8 @@ import_find_extension(PyThreadState *tstate, PyObject *name, PyObject *m_copy = def->m_base.m_copy; /* Module does not support repeated initialization */ if (m_copy == NULL) { + /* It might be a core module (e.g. sys & builtins), + for which we don't set m_copy. */ m_copy = get_core_module_dict(tstate->interp, name, filename); if (m_copy == NULL) { return NULL; @@ -1307,9 +1331,7 @@ clear_singlephase_extension(PyInterpreterState *interp, } /* Clear the cached module def. */ - if (_extensions_cache_delete(filename, name) < 0) { - return -1; - } + _extensions_cache_delete(filename, name); return 0; } @@ -3059,6 +3081,8 @@ void _PyImport_Fini(void) { /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ + // XXX Should we actually leave them (mostly) intact, since we don't + // ever dlclose() the module files? _extensions_cache_clear_all(); /* Use the same memory allocator as _PyImport_Init(). */ @@ -3096,10 +3120,6 @@ _PyImport_Fini2(void) PyStatus _PyImport_InitCore(PyThreadState *tstate, PyObject *sysmod, int importlib) { - if (_Py_IsMainInterpreter(tstate->interp)) { - _extensions_cache_init(); - } - // XXX Initialize here: interp->modules and interp->import_func. // XXX Initialize here: sys.modules and sys.meta_path. diff --git a/Python/pystate.c b/Python/pystate.c index e1261bf2acf958..8097124965cb7c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1632,75 +1632,6 @@ _PyThreadState_DeleteExcept(PyThreadState *tstate) } -//------------------------- -// "detached" thread states -//------------------------- - -void -_PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp) -{ - _PyRuntimeState *runtime = interp->runtime; - - HEAD_LOCK(runtime); - interp->threads.next_unique_id += 1; - uint64_t id = interp->threads.next_unique_id; - HEAD_UNLOCK(runtime); - - init_threadstate(tstate, interp, id); - // We do not call add_threadstate(). -} - -void -_PyThreadState_ClearDetached(PyThreadState *tstate) -{ - assert(!tstate->_status.bound); - assert(!tstate->_status.bound_gilstate); - assert(tstate->datastack_chunk == NULL); - assert(tstate->thread_id == 0); - assert(tstate->native_thread_id == 0); - assert(tstate->next == NULL); - assert(tstate->prev == NULL); - - PyThreadState_Clear(tstate); - clear_datastack(tstate); -} - -void -_PyThreadState_BindDetached(PyThreadState *tstate) -{ - assert(!_Py_IsMainInterpreter( - current_fast_get(tstate->interp->runtime)->interp)); - assert(_Py_IsMainInterpreter(tstate->interp)); - bind_tstate(tstate); - /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */ -} - -void -_PyThreadState_UnbindDetached(PyThreadState *tstate) -{ - assert(!_Py_IsMainInterpreter( - current_fast_get(tstate->interp->runtime)->interp)); - assert(_Py_IsMainInterpreter(tstate->interp)); - assert(tstate_is_alive(tstate)); - assert(!tstate->_status.active); - assert(gilstate_tss_get(tstate->interp->runtime) != tstate); - - unbind_tstate(tstate); - - /* This thread state may be bound/unbound repeatedly, - so we must erase evidence that it was ever bound (or unbound). */ - tstate->_status.bound = 0; - tstate->_status.unbound = 0; - - /* We must fully unlink the thread state from any OS thread, - to allow it to be bound more than once. */ - tstate->thread_id = 0; -#ifdef PY_HAVE_THREAD_NATIVE_ID - tstate->native_thread_id = 0; -#endif -} - - //---------- // accessors //---------- From 80aebd54c8c562d3d318c124ec735c5bf7f81d65 Mon Sep 17 00:00:00 2001 From: justdan6 <134341009+justdan6@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:29:31 -0600 Subject: [PATCH 0475/1206] [3.12] gh-106881: Check for linux/limits.h before including it (#107397) (#107414) * Check for linux/limits.h before including it Co-authored-by: Erlend E. Aasland (cherry picked from commit 11c055f5ff1a353de6d2e77f2af24aaa782878ba) --- .../Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst | 1 + Modules/posixmodule.c | 2 +- configure | 6 ++++++ configure.ac | 2 +- pyconfig.h.in | 3 +++ 5 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst diff --git a/Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst b/Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst new file mode 100644 index 00000000000000..40b2609e95c7e9 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst @@ -0,0 +1 @@ +Check for `linux/limits.h` before including it in `Modules/posixmodule.c`. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index fde1e4f461bc9e..342f393b1f0f9c 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -286,7 +286,7 @@ corresponding Unix manual entries for more information on calls."); # undef HAVE_SCHED_SETAFFINITY #endif -#if defined(HAVE_SYS_XATTR_H) && defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) +#if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LINUX_LIMITS_H) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) # define USE_XATTRS # include // Needed for XATTR_SIZE_MAX on musl libc. #endif diff --git a/configure b/configure index 3806da7723fdaf..b6f90bcd8c7300 100755 --- a/configure +++ b/configure @@ -10580,6 +10580,12 @@ if test "x$ac_cv_header_linux_fs_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_FS_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "linux/limits.h" "ac_cv_header_linux_limits_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_limits_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_LIMITS_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "linux/memfd.h" "ac_cv_header_linux_memfd_h" "$ac_includes_default" if test "x$ac_cv_header_linux_memfd_h" = xyes diff --git a/configure.ac b/configure.ac index 630db4bfbd53cc..ba768aea930714 100644 --- a/configure.ac +++ b/configure.ac @@ -2848,7 +2848,7 @@ AC_DEFINE([STDC_HEADERS], [1], # checks for header files AC_CHECK_HEADERS([ \ alloca.h asm/types.h bluetooth.h conio.h crypt.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \ - ieeefp.h io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/memfd.h \ + ieeefp.h io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/limits.h linux/memfd.h \ linux/random.h linux/soundcard.h \ linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \ sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \ diff --git a/pyconfig.h.in b/pyconfig.h.in index 7c87cd7d5ddd1f..ada9dccfef1084 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -727,6 +727,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FS_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_LIMITS_H + /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_MEMFD_H From 34e6e14602ae5d03040f8fa38f4a841c9fe66e10 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 29 Jul 2023 08:52:25 +0300 Subject: [PATCH 0476/1206] [3.12] gh-107091: Fix some uses of :func: role (GH-107378) (GH-107416) :c:func: or :c:macro: should be used instead. (cherry picked from commit 413ba8943e2f1d896a0568eb571a041b88589440) --- Doc/whatsnew/2.0.rst | 12 ++++++------ Doc/whatsnew/2.1.rst | 18 +++++++++--------- Misc/NEWS.d/3.11.0b1.rst | 2 +- Misc/NEWS.d/3.12.0a1.rst | 2 +- Misc/NEWS.d/3.12.0b1.rst | 2 +- Misc/NEWS.d/3.9.0a1.rst | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst index 0eefefd863a68f..5e9d03e48d97c1 100644 --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -664,7 +664,7 @@ extra set of parentheses to pass both values as a tuple: ``L.append( (1,2) )``. The earlier versions of these methods were more forgiving because they used an old function in Python's C interface to parse their arguments; 2.0 modernizes -them to use :func:`PyArg_ParseTuple`, the current argument parsing function, +them to use :c:func:`PyArg_ParseTuple`, the current argument parsing function, which provides more helpful error messages and treats multi-argument calls as errors. If you absolutely must use 2.0 but can't fix your code, you can edit :file:`Objects/listobject.c` and define the preprocessor symbol @@ -766,7 +766,7 @@ file, :file:`Include/pyport.h`. Vladimir Marangozov's long-awaited malloc restructuring was completed, to make it easy to have the Python interpreter use a custom allocator instead of C's -standard :func:`malloc`. For documentation, read the comments in +standard :c:func:`malloc`. For documentation, read the comments in :file:`Include/pymem.h` and :file:`Include/objimpl.h`. For the lengthy discussions during which the interface was hammered out, see the web archives of the 'patches' and 'python-dev' lists at python.org. @@ -794,15 +794,15 @@ are generating Python code would run into this limit. A patch by Charles G. Waldman raises the limit from ``2**16`` to ``2**32``. Three new convenience functions intended for adding constants to a module's -dictionary at module initialization time were added: :func:`PyModule_AddObject`, -:func:`PyModule_AddIntConstant`, and :func:`PyModule_AddStringConstant`. Each +dictionary at module initialization time were added: :c:func:`PyModule_AddObject`, +:c:func:`PyModule_AddIntConstant`, and :c:func:`PyModule_AddStringConstant`. Each of these functions takes a module object, a null-terminated C string containing the name to be added, and a third argument for the value to be assigned to the name. This third argument is, respectively, a Python object, a C long, or a C string. -A wrapper API was added for Unix-style signal handlers. :func:`PyOS_getsig` gets -a signal handler and :func:`PyOS_setsig` will set a new handler. +A wrapper API was added for Unix-style signal handlers. :c:func:`PyOS_getsig` gets +a signal handler and :c:func:`PyOS_setsig` will set a new handler. .. ====================================================================== diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst index 676da702b39693..f0e1ded75a9d27 100644 --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -692,8 +692,8 @@ applied, and 136 bugs fixed; both figures are likely to be underestimates. Some of the more notable changes are: * A specialized object allocator is now optionally available, that should be - faster than the system :func:`malloc` and have less memory overhead. The - allocator uses C's :func:`malloc` function to get large pools of memory, and + faster than the system :c:func:`malloc` and have less memory overhead. The + allocator uses C's :c:func:`!malloc` function to get large pools of memory, and then fulfills smaller memory requests from these pools. It can be enabled by providing the :option:`!--with-pymalloc` option to the :program:`configure` script; see :file:`Objects/obmalloc.c` for the implementation details. @@ -701,13 +701,13 @@ of the more notable changes are: Authors of C extension modules should test their code with the object allocator enabled, because some incorrect code may break, causing core dumps at runtime. There are a bunch of memory allocation functions in Python's C API that have - previously been just aliases for the C library's :func:`malloc` and - :func:`free`, meaning that if you accidentally called mismatched functions, the + previously been just aliases for the C library's :c:func:`malloc` and + :c:func:`free`, meaning that if you accidentally called mismatched functions, the error wouldn't be noticeable. When the object allocator is enabled, these - functions aren't aliases of :func:`malloc` and :func:`free` any more, and + functions aren't aliases of :c:func:`!malloc` and :c:func:`!free` any more, and calling the wrong function to free memory will get you a core dump. For - example, if memory was allocated using :func:`PyMem_New`, it has to be freed - using :func:`PyMem_Del`, not :func:`free`. A few modules included with Python + example, if memory was allocated using :c:macro:`PyMem_New`, it has to be freed + using :c:func:`PyMem_Del`, not :c:func:`!free`. A few modules included with Python fell afoul of this and had to be fixed; doubtless there are more third-party modules that will have the same problem. @@ -717,7 +717,7 @@ of the more notable changes are: complain about its lack of speed, and because it's often been used as a naïve benchmark. The :meth:`readline` method of file objects has therefore been rewritten to be much faster. The exact amount of the speedup will vary from - platform to platform depending on how slow the C library's :func:`getc` was, but + platform to platform depending on how slow the C library's :c:func:`!getc` was, but is around 66%, and potentially much faster on some particular operating systems. Tim Peters did much of the benchmarking and coding for this change, motivated by a discussion in comp.lang.python. @@ -770,7 +770,7 @@ of the more notable changes are: reorganization done by Jeremy Hylton. * C extensions which import other modules have been changed to use - :func:`PyImport_ImportModule`, which means that they will use any import hooks + :c:func:`PyImport_ImportModule`, which means that they will use any import hooks that have been installed. This is also encouraged for third-party extensions that need to import some other module from C code. diff --git a/Misc/NEWS.d/3.11.0b1.rst b/Misc/NEWS.d/3.11.0b1.rst index ad52bd14dbfd1d..6b601489a77285 100644 --- a/Misc/NEWS.d/3.11.0b1.rst +++ b/Misc/NEWS.d/3.11.0b1.rst @@ -1799,7 +1799,7 @@ The documentation now lists which members of C structs are part of the .. nonce: FIVe9I .. section: Documentation -All docstrings in code snippets are now wrapped into :func:`PyDoc_STR` to +All docstrings in code snippets are now wrapped into :c:macro:`PyDoc_STR` to follow the guideline of `PEP 7's Documentation Strings paragraph `_. Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 51b5c6e35a4f27..1888cae0ba720d 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -203,7 +203,7 @@ the interpreter. .. nonce: LYAWlE .. section: Core and Builtins -Bugfix: :func:`PyFunction_GetAnnotations` should return a borrowed +Bugfix: :c:func:`PyFunction_GetAnnotations` should return a borrowed reference. It was returning a new reference. .. diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index acb68db2db912b..23540f71a347cf 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -1205,7 +1205,7 @@ the future, it will raise a ``KeyError``. Fixed a bug where :mod:`pdb` crashes when reading source file with different encoding by replacing :func:`io.open` with :func:`io.open_code`. The new -method would also call into the hook set by :func:`PyFile_SetOpenCodeHook`. +method would also call into the hook set by :c:func:`PyFile_SetOpenCodeHook`. .. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 5e6fa6759d5779..85473da78bd438 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -5686,7 +5686,7 @@ positional argument. .. nonce: zrmgki .. section: C API -Add :func:`PyConfig_SetWideStringList` function. +Add :c:func:`PyConfig_SetWideStringList` function. .. From d514e1439f396d984f4f886e19c47f56e565a7d1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 29 Jul 2023 09:16:27 +0300 Subject: [PATCH 0477/1206] [3.12] gh-101100: Sphinx warnings: pick the low hanging fruits (GH-107386) (GH-107419) (cherry picked from commit f2d07d3289947d10b065b2bb7670c8fb6b6582f2) --- Doc/c-api/bool.rst | 6 +++++ Doc/faq/extending.rst | 4 +-- Doc/howto/curses.rst | 2 +- Doc/install/index.rst | 2 +- Doc/library/asyncio-extending.rst | 2 +- Doc/library/asyncio-future.rst | 2 +- Doc/library/bz2.rst | 3 ++- Doc/library/code.rst | 4 +-- Doc/library/concurrent.rst | 4 +-- Doc/library/curses.rst | 2 ++ Doc/library/email.charset.rst | 2 +- Doc/library/email.encoders.rst | 2 +- Doc/library/email.generator.rst | 4 +-- Doc/library/email.message.rst | 8 +++--- Doc/library/email.parser.rst | 4 +-- Doc/library/filecmp.rst | 2 +- Doc/library/fileinput.rst | 2 +- Doc/library/graphlib.rst | 4 +-- Doc/library/gzip.rst | 4 +-- Doc/library/hashlib.rst | 6 ++--- Doc/library/importlib.resources.abc.rst | 6 ++--- Doc/library/json.rst | 6 ++--- Doc/library/logging.rst | 30 ++++++++++----------- Doc/library/lzma.rst | 3 ++- Doc/library/msvcrt.rst | 2 +- Doc/library/netrc.rst | 16 ++++++++--- Doc/library/operator.rst | 6 ++--- Doc/library/poplib.rst | 2 +- Doc/library/pprint.rst | 2 +- Doc/library/pty.rst | 2 +- Doc/library/sched.rst | 2 +- Doc/library/selectors.rst | 8 +++--- Doc/library/shutil.rst | 2 +- Doc/library/stat.rst | 8 +++--- Doc/library/stdtypes.rst | 2 +- Doc/library/sysconfig.rst | 2 +- Doc/library/textwrap.rst | 4 +-- Doc/library/urllib.error.rst | 6 +++-- Doc/library/winreg.rst | 8 +++--- Doc/library/winsound.rst | 4 +-- Doc/library/xml.rst | 8 +++--- Doc/library/xml.sax.handler.rst | 2 +- Doc/library/xml.sax.utils.rst | 2 +- Doc/library/xmlrpc.rst | 4 +-- Doc/reference/datamodel.rst | 8 +++--- Doc/reference/expressions.rst | 2 +- Doc/reference/lexical_analysis.rst | 2 +- Doc/tools/.nitignore | 36 ------------------------- Doc/tutorial/errors.rst | 4 +-- Doc/tutorial/interactive.rst | 2 +- Doc/whatsnew/3.0.rst | 2 +- Misc/NEWS.d/3.11.0a6.rst | 2 +- 52 files changed, 125 insertions(+), 139 deletions(-) diff --git a/Doc/c-api/bool.rst b/Doc/c-api/bool.rst index b2d8f2124fc203..b14fa6a0a982e2 100644 --- a/Doc/c-api/bool.rst +++ b/Doc/c-api/bool.rst @@ -11,6 +11,12 @@ creation and deletion functions don't apply to booleans. The following macros are available, however. +.. c:var:: PyTypeObject PyBool_Type + + This instance of :c:type:`PyTypeObject` represents the Python boolean type; it + is the same object as :class:`bool` in the Python layer. + + .. c:function:: int PyBool_Check(PyObject *o) Return true if *o* is of type :c:data:`PyBool_Type`. This function always diff --git a/Doc/faq/extending.rst b/Doc/faq/extending.rst index bc3080f60ee237..2a8b976925d042 100644 --- a/Doc/faq/extending.rst +++ b/Doc/faq/extending.rst @@ -81,13 +81,13 @@ How do I extract C values from a Python object? That depends on the object's type. If it's a tuple, :c:func:`PyTuple_Size` returns its length and :c:func:`PyTuple_GetItem` returns the item at a specified -index. Lists have similar functions, :c:func:`PyListSize` and +index. Lists have similar functions, :c:func:`PyList_Size` and :c:func:`PyList_GetItem`. For bytes, :c:func:`PyBytes_Size` returns its length and :c:func:`PyBytes_AsStringAndSize` provides a pointer to its value and its length. Note that Python bytes objects may contain null bytes so C's -:c:func:`strlen` should not be used. +:c:func:`!strlen` should not be used. To test the type of an object, first make sure it isn't ``NULL``, and then use :c:func:`PyBytes_Check`, :c:func:`PyTuple_Check`, :c:func:`PyList_Check`, etc. diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst index a3068d86d85bc4..4828e2fa29bd24 100644 --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -527,7 +527,7 @@ If you're in doubt about the detailed behavior of the curses functions, consult the manual pages for your curses implementation, whether it's ncurses or a proprietary Unix vendor's. The manual pages will document any quirks, and provide complete lists of all the -functions, attributes, and :const:`ACS_\*` characters available to +functions, attributes, and :ref:`ACS_\* ` characters available to you. Because the curses API is so large, some functions aren't supported in diff --git a/Doc/install/index.rst b/Doc/install/index.rst index 443c75b7684fb6..ffb4a202fe89f2 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -778,7 +778,7 @@ Notes: (2) On Unix, if the :envvar:`HOME` environment variable is not defined, the user's - home directory will be determined with the :func:`getpwuid` function from the + home directory will be determined with the :func:`~pwd.getpwuid` function from the standard :mod:`pwd` module. This is done by the :func:`os.path.expanduser` function used by Distutils. diff --git a/Doc/library/asyncio-extending.rst b/Doc/library/asyncio-extending.rst index 8ffd356f2d1cc3..e7b293f484f8de 100644 --- a/Doc/library/asyncio-extending.rst +++ b/Doc/library/asyncio-extending.rst @@ -69,7 +69,7 @@ Task lifetime support ===================== A third party task implementation should call the following functions to keep a task -visible by :func:`asyncio.get_tasks` and :func:`asyncio.current_task`: +visible by :func:`asyncio.all_tasks` and :func:`asyncio.current_task`: .. function:: _register_task(task) diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst index 70cec9b2f90248..893ae5518f757d 100644 --- a/Doc/library/asyncio-future.rst +++ b/Doc/library/asyncio-future.rst @@ -276,4 +276,4 @@ the Future has a result:: :func:`concurrent.futures.as_completed` functions. - :meth:`asyncio.Future.cancel` accepts an optional ``msg`` argument, - but :func:`concurrent.futures.cancel` does not. + but :meth:`concurrent.futures.Future.cancel` does not. diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst index 32df99869eb530..ec4aeaa04395ac 100644 --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -87,7 +87,8 @@ The :mod:`bz2` module contains: compressed streams. :class:`BZ2File` provides all of the members specified by the - :class:`io.BufferedIOBase`, except for :meth:`detach` and :meth:`truncate`. + :class:`io.BufferedIOBase`, except for :meth:`~io.BufferedIOBase.detach` + and :meth:`~io.IOBase.truncate`. Iteration and the :keyword:`with` statement are supported. :class:`BZ2File` also provides the following method: diff --git a/Doc/library/code.rst b/Doc/library/code.rst index 538e5afc7822aa..3d7f43c86a0557 100644 --- a/Doc/library/code.rst +++ b/Doc/library/code.rst @@ -163,12 +163,12 @@ interpreter objects as well as the following additions. Push a line of source text to the interpreter. The line should not have a trailing newline; it may have internal newlines. The line is appended to a - buffer and the interpreter's :meth:`runsource` method is called with the + buffer and the interpreter's :meth:`~InteractiveInterpreter.runsource` method is called with the concatenated contents of the buffer as source. If this indicates that the command was executed or invalid, the buffer is reset; otherwise, the command is incomplete, and the buffer is left as it was after the line was appended. The return value is ``True`` if more input is required, ``False`` if the line was - dealt with in some way (this is the same as :meth:`runsource`). + dealt with in some way (this is the same as :meth:`!runsource`). .. method:: InteractiveConsole.resetbuffer() diff --git a/Doc/library/concurrent.rst b/Doc/library/concurrent.rst index 2eba5365125805..8caea78bbb57e8 100644 --- a/Doc/library/concurrent.rst +++ b/Doc/library/concurrent.rst @@ -1,5 +1,5 @@ -The :mod:`concurrent` package -============================= +The :mod:`!concurrent` package +============================== Currently, there is only one module in this package: diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 391c81a844d3e0..9ab67c21975394 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1648,6 +1648,8 @@ keys); also, the following keypad mappings are standard: | :kbd:`Page Down` | KEY_NPAGE | +------------------+-----------+ +.. _curses-acs-codes: + The following table lists characters from the alternate character set. These are inherited from the VT100 terminal, and will generally be available on software emulations such as X terminals. When there is no graphic available, curses diff --git a/Doc/library/email.charset.rst b/Doc/library/email.charset.rst index adbe6c1c7d29b8..aa0134412f3a60 100644 --- a/Doc/library/email.charset.rst +++ b/Doc/library/email.charset.rst @@ -150,7 +150,7 @@ Import this class from the :mod:`email.charset` module. .. method:: __str__() Returns *input_charset* as a string coerced to lower - case. :meth:`__repr__` is an alias for :meth:`__str__`. + case. :meth:`!__repr__` is an alias for :meth:`!__str__`. .. method:: __eq__(other) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst index 5d68b104f3a45c..3bd377e33f6c15 100644 --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -25,7 +25,7 @@ is especially true for :mimetype:`image/\*` and :mimetype:`text/\*` type message containing binary data. The :mod:`email` package provides some convenient encoders in its -:mod:`encoders` module. These encoders are actually used by the +:mod:`~email.encoders` module. These encoders are actually used by the :class:`~email.mime.audio.MIMEAudio` and :class:`~email.mime.image.MIMEImage` class constructors to provide default encodings. All encoder functions take exactly one argument, the message object to encode. They usually extract the diff --git a/Doc/library/email.generator.rst b/Doc/library/email.generator.rst index 34ad7b7f200af3..91d9d69a63d73f 100644 --- a/Doc/library/email.generator.rst +++ b/Doc/library/email.generator.rst @@ -274,9 +274,9 @@ in with information about the part. .. rubric:: Footnotes .. [#] This statement assumes that you use the appropriate setting for - ``unixfrom``, and that there are no :mod:`policy` settings calling for + ``unixfrom``, and that there are no :mod:`email.policy` settings calling for automatic adjustments (for example, - :attr:`~email.policy.Policy.refold_source` must be ``none``, which is + :attr:`~email.policy.EmailPolicy.refold_source` must be ``none``, which is *not* the default). It is also not 100% true, since if the message does not conform to the RFC standards occasionally information about the exact original text is lost during parsing error recovery. It is a goal diff --git a/Doc/library/email.message.rst b/Doc/library/email.message.rst index 5e0509f4181199..225f498781fa86 100644 --- a/Doc/library/email.message.rst +++ b/Doc/library/email.message.rst @@ -67,7 +67,7 @@ message objects. with the base :class:`~email.message.Message` class *maxheaderlen* is accepted, but defaults to ``None``, which means that by default the line length is controlled by the - :attr:`~email.policy.EmailPolicy.max_line_length` of the policy. The + :attr:`~email.policy.Policy.max_line_length` of the policy. The *policy* argument may be used to override the default policy obtained from the message instance. This can be used to control some of the formatting produced by the method, since the specified *policy* will be @@ -213,7 +213,7 @@ message objects. del msg['subject'] msg['subject'] = 'Python roolz!' - If the :mod:`policy` defines certain headers to be unique (as the standard + If the :mod:`policy ` defines certain headers to be unique (as the standard policies do), this method may raise a :exc:`ValueError` when an attempt is made to assign a value to such a header when one already exists. This behavior is intentional for consistency's sake, but do not depend on it @@ -378,7 +378,7 @@ message objects. deprecated. Note that existing parameter values of headers may be accessed through - the :attr:`~email.headerregistry.BaseHeader.params` attribute of the + the :attr:`~email.headerregistry.ParameterizedMIMEHeader.params` attribute of the header value (for example, ``msg['Content-Type'].params['charset']``). .. versionchanged:: 3.4 ``replace`` keyword was added. @@ -691,7 +691,7 @@ message objects. .. method:: clear_content() - Remove the payload and all of the :exc:`Content-` headers, leaving + Remove the payload and all of the :mailheader:`!Content-` headers, leaving all other headers intact and in their original order. diff --git a/Doc/library/email.parser.rst b/Doc/library/email.parser.rst index d9a61616bbbdfb..dda0466a6afa7d 100644 --- a/Doc/library/email.parser.rst +++ b/Doc/library/email.parser.rst @@ -39,9 +39,9 @@ returns the root object when you close the parser. Note that the parser can be extended in limited ways, and of course you can implement your own parser completely from scratch. All of the logic that connects the :mod:`email` package's bundled parser and the -:class:`~email.message.EmailMessage` class is embodied in the :mod:`policy` +:class:`~email.message.EmailMessage` class is embodied in the :class:`~email.policy.Policy` class, so a custom parser can create message object trees any way it finds -necessary by implementing custom versions of the appropriate :mod:`policy` +necessary by implementing custom versions of the appropriate :class:`!Policy` methods. diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst index 0efb4897a1eb86..dfe4b7c59fd578 100644 --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -100,7 +100,7 @@ The :class:`dircmp` class used to get various bits of information about the directory trees being compared. - Note that via :meth:`__getattr__` hooks, all attributes are computed lazily, + Note that via :meth:`~object.__getattr__` hooks, all attributes are computed lazily, so there is no speed penalty if only those attributes which are lightweight to compute are used. diff --git a/Doc/library/fileinput.rst b/Doc/library/fileinput.rst index 4bc868759f2025..f93e9a58791eeb 100644 --- a/Doc/library/fileinput.rst +++ b/Doc/library/fileinput.rst @@ -177,7 +177,7 @@ available for subclassing as well: The keyword-only parameter *encoding* and *errors* are added. .. versionchanged:: 3.11 - The ``'rU'`` and ``'U'`` modes and the :meth:`__getitem__` method have + The ``'rU'`` and ``'U'`` modes and the :meth:`!__getitem__` method have been removed. diff --git a/Doc/library/graphlib.rst b/Doc/library/graphlib.rst index fe7932e7a61cb5..fdd8f39ef4e1c4 100644 --- a/Doc/library/graphlib.rst +++ b/Doc/library/graphlib.rst @@ -115,7 +115,7 @@ :meth:`TopologicalSorter.done` is less than the number that have been returned by :meth:`TopologicalSorter.get_ready`. - The :meth:`~TopologicalSorter.__bool__` method of this class defers to + The :meth:`~object.__bool__` method of this class defers to this function, so instead of:: if ts.is_active(): @@ -204,7 +204,7 @@ The :mod:`graphlib` module defines the following exception classes: in the working graph. If multiple cycles exist, only one undefined choice among them will be reported and included in the exception. - The detected cycle can be accessed via the second element in the :attr:`~CycleError.args` + The detected cycle can be accessed via the second element in the :attr:`~BaseException.args` attribute of the exception instance and consists in a list of nodes, such that each node is, in the graph, an immediate predecessor of the next node in the list. In the reported list, the first and the last node will be the same, to make it clear that it is cyclic. diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 979b39a3a5abbc..60236a1190e423 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -70,7 +70,7 @@ The module defines the following items: .. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None) Constructor for the :class:`GzipFile` class, which simulates most of the - methods of a :term:`file object`, with the exception of the :meth:`truncate` + methods of a :term:`file object`, with the exception of the :meth:`~io.IOBase.truncate` method. At least one of *fileobj* and *filename* must be given a non-trivial value. @@ -113,7 +113,7 @@ The module defines the following items: :class:`GzipFile` supports the :class:`io.BufferedIOBase` interface, including iteration and the :keyword:`with` statement. Only the - :meth:`truncate` method isn't implemented. + :meth:`~io.IOBase.truncate` method isn't implemented. :class:`GzipFile` also provides the following method and attribute: diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 8102767a43d6dd..69fb79b49ca2a0 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -244,7 +244,7 @@ by the SHAKE algorithm. .. method:: shake.digest(length) - Return the digest of the data passed to the :meth:`update` method so far. + Return the digest of the data passed to the :meth:`~hash.update` method so far. This is a bytes object of size *length* which may contain bytes in the whole range from 0 to 255. @@ -507,9 +507,9 @@ Simple hashing To calculate hash of some data, you should first construct a hash object by calling the appropriate constructor function (:func:`blake2b` or -:func:`blake2s`), then update it with the data by calling :meth:`update` on the +:func:`blake2s`), then update it with the data by calling :meth:`~hash.update` on the object, and, finally, get the digest out of the object by calling -:meth:`digest` (or :meth:`hexdigest` for hex-encoded string). +:meth:`~hash.digest` (or :meth:`~hash.hexdigest` for hex-encoded string). >>> from hashlib import blake2b >>> h = blake2b() diff --git a/Doc/library/importlib.resources.abc.rst b/Doc/library/importlib.resources.abc.rst index b0e75737137f2c..65c42858bbbb7d 100644 --- a/Doc/library/importlib.resources.abc.rst +++ b/Doc/library/importlib.resources.abc.rst @@ -145,10 +145,10 @@ An abstract base class for resource readers capable of serving the :meth:`importlib.resources.files` interface. Subclasses - :class:`importlib.resources.abc.ResourceReader` and provides - concrete implementations of the :class:`importlib.resources.abc.ResourceReader`'s + :class:`ResourceReader` and provides + concrete implementations of the :class:`!ResourceReader`'s abstract methods. Therefore, any loader supplying - :class:`importlib.abc.TraversableResources` also supplies ResourceReader. + :class:`!TraversableResources` also supplies :class:`!ResourceReader`. Loaders that wish to support resource reading are expected to implement this interface. diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 35a08995487c1b..6c3059381776c9 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -192,7 +192,7 @@ Basic Usage dictionaries will be sorted by key. To use a custom :class:`JSONEncoder` subclass (e.g. one that overrides the - :meth:`default` method to serialize additional types), specify it with the + :meth:`~JSONEncoder.default` method to serialize additional types), specify it with the *cls* kwarg; otherwise :class:`JSONEncoder` is used. .. versionchanged:: 3.6 @@ -422,7 +422,7 @@ Encoders and Decoders Added support for int- and float-derived Enum classes. To extend this to recognize other objects, subclass and implement a - :meth:`default` method with another method that returns a serializable object + :meth:`~JSONEncoder.default` method with another method that returns a serializable object for ``o`` if possible, otherwise it should call the superclass implementation (to raise :exc:`TypeError`). @@ -483,7 +483,7 @@ Encoders and Decoders :exc:`TypeError`). For example, to support arbitrary iterators, you could implement - :meth:`default` like this:: + :meth:`~JSONEncoder.default` like this:: def default(self, o): try: diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 22412e1a2113bb..70a9c8b9aa86e3 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -397,21 +397,21 @@ have specific values relative to the predefined levels. If you define a level with the same numeric value, it overwrites the predefined value; the predefined name is lost. -+--------------+---------------+ -| Level | Numeric value | -+==============+===============+ -| ``CRITICAL`` | 50 | -+--------------+---------------+ -| ``ERROR`` | 40 | -+--------------+---------------+ -| ``WARNING`` | 30 | -+--------------+---------------+ -| ``INFO`` | 20 | -+--------------+---------------+ -| ``DEBUG`` | 10 | -+--------------+---------------+ -| ``NOTSET`` | 0 | -+--------------+---------------+ ++-----------------------+---------------+ +| Level | Numeric value | ++=======================+===============+ +| .. py:data:: CRITICAL | 50 | ++-----------------------+---------------+ +| .. py:data:: ERROR | 40 | ++-----------------------+---------------+ +| .. py:data:: WARNING | 30 | ++-----------------------+---------------+ +| .. py:data:: INFO | 20 | ++-----------------------+---------------+ +| .. py:data:: DEBUG | 10 | ++-----------------------+---------------+ +| .. py:data:: NOTSET | 0 | ++-----------------------+---------------+ .. _handler: diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 868d4dcfb6c996..434e7ac9061186 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -100,7 +100,8 @@ Reading and writing compressed files *filters* arguments have the same meanings as for :class:`LZMACompressor`. :class:`LZMAFile` supports all the members specified by - :class:`io.BufferedIOBase`, except for :meth:`detach` and :meth:`truncate`. + :class:`io.BufferedIOBase`, except for :meth:`~io.BufferedIOBase.detach` + and :meth:`~io.IOBase.truncate`. Iteration and the :keyword:`with` statement are supported. The following method is also provided: diff --git a/Doc/library/msvcrt.rst b/Doc/library/msvcrt.rst index 42fffee6a0f449..32693e3d007c05 100644 --- a/Doc/library/msvcrt.rst +++ b/Doc/library/msvcrt.rst @@ -38,7 +38,7 @@ File Operations Lock part of a file based on file descriptor *fd* from the C runtime. Raises :exc:`OSError` on failure. The locked region of the file extends from the current file position for *nbytes* bytes, and may continue beyond the end of the - file. *mode* must be one of the :const:`LK_\*` constants listed below. Multiple + file. *mode* must be one of the :const:`!LK_\*` constants listed below. Multiple regions in a file may be locked at the same time, but may not overlap. Adjacent regions are not merged; they must be unlocked individually. diff --git a/Doc/library/netrc.rst b/Doc/library/netrc.rst index 88265d9b9e9e93..c36e5cfecfc6a8 100644 --- a/Doc/library/netrc.rst +++ b/Doc/library/netrc.rst @@ -51,9 +51,19 @@ the Unix :program:`ftp` program and other FTP clients. Exception raised by the :class:`~netrc.netrc` class when syntactical errors are encountered in source text. Instances of this exception provide three - interesting attributes: :attr:`msg` is a textual explanation of the error, - :attr:`filename` is the name of the source file, and :attr:`lineno` gives the - line number on which the error was found. + interesting attributes: + + .. attribute:: msg + + Textual explanation of the error. + + .. attribute:: filename + + The name of the source file. + + .. attribute:: lineno + + The line number on which the error was found. .. _netrc-objects: diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index dab4de9eb6abb7..57c67bcf3aa12e 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -59,9 +59,9 @@ truth tests, identity tests, and boolean operations: __not__(obj) Return the outcome of :keyword:`not` *obj*. (Note that there is no - :meth:`__not__` method for object instances; only the interpreter core defines - this operation. The result is affected by the :meth:`__bool__` and - :meth:`__len__` methods.) + :meth:`!__not__` method for object instances; only the interpreter core defines + this operation. The result is affected by the :meth:`~object.__bool__` and + :meth:`~object.__len__` methods.) .. function:: truth(obj) diff --git a/Doc/library/poplib.rst b/Doc/library/poplib.rst index fbd5e150b4cd54..943eb21f6eec02 100644 --- a/Doc/library/poplib.rst +++ b/Doc/library/poplib.rst @@ -148,7 +148,7 @@ A :class:`POP3` instance has the following methods: .. method:: POP3.pass_(password) Send password, response includes message count and mailbox size. Note: the - mailbox on the server is locked until :meth:`~poplib.quit` is called. + mailbox on the server is locked until :meth:`~POP3.quit` is called. .. method:: POP3.apop(user, secret) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index d8269ef48cb36a..e883acd67d6c72 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -45,7 +45,7 @@ The :mod:`pprint` module defines one class: several keyword parameters. *stream* (default ``sys.stdout``) is a :term:`file-like object` to - which the output will be written by calling its :meth:`write` method. + which the output will be written by calling its :meth:`!write` method. If both *stream* and ``sys.stdout`` are ``None``, then :meth:`~PrettyPrinter.pprint` silently returns. diff --git a/Doc/library/pty.rst b/Doc/library/pty.rst index 7f4da41e93802d..ad4981c97119fa 100644 --- a/Doc/library/pty.rst +++ b/Doc/library/pty.rst @@ -71,7 +71,7 @@ The :mod:`pty` module defines the following functions: Return the exit status value from :func:`os.waitpid` on the child process. - :func:`waitstatus_to_exitcode` can be used to convert the exit status into + :func:`os.waitstatus_to_exitcode` can be used to convert the exit status into an exit code. .. audit-event:: pty.spawn argv pty.spawn diff --git a/Doc/library/sched.rst b/Doc/library/sched.rst index 04215d31ba10ca..01bac5afd0b9b3 100644 --- a/Doc/library/sched.rst +++ b/Doc/library/sched.rst @@ -115,7 +115,7 @@ Scheduler Objects .. method:: scheduler.run(blocking=True) - Run all scheduled events. This method will wait (using the :func:`delayfunc` + Run all scheduled events. This method will wait (using the *delayfunc* function passed to the constructor) for the next event, then execute it and so on until there are no more scheduled events. diff --git a/Doc/library/selectors.rst b/Doc/library/selectors.rst index 0deb15cf4c5037..dd50bac37e49b8 100644 --- a/Doc/library/selectors.rst +++ b/Doc/library/selectors.rst @@ -60,9 +60,9 @@ constants below: +-----------------------+-----------------------------------------------+ | Constant | Meaning | +=======================+===============================================+ - | :const:`EVENT_READ` | Available for read | + | .. data:: EVENT_READ | Available for read | +-----------------------+-----------------------------------------------+ - | :const:`EVENT_WRITE` | Available for write | + | .. data:: EVENT_WRITE | Available for write | +-----------------------+-----------------------------------------------+ @@ -132,8 +132,8 @@ constants below: Change a registered file object's monitored events or attached data. - This is equivalent to :meth:`BaseSelector.unregister(fileobj)` followed - by :meth:`BaseSelector.register(fileobj, events, data)`, except that it + This is equivalent to ``BaseSelector.unregister(fileobj)`` followed + by ``BaseSelector.register(fileobj, events, data)``, except that it can be implemented more efficiently. This returns a new :class:`SelectorKey` instance, or raises a diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 7699d22a72aaff..4390a8e22306fa 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -369,7 +369,7 @@ Directory and files operations If *copy_function* is given, it must be a callable that takes two arguments *src* and *dst*, and will be used to copy *src* to *dst* if :func:`os.rename` cannot be used. If the source is a directory, - :func:`copytree` is called, passing it the :func:`copy_function`. The + :func:`copytree` is called, passing it the *copy_function*. The default *copy_function* is :func:`copy2`. Using :func:`~shutil.copy` as the *copy_function* allows the move to succeed when it is not possible to also copy the metadata, at the expense of not copying any of the metadata. diff --git a/Doc/library/stat.rst b/Doc/library/stat.rst index 083dc5e3bcfd68..77538514598a50 100644 --- a/Doc/library/stat.rst +++ b/Doc/library/stat.rst @@ -13,8 +13,8 @@ The :mod:`stat` module defines constants and functions for interpreting the results of :func:`os.stat`, :func:`os.fstat` and :func:`os.lstat` (if they -exist). For complete details about the :c:func:`stat`, :c:func:`fstat` and -:c:func:`lstat` calls, consult the documentation for your system. +exist). For complete details about the :c:func:`stat`, :c:func:`!fstat` and +:c:func:`!lstat` calls, consult the documentation for your system. .. versionchanged:: 3.4 The stat module is backed by a C implementation. @@ -89,9 +89,9 @@ mode: .. function:: S_IFMT(mode) Return the portion of the file's mode that describes the file type (used by the - :func:`S_IS\*` functions above). + :func:`!S_IS\*` functions above). -Normally, you would use the :func:`os.path.is\*` functions for testing the type +Normally, you would use the :func:`!os.path.is\*` functions for testing the type of a file; the functions here are useful when you are doing multiple tests of the same file and wish to avoid the overhead of the :c:func:`stat` system call for each test. These are also useful when checking for information about a file diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index d0233e3f35394e..804342386abd7f 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -44,7 +44,7 @@ Any object can be tested for truth value, for use in an :keyword:`if` or .. index:: single: true By default, an object is considered true unless its class defines either a -:meth:`__bool__` method that returns ``False`` or a :meth:`__len__` method that +:meth:`~object.__bool__` method that returns ``False`` or a :meth:`__len__` method that returns zero, when called with the object. [1]_ Here are most of the built-in objects considered false: diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index 839c2c015b49ae..c805c50ffc689f 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -69,7 +69,7 @@ Python uses an installation scheme that differs depending on the platform and on the installation options. These schemes are stored in :mod:`sysconfig` under unique identifiers based on the value returned by :const:`os.name`. -Every new component that is installed using :mod:`distutils` or a +Every new component that is installed using :mod:`!distutils` or a Distutils-based system will follow the same scheme to copy its file in the right places. diff --git a/Doc/library/textwrap.rst b/Doc/library/textwrap.rst index 1a9d5f98f78a7e..a150eefbf932ef 100644 --- a/Doc/library/textwrap.rst +++ b/Doc/library/textwrap.rst @@ -60,7 +60,7 @@ functions should be good enough; otherwise, you should use an instance of First the whitespace in *text* is collapsed (all whitespace is replaced by single spaces). If the result fits in the *width*, it is returned. Otherwise, enough words are dropped from the end so that the remaining words - plus the :attr:`placeholder` fit within :attr:`width`:: + plus the :attr:`.placeholder` fit within :attr:`.width`:: >>> textwrap.shorten("Hello world!", width=12) 'Hello world!' @@ -173,7 +173,7 @@ hyphenated words; only then will long words be broken if necessary, unless .. attribute:: expand_tabs (default: ``True``) If true, then all tab characters in *text* will be - expanded to spaces using the :meth:`expandtabs` method of *text*. + expanded to spaces using the :meth:`~str.expandtabs` method of *text*. .. attribute:: tabsize diff --git a/Doc/library/urllib.error.rst b/Doc/library/urllib.error.rst index 3adbdd26132273..a5bcb5b1e643bf 100644 --- a/Doc/library/urllib.error.rst +++ b/Doc/library/urllib.error.rst @@ -72,6 +72,8 @@ The following exceptions are raised by :mod:`urllib.error` as appropriate: This exception is raised when the :func:`~urllib.request.urlretrieve` function detects that the amount of the downloaded data is less than the expected amount (given by - the *Content-Length* header). The :attr:`content` attribute stores the - downloaded (and supposedly truncated) data. + the *Content-Length* header). + .. attribute:: content + + The downloaded (and supposedly truncated) data. diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 4ab671817710dd..06bd4d87eb03c6 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -288,7 +288,7 @@ This module offers the following functions: table (FAT) file system, the filename may not have an extension. A call to :func:`LoadKey` fails if the calling process does not have the - :const:`SE_RESTORE_PRIVILEGE` privilege. Note that privileges are different + :c:data:`!SE_RESTORE_PRIVILEGE` privilege. Note that privileges are different from permissions -- see the `RegLoadKey documentation `__ for more details. @@ -414,7 +414,7 @@ This module offers the following functions: If *key* represents a key on a remote computer, the path described by *file_name* is relative to the remote computer. The caller of this method must - possess the :const:`SeBackupPrivilege` security privilege. Note that + possess the **SeBackupPrivilege** security privilege. Note that privileges are different than permissions -- see the `Conflicts Between User Rights and Permissions documentation `__ @@ -536,7 +536,7 @@ This module offers the following functions: Constants ------------------ -The following constants are defined for use in many :mod:`_winreg` functions. +The following constants are defined for use in many :mod:`winreg` functions. .. _hkey-constants: @@ -745,7 +745,7 @@ All registry functions in this module return one of these objects. All registry functions in this module which accept a handle object also accept an integer, however, use of the handle object is encouraged. -Handle objects provide semantics for :meth:`__bool__` -- thus :: +Handle objects provide semantics for :meth:`~object.__bool__` -- thus :: if handle: print("Yes") diff --git a/Doc/library/winsound.rst b/Doc/library/winsound.rst index 372f792a0f938e..370c5216652ba7 100644 --- a/Doc/library/winsound.rst +++ b/Doc/library/winsound.rst @@ -24,7 +24,7 @@ provided by Windows platforms. It includes functions and several constants. .. function:: PlaySound(sound, flags) - Call the underlying :c:func:`PlaySound` function from the Platform API. The + Call the underlying :c:func:`!PlaySound` function from the Platform API. The *sound* parameter may be a filename, a system sound alias, audio data as a :term:`bytes-like object`, or ``None``. Its interpretation depends on the value of *flags*, which can be a bitwise ORed @@ -35,7 +35,7 @@ provided by Windows platforms. It includes functions and several constants. .. function:: MessageBeep(type=MB_OK) - Call the underlying :c:func:`MessageBeep` function from the Platform API. This + Call the underlying :c:func:`!MessageBeep` function from the Platform API. This plays a sound as specified in the registry. The *type* argument specifies which sound to play; possible values are ``-1``, ``MB_ICONASTERISK``, ``MB_ICONEXCLAMATION``, ``MB_ICONHAND``, ``MB_ICONQUESTION``, and ``MB_OK``, all diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst index cf30de67719b93..1e49b6568dfc28 100644 --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -75,10 +75,10 @@ decompression bomb Safe Safe Safe potential reliance on system-provided libraries. Check :const:`pyexpat.EXPAT_VERSION`. 2. :mod:`xml.etree.ElementTree` doesn't expand external entities and raises a - :exc:`ParserError` when an entity occurs. + :exc:`~xml.etree.ElementTree.ParseError` when an entity occurs. 3. :mod:`xml.dom.minidom` doesn't expand external entities and simply returns the unexpanded entity verbatim. -4. :mod:`xmlrpclib` doesn't expand external entities and omits them. +4. :mod:`xmlrpc.client` doesn't expand external entities and omits them. 5. Since Python 3.7.1, external general entities are no longer processed by default. @@ -119,8 +119,8 @@ all known attack vectors with examples and references. .. _defusedxml-package: -The :mod:`defusedxml` Package ------------------------------------------------------- +The :mod:`!defusedxml` Package +------------------------------ `defusedxml`_ is a pure Python package with modified subclasses of all stdlib XML parsers that prevent any potentially malicious operation. Use of this diff --git a/Doc/library/xml.sax.handler.rst b/Doc/library/xml.sax.handler.rst index 719ce5ab1bcf65..e2f28e3244cb09 100644 --- a/Doc/library/xml.sax.handler.rst +++ b/Doc/library/xml.sax.handler.rst @@ -393,7 +393,7 @@ implements this interface, then register the object with your :class:`~xml.sax.xmlreader.XMLReader`, the parser will call the methods in your object to report all warnings and errors. There are three levels of errors available: warnings, (possibly) recoverable errors, -and unrecoverable errors. All methods take a :exc:`SAXParseException` as the +and unrecoverable errors. All methods take a :exc:`~xml.sax.SAXParseException` as the only parameter. Errors and warnings may be converted to an exception by raising the passed-in exception object. diff --git a/Doc/library/xml.sax.utils.rst b/Doc/library/xml.sax.utils.rst index ab4606bcf9fe6c..e57e76dcac7820 100644 --- a/Doc/library/xml.sax.utils.rst +++ b/Doc/library/xml.sax.utils.rst @@ -92,5 +92,5 @@ or as base classes. reading. The input source can be given as a string, a file-like object, or an :class:`~xml.sax.xmlreader.InputSource` object; parsers will use this function to implement the polymorphic *source* argument to their - :meth:`parse` method. + :meth:`~xml.sax.xmlreader.XMLReader.parse` method. diff --git a/Doc/library/xmlrpc.rst b/Doc/library/xmlrpc.rst index ae68157b0f63c1..5f0a2cf68d01f9 100644 --- a/Doc/library/xmlrpc.rst +++ b/Doc/library/xmlrpc.rst @@ -1,5 +1,5 @@ -:mod:`xmlrpc` --- XMLRPC server and client modules -================================================== +:mod:`!xmlrpc` --- XMLRPC server and client modules +=================================================== XML-RPC is a Remote Procedure Call method that uses XML passed via HTTP as a transport. With it, a client can call methods with parameters on a remote diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index ce36bff89424cd..4bc49a5a83d7a4 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1594,9 +1594,9 @@ Basic customization Called to implement truth value testing and the built-in operation ``bool()``; should return ``False`` or ``True``. When this method is not - defined, :meth:`__len__` is called, if it is defined, and the object is + defined, :meth:`~object.__len__` is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither - :meth:`__len__` nor :meth:`__bool__`, all its instances are considered + :meth:`!__len__` nor :meth:`!__bool__`, all its instances are considered true. @@ -2494,7 +2494,7 @@ through the object's keys; for sequences, it should iterate through the values. Called to implement the built-in function :func:`len`. Should return the length of the object, an integer ``>=`` 0. Also, an object that doesn't define a - :meth:`__bool__` method and whose :meth:`__len__` method returns zero is + :meth:`~object.__bool__` method and whose :meth:`!__len__` method returns zero is considered to be false in a Boolean context. .. impl-detail:: @@ -2503,7 +2503,7 @@ through the object's keys; for sequences, it should iterate through the values. If the length is larger than :data:`!sys.maxsize` some features (such as :func:`len`) may raise :exc:`OverflowError`. To prevent raising :exc:`!OverflowError` by truth value testing, an object must define a - :meth:`__bool__` method. + :meth:`~object.__bool__` method. .. method:: object.__length_hint__(self) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 08dcc8095bee8c..5d7a36aa8ff52b 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1717,7 +1717,7 @@ control flow statements, the following values are interpreted as false: ``False``, ``None``, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true. User-defined objects can customize their -truth value by providing a :meth:`__bool__` method. +truth value by providing a :meth:`~object.__bool__` method. .. index:: pair: operator; not diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index dde7ba1d941dce..83cd4402a36cf6 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -787,7 +787,7 @@ is converted before formatting. Conversion ``'!s'`` calls :func:`str` on the result, ``'!r'`` calls :func:`repr`, and ``'!a'`` calls :func:`ascii`. The result is then formatted using the :func:`format` protocol. The -format specifier is passed to the :meth:`__format__` method of the +format specifier is passed to the :meth:`~object.__format__` method of the expression or conversion result. An empty string is passed when the format specifier is omitted. The formatted result is then included in the final value of the whole string. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 899e98acec8adf..b3ef4a63731959 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -4,7 +4,6 @@ # to help avoid merge conflicts. Doc/c-api/arg.rst -Doc/c-api/bool.rst Doc/c-api/buffer.rst Doc/c-api/datetime.rst Doc/c-api/descriptor.rst @@ -31,19 +30,16 @@ Doc/c-api/unicode.rst Doc/extending/extending.rst Doc/extending/newtypes.rst Doc/faq/design.rst -Doc/faq/extending.rst Doc/faq/gui.rst Doc/faq/library.rst Doc/faq/programming.rst Doc/glossary.rst -Doc/howto/curses.rst Doc/howto/descriptor.rst Doc/howto/enum.rst Doc/howto/isolating-extensions.rst Doc/howto/logging-cookbook.rst Doc/howto/logging.rst Doc/howto/urllib2.rst -Doc/install/index.rst Doc/library/2to3.rst Doc/library/__future__.rst Doc/library/abc.rst @@ -52,7 +48,6 @@ Doc/library/ast.rst Doc/library/asyncio-dev.rst Doc/library/asyncio-eventloop.rst Doc/library/asyncio-extending.rst -Doc/library/asyncio-future.rst Doc/library/asyncio-policy.rst Doc/library/asyncio-stream.rst Doc/library/asyncio-subprocess.rst @@ -66,12 +61,10 @@ Doc/library/cgi.rst Doc/library/chunk.rst Doc/library/cmath.rst Doc/library/cmd.rst -Doc/library/code.rst Doc/library/codecs.rst Doc/library/collections.abc.rst Doc/library/collections.rst Doc/library/concurrent.futures.rst -Doc/library/concurrent.rst Doc/library/configparser.rst Doc/library/contextlib.rst Doc/library/copy.rst @@ -86,11 +79,8 @@ Doc/library/dis.rst Doc/library/doctest.rst Doc/library/email.charset.rst Doc/library/email.compat32-message.rst -Doc/library/email.encoders.rst Doc/library/email.errors.rst -Doc/library/email.generator.rst Doc/library/email.headerregistry.rst -Doc/library/email.message.rst Doc/library/email.mime.rst Doc/library/email.parser.rst Doc/library/email.policy.rst @@ -98,27 +88,21 @@ Doc/library/enum.rst Doc/library/exceptions.rst Doc/library/faulthandler.rst Doc/library/fcntl.rst -Doc/library/filecmp.rst -Doc/library/fileinput.rst Doc/library/ftplib.rst Doc/library/functions.rst Doc/library/functools.rst Doc/library/getopt.rst Doc/library/getpass.rst Doc/library/gettext.rst -Doc/library/graphlib.rst Doc/library/gzip.rst -Doc/library/hashlib.rst Doc/library/http.client.rst Doc/library/http.cookiejar.rst Doc/library/http.cookies.rst Doc/library/http.server.rst -Doc/library/importlib.resources.abc.rst Doc/library/importlib.resources.rst Doc/library/importlib.rst Doc/library/inspect.rst Doc/library/io.rst -Doc/library/json.rst Doc/library/locale.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst @@ -127,13 +111,10 @@ Doc/library/lzma.rst Doc/library/mailbox.rst Doc/library/mmap.rst Doc/library/msilib.rst -Doc/library/msvcrt.rst Doc/library/multiprocessing.rst Doc/library/multiprocessing.shared_memory.rst -Doc/library/netrc.rst Doc/library/nntplib.rst Doc/library/numbers.rst -Doc/library/operator.rst Doc/library/optparse.rst Doc/library/os.path.rst Doc/library/os.rst @@ -142,10 +123,7 @@ Doc/library/pickle.rst Doc/library/pickletools.rst Doc/library/platform.rst Doc/library/plistlib.rst -Doc/library/poplib.rst -Doc/library/pprint.rst Doc/library/profile.rst -Doc/library/pty.rst Doc/library/pyclbr.rst Doc/library/pydoc.rst Doc/library/pyexpat.rst @@ -154,32 +132,27 @@ Doc/library/readline.rst Doc/library/reprlib.rst Doc/library/resource.rst Doc/library/rlcompleter.rst -Doc/library/sched.rst Doc/library/select.rst Doc/library/selectors.rst Doc/library/shelve.rst -Doc/library/shutil.rst Doc/library/signal.rst Doc/library/site.rst Doc/library/smtplib.rst Doc/library/socket.rst Doc/library/socketserver.rst Doc/library/ssl.rst -Doc/library/stat.rst Doc/library/stdtypes.rst Doc/library/string.rst Doc/library/subprocess.rst Doc/library/sunau.rst Doc/library/sys.rst Doc/library/sys_path_init.rst -Doc/library/sysconfig.rst Doc/library/syslog.rst Doc/library/tarfile.rst Doc/library/telnetlib.rst Doc/library/tempfile.rst Doc/library/termios.rst Doc/library/test.rst -Doc/library/textwrap.rst Doc/library/threading.rst Doc/library/time.rst Doc/library/tkinter.rst @@ -192,14 +165,11 @@ Doc/library/turtle.rst Doc/library/unittest.mock-examples.rst Doc/library/unittest.mock.rst Doc/library/unittest.rst -Doc/library/urllib.error.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst Doc/library/uuid.rst Doc/library/weakref.rst Doc/library/webbrowser.rst -Doc/library/winreg.rst -Doc/library/winsound.rst Doc/library/wsgiref.rst Doc/library/xdrlib.rst Doc/library/xml.dom.minidom.rst @@ -210,9 +180,7 @@ Doc/library/xml.rst Doc/library/xml.sax.handler.rst Doc/library/xml.sax.reader.rst Doc/library/xml.sax.rst -Doc/library/xml.sax.utils.rst Doc/library/xmlrpc.client.rst -Doc/library/xmlrpc.rst Doc/library/xmlrpc.server.rst Doc/library/zlib.rst Doc/license.rst @@ -220,18 +188,14 @@ Doc/reference/compound_stmts.rst Doc/reference/datamodel.rst Doc/reference/expressions.rst Doc/reference/import.rst -Doc/reference/lexical_analysis.rst Doc/reference/simple_stmts.rst Doc/tutorial/appendix.rst Doc/tutorial/classes.rst Doc/tutorial/controlflow.rst Doc/tutorial/datastructures.rst -Doc/tutorial/errors.rst Doc/tutorial/inputoutput.rst -Doc/tutorial/interactive.rst Doc/tutorial/introduction.rst Doc/tutorial/modules.rst -Doc/tutorial/stdlib2.rst Doc/using/cmdline.rst Doc/using/configure.rst Doc/using/windows.rst diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 8a207c385c6ab7..1ec59767e9ce12 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -154,7 +154,7 @@ exception type. The *except clause* may specify a variable after the exception name. The variable is bound to the exception instance which typically has an ``args`` attribute that stores the arguments. For convenience, builtin exception -types define :meth:`__str__` to print all the arguments without explicitly +types define :meth:`~object.__str__` to print all the arguments without explicitly accessing ``.args``. :: >>> try: @@ -174,7 +174,7 @@ accessing ``.args``. :: x = spam y = eggs -The exception's :meth:`__str__` output is printed as the last part ('detail') +The exception's :meth:`~object.__str__` output is printed as the last part ('detail') of the message for unhandled exceptions. :exc:`BaseException` is the common base class of all exceptions. One of its diff --git a/Doc/tutorial/interactive.rst b/Doc/tutorial/interactive.rst index c0eb1feec4eb4d..0d3896a4832b59 100644 --- a/Doc/tutorial/interactive.rst +++ b/Doc/tutorial/interactive.rst @@ -23,7 +23,7 @@ Python statement names, the current local variables, and the available module names. For dotted expressions such as ``string.a``, it will evaluate the expression up to the final ``'.'`` and then suggest completions from the attributes of the resulting object. Note that this may execute -application-defined code if an object with a :meth:`__getattr__` method +application-defined code if an object with a :meth:`~object.__getattr__` method is part of the expression. The default configuration also saves your history into a file named :file:`.python_history` in your user directory. The history will be available again during the next interactive interpreter diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index f9ac13036cbc8d..379c74981fbf08 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -789,7 +789,7 @@ Operators And Special Methods :attr:`__doc__`, :attr:`__globals__`, :attr:`~definition.__name__`, respectively. -* :meth:`__nonzero__` is now :meth:`__bool__`. +* :meth:`!__nonzero__` is now :meth:`~object.__bool__`. Builtins -------- diff --git a/Misc/NEWS.d/3.11.0a6.rst b/Misc/NEWS.d/3.11.0a6.rst index 8621edcfb04bb3..fcec71c6f59da2 100644 --- a/Misc/NEWS.d/3.11.0a6.rst +++ b/Misc/NEWS.d/3.11.0a6.rst @@ -352,7 +352,7 @@ rather than ``JUMP_FORWARD`` with an argument of ``(2**32)+offset``. .. nonce: 3Z_qxd .. section: Core and Builtins -Correct the docstring for the :meth:`__bool__` method. Patch by Jelle +Correct the docstring for the :meth:`~object.__bool__` method. Patch by Jelle Zijlstra. .. From 2c0a99d322037d653063dc8466b886110e0fc447 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 29 Jul 2023 10:12:50 -0700 Subject: [PATCH 0478/1206] [3.12] gh-107422: Remove outdated `TypedDict` example from typing docs (GH-107436) (#107437) gh-107422: Remove outdated `TypedDict` example from typing docs (GH-107436) (cherry picked from commit 89fd4f4a3fc5fb8076ec064c22a30108480e946b) Co-authored-by: Rakesh Sabale <102187286+ghubrakesh@users.noreply.github.com> --- Doc/library/typing.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index e1acbd83a41730..11c39a444ef65d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2327,9 +2327,6 @@ types. class XZ(X, Z): pass # raises TypeError - T = TypeVar('T') - class XT(X, Generic[T]): pass # raises TypeError - A ``TypedDict`` can be generic:: class Group[T](TypedDict): From e3b5ed7b1cb8ad12aa285cf78303c6dda0953181 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 29 Jul 2023 10:52:17 -0700 Subject: [PATCH 0479/1206] [3.12] Fix the documentation for PyCode_New add `qualname` parameter (GH-107186) (#107440) Fix the documentation for PyCode_New add `qualname` parameter (GH-107186) (cherry picked from commit f2abeb590dae5918388f91b60b31f040d44218f0) Co-authored-by: da-woods --- Doc/c-api/code.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index 89fe42d1ff05f1..5082b0cb6ad3f3 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -33,7 +33,7 @@ bound into a function. Return the number of free variables in *co*. -.. c:function:: PyCodeObject* PyUnstable_Code_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *linetable, PyObject *exceptiontable) +.. c:function:: PyCodeObject* PyUnstable_Code_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable) Return a new code object. If you need a dummy code object to create a frame, use :c:func:`PyCode_NewEmpty` instead. @@ -46,7 +46,7 @@ bound into a function. execution or VM crashes. Use this function only with extreme care. .. versionchanged:: 3.11 - Added ``exceptiontable`` parameter. + Added ``qualname`` and ``exceptiontable`` parameters. .. index:: single: PyCode_New @@ -56,7 +56,7 @@ bound into a function. The old name is deprecated, but will remain available until the signature changes again. -.. c:function:: PyCodeObject* PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *linetable, PyObject *exceptiontable) +.. c:function:: PyCodeObject* PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable) Similar to :c:func:`PyUnstable_Code_New`, but with an extra "posonlyargcount" for positional-only arguments. The same caveats that apply to ``PyUnstable_Code_New`` also apply to this function. @@ -66,7 +66,7 @@ bound into a function. .. versionadded:: 3.8 as ``PyCode_NewWithPosOnlyArgs`` .. versionchanged:: 3.11 - Added ``exceptiontable`` parameter. + Added ``qualname`` and ``exceptiontable`` parameters. .. versionchanged:: 3.12 From 0b3d6381757a6616fdf093a2ba99cc68c018b845 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 30 Jul 2023 08:49:26 -0700 Subject: [PATCH 0480/1206] [3.12] gh-107427: Update the description of UNPACK_SEQUENCE (gh-107429) (gh-107459) --- Doc/library/dis.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 97d5121c4e8a5e..085fd2baba55c0 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -864,9 +864,10 @@ iterations of the loop. .. opcode:: UNPACK_SEQUENCE (count) Unpacks ``STACK[-1]`` into *count* individual values, which are put onto the stack - right-to-left:: + right-to-left. Require there to be exactly *count* values.:: - STACK.extend(STACK.pop()[:count:-1]) + assert(len(STACK[-1]) == count) + STACK.extend(STACK.pop()[:-count-1:-1]) .. opcode:: UNPACK_EX (counts) From 23655fc62714aeb374d77bd895e318fb55689fe4 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Mon, 31 Jul 2023 01:21:43 -0400 Subject: [PATCH 0481/1206] [3.12] gh-99079: Update macOS installer to use OpenSSL 3.0.9. (gh-107472) --- Doc/license.rst | 308 ++++++++++-------- Mac/BuildScript/build-installer.py | 6 +- ...3-07-30-23-42-20.gh-issue-99079.JAtoh1.rst | 1 + 3 files changed, 184 insertions(+), 131 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst diff --git a/Doc/license.rst b/Doc/license.rst index 005d048b6eb209..812a0adffe1a49 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -659,134 +659,186 @@ The modules :mod:`hashlib`, :mod:`posix`, :mod:`ssl`, :mod:`crypt` use the OpenSSL library for added performance if made available by the operating system. Additionally, the Windows and macOS installers for Python may include a copy of the OpenSSL libraries, so we include a copy -of the OpenSSL license here:: - - - LICENSE ISSUES - ============== - - The OpenSSL toolkit stays under a dual license, i.e. both the conditions of - the OpenSSL License and the original SSLeay license apply to the toolkit. - See below for the actual license texts. Actually both licenses are BSD-style - Open Source licenses. In case of any license issues related to OpenSSL - please contact openssl-core@openssl.org. - - OpenSSL License - --------------- - - /* ==================================================================== - * Copyright (c) 1998-2008 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - - Original SSLeay License - ----------------------- - - /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ +of the OpenSSL license here. For the OpenSSL 3.0 release, +and later releases derived from that, the Apache License v2 applies:: + + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS expat diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 9729759434a9f4..0fc25ec74565df 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -246,9 +246,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.1.1u", - url="https://www.openssl.org/source/openssl-1.1.1u.tar.gz", - checksum='e2f8d84b523eecd06c7be7626830370300fbcc15386bf5142d72758f6963ebc6', + name="OpenSSL 3.0.9", + url="https://www.openssl.org/source/openssl-3.0.9.tar.gz", + checksum='eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst b/Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst new file mode 100644 index 00000000000000..d0eef4ec1003ce --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst @@ -0,0 +1 @@ +Update macOS installer to use OpenSSL 3.0.9. From 08f8165b132390b27cce8d78203383bf3ca364bc Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Mon, 31 Jul 2023 01:22:34 -0400 Subject: [PATCH 0482/1206] [3.12] Update macOS installer screens for 3.12rc/final. (GH-107473) --- Mac/BuildScript/resources/ReadMe.rtf | 10 ++------- Mac/BuildScript/resources/Welcome.rtf | 29 +-------------------------- 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf index 5bc356d5267045..384840cd92dc5b 100644 --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -8,25 +8,19 @@ \f0\fs24 \cf0 This package will install Python $FULL_VERSION for macOS $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES.\ \ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 - -\f1\b \cf0 NOTE: -\f0\b0 This is a beta preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 -\cf0 \ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \f1\b \cf0 \ul \ulc0 Certificate verification and OpenSSL\ \f0\b0 \ulnone \ -This package includes its own private copy of OpenSSL 1.1.1. The trust certificates in system and user keychains managed by the +This package includes its own private copy of OpenSSL 3.0. The trust certificates in system and user keychains managed by the \f2\i Keychain Access \f0\i0 application and the \f2\i security \f0\i0 command line utility are not used as defaults by the Python \f3 ssl \f0 module. A sample command script is included in -\f3 /Applications/Python 3.11 +\f3 /Applications/Python 3.12 \f0 to install a curated bundle of default root certificates from the third-party \f3 certifi \f0 package ({\field{\*\fldinst{HYPERLINK "https://pypi.org/project/certifi/"}}{\fldrslt https://pypi.org/project/certifi/}}). Double-click on diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index dfb02a0b314b7a..8ae9b01b6ddbcf 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -12,9 +12,8 @@ \f1\b macOS $MACOSX_DEPLOYMENT_TARGET \f0\b0 .\ \ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 -\f1\b \cf0 Python for macOS +\f1\b Python for macOS \f0\b0 consists of the {\field{\*\fldinst{HYPERLINK "https://www.python.org"}}{\fldrslt Python}} programming language interpreter and its batteries-included standard library to allow easy access to macOS features. It also includes the Python integrated development environment, \f1\b IDLE \f0\b0 . You can also use the included @@ -24,30 +23,4 @@ At the end of this install, click on \f2 Install Certificates \f0 to install a set of current SSL root certificates.\ -\ - -\f1\b [UPDATE: fixed in macOS 13.4] macOS 13 Ventura users -\f0\b0 : Due to an issue with the macOS -\f1\b Installer -\f0\b0 app in macOS 13 Ventura updates prior to macOS 13.4, installation of some third-party packages including this Python package may fail with a vague -\f1\b "The installer encountered an error" -\f0\b0 message if the -\f1\b Installer -\f0\b0 app does not have permission to access the folder containing the downloaded installer file, typically in the -\f1\b Downloads -\f0\b0 folder. Go to -\f1\b System Settings -\f0\b0 -> -\f1\b Privacy & Security -\f0\b0 -> -\f1\b Files and Folders -\f0\b0 , then click the mark in front of -\f1\b Installer -\f0\b0 to expand, and enable -\f1\b Downloads Folder -\f0\b0 by moving the toggle to the right. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. This problem has been resolved in macOS 13.4.\ -\ - -\f1\b NOTE: -\f0\b0 This is a beta test preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ } \ No newline at end of file From f9f9bc9bb74ae58155428527dc1b67d5e1b8c80f Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Mon, 31 Jul 2023 03:12:07 -0400 Subject: [PATCH 0483/1206] [3.12] gh-99079: add What's New item (GH-107481) --- Doc/whatsnew/3.12.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 71b9358323e3d0..2ec25eb25ecb47 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1586,6 +1586,8 @@ Build Changes :file:`!configure`. (Contributed by Christian Heimes in :gh:`89886`.) +* Windows builds and macOS installers from python.org now use OpenSSL 3.0. + C API Changes ============= From 1d21c99e1d234041cf0593df3dc5591c10223d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 31 Jul 2023 08:28:36 +0000 Subject: [PATCH 0484/1206] [3.12] gh-105751, test_ctypes: Remove disabled tests (GH-105826) (#107483) * The following tests were disabled since the initial ctypes commit in 2006, commit babddfca758abe34ff12023f63b18d745fae7ca9: * Callbacks.test_char_p() * DeletePointerTestCase.test_X() * NumberTestCase.test_perf() * StructureTestCase.test_subclass_creation() * Tests.test_X() of test_byteswap * NumberTestCase.test_bool_from_address() was disabled in 2007 by commit 5dc4fe09b7648f9801558e766b21a3d3b2dcad3b. * Remove check_perf() and run_test() of test_numbers. (cherry picked from commit 8f10140e74d141a0a894702044e213e6f0690d9c) Co-authored-by: Victor Stinner --- Lib/test/test_ctypes/test_byteswap.py | 8 --- Lib/test/test_ctypes/test_callbacks.py | 8 --- Lib/test/test_ctypes/test_keeprefs.py | 31 ---------- Lib/test/test_ctypes/test_numbers.py | 77 ------------------------- Lib/test/test_ctypes/test_structures.py | 9 --- 5 files changed, 133 deletions(-) diff --git a/Lib/test/test_ctypes/test_byteswap.py b/Lib/test/test_ctypes/test_byteswap.py index 7e98559dfbccb6..caefb774cc5375 100644 --- a/Lib/test/test_ctypes/test_byteswap.py +++ b/Lib/test/test_ctypes/test_byteswap.py @@ -14,14 +14,6 @@ def bin(s): # For Structures and Unions, these types are created on demand. class Test(unittest.TestCase): - @unittest.skip('test disabled') - def test_X(self): - print(sys.byteorder, file=sys.stderr) - for i in range(32): - bits = BITS() - setattr(bits, "i%s" % i, 1) - dump(bits) - def test_slots(self): class BigPoint(BigEndianStructure): __slots__ = () diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index b185e388ab1527..0069c640d7927c 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -93,14 +93,6 @@ def test_char(self): self.check_type(c_char, b"x") self.check_type(c_char, b"a") - # disabled: would now (correctly) raise a RuntimeWarning about - # a memory leak. A callback function cannot return a non-integral - # C type without causing a memory leak. - @unittest.skip('test disabled') - def test_char_p(self): - self.check_type(c_char_p, "abc") - self.check_type(c_char_p, "def") - def test_pyobject(self): o = () from sys import getrefcount as grc diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index 94c02573fa19d8..e20adc7696f501 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -93,37 +93,6 @@ def test_p_cint(self): x = pointer(i) self.assertEqual(x._objects, {'1': i}) -class DeletePointerTestCase(unittest.TestCase): - @unittest.skip('test disabled') - def test_X(self): - class X(Structure): - _fields_ = [("p", POINTER(c_char_p))] - x = X() - i = c_char_p("abc def") - from sys import getrefcount as grc - print("2?", grc(i)) - x.p = pointer(i) - print("3?", grc(i)) - for i in range(320): - c_int(99) - x.p[0] - print(x.p[0]) -## del x -## print "2?", grc(i) -## del i - import gc - gc.collect() - for i in range(320): - c_int(99) - x.p[0] - print(x.p[0]) - print(x.p.contents) -## print x._objects - - x.p[0] = "spam spam" -## print x.p[0] - print("+" * 42) - print(x._objects) class PointerToStructure(unittest.TestCase): def test(self): diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index db500e812beb15..dc5d4a713c5b00 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -82,14 +82,6 @@ def test_typeerror(self): self.assertRaises(TypeError, t, "") self.assertRaises(TypeError, t, None) - @unittest.skip('test disabled') - def test_valid_ranges(self): - # invalid values of the correct type - # raise ValueError (not OverflowError) - for t, (l, h) in zip(unsigned_types, unsigned_ranges): - self.assertRaises(ValueError, t, l-1) - self.assertRaises(ValueError, t, h+1) - def test_from_param(self): # the from_param class method attribute always # returns PyCArgObject instances @@ -205,19 +197,6 @@ def test_char_from_address(self): a[0] = ord('?') self.assertEqual(v.value, b'?') - # array does not support c_bool / 't' - @unittest.skip('test disabled') - def test_bool_from_address(self): - from ctypes import c_bool - from array import array - a = array(c_bool._type_, [True]) - v = t.from_address(a.buffer_info()[0]) - self.assertEqual(v.value, a[0]) - self.assertEqual(type(v) is t) - a[0] = False - self.assertEqual(v.value, a[0]) - self.assertEqual(type(v) is t) - def test_init(self): # c_int() can be initialized from Python's int, and c_int. # Not from c_long or so, which seems strange, abc should @@ -234,62 +213,6 @@ def test_float_overflow(self): if (hasattr(t, "__ctype_le__")): self.assertRaises(OverflowError, t.__ctype_le__, big_int) - @unittest.skip('test disabled') - def test_perf(self): - check_perf() - -from ctypes import _SimpleCData -class c_int_S(_SimpleCData): - _type_ = "i" - __slots__ = [] - -def run_test(rep, msg, func, arg=None): -## items = [None] * rep - items = range(rep) - from time import perf_counter as clock - if arg is not None: - start = clock() - for i in items: - func(arg); func(arg); func(arg); func(arg); func(arg) - stop = clock() - else: - start = clock() - for i in items: - func(); func(); func(); func(); func() - stop = clock() - print("%15s: %.2f us" % (msg, ((stop-start)*1e6/5/rep))) - -def check_perf(): - # Construct 5 objects - from ctypes import c_int - - REP = 200000 - - run_test(REP, "int()", int) - run_test(REP, "int(999)", int) - run_test(REP, "c_int()", c_int) - run_test(REP, "c_int(999)", c_int) - run_test(REP, "c_int_S()", c_int_S) - run_test(REP, "c_int_S(999)", c_int_S) - -# Python 2.3 -OO, win2k, P4 700 MHz: -# -# int(): 0.87 us -# int(999): 0.87 us -# c_int(): 3.35 us -# c_int(999): 3.34 us -# c_int_S(): 3.23 us -# c_int_S(999): 3.24 us - -# Python 2.2 -OO, win2k, P4 700 MHz: -# -# int(): 0.89 us -# int(999): 0.89 us -# c_int(): 9.99 us -# c_int(999): 10.02 us -# c_int_S(): 9.87 us -# c_int_S(999): 9.85 us if __name__ == '__main__': -## check_perf() unittest.main() diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index df39dc7f50d3f7..a40ce3e86695a1 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -359,15 +359,6 @@ def get_except(self, func, *args): except Exception as detail: return detail.__class__, str(detail) - @unittest.skip('test disabled') - def test_subclass_creation(self): - meta = type(Structure) - # same as 'class X(Structure): pass' - # fails, since we need either a _fields_ or a _abstract_ attribute - cls, msg = self.get_except(meta, "X", (Structure,), {}) - self.assertEqual((cls, msg), - (AttributeError, "class must define a '_fields_' attribute")) - def test_abstract_class(self): class X(Structure): _abstract_ = "something" From 04bd8c76b2578fb6715d6766c637f2b4d3e6a52f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 02:16:30 -0700 Subject: [PATCH 0485/1206] [3.12] gh-104280: Add test cases for DTrace probes (GH-107125) (#107489) gh-104280: Add test cases for DTrace probes (GH-107125) (cherry picked from commit a1c737b73d3658be0e1d072a340d42e3d96373c6) Co-authored-by: Furkan Onder --- Lib/test/test_dtrace.py | 82 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 4b971deacc1a5c..e1adf8e9748506 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -3,6 +3,7 @@ import re import subprocess import sys +import sysconfig import types import unittest @@ -173,6 +174,87 @@ class SystemTapOptimizedTests(TraceTests, unittest.TestCase): backend = SystemTapBackend() optimize_python = 2 +class CheckDtraceProbes(unittest.TestCase): + @classmethod + def setUpClass(cls): + if sysconfig.get_config_var('WITH_DTRACE'): + readelf_major_version, readelf_minor_version = cls.get_readelf_version() + if support.verbose: + print(f"readelf version: {readelf_major_version}.{readelf_minor_version}") + else: + raise unittest.SkipTest("CPython must be configured with the --with-dtrace option.") + + + @staticmethod + def get_readelf_version(): + try: + cmd = ["readelf", "--version"] + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + with proc: + version, stderr = proc.communicate() + + if proc.returncode: + raise Exception( + f"Command {' '.join(cmd)!r} failed " + f"with exit code {proc.returncode}: " + f"stdout={version!r} stderr={stderr!r}" + ) + except OSError: + raise unittest.SkipTest("Couldn't find readelf on the path") + + # Regex to parse: + # 'GNU readelf (GNU Binutils) 2.40.0\n' -> 2.40 + match = re.search(r"^(?:GNU) readelf.*?\b(\d+)\.(\d+)", version) + if match is None: + raise unittest.SkipTest(f"Unable to parse readelf version: {version}") + + return int(match.group(1)), int(match.group(2)) + + def get_readelf_output(self): + command = ["readelf", "-n", sys.executable] + stdout, _ = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + ).communicate() + return stdout + + def test_check_probes(self): + readelf_output = self.get_readelf_output() + + available_probe_names = [ + "Name: import__find__load__done", + "Name: import__find__load__start", + "Name: audit", + "Name: gc__start", + "Name: gc__done", + ] + + for probe_name in available_probe_names: + with self.subTest(probe_name=probe_name): + self.assertIn(probe_name, readelf_output) + + @unittest.expectedFailure + def test_missing_probes(self): + readelf_output = self.get_readelf_output() + + # Missing probes will be added in the future. + missing_probe_names = [ + "Name: function__entry", + "Name: function__return", + "Name: line", + ] + + for probe_name in missing_probe_names: + with self.subTest(probe_name=probe_name): + self.assertIn(probe_name, readelf_output) + if __name__ == '__main__': unittest.main() From 54aaaadef8a44324f6be674707c67a3516470ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 31 Jul 2023 09:16:45 +0000 Subject: [PATCH 0486/1206] [3.12] gh-46376: Return existing pointer when possible in ctypes (GH-107131) (#107487) (cherry picked from commit 08447b5deb47e2a0df87fa0a0576d300e5c909b4) Co-authored-by: Konstantin --- Lib/test/test_ctypes/test_keeprefs.py | 27 +++++++++++++++++ ...3-07-24-01-21-16.gh-issue-46376.w-xuDL.rst | 1 + Modules/_ctypes/_ctypes.c | 29 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index e20adc7696f501..61650ad1704753 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -93,6 +93,33 @@ def test_p_cint(self): x = pointer(i) self.assertEqual(x._objects, {'1': i}) + def test_pp_ownership(self): + d = c_int(123) + n = c_int(456) + + p = pointer(d) + pp = pointer(p) + + self.assertIs(pp._objects['1'], p) + self.assertIs(pp._objects['0']['1'], d) + + pp.contents.contents = n + + self.assertIs(pp._objects['1'], p) + self.assertIs(pp._objects['0']['1'], n) + + self.assertIs(p._objects['1'], n) + self.assertEqual(len(p._objects), 1) + + del d + del p + + self.assertIs(pp._objects['0']['1'], n) + self.assertEqual(len(pp._objects), 2) + + del n + + self.assertEqual(len(pp._objects), 2) class PointerToStructure(unittest.TestCase): def test(self): diff --git a/Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst b/Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst new file mode 100644 index 00000000000000..8e8f0245b4539b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst @@ -0,0 +1 @@ +Prevent memory leak and use-after-free when using pointers to pointers with ctypes diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 534ef8c1d6cf8f..8496077322a662 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5122,6 +5122,8 @@ static PyObject * Pointer_get_contents(CDataObject *self, void *closure) { StgDictObject *stgdict; + PyObject *keep, *ptr_probe; + CDataObject *ptr2ptr; if (*(void **)self->b_ptr == NULL) { PyErr_SetString(PyExc_ValueError, @@ -5131,6 +5133,33 @@ Pointer_get_contents(CDataObject *self, void *closure) stgdict = PyObject_stgdict((PyObject *)self); assert(stgdict); /* Cannot be NULL for pointer instances */ + + keep = GetKeepedObjects(self); + if (keep != NULL) { + // check if it's a pointer to a pointer: + // pointers will have '0' key in the _objects + ptr_probe = PyDict_GetItemString(keep, "0"); + + if (ptr_probe != NULL) { + ptr2ptr = (CDataObject*) PyDict_GetItemString(keep, "1"); + if (ptr2ptr == NULL) { + PyErr_SetString(PyExc_ValueError, + "Unexpected NULL pointer in _objects"); + return NULL; + } + // don't construct a new object, + // return existing one instead to preserve refcount + assert( + *(void**) self->b_ptr == ptr2ptr->b_ptr || + *(void**) self->b_value.c == ptr2ptr->b_ptr || + *(void**) self->b_ptr == ptr2ptr->b_value.c || + *(void**) self->b_value.c == ptr2ptr->b_value.c + ); // double-check that we are returning the same thing + Py_INCREF(ptr2ptr); + return (PyObject *) ptr2ptr; + } + } + return PyCData_FromBaseObj(stgdict->proto, (PyObject *)self, 0, *(void **)self->b_ptr); From 8f080a290bd45f4664d3a457256310cc02883d7d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 05:27:59 -0700 Subject: [PATCH 0487/1206] [3.12] gh-102509: Start initializing `ob_digit` of `_PyLongValue` (GH-102510) (#107464) gh-102509: Start initializing `ob_digit` of `_PyLongValue` (GH-102510) (cherry picked from commit fc130c47daa715d60d8925c478a96d5083e47b6a) Co-authored-by: Illia Volochii --- .../Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst | 2 ++ Objects/longobject.c | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst diff --git a/Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst b/Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst new file mode 100644 index 00000000000000..d1a8e8b5a8d3c4 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst @@ -0,0 +1,2 @@ +Start initializing ``ob_digit`` during creation of :c:type:`PyLongObject` +objects. Patch by Illia Volochii. diff --git a/Objects/longobject.c b/Objects/longobject.c index 5fca55e5c3a2be..5d9b413861478a 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -163,6 +163,9 @@ _PyLong_New(Py_ssize_t size) } _PyLong_SetSignAndDigitCount(result, size != 0, size); _PyObject_Init((PyObject*)result, &PyLong_Type); + /* The digit has to be initialized explicitly to avoid + * use-of-uninitialized-value. */ + result->long_value.ob_digit[0] = 0; return result; } From 99518bbbf47a198f8c51e82e7357ac7efdafdcd8 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Mon, 31 Jul 2023 20:34:16 +0800 Subject: [PATCH 0488/1206] =?UTF-8?q?[3.12]=20gh-106263:=20Fix=20segfault?= =?UTF-8?q?=20in=20`signaldict=5Frepr`=20=20in=20`=5Fdecimal`=20module=20(?= =?UTF-8?q?#=E2=80=A6=20(#107491)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> (cherry picked from commit 3979150a0d406707f6d253d7c15fb32c1e005a77) --- Lib/test/test_decimal.py | 30 +++++++++++++++++++ ...-06-30-16-42-44.gh-issue-106263.tk-t93.rst | 2 ++ Modules/_decimal/_decimal.c | 29 ++++++++++++++++-- Tools/c-analyzer/cpython/ignored.tsv | 1 + 4 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 749496e3e9455e..d0ba34803c21e6 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -5682,6 +5682,36 @@ def test_maxcontext_exact_arith(self): self.assertEqual(Decimal(400) ** -1, Decimal('0.0025')) + def test_c_signaldict_segfault(self): + # See gh-106263 for details. + SignalDict = type(C.Context().flags) + sd = SignalDict() + err_msg = "invalid signal dict" + + with self.assertRaisesRegex(ValueError, err_msg): + len(sd) + + with self.assertRaisesRegex(ValueError, err_msg): + iter(sd) + + with self.assertRaisesRegex(ValueError, err_msg): + repr(sd) + + with self.assertRaisesRegex(ValueError, err_msg): + sd[C.InvalidOperation] = True + + with self.assertRaisesRegex(ValueError, err_msg): + sd[C.InvalidOperation] + + with self.assertRaisesRegex(ValueError, err_msg): + sd == C.Context().flags + + with self.assertRaisesRegex(ValueError, err_msg): + C.Context().flags == sd + + with self.assertRaisesRegex(ValueError, err_msg): + sd.copy() + @requires_docstrings @requires_cdecimal class SignatureTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst b/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst new file mode 100644 index 00000000000000..23763818d84ba5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst @@ -0,0 +1,2 @@ +Fix crash when calling ``repr`` with a manually constructed SignalDict object. +Patch by Charlie Zhao. \ No newline at end of file diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 70e18edb464538..70b13982bb0cc4 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -246,14 +246,12 @@ value_error_int(const char *mesg) return -1; } -#ifdef CONFIG_32 static PyObject * value_error_ptr(const char *mesg) { PyErr_SetString(PyExc_ValueError, mesg); return NULL; } -#endif static int type_error_int(const char *mesg) @@ -540,6 +538,8 @@ getround(PyObject *v) initialized to new SignalDicts. Once a SignalDict is tied to a context, it cannot be deleted. */ +static const char *INVALID_SIGNALDICT_ERROR_MSG = "invalid signal dict"; + static int signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED) { @@ -548,8 +548,11 @@ signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED) } static Py_ssize_t -signaldict_len(PyObject *self UNUSED) +signaldict_len(PyObject *self) { + if (SdFlagAddr(self) == NULL) { + return value_error_int(INVALID_SIGNALDICT_ERROR_MSG); + } return SIGNAL_MAP_LEN; } @@ -557,6 +560,9 @@ static PyObject *SignalTuple; static PyObject * signaldict_iter(PyObject *self UNUSED) { + if (SdFlagAddr(self) == NULL) { + return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG); + } return PyTuple_Type.tp_iter(SignalTuple); } @@ -564,6 +570,9 @@ static PyObject * signaldict_getitem(PyObject *self, PyObject *key) { uint32_t flag; + if (SdFlagAddr(self) == NULL) { + return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG); + } flag = exception_as_flag(key); if (flag & DEC_ERRORS) { @@ -579,6 +588,10 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) uint32_t flag; int x; + if (SdFlagAddr(self) == NULL) { + return value_error_int(INVALID_SIGNALDICT_ERROR_MSG); + } + if (value == NULL) { return value_error_int("signal keys cannot be deleted"); } @@ -611,6 +624,10 @@ signaldict_repr(PyObject *self) const char *b[SIGNAL_MAP_LEN]; /* bool */ int i; + if (SdFlagAddr(self) == NULL) { + return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG); + } + assert(SIGNAL_MAP_LEN == 9); for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { @@ -632,6 +649,9 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) PyObject *res = Py_NotImplemented; assert(PyDecSignalDict_Check(v)); + if ((SdFlagAddr(v) == NULL) || (SdFlagAddr(w) == NULL)) { + return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG); + } if (op == Py_EQ || op == Py_NE) { if (PyDecSignalDict_Check(w)) { @@ -660,6 +680,9 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) static PyObject * signaldict_copy(PyObject *self, PyObject *args UNUSED) { + if (SdFlagAddr(self) == NULL) { + return value_error_ptr(INVALID_SIGNALDICT_ERROR_MSG); + } return flags_as_dict(SdFlags(self)); } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index afc28e551813b4..78be97da41b503 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -213,6 +213,7 @@ Modules/_decimal/_decimal.c - invalid_rounding_err - Modules/_decimal/_decimal.c - invalid_signals_err - Modules/_decimal/_decimal.c - signal_map - Modules/_decimal/_decimal.c - ssize_constants - +Modules/_decimal/_decimal.c - INVALID_SIGNALDICT_ERROR_MSG - Modules/_elementtree.c - ExpatMemoryHandler - Modules/_hashopenssl.c - py_hashes - Modules/_hacl/Hacl_Hash_SHA1.c - _h0 - From 831fd19d30a4051d96117f42b625642ee8a250fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 31 Jul 2023 15:01:25 +0000 Subject: [PATCH 0489/1206] [3.12] gh-105751: Remove obsolete `object` base class in some ctypes tests (GH-107460) (#107501) (cherry picked from commit 520efecfc3aed34d3a44545c7cd872d1aea8c7dc) Co-authored-by: Tomas R --- Lib/test/test_ctypes/test_as_parameter.py | 6 +++--- Lib/test/test_ctypes/test_callbacks.py | 2 +- Lib/test/test_ctypes/test_numbers.py | 8 ++++---- Lib/test/test_ctypes/test_parameters.py | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index e9ec9ad847b487..36fec572b16741 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -194,7 +194,7 @@ class S8I(Structure): def test_recursive_as_param(self): from ctypes import c_int - class A(object): + class A: pass a = A() @@ -205,7 +205,7 @@ class A(object): #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class AsParamWrapper(object): +class AsParamWrapper: def __init__(self, param): self._as_parameter_ = param @@ -214,7 +214,7 @@ class AsParamWrapperTestCase(BasicWrapTestCase): #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class AsParamPropertyWrapper(object): +class AsParamPropertyWrapper: def __init__(self, param): self._param = param diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index 0069c640d7927c..a9c6524b4d4ee7 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -122,7 +122,7 @@ def test_unsupported_restype_2(self): def test_issue_7959(self): proto = self.functype.__func__(None) - class X(object): + class X: def func(self): pass def __init__(self): self.v = proto(self.func) diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index dc5d4a713c5b00..a7696376a5ab05 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -98,7 +98,7 @@ def test_byref(self): def test_floats(self): # c_float and c_double can be created from # Python int and float - class FloatLike(object): + class FloatLike: def __float__(self): return 2.0 f = FloatLike() @@ -109,15 +109,15 @@ def __float__(self): self.assertEqual(t(f).value, 2.0) def test_integers(self): - class FloatLike(object): + class FloatLike: def __float__(self): return 2.0 f = FloatLike() - class IntLike(object): + class IntLike: def __int__(self): return 2 d = IntLike() - class IndexLike(object): + class IndexLike: def __index__(self): return 2 i = IndexLike() diff --git a/Lib/test/test_ctypes/test_parameters.py b/Lib/test/test_ctypes/test_parameters.py index 06cc95107b79fa..f5afa76fd92a38 100644 --- a/Lib/test/test_ctypes/test_parameters.py +++ b/Lib/test/test_ctypes/test_parameters.py @@ -167,7 +167,7 @@ def test_noctypes_argtype(self): # TypeError: has no from_param method self.assertRaises(TypeError, setattr, func, "argtypes", (object,)) - class Adapter(object): + class Adapter: def from_param(cls, obj): return None @@ -175,7 +175,7 @@ def from_param(cls, obj): self.assertEqual(func(None), None) self.assertEqual(func(object()), None) - class Adapter(object): + class Adapter: def from_param(cls, obj): return obj @@ -184,7 +184,7 @@ def from_param(cls, obj): self.assertRaises(ArgumentError, func, object()) self.assertEqual(func(c_void_p(42)), 42) - class Adapter(object): + class Adapter: def from_param(cls, obj): raise ValueError(obj) From 9f58d9ec9061f1e6ec37432b6031b7c9a580fb6c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 08:33:00 -0700 Subject: [PATCH 0490/1206] [3.12] gh-105578: Add more usage examples to `typing.AnyStr` docs (GH-107045) (#107503) gh-105578: Add more usage examples to `typing.AnyStr` docs (GH-107045) ``typing.AnyStr`` has different semantics to ``str | bytes``, which often leads to user confusion (cherry picked from commit f877b32b879f2076bb1c52826af0c28ebf1aaeed) Co-authored-by: Michael The --- Doc/library/typing.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 11c39a444ef65d..60bf06e471cb20 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -849,6 +849,21 @@ using ``[]``. concat(b"foo", b"bar") # OK, output has type 'bytes' concat("foo", b"bar") # Error, cannot mix str and bytes + Note that, despite its name, ``AnyStr`` has nothing to do with the + :class:`Any` type, nor does it mean "any string". In particular, ``AnyStr`` + and ``str | bytes`` are different from each other and have different use + cases:: + + # Invalid use of AnyStr: + # The type variable is used only once in the function signature, + # so cannot be "solved" by the type checker + def greet_bad(cond: bool) -> AnyStr: + return "hi there!" if cond else b"greetings!" + + # The better way of annotating this function: + def greet_proper(cond: bool) -> str | bytes: + return "hi there!" if cond else b"greetings!" + .. data:: LiteralString Special type that includes only literal strings. From f66b992e27e7af534606132a48837b190db2d81c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 08:57:25 -0700 Subject: [PATCH 0491/1206] [3.12] gh-106368: Add test for Argument Clinic misbehaving custom converter_init() (GH-107496) (#107499) (cherry picked from commit 2c5d206b33e4cdcafaaaf1eeaa189c10de332dc5) Co-authored-by: Erlend E. Aasland --- Lib/test/test_clinic.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 3d740910a57ae6..520cc51302212d 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -314,6 +314,26 @@ def test_unknown_destination_command(self): msg = "unknown destination command 'nosuchcommand'" self.assertIn(msg, out) + def test_no_access_to_members_in_converter_init(self): + out = self.expect_failure(""" + /*[python input] + class Custom_converter(CConverter): + converter = "some_c_function" + def converter_init(self): + self.function.noaccess + [python start generated code]*/ + /*[clinic input] + module test + test.fn + a: Custom + [clinic start generated code]*/ + """) + msg = ( + "Stepped on a land mine, trying to access attribute 'noaccess':\n" + "Don't access members of self.function inside converter_init!" + ) + self.assertIn(msg, out) + class ClinicGroupPermuterTest(TestCase): def _test(self, l, m, r, output): From 5f7862dc1f0ba7e47fc01acb7f7a2e0f68176924 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 10:16:00 -0700 Subject: [PATCH 0492/1206] [3.12] GH-101291: Add warning to "what's new" that `PyLongObject` internals have changed. (GH-107388) (#107392) (cherry picked from commit 1ee605c5888fbc3d51b3e7610bac38ea6bc25e31) Co-authored-by: Mark Shannon --- Doc/whatsnew/3.12.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 2ec25eb25ecb47..fe912e8422e9ee 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1867,6 +1867,17 @@ Porting to Python 3.12 subinterpreter that they don't support (or haven't yet been loaded in). See :gh:`104668` for more info. +* :c:struct:`PyLongObject` has had its internals changed for better performance. + Although the internals of :c:struct:`PyLongObject` are private, they are used + by some extension modules. + The internal fields should no longer be accessed directly, instead the API + functions beginning ``PyLong_...`` should be used instead. + Two new *unstable* API functions are provided for efficient access to the + value of :c:struct:`PyLongObject`\s which fit into a single machine word: + + * :c:func:`PyUnstable_Long_IsCompact` + * :c:func:`PyUnstable_Long_CompactValue` + Deprecated ---------- From 0fbe69fc41dd2e0bcbe4ab68fc82b727a4cc607b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:33:32 -0700 Subject: [PATCH 0493/1206] [3.12] gh-106762: Add news for `EnumMeta.__getattr__` removal (GH-107466) (GH-107509) gh-106762: Add news for `EnumMeta.__getattr__` removal (GH-107466) (cherry picked from commit de51dede5b48ef23d7d33d92f3616824e23fd205) Co-authored-by: Jacob Walls --- Doc/whatsnew/3.12.rst | 4 ++++ Misc/NEWS.d/3.12.0a1.rst | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index fe912e8422e9ee..d7389f696ea2e3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1234,6 +1234,10 @@ Removed (Contributed by Pradyun Gedam in :gh:`95299`.) +* :mod:`enum`: Remove ``EnumMeta.__getattr__``, which is no longer needed for + enum attribute access. + (Contributed by Ethan Furman in :gh:`95083`.) + * :mod:`ftplib`: Remove the ``FTP_TLS.ssl_version`` class attribute: use the *context* parameter instead. (Contributed by Victor Stinner in :gh:`94172`.) diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 1888cae0ba720d..84036788774f76 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -2752,7 +2752,7 @@ by Shin-myoung-serp. .. section: Library Add deprecation warning for enum ``member.member`` access (e.g. -``Color.RED.BLUE``). +``Color.RED.BLUE``). Remove ``EnumMeta.__getattr__``. .. From fd6085529935afec085cea0729507ba6d4b34ab3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:42:58 -0700 Subject: [PATCH 0494/1206] [3.12] gh-107507: Replace 'The goals of Argument Clinic' with a summary (GH-107508) (#107516) Summarise the goals of Argument Clinic in a single sentence. Mention that Argument Clinic was introduced with PEP-436. (cherry picked from commit abb71c6a8f73482c910ffdf050a86089a48e0e60) Co-authored-by: Erlend E. Aasland --- Doc/howto/clinic.rst | 58 +++----------------------------------------- 1 file changed, 4 insertions(+), 54 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 7aafd48711b58e..9c9a4f45dd0f58 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -13,8 +13,10 @@ Argument Clinic How-To .. topic:: Abstract Argument Clinic is a preprocessor for CPython C files. - Its purpose is to automate all the boilerplate involved - with writing argument parsing code for "builtins", + It was introduced in Python 3.4 with :pep:`436`, + in order to provide introspection signatures, + and to generate performant and tailor-made boilerplate code + for argument parsing in CPython builtins, module level functions, and class methods. This document is divided in four major sections: @@ -44,58 +46,6 @@ Argument Clinic How-To Background ========== - -The goals of Argument Clinic ----------------------------- - -Argument Clinic's primary goal -is to take over responsibility for all argument parsing code -inside CPython. This means that, when you convert a function -to work with Argument Clinic, that function should no longer -do any of its own argument parsing—the code generated by -Argument Clinic should be a "black box" to you, where CPython -calls in at the top, and your code gets called at the bottom, -with ``PyObject *args`` (and maybe ``PyObject *kwargs``) -magically converted into the C variables and types you need. - -In order for Argument Clinic to accomplish its primary goal, -it must be easy to use. Currently, working with CPython's -argument parsing library is a chore, requiring maintaining -redundant information in a surprising number of places. -When you use Argument Clinic, you don't have to repeat yourself. - -Obviously, no one would want to use Argument Clinic unless -it's solving their problem—and without creating new problems of -its own. -So it's paramount that Argument Clinic generate correct code. -It'd be nice if the code was faster, too, but at the very least -it should not introduce a major speed regression. (Eventually Argument -Clinic *should* make a major speedup possible—we could -rewrite its code generator to produce tailor-made argument -parsing code, rather than calling the general-purpose CPython -argument parsing library. That would make for the fastest -argument parsing possible!) - -Additionally, Argument Clinic must be flexible enough to -work with any approach to argument parsing. Python has -some functions with some very strange parsing behaviors; -Argument Clinic's goal is to support all of them. - -Finally, the original motivation for Argument Clinic was -to provide introspection "signatures" for CPython builtins. -It used to be, the introspection query functions would throw -an exception if you passed in a builtin. With Argument -Clinic, that's a thing of the past! - -One idea you should keep in mind, as you work with -Argument Clinic: the more information you give it, the -better job it'll be able to do. -Argument Clinic is admittedly relatively simple right -now. But as it evolves it will get more sophisticated, -and it should be able to do many interesting and smart -things with all the information you give it. - - Basic concepts -------------- From 3f6afafa7e7294786913dbecf79fe42c8b510f85 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 16:15:13 -0700 Subject: [PATCH 0495/1206] [3.12] gh-107306: Add a Doc Entry for Py_mod_multiple_interpreters (GH-107403) (gh-107521) gh-107306: Add a Doc Entry for Py_mod_multiple_interpreters (GH-107403) It was added in 3.12 for PEP 684 (per-interpreter GIL). (cherry picked from commit fb344e99aa0da5bef9318684ade69978585fe060) Co-authored-by: Eric Snow --- Doc/c-api/init.rst | 1 + Doc/c-api/module.rst | 31 ++++++++++++++++++++++++++++++ Doc/howto/isolating-extensions.rst | 2 ++ 3 files changed, 34 insertions(+) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 52824b6d88afda..8b960b06871b17 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1555,6 +1555,7 @@ function. You can create and destroy them using the following functions: in any thread where the sub-interpreter is currently active. Otherwise only multi-phase init extension modules (see :pep:`489`) may be imported. + (Also see :c:macro:`Py_mod_multiple_interpreters`.) This must be ``1`` (non-zero) if :c:member:`~PyInterpreterConfig.use_main_obmalloc` is ``0``. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 8ca48c852d4e6f..2b6875d533c825 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -376,6 +376,37 @@ The available slot types are: If multiple ``Py_mod_exec`` slots are specified, they are processed in the order they appear in the *m_slots* array. +.. c:macro:: Py_mod_multiple_interpreters + + Specifies one of the following values: + + .. c:macro:: Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED + + The module does not support being imported in subinterpreters. + + .. c:macro:: Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED + + The module supports being imported in subinterpreters, + but only when they share the main interpreter's GIL. + (See :ref:`isolating-extensions-howto`.) + + .. c:macro:: Py_MOD_PER_INTERPRETER_GIL_SUPPORTED + + The module supports being imported in subinterpreters, + even when they have their own GIL. + (See :ref:`isolating-extensions-howto`.) + + This slot determines whether or not importing this module + in a subinterpreter will fail. + + Multiple ``Py_mod_multiple_interpreters`` slots may not be specified + in one module definition. + + If ``Py_mod_multiple_interpreters`` is not specified, the import + machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED``. + + .. versionadded:: 3.12 + See :PEP:`489` for more details on multi-phase initialization. Low-level module creation functions diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 60854c3c034d73..2551fbe87b5c2a 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -1,5 +1,7 @@ .. highlight:: c +.. _isolating-extensions-howto: + *************************** Isolating Extension Modules *************************** From 31cd12ab21b305f19732372634cb50940f353e6e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 16:24:45 -0700 Subject: [PATCH 0496/1206] [3.12] gh-99113: Add a What's New Entry for PEP 684 (gh-107520) (gh-107523) gh-99113: Add a What's New Entry for PEP 684 (gh-107520) (cherry picked from commit 79e479c45fc63b6001b206fec832064c31fc1f11) Co-authored-by: Eric Snow --- Doc/whatsnew/3.12.rst | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d7389f696ea2e3..cbf47e4ad835dc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -70,6 +70,10 @@ New grammar features: * :pep:`701`: Syntactic formalization of f-strings +Interpreter improvements: + +* :ref:`whatsnew312-pep684` + New typing features: * :pep:`688`: Making the buffer protocol accessible in Python @@ -277,6 +281,36 @@ The new :class:`inspect.BufferFlags` enum represents the flags that can be used to customize buffer creation. (Contributed by Jelle Zijlstra in :gh:`102500`.) +.. _whatsnew312-pep684: + +PEP 684: A Per-Interpreter GIL +------------------------------ + +Sub-interpreters may now be created with a unique GIL per interpreter. +This allows Python programs to take full advantage of multiple CPU +cores. + +Use the new :c:func:`Py_NewInterpreterFromConfig` function to +create an interpreter with its own GIL:: + + PyInterpreterConfig config = { + .check_multi_interp_extensions = 1, + .gil = PyInterpreterConfig_OWN_GIL, + }; + PyThreadState *tstate = NULL; + PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config); + if (PyStatus_Exception(status)) { + return -1; + } + /* The new interpeter is now active in the current thread. */ + +For further examples how to use the C-API for sub-interpreters with a +per-interpreter GIL, see :source:`Modules/_xxsubinterpretersmodule.c`. + +A Python API is anticipated for 3.13. (See :pep:`554`.) + +(Contributed by Eric Snow in :gh:`104210`, etc.) + New Features Related to Type Hints ================================== @@ -1744,6 +1778,12 @@ New Features (Contributed by Eddie Elizondo in :gh:`84436`.) +* :pep:`684`: Added the new :c:func:`Py_NewInterpreterFromConfig` + function and :c:type:`PyInterpreterConfig`, which may be used + to create sub-interpreters with their own GILs. + (See :ref:`whatsnew312-pep684` for more info.) + (Contributed by Eric Snow in :gh:`104110`.) + * In the limited C API version 3.12, :c:func:`Py_INCREF` and :c:func:`Py_DECREF` functions are now implemented as opaque function calls to hide implementation details. From fc4532a55d23887bae49350d2f939c597d6b5b98 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Jul 2023 16:25:18 -0700 Subject: [PATCH 0497/1206] [3.12] gh-105766: Document that Custom Allocators Must Be Thread-Safe (gh-107519) (gh-107522) gh-105766: Document that Custom Allocators Must Be Thread-Safe (gh-107519) (cherry picked from commit db361a340af3970c279908c8746a6b9ed45f47b8) Co-authored-by: Eric Snow --- Doc/c-api/memory.rst | 6 ++++++ Doc/whatsnew/3.12.rst | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 8968b26b64320a..1df8c2b911ca8f 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -476,6 +476,10 @@ Customize Memory Allocators thread-safe: the :term:`GIL ` is not held when the allocator is called. + For the remaining domains, the allocator must also be thread-safe: + the allocator may be called in different interpreters that do not + share a ``GIL``. + If the new allocator is not a hook (does not call the previous allocator), the :c:func:`PyMem_SetupDebugHooks` function must be called to reinstall the debug hooks on top on the new allocator. @@ -500,6 +504,8 @@ Customize Memory Allocators **must** wrap the existing allocator. Substituting the current allocator for some other arbitrary one is **not supported**. + .. versionchanged:: 3.12 + All allocators must be thread-safe. .. c:function:: void PyMem_SetupDebugHooks(void) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index cbf47e4ad835dc..39e702bb012fb9 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1922,6 +1922,13 @@ Porting to Python 3.12 * :c:func:`PyUnstable_Long_IsCompact` * :c:func:`PyUnstable_Long_CompactValue` +* Custom allocators, set via :c:func:`PyMem_SetAllocator`, are now + required to be thread-safe, regardless of memory domain. Allocators + that don't have their own state, including "hooks", are not affected. + If your custom allocator is not already thread-safe and you need + guidance then please create a new GitHub issue + and CC ``@ericsnowcurrently``. + Deprecated ---------- From b68faa3fa3214cda35d5a34639a7a62b6a98bc6c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 1 Aug 2023 03:42:55 -0700 Subject: [PATCH 0498/1206] [3.12] gh-106092: Fix use-after-free crash in frame_dealloc (GH-106875) (#107532) gh-106092: Fix use-after-free crash in frame_dealloc (GH-106875) It was possible for the trashcan to delay the deallocation of a PyFrameObject until after its corresponding _PyInterpreterFrame has already been freed. So frame_dealloc needs to avoid dereferencing the f_frame pointer unless it first checks that the pointer still points to the interpreter frame within the frame object. (cherry picked from commit 557b05c7a5334de5da3dc94c108c0121f10b9191) Signed-off-by: Anders Kaseorg Co-authored-by: Anders Kaseorg --- .../2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst | 2 ++ Objects/frameobject.c | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst new file mode 100644 index 00000000000000..7fb5b45c763e45 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst @@ -0,0 +1,2 @@ +Fix a segmentation fault caused by a use-after-free bug in ``frame_dealloc`` +when the trashcan delays the deallocation of a ``PyFrameObject``. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index e62cfab80b2e35..ba365750bd4d2b 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -878,9 +878,6 @@ frame_dealloc(PyFrameObject *f) /* It is the responsibility of the owning generator/coroutine * to have cleared the generator pointer */ - assert(f->f_frame->owner != FRAME_OWNED_BY_GENERATOR || - _PyFrame_GetGenerator(f->f_frame)->gi_frame_state == FRAME_CLEARED); - if (_PyObject_GC_IS_TRACKED(f)) { _PyObject_GC_UNTRACK(f); } @@ -888,10 +885,14 @@ frame_dealloc(PyFrameObject *f) Py_TRASHCAN_BEGIN(f, frame_dealloc); PyCodeObject *co = NULL; + /* GH-106092: If f->f_frame was on the stack and we reached the maximum + * nesting depth for deallocations, the trashcan may have delayed this + * deallocation until after f->f_frame is freed. Avoid dereferencing + * f->f_frame unless we know it still points to valid memory. */ + _PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data; + /* Kill all local variables including specials, if we own them */ - if (f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) { - assert(f->f_frame == (_PyInterpreterFrame *)f->_f_frame_data); - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data; + if (f->f_frame == frame && frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) { /* Don't clear code object until the end */ co = frame->f_code; frame->f_code = NULL; From f7e16d74adffb8bc890530caebf0a08a6ea89d36 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:52:28 -0700 Subject: [PATCH 0499/1206] [3.12] Clarify `Self` interaction with subclasses (GH-107511) (#107548) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify `Self` interaction with subclasses (GH-107511) (cherry picked from commit c8872f4285d3b61c252e3384bec6d30618b7d698) Co-authored-by: Alexandru Mărășteanu --- Doc/library/typing.rst | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 60bf06e471cb20..d060066c0cdea1 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -953,13 +953,17 @@ using ``[]``. For example:: - from typing import Self + from typing import Self, reveal_type class Foo: def return_self(self) -> Self: ... return self + class SubclassOfFoo(Foo): pass + + reveal_type(Foo().return_self()) # Revealed type is "Foo" + reveal_type(SubclassOfFoo().return_self()) # Revealed type is "SubclassOfFoo" This annotation is semantically equivalent to the following, albeit in a more succinct fashion:: @@ -973,15 +977,11 @@ using ``[]``. ... return self - In general if something currently follows the pattern of:: - - class Foo: - def return_self(self) -> "Foo": - ... - return self - - You should use :data:`Self` as calls to ``SubclassOfFoo.return_self`` would have - ``Foo`` as the return type and not ``SubclassOfFoo``. + In general, if something returns ``self``, as in the above examples, you + should use ``Self`` as the return annotation. If ``Foo.return_self`` was + annotated as returning ``"Foo"``, then the type checker would infer the + object returned from ``SubclassOfFoo.return_self`` as being of type ``Foo`` + rather than ``SubclassOfFoo``. Other common use cases include: @@ -989,6 +989,17 @@ using ``[]``. of the ``cls`` parameter. - Annotating an :meth:`~object.__enter__` method which returns self. + You should not use ``Self`` as the return annotation if the method is not + guaranteed to return an instance of a subclass when the class is + subclassed:: + + class Eggs: + # Self would be an incorrect return annotation here, + # as the object returned is always an instance of Eggs, + # even in subclasses + def returns_eggs(self) -> "Eggs": + return Eggs() + See :pep:`673` for more details. .. versionadded:: 3.11 From 12d1c494ae236e1a1ce8ae8084f8f9a6b6eb8295 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:23:15 -0700 Subject: [PATCH 0500/1206] [3.12] gh-107471: Fix Refleaks in test_import (gh-107569) (#107571) gh-107471: Fix Refleaks in test_import (gh-107569) gh-107184 introduced a refleak in test_import.SubinterpImportTests (specifically test_singlephase_check_with_setting_and_override and test_single_init_extension_compat). We fix it here by making sure _testsinglephase is removed from sys.modules whenever we clear the runtime's internal state for the module. The underlying problem is strictly contained in the internal function _PyImport_ClearExtension() (AKA _testinternalcapi.clear_extension()), which is only used in tests. (This also fixes an intermittent segfault introduced in the same place, in test_disallowed_reimport.) (cherry picked from commit 017f047183fa33743f7e36c5c360f5c670032be3) Co-authored-by: Eric Snow --- Lib/test/test_import/__init__.py | 3 ++- Python/import.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index cc6e8d4e640cd6..06adf01f18c0a4 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -131,6 +131,7 @@ def _ready_to_import(name=None, source=""): def restore__testsinglephase(*, _orig=_testsinglephase): # We started with the module imported and want to restore # it to its nominal state. + sys.modules.pop('_testsinglephase', None) _orig._clear_globals() _testinternalcapi.clear_extension('_testsinglephase', _orig.__file__) import _testsinglephase @@ -2110,7 +2111,7 @@ def clean_up(): _interpreters.run_string(interpid, textwrap.dedent(f''' name = {self.NAME!r} if name in sys.modules: - sys.modules[name]._clear_globals() + sys.modules.pop(name)._clear_globals() _testinternalcapi.clear_extension(name, {self.FILE!r}) ''')) _interpreters.destroy(interpid) diff --git a/Python/import.c b/Python/import.c index f8f01f1bcd8c62..3f3f2a2b681351 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1080,6 +1080,7 @@ _extensions_cache_delete(PyObject *filename, PyObject *name) However, this decref would be problematic if the module def were dynamically allocated, it were the last ref, and this function were called with an interpreter other than the def's owner. */ + assert(_Py_IsImmortal(entry->value)); entry->value = NULL; finally: From 93fcf7587888e93ff7e45f4422c315f8a5f1ba0d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 3 Aug 2023 07:09:29 -0700 Subject: [PATCH 0501/1206] [3.12] gh-107077: Raise SSLCertVerificationError even if the error is set via SSL_ERROR_SYSCALL (GH-107586) (#107587) Co-authored-by: Pablo Galindo Salgado Co-authored-by: T. Wouters --- .../Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst | 6 ++++++ Modules/_ssl.c | 4 ++++ 2 files changed, 10 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst diff --git a/Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst b/Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst new file mode 100644 index 00000000000000..ecaf437a48e0ae --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst @@ -0,0 +1,6 @@ +Seems that in some conditions, OpenSSL will return ``SSL_ERROR_SYSCALL`` +instead of ``SSL_ERROR_SSL`` when a certification verification has failed, +but the error parameters will still contain ``ERR_LIB_SSL`` and +``SSL_R_CERTIFICATE_VERIFY_FAILED``. We are now detecting this situation and +raising the appropiate ``ssl.SSLCertVerificationError``. Patch by Pablo +Galindo diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 619b4f4e94d06a..e939f95048984b 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -647,6 +647,10 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) errstr = "Some I/O error occurred"; } } else { + if (ERR_GET_LIB(e) == ERR_LIB_SSL && + ERR_GET_REASON(e) == SSL_R_CERTIFICATE_VERIFY_FAILED) { + type = state->PySSLCertVerificationErrorObject; + } p = PY_SSL_ERROR_SYSCALL; } break; From d2c7b25afba3d86ee20331d9fb722a6fe1f768ac Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 3 Aug 2023 08:07:43 -0700 Subject: [PATCH 0502/1206] [3.12] gh-107576: Ensure `__orig_bases__` are our own in `get_original_bases` (GH-107584) (#107592) gh-107576: Ensure `__orig_bases__` are our own in `get_original_bases` (GH-107584) (cherry picked from commit ed4a978449c856372d1a7cd389f91cafe2581c87) Co-authored-by: James Hilton-Balfe Co-authored-by: Chris Bouchard Co-authored-by: Alex Waygood --- Lib/test/test_types.py | 13 +++++++++++++ Lib/types.py | 11 ++++------- .../2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst | 3 +++ 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 81744940f25b82..f2efee90dc0240 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1397,6 +1397,7 @@ class A: pass class B(typing.Generic[T]): pass class C(B[int]): pass class D(B[str], float): pass + self.assertEqual(types.get_original_bases(A), (object,)) self.assertEqual(types.get_original_bases(B), (typing.Generic[T],)) self.assertEqual(types.get_original_bases(C), (B[int],)) @@ -1409,6 +1410,18 @@ class F(list[int]): pass self.assertEqual(types.get_original_bases(E), (list[T],)) self.assertEqual(types.get_original_bases(F), (list[int],)) + class FirstBase(typing.Generic[T]): pass + class SecondBase(typing.Generic[T]): pass + class First(FirstBase[int]): pass + class Second(SecondBase[int]): pass + class G(First, Second): pass + self.assertEqual(types.get_original_bases(G), (First, Second)) + + class First_(typing.Generic[T]): pass + class Second_(typing.Generic[T]): pass + class H(First_, Second_): pass + self.assertEqual(types.get_original_bases(H), (First_, Second_)) + class ClassBasedNamedTuple(typing.NamedTuple): x: int diff --git a/Lib/types.py b/Lib/types.py index 6110e6e1de7249..b4aa19cec40c89 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -165,14 +165,11 @@ class Baz(list[str]): ... assert get_original_bases(int) == (object,) """ try: - return cls.__orig_bases__ + return cls.__dict__.get("__orig_bases__", cls.__bases__) except AttributeError: - try: - return cls.__bases__ - except AttributeError: - raise TypeError( - f'Expected an instance of type, not {type(cls).__name__!r}' - ) from None + raise TypeError( + f"Expected an instance of type, not {type(cls).__name__!r}" + ) from None class DynamicClassAttribute: diff --git a/Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst b/Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst new file mode 100644 index 00000000000000..67677dd3c8ed24 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst @@ -0,0 +1,3 @@ +Fix :func:`types.get_original_bases` to only return +:attr:`!__orig_bases__` if it is present on ``cls`` directly. Patch by +James Hilton-Balfe. From 58af2293c52a1ad3754d254690c0e54f787c545b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:18:29 -0700 Subject: [PATCH 0503/1206] [3.12] gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated Subinterpreters (gh-107567) (#107599) gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated Subinterpreters (gh-107567) The linked list of objects was a global variable, which broke isolation between interpreters, causing crashes. To solve this, we've moved the linked list to each interpreter. (cherry picked from commit 58ef74186795c56e3ec86e8c8f351a1d7826638a) Co-authored-by: Eric Snow --- Include/internal/pycore_object.h | 4 +- Include/internal/pycore_object_state.h | 13 +++-- Include/internal/pycore_runtime_init.h | 11 ++++ ...-08-02-12-24-51.gh-issue-107080.PNolFU.rst | 4 ++ Objects/object.c | 51 ++++++++++++------- Python/pylifecycle.c | 8 +-- 6 files changed, 62 insertions(+), 29 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 0981d1122fec54..5a9403456903ed 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -271,8 +271,8 @@ extern void _PyDebug_PrintTotalRefs(void); #ifdef Py_TRACE_REFS extern void _Py_AddToAllObjects(PyObject *op, int force); -extern void _Py_PrintReferences(FILE *); -extern void _Py_PrintReferenceAddresses(FILE *); +extern void _Py_PrintReferences(PyInterpreterState *, FILE *); +extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h index 94005d77881432..65feb5af969f8b 100644 --- a/Include/internal/pycore_object_state.h +++ b/Include/internal/pycore_object_state.h @@ -11,17 +11,22 @@ extern "C" { struct _py_object_runtime_state { #ifdef Py_REF_DEBUG Py_ssize_t interpreter_leaks; -#else - int _not_used; #endif + int _not_used; }; struct _py_object_state { #ifdef Py_REF_DEBUG Py_ssize_t reftotal; -#else - int _not_used; #endif +#ifdef Py_TRACE_REFS + /* Head of circular doubly-linked list of all objects. These are linked + * together via the _ob_prev and _ob_next members of a PyObject, which + * exist only in a Py_TRACE_REFS build. + */ + PyObject refchain; +#endif + int _not_used; }; diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 4130188079cffa..7aace9f86119c4 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -101,6 +101,7 @@ extern PyTypeObject _PyExc_MemoryError; { .threshold = 10, }, \ }, \ }, \ + .object_state = _py_object_state_INIT(INTERP), \ .dtoa = _dtoa_state_INIT(&(INTERP)), \ .dict_state = _dict_state_INIT, \ .func_state = { \ @@ -130,6 +131,16 @@ extern PyTypeObject _PyExc_MemoryError; .context_ver = 1, \ } +#ifdef Py_TRACE_REFS +# define _py_object_state_INIT(INTERP) \ + { \ + .refchain = {&INTERP.object_state.refchain, &INTERP.object_state.refchain}, \ + } +#else +# define _py_object_state_INIT(INTERP) \ + { 0 } +#endif + // global objects diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst new file mode 100644 index 00000000000000..5084c854360e35 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst @@ -0,0 +1,4 @@ +Trace refs builds (``--with-trace-refs``) were crashing when used with +isolated subinterpreters. The problematic global state has been isolated to +each interpreter. Other fixing the crashes, this change does not affect +users. diff --git a/Objects/object.c b/Objects/object.c index bd0fa40bd2a851..b4c9416036c44e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -158,11 +158,8 @@ _PyDebug_PrintTotalRefs(void) { Do not call them otherwise, they do not initialize the object! */ #ifdef Py_TRACE_REFS -/* Head of circular doubly-linked list of all objects. These are linked - * together via the _ob_prev and _ob_next members of a PyObject, which - * exist only in a Py_TRACE_REFS build. - */ -static PyObject refchain = {&refchain, &refchain}; + +#define REFCHAIN(interp) &interp->object_state.refchain /* Insert op at the front of the list of all objects. If force is true, * op is added even if _ob_prev and _ob_next are non-NULL already. If @@ -187,10 +184,11 @@ _Py_AddToAllObjects(PyObject *op, int force) } #endif if (force || op->_ob_prev == NULL) { - op->_ob_next = refchain._ob_next; - op->_ob_prev = &refchain; - refchain._ob_next->_ob_prev = op; - refchain._ob_next = op; + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); + op->_ob_next = refchain->_ob_next; + op->_ob_prev = refchain; + refchain->_ob_next->_ob_prev = op; + refchain->_ob_next = op; } } #endif /* Py_TRACE_REFS */ @@ -2206,7 +2204,8 @@ _Py_ForgetReference(PyObject *op) _PyObject_ASSERT_FAILED_MSG(op, "negative refcnt"); } - if (op == &refchain || + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); + if (op == refchain || op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) { _PyObject_ASSERT_FAILED_MSG(op, "invalid object chain"); @@ -2214,12 +2213,12 @@ _Py_ForgetReference(PyObject *op) #ifdef SLOW_UNREF_CHECK PyObject *p; - for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { + for (p = refchain->_ob_next; p != refchain; p = p->_ob_next) { if (p == op) { break; } } - if (p == &refchain) { + if (p == refchain) { /* Not found */ _PyObject_ASSERT_FAILED_MSG(op, "object not found in the objects list"); @@ -2235,11 +2234,15 @@ _Py_ForgetReference(PyObject *op) * interpreter must be in a healthy state. */ void -_Py_PrintReferences(FILE *fp) +_Py_PrintReferences(PyInterpreterState *interp, FILE *fp) { PyObject *op; + if (interp == NULL) { + interp = _PyInterpreterState_Main(); + } fprintf(fp, "Remaining objects:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { + PyObject *refchain = REFCHAIN(interp); + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) { fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op)); if (PyObject_Print(op, fp, 0) != 0) { PyErr_Clear(); @@ -2251,34 +2254,42 @@ _Py_PrintReferences(FILE *fp) /* Print the addresses of all live objects. Unlike _Py_PrintReferences, this * doesn't make any calls to the Python C API, so is always safe to call. */ +// XXX This function is not safe to use if the interpreter has been +// freed or is in an unhealthy state (e.g. late in finalization). +// The call in Py_FinalizeEx() is okay since the main interpreter +// is statically allocated. void -_Py_PrintReferenceAddresses(FILE *fp) +_Py_PrintReferenceAddresses(PyInterpreterState *interp, FILE *fp) { PyObject *op; + PyObject *refchain = REFCHAIN(interp); fprintf(fp, "Remaining object addresses:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) fprintf(fp, "%p [%zd] %s\n", (void *)op, Py_REFCNT(op), Py_TYPE(op)->tp_name); } +/* The implementation of sys.getobjects(). */ PyObject * _Py_GetObjects(PyObject *self, PyObject *args) { int i, n; PyObject *t = NULL; PyObject *res, *op; + PyInterpreterState *interp = _PyInterpreterState_GET(); if (!PyArg_ParseTuple(args, "i|O", &n, &t)) return NULL; - op = refchain._ob_next; + PyObject *refchain = REFCHAIN(interp); + op = refchain->_ob_next; res = PyList_New(0); if (res == NULL) return NULL; - for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { + for (i = 0; (n == 0 || i < n) && op != refchain; i++) { while (op == self || op == args || op == res || op == t || (t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) { op = op->_ob_next; - if (op == &refchain) + if (op == refchain) return res; } if (PyList_Append(res, op) < 0) { @@ -2290,6 +2301,8 @@ _Py_GetObjects(PyObject *self, PyObject *args) return res; } +#undef REFCHAIN + #endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index a67fa26b372278..5b8c8af179c005 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1920,11 +1920,11 @@ Py_FinalizeEx(void) } if (dump_refs) { - _Py_PrintReferences(stderr); + _Py_PrintReferences(tstate->interp, stderr); } if (dump_refs_fp != NULL) { - _Py_PrintReferences(dump_refs_fp); + _Py_PrintReferences(tstate->interp, dump_refs_fp); } #endif /* Py_TRACE_REFS */ @@ -1960,11 +1960,11 @@ Py_FinalizeEx(void) */ if (dump_refs) { - _Py_PrintReferenceAddresses(stderr); + _Py_PrintReferenceAddresses(tstate->interp, stderr); } if (dump_refs_fp != NULL) { - _Py_PrintReferenceAddresses(dump_refs_fp); + _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp); fclose(dump_refs_fp); } #endif /* Py_TRACE_REFS */ From 98902d6c0522df022d2f88499faf9774970e2838 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 4 Aug 2023 03:25:51 -0700 Subject: [PATCH 0504/1206] [3.12] GH-107263: Increase C stack limit for most functions, except `_PyEval_EvalFrameDefault()` (GH-107535) (#107618) GH-107263: Increase C stack limit for most functions, except `_PyEval_EvalFrameDefault()` (GH-107535) * Set C recursion limit to 1500, set cost of eval loop to 2 frames, and compiler mutliply to 2. (cherry picked from commit fa45958450aa3489607daf9855ca0474a2a20878) Co-authored-by: Mark Shannon --- Doc/whatsnew/3.12.rst | 5 +++++ Include/cpython/pystate.h | 3 ++- Lib/test/list_tests.py | 4 ++-- Lib/test/mapping_tests.py | 3 ++- Lib/test/support/__init__.py | 10 ++++++++- Lib/test/test_ast.py | 1 + Lib/test/test_call.py | 3 ++- Lib/test/test_compile.py | 21 +++++++------------ Lib/test/test_dict.py | 4 ++-- Lib/test/test_dictviews.py | 3 ++- Lib/test/test_exception_group.py | 4 ++-- Lib/test/test_zlib.py | 7 ++----- ...-07-30-05-20-16.gh-issue-107263.q0IU2M.rst | 3 +++ Parser/asdl_c.py | 2 +- Python/Python-ast.c | 2 +- Python/ast.c | 2 +- Python/ast_opt.c | 2 +- Python/bytecodes.c | 2 +- Python/ceval.c | 8 ++++++- Python/generated_cases.c.h | 2 +- Python/symtable.c | 11 ++-------- 21 files changed, 57 insertions(+), 45 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 39e702bb012fb9..79e618588143a8 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -802,6 +802,11 @@ sys exception instance, rather than to a ``(typ, exc, tb)`` tuple. (Contributed by Irit Katriel in :gh:`103176`.) +* :func:`sys.setrecursionlimit` and :func:`sys.getrecursionlimit`. + The recursion limit now applies only to Python code. Builtin functions do + not use the recursion limit, but are protected by a different mechanism + that prevents recursion from causing a virtual machine crash. + tempfile -------- diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index f33c72d4cf4d2a..628f2e0996e469 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -255,7 +255,8 @@ struct _ts { # ifdef __wasi__ # define C_RECURSION_LIMIT 500 # else -# define C_RECURSION_LIMIT 800 + // This value is duplicated in Lib/test/support/__init__.py +# define C_RECURSION_LIMIT 1500 # endif #endif diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index fe3ee80b8d461f..b1ef332522d2ce 100644 --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -6,7 +6,7 @@ from functools import cmp_to_key from test import seq_tests -from test.support import ALWAYS_EQ, NEVER_EQ +from test.support import ALWAYS_EQ, NEVER_EQ, C_RECURSION_LIMIT class CommonTest(seq_tests.CommonTest): @@ -61,7 +61,7 @@ def test_repr(self): def test_repr_deep(self): a = self.type2test([]) - for i in range(sys.getrecursionlimit() + 100): + for i in range(C_RECURSION_LIMIT + 1): a = self.type2test([a]) self.assertRaises(RecursionError, repr, a) diff --git a/Lib/test/mapping_tests.py b/Lib/test/mapping_tests.py index 613206a0855aea..5492bbf86d1f87 100644 --- a/Lib/test/mapping_tests.py +++ b/Lib/test/mapping_tests.py @@ -2,6 +2,7 @@ import unittest import collections import sys +from test.support import C_RECURSION_LIMIT class BasicTestMappingProtocol(unittest.TestCase): @@ -624,7 +625,7 @@ def __repr__(self): def test_repr_deep(self): d = self._empty_mapping() - for i in range(sys.getrecursionlimit() + 100): + for i in range(C_RECURSION_LIMIT + 1): d0 = d d = self._empty_mapping() d[1] = d0 diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 3b332f49951f0c..c3c3cf0a71596c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -64,7 +64,8 @@ "run_with_tz", "PGO", "missing_compiler_executable", "ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST", "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", - "Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", + "Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", "C_RECURSION_LIMIT", + "skip_on_s390x", ] @@ -2460,3 +2461,10 @@ def adjust_int_max_str_digits(max_digits): #For recursion tests, easily exceeds default recursion limit EXCEEDS_RECURSION_LIMIT = 5000 + +# The default C recursion limit (from Include/cpython/pystate.h). +C_RECURSION_LIMIT = 1500 + +#Windows doesn't have os.uname() but it doesn't support s390x. +skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x', + 'skipped on s390x') diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index a03fa4c7187b05..5346b39043f0f5 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1084,6 +1084,7 @@ def next(self): return self enum._test_simple_enum(_Precedence, ast._Precedence) + @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") @support.cpython_only def test_ast_recursion_limit(self): fail_depth = support.EXCEEDS_RECURSION_LIMIT diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 12759c53bb662c..ec8dc29d36c16a 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -1,5 +1,5 @@ import unittest -from test.support import cpython_only, requires_limited_api +from test.support import cpython_only, requires_limited_api, skip_on_s390x try: import _testcapi except ImportError: @@ -931,6 +931,7 @@ def test_multiple_values(self): @cpython_only class TestRecursion(unittest.TestCase): + @skip_on_s390x def test_super_deep(self): def recurse(n): diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 784c0550cc09b1..142d3f5c125b6d 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -11,10 +11,9 @@ import warnings from test import support from test.support import (script_helper, requires_debug_ranges, - requires_specialization) + requires_specialization, C_RECURSION_LIMIT) from test.support.os_helper import FakePath - class TestSpecifics(unittest.TestCase): def compile_single(self, source): @@ -112,7 +111,7 @@ def __getitem__(self, key): @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_extended_arg(self): - repeat = 2000 + repeat = int(C_RECURSION_LIMIT * 0.9) longexpr = 'x = x or ' + '-x' * repeat g = {} code = textwrap.dedent(''' @@ -558,16 +557,12 @@ def test_yet_more_evil_still_undecodable(self): @support.cpython_only @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_compiler_recursion_limit(self): - # Expected limit is sys.getrecursionlimit() * the scaling factor - # in symtable.c (currently 3) - # We expect to fail *at* that limit, because we use up some of - # the stack depth limit in the test suite code - # So we check the expected limit and 75% of that - # XXX (ncoghlan): duplicating the scaling factor here is a little - # ugly. Perhaps it should be exposed somewhere... - fail_depth = sys.getrecursionlimit() * 3 - crash_depth = sys.getrecursionlimit() * 300 - success_depth = int(fail_depth * 0.75) + # Expected limit is C_RECURSION_LIMIT * 2 + # Duplicating the limit here is a little ugly. + # Perhaps it should be exposed somewhere... + fail_depth = C_RECURSION_LIMIT * 2 + 1 + crash_depth = C_RECURSION_LIMIT * 100 + success_depth = int(C_RECURSION_LIMIT * 1.8) def check_limit(prefix, repeated, mode="single"): expect_ok = prefix + repeated * success_depth diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 79638340059f65..fbc6ce8282de3c 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -8,7 +8,7 @@ import unittest import weakref from test import support -from test.support import import_helper +from test.support import import_helper, C_RECURSION_LIMIT class DictTest(unittest.TestCase): @@ -596,7 +596,7 @@ def __repr__(self): def test_repr_deep(self): d = {} - for i in range(sys.getrecursionlimit() + 100): + for i in range(C_RECURSION_LIMIT + 1): d = {1: d} self.assertRaises(RecursionError, repr, d) diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py index 924f4a6829e19c..2bd9d6eef8cfc6 100644 --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -3,6 +3,7 @@ import pickle import sys import unittest +from test.support import C_RECURSION_LIMIT class DictSetTest(unittest.TestCase): @@ -279,7 +280,7 @@ def test_recursive_repr(self): def test_deeply_nested_repr(self): d = {} - for i in range(sys.getrecursionlimit() + 100): + for i in range(C_RECURSION_LIMIT//2 + 100): d = {42: d.values()} self.assertRaises(RecursionError, repr, d) diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py index fa159a76ec1aff..22be3a7795cb9a 100644 --- a/Lib/test/test_exception_group.py +++ b/Lib/test/test_exception_group.py @@ -1,7 +1,7 @@ import collections.abc import types import unittest - +from test.support import C_RECURSION_LIMIT class TestExceptionGroupTypeHierarchy(unittest.TestCase): def test_exception_group_types(self): @@ -433,7 +433,7 @@ def test_basics_split_by_predicate__match(self): class DeepRecursionInSplitAndSubgroup(unittest.TestCase): def make_deep_eg(self): e = TypeError(1) - for i in range(2000): + for i in range(C_RECURSION_LIMIT + 1): e = ExceptionGroup('eg', [e]) return e diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 3dac70eb12852c..2113757254c0ed 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -7,7 +7,7 @@ import pickle import random import sys -from test.support import bigmemtest, _1G, _4G +from test.support import bigmemtest, _1G, _4G, skip_on_s390x zlib = import_helper.import_module('zlib') @@ -44,10 +44,7 @@ # zlib.decompress(func1(data)) == zlib.decompress(func2(data)) == data # # Make the assumption that s390x always has an accelerator to simplify the skip -# condition. Windows doesn't have os.uname() but it doesn't support s390x. -skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x', - 'skipped on s390x') - +# condition. class VersionTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst new file mode 100644 index 00000000000000..fb0940b456dae5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst @@ -0,0 +1,3 @@ +Increase C recursion limit for functions other than the main interpreter +from 800 to 1500. This should allow functions like ``list.__repr__`` and +``json.dumps`` to handle all the inputs that they could prior to 3.12 diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index d4763ea260a5a2..aa093b30a74d70 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1393,7 +1393,7 @@ class PartingShots(StaticVisitor): int starting_recursion_depth; /* Be careful here to prevent overflow. */ - int COMPILER_STACK_FRAME_SCALE = 3; + int COMPILER_STACK_FRAME_SCALE = 2; PyThreadState *tstate = _PyThreadState_GET(); if (!tstate) { return 0; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 5db9ade3af4547..f8bb6124fa4878 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -13074,7 +13074,7 @@ PyObject* PyAST_mod2obj(mod_ty t) int starting_recursion_depth; /* Be careful here to prevent overflow. */ - int COMPILER_STACK_FRAME_SCALE = 3; + int COMPILER_STACK_FRAME_SCALE = 2; PyThreadState *tstate = _PyThreadState_GET(); if (!tstate) { return 0; diff --git a/Python/ast.c b/Python/ast.c index 68600ce683b974..74c97f948d15e6 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -1029,7 +1029,7 @@ validate_type_params(struct validator *state, asdl_type_param_seq *tps) /* See comments in symtable.c. */ -#define COMPILER_STACK_FRAME_SCALE 3 +#define COMPILER_STACK_FRAME_SCALE 2 int _PyAST_Validate(mod_ty mod) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 274bd134e1435b..f8c4a9513236b9 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -1103,7 +1103,7 @@ astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTOptimizeState *stat #undef CALL_SEQ /* See comments in symtable.c. */ -#define COMPILER_STACK_FRAME_SCALE 3 +#define COMPILER_STACK_FRAME_SCALE 2 int _PyAST_Optimize(mod_ty mod, PyArena *arena, _PyASTOptimizeState *state) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7ee48c70b00054..dc2ae221f0bdb1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -635,7 +635,7 @@ dummy_func( tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); assert(!_PyErr_Occurred(tstate)); - _Py_LeaveRecursiveCallTstate(tstate); + tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; return retval; } diff --git a/Python/ceval.c b/Python/ceval.c index 49474206162130..88d6362bf48a1f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -637,6 +637,11 @@ static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { # pragma warning(disable:4102) #endif + +/* _PyEval_EvalFrameDefault() is a *big* function, + * so consume 3 units of C stack */ +#define PY_EVAL_C_STACK_UNITS 2 + PyObject* _Py_HOT_FUNCTION _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) { @@ -691,6 +696,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int frame->previous = &entry_frame; cframe.current_frame = frame; + tstate->c_recursion_remaining -= (PY_EVAL_C_STACK_UNITS - 1); if (_Py_EnterRecursiveCallTstate(tstate, "")) { tstate->c_recursion_remaining--; tstate->py_recursion_remaining--; @@ -990,7 +996,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int /* Restore previous cframe and exit */ tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); - _Py_LeaveRecursiveCallTstate(tstate); + tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; return NULL; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index eabb9fe5fac4d5..b0a363ce9aa111 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -922,7 +922,7 @@ tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); assert(!_PyErr_Occurred(tstate)); - _Py_LeaveRecursiveCallTstate(tstate); + tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS; return retval; #line 928 "Python/generated_cases.c.h" } diff --git a/Python/symtable.c b/Python/symtable.c index e2c00d17480dd1..115882da09b75a 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -282,17 +282,10 @@ symtable_new(void) return NULL; } -/* When compiling the use of C stack is probably going to be a lot - lighter than when executing Python code but still can overflow - and causing a Python crash if not checked (e.g. eval("()"*300000)). - Using the current recursion limit for the compiler seems too - restrictive (it caused at least one test to fail) so a factor is - used to allow deeper recursion when compiling an expression. - - Using a scaling factor means this should automatically adjust when +/* Using a scaling factor means this should automatically adjust when the recursion limit is adjusted for small or large C stack allocations. */ -#define COMPILER_STACK_FRAME_SCALE 3 +#define COMPILER_STACK_FRAME_SCALE 2 struct symtable * _PySymtable_Build(mod_ty mod, PyObject *filename, PyFutureFeatures *future) From 310e1460c08d71447305e381e4fcd25af6519aeb Mon Sep 17 00:00:00 2001 From: "T. Wouters" Date: Fri, 4 Aug 2023 15:41:03 +0200 Subject: [PATCH 0505/1206] [3.12] Update the expected bytecode magic in test_importlib.test_util (#107626) Update the expected bytecode magic in test_importlib.test_util to the final 3.12 magic number. From now on it's not allowed to change for any 3.12 release. --- Lib/test/test_importlib/test_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index e967adc9451c81..217c1ad78be252 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -634,7 +634,7 @@ def test_magic_number(self): # stakeholders such as OS package maintainers must be notified # in advance. Such exceptional releases will then require an # adjustment to this test case. - EXPECTED_MAGIC_NUMBER = 3495 + EXPECTED_MAGIC_NUMBER = 3531 actual = int.from_bytes(importlib.util.MAGIC_NUMBER[:2], 'little') msg = ( From 28a9849d7c2f2ae3c283cf61b904418d8b01ec01 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 4 Aug 2023 23:20:20 +0300 Subject: [PATCH 0506/1206] [3.12] Docs: upgrade to python-docs-theme 2023.7 (GH-107617) (#107633) (cherry picked from commit 19f32b24b2e1680ff9929bb64d681397b259c6fb) --- Doc/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 4c9d02ea37ab58..fb558b3c5af249 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -14,6 +14,6 @@ sphinxext-opengraph==0.7.5 # The theme used by the documentation is stored separately, so we need # to install that as well. -python-docs-theme>=2022.1 +python-docs-theme>=2023.7 -c constraints.txt From 0e7a4f733685e7a7ccf28d850bae1b2222977362 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 4 Aug 2023 13:20:46 -0700 Subject: [PATCH 0507/1206] [3.12] Docs: Only include Plausible for html, not for epub etc (GH-107637) (#107642) Docs: Only include Plausible for html, not for epub etc (GH-107637) Only include Plausible for html, not for epub etc (cherry picked from commit 904b5319b3cc72063f4bfcd7beb3a1ef0fc641be) Co-authored-by: Hugo van Kemenade --- Doc/tools/templates/layout.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index 9832feba141675..80103158ea01e6 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -26,7 +26,9 @@ {% endblock %} {% block extrahead %} - + {% if builder == "html" %} + + {% endif %} {% if builder != "htmlhelp" %} {% if pagename == 'whatsnew/changelog' and not embedded %} From 6e4eec760648a71e1cd8f8f551997b1823b4bb9f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 5 Aug 2023 05:44:54 -0600 Subject: [PATCH 0508/1206] [3.12] gh-107630: Revert "[3.12] gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated Subinterpreters (gh-107567) (#107599)" (#107648) Revert "[3.12] gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated Subinterpreters (gh-107567) (#107599)" This reverts commit 58af2293c52a1ad3754d254690c0e54f787c545b. --- Include/internal/pycore_object.h | 4 +- Include/internal/pycore_object_state.h | 13 ++--- Include/internal/pycore_runtime_init.h | 11 ---- ...-08-02-12-24-51.gh-issue-107080.PNolFU.rst | 4 -- Objects/object.c | 51 +++++++------------ Python/pylifecycle.c | 8 +-- 6 files changed, 29 insertions(+), 62 deletions(-) delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 5a9403456903ed..0981d1122fec54 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -271,8 +271,8 @@ extern void _PyDebug_PrintTotalRefs(void); #ifdef Py_TRACE_REFS extern void _Py_AddToAllObjects(PyObject *op, int force); -extern void _Py_PrintReferences(PyInterpreterState *, FILE *); -extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *); +extern void _Py_PrintReferences(FILE *); +extern void _Py_PrintReferenceAddresses(FILE *); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h index 65feb5af969f8b..94005d77881432 100644 --- a/Include/internal/pycore_object_state.h +++ b/Include/internal/pycore_object_state.h @@ -11,22 +11,17 @@ extern "C" { struct _py_object_runtime_state { #ifdef Py_REF_DEBUG Py_ssize_t interpreter_leaks; -#endif +#else int _not_used; +#endif }; struct _py_object_state { #ifdef Py_REF_DEBUG Py_ssize_t reftotal; -#endif -#ifdef Py_TRACE_REFS - /* Head of circular doubly-linked list of all objects. These are linked - * together via the _ob_prev and _ob_next members of a PyObject, which - * exist only in a Py_TRACE_REFS build. - */ - PyObject refchain; -#endif +#else int _not_used; +#endif }; diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 7aace9f86119c4..4130188079cffa 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -101,7 +101,6 @@ extern PyTypeObject _PyExc_MemoryError; { .threshold = 10, }, \ }, \ }, \ - .object_state = _py_object_state_INIT(INTERP), \ .dtoa = _dtoa_state_INIT(&(INTERP)), \ .dict_state = _dict_state_INIT, \ .func_state = { \ @@ -131,16 +130,6 @@ extern PyTypeObject _PyExc_MemoryError; .context_ver = 1, \ } -#ifdef Py_TRACE_REFS -# define _py_object_state_INIT(INTERP) \ - { \ - .refchain = {&INTERP.object_state.refchain, &INTERP.object_state.refchain}, \ - } -#else -# define _py_object_state_INIT(INTERP) \ - { 0 } -#endif - // global objects diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst deleted file mode 100644 index 5084c854360e35..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst +++ /dev/null @@ -1,4 +0,0 @@ -Trace refs builds (``--with-trace-refs``) were crashing when used with -isolated subinterpreters. The problematic global state has been isolated to -each interpreter. Other fixing the crashes, this change does not affect -users. diff --git a/Objects/object.c b/Objects/object.c index b4c9416036c44e..bd0fa40bd2a851 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -158,8 +158,11 @@ _PyDebug_PrintTotalRefs(void) { Do not call them otherwise, they do not initialize the object! */ #ifdef Py_TRACE_REFS - -#define REFCHAIN(interp) &interp->object_state.refchain +/* Head of circular doubly-linked list of all objects. These are linked + * together via the _ob_prev and _ob_next members of a PyObject, which + * exist only in a Py_TRACE_REFS build. + */ +static PyObject refchain = {&refchain, &refchain}; /* Insert op at the front of the list of all objects. If force is true, * op is added even if _ob_prev and _ob_next are non-NULL already. If @@ -184,11 +187,10 @@ _Py_AddToAllObjects(PyObject *op, int force) } #endif if (force || op->_ob_prev == NULL) { - PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); - op->_ob_next = refchain->_ob_next; - op->_ob_prev = refchain; - refchain->_ob_next->_ob_prev = op; - refchain->_ob_next = op; + op->_ob_next = refchain._ob_next; + op->_ob_prev = &refchain; + refchain._ob_next->_ob_prev = op; + refchain._ob_next = op; } } #endif /* Py_TRACE_REFS */ @@ -2204,8 +2206,7 @@ _Py_ForgetReference(PyObject *op) _PyObject_ASSERT_FAILED_MSG(op, "negative refcnt"); } - PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); - if (op == refchain || + if (op == &refchain || op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) { _PyObject_ASSERT_FAILED_MSG(op, "invalid object chain"); @@ -2213,12 +2214,12 @@ _Py_ForgetReference(PyObject *op) #ifdef SLOW_UNREF_CHECK PyObject *p; - for (p = refchain->_ob_next; p != refchain; p = p->_ob_next) { + for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { if (p == op) { break; } } - if (p == refchain) { + if (p == &refchain) { /* Not found */ _PyObject_ASSERT_FAILED_MSG(op, "object not found in the objects list"); @@ -2234,15 +2235,11 @@ _Py_ForgetReference(PyObject *op) * interpreter must be in a healthy state. */ void -_Py_PrintReferences(PyInterpreterState *interp, FILE *fp) +_Py_PrintReferences(FILE *fp) { PyObject *op; - if (interp == NULL) { - interp = _PyInterpreterState_Main(); - } fprintf(fp, "Remaining objects:\n"); - PyObject *refchain = REFCHAIN(interp); - for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) { + for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op)); if (PyObject_Print(op, fp, 0) != 0) { PyErr_Clear(); @@ -2254,42 +2251,34 @@ _Py_PrintReferences(PyInterpreterState *interp, FILE *fp) /* Print the addresses of all live objects. Unlike _Py_PrintReferences, this * doesn't make any calls to the Python C API, so is always safe to call. */ -// XXX This function is not safe to use if the interpreter has been -// freed or is in an unhealthy state (e.g. late in finalization). -// The call in Py_FinalizeEx() is okay since the main interpreter -// is statically allocated. void -_Py_PrintReferenceAddresses(PyInterpreterState *interp, FILE *fp) +_Py_PrintReferenceAddresses(FILE *fp) { PyObject *op; - PyObject *refchain = REFCHAIN(interp); fprintf(fp, "Remaining object addresses:\n"); - for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) + for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) fprintf(fp, "%p [%zd] %s\n", (void *)op, Py_REFCNT(op), Py_TYPE(op)->tp_name); } -/* The implementation of sys.getobjects(). */ PyObject * _Py_GetObjects(PyObject *self, PyObject *args) { int i, n; PyObject *t = NULL; PyObject *res, *op; - PyInterpreterState *interp = _PyInterpreterState_GET(); if (!PyArg_ParseTuple(args, "i|O", &n, &t)) return NULL; - PyObject *refchain = REFCHAIN(interp); - op = refchain->_ob_next; + op = refchain._ob_next; res = PyList_New(0); if (res == NULL) return NULL; - for (i = 0; (n == 0 || i < n) && op != refchain; i++) { + for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { while (op == self || op == args || op == res || op == t || (t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) { op = op->_ob_next; - if (op == refchain) + if (op == &refchain) return res; } if (PyList_Append(res, op) < 0) { @@ -2301,8 +2290,6 @@ _Py_GetObjects(PyObject *self, PyObject *args) return res; } -#undef REFCHAIN - #endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5b8c8af179c005..a67fa26b372278 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1920,11 +1920,11 @@ Py_FinalizeEx(void) } if (dump_refs) { - _Py_PrintReferences(tstate->interp, stderr); + _Py_PrintReferences(stderr); } if (dump_refs_fp != NULL) { - _Py_PrintReferences(tstate->interp, dump_refs_fp); + _Py_PrintReferences(dump_refs_fp); } #endif /* Py_TRACE_REFS */ @@ -1960,11 +1960,11 @@ Py_FinalizeEx(void) */ if (dump_refs) { - _Py_PrintReferenceAddresses(tstate->interp, stderr); + _Py_PrintReferenceAddresses(stderr); } if (dump_refs_fp != NULL) { - _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp); + _Py_PrintReferenceAddresses(dump_refs_fp); fclose(dump_refs_fp); } #endif /* Py_TRACE_REFS */ From 236cdadb08f1881bda96b48429ce8e882f8bcb9d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 5 Aug 2023 05:08:04 -0700 Subject: [PATCH 0509/1206] [3.12] gh-107432 Fix incorrect indentation in annotations HOWTO (GH-107445) (#107654) gh-107432 Fix incorrect indentation in annotations HOWTO (GH-107445) gh-107432 Fix incorrect indentation in annotations document Body text in https://docs.python.org/3/howto/annotations.html was indented throughout, and was being rendered in blockquote elements. (cherry picked from commit 5e2746d6e2fb0da29225ead7135f078c5f087b57) Co-authored-by: Daniele Procida --- Doc/howto/annotations.rst | 326 +++++++++++++++++++------------------- 1 file changed, 163 insertions(+), 163 deletions(-) diff --git a/Doc/howto/annotations.rst b/Doc/howto/annotations.rst index 472069032d6509..1134686c947d66 100644 --- a/Doc/howto/annotations.rst +++ b/Doc/howto/annotations.rst @@ -32,201 +32,201 @@ Annotations Best Practices Accessing The Annotations Dict Of An Object In Python 3.10 And Newer ==================================================================== - Python 3.10 adds a new function to the standard library: - :func:`inspect.get_annotations`. In Python versions 3.10 - and newer, calling this function is the best practice for - accessing the annotations dict of any object that supports - annotations. This function can also "un-stringize" - stringized annotations for you. - - If for some reason :func:`inspect.get_annotations` isn't - viable for your use case, you may access the - ``__annotations__`` data member manually. Best practice - for this changed in Python 3.10 as well: as of Python 3.10, - ``o.__annotations__`` is guaranteed to *always* work - on Python functions, classes, and modules. If you're - certain the object you're examining is one of these three - *specific* objects, you may simply use ``o.__annotations__`` - to get at the object's annotations dict. - - However, other types of callables--for example, - callables created by :func:`functools.partial`--may - not have an ``__annotations__`` attribute defined. When - accessing the ``__annotations__`` of a possibly unknown - object, best practice in Python versions 3.10 and - newer is to call :func:`getattr` with three arguments, - for example ``getattr(o, '__annotations__', None)``. - - Before Python 3.10, accessing ``__annotations__`` on a class that - defines no annotations but that has a parent class with - annotations would return the parent's ``__annotations__``. - In Python 3.10 and newer, the child class's annotations - will be an empty dict instead. +Python 3.10 adds a new function to the standard library: +:func:`inspect.get_annotations`. In Python versions 3.10 +and newer, calling this function is the best practice for +accessing the annotations dict of any object that supports +annotations. This function can also "un-stringize" +stringized annotations for you. + +If for some reason :func:`inspect.get_annotations` isn't +viable for your use case, you may access the +``__annotations__`` data member manually. Best practice +for this changed in Python 3.10 as well: as of Python 3.10, +``o.__annotations__`` is guaranteed to *always* work +on Python functions, classes, and modules. If you're +certain the object you're examining is one of these three +*specific* objects, you may simply use ``o.__annotations__`` +to get at the object's annotations dict. + +However, other types of callables--for example, +callables created by :func:`functools.partial`--may +not have an ``__annotations__`` attribute defined. When +accessing the ``__annotations__`` of a possibly unknown +object, best practice in Python versions 3.10 and +newer is to call :func:`getattr` with three arguments, +for example ``getattr(o, '__annotations__', None)``. + +Before Python 3.10, accessing ``__annotations__`` on a class that +defines no annotations but that has a parent class with +annotations would return the parent's ``__annotations__``. +In Python 3.10 and newer, the child class's annotations +will be an empty dict instead. Accessing The Annotations Dict Of An Object In Python 3.9 And Older =================================================================== - In Python 3.9 and older, accessing the annotations dict - of an object is much more complicated than in newer versions. - The problem is a design flaw in these older versions of Python, - specifically to do with class annotations. +In Python 3.9 and older, accessing the annotations dict +of an object is much more complicated than in newer versions. +The problem is a design flaw in these older versions of Python, +specifically to do with class annotations. - Best practice for accessing the annotations dict of other - objects--functions, other callables, and modules--is the same - as best practice for 3.10, assuming you aren't calling - :func:`inspect.get_annotations`: you should use three-argument - :func:`getattr` to access the object's ``__annotations__`` - attribute. +Best practice for accessing the annotations dict of other +objects--functions, other callables, and modules--is the same +as best practice for 3.10, assuming you aren't calling +:func:`inspect.get_annotations`: you should use three-argument +:func:`getattr` to access the object's ``__annotations__`` +attribute. - Unfortunately, this isn't best practice for classes. The problem - is that, since ``__annotations__`` is optional on classes, and - because classes can inherit attributes from their base classes, - accessing the ``__annotations__`` attribute of a class may - inadvertently return the annotations dict of a *base class.* - As an example:: +Unfortunately, this isn't best practice for classes. The problem +is that, since ``__annotations__`` is optional on classes, and +because classes can inherit attributes from their base classes, +accessing the ``__annotations__`` attribute of a class may +inadvertently return the annotations dict of a *base class.* +As an example:: - class Base: - a: int = 3 - b: str = 'abc' + class Base: + a: int = 3 + b: str = 'abc' - class Derived(Base): - pass + class Derived(Base): + pass - print(Derived.__annotations__) + print(Derived.__annotations__) - This will print the annotations dict from ``Base``, not - ``Derived``. +This will print the annotations dict from ``Base``, not +``Derived``. - Your code will have to have a separate code path if the object - you're examining is a class (``isinstance(o, type)``). - In that case, best practice relies on an implementation detail - of Python 3.9 and before: if a class has annotations defined, - they are stored in the class's ``__dict__`` dictionary. Since - the class may or may not have annotations defined, best practice - is to call the ``get`` method on the class dict. +Your code will have to have a separate code path if the object +you're examining is a class (``isinstance(o, type)``). +In that case, best practice relies on an implementation detail +of Python 3.9 and before: if a class has annotations defined, +they are stored in the class's ``__dict__`` dictionary. Since +the class may or may not have annotations defined, best practice +is to call the ``get`` method on the class dict. - To put it all together, here is some sample code that safely - accesses the ``__annotations__`` attribute on an arbitrary - object in Python 3.9 and before:: +To put it all together, here is some sample code that safely +accesses the ``__annotations__`` attribute on an arbitrary +object in Python 3.9 and before:: - if isinstance(o, type): - ann = o.__dict__.get('__annotations__', None) - else: - ann = getattr(o, '__annotations__', None) + if isinstance(o, type): + ann = o.__dict__.get('__annotations__', None) + else: + ann = getattr(o, '__annotations__', None) - After running this code, ``ann`` should be either a - dictionary or ``None``. You're encouraged to double-check - the type of ``ann`` using :func:`isinstance` before further - examination. +After running this code, ``ann`` should be either a +dictionary or ``None``. You're encouraged to double-check +the type of ``ann`` using :func:`isinstance` before further +examination. - Note that some exotic or malformed type objects may not have - a ``__dict__`` attribute, so for extra safety you may also wish - to use :func:`getattr` to access ``__dict__``. +Note that some exotic or malformed type objects may not have +a ``__dict__`` attribute, so for extra safety you may also wish +to use :func:`getattr` to access ``__dict__``. Manually Un-Stringizing Stringized Annotations ============================================== - In situations where some annotations may be "stringized", - and you wish to evaluate those strings to produce the - Python values they represent, it really is best to - call :func:`inspect.get_annotations` to do this work - for you. - - If you're using Python 3.9 or older, or if for some reason - you can't use :func:`inspect.get_annotations`, you'll need - to duplicate its logic. You're encouraged to examine the - implementation of :func:`inspect.get_annotations` in the - current Python version and follow a similar approach. - - In a nutshell, if you wish to evaluate a stringized annotation - on an arbitrary object ``o``: - - * If ``o`` is a module, use ``o.__dict__`` as the - ``globals`` when calling :func:`eval`. - * If ``o`` is a class, use ``sys.modules[o.__module__].__dict__`` - as the ``globals``, and ``dict(vars(o))`` as the ``locals``, - when calling :func:`eval`. - * If ``o`` is a wrapped callable using :func:`functools.update_wrapper`, - :func:`functools.wraps`, or :func:`functools.partial`, iteratively - unwrap it by accessing either ``o.__wrapped__`` or ``o.func`` as - appropriate, until you have found the root unwrapped function. - * If ``o`` is a callable (but not a class), use - ``o.__globals__`` as the globals when calling :func:`eval`. - - However, not all string values used as annotations can - be successfully turned into Python values by :func:`eval`. - String values could theoretically contain any valid string, - and in practice there are valid use cases for type hints that - require annotating with string values that specifically - *can't* be evaluated. For example: - - * :pep:`604` union types using ``|``, before support for this - was added to Python 3.10. - * Definitions that aren't needed at runtime, only imported - when :const:`typing.TYPE_CHECKING` is true. - - If :func:`eval` attempts to evaluate such values, it will - fail and raise an exception. So, when designing a library - API that works with annotations, it's recommended to only - attempt to evaluate string values when explicitly requested - to by the caller. +In situations where some annotations may be "stringized", +and you wish to evaluate those strings to produce the +Python values they represent, it really is best to +call :func:`inspect.get_annotations` to do this work +for you. + +If you're using Python 3.9 or older, or if for some reason +you can't use :func:`inspect.get_annotations`, you'll need +to duplicate its logic. You're encouraged to examine the +implementation of :func:`inspect.get_annotations` in the +current Python version and follow a similar approach. + +In a nutshell, if you wish to evaluate a stringized annotation +on an arbitrary object ``o``: + +* If ``o`` is a module, use ``o.__dict__`` as the + ``globals`` when calling :func:`eval`. +* If ``o`` is a class, use ``sys.modules[o.__module__].__dict__`` + as the ``globals``, and ``dict(vars(o))`` as the ``locals``, + when calling :func:`eval`. +* If ``o`` is a wrapped callable using :func:`functools.update_wrapper`, + :func:`functools.wraps`, or :func:`functools.partial`, iteratively + unwrap it by accessing either ``o.__wrapped__`` or ``o.func`` as + appropriate, until you have found the root unwrapped function. +* If ``o`` is a callable (but not a class), use + ``o.__globals__`` as the globals when calling :func:`eval`. + +However, not all string values used as annotations can +be successfully turned into Python values by :func:`eval`. +String values could theoretically contain any valid string, +and in practice there are valid use cases for type hints that +require annotating with string values that specifically +*can't* be evaluated. For example: + +* :pep:`604` union types using ``|``, before support for this + was added to Python 3.10. +* Definitions that aren't needed at runtime, only imported + when :const:`typing.TYPE_CHECKING` is true. + +If :func:`eval` attempts to evaluate such values, it will +fail and raise an exception. So, when designing a library +API that works with annotations, it's recommended to only +attempt to evaluate string values when explicitly requested +to by the caller. Best Practices For ``__annotations__`` In Any Python Version ============================================================ - * You should avoid assigning to the ``__annotations__`` member - of objects directly. Let Python manage setting ``__annotations__``. +* You should avoid assigning to the ``__annotations__`` member + of objects directly. Let Python manage setting ``__annotations__``. - * If you do assign directly to the ``__annotations__`` member - of an object, you should always set it to a ``dict`` object. +* If you do assign directly to the ``__annotations__`` member + of an object, you should always set it to a ``dict`` object. - * If you directly access the ``__annotations__`` member - of an object, you should ensure that it's a - dictionary before attempting to examine its contents. +* If you directly access the ``__annotations__`` member + of an object, you should ensure that it's a + dictionary before attempting to examine its contents. - * You should avoid modifying ``__annotations__`` dicts. +* You should avoid modifying ``__annotations__`` dicts. - * You should avoid deleting the ``__annotations__`` attribute - of an object. +* You should avoid deleting the ``__annotations__`` attribute + of an object. ``__annotations__`` Quirks ========================== - In all versions of Python 3, function - objects lazy-create an annotations dict if no annotations - are defined on that object. You can delete the ``__annotations__`` - attribute using ``del fn.__annotations__``, but if you then - access ``fn.__annotations__`` the object will create a new empty dict - that it will store and return as its annotations. Deleting the - annotations on a function before it has lazily created its annotations - dict will throw an ``AttributeError``; using ``del fn.__annotations__`` - twice in a row is guaranteed to always throw an ``AttributeError``. - - Everything in the above paragraph also applies to class and module - objects in Python 3.10 and newer. - - In all versions of Python 3, you can set ``__annotations__`` - on a function object to ``None``. However, subsequently - accessing the annotations on that object using ``fn.__annotations__`` - will lazy-create an empty dictionary as per the first paragraph of - this section. This is *not* true of modules and classes, in any Python - version; those objects permit setting ``__annotations__`` to any - Python value, and will retain whatever value is set. - - If Python stringizes your annotations for you - (using ``from __future__ import annotations``), and you - specify a string as an annotation, the string will - itself be quoted. In effect the annotation is quoted - *twice.* For example:: - - from __future__ import annotations - def foo(a: "str"): pass - - print(foo.__annotations__) - - This prints ``{'a': "'str'"}``. This shouldn't really be considered - a "quirk"; it's mentioned here simply because it might be surprising. +In all versions of Python 3, function +objects lazy-create an annotations dict if no annotations +are defined on that object. You can delete the ``__annotations__`` +attribute using ``del fn.__annotations__``, but if you then +access ``fn.__annotations__`` the object will create a new empty dict +that it will store and return as its annotations. Deleting the +annotations on a function before it has lazily created its annotations +dict will throw an ``AttributeError``; using ``del fn.__annotations__`` +twice in a row is guaranteed to always throw an ``AttributeError``. + +Everything in the above paragraph also applies to class and module +objects in Python 3.10 and newer. + +In all versions of Python 3, you can set ``__annotations__`` +on a function object to ``None``. However, subsequently +accessing the annotations on that object using ``fn.__annotations__`` +will lazy-create an empty dictionary as per the first paragraph of +this section. This is *not* true of modules and classes, in any Python +version; those objects permit setting ``__annotations__`` to any +Python value, and will retain whatever value is set. + +If Python stringizes your annotations for you +(using ``from __future__ import annotations``), and you +specify a string as an annotation, the string will +itself be quoted. In effect the annotation is quoted +*twice.* For example:: + + from __future__ import annotations + def foo(a: "str"): pass + + print(foo.__annotations__) + +This prints ``{'a': "'str'"}``. This shouldn't really be considered +a "quirk"; it's mentioned here simply because it might be surprising. From 63bcd91daccc7c873d57e21406d038f8216b6ddf Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Sat, 5 Aug 2023 14:10:03 +0200 Subject: [PATCH 0510/1206] Python 3.12.0rc1 --- Include/patchlevel.h | 6 +- Lib/pydoc_data/topics.py | 23 +- Misc/NEWS.d/3.12.0rc1.rst | 495 ++++++++++++++++++ ...-02-03-21-36-42.gh-issue-101538.sF5F6S.rst | 1 - ...-07-23-00-38-51.gh-issue-106962.VVYrWB.rst | 1 - ...-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst | 1 - ...-07-25-13-41-09.gh-issue-107226.N919zH.rst | 2 - ...-06-02-19-37-29.gh-issue-105235.fgFGTi.rst | 1 - ...-07-13-14-55-45.gh-issue-106723.KsMufQ.rst | 1 - ...-07-13-15-59-07.gh-issue-106719.jmVrsv.rst | 2 - ...-07-18-16-13-51.gh-issue-106092.bObgRM.rst | 2 - ...-07-20-12-21-37.gh-issue-105699.08ywGV.rst | 4 - ...-07-20-15-15-57.gh-issue-105699.DdqHFg.rst | 3 - ...-07-21-14-37-48.gh-issue-106917.1jWp_m.rst | 4 - ...-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst | 1 - ...-07-26-12-18-10.gh-issue-106897.EsGurc.rst | 3 - ...-07-26-18-53-34.gh-issue-106895.DdEwV8.rst | 2 - ...-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst | 3 - ...-07-27-11-47-29.gh-issue-104432.oGHF-z.rst | 4 - ...-07-30-05-20-16.gh-issue-107263.q0IU2M.rst | 3 - ...3-05-16-22-08-24.gh-issue-54738.mJvCnj.rst | 1 - ...-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst | 1 - ...-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst | 2 - ...-07-26-16-33-04.gh-issue-107305.qB2LS4.rst | 3 - .../2020-05-03-00-33-15.bpo-18319.faPTlx.rst | 2 - ...-06-10-12-20-17.gh-issue-105626.XyZein.rst | 3 - ...-06-30-16-42-44.gh-issue-106263.tk-t93.rst | 2 - ...-07-03-03-46-20.gh-issue-106350.LLcTEe.rst | 2 - ...-07-04-07-25-30.gh-issue-106403.GmefbV.rst | 4 - ...-07-11-09-25-40.gh-issue-106530.VgXrMx.rst | 2 - ...-07-12-04-58-45.gh-issue-106602.dGCcXe.rst | 1 - ...-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst | 5 - ...-07-15-10-24-56.gh-issue-106774.FJcqCj.rst | 1 - ...-07-17-21-45-15.gh-issue-106831.RqVq9X.rst | 2 - ...-07-22-12-53-53.gh-issue-105002.gkfsW0.rst | 3 - ...-07-22-13-09-28.gh-issue-106186.EIsUNG.rst | 3 - ...3-07-22-15-51-33.gh-issue-83006.21zaCz.rst | 2 - ...3-07-23-12-26-23.gh-issue-62519.w8-81X.rst | 2 - ...3-07-24-01-21-16.gh-issue-46376.w-xuDL.rst | 1 - ...-08-03-11-31-11.gh-issue-107576.pO_s9I.rst | 3 - ...-08-03-12-52-19.gh-issue-107077.-pzHD6.rst | 6 - ...-03-07-21-46-29.gh-issue-102509.5ouaH_.rst | 2 - ...-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst | 4 - ...-07-14-16-20-06.gh-issue-106752.gd1i6D.rst | 2 - ...-07-16-02-57-08.gh-issue-104090.cKtK7g.rst | 1 - ...-07-22-13-49-40.gh-issue-106714.btYI5S.rst | 3 - ...-07-25-14-36-33.gh-issue-107237.y1pY79.rst | 2 - ...-04-05-07-19-36.gh-issue-103186.yEozgK.rst | 2 - ...-07-21-23-16-05.gh-issue-106970.NLRnml.rst | 4 - ...3-07-11-20-48-17.gh-issue-99079.CIMftz.rst | 1 - ...3-07-30-23-42-20.gh-issue-99079.JAtoh1.rst | 1 - README.rst | 4 +- 52 files changed, 515 insertions(+), 124 deletions(-) create mode 100644 Misc/NEWS.d/3.12.0rc1.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst delete mode 100644 Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst delete mode 100644 Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst delete mode 100644 Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst delete mode 100644 Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index e3d7ef51ba60c0..51e0e9b6d758f0 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -19,11 +19,11 @@ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 4 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.12.0b4+" +#define PY_VERSION "3.12.0rc1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 9603975729cfaf..8d19a85963fe43 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Jul 11 14:22:58 2023 +# Autogenerated by Sphinx on Sat Aug 5 14:10:40 2023 # as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' @@ -9689,7 +9689,8 @@ ' still alive. The list is in definition order. Example:\n' '\n' ' >>> int.__subclasses__()\n' - " []\n", + " [, , , " + "]\n", 'specialnames': 'Special method names\n' '********************\n' '\n' @@ -12558,7 +12559,7 @@ 'followed by\n' ' the string itself.\n' '\n' - 'str.rsplit(sep=None, maxsplit=- 1)\n' + 'str.rsplit(sep=None, maxsplit=-1)\n' '\n' ' Return a list of the words in the string, using *sep* ' 'as the\n' @@ -12599,7 +12600,7 @@ " >>> 'Monty Python'.removesuffix(' Python')\n" " 'Monty'\n" '\n' - 'str.split(sep=None, maxsplit=- 1)\n' + 'str.split(sep=None, maxsplit=-1)\n' '\n' ' Return a list of the words in the string, using *sep* ' 'as the\n' @@ -13009,6 +13010,10 @@ 'the\n' 'literal, i.e. either "\'" or """.)\n' '\n' + '\n' + 'Escape sequences\n' + '================\n' + '\n' 'Unless an "\'r\'" or "\'R\'" prefix is present, escape sequences ' 'in string\n' 'and bytes literals are interpreted according to rules similar to ' @@ -15184,10 +15189,12 @@ ' >>> # set operations\n' " >>> keys & {'eggs', 'bacon', 'salad'}\n" " {'bacon'}\n" - " >>> keys ^ {'sausage', 'juice'}\n" - " {'juice', 'sausage', 'bacon', 'spam'}\n" - " >>> keys | ['juice', 'juice', 'juice']\n" - " {'juice', 'sausage', 'bacon', 'spam', 'eggs'}\n" + " >>> keys ^ {'sausage', 'juice'} == {'juice', 'sausage', " + "'bacon', 'spam'}\n" + ' True\n' + " >>> keys | ['juice', 'juice', 'juice'] == {'bacon', " + "'spam', 'juice'}\n" + ' True\n' '\n' ' >>> # get back a read-only proxy for the original ' 'dictionary\n' diff --git a/Misc/NEWS.d/3.12.0rc1.rst b/Misc/NEWS.d/3.12.0rc1.rst new file mode 100644 index 00000000000000..ca826cf24258cf --- /dev/null +++ b/Misc/NEWS.d/3.12.0rc1.rst @@ -0,0 +1,495 @@ +.. date: 2023-06-13-20-52-24 +.. gh-issue: 102988 +.. nonce: Kei7Vf +.. release date: 2023-08-05 +.. section: Security + +Reverted the :mod:`email.utils` security improvement change released in +3.12beta4 that unintentionally caused :mod:`email.utils.getaddresses` to +fail to parse email addresses with a comma in the quoted name field. See +:gh:`106669`. + +.. + +.. date: 2023-03-07-21-46-29 +.. gh-issue: 102509 +.. nonce: 5ouaH_ +.. section: Security + +Start initializing ``ob_digit`` during creation of :c:type:`PyLongObject` +objects. Patch by Illia Volochii. + +.. + +.. date: 2023-07-30-05-20-16 +.. gh-issue: 107263 +.. nonce: q0IU2M +.. section: Core and Builtins + +Increase C recursion limit for functions other than the main interpreter +from 800 to 1500. This should allow functions like ``list.__repr__`` and +``json.dumps`` to handle all the inputs that they could prior to 3.12 + +.. + +.. date: 2023-07-27-11-47-29 +.. gh-issue: 104432 +.. nonce: oGHF-z +.. section: Core and Builtins + +Fix potential unaligned memory access on C APIs involving returned sequences +of `char *` pointers within the :mod:`grp` and :mod:`socket` modules. These +were revealed using a ``-fsaniziter=alignment`` build on ARM macOS. Patch by +Christopher Chavez. + +.. + +.. date: 2023-07-26-21-28-06 +.. gh-issue: 106898 +.. nonce: 8Wjuiv +.. section: Core and Builtins + +Add the exception as the third argument to ``PY_UNIND`` callbacks in +``sys.monitoring``. This makes the ``PY_UNWIND`` callback consistent with +the other exception hanlding callbacks. + +.. + +.. date: 2023-07-26-18-53-34 +.. gh-issue: 106895 +.. nonce: DdEwV8 +.. section: Core and Builtins + +Raise a ``ValueError`` when a monitoring callback funtion returns +``DISABLE`` for events that cannot be disabled locally. + +.. + +.. date: 2023-07-26-12-18-10 +.. gh-issue: 106897 +.. nonce: EsGurc +.. section: Core and Builtins + +Add a ``RERAISE`` event to ``sys.monitoring``, which occurs when an +exception is reraised, either explicitly by a plain ``raise`` statement, or +implicitly in an ``except`` or ``finally`` block. + +.. + +.. date: 2023-07-24-11-11-41 +.. gh-issue: 104621 +.. nonce: vM8Y_l +.. section: Core and Builtins + +Unsupported modules now always fail to be imported. + +.. + +.. date: 2023-07-21-14-37-48 +.. gh-issue: 106917 +.. nonce: 1jWp_m +.. section: Core and Builtins + +Fix classmethod-style :func:`super` method calls (i.e., where the second +argument to :func:`super`, or the implied second argument drawn from +``self/cls`` in the case of zero-arg super, is a type) when the target of +the call is not a classmethod. + +.. + +.. date: 2023-07-20-15-15-57 +.. gh-issue: 105699 +.. nonce: DdqHFg +.. section: Core and Builtins + +Python no longer crashes due an infrequent race when initialzing +per-interpreter interned strings. The crash would manifest when the +interpreter was finalized. + +.. + +.. date: 2023-07-20-12-21-37 +.. gh-issue: 105699 +.. nonce: 08ywGV +.. section: Core and Builtins + +Python no longer crashes due to an infrequent race in setting +``Py_FileSystemDefaultEncoding`` and ``Py_FileSystemDefaultEncodeErrors`` +(both deprecated), when simultaneously initializing two isolated +subinterpreters. Now they are only set during runtime initialization. + +.. + +.. date: 2023-07-18-16-13-51 +.. gh-issue: 106092 +.. nonce: bObgRM +.. section: Core and Builtins + +Fix a segmentation fault caused by a use-after-free bug in ``frame_dealloc`` +when the trashcan delays the deallocation of a ``PyFrameObject``. + +.. + +.. date: 2023-07-13-15-59-07 +.. gh-issue: 106719 +.. nonce: jmVrsv +.. section: Core and Builtins + +No longer suppress arbitrary errors in the ``__annotations__`` getter and +setter in the type and module types. + +.. + +.. date: 2023-07-13-14-55-45 +.. gh-issue: 106723 +.. nonce: KsMufQ +.. section: Core and Builtins + +Propagate ``frozen_modules`` to multiprocessing spawned process +interpreters. + +.. + +.. date: 2023-06-02-19-37-29 +.. gh-issue: 105235 +.. nonce: fgFGTi +.. section: Core and Builtins + +Prevent out-of-bounds memory access during ``mmap.find()`` calls. + +.. + +.. date: 2023-08-03-12-52-19 +.. gh-issue: 107077 +.. nonce: -pzHD6 +.. section: Library + +Seems that in some conditions, OpenSSL will return ``SSL_ERROR_SYSCALL`` +instead of ``SSL_ERROR_SSL`` when a certification verification has failed, +but the error parameters will still contain ``ERR_LIB_SSL`` and +``SSL_R_CERTIFICATE_VERIFY_FAILED``. We are now detecting this situation and +raising the appropiate ``ssl.SSLCertVerificationError``. Patch by Pablo +Galindo + +.. + +.. date: 2023-08-03-11-31-11 +.. gh-issue: 107576 +.. nonce: pO_s9I +.. section: Library + +Fix :func:`types.get_original_bases` to only return :attr:`!__orig_bases__` +if it is present on ``cls`` directly. Patch by James Hilton-Balfe. + +.. + +.. date: 2023-07-24-01-21-16 +.. gh-issue: 46376 +.. nonce: w-xuDL +.. section: Library + +Prevent memory leak and use-after-free when using pointers to pointers with +ctypes + +.. + +.. date: 2023-07-23-12-26-23 +.. gh-issue: 62519 +.. nonce: w8-81X +.. section: Library + +Make :func:`gettext.pgettext` search plural definitions when translation is +not found. + +.. + +.. date: 2023-07-22-15-51-33 +.. gh-issue: 83006 +.. nonce: 21zaCz +.. section: Library + +Document behavior of :func:`shutil.disk_usage` for non-mounted filesystems +on Unix. + +.. + +.. date: 2023-07-22-13-09-28 +.. gh-issue: 106186 +.. nonce: EIsUNG +.. section: Library + +Do not report ``MultipartInvariantViolationDefect`` defect when the +:class:`email.parser.Parser` class is used to parse emails with +``headersonly=True``. + +.. + +.. date: 2023-07-22-12-53-53 +.. gh-issue: 105002 +.. nonce: gkfsW0 +.. section: Library + +Fix invalid result from :meth:`PurePath.relative_to` method when attempting +to walk a "``..``" segment in *other* with *walk_up* enabled. A +:exc:`ValueError` exception is now raised in this case. + +.. + +.. date: 2023-07-17-21-45-15 +.. gh-issue: 106831 +.. nonce: RqVq9X +.. section: Library + +Fix potential missing ``NULL`` check of ``d2i_SSL_SESSION`` result in +``_ssl.c``. + +.. + +.. date: 2023-07-15-10-24-56 +.. gh-issue: 106774 +.. nonce: FJcqCj +.. section: Library + +Update the bundled copy of pip to version 23.2.1. + +.. + +.. date: 2023-07-14-16-54-13 +.. gh-issue: 106752 +.. nonce: BT1Yxw +.. section: Library + +Fixed several bugs in zipfile.Path, including: in ``Path.match`, Windows +separators are no longer honored (and never were meant to be); Fixed +``name``/``suffix``/``suffixes``/``stem`` operations when no filename is +present and the Path is not at the root of the zipfile; Reworked glob for +performance and more correct matching behavior. + +.. + +.. date: 2023-07-12-04-58-45 +.. gh-issue: 106602 +.. nonce: dGCcXe +.. section: Library + +Add __copy__ and __deepcopy__ in :mod:`enum` + +.. + +.. date: 2023-07-11-09-25-40 +.. gh-issue: 106530 +.. nonce: VgXrMx +.. section: Library + +Revert a change to :func:`colorsys.rgb_to_hls` that caused division by zero +for certain almost-white inputs. Patch by Terry Jan Reedy. + +.. + +.. date: 2023-07-04-07-25-30 +.. gh-issue: 106403 +.. nonce: GmefbV +.. section: Library + +Instances of :class:`typing.TypeVar`, :class:`typing.ParamSpec`, +:class:`typing.ParamSpecArgs`, :class:`typing.ParamSpecKwargs`, and +:class:`typing.TypeVarTuple` once again support weak references, fixing a +regression introduced in Python 3.12.0 beta 1. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-07-03-03-46-20 +.. gh-issue: 106350 +.. nonce: LLcTEe +.. section: Library + +Detect possible memory allocation failure in the libtommath function +:c:func:`mp_init` used by the ``_tkinter`` module. + +.. + +.. date: 2023-06-30-16-42-44 +.. gh-issue: 106263 +.. nonce: tk-t93 +.. section: Library + +Fix crash when calling ``repr`` with a manually constructed SignalDict +object. Patch by Charlie Zhao. + +.. + +.. date: 2023-06-10-12-20-17 +.. gh-issue: 105626 +.. nonce: XyZein +.. section: Library + +Change the default return value of +:meth:`http.client.HTTPConnection.get_proxy_response_headers` to be ``None`` +and not ``{}``. + +.. + +.. bpo: 18319 +.. date: 2020-05-03-00-33-15 +.. nonce: faPTlx +.. section: Library + +Ensure `gettext(msg)` retrieve translations even if a plural form exists. In +other words: `gettext(msg) == ngettext(msg, '', 1)`. + +.. + +.. date: 2023-07-26-16-33-04 +.. gh-issue: 107305 +.. nonce: qB2LS4 +.. section: Documentation + +Add documentation for :c:type:`PyInterpreterConfig` and +:c:func:`Py_NewInterpreterFromConfig`. Also clarify some of the nearby docs +relative to per-interpreter GIL. + +.. + +.. date: 2023-07-22-15-14-13 +.. gh-issue: 107008 +.. nonce: 3JQ1Vt +.. section: Documentation + +Document the :mod:`curses` module variables :const:`~curses.LINES` and +:const:`~curses.COLS`. + +.. + +.. date: 2023-07-21-11-51-57 +.. gh-issue: 106948 +.. nonce: K_JQ7j +.. section: Documentation + +Add a number of standard external names to ``nitpick_ignore``. + +.. + +.. date: 2023-05-16-22-08-24 +.. gh-issue: 54738 +.. nonce: mJvCnj +.. section: Documentation + +Add documentation on how to localize the :mod:`argparse` module. + +.. + +.. date: 2023-07-25-14-36-33 +.. gh-issue: 107237 +.. nonce: y1pY79 +.. section: Tests + +``test_logging``: Fix ``test_udp_reconnection()`` by increasing the timeout +from 100 ms to 5 minutes (LONG_TIMEOUT). Patch by Victor Stinner. + +.. + +.. date: 2023-07-22-13-49-40 +.. gh-issue: 106714 +.. nonce: btYI5S +.. section: Tests + +test_capi: Fix test_no_FatalError_infinite_loop() to no longer write a +coredump, by using test.support.SuppressCrashReport. Patch by Victor +Stinner. + +.. + +.. date: 2023-07-16-02-57-08 +.. gh-issue: 104090 +.. nonce: cKtK7g +.. section: Tests + +Avoid creating a reference to the test object in +:meth:`~unittest.TestResult.collectedDurations`. + +.. + +.. date: 2023-07-14-16-20-06 +.. gh-issue: 106752 +.. nonce: gd1i6D +.. section: Tests + +Moved tests for ``zipfile.Path`` into ``Lib/test/test_zipfile/_path``. Made +``zipfile._path`` a package. + +.. + +.. date: 2023-07-28-18-17-33 +.. gh-issue: 106881 +.. nonce: U3Ezdq +.. section: Build + +Check for `linux/limits.h` before including it in `Modules/posixmodule.c`. + +.. + +.. date: 2023-07-23-00-38-51 +.. gh-issue: 106962 +.. nonce: VVYrWB +.. section: Build + +Detect MPI compilers in :file:`configure`. + +.. + +.. date: 2023-02-03-21-36-42 +.. gh-issue: 101538 +.. nonce: sF5F6S +.. section: Build + +Add experimental wasi-threads support. Patch by Takashi Yamamoto. + +.. + +.. date: 2023-07-11-20-48-17 +.. gh-issue: 99079 +.. nonce: CIMftz +.. section: Windows + +Update Windows build to use OpenSSL 3.0.9 + +.. + +.. date: 2023-07-30-23-42-20 +.. gh-issue: 99079 +.. nonce: JAtoh1 +.. section: macOS + +Update macOS installer to use OpenSSL 3.0.9. + +.. + +.. date: 2023-07-21-23-16-05 +.. gh-issue: 106970 +.. nonce: NLRnml +.. section: Tools/Demos + +Fix bugs in the Argument Clinic ``destination clear`` command; the +destination buffers would never be cleared, and the ``destination`` +directive parser would simply continue to the fault handler after processing +the command. Patch by Erlend E. Aasland. + +.. + +.. date: 2023-04-05-07-19-36 +.. gh-issue: 103186 +.. nonce: yEozgK +.. section: Tools/Demos + +``freeze`` now fetches ``CONFIG_ARGS`` from the original CPython instance +the Makefile uses to call utility scripts. Patch by Ijtaba Hussain. + +.. + +.. date: 2023-07-25-13-41-09 +.. gh-issue: 107226 +.. nonce: N919zH +.. section: C API + +:c:func:`PyModule_AddObjectRef` is now only available in the limited API +version 3.10 or later. diff --git a/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst b/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst deleted file mode 100644 index 4b83c303b3d2c5..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst +++ /dev/null @@ -1 +0,0 @@ -Add experimental wasi-threads support. Patch by Takashi Yamamoto. diff --git a/Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst b/Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst deleted file mode 100644 index 32e196fe26d3b7..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-07-23-00-38-51.gh-issue-106962.VVYrWB.rst +++ /dev/null @@ -1 +0,0 @@ -Detect MPI compilers in :file:`configure`. diff --git a/Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst b/Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst deleted file mode 100644 index 40b2609e95c7e9..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-07-28-18-17-33.gh-issue-106881.U3Ezdq.rst +++ /dev/null @@ -1 +0,0 @@ -Check for `linux/limits.h` before including it in `Modules/posixmodule.c`. diff --git a/Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst b/Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst deleted file mode 100644 index 6178f18517d48f..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-07-25-13-41-09.gh-issue-107226.N919zH.rst +++ /dev/null @@ -1,2 +0,0 @@ -:c:func:`PyModule_AddObjectRef` is now only available in the limited API -version 3.10 or later. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst deleted file mode 100644 index c28d0101cd4bad..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst +++ /dev/null @@ -1 +0,0 @@ -Prevent out-of-bounds memory access during ``mmap.find()`` calls. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst deleted file mode 100644 index 207f397f17d3f3..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-13-14-55-45.gh-issue-106723.KsMufQ.rst +++ /dev/null @@ -1 +0,0 @@ -Propagate ``frozen_modules`` to multiprocessing spawned process interpreters. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst deleted file mode 100644 index dc4bef193a3220..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst +++ /dev/null @@ -1,2 +0,0 @@ -No longer suppress arbitrary errors in the ``__annotations__`` getter and -setter in the type and module types. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst deleted file mode 100644 index 7fb5b45c763e45..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a segmentation fault caused by a use-after-free bug in ``frame_dealloc`` -when the trashcan delays the deallocation of a ``PyFrameObject``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst deleted file mode 100644 index 82312718cd047e..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-20-12-21-37.gh-issue-105699.08ywGV.rst +++ /dev/null @@ -1,4 +0,0 @@ -Python no longer crashes due to an infrequent race in setting -``Py_FileSystemDefaultEncoding`` and ``Py_FileSystemDefaultEncodeErrors`` -(both deprecated), when simultaneously initializing two isolated -subinterpreters. Now they are only set during runtime initialization. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst deleted file mode 100644 index 4a257c6282220f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-20-15-15-57.gh-issue-105699.DdqHFg.rst +++ /dev/null @@ -1,3 +0,0 @@ -Python no longer crashes due an infrequent race when initialzing -per-interpreter interned strings. The crash would manifest when the -interpreter was finalized. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst deleted file mode 100644 index 82c74d5465458a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix classmethod-style :func:`super` method calls (i.e., where the second -argument to :func:`super`, or the implied second argument drawn from -``self/cls`` in the case of zero-arg super, is a type) when the target of -the call is not a classmethod. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst deleted file mode 100644 index 86c976295f2620..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-24-11-11-41.gh-issue-104621.vM8Y_l.rst +++ /dev/null @@ -1 +0,0 @@ -Unsupported modules now always fail to be imported. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst deleted file mode 100644 index 52c49c3c0f5e7b..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-12-18-10.gh-issue-106897.EsGurc.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add a ``RERAISE`` event to ``sys.monitoring``, which occurs when an -exception is reraised, either explicitly by a plain ``raise`` statement, or -implicitly in an ``except`` or ``finally`` block. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst deleted file mode 100644 index 370a29d34c860a..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-18-53-34.gh-issue-106895.DdEwV8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Raise a ``ValueError`` when a monitoring callback funtion returns -``DISABLE`` for events that cannot be disabled locally. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst deleted file mode 100644 index f1b1c4c64b4aca..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-26-21-28-06.gh-issue-106898.8Wjuiv.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add the exception as the third argument to ``PY_UNIND`` callbacks in -``sys.monitoring``. This makes the ``PY_UNWIND`` callback consistent with -the other exception hanlding callbacks. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst deleted file mode 100644 index e47927b4e11886..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-27-11-47-29.gh-issue-104432.oGHF-z.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix potential unaligned memory access on C APIs involving returned sequences -of `char *` pointers within the :mod:`grp` and :mod:`socket` modules. These -were revealed using a ``-fsaniziter=alignment`` build on ARM macOS. Patch by -Christopher Chavez. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst deleted file mode 100644 index fb0940b456dae5..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-30-05-20-16.gh-issue-107263.q0IU2M.rst +++ /dev/null @@ -1,3 +0,0 @@ -Increase C recursion limit for functions other than the main interpreter -from 800 to 1500. This should allow functions like ``list.__repr__`` and -``json.dumps`` to handle all the inputs that they could prior to 3.12 diff --git a/Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst b/Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst deleted file mode 100644 index 4da58fc982b6d7..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-05-16-22-08-24.gh-issue-54738.mJvCnj.rst +++ /dev/null @@ -1 +0,0 @@ -Add documentation on how to localize the :mod:`argparse` module. diff --git a/Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst b/Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst deleted file mode 100644 index 42b6348153b56a..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-07-21-11-51-57.gh-issue-106948.K_JQ7j.rst +++ /dev/null @@ -1 +0,0 @@ -Add a number of standard external names to ``nitpick_ignore``. diff --git a/Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst b/Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst deleted file mode 100644 index a0fa27ec10303e..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-07-22-15-14-13.gh-issue-107008.3JQ1Vt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document the :mod:`curses` module variables :const:`~curses.LINES` and -:const:`~curses.COLS`. diff --git a/Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst b/Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst deleted file mode 100644 index 038f9e68a5422a..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-07-26-16-33-04.gh-issue-107305.qB2LS4.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add documentation for :c:type:`PyInterpreterConfig` and -:c:func:`Py_NewInterpreterFromConfig`. Also clarify some of the nearby docs -relative to per-interpreter GIL. diff --git a/Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst b/Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst deleted file mode 100644 index a1a4cf6d63725a..00000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-03-00-33-15.bpo-18319.faPTlx.rst +++ /dev/null @@ -1,2 +0,0 @@ -Ensure `gettext(msg)` retrieve translations even if a plural form exists. In -other words: `gettext(msg) == ngettext(msg, '', 1)`. diff --git a/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst b/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst deleted file mode 100644 index 2a48361fa596c9..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst +++ /dev/null @@ -1,3 +0,0 @@ -Change the default return value of -:meth:`http.client.HTTPConnection.get_proxy_response_headers` to be ``None`` -and not ``{}``. diff --git a/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst b/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst deleted file mode 100644 index 23763818d84ba5..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-06-30-16-42-44.gh-issue-106263.tk-t93.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash when calling ``repr`` with a manually constructed SignalDict object. -Patch by Charlie Zhao. \ No newline at end of file diff --git a/Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst b/Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst deleted file mode 100644 index 681d63a6668be8..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-03-03-46-20.gh-issue-106350.LLcTEe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Detect possible memory allocation failure in the libtommath function :c:func:`mp_init` -used by the ``_tkinter`` module. diff --git a/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst b/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst deleted file mode 100644 index 4fea45f16c4f8e..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst +++ /dev/null @@ -1,4 +0,0 @@ -Instances of :class:`typing.TypeVar`, :class:`typing.ParamSpec`, -:class:`typing.ParamSpecArgs`, :class:`typing.ParamSpecKwargs`, and -:class:`typing.TypeVarTuple` once again support weak references, fixing a -regression introduced in Python 3.12.0 beta 1. Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst b/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst deleted file mode 100644 index 09fc647cc01d21..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst +++ /dev/null @@ -1,2 +0,0 @@ -Revert a change to :func:`colorsys.rgb_to_hls` that caused division by zero -for certain almost-white inputs. Patch by Terry Jan Reedy. diff --git a/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst b/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst deleted file mode 100644 index d9c122f1d3c723..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst +++ /dev/null @@ -1 +0,0 @@ -Add __copy__ and __deepcopy__ in :mod:`enum` diff --git a/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst b/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst deleted file mode 100644 index bbc53d76decbc3..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fixed several bugs in zipfile.Path, including: in ``Path.match`, Windows -separators are no longer honored (and never were meant to be); Fixed -``name``/``suffix``/``suffixes``/``stem`` operations when no filename is -present and the Path is not at the root of the zipfile; Reworked glob for -performance and more correct matching behavior. diff --git a/Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst b/Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst deleted file mode 100644 index ed467573b89e14..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-15-10-24-56.gh-issue-106774.FJcqCj.rst +++ /dev/null @@ -1 +0,0 @@ -Update the bundled copy of pip to version 23.2.1. diff --git a/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst b/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst deleted file mode 100644 index d3b98626845392..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix potential missing ``NULL`` check of ``d2i_SSL_SESSION`` result in -``_ssl.c``. diff --git a/Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst b/Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst deleted file mode 100644 index b4c133a5cb1244..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-22-12-53-53.gh-issue-105002.gkfsW0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix invalid result from :meth:`PurePath.relative_to` method when attempting to walk -a "``..``" segment in *other* with *walk_up* enabled. A :exc:`ValueError` exception -is now raised in this case. diff --git a/Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst b/Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst deleted file mode 100644 index 07fdcc96fa38a6..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-22-13-09-28.gh-issue-106186.EIsUNG.rst +++ /dev/null @@ -1,3 +0,0 @@ -Do not report ``MultipartInvariantViolationDefect`` defect -when the :class:`email.parser.Parser` class is used -to parse emails with ``headersonly=True``. diff --git a/Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst b/Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst deleted file mode 100644 index e64d1860828430..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-22-15-51-33.gh-issue-83006.21zaCz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document behavior of :func:`shutil.disk_usage` for non-mounted filesystems -on Unix. diff --git a/Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst b/Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst deleted file mode 100644 index 96e2a3dcc24fb0..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-23-12-26-23.gh-issue-62519.w8-81X.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make :func:`gettext.pgettext` search plural definitions when -translation is not found. diff --git a/Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst b/Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst deleted file mode 100644 index 8e8f0245b4539b..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-24-01-21-16.gh-issue-46376.w-xuDL.rst +++ /dev/null @@ -1 +0,0 @@ -Prevent memory leak and use-after-free when using pointers to pointers with ctypes diff --git a/Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst b/Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst deleted file mode 100644 index 67677dd3c8ed24..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-03-11-31-11.gh-issue-107576.pO_s9I.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :func:`types.get_original_bases` to only return -:attr:`!__orig_bases__` if it is present on ``cls`` directly. Patch by -James Hilton-Balfe. diff --git a/Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst b/Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst deleted file mode 100644 index ecaf437a48e0ae..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-03-12-52-19.gh-issue-107077.-pzHD6.rst +++ /dev/null @@ -1,6 +0,0 @@ -Seems that in some conditions, OpenSSL will return ``SSL_ERROR_SYSCALL`` -instead of ``SSL_ERROR_SSL`` when a certification verification has failed, -but the error parameters will still contain ``ERR_LIB_SSL`` and -``SSL_R_CERTIFICATE_VERIFY_FAILED``. We are now detecting this situation and -raising the appropiate ``ssl.SSLCertVerificationError``. Patch by Pablo -Galindo diff --git a/Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst b/Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst deleted file mode 100644 index d1a8e8b5a8d3c4..00000000000000 --- a/Misc/NEWS.d/next/Security/2023-03-07-21-46-29.gh-issue-102509.5ouaH_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Start initializing ``ob_digit`` during creation of :c:type:`PyLongObject` -objects. Patch by Illia Volochii. diff --git a/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst deleted file mode 100644 index c67ec45737b535..00000000000000 --- a/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst +++ /dev/null @@ -1,4 +0,0 @@ -Reverted the :mod:`email.utils` security improvement change released in -3.12beta4 that unintentionally caused :mod:`email.utils.getaddresses` to fail -to parse email addresses with a comma in the quoted name field. -See :gh:`106669`. diff --git a/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst b/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst deleted file mode 100644 index ba7257e3610808..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst +++ /dev/null @@ -1,2 +0,0 @@ -Moved tests for ``zipfile.Path`` into ``Lib/test/test_zipfile/_path``. Made -``zipfile._path`` a package. diff --git a/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst b/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst deleted file mode 100644 index 5cc6c5bbe15446..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst +++ /dev/null @@ -1 +0,0 @@ -Avoid creating a reference to the test object in :meth:`~unittest.TestResult.collectedDurations`. diff --git a/Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst b/Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst deleted file mode 100644 index 955620521c8f68..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-07-22-13-49-40.gh-issue-106714.btYI5S.rst +++ /dev/null @@ -1,3 +0,0 @@ -test_capi: Fix test_no_FatalError_infinite_loop() to no longer write a -coredump, by using test.support.SuppressCrashReport. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst b/Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst deleted file mode 100644 index a04f7eeddef174..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-07-25-14-36-33.gh-issue-107237.y1pY79.rst +++ /dev/null @@ -1,2 +0,0 @@ -``test_logging``: Fix ``test_udp_reconnection()`` by increasing the timeout -from 100 ms to 5 minutes (LONG_TIMEOUT). Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst b/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst deleted file mode 100644 index 7e28ba6963216a..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst +++ /dev/null @@ -1,2 +0,0 @@ -``freeze`` now fetches ``CONFIG_ARGS`` from the original CPython instance -the Makefile uses to call utility scripts. Patch by Ijtaba Hussain. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst b/Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst deleted file mode 100644 index 194e3351b0470c..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-07-21-23-16-05.gh-issue-106970.NLRnml.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix bugs in the Argument Clinic ``destination clear`` command; the -destination buffers would never be cleared, and the ``destination`` -directive parser would simply continue to the fault handler after processing -the command. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst b/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst deleted file mode 100644 index 11f411be0f17c5..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows build to use OpenSSL 3.0.9 diff --git a/Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst b/Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst deleted file mode 100644 index d0eef4ec1003ce..00000000000000 --- a/Misc/NEWS.d/next/macOS/2023-07-30-23-42-20.gh-issue-99079.JAtoh1.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use OpenSSL 3.0.9. diff --git a/README.rst b/README.rst index 5257beacd31854..7742de68d5a2f0 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.12.0 beta 4 -===================================== +This is Python version 3.12.0 release candidate 1 +================================================= .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg :alt: CPython build status on GitHub Actions From 4edff44e7de383e107bcb0094e09482e50ac5779 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Sun, 6 Aug 2023 14:50:13 +0200 Subject: [PATCH 0511/1206] Post 3.12.0rc1 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 51e0e9b6d758f0..29a87c5a3f5ef6 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.12.0rc1" +#define PY_VERSION "3.12.0rc1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 6132f7099d9bb0138542d1e03728194bd066361c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Aug 2023 06:14:42 -0700 Subject: [PATCH 0512/1206] [3.12] gh-107662: Switch 'any' and 'anext' in functions.rst (GH-107663) (#107664) gh-107662: Switch 'any' and 'anext' in functions.rst (GH-107663) Order was reversed in index at top, not in body. (cherry picked from commit 9ebc6ecbc336d7b17cd158d1a4522f832df3e6e2) Co-authored-by: Terry Jan Reedy --- Doc/library/functions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 2688f43f9b4ffc..b271067ae639c5 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -14,8 +14,8 @@ are always available. They are listed here in alphabetical order. | | :func:`abs` | | :func:`enumerate` | | :func:`len` | | |func-range|_ | | | :func:`aiter` | | :func:`eval` | | |func-list|_ | | :func:`repr` | | | :func:`all` | | :func:`exec` | | :func:`locals` | | :func:`reversed` | -| | :func:`any` | | | | | | :func:`round` | -| | :func:`anext` | | **F** | | **M** | | | +| | :func:`anext` | | | | | | :func:`round` | +| | :func:`any` | | **F** | | **M** | | | | | :func:`ascii` | | :func:`filter` | | :func:`map` | | **S** | | | | | :func:`float` | | :func:`max` | | |func-set|_ | | | **B** | | :func:`format` | | |func-memoryview|_ | | :func:`setattr` | From cc766c0b15ed81ad5a6f0355da98a5e95aad7bfb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Aug 2023 06:15:39 -0700 Subject: [PATCH 0513/1206] [3.12] Docs: skip python-docs-theme 2023.7 to fix mobile menu (GH-107666) (#107690) Docs: skip python-docs-theme 2023.7 to fix mobile menu (GH-107666) (cherry picked from commit 9641c4d8e2bdf9b00dd9f373d4a74dfad000afd1) Co-authored-by: Hugo van Kemenade --- Doc/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/requirements.txt b/Doc/requirements.txt index fb558b3c5af249..4741265a0347f2 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -14,6 +14,6 @@ sphinxext-opengraph==0.7.5 # The theme used by the documentation is stored separately, so we need # to install that as well. -python-docs-theme>=2023.7 +python-docs-theme>=2023.3.1,!=2023.7 -c constraints.txt From c80112906a406d2eecf63729caad129c3f920f87 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Aug 2023 07:17:20 -0700 Subject: [PATCH 0514/1206] [3.12] Do not use deprecated ``logger.warn()`` in pyspecific (GH-107694) (#107695) Do not use deprecated ``logger.warn()`` in pyspecific (GH-107694) (cherry picked from commit 9564e31cbc95a723f2414537231bc4611b56644f) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/tools/extensions/pyspecific.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 003229d8a59754..5ae742068e491e 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -180,7 +180,7 @@ def parse_platforms(self): if unknown: cls = type(self) logger = logging.getLogger(cls.__qualname__) - logger.warn( + logger.warning( f"Unknown platform(s) or syntax '{' '.join(sorted(unknown))}' " f"in '.. availability:: {self.arguments[0]}', see " f"{__file__}:{cls.__qualname__}.known_platforms for a set " @@ -267,7 +267,7 @@ def run(self): info = env.all_audit_events.setdefault(name, new_info) if info is not new_info: if not self._do_args_match(info['args'], new_info['args']): - self.logger.warn( + self.logger.warning( "Mismatched arguments for audit-event {}: {!r} != {!r}" .format(name, info['args'], new_info['args']) ) @@ -544,7 +544,7 @@ def write(self, *ignored): 'building topics... ', length=len(pydoc_topic_labels)): if label not in self.env.domaindata['std']['labels']: - self.env.logger.warn('label %r not in documentation' % label) + self.env.logger.warning(f'label {label!r} not in documentation') continue docname, labelid, sectname = self.env.domaindata['std']['labels'][label] doctree = self.env.get_and_resolve_doctree(docname, self) From 6b02734af7849fd4da6215d7b4f8df2010e240bf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Aug 2023 07:17:45 -0700 Subject: [PATCH 0515/1206] [3.12] GH-84435: Make pyspecific directives translatable (GH-19470) (#107681) GH-84435: Make pyspecific directives translatable (GH-19470) (cherry picked from commit ecb05e0b9842ba03b42b4dec8767b1c18a4e28b3) Co-authored-by: cocoatomo Co-authored-by: Jelle Zijlstra Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- Doc/tools/extensions/pyspecific.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 5ae742068e491e..c286bcf34fa8ba 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -98,14 +98,13 @@ class ImplementationDetail(Directive): final_argument_whitespace = True # This text is copied to templates/dummy.html - label_text = 'CPython implementation detail:' + label_text = sphinx_gettext('CPython implementation detail:') def run(self): self.assert_has_content() pnode = nodes.compound(classes=['impl-detail']) - label = sphinx_gettext(self.label_text) content = self.content - add_text = nodes.strong(label, label) + add_text = nodes.strong(self.label_text, self.label_text) self.state.nested_parse(content, self.content_offset, pnode) content = nodes.inline(pnode[0].rawsource, translatable=True) content.source = pnode[0].source @@ -234,9 +233,9 @@ class AuditEvent(Directive): final_argument_whitespace = True _label = [ - "Raises an :ref:`auditing event ` {name} with no arguments.", - "Raises an :ref:`auditing event ` {name} with argument {args}.", - "Raises an :ref:`auditing event ` {name} with arguments {args}.", + sphinx_gettext("Raises an :ref:`auditing event ` {name} with no arguments."), + sphinx_gettext("Raises an :ref:`auditing event ` {name} with argument {args}."), + sphinx_gettext("Raises an :ref:`auditing event ` {name} with arguments {args}."), ] @property @@ -252,7 +251,7 @@ def run(self): else: args = [] - label = sphinx_gettext(self._label[min(2, len(args))]) + label = self._label[min(2, len(args))] text = label.format(name="``{}``".format(name), args=", ".join("``{}``".format(a) for a in args if a)) @@ -414,8 +413,8 @@ class DeprecatedRemoved(Directive): final_argument_whitespace = True option_spec = {} - _deprecated_label = 'Deprecated since version {deprecated}, will be removed in version {removed}' - _removed_label = 'Deprecated since version {deprecated}, removed in version {removed}' + _deprecated_label = sphinx_gettext('Deprecated since version {deprecated}, will be removed in version {removed}') + _removed_label = sphinx_gettext('Deprecated since version {deprecated}, removed in version {removed}') def run(self): node = addnodes.versionmodified() @@ -431,7 +430,6 @@ def run(self): else: label = self._removed_label - label = sphinx_gettext(label) text = label.format(deprecated=self.arguments[0], removed=self.arguments[1]) if len(self.arguments) == 3: inodes, messages = self.state.inline_text(self.arguments[2], From e950d7045161b3dd10185400799637e5f7118b3c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Aug 2023 13:08:38 -0700 Subject: [PATCH 0516/1206] [3.12] Docs: Fix Sphinx annotations in Doc/library/ctypes.rst (GH-107672) (#107685) Docs: Fix Sphinx annotations in Doc/library/ctypes.rst (GH-107672) (cherry picked from commit 71a7c96ffeb0d7fef06be3e57468896e030967a5) Co-authored-by: Erlend E. Aasland Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/conf.py | 2 ++ Doc/library/ctypes.rst | 65 +++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index a8fd853ebb1f06..fd115f7551f44c 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -110,6 +110,8 @@ ('c:type', 'uintptr_t'), ('c:type', 'va_list'), ('c:type', 'wchar_t'), + ('c:type', '__int64'), + ('c:type', 'unsigned __int64'), # Standard C structures ('c:struct', 'in6_addr'), ('c:struct', 'in_addr'), diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index c253a45e1a8b54..ff579d980d5ed9 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -72,8 +72,9 @@ Windows appends the usual ``.dll`` file suffix automatically. On Linux, it is required to specify the filename *including* the extension to load a library, so attribute access can not be used to load libraries. Either the -:meth:`LoadLibrary` method of the dll loaders should be used, or you should load -the library by creating an instance of CDLL by calling the constructor:: +:meth:`~LibraryLoader.LoadLibrary` method of the dll loaders should be used, +or you should load the library by creating an instance of CDLL by calling +the constructor:: >>> cdll.LoadLibrary("libc.so.6") # doctest: +LINUX @@ -333,7 +334,7 @@ property:: 10 b'Hi\x00lo\x00\x00\x00\x00\x00' >>> -The :func:`create_string_buffer` function replaces the old :func:`c_buffer` +The :func:`create_string_buffer` function replaces the old :func:`!c_buffer` function (which is still available as an alias). To create a mutable memory block containing unicode characters of the C type :c:type:`wchar_t`, use the :func:`create_unicode_buffer` function. @@ -383,15 +384,15 @@ as calling functions with a fixed number of parameters. On some platforms, and i particular ARM64 for Apple Platforms, the calling convention for variadic functions is different than that for regular functions. -On those platforms it is required to specify the *argtypes* attribute for the -regular, non-variadic, function arguments: +On those platforms it is required to specify the :attr:`~_FuncPtr.argtypes` +attribute for the regular, non-variadic, function arguments: .. code-block:: python3 libc.printf.argtypes = [ctypes.c_char_p] Because specifying the attribute does not inhibit portability it is advised to always -specify ``argtypes`` for all variadic functions. +specify :attr:`~_FuncPtr.argtypes` for all variadic functions. .. _ctypes-calling-functions-with-own-custom-data-types: @@ -401,7 +402,7 @@ Calling functions with your own custom data types You can also customize :mod:`ctypes` argument conversion to allow instances of your own classes be used as function arguments. :mod:`ctypes` looks for an -:attr:`_as_parameter_` attribute and uses this as the function argument. Of +:attr:`!_as_parameter_` attribute and uses this as the function argument. Of course, it must be one of integer, string, or bytes:: >>> class Bottles: @@ -414,7 +415,7 @@ course, it must be one of integer, string, or bytes:: 19 >>> -If you don't want to store the instance's data in the :attr:`_as_parameter_` +If you don't want to store the instance's data in the :attr:`!_as_parameter_` instance variable, you could define a :class:`property` which makes the attribute available on request. @@ -425,9 +426,9 @@ Specifying the required argument types (function prototypes) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It is possible to specify the required argument types of functions exported from -DLLs by setting the :attr:`argtypes` attribute. +DLLs by setting the :attr:`~_FuncPtr.argtypes` attribute. -:attr:`argtypes` must be a sequence of C data types (the ``printf`` function is +:attr:`~_FuncPtr.argtypes` must be a sequence of C data types (the :func:`!printf` function is probably not a good example here, because it takes a variable number and different types of parameters depending on the format string, on the other hand this is quite handy to experiment with this feature):: @@ -451,14 +452,14 @@ prototype for a C function), and tries to convert the arguments to valid types:: >>> If you have defined your own classes which you pass to function calls, you have -to implement a :meth:`from_param` class method for them to be able to use them -in the :attr:`argtypes` sequence. The :meth:`from_param` class method receives +to implement a :meth:`~_CData.from_param` class method for them to be able to use them +in the :attr:`~_FuncPtr.argtypes` sequence. The :meth:`~_CData.from_param` class method receives the Python object passed to the function call, it should do a typecheck or whatever is needed to make sure this object is acceptable, and then return the -object itself, its :attr:`_as_parameter_` attribute, or whatever you want to +object itself, its :attr:`!_as_parameter_` attribute, or whatever you want to pass as the C function argument in this case. Again, the result should be an integer, string, bytes, a :mod:`ctypes` instance, or an object with an -:attr:`_as_parameter_` attribute. +:attr:`!_as_parameter_` attribute. .. _ctypes-return-types: @@ -478,13 +479,13 @@ By default functions are assumed to return the C :c:expr:`int` type. Other return types can be specified by setting the :attr:`restype` attribute of the function object. -The C prototype of ``time()`` is ``time_t time(time_t *)``. Because :c:type:`time_t` -might be of a different type than the default return type ``int``, you should -specify the ``restype``:: +The C prototype of :c:func:`time` is ``time_t time(time_t *)``. Because :c:type:`time_t` +might be of a different type than the default return type :c:expr:`int`, you should +specify the :attr:`!restype` attribute:: >>> libc.time.restype = c_time_t -The argument types can be specified using ``argtypes``:: +The argument types can be specified using :attr:`~_FuncPtr.argtypes`:: >>> libc.time.argtypes = (POINTER(c_time_t),) @@ -493,7 +494,7 @@ To call the function with a ``NULL`` pointer as first argument, use ``None``:: >>> print(libc.time(None)) # doctest: +SKIP 1150640792 -Here is a more advanced example, it uses the ``strchr`` function, which expects +Here is a more advanced example, it uses the :func:`strchr` function, which expects a string pointer and a char, and returns a pointer to a string:: >>> strchr = libc.strchr @@ -506,8 +507,8 @@ a string pointer and a char, and returns a pointer to a string:: None >>> -If you want to avoid the ``ord("x")`` calls above, you can set the -:attr:`argtypes` attribute, and the second argument will be converted from a +If you want to avoid the :func:`ord("x") ` calls above, you can set the +:attr:`~_FuncPtr.argtypes` attribute, and the second argument will be converted from a single character Python bytes object into a C char: .. doctest:: @@ -853,7 +854,7 @@ Type conversions ^^^^^^^^^^^^^^^^ Usually, ctypes does strict type checking. This means, if you have -``POINTER(c_int)`` in the :attr:`argtypes` list of a function or as the type of +``POINTER(c_int)`` in the :attr:`~_FuncPtr.argtypes` list of a function or as the type of a member field in a structure definition, only instances of exactly the same type are accepted. There are some exceptions to this rule, where ctypes accepts other objects. For example, you can pass compatible array instances instead of @@ -874,7 +875,7 @@ pointer types. So, for ``POINTER(c_int)``, ctypes accepts an array of c_int:: >>> In addition, if a function argument is explicitly declared to be a pointer type -(such as ``POINTER(c_int)``) in :attr:`argtypes`, an object of the pointed +(such as ``POINTER(c_int)``) in :attr:`_FuncPtr.argtypes`, an object of the pointed type (``c_int`` in this case) can be passed to the function. ctypes will apply the required :func:`byref` conversion in this case automatically. @@ -1437,7 +1438,7 @@ function exported by these libraries, and reacquired afterwards. All these classes can be instantiated by calling them with at least one argument, the pathname of the shared library. If you have an existing handle to an already loaded shared library, it can be passed as the ``handle`` named -parameter, otherwise the underlying platforms ``dlopen`` or ``LoadLibrary`` +parameter, otherwise the underlying platforms :c:func:`!dlopen` or :c:func:`LoadLibrary` function is used to load the library into the process, and to get a handle to it. @@ -1522,8 +1523,8 @@ underscore to not clash with exported function names: Shared libraries can also be loaded by using one of the prefabricated objects, which are instances of the :class:`LibraryLoader` class, either by calling the -:meth:`LoadLibrary` method, or by retrieving the library as attribute of the -loader instance. +:meth:`~LibraryLoader.LoadLibrary` method, or by retrieving the library as +attribute of the loader instance. .. class:: LibraryLoader(dlltype) @@ -1639,14 +1640,14 @@ They are instances of a private class: unspecified arguments as well. When a foreign function is called, each actual argument is passed to the - :meth:`from_param` class method of the items in the :attr:`argtypes` + :meth:`~_CData.from_param` class method of the items in the :attr:`argtypes` tuple, this method allows adapting the actual argument to an object that the foreign function accepts. For example, a :class:`c_char_p` item in the :attr:`argtypes` tuple will convert a string passed as argument into a bytes object using ctypes conversion rules. New: It is now possible to put items in argtypes which are not ctypes - types, but each item must have a :meth:`from_param` method which returns a + types, but each item must have a :meth:`~_CData.from_param` method which returns a value usable as argument (integer, string, ctypes instance). This allows defining adapters that can adapt custom objects as function parameters. @@ -1770,12 +1771,12 @@ different ways, depending on the type and number of the parameters in the call: COM methods use a special calling convention: They require a pointer to the COM interface as first argument, in addition to those parameters that - are specified in the :attr:`argtypes` tuple. + are specified in the :attr:`~_FuncPtr.argtypes` tuple. The optional *paramflags* parameter creates foreign function wrappers with much more functionality than the features described above. - *paramflags* must be a tuple of the same length as :attr:`argtypes`. + *paramflags* must be a tuple of the same length as :attr:`~_FuncPtr.argtypes`. Each item in this tuple contains further information about a parameter, it must be a tuple containing one, two, or three items. @@ -2157,8 +2158,8 @@ Data types This method adapts *obj* to a ctypes type. It is called with the actual object used in a foreign function call when the type is present in the - foreign function's :attr:`argtypes` tuple; it must return an object that - can be used as a function call parameter. + foreign function's :attr:`~_FuncPtr.argtypes` tuple; + it must return an object that can be used as a function call parameter. All ctypes data types have a default implementation of this classmethod that normally returns *obj* if that is an instance of the type. Some From e94548479aaa46e0624da98f8f6b48904860ee73 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Aug 2023 13:09:00 -0700 Subject: [PATCH 0517/1206] [3.12] Docs: Argument Clinic: Improve 'How to write a custom converter' (GH-107328) (#107669) Docs: Argument Clinic: Improve 'How to write a custom converter' (GH-107328) - Omit unneccesary wording and sentences - Don't mention implementation details (no digression, explanation) (cherry picked from commit 4a5b4221e381c541f3f73537b7b87580d100158b) Co-authored-by: Erlend E. Aasland Co-authored-by: Ezio Melotti --- Doc/howto/clinic.rst | 50 +++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 9c9a4f45dd0f58..dcede13a03b4a5 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1343,35 +1343,37 @@ state. Example from the ``setattro`` slot method in See also :pep:`573`. +.. _clinic-howto-custom-converter: + How to write a custom converter ------------------------------- -As we hinted at in the previous section... you can write your own converters! -A converter is simply a Python class that inherits from :py:class:`!CConverter`. -The main purpose of a custom converter is if you have a parameter using -the ``O&`` format unit—parsing this parameter means calling +A converter is a Python class that inherits from :py:class:`!CConverter`. +The main purpose of a custom converter, is for parameters parsed with +the ``O&`` format unit --- parsing such a parameter means calling a :c:func:`PyArg_ParseTuple` "converter function". -Your converter class should be named ``*something*_converter``. -If the name follows this convention, then your converter class -will be automatically registered with Argument Clinic; its name -will be the name of your class with the ``_converter`` suffix -stripped off. (This is accomplished with a metaclass.) - -You shouldn't subclass :py:meth:`!CConverter.__init__`. Instead, you should -write a :py:meth:`!converter_init` function. :py:meth:`!converter_init` -always accepts a *self* parameter; after that, all additional -parameters *must* be keyword-only. Any arguments passed in to -the converter in Argument Clinic will be passed along to your -:py:meth:`!converter_init`. +Your converter class should be named :samp:`{ConverterName}_converter`. +By following this convention, your converter class will be automatically +registered with Argument Clinic, with its *converter name* being the name of +your converter class with the ``_converter`` suffix stripped off. -There are some additional members of :py:class:`!CConverter` you may wish -to specify in your subclass. Here's the current list: +Instead of subclassing :py:meth:`!CConverter.__init__`, +write a :py:meth:`!converter_init` method. +Apart for the *self* parameter, all additional :py:meth:`!converter_init` +parameters **must** be keyword-only. +Any arguments passed to the converter in Argument Clinic +will be passed along to your :py:meth:`!converter_init` method. +See :py:class:`!CConverter` for a list of members you may wish to specify in +your subclass. .. module:: clinic .. class:: CConverter + The base class for all converters. + See :ref:`clinic-howto-custom-converter` for how to subclass this class. + .. attribute:: type The C type to use for this variable. @@ -1436,16 +1438,16 @@ Here's the simplest example of a custom converter, from :source:`Modules/zlibmod [python start generated code]*/ /*[python end generated code: output=da39a3ee5e6b4b0d input=35521e4e733823c7]*/ -This block adds a converter to Argument Clinic named ``ssize_t``. Parameters -declared as ``ssize_t`` will be declared as type :c:type:`Py_ssize_t`, and will -be parsed by the ``'O&'`` format unit, which will call the -``ssize_t_converter`` converter function. ``ssize_t`` variables -automatically support default values. +This block adds a converter named ``ssize_t`` to Argument Clinic. +Parameters declared as ``ssize_t`` will be declared with type :c:type:`Py_ssize_t`, +and will be parsed by the ``'O&'`` format unit, +which will call the :c:func:`!ssize_t_converter` converter C function. +``ssize_t`` variables automatically support default values. More sophisticated custom converters can insert custom C code to handle initialization and cleanup. You can see more examples of custom converters in the CPython -source tree; grep the C files for the string :py:class:`!CConverter`. +source tree; grep the C files for the string ``CConverter``. How to write a custom return converter From ab1988d5a6797a35a9d81e840a73b2e988da6dcc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 6 Aug 2023 15:48:48 -0700 Subject: [PATCH 0518/1206] [3.12] Improve cross-references in `runpy` docs (GH-107673) (#107698) Improve cross-references in `runpy` docs (GH-107673) - Add links to `__main__` and `sys.path` where appropriate - Ensure each paragraph never has more than one link to the same thing, to avoid visual clutter from too many links (cherry picked from commit 4e242d1ffb2d165443fe2680f7d1fef9fecbcfc0) Co-authored-by: Kamil Turek --- Doc/library/runpy.rst | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst index 42ed8c253b8027..406b080b7be30f 100644 --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -39,7 +39,7 @@ The :mod:`runpy` module provides two functions: The *mod_name* argument should be an absolute module name. If the module name refers to a package rather than a normal - module, then that package is imported and the ``__main__`` submodule within + module, then that package is imported and the :mod:`__main__` submodule within that package is then executed and the resulting module globals dictionary returned. @@ -74,7 +74,7 @@ The :mod:`runpy` module provides two functions: Note that this manipulation of :mod:`sys` is not thread-safe. Other threads may see the partially initialised module, as well as the altered list of - arguments. It is recommended that the :mod:`sys` module be left alone when + arguments. It is recommended that the ``sys`` module be left alone when invoking this function from threaded code. .. seealso:: @@ -82,7 +82,7 @@ The :mod:`runpy` module provides two functions: command line. .. versionchanged:: 3.1 - Added ability to execute packages by looking for a ``__main__`` submodule. + Added ability to execute packages by looking for a :mod:`__main__` submodule. .. versionchanged:: 3.2 Added ``__cached__`` global variable (see :pep:`3147`). @@ -106,15 +106,16 @@ The :mod:`runpy` module provides two functions: Execute the code at the named filesystem location and return the resulting module globals dictionary. As with a script name supplied to the CPython command line, the supplied path may refer to a Python source file, a - compiled bytecode file or a valid sys.path entry containing a ``__main__`` - module (e.g. a zipfile containing a top-level ``__main__.py`` file). + compiled bytecode file or a valid :data:`sys.path` entry containing a + :mod:`__main__` module + (e.g. a zipfile containing a top-level ``__main__.py`` file). For a simple script, the specified code is simply executed in a fresh - module namespace. For a valid sys.path entry (typically a zipfile or + module namespace. For a valid :data:`sys.path` entry (typically a zipfile or directory), the entry is first added to the beginning of ``sys.path``. The function then looks for and executes a :mod:`__main__` module using the updated path. Note that there is no special protection against invoking - an existing :mod:`__main__` entry located elsewhere on ``sys.path`` if + an existing ``__main__`` entry located elsewhere on ``sys.path`` if there is no such module at the specified location. The optional dictionary argument *init_globals* may be used to pre-populate @@ -137,14 +138,14 @@ The :mod:`runpy` module provides two functions: supplied path, and ``__spec__``, ``__cached__``, ``__loader__`` and ``__package__`` will all be set to :const:`None`. - If the supplied path is a reference to a valid sys.path entry, then - ``__spec__`` will be set appropriately for the imported ``__main__`` + If the supplied path is a reference to a valid :data:`sys.path` entry, then + ``__spec__`` will be set appropriately for the imported :mod:`__main__` module (that is, ``__spec__.name`` will always be ``__main__``). ``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` will be :ref:`set as normal ` based on the module spec. A number of alterations are also made to the :mod:`sys` module. Firstly, - ``sys.path`` may be altered as described above. ``sys.argv[0]`` is updated + :data:`sys.path` may be altered as described above. ``sys.argv[0]`` is updated with the value of ``path_name`` and ``sys.modules[__name__]`` is updated with a temporary module object for the module being executed. All modifications to items in :mod:`sys` are reverted before the function @@ -152,7 +153,7 @@ The :mod:`runpy` module provides two functions: Note that, unlike :func:`run_module`, the alterations made to :mod:`sys` are not optional in this function as these adjustments are essential to - allowing the execution of sys.path entries. As the thread-safety + allowing the execution of :data:`sys.path` entries. As the thread-safety limitations still apply, use of this function in threaded code should be either serialised with the import lock or delegated to a separate process. @@ -165,7 +166,7 @@ The :mod:`runpy` module provides two functions: .. versionchanged:: 3.4 Updated to take advantage of the module spec feature added by :pep:`451`. This allows ``__cached__`` to be set correctly in the - case where ``__main__`` is imported from a valid sys.path entry rather + case where ``__main__`` is imported from a valid :data:`sys.path` entry rather than being executed directly. .. versionchanged:: 3.12 From 19863c36d2c9172b5c6c930e3c54ab8d63271993 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 7 Aug 2023 03:03:07 -0700 Subject: [PATCH 0519/1206] [3.12] Docs: Argument Clinic: Move the CConverter class to the reference (GH-107671) (#107701) Docs: Argument Clinic: Move the CConverter class to the reference (GH-107671) (cherry picked from commit a6675b1a597c67be972598ac8562883fabe48099) Co-authored-by: Erlend E. Aasland --- Doc/howto/clinic.rst | 133 ++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index dcede13a03b4a5..e8e6aace350e0c 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -193,6 +193,71 @@ The CLI supports the following options: The list of files to process. +.. _clinic-classes: + +Classes for extending Argument Clinic +------------------------------------- + +.. module:: clinic + +.. class:: CConverter + + The base class for all converters. + See :ref:`clinic-howto-custom-converter` for how to subclass this class. + + .. attribute:: type + + The C type to use for this variable. + :attr:`!type` should be a Python string specifying the type, + e.g. ``'int'``. + If this is a pointer type, the type string should end with ``' *'``. + + .. attribute:: default + + The Python default value for this parameter, as a Python value. + Or the magic value ``unspecified`` if there is no default. + + .. attribute:: py_default + + :attr:`!default` as it should appear in Python code, + as a string. + Or ``None`` if there is no default. + + .. attribute:: c_default + + :attr:`!default` as it should appear in C code, + as a string. + Or ``None`` if there is no default. + + .. attribute:: c_ignored_default + + The default value used to initialize the C variable when + there is no default, but not specifying a default may + result in an "uninitialized variable" warning. This can + easily happen when using option groups—although + properly written code will never actually use this value, + the variable does get passed in to the impl, and the + C compiler will complain about the "use" of the + uninitialized value. This value should always be a + non-empty string. + + .. attribute:: converter + + The name of the C converter function, as a string. + + .. attribute:: impl_by_reference + + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into the impl function. + + .. attribute:: parse_by_reference + + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into :c:func:`PyArg_ParseTuple`. + + .. _clinic-tutorial: Tutorial @@ -1348,7 +1413,7 @@ See also :pep:`573`. How to write a custom converter ------------------------------- -A converter is a Python class that inherits from :py:class:`!CConverter`. +A converter is a Python class that inherits from :py:class:`CConverter`. The main purpose of a custom converter, is for parameters parsed with the ``O&`` format unit --- parsing such a parameter means calling a :c:func:`PyArg_ParseTuple` "converter function". @@ -1360,73 +1425,13 @@ your converter class with the ``_converter`` suffix stripped off. Instead of subclassing :py:meth:`!CConverter.__init__`, write a :py:meth:`!converter_init` method. -Apart for the *self* parameter, all additional :py:meth:`!converter_init` -parameters **must** be keyword-only. +:py:meth:`!converter_init` always accepts a *self* parameter. +After *self*, all additional parameters **must** be keyword-only. Any arguments passed to the converter in Argument Clinic will be passed along to your :py:meth:`!converter_init` method. -See :py:class:`!CConverter` for a list of members you may wish to specify in +See :py:class:`CConverter` for a list of members you may wish to specify in your subclass. -.. module:: clinic - -.. class:: CConverter - - The base class for all converters. - See :ref:`clinic-howto-custom-converter` for how to subclass this class. - - .. attribute:: type - - The C type to use for this variable. - :attr:`!type` should be a Python string specifying the type, - e.g. ``'int'``. - If this is a pointer type, the type string should end with ``' *'``. - - .. attribute:: default - - The Python default value for this parameter, as a Python value. - Or the magic value ``unspecified`` if there is no default. - - .. attribute:: py_default - - :attr:`!default` as it should appear in Python code, - as a string. - Or ``None`` if there is no default. - - .. attribute:: c_default - - :attr:`!default` as it should appear in C code, - as a string. - Or ``None`` if there is no default. - - .. attribute:: c_ignored_default - - The default value used to initialize the C variable when - there is no default, but not specifying a default may - result in an "uninitialized variable" warning. This can - easily happen when using option groups—although - properly written code will never actually use this value, - the variable does get passed in to the impl, and the - C compiler will complain about the "use" of the - uninitialized value. This value should always be a - non-empty string. - - .. attribute:: converter - - The name of the C converter function, as a string. - - .. attribute:: impl_by_reference - - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into the impl function. - - .. attribute:: parse_by_reference - - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into :c:func:`PyArg_ParseTuple`. - - Here's the simplest example of a custom converter, from :source:`Modules/zlibmodule.c`:: /*[python input] From e5582bdbcf56033a445c7a96eca8503968771b33 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 7 Aug 2023 05:33:25 -0700 Subject: [PATCH 0520/1206] [3.12] gh-107442: Document all valid types for ctypes _as_parameter_ (GH-107443) (#107707) gh-107442: Document all valid types for ctypes _as_parameter_ (GH-107443) (cherry picked from commit 6925c578a0e3cbb00858e64da813a7ffe79623c4) Co-authored-by: Tomas R --- Doc/library/ctypes.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index ff579d980d5ed9..3c794beca32c14 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -401,9 +401,10 @@ Calling functions with your own custom data types ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can also customize :mod:`ctypes` argument conversion to allow instances of -your own classes be used as function arguments. :mod:`ctypes` looks for an -:attr:`!_as_parameter_` attribute and uses this as the function argument. Of -course, it must be one of integer, string, or bytes:: +your own classes be used as function arguments. :mod:`ctypes` looks for an +:attr:`!_as_parameter_` attribute and uses this as the function argument. The +attribute must be an integer, string, bytes, a :mod:`ctypes` instance, or an +object with an :attr:`!_as_parameter_` attribute:: >>> class Bottles: ... def __init__(self, number): From aa2ecef22a66938cba072ea57c27c63c11f79c9a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 8 Aug 2023 07:25:35 -0700 Subject: [PATCH 0521/1206] [3.12] gh-98154: Clarify Usage of "Reference Count" In the Docs (gh-107552) (#107752) * gh-98154: Clarify Usage of "Reference Count" In the Docs (gh-107552) PEP 683 (immortal objects) revealed some ways in which the Python documentation has been unnecessarily coupled to the implementation details of reference counts. In the end users should focus on reference ownership, including taking references and releasing them, rather than on how many reference counts an object has. This change updates the documentation to reflect that perspective. It also updates the docs relative to immortal objects in a handful of places. (cherry picked from commit 5dc825d504ad08d64c9d1ce578f9deebbe012604) Co-authored-by: Eric Snow * Fix a typo. --------- Co-authored-by: Eric Snow --- Doc/c-api/allocation.rst | 13 ++++--- Doc/c-api/arg.rst | 17 +++++--- Doc/c-api/buffer.rst | 7 +++- Doc/c-api/bytes.rst | 4 +- Doc/c-api/exceptions.rst | 3 +- Doc/c-api/init_config.rst | 2 +- Doc/c-api/intro.rst | 59 +++++++++++++++------------- Doc/c-api/module.rst | 2 +- Doc/c-api/object.rst | 13 ++++--- Doc/c-api/refcounting.rst | 81 ++++++++++++++++++++++++++++----------- Doc/c-api/sys.rst | 5 ++- Doc/c-api/typeobj.rst | 10 +++-- Doc/c-api/unicode.rst | 12 +++--- Doc/glossary.rst | 15 +++++--- Doc/library/sys.rst | 9 +++++ 15 files changed, 162 insertions(+), 90 deletions(-) diff --git a/Doc/c-api/allocation.rst b/Doc/c-api/allocation.rst index 44747e29643661..b3609c233156b6 100644 --- a/Doc/c-api/allocation.rst +++ b/Doc/c-api/allocation.rst @@ -29,12 +29,13 @@ Allocating Objects on the Heap .. c:macro:: PyObject_New(TYPE, typeobj) - Allocate a new Python object using the C structure type *TYPE* and the - Python type object *typeobj* (``PyTypeObject*``). - Fields not defined by the Python object header - are not initialized; the object's reference count will be one. The size of - the memory allocation is determined from the :c:member:`~PyTypeObject.tp_basicsize` field of - the type object. + Allocate a new Python object using the C structure type *TYPE* + and the Python type object *typeobj* (``PyTypeObject*``). + Fields not defined by the Python object header are not initialized. + The caller will own the only reference to the object + (i.e. its reference count will be one). + The size of the memory allocation is determined from the + :c:member:`~PyTypeObject.tp_basicsize` field of the type object. .. c:macro:: PyObject_NewVar(TYPE, typeobj, size) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index c09c2d5261ca08..657b10d3e0ac48 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -293,8 +293,10 @@ Other objects ``O`` (object) [PyObject \*] Store a Python object (without any conversion) in a C object pointer. The C - program thus receives the actual object that was passed. The object's reference - count is not increased. The pointer stored is not ``NULL``. + program thus receives the actual object that was passed. A new + :term:`strong reference` to the object is not created + (i.e. its reference count is not increased). + The pointer stored is not ``NULL``. ``O!`` (object) [*typeobject*, PyObject \*] Store a Python object in a C object pointer. This is similar to ``O``, but @@ -378,7 +380,8 @@ inside nested parentheses. They are: mutually exclude each other. Note that any Python object references which are provided to the caller are -*borrowed* references; do not decrement their reference count! +*borrowed* references; do not release them +(i.e. do not decrement their reference count)! Additional arguments passed to these functions must be addresses of variables whose type is determined by the format string; these are used to store values @@ -613,8 +616,10 @@ Building values Convert a C :c:type:`Py_complex` structure to a Python complex number. ``O`` (object) [PyObject \*] - Pass a Python object untouched (except for its reference count, which is - incremented by one). If the object passed in is a ``NULL`` pointer, it is assumed + Pass a Python object untouched but create a new + :term:`strong reference` to it + (i.e. its reference count is incremented by one). + If the object passed in is a ``NULL`` pointer, it is assumed that this was caused because the call producing the argument found an error and set an exception. Therefore, :c:func:`Py_BuildValue` will return ``NULL`` but won't raise an exception. If no exception has been raised yet, :exc:`SystemError` is @@ -624,7 +629,7 @@ Building values Same as ``O``. ``N`` (object) [PyObject \*] - Same as ``O``, except it doesn't increment the reference count on the object. + Same as ``O``, except it doesn't create a new :term:`strong reference`. Useful when the object is created by a call to an object constructor in the argument list. diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 02b53ec149c733..8ca1c190dab9a9 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -102,7 +102,9 @@ a buffer, see :c:func:`PyObject_GetBuffer`. .. c:member:: PyObject *obj A new reference to the exporting object. The reference is owned by - the consumer and automatically decremented and set to ``NULL`` by + the consumer and automatically released + (i.e. reference count decremented) + and set to ``NULL`` by :c:func:`PyBuffer_Release`. The field is the equivalent of the return value of any standard C-API function. @@ -454,7 +456,8 @@ Buffer-related functions .. c:function:: void PyBuffer_Release(Py_buffer *view) - Release the buffer *view* and decrement the reference count for + Release the buffer *view* and release the :term:`strong reference` + (i.e. decrement the reference count) to the view's supporting object, ``view->obj``. This function MUST be called when the buffer is no longer being used, otherwise reference leaks may occur. diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index 4e3ffc7e23e3f8..61a68f52773882 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -184,8 +184,8 @@ called with a non-bytes parameter. .. c:function:: void PyBytes_ConcatAndDel(PyObject **bytes, PyObject *newpart) Create a new bytes object in *\*bytes* containing the contents of *newpart* - appended to *bytes*. This version decrements the reference count of - *newpart*. + appended to *bytes*. This version releases the :term:`strong reference` + to *newpart* (i.e. decrements its reference count). .. c:function:: int _PyBytes_Resize(PyObject **bytes, Py_ssize_t newsize) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index a2126ffc559aba..f1d6c995188abb 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -110,7 +110,8 @@ For convenience, some of these functions will always return a This is the most common way to set the error indicator. The first argument specifies the exception type; it is normally one of the standard exceptions, - e.g. :c:data:`PyExc_RuntimeError`. You need not increment its reference count. + e.g. :c:data:`PyExc_RuntimeError`. You need not create a new + :term:`strong reference` to it (e.g. with :c:func:`Py_INCREF`). The second argument is an error message; it is decoded from ``'utf-8'``. diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 9da9f873e74484..96705c804f11d7 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -1109,7 +1109,7 @@ PyConfig .. c:member:: int show_ref_count - Show total reference count at exit? + Show total reference count at exit (excluding immortal objects)? Set to ``1`` by :option:`-X showrefcount <-X>` command line option. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 42a5db1893472e..4a6cb7ab3b8381 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -287,52 +287,58 @@ true if (and only if) the object pointed to by *a* is a Python list. Reference Counts ---------------- -The reference count is important because today's computers have a finite (and -often severely limited) memory size; it counts how many different places there -are that have a reference to an object. Such a place could be another object, -or a global (or static) C variable, or a local variable in some C function. -When an object's reference count becomes zero, the object is deallocated. If -it contains references to other objects, their reference count is decremented. -Those other objects may be deallocated in turn, if this decrement makes their -reference count become zero, and so on. (There's an obvious problem with -objects that reference each other here; for now, the solution is "don't do -that.") +The reference count is important because today's computers have a finite +(and often severely limited) memory size; it counts how many different +places there are that have a :term:`strong reference` to an object. +Such a place could be another object, or a global (or static) C variable, +or a local variable in some C function. +When the last :term:`strong reference` to an object is released +(i.e. its reference count becomes zero), the object is deallocated. +If it contains references to other objects, those references are released. +Those other objects may be deallocated in turn, if there are no more +references to them, and so on. (There's an obvious problem with +objects that reference each other here; for now, the solution +is "don't do that.") .. index:: single: Py_INCREF() single: Py_DECREF() -Reference counts are always manipulated explicitly. The normal way is to use -the macro :c:func:`Py_INCREF` to increment an object's reference count by one, -and :c:func:`Py_DECREF` to decrement it by one. The :c:func:`Py_DECREF` macro +Reference counts are always manipulated explicitly. The normal way is +to use the macro :c:func:`Py_INCREF` to take a new reference to an +object (i.e. increment its reference count by one), +and :c:func:`Py_DECREF` to release that reference (i.e. decrement the +reference count by one). The :c:func:`Py_DECREF` macro is considerably more complex than the incref one, since it must check whether the reference count becomes zero and then cause the object's deallocator to be -called. The deallocator is a function pointer contained in the object's type -structure. The type-specific deallocator takes care of decrementing the -reference counts for other objects contained in the object if this is a compound +called. The deallocator is a function pointer contained in the object's type +structure. The type-specific deallocator takes care of releasing references +for other objects contained in the object if this is a compound object type, such as a list, as well as performing any additional finalization that's needed. There's no chance that the reference count can overflow; at least as many bits are used to hold the reference count as there are distinct memory locations in virtual memory (assuming ``sizeof(Py_ssize_t) >= sizeof(void*)``). Thus, the reference count increment is a simple operation. -It is not necessary to increment an object's reference count for every local -variable that contains a pointer to an object. In theory, the object's +It is not necessary to hold a :term:`strong reference` (i.e. increment +the reference count) for every local variable that contains a pointer +to an object. In theory, the object's reference count goes up by one when the variable is made to point to it and it goes down by one when the variable goes out of scope. However, these two cancel each other out, so at the end the reference count hasn't changed. The only real reason to use the reference count is to prevent the object from being deallocated as long as our variable is pointing to it. If we know that there is at least one other reference to the object that lives at least as long as -our variable, there is no need to increment the reference count temporarily. +our variable, there is no need to take a new :term:`strong reference` +(i.e. increment the reference count) temporarily. An important situation where this arises is in objects that are passed as arguments to C functions in an extension module that are called from Python; the call mechanism guarantees to hold a reference to every argument for the duration of the call. However, a common pitfall is to extract an object from a list and hold on to it -for a while without incrementing its reference count. Some other operation might -conceivably remove the object from the list, decrementing its reference count +for a while without taking a new reference. Some other operation might +conceivably remove the object from the list, releasing that reference, and possibly deallocating it. The real danger is that innocent-looking operations may invoke arbitrary Python code which could do this; there is a code path which allows control to flow back to the user from a :c:func:`Py_DECREF`, so @@ -340,7 +346,8 @@ almost any operation is potentially dangerous. A safe approach is to always use the generic operations (functions whose name begins with ``PyObject_``, ``PyNumber_``, ``PySequence_`` or ``PyMapping_``). -These operations always increment the reference count of the object they return. +These operations always create a new :term:`strong reference` +(i.e. increment the reference count) of the object they return. This leaves the caller with the responsibility to call :c:func:`Py_DECREF` when they are done with the result; this soon becomes second nature. @@ -356,7 +363,7 @@ to objects (objects are not owned: they are always shared). "Owning a reference" means being responsible for calling Py_DECREF on it when the reference is no longer needed. Ownership can also be transferred, meaning that the code that receives ownership of the reference then becomes responsible for -eventually decref'ing it by calling :c:func:`Py_DECREF` or :c:func:`Py_XDECREF` +eventually releasing it by calling :c:func:`Py_DECREF` or :c:func:`Py_XDECREF` when it's no longer needed---or passing on this responsibility (usually to its caller). When a function passes ownership of a reference on to its caller, the caller is said to receive a *new* reference. When no ownership is transferred, @@ -414,9 +421,9 @@ For example, the above two blocks of code could be replaced by the following It is much more common to use :c:func:`PyObject_SetItem` and friends with items whose references you are only borrowing, like arguments that were passed in to -the function you are writing. In that case, their behaviour regarding reference -counts is much saner, since you don't have to increment a reference count so you -can give a reference away ("have it be stolen"). For example, this function +the function you are writing. In that case, their behaviour regarding references +is much saner, since you don't have to take a new reference just so you +can give that reference away ("have it be stolen"). For example, this function sets all items of a list (actually, any mutable sequence) to a given item:: int diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 2b6875d533c825..cb6b0a47681e95 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -529,7 +529,7 @@ state: .. note:: Unlike other functions that steal references, ``PyModule_AddObject()`` - only decrements the reference count of *value* **on success**. + only releases the reference to *value* **on success**. This means that its return value must be checked, and calling code must :c:func:`Py_DECREF` *value* manually on error. diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 5b3c3615f75818..4a3fed1a6087a1 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -15,8 +15,8 @@ Object Protocol .. c:macro:: Py_RETURN_NOTIMPLEMENTED Properly handle returning :c:data:`Py_NotImplemented` from within a C - function (that is, increment the reference count of NotImplemented and - return it). + function (that is, create a new :term:`strong reference` + to NotImplemented and return it). .. c:function:: int PyObject_Print(PyObject *o, FILE *fp, int flags) @@ -320,11 +320,12 @@ Object Protocol When *o* is non-``NULL``, returns a type object corresponding to the object type of object *o*. On failure, raises :exc:`SystemError` and returns ``NULL``. This - is equivalent to the Python expression ``type(o)``. This function increments the - reference count of the return value. There's really no reason to use this + is equivalent to the Python expression ``type(o)``. + This function creates a new :term:`strong reference` to the return value. + There's really no reason to use this function instead of the :c:func:`Py_TYPE()` function, which returns a - pointer of type :c:expr:`PyTypeObject*`, except when the incremented reference - count is needed. + pointer of type :c:expr:`PyTypeObject*`, except when a new + :term:`strong reference` is needed. .. c:function:: int PyObject_TypeCheck(PyObject *o, PyTypeObject *type) diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst index 640c5c610899f8..4ea0378d02a655 100644 --- a/Doc/c-api/refcounting.rst +++ b/Doc/c-api/refcounting.rst @@ -15,6 +15,12 @@ of Python objects. Get the reference count of the Python object *o*. + Note that the returned value may not actually reflect how many + references to the object are actually held. For example, some + objects are "immortal" and have a very high refcount that does not + reflect the actual number of references. Consequently, do not rely + on the returned value to be accurate, other than a value of 0 or 1. + Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count. .. versionchanged:: 3.11 @@ -28,36 +34,53 @@ of Python objects. Set the object *o* reference counter to *refcnt*. + Note that this function has no effect on + `immortal `_ + objects. + .. versionadded:: 3.9 + .. versionchanged:: 3.12 + Immortal objects are not modified. + .. c:function:: void Py_INCREF(PyObject *o) - Increment the reference count for object *o*. + Indicate taking a new :term:`strong reference` to object *o*, + indicating it is in use and should not be destroyed. This function is usually used to convert a :term:`borrowed reference` to a :term:`strong reference` in-place. The :c:func:`Py_NewRef` function can be used to create a new :term:`strong reference`. + When done using the object, release it by calling :c:func:`Py_DECREF`. + The object must not be ``NULL``; if you aren't sure that it isn't ``NULL``, use :c:func:`Py_XINCREF`. + Do not expect this function to actually modify *o* in any way. + For at least `some objects `_, + this function has no effect. + + .. versionchanged:: 3.12 + Immortal objects are not modified. + .. c:function:: void Py_XINCREF(PyObject *o) - Increment the reference count for object *o*. The object may be ``NULL``, in - which case the macro has no effect. + Similar to :c:func:`Py_INCREF`, but the object *o* can be ``NULL``, + in which case this has no effect. See also :c:func:`Py_XNewRef`. .. c:function:: PyObject* Py_NewRef(PyObject *o) - Create a new :term:`strong reference` to an object: increment the reference - count of the object *o* and return the object *o*. + Create a new :term:`strong reference` to an object: + call :c:func:`Py_INCREF` on *o* and return the object *o*. When the :term:`strong reference` is no longer needed, :c:func:`Py_DECREF` - should be called on it to decrement the object reference count. + should be called on it to release the reference. The object *o* must not be ``NULL``; use :c:func:`Py_XNewRef` if *o* can be ``NULL``. @@ -87,9 +110,12 @@ of Python objects. .. c:function:: void Py_DECREF(PyObject *o) - Decrement the reference count for object *o*. + Release a :term:`strong reference` to object *o*, indicating the + reference is no longer used. - If the reference count reaches zero, the object's type's deallocation + Once the last :term:`strong reference` is released + (i.e. the object's reference count reaches 0), + the object's type's deallocation function (which must not be ``NULL``) is invoked. This function is usually used to delete a :term:`strong reference` before @@ -98,6 +124,10 @@ of Python objects. The object must not be ``NULL``; if you aren't sure that it isn't ``NULL``, use :c:func:`Py_XDECREF`. + Do not expect this function to actually modify *o* in any way. + For at least `some objects `_, + this function has no effect. + .. warning:: The deallocation function can cause arbitrary Python code to be invoked (e.g. @@ -109,25 +139,29 @@ of Python objects. reference to the deleted object in a temporary variable, update the list data structure, and then call :c:func:`Py_DECREF` for the temporary variable. + .. versionchanged:: 3.12 + Immortal objects are not modified. + .. c:function:: void Py_XDECREF(PyObject *o) - Decrement the reference count for object *o*. The object may be ``NULL``, in - which case the macro has no effect; otherwise the effect is the same as for - :c:func:`Py_DECREF`, and the same warning applies. + Similar to :c:func:`Py_DECREF`, but the object *o* can be ``NULL``, + in which case this has no effect. + The same warning from :c:func:`Py_DECREF` applies here as well. .. c:function:: void Py_CLEAR(PyObject *o) - Decrement the reference count for object *o*. The object may be ``NULL``, in + Release a :term:`strong reference` for object *o*. + The object may be ``NULL``, in which case the macro has no effect; otherwise the effect is the same as for :c:func:`Py_DECREF`, except that the argument is also set to ``NULL``. The warning for :c:func:`Py_DECREF` does not apply with respect to the object passed because the macro carefully uses a temporary variable and sets the argument to ``NULL`` - before decrementing its reference count. + before releasing the reference. - It is a good idea to use this macro whenever decrementing the reference - count of an object that might be traversed during garbage collection. + It is a good idea to use this macro whenever releasing a reference + to an object that might be traversed during garbage collection. .. versionchanged:: 3.12 The macro argument is now only evaluated once. If the argument has side @@ -136,20 +170,22 @@ of Python objects. .. c:function:: void Py_IncRef(PyObject *o) - Increment the reference count for object *o*. A function version of :c:func:`Py_XINCREF`. + Indicate taking a new :term:`strong reference` to object *o*. + A function version of :c:func:`Py_XINCREF`. It can be used for runtime dynamic embedding of Python. .. c:function:: void Py_DecRef(PyObject *o) - Decrement the reference count for object *o*. A function version of :c:func:`Py_XDECREF`. + Release a :term:`strong reference` to object *o*. + A function version of :c:func:`Py_XDECREF`. It can be used for runtime dynamic embedding of Python. .. c:macro:: Py_SETREF(dst, src) - Macro safely decrementing the `dst` reference count and setting `dst` to - `src`. + Macro safely releasing a :term:`strong reference` to object *dst* + and setting *dst* to *src*. As in case of :c:func:`Py_CLEAR`, "the obvious" code can be deadly:: @@ -160,9 +196,10 @@ of Python objects. Py_SETREF(dst, src); - That arranges to set `dst` to `src` _before_ decrementing reference count of - *dst* old value, so that any code triggered as a side-effect of `dst` - getting torn down no longer believes `dst` points to a valid object. + That arranges to set *dst* to *src* _before_ releasing the reference + to the old value of *dst*, so that any code triggered as a side-effect + of *dst* getting torn down no longer believes *dst* points + to a valid object. .. versionadded:: 3.6 diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst index 1cec0666f5319b..a8a284e6e1cf95 100644 --- a/Doc/c-api/sys.rst +++ b/Doc/c-api/sys.rst @@ -8,8 +8,9 @@ Operating System Utilities .. c:function:: PyObject* PyOS_FSPath(PyObject *path) Return the file system representation for *path*. If the object is a - :class:`str` or :class:`bytes` object, then its reference count is - incremented. If the object implements the :class:`os.PathLike` interface, + :class:`str` or :class:`bytes` object, then a new + :term:`strong reference` is returned. + If the object implements the :class:`os.PathLike` interface, then :meth:`~os.PathLike.__fspath__` is returned as long as it is a :class:`str` or :class:`bytes` object. Otherwise :exc:`TypeError` is raised and ``NULL`` is returned. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 26e6133aebaa8f..221a05b1922404 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -690,7 +690,8 @@ and :c:data:`PyType_Type` effectively act as defaults.) } Finally, if the type is heap allocated (:c:macro:`Py_TPFLAGS_HEAPTYPE`), the - deallocator should decrement the reference count for its type object after + deallocator should release the owned reference to its type object + (via :c:func:`Py_DECREF`) after calling the type deallocator. In order to avoid dangling pointers, the recommended way to achieve this is: @@ -1461,9 +1462,10 @@ and :c:data:`PyType_Type` effectively act as defaults.) } The :c:func:`Py_CLEAR` macro should be used, because clearing references is - delicate: the reference to the contained object must not be decremented until + delicate: the reference to the contained object must not be released + (via :c:func:`Py_DECREF`) until after the pointer to the contained object is set to ``NULL``. This is because - decrementing the reference count may cause the contained object to become trash, + releasing the reference may cause the contained object to become trash, triggering a chain of reclamation activity that may include invoking arbitrary Python code (due to finalizers, or weakref callbacks, associated with the contained object). If it's possible for such code to reference *self* again, @@ -1541,7 +1543,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) they may be C ints or floats). The third argument specifies the requested operation, as for :c:func:`PyObject_RichCompare`. - The return value's reference count is properly incremented. + The returned value is a new :term:`strong reference`. On error, sets an exception and returns ``NULL`` from the function. diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 02f9597c345a02..586ad182e3a459 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -571,7 +571,7 @@ APIs: Copy an instance of a Unicode subtype to a new true Unicode object if necessary. If *obj* is already a true Unicode object (not a subtype), - return the reference with incremented refcount. + return a new :term:`strong reference` to the object. Objects other than Unicode or its subtypes will cause a :exc:`TypeError`. @@ -1445,11 +1445,11 @@ They all return ``NULL`` or ``-1`` if an exception occurs. Intern the argument *\*string* in place. The argument must be the address of a pointer variable pointing to a Python Unicode string object. If there is an existing interned string that is the same as *\*string*, it sets *\*string* to - it (decrementing the reference count of the old string object and incrementing - the reference count of the interned string object), otherwise it leaves - *\*string* alone and interns it (incrementing its reference count). - (Clarification: even though there is a lot of talk about reference counts, think - of this function as reference-count-neutral; you own the object after the call + it (releasing the reference to the old string object and creating a new + :term:`strong reference` to the interned string object), otherwise it leaves + *\*string* alone and interns it (creating a new :term:`strong reference`). + (Clarification: even though there is a lot of talk about references, think + of this function as reference-neutral; you own the object after the call if and only if you owned it before the call.) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 5c0f0f15217a07..f3d5c5eede9701 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -168,8 +168,9 @@ Glossary :class:`str` objects. borrowed reference - In Python's C API, a borrowed reference is a reference to an object. - It does not modify the object reference count. It becomes a dangling + In Python's C API, a borrowed reference is a reference to an object, + where the code using the object does not own the reference. + It becomes a dangling pointer if the object is destroyed. For example, a garbage collection can remove the last :term:`strong reference` to the object and so destroy it. @@ -1063,7 +1064,9 @@ Glossary reference count The number of references to an object. When the reference count of an - object drops to zero, it is deallocated. Reference counting is + object drops to zero, it is deallocated. Some objects are + "immortal" and have reference counts that are never modified, and + therefore the objects are never deallocated. Reference counting is generally not visible to Python code, but it is a key element of the :term:`CPython` implementation. Programmers can call the :func:`sys.getrefcount` function to return the @@ -1131,8 +1134,10 @@ Glossary strong reference In Python's C API, a strong reference is a reference to an object - which increments the object's reference count when it is created and - decrements the object's reference count when it is deleted. + which is owned by the code holding the reference. The strong + reference is taken by calling :c:func:`Py_INCREF` when the + reference is created and released with :c:func:`Py_DECREF` + when the reference is deleted. The :c:func:`Py_NewRef` function can be used to create a strong reference to an object. Usually, the :c:func:`Py_DECREF` function must be called on diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index a61737383e3939..33391d11ab392d 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -770,6 +770,15 @@ always available. higher than you might expect, because it includes the (temporary) reference as an argument to :func:`getrefcount`. + Note that the returned value may not actually reflect how many + references to the object are actually held. For example, some + objects are "immortal" and have a very high refcount that does not + reflect the actual number of references. Consequently, do not rely + on the returned value to be accurate, other than a value of 0 or 1. + + .. versionchanged:: 3.12 + Immortal objects have very large refcounts that do not match + the actual number of references to the object. .. function:: getrecursionlimit() From 3bb43b7b1b75154bc4e94b1fa81afe296a8150d0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 9 Aug 2023 13:26:51 +0300 Subject: [PATCH 0522/1206] [3.12] gh-106052: Fix bug in the matching of possessive quantifiers (GH-106515) (#107796) [3.12] gh-106052: Fix bug in the matching of possessive quantifiers (gh-106515) It did not work in the case of a subpattern containing backtracking. Temporary implement possessive quantifiers as equivalent greedy qualifiers in atomic groups.. (cherry picked from commit 7b6e34e5baeb4162815ffa4d943b09a58e3f6580) --- Lib/re/_compiler.py | 7 +++++++ Lib/test/test_re.py | 12 ++++++++++++ .../2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst | 2 ++ 3 files changed, 21 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index d8e0d2fdefdcca..e30740b9c30b0e 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -100,6 +100,13 @@ def _compile(code, pattern, flags): emit(ANY_ALL) else: emit(ANY) + elif op is POSSESSIVE_REPEAT: + # gh-106052: Possessive quantifiers do not work when the + # subpattern contains backtracking, i.e. "(?:ab?c)*+". + # Implement it as equivalent greedy qualifier in atomic group. + p = [(MAX_REPEAT, av)] + p = [(ATOMIC_GROUP, p)] + _compile(code, p, flags) elif op in REPEATING_CODES: if flags & SRE_FLAG_TEMPLATE: raise error("internal: unsupported template operator %r" % (op,)) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 50b9ad701f0ce7..85541f4451d031 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2365,6 +2365,16 @@ def test_template_function_and_flag_is_deprecated(self): self.assertTrue(template_re1.match('ahoy')) self.assertFalse(template_re1.match('nope')) + def test_bug_gh106052(self): + self.assertEqual(re.match("(?>(?:ab?c)+)", "aca").span(), (0, 2)) + self.assertEqual(re.match("(?:ab?c)++", "aca").span(), (0, 2)) + self.assertEqual(re.match("(?>(?:ab?c)*)", "aca").span(), (0, 2)) + self.assertEqual(re.match("(?:ab?c)*+", "aca").span(), (0, 2)) + self.assertEqual(re.match("(?>(?:ab?c)?)", "a").span(), (0, 0)) + self.assertEqual(re.match("(?:ab?c)?+", "a").span(), (0, 0)) + self.assertEqual(re.match("(?>(?:ab?c){1,3})", "aca").span(), (0, 2)) + self.assertEqual(re.match("(?:ab?c){1,3}+", "aca").span(), (0, 2)) + @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') def test_regression_gh94675(self): pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' @@ -2461,6 +2471,7 @@ def test_atomic_group(self): 17: SUCCESS ''') + @unittest.expectedFailure # gh-106052 def test_possesive_repeat_one(self): self.assertEqual(get_debug_out(r'a?+'), '''\ POSSESSIVE_REPEAT 0 1 @@ -2473,6 +2484,7 @@ def test_possesive_repeat_one(self): 12: SUCCESS ''') + @unittest.expectedFailure # gh-106052 def test_possesive_repeat(self): self.assertEqual(get_debug_out(r'(?:ab)?+'), '''\ POSSESSIVE_REPEAT 0 1 diff --git a/Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst b/Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst new file mode 100644 index 00000000000000..f2d4c2f7b18ec7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst @@ -0,0 +1,2 @@ +:mod:`re` module: fix the matching of possessive quantifiers in the case of +a subpattern containing backtracking. From a71500cd2446ac460610c8d57951d02ea37b0bb6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 10 Aug 2023 02:19:14 -0700 Subject: [PATCH 0523/1206] [3.12] gh-107814: Avoid output from Nuget installation in find_python.bat (GH-107815) (#107823) gh-107814: Avoid output from Nuget installation in find_python.bat (GH-107815) (cherry picked from commit 1e229e2c3d212accbd5fbe3a46cd42f8252b2868) Co-authored-by: Max Bachmann --- .../Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst | 1 + PCbuild/find_python.bat | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst diff --git a/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst b/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst new file mode 100644 index 00000000000000..d3723353470ce2 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst @@ -0,0 +1 @@ +When calling ``find_python.bat`` with ``-q`` it did not properly silence the output of nuget. That is now fixed. diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat index 7af5503d80a0fc..d3f62c93869003 100644 --- a/PCbuild/find_python.bat +++ b/PCbuild/find_python.bat @@ -52,7 +52,7 @@ @if "%_Py_NUGET%"=="" (set _Py_NUGET=%_Py_EXTERNALS_DIR%\nuget.exe) @if "%_Py_NUGET_URL%"=="" (set _Py_NUGET_URL=https://aka.ms/nugetclidl) @if NOT exist "%_Py_NUGET%" ( - @echo Downloading nuget... + @if not "%_Py_Quiet%"=="1" @echo Downloading nuget... @rem NB: Must use single quotes around NUGET here, NOT double! @rem Otherwise, a space in the path would break things @rem If it fails, retry with any available copy of Python @@ -63,7 +63,11 @@ ) @if not "%_Py_Quiet%"=="1" @echo Installing Python via nuget... -@"%_Py_NUGET%" install pythonx86 -ExcludeVersion -OutputDirectory "%_Py_EXTERNALS_DIR%" +@if not "%_Py_Quiet%"=="1" ( + @"%_Py_NUGET%" install pythonx86 -ExcludeVersion -OutputDirectory "%_Py_EXTERNALS_DIR%" +) else ( + @"%_Py_NUGET%" install pythonx86 -Verbosity quiet -ExcludeVersion -OutputDirectory "%_Py_EXTERNALS_DIR%" +) @rem Quote it here; it's not quoted later because "py -x.y" wouldn't work @if not errorlevel 1 (set PYTHON="%_Py_EXTERNALS_DIR%\pythonx86\tools\python.exe") & (set _Py_Python_Source=found on nuget.org) & goto :found From 7853c769067699c79c0d4fe4967e9d8f8b8b0a5e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 10 Aug 2023 02:24:22 -0700 Subject: [PATCH 0524/1206] [3.12] GH-106684: Close `asyncio.StreamWriter` when `asyncio.StreamWriter` is not closed by application (GH-107650) (#107656) GH-106684: raise `ResourceWarning` when `asyncio.StreamWriter` is not closed (GH-107650) (cherry picked from commit 41178e41995992bbe417f94bce158de93f9e3188) Co-authored-by: Kumar Aditya Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Lib/asyncio/streams.py | 4 ++++ .../Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst | 1 + 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index bf15f517e50dce..14861dffce3a84 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -392,6 +392,10 @@ async def start_tls(self, sslcontext, *, self._transport = new_transport protocol._replace_writer(self) + def __del__(self): + if not self._transport.is_closing(): + self.close() + class StreamReader: diff --git a/Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst b/Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst new file mode 100644 index 00000000000000..85bce76229853f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst @@ -0,0 +1 @@ +Close :class:`asyncio.StreamWriter` when it is not closed by application leading to memory leaks. Patch by Kumar Aditya. From ddca26188d7828ecb762213f4b9c15d44b6048cc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 11 Aug 2023 02:58:27 -0700 Subject: [PATCH 0525/1206] [3.12] GH-107724: Fix the signature of `PY_THROW` callback functions. (GH-107725) (#107802) GH-107724: Fix the signature of `PY_THROW` callback functions. (GH-107725) (cherry picked from commit 52fbcf61b5a70993c2d32332ff0ad9f369d968d3) Co-authored-by: Mark Shannon --- Include/internal/pycore_instruments.h | 4 --- Lib/test/test_monitoring.py | 32 +++++++++++++++++++ ...-08-04-21-25-26.gh-issue-107724.EbBXMr.rst | 3 ++ Python/ceval.c | 2 +- Python/instrumentation.c | 10 ------ Python/legacy_tracing.c | 6 ++-- 6 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index ccccd54a2f70a2..56de9f87171484 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -90,10 +90,6 @@ extern int _Py_call_instrumentation_2args(PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); -extern void -_Py_call_instrumentation_exc0(PyThreadState *tstate, int event, - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); - extern void _Py_call_instrumentation_exc2(PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 9d0ad6fa834bc7..4c7438992f88e5 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -743,6 +743,13 @@ class ExceptionHandledRecorder(ExceptionRecorder): def __call__(self, code, offset, exc): self.events.append(("handled", type(exc))) +class ThrowRecorder(ExceptionRecorder): + + event_type = E.PY_THROW + + def __call__(self, code, offset, exc): + self.events.append(("throw", type(exc))) + class ExceptionMonitoringTest(CheckEvents): @@ -888,6 +895,31 @@ async def async_loop(): func, recorders = self.exception_recorders) + def test_throw(self): + + def gen(): + yield 1 + yield 2 + + def func(): + try: + g = gen() + next(g) + g.throw(IndexError) + except IndexError: + pass + + self.check_balanced( + func, + recorders = self.exception_recorders) + + events = self.get_events( + func, + TEST_TOOL, + self.exception_recorders + (ThrowRecorder,) + ) + self.assertEqual(events[0], ("throw", IndexError)) + class LineRecorder: event_type = E.LINE diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst new file mode 100644 index 00000000000000..6e853cf72a3348 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst @@ -0,0 +1,3 @@ +In pre-release versions of 3.12, up to rc1, the sys.monitoring callback +function for the ``PY_THROW`` event was missing the third, exception +argument. That is now fixed. diff --git a/Python/ceval.c b/Python/ceval.c index 88d6362bf48a1f..c6f54dd24052e8 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2099,7 +2099,7 @@ monitor_throw(PyThreadState *tstate, if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_THROW)) { return; } - _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_THROW, frame, instr); + do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_THROW); } void diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 05a53d04bf3cc4..8714324e72c327 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1070,16 +1070,6 @@ call_instrumentation_vector_protected( assert(_PyErr_Occurred(tstate)); } -void -_Py_call_instrumentation_exc0( - PyThreadState *tstate, int event, - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) -{ - assert(_PyErr_Occurred(tstate)); - PyObject *args[3] = { NULL, NULL, NULL }; - call_instrumentation_vector_protected(tstate, event, frame, instr, 2, args); -} - void _Py_call_instrumentation_exc2( PyThreadState *tstate, int event, diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index c1c70f667ccd29..b0136d2ebc7554 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -163,7 +163,7 @@ sys_trace_func2( } static PyObject * -sys_trace_unwind( +sys_trace_func3( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { @@ -446,7 +446,7 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, - (vectorcallfunc)sys_trace_func2, PyTrace_CALL, + (vectorcallfunc)sys_trace_func3, PyTrace_CALL, PY_MONITORING_EVENT_PY_THROW, -1)) { return -1; } @@ -471,7 +471,7 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, - (vectorcallfunc)sys_trace_unwind, PyTrace_RETURN, + (vectorcallfunc)sys_trace_func3, PyTrace_RETURN, PY_MONITORING_EVENT_PY_UNWIND, -1)) { return -1; } From 81d3afae1ae89a302866fb0cd12dc9f722e8aa4c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 11 Aug 2023 02:58:58 -0700 Subject: [PATCH 0526/1206] [3.12] GH-107774: Add missing audit event for PEP 669 (GH-107775) (#107839) GH-107774: Add missing audit event for PEP 669 (GH-107775) (cherry picked from commit 494e3d4436774a5ac1a569a635b8c5c881ef1c0c) Co-authored-by: Mark Shannon --- Lib/test/audit-tests.py | 11 +++++++++++ Lib/test/test_audit.py | 13 +++++++++++++ .../2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst | 3 +++ Python/instrumentation.c | 3 +++ 4 files changed, 30 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 0edc9d9c472766..9504829e96f00e 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -514,6 +514,17 @@ def test_not_in_gc(): assert hook not in o +def test_sys_monitoring_register_callback(): + import sys + + def hook(event, args): + if event.startswith("sys.monitoring"): + print(event, args) + + sys.addaudithook(hook) + sys.monitoring.register_callback(1, 1, None) + + if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 0b69864751d83d..b12ffa5d872e83 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -257,5 +257,18 @@ def test_not_in_gc(self): self.fail(stderr) + def test_sys_monitoring_register_callback(self): + returncode, events, stderr = self.run_python("test_sys_monitoring_register_callback") + if returncode: + self.fail(stderr) + + if support.verbose: + print(*events, sep='\n') + actual = [(ev[0], ev[2]) for ev in events] + expected = [("sys.monitoring.register_callback", "(None,)")] + + self.assertEqual(actual, expected) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst b/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst new file mode 100644 index 00000000000000..b89b50c79f7e2a --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst @@ -0,0 +1,3 @@ +PEP 669 specifies that ``sys.monitoring.register_callback`` will generate an +audit event. Pre-releases of Python 3.12 did not generate the audit event. +This is now fixed. diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 8714324e72c327..a5b10ae63e2e6a 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1858,6 +1858,9 @@ monitoring_register_callback_impl(PyObject *module, int tool_id, int event, PyErr_Format(PyExc_ValueError, "invalid event %d", event); return NULL; } + if (PySys_Audit("sys.monitoring.register_callback", "O", func) < 0) { + return NULL; + } if (func == Py_None) { func = NULL; } From 585b4cc3bd57480f8bd04ddbc6f098e55d311582 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 11 Aug 2023 02:59:45 -0700 Subject: [PATCH 0527/1206] [3.12] Fix the long64 reader in umarshal.py (GH-107828) (#107849) Fix the long64 reader in umarshal.py (GH-107828) (cherry picked from commit 50bbc56009ae7303d2482f28eb62f2603664b58f) Co-authored-by: Martin DeMello --- Tools/build/umarshal.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tools/build/umarshal.py b/Tools/build/umarshal.py index f61570cbaff751..e05d93cf23c921 100644 --- a/Tools/build/umarshal.py +++ b/Tools/build/umarshal.py @@ -125,10 +125,10 @@ def r_long64(self) -> int: x |= buf[1] << 8 x |= buf[2] << 16 x |= buf[3] << 24 - x |= buf[1] << 32 - x |= buf[1] << 40 - x |= buf[1] << 48 - x |= buf[1] << 56 + x |= buf[4] << 32 + x |= buf[5] << 40 + x |= buf[6] << 48 + x |= buf[7] << 56 x |= -(x & (1<<63)) # Sign-extend return x From 431ce239d2a906ec4d9a27a83549258d7cef3701 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 11 Aug 2023 07:12:50 -0700 Subject: [PATCH 0528/1206] [3.12] gh-107810: Improve DeprecationWarning for metaclasses with custom tp_new (GH-107834) (#107864) gh-107810: Improve DeprecationWarning for metaclasses with custom tp_new (GH-107834) (cherry picked from commit 16dcce21768ba381996a88ac8c255bf1490b3680) Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Co-authored-by: Kirill Podoprigora --- Lib/test/test_capi/test_misc.py | 2 +- .../C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst | 1 + Objects/typeobject.c | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index cd37fc71aa966e..3f2736da7d93a4 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -740,7 +740,7 @@ class Base(metaclass=metaclass): # Class creation from C with warnings_helper.check_warnings( - ('.*custom tp_new.*in Python 3.14.*', DeprecationWarning), + ('.* _testcapi.Subclass .* custom tp_new.*in Python 3.14.*', DeprecationWarning), ): sub = _testcapi.make_type_with_base(Base) self.assertTrue(issubclass(sub, Base)) diff --git a/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst b/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst new file mode 100644 index 00000000000000..c8a1f6d122b61b --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst @@ -0,0 +1 @@ +Improve :exc:`DeprecationWarning` for uses of :c:type:`PyType_Spec` with metaclasses that have custom ``tp_new``. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 40e187d4d8d22a..5c71c28f751504 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4242,9 +4242,9 @@ _PyType_FromMetaclass_impl( if (_allow_tp_new) { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "Using PyType_Spec with metaclasses that have custom " - "tp_new is deprecated and will no longer be allowed in " - "Python 3.14.") < 0) { + "Type %s uses PyType_Spec with a metaclass that has custom " + "tp_new. This is deprecated and will no longer be allowed in " + "Python 3.14.", spec->name) < 0) { goto finally; } } From 98dd9d9725e6fa137e14f00b2907fdec19aee4ac Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 11 Aug 2023 07:13:14 -0700 Subject: [PATCH 0529/1206] [3.12] gh-91054: make code watcher tests resilient to other watchers (GH-107821) (#107835) gh-91054: make code watcher tests resilient to other watchers (GH-107821) (cherry picked from commit 2ec16fed14aae896e38dd5bd9e73e2eddc974439) Co-authored-by: Carl Meyer --- Modules/_testcapi/watchers.c | 14 +++++++++++--- Tools/c-analyzer/cpython/ignored.tsv | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index 7167943fffab39..fd695df7490705 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -295,6 +295,7 @@ _testcapi_unwatch_type_impl(PyObject *module, int watcher_id, PyObject *type) // Test code object watching #define NUM_CODE_WATCHERS 2 +static int code_watcher_ids[NUM_CODE_WATCHERS] = {-1, -1}; static int num_code_object_created_events[NUM_CODE_WATCHERS] = {0, 0}; static int num_code_object_destroyed_events[NUM_CODE_WATCHERS] = {0, 0}; @@ -345,11 +346,13 @@ add_code_watcher(PyObject *self, PyObject *which_watcher) long which_l = PyLong_AsLong(which_watcher); if (which_l == 0) { watcher_id = PyCode_AddWatcher(first_code_object_callback); + code_watcher_ids[0] = watcher_id; num_code_object_created_events[0] = 0; num_code_object_destroyed_events[0] = 0; } else if (which_l == 1) { watcher_id = PyCode_AddWatcher(second_code_object_callback); + code_watcher_ids[1] = watcher_id; num_code_object_created_events[1] = 0; num_code_object_destroyed_events[1] = 0; } @@ -375,9 +378,14 @@ clear_code_watcher(PyObject *self, PyObject *watcher_id) return NULL; } // reset static events counters - if (watcher_id_l >= 0 && watcher_id_l < NUM_CODE_WATCHERS) { - num_code_object_created_events[watcher_id_l] = 0; - num_code_object_destroyed_events[watcher_id_l] = 0; + if (watcher_id_l >= 0) { + for (int i = 0; i < NUM_CODE_WATCHERS; i++) { + if (watcher_id_l == code_watcher_ids[i]) { + code_watcher_ids[i] = -1; + num_code_object_created_events[i] = 0; + num_code_object_destroyed_events[i] = 0; + } + } } Py_RETURN_NONE; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 78be97da41b503..6a7c14ebb220a8 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -426,6 +426,7 @@ Modules/_testcapi/watchers.c - g_dict_watch_events - Modules/_testcapi/watchers.c - g_dict_watchers_installed - Modules/_testcapi/watchers.c - g_type_modified_events - Modules/_testcapi/watchers.c - g_type_watchers_installed - +Modules/_testcapi/watchers.c - code_watcher_ids - Modules/_testcapi/watchers.c - num_code_object_created_events - Modules/_testcapi/watchers.c - num_code_object_destroyed_events - Modules/_testcapi/watchers.c - pyfunc_watchers - From d20d52bc4d9910666706ea1fb4ca790f87acd06e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 11 Aug 2023 13:29:57 -0700 Subject: [PATCH 0530/1206] [3.12] Docs: Document PyBUF_MAX_NDIM (GH-107865) (#107871) Docs: Document PyBUF_MAX_NDIM (GH-107865) (cherry picked from commit 637f7ff2c60f262659da0334f1cb672bd361f398) Co-authored-by: Erlend E. Aasland --- Doc/c-api/buffer.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 8ca1c190dab9a9..ba391a5279f205 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -161,10 +161,14 @@ a buffer, see :c:func:`PyObject_GetBuffer`. If it is ``0``, :c:member:`~Py_buffer.buf` points to a single item representing a scalar. In this case, :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides` and :c:member:`~Py_buffer.suboffsets` MUST be ``NULL``. + The maximum number of dimensions is given by :c:macro:`PyBUF_MAX_NDIM`. - The macro :c:macro:`PyBUF_MAX_NDIM` limits the maximum number of dimensions - to 64. Exporters MUST respect this limit, consumers of multi-dimensional - buffers SHOULD be able to handle up to :c:macro:`PyBUF_MAX_NDIM` dimensions. + .. :c:macro:: PyBUF_MAX_NDIM + + The maximum number of dimensions the memory represents. + Exporters MUST respect this limit, consumers of multi-dimensional + buffers SHOULD be able to handle up to :c:macro:`!PyBUF_MAX_NDIM` dimensions. + Currently set to 64. .. c:member:: Py_ssize_t *shape From 39ce30dd3ed13e5ce275d1aaa9ee1d8c5ba62f17 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 14 Aug 2023 05:39:30 -0700 Subject: [PATCH 0531/1206] [3.12] gh-107891: Fix typo in 3.12 whatsnew (GH-107892) (#107893) gh-107891: Fix typo in 3.12 whatsnew (GH-107892) (cherry picked from commit 2e1f688fe0f0a612e54c09f5a7027a834dd8b8d5) Co-authored-by: wookie184 --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 79e618588143a8..bf9eadcaefc853 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1576,7 +1576,7 @@ Changes in the Python API 1,13-1,17: FSTRING_MIDDLE ' end' 1,17-1,18: FSTRING_END '"' - Additionally, there may be some minor behavioral changes as a consecuence of the + Additionally, there may be some minor behavioral changes as a consequence of the changes required to support :pep:`701`. Some of these changes include: * The ``type`` attribute of the tokens emitted when tokenizing some invalid Python From ba8ab4e8aecfb5b34b591bf93bd1b31f62b6e0a3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 14 Aug 2023 05:40:47 -0700 Subject: [PATCH 0532/1206] [3.12] gh-107877: Update logging levels reference table with usage criteria. (GH-107894) (#107922) gh-107877: Update logging levels reference table with usage criteria. (GH-107894) (cherry picked from commit cc2cf85d03cf29994a707aae5cc9a349a4165b84) Co-authored-by: Vinay Sajip Co-authored-by: Alex Waygood --- Doc/library/logging.rst | 48 ++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 70a9c8b9aa86e3..a92ef1787af744 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -397,21 +397,39 @@ have specific values relative to the predefined levels. If you define a level with the same numeric value, it overwrites the predefined value; the predefined name is lost. -+-----------------------+---------------+ -| Level | Numeric value | -+=======================+===============+ -| .. py:data:: CRITICAL | 50 | -+-----------------------+---------------+ -| .. py:data:: ERROR | 40 | -+-----------------------+---------------+ -| .. py:data:: WARNING | 30 | -+-----------------------+---------------+ -| .. py:data:: INFO | 20 | -+-----------------------+---------------+ -| .. py:data:: DEBUG | 10 | -+-----------------------+---------------+ -| .. py:data:: NOTSET | 0 | -+-----------------------+---------------+ ++-----------------------+---------------+-------------------------------------+ +| Level | Numeric value | What it means / When to use it | ++=======================+===============+=====================================+ +| .. py:data:: NOTSET | 0 | When set on a logger, indicates that| +| | | ancestor loggers are to be consulted| +| | | to determine the effective level. | +| | | If that still resolves to | +| | | :const:`!NOTSET`, then all events | +| | | are logged. When set on a handler, | +| | | all events are handled. | ++-----------------------+---------------+-------------------------------------+ +| .. py:data:: DEBUG | 10 | Detailed information, typically only| +| | | of interest to a developer trying to| +| | | diagnose a problem. | ++-----------------------+---------------+-------------------------------------+ +| .. py:data:: INFO | 20 | Confirmation that things are working| +| | | as expected. | ++-----------------------+---------------+-------------------------------------+ +| .. py:data:: WARNING | 30 | An indication that something | +| | | unexpected happened, or that a | +| | | problem might occur in the near | +| | | future (e.g. 'disk space low'). The | +| | | software is still working as | +| | | expected. | ++-----------------------+---------------+-------------------------------------+ +| .. py:data:: ERROR | 40 | Due to a more serious problem, the | +| | | software has not been able to | +| | | perform some function. | ++-----------------------+---------------+-------------------------------------+ +| .. py:data:: CRITICAL | 50 | A serious error, indicating that the| +| | | program itself may be unable to | +| | | continue running. | ++-----------------------+---------------+-------------------------------------+ .. _handler: From e8963a86ead0f5516948b3ad55b410b7fc5fb194 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 14 Aug 2023 07:58:54 -0700 Subject: [PATCH 0533/1206] [3.12] Add another example to the statistics docs (GH-107904) (#107941) Add another example to the statistics docs (GH-107904) (cherry picked from commit 2b6dc2accc315ce279d259ed39e058a225068531) Co-authored-by: Raymond Hettinger --- Doc/library/kde_example.png | Bin 0 -> 332212 bytes Doc/library/statistics.rst | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 Doc/library/kde_example.png diff --git a/Doc/library/kde_example.png b/Doc/library/kde_example.png new file mode 100644 index 0000000000000000000000000000000000000000..f45048956999741a6889bdfe85c40e1f25e8863b GIT binary patch literal 332212 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

8n%mVi2eOhS-hCgq(LM(4 z{=(b6U%Q52dZR5J;g=*&M9!)<0i^qNClzp;jZfl=bcQZv9;P<)v;^upT|5gkFsFZf@qDdRH#VkcD!YQlz2}GB1$~h1Czxr!4mW4Ue=ovFuPOj zmm3|G_t^yeac9-RJW>kYJt*bATSl!$n%Xo}uSOQ6!CxJZnX(On2()M@Ta6@8neThTMdlv3sM-qXmAy~-Lz zcE)}TWB7&aV~y-Ch-l6W@Lc>4J+uuKcKe=ScI2sAmcpznGZjmsNScpfM1_+hEFMiF zjUQIc?@y+AnydM&z*uxa6F#xUqB_|7R%OE*%zJj`r8<_ZT~NuUm|{dYF}xFYVSKqi zD~qYf3l?YGJLt?d+D7wnTjT*`B*Y{0pAanm(45$i!|3Cbrk(JKe=6jDl^X138*%hzK_GA+*Q0At@D}4aamn6cO#th~|%rqv>29^{@r;x@Zt@%U3X? z)ID83oZrJgYUhaRHelMeD<(y0tCZkRC=eA6I%G>Wn*BjmmTWMM;pIQvmk1lG?<4H z3Y?vfJ1L(7Ef8iLp_7ep+l)lxkp3sqotqJ>e<*oV@Ng-~gDZ7@iG2_AN0cHlFn?u4 z*)Y68?jVbdQsMqE;8&Tq=2a*X-H8yuUzXV@v%p+^#;^S`*PCZsyONGF^1^1x2)t=E zvpt60kn>JuwDSmBt`E5;lfwLv{6V(1G!NCD^8hnOydnSO;M5n#Y*6G{5z2IG-AHEf zR_g4s&grYhCHGn>g_%?`CGBC|bptGGatYdvIMkw< zW{H~b9gyZK(XG+D5Fbj{Xu1j%HXKU0Rr^N2a!jg-@aiwNQ-PxI^l6@uLf7HbxXdz4 zyi(1OQOHd9>SRf+rrf$R-WgDO$h6pd5z1^UWzVx6ZQiySx1Bv%u1Yae{*)@hUzrSa z^x4=To24 zexoYX`1cgpvx#fu+&T0+o_MAB2*HKhYjQ%po{-3wIY+aoa4U;cg0k>2P`THIF z@jbqW?XGD3Pnuy@#cl+~m=aP8KfwYTTLsyCIcP72-wA;_no)sqc~P&^={z>^CL2nd zp(+FC9H{4n8BRC$ilgfzN@wdkg%mRKdsvmoU2fT40uxj5VOLLgna5;F_a<5GVHoaH zPwHO)4H$ESM#qUTRx3Rp|Jji?*gLR#2is@E!8QU`t>4#+ESf0*=nXeO4$9%k;o1

=5qOU_mY@D;PZz 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 z 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

38N0i! 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 and `deciles >>> list(map(round, sat.quantiles(n=10))) [810, 896, 958, 1011, 1060, 1109, 1162, 1224, 1310] + +Monte Carlo inputs for simulations +********************************** + To estimate the distribution for a model than isn't easy to solve analytically, :class:`NormalDist` can generate input samples for a `Monte Carlo simulation `_: @@ -963,6 +971,9 @@ Carlo simulation `_: >>> quantiles(map(model, X, Y, Z)) # doctest: +SKIP [1.4591308524824727, 1.8035946855390597, 2.175091447274739] +Approximating binomial distributions +************************************ + Normal distributions can be used to approximate `Binomial distributions `_ when the sample size is large and when the probability of a successful @@ -1000,6 +1011,10 @@ probability that the Python room will stay within its capacity limits? >>> mean(trial() <= k for i in range(10_000)) 0.8398 + +Naive bayesian classifier +************************* + Normal distributions commonly arise in machine learning problems. Wikipedia has a `nice example of a Naive Bayesian Classifier @@ -1054,6 +1069,48 @@ The final prediction goes to the largest posterior. This is known as the 'female' +Kernel density estimation +************************* + +It is possible to estimate a continuous probability density function +from a fixed number of discrete samples. + +The basic idea is to smooth the data using `a kernel function such as a +normal distribution, triangular distribution, or uniform distribution +`_. +The degree of smoothing is controlled by a single +parameter, ``h``, representing the variance of the kernel function. + +.. testcode:: + + import math + + def kde_normal(sample, h): + "Create a continous probability density function from a sample." + # Smooth the sample with a normal distribution of variance h. + kernel_h = NormalDist(0.0, math.sqrt(h)).pdf + n = len(sample) + def pdf(x): + return sum(kernel_h(x - x_i) for x_i in sample) / n + return pdf + +`Wikipedia has an example +`_ +where we can use the ``kde_normal()`` recipe to generate and plot +a probability density function estimated from a small sample: + +.. doctest:: + + >>> sample = [-2.1, -1.3, -0.4, 1.9, 5.1, 6.2] + >>> f_hat = kde_normal(sample, h=2.25) + >>> xarr = [i/100 for i in range(-750, 1100)] + >>> yarr = [f_hat(x) for x in xarr] + +The points in ``xarr`` and ``yarr`` can be used to make a PDF plot: + +.. image:: kde_example.png + :alt: Scatter plot of the estimated probability density function. + .. # This modelines must appear within the last ten lines of the file. kate: indent-width 3; remove-trailing-space on; replace-tabs on; encoding utf-8; From d189480942348aab345500ac9204965f67f30210 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 15 Aug 2023 05:41:55 -0700 Subject: [PATCH 0534/1206] [3.12] gh-107967: Fix infinite recursion on invalid escape sequence warning (GH-107968) (#107970) gh-107967: Fix infinite recursion on invalid escape sequence warning (GH-107968) (cherry picked from commit d66bc9e8a7a8d6774d912a4b9d151885c4d8de1d) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_fstring.py | 10 ++++++++++ Parser/tokenizer.c | 3 +++ 2 files changed, 13 insertions(+) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index cb14bba2602def..16f01973f99f3e 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1673,5 +1673,15 @@ def test_debug_in_file(self): self.assertEqual(stdout.decode('utf-8').strip().replace('\r\n', '\n').replace('\r', '\n'), "3\n=3") + def test_syntax_warning_infinite_recursion_in_file(self): + with temp_cwd(): + script = 'script.py' + with open(script, 'w') as f: + f.write(r"print(f'\{1}')") + + _, stdout, stderr = assert_python_ok(script) + self.assertIn(rb'\1', stdout) + self.assertEqual(len(stderr.strip().splitlines()), 2) + if __name__ == '__main__': unittest.main() diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 7e246d2f56481c..c4c345e4c358e5 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1544,6 +1544,9 @@ parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...) static int warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_char) { + if (!tok->report_warnings) { + return 0; + } PyObject *msg = PyUnicode_FromFormat( "invalid escape sequence '\\%c'", From f0a583b6fbc9a4b2f9358c8426110a5c1f7948a3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 15 Aug 2023 07:56:53 -0700 Subject: [PATCH 0535/1206] [3.12] gh-107963: Fix set_forkserver_preload to check the type of given list (GH-107965) (#107975) gh-107963: Fix set_forkserver_preload to check the type of given list (GH-107965) (cherry picked from commit 6515ec3d3d5acd3d0b99c88794bdec09f0831e5b) gh-107963: Fix set_forkserver_preload to check the type of given list Co-authored-by: Dong-hee Na --- Lib/multiprocessing/forkserver.py | 2 +- Lib/test/_test_multiprocessing.py | 8 ++++++++ .../2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py index 22a911a7a29cdc..4642707dae2f4e 100644 --- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -61,7 +61,7 @@ def _stop_unlocked(self): def set_forkserver_preload(self, modules_names): '''Set list of module names to try to load in forkserver process.''' - if not all(type(mod) is str for mod in self._preload_modules): + if not all(type(mod) is str for mod in modules_names): raise TypeError('module_names must be a list of strings') self._preload_modules = modules_names diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index c13b049645ac90..4afbe172a1eefa 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5331,6 +5331,14 @@ def test_context(self): self.assertRaises(ValueError, ctx.set_start_method, None) self.check_context(ctx) + def test_context_check_module_types(self): + try: + ctx = multiprocessing.get_context('forkserver') + except ValueError: + raise unittest.SkipTest('forkserver should be available') + with self.assertRaisesRegex(TypeError, 'module_names must be a list of strings'): + ctx.set_forkserver_preload([1, 2, 3]) + def test_set_get(self): multiprocessing.set_forkserver_preload(PRELOAD) count = 0 diff --git a/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst b/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst new file mode 100644 index 00000000000000..3a73b2da0c4334 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst @@ -0,0 +1,2 @@ +Fix :func:`multiprocessing.set_forkserver_preload` to check the given list +of modules names. Patch by Dong-hee Na. From 00bfed7cba3f2d66a1534f9f088ddf68abbf0d3f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 02:58:54 -0700 Subject: [PATCH 0536/1206] [3.12] gh-91051: fix segfault when using all 8 type watchers (GH-107853) (#107876) * gh-91051: fix segfault when using all 8 type watchers (GH-107853) (cherry picked from commit 66e4edd7346b1cd65ddff6da890a0d725e325116) Co-authored-by: Carl Meyer --- Doc/c-api/typeobj.rst | 4 +- Doc/data/python3.12.abi | 52921 ++++++++-------- Doc/includes/typestruct.h | 2 +- Include/cpython/object.h | 2 +- Lib/test/test_capi/test_watchers.py | 12 + ...3-08-10-17-36-27.gh-issue-91051.LfaeNW.rst | 2 + 6 files changed, 26475 insertions(+), 26468 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 221a05b1922404..faa183e27fcfa2 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -147,7 +147,7 @@ Quick Reference +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ | :c:member:`~PyTypeObject.tp_vectorcall` | :c:type:`vectorcallfunc` | | | | | | +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ - | [:c:member:`~PyTypeObject.tp_watched`] | char | | | | | | + | [:c:member:`~PyTypeObject.tp_watched`] | unsigned char | | | | | | +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ .. [#slots] @@ -2141,7 +2141,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) .. versionadded:: 3.9 (the field exists since 3.8 but it's only used since 3.9) -.. c:member:: char PyTypeObject.tp_watched +.. c:member:: unsigned char PyTypeObject.tp_watched Internal. Do not use. diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index 5eec83faf1679b..cdefda782b9c6f 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -1,26464 +1,26457 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h index f0ad1e47cb0d86..ec939c28831c33 100644 --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -82,5 +82,5 @@ typedef struct _typeobject { vectorcallfunc tp_vectorcall; /* bitset of which type-watchers care about this type */ - char tp_watched; + unsigned char tp_watched; } PyTypeObject; diff --git a/Include/cpython/object.h b/Include/cpython/object.h index c5d0851a4b11bf..ae7f780a93182a 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -227,7 +227,7 @@ struct _typeobject { vectorcallfunc tp_vectorcall; /* bitset of which type-watchers care about this type */ - char tp_watched; + unsigned char tp_watched; }; /* This struct is used by the specializer diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py index 93f6ef752d0663..10b76e163bfb21 100644 --- a/Lib/test/test_capi/test_watchers.py +++ b/Lib/test/test_capi/test_watchers.py @@ -294,6 +294,18 @@ class C2: pass C2.hmm = "baz" self.assert_events([C1, [C2]]) + def test_all_watchers(self): + class C: pass + with ExitStack() as stack: + last_wid = -1 + # don't make assumptions about how many watchers are already + # registered, just go until we reach the max ID + while last_wid < self.TYPE_MAX_WATCHERS - 1: + last_wid = stack.enter_context(self.watcher()) + self.watch(last_wid, C) + C.foo = "bar" + self.assert_events([C]) + def test_watch_non_type(self): with self.watcher() as wid: with self.assertRaisesRegex(ValueError, r"Cannot watch non-type"): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst new file mode 100644 index 00000000000000..b4b90ad4ea0ecc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst @@ -0,0 +1,2 @@ +Fix abort / segfault when using all eight type watcher slots, on platforms +where ``char`` is signed by default. From bd2ef82a5010985abdeef2ca71bcbcc9a366993b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 16 Aug 2023 13:00:55 +0300 Subject: [PATCH 0537/1206] [3.12] gh-100061: Proper fix of the bug in the matching of possessive quantifiers (GH-102612) (#108003) Restore the global Input Stream pointer after trying to match a sub-pattern. . (cherry picked from commit abd9cc52d94b8e2835322b62c29f09bb0e6fcfe9) Co-authored-by: SKO <41810398+uyw4687@users.noreply.github.com> --- Lib/re/_compiler.py | 7 ------- Lib/test/test_re.py | 12 ++++++++++-- .../2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst | 2 ++ Modules/_sre/sre_lib.h | 4 ++++ 4 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index e30740b9c30b0e..d8e0d2fdefdcca 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -100,13 +100,6 @@ def _compile(code, pattern, flags): emit(ANY_ALL) else: emit(ANY) - elif op is POSSESSIVE_REPEAT: - # gh-106052: Possessive quantifiers do not work when the - # subpattern contains backtracking, i.e. "(?:ab?c)*+". - # Implement it as equivalent greedy qualifier in atomic group. - p = [(MAX_REPEAT, av)] - p = [(ATOMIC_GROUP, p)] - _compile(code, p, flags) elif op in REPEATING_CODES: if flags & SRE_FLAG_TEMPLATE: raise error("internal: unsupported template operator %r" % (op,)) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 85541f4451d031..5a5de523eba052 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2366,6 +2366,16 @@ def test_template_function_and_flag_is_deprecated(self): self.assertFalse(template_re1.match('nope')) def test_bug_gh106052(self): + # gh-100061 + self.assertEqual(re.match('(?>(?:.(?!D))+)', 'ABCDE').span(), (0, 2)) + self.assertEqual(re.match('(?:.(?!D))++', 'ABCDE').span(), (0, 2)) + self.assertEqual(re.match('(?>(?:.(?!D))*)', 'ABCDE').span(), (0, 2)) + self.assertEqual(re.match('(?:.(?!D))*+', 'ABCDE').span(), (0, 2)) + self.assertEqual(re.match('(?>(?:.(?!D))?)', 'CDE').span(), (0, 0)) + self.assertEqual(re.match('(?:.(?!D))?+', 'CDE').span(), (0, 0)) + self.assertEqual(re.match('(?>(?:.(?!D)){1,3})', 'ABCDE').span(), (0, 2)) + self.assertEqual(re.match('(?:.(?!D)){1,3}+', 'ABCDE').span(), (0, 2)) + # gh-106052 self.assertEqual(re.match("(?>(?:ab?c)+)", "aca").span(), (0, 2)) self.assertEqual(re.match("(?:ab?c)++", "aca").span(), (0, 2)) self.assertEqual(re.match("(?>(?:ab?c)*)", "aca").span(), (0, 2)) @@ -2471,7 +2481,6 @@ def test_atomic_group(self): 17: SUCCESS ''') - @unittest.expectedFailure # gh-106052 def test_possesive_repeat_one(self): self.assertEqual(get_debug_out(r'a?+'), '''\ POSSESSIVE_REPEAT 0 1 @@ -2484,7 +2493,6 @@ def test_possesive_repeat_one(self): 12: SUCCESS ''') - @unittest.expectedFailure # gh-106052 def test_possesive_repeat(self): self.assertEqual(get_debug_out(r'(?:ab)?+'), '''\ POSSESSIVE_REPEAT 0 1 diff --git a/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst b/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst new file mode 100644 index 00000000000000..dfed34f6ae9768 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst @@ -0,0 +1,2 @@ +Fix a bug that causes wrong matches for regular expressions with possessive +qualifier. diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h index fb4c18b63d643d..e83149825e2cdb 100644 --- a/Modules/_sre/sre_lib.h +++ b/Modules/_sre/sre_lib.h @@ -1334,6 +1334,10 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) MARK_POP(ctx->lastmark); LASTMARK_RESTORE(); + /* Restore the global Input Stream pointer + since it can change after jumps. */ + state->ptr = ptr; + /* We have sufficient matches, so exit loop. */ break; } From aa9707dda9f8dcbe2ada8d8a7280f0f6a8229c59 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 16 Aug 2023 04:03:05 -0600 Subject: [PATCH 0538/1206] [3.12] gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated Subinterpreters (#107751) * Unrevert "[3.12] gh-107080: Fix Py_TRACE_REFS Crashes Under Isolated Subinterpreters (gh-107567) (#107599)". This reverts commit 6e4eec760648a71e1cd8f8f551997b1823b4bb9f (gh-107648). * Initialize each interpreter's refchain properly. * Skip test_basic_multiple_interpreters_deleted_no_reset on tracerefs builds. --- Include/internal/pycore_object.h | 5 +- Include/internal/pycore_object_state.h | 13 +++- Include/internal/pycore_runtime_init.h | 11 +++ Lib/test/test_import/__init__.py | 6 ++ ...-08-02-12-24-51.gh-issue-107080.PNolFU.rst | 4 + Objects/object.c | 73 ++++++++++++++----- Python/pylifecycle.c | 10 ++- Python/pystate.c | 1 + 8 files changed, 93 insertions(+), 30 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 0981d1122fec54..7a2f13a21bda76 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -152,6 +152,7 @@ _PyType_HasFeature(PyTypeObject *type, unsigned long feature) { extern void _PyType_InitCache(PyInterpreterState *interp); +extern void _PyObject_InitState(PyInterpreterState *interp); /* Inline functions trading binary compatibility for speed: _PyObject_Init() is the fast version of PyObject_Init(), and @@ -271,8 +272,8 @@ extern void _PyDebug_PrintTotalRefs(void); #ifdef Py_TRACE_REFS extern void _Py_AddToAllObjects(PyObject *op, int force); -extern void _Py_PrintReferences(FILE *); -extern void _Py_PrintReferenceAddresses(FILE *); +extern void _Py_PrintReferences(PyInterpreterState *, FILE *); +extern void _Py_PrintReferenceAddresses(PyInterpreterState *, FILE *); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h index 94005d77881432..65feb5af969f8b 100644 --- a/Include/internal/pycore_object_state.h +++ b/Include/internal/pycore_object_state.h @@ -11,17 +11,22 @@ extern "C" { struct _py_object_runtime_state { #ifdef Py_REF_DEBUG Py_ssize_t interpreter_leaks; -#else - int _not_used; #endif + int _not_used; }; struct _py_object_state { #ifdef Py_REF_DEBUG Py_ssize_t reftotal; -#else - int _not_used; #endif +#ifdef Py_TRACE_REFS + /* Head of circular doubly-linked list of all objects. These are linked + * together via the _ob_prev and _ob_next members of a PyObject, which + * exist only in a Py_TRACE_REFS build. + */ + PyObject refchain; +#endif + int _not_used; }; diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 4130188079cffa..7aace9f86119c4 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -101,6 +101,7 @@ extern PyTypeObject _PyExc_MemoryError; { .threshold = 10, }, \ }, \ }, \ + .object_state = _py_object_state_INIT(INTERP), \ .dtoa = _dtoa_state_INIT(&(INTERP)), \ .dict_state = _dict_state_INIT, \ .func_state = { \ @@ -130,6 +131,16 @@ extern PyTypeObject _PyExc_MemoryError; .context_ver = 1, \ } +#ifdef Py_TRACE_REFS +# define _py_object_state_INIT(INTERP) \ + { \ + .refchain = {&INTERP.object_state.refchain, &INTERP.object_state.refchain}, \ + } +#else +# define _py_object_state_INIT(INTERP) \ + { 0 } +#endif + // global objects diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 06adf01f18c0a4..f7df6d7e42319f 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -2539,6 +2539,12 @@ def test_basic_multiple_interpreters_main_no_reset(self): def test_basic_multiple_interpreters_deleted_no_reset(self): # without resetting; already loaded in a deleted interpreter + if hasattr(sys, 'getobjects'): + # It's a Py_TRACE_REFS build. + # This test breaks interpreter isolation a little, + # which causes problems on Py_TRACE_REF builds. + raise unittest.SkipTest('crashes on Py_TRACE_REFS builds') + # At this point: # * alive in 0 interpreters # * module def may or may not be loaded already diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst new file mode 100644 index 00000000000000..5084c854360e35 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst @@ -0,0 +1,4 @@ +Trace refs builds (``--with-trace-refs``) were crashing when used with +isolated subinterpreters. The problematic global state has been isolated to +each interpreter. Other fixing the crashes, this change does not affect +users. diff --git a/Objects/object.c b/Objects/object.c index bd0fa40bd2a851..8a4010fb13669b 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -158,11 +158,16 @@ _PyDebug_PrintTotalRefs(void) { Do not call them otherwise, they do not initialize the object! */ #ifdef Py_TRACE_REFS -/* Head of circular doubly-linked list of all objects. These are linked - * together via the _ob_prev and _ob_next members of a PyObject, which - * exist only in a Py_TRACE_REFS build. - */ -static PyObject refchain = {&refchain, &refchain}; + +#define REFCHAIN(interp) &interp->object_state.refchain + +static inline void +init_refchain(PyInterpreterState *interp) +{ + PyObject *refchain = REFCHAIN(interp); + refchain->_ob_prev = refchain; + refchain->_ob_next = refchain; +} /* Insert op at the front of the list of all objects. If force is true, * op is added even if _ob_prev and _ob_next are non-NULL already. If @@ -187,10 +192,11 @@ _Py_AddToAllObjects(PyObject *op, int force) } #endif if (force || op->_ob_prev == NULL) { - op->_ob_next = refchain._ob_next; - op->_ob_prev = &refchain; - refchain._ob_next->_ob_prev = op; - refchain._ob_next = op; + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); + op->_ob_next = refchain->_ob_next; + op->_ob_prev = refchain; + refchain->_ob_next->_ob_prev = op; + refchain->_ob_next = op; } } #endif /* Py_TRACE_REFS */ @@ -1998,6 +2004,18 @@ PyObject _Py_NotImplementedStruct = { &_PyNotImplemented_Type }; + +void +_PyObject_InitState(PyInterpreterState *interp) +{ +#ifdef Py_TRACE_REFS + if (!_Py_IsMainInterpreter(interp)) { + init_refchain(interp); + } +#endif +} + + extern PyTypeObject _Py_GenericAliasIterType; extern PyTypeObject _PyMemoryIter_Type; extern PyTypeObject _PyLineIterator; @@ -2206,7 +2224,8 @@ _Py_ForgetReference(PyObject *op) _PyObject_ASSERT_FAILED_MSG(op, "negative refcnt"); } - if (op == &refchain || + PyObject *refchain = REFCHAIN(_PyInterpreterState_GET()); + if (op == refchain || op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) { _PyObject_ASSERT_FAILED_MSG(op, "invalid object chain"); @@ -2214,12 +2233,12 @@ _Py_ForgetReference(PyObject *op) #ifdef SLOW_UNREF_CHECK PyObject *p; - for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { + for (p = refchain->_ob_next; p != refchain; p = p->_ob_next) { if (p == op) { break; } } - if (p == &refchain) { + if (p == refchain) { /* Not found */ _PyObject_ASSERT_FAILED_MSG(op, "object not found in the objects list"); @@ -2235,11 +2254,15 @@ _Py_ForgetReference(PyObject *op) * interpreter must be in a healthy state. */ void -_Py_PrintReferences(FILE *fp) +_Py_PrintReferences(PyInterpreterState *interp, FILE *fp) { PyObject *op; + if (interp == NULL) { + interp = _PyInterpreterState_Main(); + } fprintf(fp, "Remaining objects:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { + PyObject *refchain = REFCHAIN(interp); + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) { fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op)); if (PyObject_Print(op, fp, 0) != 0) { PyErr_Clear(); @@ -2251,34 +2274,42 @@ _Py_PrintReferences(FILE *fp) /* Print the addresses of all live objects. Unlike _Py_PrintReferences, this * doesn't make any calls to the Python C API, so is always safe to call. */ +// XXX This function is not safe to use if the interpreter has been +// freed or is in an unhealthy state (e.g. late in finalization). +// The call in Py_FinalizeEx() is okay since the main interpreter +// is statically allocated. void -_Py_PrintReferenceAddresses(FILE *fp) +_Py_PrintReferenceAddresses(PyInterpreterState *interp, FILE *fp) { PyObject *op; + PyObject *refchain = REFCHAIN(interp); fprintf(fp, "Remaining object addresses:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) + for (op = refchain->_ob_next; op != refchain; op = op->_ob_next) fprintf(fp, "%p [%zd] %s\n", (void *)op, Py_REFCNT(op), Py_TYPE(op)->tp_name); } +/* The implementation of sys.getobjects(). */ PyObject * _Py_GetObjects(PyObject *self, PyObject *args) { int i, n; PyObject *t = NULL; PyObject *res, *op; + PyInterpreterState *interp = _PyInterpreterState_GET(); if (!PyArg_ParseTuple(args, "i|O", &n, &t)) return NULL; - op = refchain._ob_next; + PyObject *refchain = REFCHAIN(interp); + op = refchain->_ob_next; res = PyList_New(0); if (res == NULL) return NULL; - for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { + for (i = 0; (n == 0 || i < n) && op != refchain; i++) { while (op == self || op == args || op == res || op == t || (t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) { op = op->_ob_next; - if (op == &refchain) + if (op == refchain) return res; } if (PyList_Append(res, op) < 0) { @@ -2290,7 +2321,9 @@ _Py_GetObjects(PyObject *self, PyObject *args) return res; } -#endif +#undef REFCHAIN + +#endif /* Py_TRACE_REFS */ /* Hack to force loading of abstract.o */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index a67fa26b372278..29771e07ae6a2c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1920,11 +1920,11 @@ Py_FinalizeEx(void) } if (dump_refs) { - _Py_PrintReferences(stderr); + _Py_PrintReferences(tstate->interp, stderr); } if (dump_refs_fp != NULL) { - _Py_PrintReferences(dump_refs_fp); + _Py_PrintReferences(tstate->interp, dump_refs_fp); } #endif /* Py_TRACE_REFS */ @@ -1960,11 +1960,11 @@ Py_FinalizeEx(void) */ if (dump_refs) { - _Py_PrintReferenceAddresses(stderr); + _Py_PrintReferenceAddresses(tstate->interp, stderr); } if (dump_refs_fp != NULL) { - _Py_PrintReferenceAddresses(dump_refs_fp); + _Py_PrintReferenceAddresses(tstate->interp, dump_refs_fp); fclose(dump_refs_fp); } #endif /* Py_TRACE_REFS */ @@ -2074,6 +2074,8 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) } has_gil = 1; + /* No objects have been created yet. */ + status = pycore_interp_init(tstate); if (_PyStatus_EXCEPTION(status)) { goto error; diff --git a/Python/pystate.c b/Python/pystate.c index 8097124965cb7c..2ee16e3de25da3 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -673,6 +673,7 @@ init_interpreter(PyInterpreterState *interp, _obmalloc_pools_INIT(interp->obmalloc.pools); memcpy(&interp->obmalloc.pools.used, temp, sizeof(temp)); } + _PyObject_InitState(interp); _PyEval_InitState(interp, pending_lock); _PyGC_InitState(&interp->gc); From b5176a86bd2587856f88aec3958ad8caef7b11fc Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 16 Aug 2023 13:10:42 +0300 Subject: [PATCH 0539/1206] [3.12] gh-106844: Fix issues in _winapi.LCMapStringEx (GH-107832) (#107874) * Strings with length from 2**31-1 to 2**32-2 always caused MemoryError, it doesn't matter how much memory is available. * Strings with length exactly 2**32-1 caused OSError. * Strings longer than 2**32-1 characters were truncated due to integer overflow bug. * Strings containing the null character were truncated at the first null character. Now strings longer than 2**31-1 characters caused OverflowError and the null character is allowed.. (cherry picked from commit 04cc01453db2f0af72a06440831637f8bf512daf) --- Lib/test/test_ntpath.py | 1 + ...-07-18-13-01-26.gh-issue-106844.mci4xO.rst | 1 + Modules/_winapi.c | 34 ++++++++++++++----- Modules/clinic/_winapi.c.h | 12 +++---- 4 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 538d758624c9d6..78e1cb582512b0 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1036,6 +1036,7 @@ def test_path_normcase(self): self._check_function(self.path.normcase) if sys.platform == 'win32': self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ') + self.assertEqual(ntpath.normcase('abc\x00def'), 'abc\x00def') def test_path_isabs(self): self._check_function(self.path.isabs) diff --git a/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst b/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst new file mode 100644 index 00000000000000..1fdf162ef4ecdd --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst @@ -0,0 +1 @@ +Fix integer overflow and truncating by the null character in :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index d6d2f4a6a9b103..77275408aed868 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1538,40 +1538,56 @@ _winapi.LCMapStringEx locale: LPCWSTR flags: DWORD - src: LPCWSTR + src: unicode [clinic start generated code]*/ static PyObject * _winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags, - LPCWSTR src) -/*[clinic end generated code: output=cf4713d80e2b47c9 input=9fe26f95d5ab0001]*/ + PyObject *src) +/*[clinic end generated code: output=b90e6b26e028ff0a input=3e3dcd9b8164012f]*/ { if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV | LCMAP_SORTKEY)) { return PyErr_Format(PyExc_ValueError, "unsupported flags"); } - int dest_size = LCMapStringEx(locale, flags, src, -1, NULL, 0, + Py_ssize_t src_size; + wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size); + if (!src_) { + return NULL; + } + if (src_size > INT_MAX) { + PyMem_Free(src_); + PyErr_SetString(PyExc_OverflowError, "input string is too long"); + return NULL; + } + + int dest_size = LCMapStringEx(locale, flags, src_, (int)src_size, NULL, 0, NULL, NULL, 0); - if (dest_size == 0) { - return PyErr_SetFromWindowsErr(0); + if (dest_size <= 0) { + DWORD error = GetLastError(); + PyMem_Free(src_); + return PyErr_SetFromWindowsErr(error); } wchar_t* dest = PyMem_NEW(wchar_t, dest_size); if (dest == NULL) { + PyMem_Free(src_); return PyErr_NoMemory(); } - int nmapped = LCMapStringEx(locale, flags, src, -1, dest, dest_size, + int nmapped = LCMapStringEx(locale, flags, src_, (int)src_size, dest, dest_size, NULL, NULL, 0); - if (nmapped == 0) { + if (nmapped <= 0) { DWORD error = GetLastError(); + PyMem_Free(src_); PyMem_DEL(dest); return PyErr_SetFromWindowsErr(error); } - PyObject *ret = PyUnicode_FromWideChar(dest, dest_size - 1); + PyMem_Free(src_); + PyObject *ret = PyUnicode_FromWideChar(dest, nmapped); PyMem_DEL(dest); return ret; diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 3767b19d76db05..1394a8fcffd9f6 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -885,7 +885,7 @@ PyDoc_STRVAR(_winapi_LCMapStringEx__doc__, static PyObject * _winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags, - LPCWSTR src); + PyObject *src); static PyObject * _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -912,16 +912,16 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, static const char * const _keywords[] = {"locale", "flags", "src", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "O&kO&:LCMapStringEx", + .format = "O&kU:LCMapStringEx", .kwtuple = KWTUPLE, }; #undef KWTUPLE LPCWSTR locale = NULL; DWORD flags; - LPCWSTR src = NULL; + PyObject *src; if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - _PyUnicode_WideCharString_Converter, &locale, &flags, _PyUnicode_WideCharString_Converter, &src)) { + _PyUnicode_WideCharString_Converter, &locale, &flags, &src)) { goto exit; } return_value = _winapi_LCMapStringEx_impl(module, locale, flags, src); @@ -929,8 +929,6 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, exit: /* Cleanup for locale */ PyMem_Free((void *)locale); - /* Cleanup for src */ - PyMem_Free((void *)src); return return_value; } @@ -1481,4 +1479,4 @@ _winapi_CopyFile2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO return return_value; } -/*[clinic end generated code: output=be1343b3759e0c96 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9d43ae4bdbe1126a input=a9049054013a1b77]*/ From 4421c65f08228b203a1bed3b30ab3f5189b62427 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 03:13:35 -0700 Subject: [PATCH 0540/1206] [3.12] gh-106300: Improve errors testing in test_unittest.test_runner (GH-106737) (#108006) gh-106300: Improve errors testing in test_unittest.test_runner (GH-106737) Use a custom exception to prevent unintentional silence of actual errors. (cherry picked from commit fd9d70a94de5b0756b52b9ae21e236e25545db4f) Co-authored-by: Nikita Sobolev --- Lib/test/test_unittest/test_runner.py | 117 ++++++++++++++------------ 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py index f3b2c0cffd4513..1b9cef43e3f9c5 100644 --- a/Lib/test/test_unittest/test_runner.py +++ b/Lib/test/test_unittest/test_runner.py @@ -24,6 +24,13 @@ def getRunner(): stream=io.StringIO()) +class CustomError(Exception): + pass + +# For test output compat: +CustomErrorRepr = f"{__name__ + '.' if __name__ != '__main__' else ''}CustomError" + + def runTests(*cases): suite = unittest.TestSuite() for case in cases: @@ -46,7 +53,7 @@ def cleanup(ordering, blowUp=False): ordering.append('cleanup_good') else: ordering.append('cleanup_exc') - raise Exception('CleanUpExc') + raise CustomError('CleanUpExc') class TestCM: @@ -108,8 +115,8 @@ def testNothing(self): result = unittest.TestResult() outcome = test._outcome = _Outcome(result=result) - CleanUpExc = Exception('foo') - exc2 = Exception('bar') + CleanUpExc = CustomError('foo') + exc2 = CustomError('bar') def cleanup1(): raise CleanUpExc @@ -125,10 +132,10 @@ def cleanup2(): (_, msg2), (_, msg1) = result.errors self.assertIn('in cleanup1', msg1) self.assertIn('raise CleanUpExc', msg1) - self.assertIn('Exception: foo', msg1) + self.assertIn(f'{CustomErrorRepr}: foo', msg1) self.assertIn('in cleanup2', msg2) self.assertIn('raise exc2', msg2) - self.assertIn('Exception: bar', msg2) + self.assertIn(f'{CustomErrorRepr}: bar', msg2) def testCleanupInRun(self): blowUp = False @@ -139,7 +146,7 @@ def setUp(self): ordering.append('setUp') test.addCleanup(cleanup2) if blowUp: - raise Exception('foo') + raise CustomError('foo') def testNothing(self): ordering.append('test') @@ -280,7 +287,7 @@ def setUpClass(cls): ordering.append('setUpClass') cls.addClassCleanup(cleanup, ordering) if blowUp: - raise Exception() + raise CustomError() def testNothing(self): ordering.append('test') @classmethod @@ -306,7 +313,7 @@ def setUpClass(cls): ordering.append('setUpClass') cls.addClassCleanup(cleanup, ordering) if blowUp: - raise Exception() + raise CustomError() def testNothing(self): ordering.append('test') @classmethod @@ -346,7 +353,7 @@ def tearDownClass(cls): ordering = [] blowUp = True suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest) - with self.assertRaises(Exception) as cm: + with self.assertRaises(CustomError) as cm: suite.debug() self.assertEqual(str(cm.exception), 'CleanUpExc') self.assertEqual(ordering, @@ -366,10 +373,10 @@ def testNothing(self): @classmethod def tearDownClass(cls): ordering.append('tearDownClass') - raise Exception('TearDownClassExc') + raise CustomError('TearDownClassExc') suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest) - with self.assertRaises(Exception) as cm: + with self.assertRaises(CustomError) as cm: suite.debug() self.assertEqual(str(cm.exception), 'TearDownClassExc') self.assertEqual(ordering, ['setUpClass', 'test', 'tearDownClass']) @@ -379,7 +386,7 @@ def tearDownClass(cls): ordering = [] blowUp = True suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest) - with self.assertRaises(Exception) as cm: + with self.assertRaises(CustomError) as cm: suite.debug() self.assertEqual(str(cm.exception), 'TearDownClassExc') self.assertEqual(ordering, ['setUpClass', 'test', 'tearDownClass']) @@ -392,16 +399,22 @@ def testNothing(self): pass def cleanup1(): - raise Exception('cleanup1') + raise CustomError('cleanup1') def cleanup2(): - raise Exception('cleanup2') + raise CustomError('cleanup2') TestableTest.addClassCleanup(cleanup1) TestableTest.addClassCleanup(cleanup2) - with self.assertRaises(Exception) as e: - TestableTest.doClassCleanups() - self.assertEqual(e, 'cleanup1') + TestableTest.doClassCleanups() + + self.assertEqual(len(TestableTest.tearDown_exceptions), 2) + + e1, e2 = TestableTest.tearDown_exceptions + self.assertIsInstance(e1[1], CustomError) + self.assertEqual(str(e1[1]), 'cleanup2') + self.assertIsInstance(e2[1], CustomError) + self.assertEqual(str(e2[1]), 'cleanup1') def test_with_errors_addCleanUp(self): ordering = [] @@ -421,7 +434,7 @@ def tearDownClass(cls): result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpClass', 'setUp', 'cleanup_exc', 'tearDownClass', 'cleanup_good']) @@ -444,7 +457,7 @@ def tearDownClass(cls): result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpClass', 'setUp', 'test', 'cleanup_good', 'tearDownClass', 'cleanup_exc']) @@ -460,11 +473,11 @@ def setUpClass(cls): ordering.append('setUpClass') cls.addClassCleanup(cleanup, ordering, blowUp=True) if class_blow_up: - raise Exception('ClassExc') + raise CustomError('ClassExc') def setUp(self): ordering.append('setUp') if method_blow_up: - raise Exception('MethodExc') + raise CustomError('MethodExc') def testNothing(self): ordering.append('test') @classmethod @@ -473,7 +486,7 @@ def tearDownClass(cls): result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpClass', 'setUp', 'test', 'tearDownClass', 'cleanup_exc']) @@ -483,9 +496,9 @@ def tearDownClass(cls): method_blow_up = False result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: ClassExc') + f'{CustomErrorRepr}: ClassExc') self.assertEqual(result.errors[1][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpClass', 'cleanup_exc']) @@ -494,9 +507,9 @@ def tearDownClass(cls): method_blow_up = True result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: MethodExc') + f'{CustomErrorRepr}: MethodExc') self.assertEqual(result.errors[1][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpClass', 'setUp', 'tearDownClass', 'cleanup_exc']) @@ -513,11 +526,11 @@ def testNothing(self): @classmethod def tearDownClass(cls): ordering.append('tearDownClass') - raise Exception('TearDownExc') + raise CustomError('TearDownExc') result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: TearDownExc') + f'{CustomErrorRepr}: TearDownExc') self.assertEqual(ordering, ['setUpClass', 'test', 'tearDownClass', 'cleanup_good']) @@ -620,7 +633,7 @@ def module_cleanup_good(*args, **kwargs): module_cleanups.append((3, args, kwargs)) def module_cleanup_bad(*args, **kwargs): - raise Exception('CleanUpExc') + raise CustomError('CleanUpExc') class Module(object): unittest.addModuleCleanup(module_cleanup_good, 1, 2, 3, @@ -630,7 +643,7 @@ class Module(object): [(module_cleanup_good, (1, 2, 3), dict(four='hello', five='goodbye')), (module_cleanup_bad, (), {})]) - with self.assertRaises(Exception) as e: + with self.assertRaises(CustomError) as e: unittest.case.doModuleCleanups() self.assertEqual(str(e.exception), 'CleanUpExc') self.assertEqual(unittest.case._module_cleanups, []) @@ -659,7 +672,7 @@ def setUpModule(): ordering.append('setUpModule') unittest.addModuleCleanup(cleanup, ordering) if blowUp: - raise Exception('setUpModule Exc') + raise CustomError('setUpModule Exc') @staticmethod def tearDownModule(): ordering.append('tearDownModule') @@ -679,7 +692,7 @@ def tearDownClass(cls): result = runTests(TestableTest) self.assertEqual(ordering, ['setUpModule', 'cleanup_good']) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: setUpModule Exc') + f'{CustomErrorRepr}: setUpModule Exc') ordering = [] blowUp = False @@ -699,7 +712,7 @@ def setUpModule(): ordering.append('setUpModule') unittest.addModuleCleanup(cleanup, ordering) if blowUp: - raise Exception() + raise CustomError() @staticmethod def tearDownModule(): ordering.append('tearDownModule') @@ -710,7 +723,7 @@ def setUpModule(): ordering.append('setUpModule2') unittest.addModuleCleanup(cleanup, ordering) if blowUp2: - raise Exception() + raise CustomError() @staticmethod def tearDownModule(): ordering.append('tearDownModule2') @@ -799,7 +812,7 @@ def setUpModule(): @staticmethod def tearDownModule(): ordering.append('tearDownModule') - raise Exception('CleanUpExc') + raise CustomError('CleanUpExc') class TestableTest(unittest.TestCase): @classmethod @@ -815,7 +828,7 @@ def tearDownClass(cls): sys.modules['Module'] = Module result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test', 'tearDownClass', 'tearDownModule', 'cleanup_good']) @@ -855,7 +868,7 @@ def tearDownClass(cls): ordering = [] blowUp = True suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest) - with self.assertRaises(Exception) as cm: + with self.assertRaises(CustomError) as cm: suite.debug() self.assertEqual(str(cm.exception), 'CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test', @@ -873,7 +886,7 @@ def setUpModule(): @staticmethod def tearDownModule(): ordering.append('tearDownModule') - raise Exception('TearDownModuleExc') + raise CustomError('TearDownModuleExc') class TestableTest(unittest.TestCase): @classmethod @@ -888,7 +901,7 @@ def tearDownClass(cls): TestableTest.__module__ = 'Module' sys.modules['Module'] = Module suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest) - with self.assertRaises(Exception) as cm: + with self.assertRaises(CustomError) as cm: suite.debug() self.assertEqual(str(cm.exception), 'TearDownModuleExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test', @@ -899,7 +912,7 @@ def tearDownClass(cls): ordering = [] blowUp = True suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestableTest) - with self.assertRaises(Exception) as cm: + with self.assertRaises(CustomError) as cm: suite.debug() self.assertEqual(str(cm.exception), 'TearDownModuleExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test', @@ -978,7 +991,7 @@ def tearDownClass(cls): result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'test', 'tearDownClass', 'cleanup_exc', 'tearDownModule', 'cleanup_good']) @@ -1008,7 +1021,7 @@ def tearDown(self): result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'setUp', 'test', 'tearDown', 'cleanup_exc', 'tearDownModule', 'cleanup_good']) @@ -1024,7 +1037,7 @@ def setUpModule(): ordering.append('setUpModule') unittest.addModuleCleanup(cleanup, ordering, blowUp=True) if module_blow_up: - raise Exception('ModuleExc') + raise CustomError('ModuleExc') @staticmethod def tearDownModule(): ordering.append('tearDownModule') @@ -1034,11 +1047,11 @@ class TestableTest(unittest.TestCase): def setUpClass(cls): ordering.append('setUpClass') if class_blow_up: - raise Exception('ClassExc') + raise CustomError('ClassExc') def setUp(self): ordering.append('setUp') if method_blow_up: - raise Exception('MethodExc') + raise CustomError('MethodExc') def testNothing(self): ordering.append('test') @classmethod @@ -1050,7 +1063,7 @@ def tearDownClass(cls): result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'setUp', 'test', 'tearDownClass', 'tearDownModule', @@ -1062,9 +1075,9 @@ def tearDownClass(cls): method_blow_up = False result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: ModuleExc') + f'{CustomErrorRepr}: ModuleExc') self.assertEqual(result.errors[1][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'cleanup_exc']) ordering = [] @@ -1073,9 +1086,9 @@ def tearDownClass(cls): method_blow_up = False result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: ClassExc') + f'{CustomErrorRepr}: ClassExc') self.assertEqual(result.errors[1][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'tearDownModule', 'cleanup_exc']) @@ -1085,9 +1098,9 @@ def tearDownClass(cls): method_blow_up = True result = runTests(TestableTest) self.assertEqual(result.errors[0][1].splitlines()[-1], - 'Exception: MethodExc') + f'{CustomErrorRepr}: MethodExc') self.assertEqual(result.errors[1][1].splitlines()[-1], - 'Exception: CleanUpExc') + f'{CustomErrorRepr}: CleanUpExc') self.assertEqual(ordering, ['setUpModule', 'setUpClass', 'setUp', 'tearDownClass', 'tearDownModule', 'cleanup_exc']) From 5d9f20a06c6ad3f1d7812e098717b1c6f7c673fa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:21:57 -0700 Subject: [PATCH 0541/1206] [3.12] gh-99203: shutil.make_archive(): restore select CPython <= 3.10.5 behavior (GH-99802) (#107998) gh-99203: shutil.make_archive(): restore select CPython <= 3.10.5 behavior (GH-99802) Restore following CPython <= 3.10.5 behavior of shutil.make_archive() that went away as part of gh-93160: Do not create an empty archive if root_dir is not a directory, and, in that case, raise FileNotFoundError or NotADirectoryError regardless of format choice. Beyond the brought-back behavior, the function may now also raise these exceptions in dry_run mode. (cherry picked from commit a86df298df5b02e2d69ea6879e9ed10a7adb85d0) Co-authored-by: 6t8k <58048945+6t8k@users.noreply.github.com> --- Lib/shutil.py | 4 ++ Lib/test/test_shutil.py | 43 +++++++++++++++++++ ...2-11-26-22-05-22.gh-issue-99203.j0DUae.rst | 5 +++ 3 files changed, 52 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst diff --git a/Lib/shutil.py b/Lib/shutil.py index 3f2864af517e7d..b37bd082eee0c6 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1156,6 +1156,10 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, supports_root_dir = getattr(func, 'supports_root_dir', False) save_cwd = None if root_dir is not None: + stmd = os.stat(root_dir).st_mode + if not stat.S_ISDIR(stmd): + raise NotADirectoryError(errno.ENOTDIR, 'Not a directory', root_dir) + if supports_root_dir: # Support path-like base_name here for backwards-compatibility. base_name = os.fspath(base_name) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index d74eee767c991d..cd1c3d8cfbc388 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1840,6 +1840,49 @@ def test_register_archive_format(self): formats = [name for name, params in get_archive_formats()] self.assertNotIn('xxx', formats) + def test_make_tarfile_rootdir_nodir(self): + # GH-99203 + self.addCleanup(os_helper.unlink, f'{TESTFN}.tar') + for dry_run in (False, True): + with self.subTest(dry_run=dry_run): + tmp_dir = self.mkdtemp() + nonexisting_file = os.path.join(tmp_dir, 'nonexisting') + with self.assertRaises(FileNotFoundError) as cm: + make_archive(TESTFN, 'tar', nonexisting_file, dry_run=dry_run) + self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(cm.exception.filename, nonexisting_file) + self.assertFalse(os.path.exists(f'{TESTFN}.tar')) + + tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir) + os.close(tmp_fd) + with self.assertRaises(NotADirectoryError) as cm: + make_archive(TESTFN, 'tar', tmp_file, dry_run=dry_run) + self.assertEqual(cm.exception.errno, errno.ENOTDIR) + self.assertEqual(cm.exception.filename, tmp_file) + self.assertFalse(os.path.exists(f'{TESTFN}.tar')) + + @support.requires_zlib() + def test_make_zipfile_rootdir_nodir(self): + # GH-99203 + self.addCleanup(os_helper.unlink, f'{TESTFN}.zip') + for dry_run in (False, True): + with self.subTest(dry_run=dry_run): + tmp_dir = self.mkdtemp() + nonexisting_file = os.path.join(tmp_dir, 'nonexisting') + with self.assertRaises(FileNotFoundError) as cm: + make_archive(TESTFN, 'zip', nonexisting_file, dry_run=dry_run) + self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(cm.exception.filename, nonexisting_file) + self.assertFalse(os.path.exists(f'{TESTFN}.zip')) + + tmp_fd, tmp_file = tempfile.mkstemp(dir=tmp_dir) + os.close(tmp_fd) + with self.assertRaises(NotADirectoryError) as cm: + make_archive(TESTFN, 'zip', tmp_file, dry_run=dry_run) + self.assertEqual(cm.exception.errno, errno.ENOTDIR) + self.assertEqual(cm.exception.filename, tmp_file) + self.assertFalse(os.path.exists(f'{TESTFN}.zip')) + ### shutil.unpack_archive def check_unpack_archive(self, format, **kwargs): diff --git a/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst b/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst new file mode 100644 index 00000000000000..fcfb044d476acc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst @@ -0,0 +1,5 @@ +Restore following CPython <= 3.10.5 behavior of :func:`shutil.make_archive`: +do not create an empty archive if ``root_dir`` is not a directory, and, in that +case, raise :class:`FileNotFoundError` or :class:`NotADirectoryError` +regardless of ``format`` choice. Beyond the brought-back behavior, the function +may now also raise these exceptions in ``dry_run`` mode. From c2fb25a7145cbb6bbe92de28a230e963fe4d696f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:22:22 -0700 Subject: [PATCH 0542/1206] [3.12] More actionable error message when spawn is incorrectly used. (GH-102203) (#107990) More actionable error message when spawn is incorrectly used. (GH-102203) (cherry picked from commit a794ebeb028f7ef287c780d3890f816db9c21c51) Co-authored-by: Yuxin Wu Co-authored-by: Yuxin Wu Co-authored-by: Oleg Iarygin --- Lib/multiprocessing/spawn.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py index f1af7709104714..daac1ecc34b55e 100644 --- a/Lib/multiprocessing/spawn.py +++ b/Lib/multiprocessing/spawn.py @@ -150,7 +150,11 @@ def _check_not_importing_main(): ... The "freeze_support()" line can be omitted if the program - is not going to be frozen to produce an executable.''') + is not going to be frozen to produce an executable. + + To fix this issue, refer to the "Safe importing of main module" + section in https://docs.python.org/3/library/multiprocessing.html + ''') def get_preparation_data(name): From 8cb750df13c3d508726b6d507d35b807f1826e32 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:24:47 -0700 Subject: [PATCH 0543/1206] [3.12] gh-91795: Update build optimization part of PCbuild/readme.txt (GH-91849) (#107776) gh-91795: Update build optimization part of PCbuild/readme.txt (GH-91849) (cherry picked from commit 906b73be5eada1995bd667a02c59f7a11998310f) Co-authored-by: Fatih <77548106+fatihkabakk@users.noreply.github.com> --- PCbuild/readme.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index fe44ca40f4a0e1..5c682a28260882 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -252,9 +252,11 @@ against a profiling library and contain extra debug information. The PGUpdate configuration takes the profiling data and generates optimized binaries. -The build_pgo.bat script automates the creation of optimized binaries. -It creates the PGI files, runs the unit test suite or PyBench with the -PGI python, and finally creates the optimized files. +The build.bat script has an argument `--pgo` that automate the creation +of optimized binaries. +It creates the PGI files, runs the unit test suite with the PGI python, +and finally creates the optimized files. +You can customize the job for profiling with `--pgo-job ` option. See https://docs.microsoft.com/en-us/cpp/build/profile-guided-optimizations From 2598a1a835e5bdf0532c08d867cf54f94aeb85a0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:25:18 -0700 Subject: [PATCH 0544/1206] [3.12] README: remove unmaintained sections (GH-107703) (#107762) README: remove unmaintained sections (GH-107703) (cherry picked from commit 7a250fdc16bb6f1fe0a6b0df8bb502870405b5d6) Co-authored-by: Inada Naoki --- README.rst | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/README.rst b/README.rst index 7742de68d5a2f0..b97bd3c8bd667d 100644 --- a/README.rst +++ b/README.rst @@ -211,30 +211,6 @@ primary version, you would execute ``make install`` in your 3.12 build directory and ``make altinstall`` in the others. -Issue Tracker and Mailing List ------------------------------- - -Bug reports are welcome! You can use Github to `report bugs -`_, and/or `submit pull requests -`_. - -You can also follow development discussion on the `python-dev mailing list -`_. - - -Proposals for enhancement -------------------------- - -If you have a proposal to change Python, you may want to send an email to the -`comp.lang.python`_ or `python-ideas`_ mailing lists for initial feedback. A -Python Enhancement Proposal (PEP) may be submitted if your idea gains ground. -All current PEPs, as well as guidelines for submitting a new PEP, are listed at -`peps.python.org `_. - -.. _python-ideas: https://mail.python.org/mailman/listinfo/python-ideas/ -.. _comp.lang.python: https://mail.python.org/mailman/listinfo/python-list - - Release Schedule ---------------- From 9864f9a7c7046d6a0174c8142ddfbb5f07de5925 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 16 Aug 2023 15:27:32 +0300 Subject: [PATCH 0545/1206] [3.12] gh-86457: Fix signature for code.replace() (GH-23199) (#107744) * [3.12] gh-86457: Fix signature for code.replace() (GH-23199) Also add support of @text_signature in Argument Clinic.. (cherry picked from commit 0e6e32fb84b2f7cb668e0b9927637587081e38cd) Co-authored-by: Serhiy Storchaka * Update 2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst --- ...3-08-07-16-30-48.gh-issue-95065.-im4R5.rst | 2 + Objects/clinic/codeobject.c.h | 34 +-- Objects/codeobject.c | 58 ++-- Tools/clinic/clinic.py | 255 +++++++++--------- 4 files changed, 177 insertions(+), 172 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst b/Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst new file mode 100644 index 00000000000000..4768e6767574d8 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst @@ -0,0 +1,2 @@ +Argument Clinic now supports overriding automatically generated signature by +using directive ``@text_signature``. diff --git a/Objects/clinic/codeobject.c.h b/Objects/clinic/codeobject.c.h index 5ad4b1fed73417..1034627edd7574 100644 --- a/Objects/clinic/codeobject.c.h +++ b/Objects/clinic/codeobject.c.h @@ -163,12 +163,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) } PyDoc_STRVAR(code_replace__doc__, -"replace($self, /, *, co_argcount=-1, co_posonlyargcount=-1,\n" -" co_kwonlyargcount=-1, co_nlocals=-1, co_stacksize=-1,\n" -" co_flags=-1, co_firstlineno=-1, co_code=None, co_consts=None,\n" -" co_names=None, co_varnames=None, co_freevars=None,\n" -" co_cellvars=None, co_filename=None, co_name=None,\n" -" co_qualname=None, co_linetable=None, co_exceptiontable=None)\n" +"replace($self, /, **changes)\n" "--\n" "\n" "Return a copy of the code object with new values for the specified fields."); @@ -180,13 +175,12 @@ static PyObject * code_replace_impl(PyCodeObject *self, int co_argcount, int co_posonlyargcount, int co_kwonlyargcount, int co_nlocals, int co_stacksize, int co_flags, - int co_firstlineno, PyBytesObject *co_code, - PyObject *co_consts, PyObject *co_names, - PyObject *co_varnames, PyObject *co_freevars, - PyObject *co_cellvars, PyObject *co_filename, - PyObject *co_name, PyObject *co_qualname, - PyBytesObject *co_linetable, - PyBytesObject *co_exceptiontable); + int co_firstlineno, PyObject *co_code, PyObject *co_consts, + PyObject *co_names, PyObject *co_varnames, + PyObject *co_freevars, PyObject *co_cellvars, + PyObject *co_filename, PyObject *co_name, + PyObject *co_qualname, PyObject *co_linetable, + PyObject *co_exceptiontable); static PyObject * code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -226,7 +220,7 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje int co_stacksize = self->co_stacksize; int co_flags = self->co_flags; int co_firstlineno = self->co_firstlineno; - PyBytesObject *co_code = NULL; + PyObject *co_code = NULL; PyObject *co_consts = self->co_consts; PyObject *co_names = self->co_names; PyObject *co_varnames = NULL; @@ -235,8 +229,8 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *co_filename = self->co_filename; PyObject *co_name = self->co_name; PyObject *co_qualname = self->co_qualname; - PyBytesObject *co_linetable = (PyBytesObject *)self->co_linetable; - PyBytesObject *co_exceptiontable = (PyBytesObject *)self->co_exceptiontable; + PyObject *co_linetable = self->co_linetable; + PyObject *co_exceptiontable = self->co_exceptiontable; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); if (!args) { @@ -313,7 +307,7 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje _PyArg_BadArgument("replace", "argument 'co_code'", "bytes", args[7]); goto exit; } - co_code = (PyBytesObject *)args[7]; + co_code = args[7]; if (!--noptargs) { goto skip_optional_kwonly; } @@ -412,7 +406,7 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje _PyArg_BadArgument("replace", "argument 'co_linetable'", "bytes", args[16]); goto exit; } - co_linetable = (PyBytesObject *)args[16]; + co_linetable = args[16]; if (!--noptargs) { goto skip_optional_kwonly; } @@ -421,7 +415,7 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje _PyArg_BadArgument("replace", "argument 'co_exceptiontable'", "bytes", args[17]); goto exit; } - co_exceptiontable = (PyBytesObject *)args[17]; + co_exceptiontable = args[17]; skip_optional_kwonly: return_value = code_replace_impl(self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_linetable, co_exceptiontable); @@ -488,4 +482,4 @@ code__varname_from_oparg(PyCodeObject *self, PyObject *const *args, Py_ssize_t n exit: return return_value; } -/*[clinic end generated code: output=f1fab6e71c785182 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ff40f7bdd3851de3 input=a9049054013a1b77]*/ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index d47ca731a10c87..aee1213632e490 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1962,27 +1962,28 @@ code_linesiterator(PyCodeObject *code, PyObject *Py_UNUSED(args)) } /*[clinic input] +@text_signature "($self, /, **changes)" code.replace * - co_argcount: int(c_default="self->co_argcount") = -1 - co_posonlyargcount: int(c_default="self->co_posonlyargcount") = -1 - co_kwonlyargcount: int(c_default="self->co_kwonlyargcount") = -1 - co_nlocals: int(c_default="self->co_nlocals") = -1 - co_stacksize: int(c_default="self->co_stacksize") = -1 - co_flags: int(c_default="self->co_flags") = -1 - co_firstlineno: int(c_default="self->co_firstlineno") = -1 - co_code: PyBytesObject(c_default="NULL") = None - co_consts: object(subclass_of="&PyTuple_Type", c_default="self->co_consts") = None - co_names: object(subclass_of="&PyTuple_Type", c_default="self->co_names") = None - co_varnames: object(subclass_of="&PyTuple_Type", c_default="NULL") = None - co_freevars: object(subclass_of="&PyTuple_Type", c_default="NULL") = None - co_cellvars: object(subclass_of="&PyTuple_Type", c_default="NULL") = None - co_filename: unicode(c_default="self->co_filename") = None - co_name: unicode(c_default="self->co_name") = None - co_qualname: unicode(c_default="self->co_qualname") = None - co_linetable: PyBytesObject(c_default="(PyBytesObject *)self->co_linetable") = None - co_exceptiontable: PyBytesObject(c_default="(PyBytesObject *)self->co_exceptiontable") = None + co_argcount: int(c_default="self->co_argcount") = unchanged + co_posonlyargcount: int(c_default="self->co_posonlyargcount") = unchanged + co_kwonlyargcount: int(c_default="self->co_kwonlyargcount") = unchanged + co_nlocals: int(c_default="self->co_nlocals") = unchanged + co_stacksize: int(c_default="self->co_stacksize") = unchanged + co_flags: int(c_default="self->co_flags") = unchanged + co_firstlineno: int(c_default="self->co_firstlineno") = unchanged + co_code: object(subclass_of="&PyBytes_Type", c_default="NULL") = unchanged + co_consts: object(subclass_of="&PyTuple_Type", c_default="self->co_consts") = unchanged + co_names: object(subclass_of="&PyTuple_Type", c_default="self->co_names") = unchanged + co_varnames: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged + co_freevars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged + co_cellvars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged + co_filename: unicode(c_default="self->co_filename") = unchanged + co_name: unicode(c_default="self->co_name") = unchanged + co_qualname: unicode(c_default="self->co_qualname") = unchanged + co_linetable: object(subclass_of="&PyBytes_Type", c_default="self->co_linetable") = unchanged + co_exceptiontable: object(subclass_of="&PyBytes_Type", c_default="self->co_exceptiontable") = unchanged Return a copy of the code object with new values for the specified fields. [clinic start generated code]*/ @@ -1991,14 +1992,13 @@ static PyObject * code_replace_impl(PyCodeObject *self, int co_argcount, int co_posonlyargcount, int co_kwonlyargcount, int co_nlocals, int co_stacksize, int co_flags, - int co_firstlineno, PyBytesObject *co_code, - PyObject *co_consts, PyObject *co_names, - PyObject *co_varnames, PyObject *co_freevars, - PyObject *co_cellvars, PyObject *co_filename, - PyObject *co_name, PyObject *co_qualname, - PyBytesObject *co_linetable, - PyBytesObject *co_exceptiontable) -/*[clinic end generated code: output=b6cd9988391d5711 input=f6f68e03571f8d7c]*/ + int co_firstlineno, PyObject *co_code, PyObject *co_consts, + PyObject *co_names, PyObject *co_varnames, + PyObject *co_freevars, PyObject *co_cellvars, + PyObject *co_filename, PyObject *co_name, + PyObject *co_qualname, PyObject *co_linetable, + PyObject *co_exceptiontable) +/*[clinic end generated code: output=e75c48a15def18b9 input=18e280e07846c122]*/ { #define CHECK_INT_ARG(ARG) \ if (ARG < 0) { \ @@ -2023,7 +2023,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount, if (code == NULL) { return NULL; } - co_code = (PyBytesObject *)code; + co_code = code; } if (PySys_Audit("code.__new__", "OOOiiiiii", @@ -2062,10 +2062,10 @@ code_replace_impl(PyCodeObject *self, int co_argcount, co = PyCode_NewWithPosOnlyArgs( co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, - co_stacksize, co_flags, (PyObject*)co_code, co_consts, co_names, + co_stacksize, co_flags, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_firstlineno, - (PyObject*)co_linetable, (PyObject*)co_exceptiontable); + co_linetable, co_exceptiontable); error: Py_XDECREF(code); diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index e775b012d0b6df..fd394c92cad9c6 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4310,6 +4310,7 @@ def reset(self) -> None: self.indent = IndentStack() self.kind = CALLABLE self.coexist = False + self.forced_text_signature: str | None = None self.parameter_continuation = '' self.preserve_output = False @@ -4444,6 +4445,11 @@ def at_coexist(self) -> None: fail("Called @coexist twice!") self.coexist = True + def at_text_signature(self, text_signature: str) -> None: + if self.forced_text_signature: + fail("Called @text_signature twice!") + self.forced_text_signature = text_signature + def parse(self, block: Block) -> None: self.reset() self.block = block @@ -5148,142 +5154,145 @@ def format_docstring(self): add(f.cls.name) else: add(f.name) - add('(') + if self.forced_text_signature: + add(self.forced_text_signature) + else: + add('(') + + # populate "right_bracket_count" field for every parameter + assert parameters, "We should always have a self parameter. " + repr(f) + assert isinstance(parameters[0].converter, self_converter) + # self is always positional-only. + assert parameters[0].is_positional_only() + parameters[0].right_bracket_count = 0 + positional_only = True + for p in parameters[1:]: + if not p.is_positional_only(): + positional_only = False + else: + assert positional_only + if positional_only: + p.right_bracket_count = abs(p.group) + else: + # don't put any right brackets around non-positional-only parameters, ever. + p.right_bracket_count = 0 + + right_bracket_count = 0 + + def fix_right_bracket_count(desired): + nonlocal right_bracket_count + s = '' + while right_bracket_count < desired: + s += '[' + right_bracket_count += 1 + while right_bracket_count > desired: + s += ']' + right_bracket_count -= 1 + return s + + need_slash = False + added_slash = False + need_a_trailing_slash = False + + # we only need a trailing slash: + # * if this is not a "docstring_only" signature + # * and if the last *shown* parameter is + # positional only + if not f.docstring_only: + for p in reversed(parameters): + if not p.converter.show_in_signature: + continue + if p.is_positional_only(): + need_a_trailing_slash = True + break - # populate "right_bracket_count" field for every parameter - assert parameters, "We should always have a self parameter. " + repr(f) - assert isinstance(parameters[0].converter, self_converter) - # self is always positional-only. - assert parameters[0].is_positional_only() - parameters[0].right_bracket_count = 0 - positional_only = True - for p in parameters[1:]: - if not p.is_positional_only(): - positional_only = False - else: - assert positional_only - if positional_only: - p.right_bracket_count = abs(p.group) - else: - # don't put any right brackets around non-positional-only parameters, ever. - p.right_bracket_count = 0 - - right_bracket_count = 0 - - def fix_right_bracket_count(desired): - nonlocal right_bracket_count - s = '' - while right_bracket_count < desired: - s += '[' - right_bracket_count += 1 - while right_bracket_count > desired: - s += ']' - right_bracket_count -= 1 - return s - need_slash = False - added_slash = False - need_a_trailing_slash = False + added_star = False - # we only need a trailing slash: - # * if this is not a "docstring_only" signature - # * and if the last *shown* parameter is - # positional only - if not f.docstring_only: - for p in reversed(parameters): + first_parameter = True + last_p = parameters[-1] + line_length = len(''.join(text)) + indent = " " * line_length + def add_parameter(text): + nonlocal line_length + nonlocal first_parameter + if first_parameter: + s = text + first_parameter = False + else: + s = ' ' + text + if line_length + len(s) >= 72: + add('\n') + add(indent) + line_length = len(indent) + s = text + line_length += len(s) + add(s) + + for p in parameters: if not p.converter.show_in_signature: continue - if p.is_positional_only(): - need_a_trailing_slash = True - break + assert p.name + is_self = isinstance(p.converter, self_converter) + if is_self and f.docstring_only: + # this isn't a real machine-parsable signature, + # so let's not print the "self" parameter + continue - added_star = False - - first_parameter = True - last_p = parameters[-1] - line_length = len(''.join(text)) - indent = " " * line_length - def add_parameter(text): - nonlocal line_length - nonlocal first_parameter - if first_parameter: - s = text - first_parameter = False - else: - s = ' ' + text - if line_length + len(s) >= 72: - add('\n') - add(indent) - line_length = len(indent) - s = text - line_length += len(s) - add(s) - - for p in parameters: - if not p.converter.show_in_signature: - continue - assert p.name - - is_self = isinstance(p.converter, self_converter) - if is_self and f.docstring_only: - # this isn't a real machine-parsable signature, - # so let's not print the "self" parameter - continue - - if p.is_positional_only(): - need_slash = not f.docstring_only - elif need_slash and not (added_slash or p.is_positional_only()): - added_slash = True - add_parameter('/,') - - if p.is_keyword_only() and not added_star: - added_star = True - add_parameter('*,') - - p_add, p_output = text_accumulator() - p_add(fix_right_bracket_count(p.right_bracket_count)) - - if isinstance(p.converter, self_converter): - # annotate first parameter as being a "self". - # - # if inspect.Signature gets this function, - # and it's already bound, the self parameter - # will be stripped off. - # - # if it's not bound, it should be marked - # as positional-only. - # - # note: we don't print "self" for __init__, - # because this isn't actually the signature - # for __init__. (it can't be, __init__ doesn't - # have a docstring.) if this is an __init__ - # (or __new__), then this signature is for - # calling the class to construct a new instance. - p_add('$') + if p.is_positional_only(): + need_slash = not f.docstring_only + elif need_slash and not (added_slash or p.is_positional_only()): + added_slash = True + add_parameter('/,') + + if p.is_keyword_only() and not added_star: + added_star = True + add_parameter('*,') + + p_add, p_output = text_accumulator() + p_add(fix_right_bracket_count(p.right_bracket_count)) + + if isinstance(p.converter, self_converter): + # annotate first parameter as being a "self". + # + # if inspect.Signature gets this function, + # and it's already bound, the self parameter + # will be stripped off. + # + # if it's not bound, it should be marked + # as positional-only. + # + # note: we don't print "self" for __init__, + # because this isn't actually the signature + # for __init__. (it can't be, __init__ doesn't + # have a docstring.) if this is an __init__ + # (or __new__), then this signature is for + # calling the class to construct a new instance. + p_add('$') - if p.is_vararg(): - p_add("*") + if p.is_vararg(): + p_add("*") - name = p.converter.signature_name or p.name - p_add(name) + name = p.converter.signature_name or p.name + p_add(name) - if not p.is_vararg() and p.converter.is_optional(): - p_add('=') - value = p.converter.py_default - if not value: - value = repr(p.converter.default) - p_add(value) + if not p.is_vararg() and p.converter.is_optional(): + p_add('=') + value = p.converter.py_default + if not value: + value = repr(p.converter.default) + p_add(value) - if (p != last_p) or need_a_trailing_slash: - p_add(',') + if (p != last_p) or need_a_trailing_slash: + p_add(',') - add_parameter(p_output()) + add_parameter(p_output()) - add(fix_right_bracket_count(0)) - if need_a_trailing_slash: - add_parameter('/') - add(')') + add(fix_right_bracket_count(0)) + if need_a_trailing_slash: + add_parameter('/') + add(')') # PEP 8 says: # From 72534ca85c64d4d33a9cf30492e037be05140fd2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 16 Aug 2023 15:28:14 +0300 Subject: [PATCH 0546/1206] [3.12] gh-107735: Add C API tests for PySys_GetObject() and PySys_SetObject() (GH-107736) (#107740) [3.12] gh-107735: Add C API tests for PySys_GetObject() and PySys_SetObject() (GH-107736). (cherry picked from commit bea5f93196d213d6fbf4ba8984caf4c3cd1da882) --- Lib/test/test_capi/test_misc.py | 42 +++++++++++++++++++++++++++++++++ Modules/_testcapimodule.c | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 3f2736da7d93a4..3d494975c71e2b 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -51,6 +51,8 @@ import _testinternalcapi +NULL = None + def decode_stderr(err): return err.decode('utf-8', 'replace').replace('\r', '') @@ -1121,6 +1123,46 @@ class Data(_testcapi.ObjExtraData): del d.extra self.assertIsNone(d.extra) + def test_sys_getobject(self): + getobject = _testcapi.sys_getobject + + self.assertIs(getobject(b'stdout'), sys.stdout) + with support.swap_attr(sys, '\U0001f40d', 42): + self.assertEqual(getobject('\U0001f40d'.encode()), 42) + + self.assertIs(getobject(b'nonexisting'), AttributeError) + self.assertIs(getobject(b'\xff'), AttributeError) + # CRASHES getobject(NULL) + + def test_sys_setobject(self): + setobject = _testcapi.sys_setobject + + value = ['value'] + value2 = ['value2'] + try: + self.assertEqual(setobject(b'newattr', value), 0) + self.assertIs(sys.newattr, value) + self.assertEqual(setobject(b'newattr', value2), 0) + self.assertIs(sys.newattr, value2) + self.assertEqual(setobject(b'newattr', NULL), 0) + self.assertFalse(hasattr(sys, 'newattr')) + self.assertEqual(setobject(b'newattr', NULL), 0) + finally: + with contextlib.suppress(AttributeError): + del sys.newattr + try: + self.assertEqual(setobject('\U0001f40d'.encode(), value), 0) + self.assertIs(getattr(sys, '\U0001f40d'), value) + self.assertEqual(setobject('\U0001f40d'.encode(), NULL), 0) + self.assertFalse(hasattr(sys, '\U0001f40d')) + finally: + with contextlib.suppress(AttributeError): + delattr(sys, '\U0001f40d') + + with self.assertRaises(UnicodeDecodeError): + setobject(b'\xff', value) + # CRASHES setobject(NULL, value) + @requires_limited_api class TestHeapTypeRelative(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 6523734131c2de..098d2cfa6d8ad8 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -45,6 +45,16 @@ // Include definitions from there. #include "_testcapi/parts.h" +#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); + +#define RETURN_INT(value) do { \ + int _ret = (value); \ + if (_ret == -1) { \ + return NULL; \ + } \ + return PyLong_FromLong(_ret); \ + } while (0) + // Forward declarations static struct PyModuleDef _testcapimodule; static PyObject *TestError; /* set to exception object in init */ @@ -3336,6 +3346,35 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args)) } +static PyObject * +sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg) +{ + const char *name; + Py_ssize_t size; + if (!PyArg_Parse(arg, "z#", &name, &size)) { + return NULL; + } + PyObject *result = PySys_GetObject(name); + if (result == NULL) { + result = PyExc_AttributeError; + } + return Py_NewRef(result); +} + +static PyObject * +sys_setobject(PyObject *Py_UNUSED(module), PyObject *args) +{ + const char *name; + Py_ssize_t size; + PyObject *value; + if (!PyArg_ParseTuple(args, "z#O", &name, &size, &value)) { + return NULL; + } + NULLABLE(value); + RETURN_INT(PySys_SetObject(name, value)); +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -3482,6 +3521,8 @@ static PyMethodDef TestMethods[] = { {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, {"test_atexit", test_atexit, METH_NOARGS}, + {"sys_getobject", sys_getobject, METH_O}, + {"sys_setobject", sys_setobject, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; From 9c8dfcec645b233dd6f36c286a7c5525c5d713e2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 16 Aug 2023 15:29:08 +0300 Subject: [PATCH 0547/1206] [3.12] gh-107178: Add the C API tests for the Abstract Objects Layer (GH-107179) (#107728) Cover all the Mapping Protocol, almost all the Sequence Protocol (except PySequence_Fast) and a part of the Object Protocol. Move existing tests to Lib/test/test_capi/test_abstract.py and Modules/_testcapi/abstract.c. Add also tests for PyDict C API.. (cherry picked from commit 16c9415fba4972743f1944ebc44946e475e68bc4) --- Lib/test/test_bytes.py | 2 +- Lib/test/test_capi/test_abstract.py | 694 ++++++++++++++++++ Lib/test/test_capi/test_dict.py | 378 ++++++++++ Lib/test/test_capi/test_misc.py | 131 ---- Lib/test/test_class.py | 4 +- ...-07-24-16-56-59.gh-issue-107178.Gq1usE.rst | 2 + Modules/Setup.stdlib.in | 2 +- Modules/_testcapi/abstract.c | 535 ++++++++++++++ Modules/_testcapi/dict.c | 323 ++++++++ Modules/_testcapi/parts.h | 2 + Modules/_testcapimodule.c | 169 +---- PCbuild/_testcapi.vcxproj | 4 +- PCbuild/_testcapi.vcxproj.filters | 8 +- 13 files changed, 1955 insertions(+), 299 deletions(-) create mode 100644 Lib/test/test_capi/test_abstract.py create mode 100644 Lib/test/test_capi/test_dict.py create mode 100644 Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst create mode 100644 Modules/_testcapi/abstract.c create mode 100644 Modules/_testcapi/dict.c diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 7c62b722059d12..afd506f07520d8 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -1354,7 +1354,7 @@ def do_tests(setitem): except ValueError: pass try: - setitem(b, 0, None) + setitem(b, 0, object()) self.fail("Didn't raise TypeError") except TypeError: pass diff --git a/Lib/test/test_capi/test_abstract.py b/Lib/test/test_capi/test_abstract.py new file mode 100644 index 00000000000000..116edd8d4d2fd6 --- /dev/null +++ b/Lib/test/test_capi/test_abstract.py @@ -0,0 +1,694 @@ +import unittest +import sys +from collections import OrderedDict +from test import support +from test.support import import_helper +import _testcapi + + +NULL = None + +class TestObject: + @property + def evil(self): + raise RuntimeError('do not get evil') + @evil.setter + def evil(self, value): + raise RuntimeError('do not set evil') + @evil.deleter + def evil(self): + raise RuntimeError('do not del evil') + +class ProxyGetItem: + def __init__(self, obj): + self.obj = obj + def __getitem__(self, key): + return self.obj[key] + +class ProxySetItem: + def __init__(self, obj): + self.obj = obj + def __setitem__(self, key, value): + self.obj[key] = value + +class ProxyDelItem: + def __init__(self, obj): + self.obj = obj + def __delitem__(self, key): + del self.obj[key] + +def gen(): + yield 'a' + yield 'b' + yield 'c' + + +class CAPITest(unittest.TestCase): + + def test_object_getattr(self): + xgetattr = _testcapi.object_getattr + obj = TestObject() + obj.a = 11 + setattr(obj, '\U0001f40d', 22) + self.assertEqual(xgetattr(obj, 'a'), 11) + self.assertRaises(AttributeError, xgetattr, obj, 'b') + self.assertEqual(xgetattr(obj, '\U0001f40d'), 22) + + self.assertRaises(RuntimeError, xgetattr, obj, 'evil') + self.assertRaises(TypeError, xgetattr, obj, 1) + # CRASHES xgetattr(obj, NULL) + # CRASHES xgetattr(NULL, 'a') + + def test_object_getattrstring(self): + getattrstring = _testcapi.object_getattrstring + obj = TestObject() + obj.a = 11 + setattr(obj, '\U0001f40d', 22) + self.assertEqual(getattrstring(obj, b'a'), 11) + self.assertRaises(AttributeError, getattrstring, obj, b'b') + self.assertEqual(getattrstring(obj, '\U0001f40d'.encode()), 22) + + self.assertRaises(RuntimeError, getattrstring, obj, b'evil') + self.assertRaises(UnicodeDecodeError, getattrstring, obj, b'\xff') + # CRASHES getattrstring(obj, NULL) + # CRASHES getattrstring(NULL, b'a') + + def test_object_hasattr(self): + xhasattr = _testcapi.object_hasattr + obj = TestObject() + obj.a = 1 + setattr(obj, '\U0001f40d', 2) + self.assertTrue(xhasattr(obj, 'a')) + self.assertFalse(xhasattr(obj, 'b')) + self.assertTrue(xhasattr(obj, '\U0001f40d')) + + self.assertFalse(xhasattr(obj, 'evil')) + self.assertFalse(xhasattr(obj, 1)) + # CRASHES xhasattr(obj, NULL) + # CRASHES xhasattr(NULL, 'a') + + def test_object_hasattrstring(self): + hasattrstring = _testcapi.object_hasattrstring + obj = TestObject() + obj.a = 1 + setattr(obj, '\U0001f40d', 2) + self.assertTrue(hasattrstring(obj, b'a')) + self.assertFalse(hasattrstring(obj, b'b')) + self.assertTrue(hasattrstring(obj, '\U0001f40d'.encode())) + + self.assertFalse(hasattrstring(obj, b'evil')) + self.assertFalse(hasattrstring(obj, b'\xff')) + # CRASHES hasattrstring(obj, NULL) + # CRASHES hasattrstring(NULL, b'a') + + def test_object_setattr(self): + xsetattr = _testcapi.object_setattr + obj = TestObject() + xsetattr(obj, 'a', 5) + self.assertEqual(obj.a, 5) + xsetattr(obj, '\U0001f40d', 8) + self.assertEqual(getattr(obj, '\U0001f40d'), 8) + + # PyObject_SetAttr(obj, attr_name, NULL) removes the attribute + xsetattr(obj, 'a', NULL) + self.assertFalse(hasattr(obj, 'a')) + self.assertRaises(AttributeError, xsetattr, obj, 'b', NULL) + self.assertRaises(RuntimeError, xsetattr, obj, 'evil', NULL) + + self.assertRaises(RuntimeError, xsetattr, obj, 'evil', 'good') + self.assertRaises(AttributeError, xsetattr, 42, 'a', 5) + self.assertRaises(TypeError, xsetattr, obj, 1, 5) + # CRASHES xsetattr(obj, NULL, 5) + # CRASHES xsetattr(NULL, 'a', 5) + + def test_object_setattrstring(self): + setattrstring = _testcapi.object_setattrstring + obj = TestObject() + setattrstring(obj, b'a', 5) + self.assertEqual(obj.a, 5) + setattrstring(obj, '\U0001f40d'.encode(), 8) + self.assertEqual(getattr(obj, '\U0001f40d'), 8) + + # PyObject_SetAttrString(obj, attr_name, NULL) removes the attribute + setattrstring(obj, b'a', NULL) + self.assertFalse(hasattr(obj, 'a')) + self.assertRaises(AttributeError, setattrstring, obj, b'b', NULL) + self.assertRaises(RuntimeError, setattrstring, obj, b'evil', NULL) + + self.assertRaises(RuntimeError, setattrstring, obj, b'evil', 'good') + self.assertRaises(AttributeError, setattrstring, 42, b'a', 5) + self.assertRaises(TypeError, setattrstring, obj, 1, 5) + self.assertRaises(UnicodeDecodeError, setattrstring, obj, b'\xff', 5) + # CRASHES setattrstring(obj, NULL, 5) + # CRASHES setattrstring(NULL, b'a', 5) + + def test_object_delattr(self): + xdelattr = _testcapi.object_delattr + obj = TestObject() + obj.a = 1 + setattr(obj, '\U0001f40d', 2) + xdelattr(obj, 'a') + self.assertFalse(hasattr(obj, 'a')) + self.assertRaises(AttributeError, xdelattr, obj, 'b') + xdelattr(obj, '\U0001f40d') + self.assertFalse(hasattr(obj, '\U0001f40d')) + + self.assertRaises(AttributeError, xdelattr, 42, 'numerator') + self.assertRaises(RuntimeError, xdelattr, obj, 'evil') + self.assertRaises(TypeError, xdelattr, obj, 1) + # CRASHES xdelattr(obj, NULL) + # CRASHES xdelattr(NULL, 'a') + + def test_object_delattrstring(self): + delattrstring = _testcapi.object_delattrstring + obj = TestObject() + obj.a = 1 + setattr(obj, '\U0001f40d', 2) + delattrstring(obj, b'a') + self.assertFalse(hasattr(obj, 'a')) + self.assertRaises(AttributeError, delattrstring, obj, b'b') + delattrstring(obj, '\U0001f40d'.encode()) + self.assertFalse(hasattr(obj, '\U0001f40d')) + + self.assertRaises(AttributeError, delattrstring, 42, b'numerator') + self.assertRaises(RuntimeError, delattrstring, obj, b'evil') + self.assertRaises(UnicodeDecodeError, delattrstring, obj, b'\xff') + # CRASHES delattrstring(obj, NULL) + # CRASHES delattrstring(NULL, b'a') + + + def test_mapping_check(self): + check = _testcapi.mapping_check + self.assertTrue(check({1: 2})) + self.assertTrue(check([1, 2])) + self.assertTrue(check((1, 2))) + self.assertTrue(check('abc')) + self.assertTrue(check(b'abc')) + self.assertFalse(check(42)) + self.assertFalse(check(object())) + self.assertFalse(check(NULL)) + + def test_mapping_size(self): + for size in _testcapi.mapping_size, _testcapi.mapping_length: + self.assertEqual(size({1: 2}), 1) + self.assertEqual(size([1, 2]), 2) + self.assertEqual(size((1, 2)), 2) + self.assertEqual(size('abc'), 3) + self.assertEqual(size(b'abc'), 3) + + self.assertRaises(TypeError, size, 42) + self.assertRaises(TypeError, size, object()) + self.assertRaises(SystemError, size, NULL) + + def test_object_getitem(self): + getitem = _testcapi.object_getitem + dct = {'a': 1, '\U0001f40d': 2} + self.assertEqual(getitem(dct, 'a'), 1) + self.assertRaises(KeyError, getitem, dct, 'b') + self.assertEqual(getitem(dct, '\U0001f40d'), 2) + + dct2 = ProxyGetItem(dct) + self.assertEqual(getitem(dct2, 'a'), 1) + self.assertRaises(KeyError, getitem, dct2, 'b') + + self.assertEqual(getitem(['a', 'b', 'c'], 1), 'b') + + self.assertRaises(TypeError, getitem, 42, 'a') + self.assertRaises(TypeError, getitem, {}, []) # unhashable + self.assertRaises(SystemError, getitem, {}, NULL) + self.assertRaises(IndexError, getitem, [], 1) + self.assertRaises(TypeError, getitem, [], 'a') + self.assertRaises(SystemError, getitem, NULL, 'a') + + def test_mapping_getitemstring(self): + getitemstring = _testcapi.mapping_getitemstring + dct = {'a': 1, '\U0001f40d': 2} + self.assertEqual(getitemstring(dct, b'a'), 1) + self.assertRaises(KeyError, getitemstring, dct, b'b') + self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2) + + dct2 = ProxyGetItem(dct) + self.assertEqual(getitemstring(dct2, b'a'), 1) + self.assertRaises(KeyError, getitemstring, dct2, b'b') + + self.assertRaises(TypeError, getitemstring, 42, b'a') + self.assertRaises(UnicodeDecodeError, getitemstring, {}, b'\xff') + self.assertRaises(SystemError, getitemstring, {}, NULL) + self.assertRaises(TypeError, getitemstring, [], b'a') + self.assertRaises(SystemError, getitemstring, NULL, b'a') + + def test_mapping_haskey(self): + haskey = _testcapi.mapping_haskey + dct = {'a': 1, '\U0001f40d': 2} + self.assertTrue(haskey(dct, 'a')) + self.assertFalse(haskey(dct, 'b')) + self.assertTrue(haskey(dct, '\U0001f40d')) + + dct2 = ProxyGetItem(dct) + self.assertTrue(haskey(dct2, 'a')) + self.assertFalse(haskey(dct2, 'b')) + + self.assertTrue(haskey(['a', 'b', 'c'], 1)) + + self.assertFalse(haskey(42, 'a')) + self.assertFalse(haskey({}, [])) # unhashable + self.assertFalse(haskey({}, NULL)) + self.assertFalse(haskey([], 1)) + self.assertFalse(haskey([], 'a')) + self.assertFalse(haskey(NULL, 'a')) + + def test_mapping_haskeystring(self): + haskeystring = _testcapi.mapping_haskeystring + dct = {'a': 1, '\U0001f40d': 2} + self.assertTrue(haskeystring(dct, b'a')) + self.assertFalse(haskeystring(dct, b'b')) + self.assertTrue(haskeystring(dct, '\U0001f40d'.encode())) + + dct2 = ProxyGetItem(dct) + self.assertTrue(haskeystring(dct2, b'a')) + self.assertFalse(haskeystring(dct2, b'b')) + + self.assertFalse(haskeystring(42, b'a')) + self.assertFalse(haskeystring({}, b'\xff')) + self.assertFalse(haskeystring({}, NULL)) + self.assertFalse(haskeystring([], b'a')) + self.assertFalse(haskeystring(NULL, b'a')) + + def test_object_setitem(self): + setitem = _testcapi.object_setitem + dct = {} + setitem(dct, 'a', 5) + self.assertEqual(dct, {'a': 5}) + setitem(dct, '\U0001f40d', 8) + self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) + + dct = {} + dct2 = ProxySetItem(dct) + setitem(dct2, 'a', 5) + self.assertEqual(dct, {'a': 5}) + + lst = ['a', 'b', 'c'] + setitem(lst, 1, 'x') + self.assertEqual(lst, ['a', 'x', 'c']) + + self.assertRaises(TypeError, setitem, 42, 'a', 5) + self.assertRaises(TypeError, setitem, {}, [], 5) # unhashable + self.assertRaises(SystemError, setitem, {}, NULL, 5) + self.assertRaises(SystemError, setitem, {}, 'a', NULL) + self.assertRaises(IndexError, setitem, [], 1, 5) + self.assertRaises(TypeError, setitem, [], 'a', 5) + self.assertRaises(TypeError, setitem, (), 1, 5) + self.assertRaises(SystemError, setitem, NULL, 'a', 5) + + def test_mapping_setitemstring(self): + setitemstring = _testcapi.mapping_setitemstring + dct = {} + setitemstring(dct, b'a', 5) + self.assertEqual(dct, {'a': 5}) + setitemstring(dct, '\U0001f40d'.encode(), 8) + self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) + + dct = {} + dct2 = ProxySetItem(dct) + setitemstring(dct2, b'a', 5) + self.assertEqual(dct, {'a': 5}) + + self.assertRaises(TypeError, setitemstring, 42, b'a', 5) + self.assertRaises(UnicodeDecodeError, setitemstring, {}, b'\xff', 5) + self.assertRaises(SystemError, setitemstring, {}, NULL, 5) + self.assertRaises(SystemError, setitemstring, {}, b'a', NULL) + self.assertRaises(TypeError, setitemstring, [], b'a', 5) + self.assertRaises(SystemError, setitemstring, NULL, b'a', 5) + + def test_object_delitem(self): + for delitem in _testcapi.object_delitem, _testcapi.mapping_delitem: + dct = {'a': 1, 'c': 2, '\U0001f40d': 3} + delitem(dct, 'a') + self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) + self.assertRaises(KeyError, delitem, dct, 'b') + delitem(dct, '\U0001f40d') + self.assertEqual(dct, {'c': 2}) + + dct = {'a': 1, 'c': 2} + dct2 = ProxyDelItem(dct) + delitem(dct2, 'a') + self.assertEqual(dct, {'c': 2}) + self.assertRaises(KeyError, delitem, dct2, 'b') + + lst = ['a', 'b', 'c'] + delitem(lst, 1) + self.assertEqual(lst, ['a', 'c']) + + self.assertRaises(TypeError, delitem, 42, 'a') + self.assertRaises(TypeError, delitem, {}, []) # unhashable + self.assertRaises(SystemError, delitem, {}, NULL) + self.assertRaises(IndexError, delitem, [], 1) + self.assertRaises(TypeError, delitem, [], 'a') + self.assertRaises(SystemError, delitem, NULL, 'a') + + def test_mapping_delitemstring(self): + delitemstring = _testcapi.mapping_delitemstring + dct = {'a': 1, 'c': 2, '\U0001f40d': 3} + delitemstring(dct, b'a') + self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) + self.assertRaises(KeyError, delitemstring, dct, b'b') + delitemstring(dct, '\U0001f40d'.encode()) + self.assertEqual(dct, {'c': 2}) + + dct = {'a': 1, 'c': 2} + dct2 = ProxyDelItem(dct) + delitemstring(dct2, b'a') + self.assertEqual(dct, {'c': 2}) + self.assertRaises(KeyError, delitemstring, dct2, b'b') + + self.assertRaises(TypeError, delitemstring, 42, b'a') + self.assertRaises(UnicodeDecodeError, delitemstring, {}, b'\xff') + self.assertRaises(SystemError, delitemstring, {}, NULL) + self.assertRaises(TypeError, delitemstring, [], b'a') + self.assertRaises(SystemError, delitemstring, NULL, b'a') + + def test_mapping_keys_valuesitems(self): + class Mapping1(dict): + def keys(self): + return list(super().keys()) + def values(self): + return list(super().values()) + def items(self): + return list(super().items()) + class Mapping2(dict): + def keys(self): + return tuple(super().keys()) + def values(self): + return tuple(super().values()) + def items(self): + return tuple(super().items()) + dict_obj = {'foo': 1, 'bar': 2, 'spam': 3} + + for mapping in [{}, OrderedDict(), Mapping1(), Mapping2(), + dict_obj, OrderedDict(dict_obj), + Mapping1(dict_obj), Mapping2(dict_obj)]: + self.assertListEqual(_testcapi.mapping_keys(mapping), + list(mapping.keys())) + self.assertListEqual(_testcapi.mapping_values(mapping), + list(mapping.values())) + self.assertListEqual(_testcapi.mapping_items(mapping), + list(mapping.items())) + + def test_mapping_keys_valuesitems_bad_arg(self): + self.assertRaises(AttributeError, _testcapi.mapping_keys, object()) + self.assertRaises(AttributeError, _testcapi.mapping_values, object()) + self.assertRaises(AttributeError, _testcapi.mapping_items, object()) + self.assertRaises(AttributeError, _testcapi.mapping_keys, []) + self.assertRaises(AttributeError, _testcapi.mapping_values, []) + self.assertRaises(AttributeError, _testcapi.mapping_items, []) + self.assertRaises(SystemError, _testcapi.mapping_keys, NULL) + self.assertRaises(SystemError, _testcapi.mapping_values, NULL) + self.assertRaises(SystemError, _testcapi.mapping_items, NULL) + + class BadMapping: + def keys(self): + return None + def values(self): + return None + def items(self): + return None + bad_mapping = BadMapping() + self.assertRaises(TypeError, _testcapi.mapping_keys, bad_mapping) + self.assertRaises(TypeError, _testcapi.mapping_values, bad_mapping) + self.assertRaises(TypeError, _testcapi.mapping_items, bad_mapping) + + def test_sequence_check(self): + check = _testcapi.sequence_check + self.assertFalse(check({1: 2})) + self.assertTrue(check([1, 2])) + self.assertTrue(check((1, 2))) + self.assertTrue(check('abc')) + self.assertTrue(check(b'abc')) + self.assertFalse(check(42)) + self.assertFalse(check(object())) + # CRASHES check(NULL) + + def test_sequence_size(self): + for size in _testcapi.sequence_size, _testcapi.sequence_length: + self.assertEqual(size([1, 2]), 2) + self.assertEqual(size((1, 2)), 2) + self.assertEqual(size('abc'), 3) + self.assertEqual(size(b'abc'), 3) + + self.assertRaises(TypeError, size, {}) + self.assertRaises(TypeError, size, 42) + self.assertRaises(TypeError, size, object()) + self.assertRaises(SystemError, size, NULL) + + def test_sequence_getitem(self): + getitem = _testcapi.sequence_getitem + lst = ['a', 'b', 'c'] + self.assertEqual(getitem(lst, 1), 'b') + self.assertEqual(getitem(lst, -1), 'c') + self.assertRaises(IndexError, getitem, lst, 3) + + self.assertRaises(TypeError, getitem, 42, 1) + self.assertRaises(TypeError, getitem, {}, 1) + self.assertRaises(SystemError, getitem, NULL, 1) + + def test_sequence_concat(self): + concat = _testcapi.sequence_concat + self.assertEqual(concat(['a', 'b'], [1, 2]), ['a', 'b', 1, 2]) + self.assertEqual(concat(('a', 'b'), (1, 2)), ('a', 'b', 1, 2)) + + self.assertRaises(TypeError, concat, [], ()) + self.assertRaises(TypeError, concat, (), []) + self.assertRaises(TypeError, concat, [], 42) + self.assertRaises(TypeError, concat, 42, []) + self.assertRaises(TypeError, concat, 42, 43) + self.assertRaises(SystemError, concat, [], NULL) + self.assertRaises(SystemError, concat, NULL, []) + + def test_sequence_repeat(self): + repeat = _testcapi.sequence_repeat + self.assertEqual(repeat(['a', 'b'], 2), ['a', 'b', 'a', 'b']) + self.assertEqual(repeat(('a', 'b'), 2), ('a', 'b', 'a', 'b')) + self.assertEqual(repeat(['a', 'b'], 0), []) + self.assertEqual(repeat(['a', 'b'], -1), []) + + self.assertRaises(TypeError, repeat, set(), 2) + self.assertRaises(TypeError, repeat, 42, 2) + self.assertRaises(SystemError, repeat, NULL, 2) + + def test_sequence_inplaceconcat(self): + inplaceconcat = _testcapi.sequence_inplaceconcat + lst = ['a', 'b'] + res = inplaceconcat(lst, [1, 2]) + self.assertEqual(res, ['a', 'b', 1, 2]) + self.assertIs(res, lst) + lst = ['a', 'b'] + res = inplaceconcat(lst, (1, 2)) + self.assertEqual(res, ['a', 'b', 1, 2]) + self.assertIs(res, lst) + self.assertEqual(inplaceconcat(('a', 'b'), (1, 2)), ('a', 'b', 1, 2)) + + self.assertRaises(TypeError, inplaceconcat, (), []) + self.assertRaises(TypeError, inplaceconcat, [], 42) + self.assertRaises(TypeError, inplaceconcat, 42, []) + self.assertRaises(TypeError, inplaceconcat, 42, 43) + self.assertRaises(SystemError, inplaceconcat, [], NULL) + self.assertRaises(SystemError, inplaceconcat, NULL, []) + + def test_sequence_inplacerepeat(self): + inplacerepeat = _testcapi.sequence_inplacerepeat + lst = ['a', 'b'] + res = inplacerepeat(lst, 2) + self.assertEqual(res, ['a', 'b', 'a', 'b']) + self.assertIs(res, lst) + self.assertEqual(inplacerepeat(('a', 'b'), 2), ('a', 'b', 'a', 'b')) + self.assertEqual(inplacerepeat(['a', 'b'], 0), []) + self.assertEqual(inplacerepeat(['a', 'b'], -1), []) + + self.assertRaises(TypeError, inplacerepeat, set(), 2) + self.assertRaises(TypeError, inplacerepeat, 42, 2) + self.assertRaises(SystemError, inplacerepeat, NULL, 2) + + def test_sequence_setitem(self): + setitem = _testcapi.sequence_setitem + lst = ['a', 'b', 'c'] + setitem(lst, 1, 'x') + self.assertEqual(lst, ['a', 'x', 'c']) + setitem(lst, -1, 'y') + self.assertEqual(lst, ['a', 'x', 'y']) + + setitem(lst, 0, NULL) + self.assertEqual(lst, ['x', 'y']) + self.assertRaises(IndexError, setitem, lst, 3, 'x') + + self.assertRaises(TypeError, setitem, 42, 1, 'x') + self.assertRaises(TypeError, setitem, {}, 1, 'x') + self.assertRaises(SystemError, setitem, NULL, 1, 'x') + + def test_sequence_delitem(self): + delitem = _testcapi.sequence_delitem + lst = ['a', 'b', 'c'] + delitem(lst, 1) + self.assertEqual(lst, ['a', 'c']) + delitem(lst, -1) + self.assertEqual(lst, ['a']) + self.assertRaises(IndexError, delitem, lst, 3) + + self.assertRaises(TypeError, delitem, 42, 1) + self.assertRaises(TypeError, delitem, {}, 1) + self.assertRaises(SystemError, delitem, NULL, 1) + + def test_sequence_setslice(self): + setslice = _testcapi.sequence_setslice + + # Correct case: + data = [1, 2, 3, 4, 5] + data_copy = data.copy() + + setslice(data, 1, 3, [8, 9]) + data_copy[1:3] = [8, 9] + self.assertEqual(data, data_copy) + self.assertEqual(data, [1, 8, 9, 4, 5]) + + # Custom class: + class Custom: + def __setitem__(self, index, value): + self.index = index + self.value = value + + c = Custom() + setslice(c, 0, 5, 'abc') + self.assertEqual(c.index, slice(0, 5)) + self.assertEqual(c.value, 'abc') + + # Immutable sequences must raise: + bad_seq1 = (1, 2, 3, 4) + self.assertRaises(TypeError, setslice, bad_seq1, 1, 3, (8, 9)) + self.assertEqual(bad_seq1, (1, 2, 3, 4)) + + bad_seq2 = 'abcd' + self.assertRaises(TypeError, setslice, bad_seq2, 1, 3, 'xy') + self.assertEqual(bad_seq2, 'abcd') + + # Not a sequence: + self.assertRaises(TypeError, setslice, object(), 1, 3, 'xy') + self.assertRaises(SystemError, setslice, NULL, 1, 3, 'xy') + + data_copy = data.copy() + setslice(data_copy, 1, 3, NULL) + self.assertEqual(data_copy, [1, 4, 5]) + + def test_sequence_delslice(self): + delslice = _testcapi.sequence_delslice + + # Correct case: + data = [1, 2, 3, 4, 5] + data_copy = data.copy() + + delslice(data, 1, 3) + del data_copy[1:3] + self.assertEqual(data, data_copy) + self.assertEqual(data, [1, 4, 5]) + + # Custom class: + class Custom: + def __delitem__(self, index): + self.index = index + + c = Custom() + delslice(c, 0, 5) + self.assertEqual(c.index, slice(0, 5)) + + # Immutable sequences must raise: + bad_seq1 = (1, 2, 3, 4) + self.assertRaises(TypeError, delslice, bad_seq1, 1, 3) + self.assertEqual(bad_seq1, (1, 2, 3, 4)) + + bad_seq2 = 'abcd' + self.assertRaises(TypeError, delslice, bad_seq2, 1, 3) + self.assertEqual(bad_seq2, 'abcd') + + # Not a sequence: + self.assertRaises(TypeError, delslice, object(), 1, 3) + self.assertRaises(SystemError, delslice, NULL, 1, 3) + + mapping = {1: 'a', 2: 'b', 3: 'c'} + self.assertRaises(KeyError, delslice, mapping, 1, 3) + self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'}) + + def test_sequence_count(self): + count = _testcapi.sequence_count + + lst = ['a', 'b', 'a'] + self.assertEqual(count(lst, 'a'), 2) + self.assertEqual(count(lst, 'c'), 0) + self.assertEqual(count(iter(lst), 'a'), 2) + self.assertEqual(count(iter(lst), 'c'), 0) + self.assertEqual(count({'a': 2}, 'a'), 1) + + self.assertRaises(TypeError, count, 42, 'a') + self.assertRaises(SystemError, count, [], NULL) + self.assertRaises(SystemError, count, [1], NULL) + self.assertRaises(SystemError, count, NULL, 'a') + + def test_sequence_contains(self): + contains = _testcapi.sequence_contains + + lst = ['a', 'b', 'a'] + self.assertEqual(contains(lst, 'a'), 1) + self.assertEqual(contains(lst, 'c'), 0) + self.assertEqual(contains(iter(lst), 'a'), 1) + self.assertEqual(contains(iter(lst), 'c'), 0) + self.assertEqual(contains({'a': 2}, 'a'), 1) + + # XXX Only for empty sequences. Should be SystemError? + self.assertEqual(contains([], NULL), 0) + + self.assertRaises(TypeError, contains, 42, 'a') + self.assertRaises(SystemError, contains, [1], NULL) + # CRASHES contains({}, NULL) + # CRASHES contains(set(), NULL) + # CRASHES contains(NULL, 'a') + + def test_sequence_index(self): + index = _testcapi.sequence_index + + lst = ['a', 'b', 'a'] + self.assertEqual(index(lst, 'a'), 0) + self.assertEqual(index(lst, 'b'), 1) + self.assertRaises(ValueError, index, lst, 'c') + self.assertEqual(index(iter(lst), 'a'), 0) + self.assertEqual(index(iter(lst), 'b'), 1) + self.assertRaises(ValueError, index, iter(lst), 'c') + dct = {'a': 2, 'b': 3} + self.assertEqual(index(dct, 'a'), 0) + self.assertEqual(index(dct, 'b'), 1) + self.assertRaises(ValueError, index, dct, 'c') + + self.assertRaises(TypeError, index, 42, 'a') + self.assertRaises(SystemError, index, [], NULL) + self.assertRaises(SystemError, index, [1], NULL) + self.assertRaises(SystemError, index, NULL, 'a') + + def test_sequence_list(self): + xlist = _testcapi.sequence_list + self.assertEqual(xlist(['a', 'b', 'c']), ['a', 'b', 'c']) + self.assertEqual(xlist(('a', 'b', 'c')), ['a', 'b', 'c']) + self.assertEqual(xlist(iter(['a', 'b', 'c'])), ['a', 'b', 'c']) + self.assertEqual(xlist(gen()), ['a', 'b', 'c']) + + self.assertRaises(TypeError, xlist, 42) + self.assertRaises(SystemError, xlist, NULL) + + def test_sequence_tuple(self): + xtuple = _testcapi.sequence_tuple + self.assertEqual(xtuple(['a', 'b', 'c']), ('a', 'b', 'c')) + self.assertEqual(xtuple(('a', 'b', 'c')), ('a', 'b', 'c')) + self.assertEqual(xtuple(iter(['a', 'b', 'c'])), ('a', 'b', 'c')) + self.assertEqual(xtuple(gen()), ('a', 'b', 'c')) + + self.assertRaises(TypeError, xtuple, 42) + self.assertRaises(SystemError, xtuple, NULL) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_capi/test_dict.py b/Lib/test/test_capi/test_dict.py new file mode 100644 index 00000000000000..0717708fcce8ef --- /dev/null +++ b/Lib/test/test_capi/test_dict.py @@ -0,0 +1,378 @@ +import unittest +import sys +from collections import OrderedDict, UserDict +from types import MappingProxyType +from test import support +from test.support import import_helper +import _testcapi + + +NULL = None + +class DictSubclass(dict): + def __getitem__(self, key): + raise RuntimeError('do not get evil') + def __setitem__(self, key, value): + raise RuntimeError('do not set evil') + def __delitem__(self, key): + raise RuntimeError('do not del evil') + +def gen(): + yield 'a' + yield 'b' + yield 'c' + + +class CAPITest(unittest.TestCase): + + def test_dict_check(self): + check = _testcapi.dict_check + self.assertTrue(check({1: 2})) + self.assertTrue(check(OrderedDict({1: 2}))) + self.assertFalse(check(UserDict({1: 2}))) + self.assertFalse(check([1, 2])) + self.assertFalse(check(object())) + #self.assertFalse(check(NULL)) + + def test_dict_checkexact(self): + check = _testcapi.dict_checkexact + self.assertTrue(check({1: 2})) + self.assertFalse(check(OrderedDict({1: 2}))) + self.assertFalse(check(UserDict({1: 2}))) + self.assertFalse(check([1, 2])) + self.assertFalse(check(object())) + #self.assertFalse(check(NULL)) + + def test_dict_new(self): + dict_new = _testcapi.dict_new + dct = dict_new() + self.assertEqual(dct, {}) + self.assertIs(type(dct), dict) + dct2 = dict_new() + self.assertIsNot(dct2, dct) + + def test_dictproxy_new(self): + dictproxy_new = _testcapi.dictproxy_new + for dct in {1: 2}, OrderedDict({1: 2}), UserDict({1: 2}): + proxy = dictproxy_new(dct) + self.assertIs(type(proxy), MappingProxyType) + self.assertEqual(proxy, dct) + with self.assertRaises(TypeError): + proxy[1] = 3 + self.assertEqual(proxy[1], 2) + dct[1] = 4 + self.assertEqual(proxy[1], 4) + + self.assertRaises(TypeError, dictproxy_new, []) + self.assertRaises(TypeError, dictproxy_new, 42) + # CRASHES dictproxy_new(NULL) + + def test_dict_copy(self): + copy = _testcapi.dict_copy + for dct in {1: 2}, OrderedDict({1: 2}): + dct_copy = copy(dct) + self.assertIs(type(dct_copy), dict) + self.assertEqual(dct_copy, dct) + + self.assertRaises(SystemError, copy, UserDict()) + self.assertRaises(SystemError, copy, []) + self.assertRaises(SystemError, copy, 42) + self.assertRaises(SystemError, copy, NULL) + + def test_dict_clear(self): + clear = _testcapi.dict_clear + dct = {1: 2} + clear(dct) + self.assertEqual(dct, {}) + + # NOTE: It is not safe to call it with OrderedDict. + + # Has no effect for non-dicts. + dct = UserDict({1: 2}) + clear(dct) + self.assertEqual(dct, {1: 2}) + lst = [1, 2] + clear(lst) + self.assertEqual(lst, [1, 2]) + clear(object()) + + # CRASHES? clear(NULL) + + def test_dict_size(self): + size = _testcapi.dict_size + self.assertEqual(size({1: 2}), 1) + self.assertEqual(size(OrderedDict({1: 2})), 1) + + self.assertRaises(SystemError, size, UserDict()) + self.assertRaises(SystemError, size, []) + self.assertRaises(SystemError, size, 42) + self.assertRaises(SystemError, size, object()) + self.assertRaises(SystemError, size, NULL) + + def test_dict_getitem(self): + getitem = _testcapi.dict_getitem + dct = {'a': 1, '\U0001f40d': 2} + self.assertEqual(getitem(dct, 'a'), 1) + self.assertIs(getitem(dct, 'b'), KeyError) + self.assertEqual(getitem(dct, '\U0001f40d'), 2) + + dct2 = DictSubclass(dct) + self.assertEqual(getitem(dct2, 'a'), 1) + self.assertIs(getitem(dct2, 'b'), KeyError) + + self.assertIs(getitem({}, []), KeyError) # unhashable + self.assertIs(getitem(42, 'a'), KeyError) + self.assertIs(getitem([1], 0), KeyError) + # CRASHES getitem({}, NULL) + # CRASHES getitem(NULL, 'a') + + def test_dict_getitemstring(self): + getitemstring = _testcapi.dict_getitemstring + dct = {'a': 1, '\U0001f40d': 2} + self.assertEqual(getitemstring(dct, b'a'), 1) + self.assertIs(getitemstring(dct, b'b'), KeyError) + self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2) + + dct2 = DictSubclass(dct) + self.assertEqual(getitemstring(dct2, b'a'), 1) + self.assertIs(getitemstring(dct2, b'b'), KeyError) + + self.assertIs(getitemstring({}, b'\xff'), KeyError) + self.assertIs(getitemstring(42, b'a'), KeyError) + self.assertIs(getitemstring([], b'a'), KeyError) + # CRASHES getitemstring({}, NULL) + # CRASHES getitemstring(NULL, b'a') + + def test_dict_getitemwitherror(self): + getitem = _testcapi.dict_getitemwitherror + dct = {'a': 1, '\U0001f40d': 2} + self.assertEqual(getitem(dct, 'a'), 1) + self.assertIs(getitem(dct, 'b'), KeyError) + self.assertEqual(getitem(dct, '\U0001f40d'), 2) + + dct2 = DictSubclass(dct) + self.assertEqual(getitem(dct2, 'a'), 1) + self.assertIs(getitem(dct2, 'b'), KeyError) + + self.assertRaises(SystemError, getitem, 42, 'a') + self.assertRaises(TypeError, getitem, {}, []) # unhashable + self.assertRaises(SystemError, getitem, [], 1) + self.assertRaises(SystemError, getitem, [], 'a') + # CRASHES getitem({}, NULL) + # CRASHES getitem(NULL, 'a') + + def test_dict_contains(self): + contains = _testcapi.dict_contains + dct = {'a': 1, '\U0001f40d': 2} + self.assertTrue(contains(dct, 'a')) + self.assertFalse(contains(dct, 'b')) + self.assertTrue(contains(dct, '\U0001f40d')) + + dct2 = DictSubclass(dct) + self.assertTrue(contains(dct2, 'a')) + self.assertFalse(contains(dct2, 'b')) + + self.assertRaises(TypeError, contains, {}, []) # unhashable + # CRASHES contains({}, NULL) + # CRASHES contains(UserDict(), 'a') + # CRASHES contains(42, 'a') + # CRASHES contains(NULL, 'a') + + def test_dict_setitem(self): + setitem = _testcapi.dict_setitem + dct = {} + setitem(dct, 'a', 5) + self.assertEqual(dct, {'a': 5}) + setitem(dct, '\U0001f40d', 8) + self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) + + dct2 = DictSubclass() + setitem(dct2, 'a', 5) + self.assertEqual(dct2, {'a': 5}) + + self.assertRaises(TypeError, setitem, {}, [], 5) # unhashable + self.assertRaises(SystemError, setitem, UserDict(), 'a', 5) + self.assertRaises(SystemError, setitem, [1], 0, 5) + self.assertRaises(SystemError, setitem, 42, 'a', 5) + # CRASHES setitem({}, NULL, 5) + # CRASHES setitem({}, 'a', NULL) + # CRASHES setitem(NULL, 'a', 5) + + def test_dict_setitemstring(self): + setitemstring = _testcapi.dict_setitemstring + dct = {} + setitemstring(dct, b'a', 5) + self.assertEqual(dct, {'a': 5}) + setitemstring(dct, '\U0001f40d'.encode(), 8) + self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) + + dct2 = DictSubclass() + setitemstring(dct2, b'a', 5) + self.assertEqual(dct2, {'a': 5}) + + self.assertRaises(UnicodeDecodeError, setitemstring, {}, b'\xff', 5) + self.assertRaises(SystemError, setitemstring, UserDict(), b'a', 5) + self.assertRaises(SystemError, setitemstring, 42, b'a', 5) + # CRASHES setitemstring({}, NULL, 5) + # CRASHES setitemstring({}, b'a', NULL) + # CRASHES setitemstring(NULL, b'a', 5) + + def test_dict_delitem(self): + delitem = _testcapi.dict_delitem + dct = {'a': 1, 'c': 2, '\U0001f40d': 3} + delitem(dct, 'a') + self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) + self.assertRaises(KeyError, delitem, dct, 'b') + delitem(dct, '\U0001f40d') + self.assertEqual(dct, {'c': 2}) + + dct2 = DictSubclass({'a': 1, 'c': 2}) + delitem(dct2, 'a') + self.assertEqual(dct2, {'c': 2}) + self.assertRaises(KeyError, delitem, dct2, 'b') + + self.assertRaises(TypeError, delitem, {}, []) # unhashable + self.assertRaises(SystemError, delitem, UserDict({'a': 1}), 'a') + self.assertRaises(SystemError, delitem, [1], 0) + self.assertRaises(SystemError, delitem, 42, 'a') + # CRASHES delitem({}, NULL) + # CRASHES delitem(NULL, 'a') + + def test_dict_delitemstring(self): + delitemstring = _testcapi.dict_delitemstring + dct = {'a': 1, 'c': 2, '\U0001f40d': 3} + delitemstring(dct, b'a') + self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) + self.assertRaises(KeyError, delitemstring, dct, b'b') + delitemstring(dct, '\U0001f40d'.encode()) + self.assertEqual(dct, {'c': 2}) + + dct2 = DictSubclass({'a': 1, 'c': 2}) + delitemstring(dct2, b'a') + self.assertEqual(dct2, {'c': 2}) + self.assertRaises(KeyError, delitemstring, dct2, b'b') + + self.assertRaises(UnicodeDecodeError, delitemstring, {}, b'\xff') + self.assertRaises(SystemError, delitemstring, UserDict({'a': 1}), b'a') + self.assertRaises(SystemError, delitemstring, 42, b'a') + # CRASHES delitemstring({}, NULL) + # CRASHES delitemstring(NULL, b'a') + + def test_dict_setdefault(self): + setdefault = _testcapi.dict_setdefault + dct = {} + self.assertEqual(setdefault(dct, 'a', 5), 5) + self.assertEqual(dct, {'a': 5}) + self.assertEqual(setdefault(dct, 'a', 8), 5) + self.assertEqual(dct, {'a': 5}) + + dct2 = DictSubclass() + self.assertEqual(setdefault(dct2, 'a', 5), 5) + self.assertEqual(dct2, {'a': 5}) + self.assertEqual(setdefault(dct2, 'a', 8), 5) + self.assertEqual(dct2, {'a': 5}) + + self.assertRaises(TypeError, setdefault, {}, [], 5) # unhashable + self.assertRaises(SystemError, setdefault, UserDict(), 'a', 5) + self.assertRaises(SystemError, setdefault, [1], 0, 5) + self.assertRaises(SystemError, setdefault, 42, 'a', 5) + # CRASHES setdefault({}, NULL, 5) + # CRASHES setdefault({}, 'a', NULL) + # CRASHES setdefault(NULL, 'a', 5) + + def test_mapping_keys_valuesitems(self): + class BadMapping(dict): + def keys(self): + return None + def values(self): + return None + def items(self): + return None + dict_obj = {'foo': 1, 'bar': 2, 'spam': 3} + for mapping in [dict_obj, DictSubclass(dict_obj), BadMapping(dict_obj)]: + self.assertListEqual(_testcapi.dict_keys(mapping), + list(dict_obj.keys())) + self.assertListEqual(_testcapi.dict_values(mapping), + list(dict_obj.values())) + self.assertListEqual(_testcapi.dict_items(mapping), + list(dict_obj.items())) + + def test_dict_keys_valuesitems_bad_arg(self): + for mapping in UserDict(), [], object(): + self.assertRaises(SystemError, _testcapi.dict_keys, mapping) + self.assertRaises(SystemError, _testcapi.dict_values, mapping) + self.assertRaises(SystemError, _testcapi.dict_items, mapping) + + def test_dict_next(self): + dict_next = _testcapi.dict_next + self.assertIsNone(dict_next({}, 0)) + dct = {'a': 1, 'b': 2, 'c': 3} + pos = 0 + pairs = [] + while True: + res = dict_next(dct, pos) + if res is None: + break + rc, pos, key, value = res + self.assertEqual(rc, 1) + pairs.append((key, value)) + self.assertEqual(pairs, list(dct.items())) + + # CRASHES dict_next(NULL, 0) + + def test_dict_update(self): + update = _testcapi.dict_update + for cls1 in dict, DictSubclass: + for cls2 in dict, DictSubclass, UserDict: + dct = cls1({'a': 1, 'b': 2}) + update(dct, cls2({'b': 3, 'c': 4})) + self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) + + self.assertRaises(AttributeError, update, {}, []) + self.assertRaises(AttributeError, update, {}, 42) + self.assertRaises(SystemError, update, UserDict(), {}) + self.assertRaises(SystemError, update, 42, {}) + self.assertRaises(SystemError, update, {}, NULL) + self.assertRaises(SystemError, update, NULL, {}) + + def test_dict_merge(self): + merge = _testcapi.dict_merge + for cls1 in dict, DictSubclass: + for cls2 in dict, DictSubclass, UserDict: + dct = cls1({'a': 1, 'b': 2}) + merge(dct, cls2({'b': 3, 'c': 4}), 0) + self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4}) + dct = cls1({'a': 1, 'b': 2}) + merge(dct, cls2({'b': 3, 'c': 4}), 1) + self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) + + self.assertRaises(AttributeError, merge, {}, [], 0) + self.assertRaises(AttributeError, merge, {}, 42, 0) + self.assertRaises(SystemError, merge, UserDict(), {}, 0) + self.assertRaises(SystemError, merge, 42, {}, 0) + self.assertRaises(SystemError, merge, {}, NULL, 0) + self.assertRaises(SystemError, merge, NULL, {}, 0) + + def test_dict_mergefromseq2(self): + mergefromseq2 = _testcapi.dict_mergefromseq2 + for cls1 in dict, DictSubclass: + for cls2 in list, iter: + dct = cls1({'a': 1, 'b': 2}) + mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 0) + self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4}) + dct = cls1({'a': 1, 'b': 2}) + mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 1) + self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) + + self.assertRaises(ValueError, mergefromseq2, {}, [(1,)], 0) + self.assertRaises(ValueError, mergefromseq2, {}, [(1, 2, 3)], 0) + self.assertRaises(TypeError, mergefromseq2, {}, [1], 0) + self.assertRaises(TypeError, mergefromseq2, {}, 42, 0) + # CRASHES mergefromseq2(UserDict(), [], 0) + # CRASHES mergefromseq2(42, [], 0) + # CRASHES mergefromseq2({}, NULL, 0) + # CRASHES mergefromseq2(NULL, {}, 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 3d494975c71e2b..2a71ac533d9e07 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -301,137 +301,6 @@ def test_getitem_with_error(self): def test_buildvalue_N(self): _testcapi.test_buildvalue_N() - def test_mapping_keys_values_items(self): - class Mapping1(dict): - def keys(self): - return list(super().keys()) - def values(self): - return list(super().values()) - def items(self): - return list(super().items()) - class Mapping2(dict): - def keys(self): - return tuple(super().keys()) - def values(self): - return tuple(super().values()) - def items(self): - return tuple(super().items()) - dict_obj = {'foo': 1, 'bar': 2, 'spam': 3} - - for mapping in [{}, OrderedDict(), Mapping1(), Mapping2(), - dict_obj, OrderedDict(dict_obj), - Mapping1(dict_obj), Mapping2(dict_obj)]: - self.assertListEqual(_testcapi.get_mapping_keys(mapping), - list(mapping.keys())) - self.assertListEqual(_testcapi.get_mapping_values(mapping), - list(mapping.values())) - self.assertListEqual(_testcapi.get_mapping_items(mapping), - list(mapping.items())) - - def test_mapping_keys_values_items_bad_arg(self): - self.assertRaises(AttributeError, _testcapi.get_mapping_keys, None) - self.assertRaises(AttributeError, _testcapi.get_mapping_values, None) - self.assertRaises(AttributeError, _testcapi.get_mapping_items, None) - - class BadMapping: - def keys(self): - return None - def values(self): - return None - def items(self): - return None - bad_mapping = BadMapping() - self.assertRaises(TypeError, _testcapi.get_mapping_keys, bad_mapping) - self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping) - self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping) - - def test_mapping_has_key(self): - dct = {'a': 1} - self.assertTrue(_testcapi.mapping_has_key(dct, 'a')) - self.assertFalse(_testcapi.mapping_has_key(dct, 'b')) - - class SubDict(dict): - pass - - dct2 = SubDict({'a': 1}) - self.assertTrue(_testcapi.mapping_has_key(dct2, 'a')) - self.assertFalse(_testcapi.mapping_has_key(dct2, 'b')) - - def test_sequence_set_slice(self): - # Correct case: - data = [1, 2, 3, 4, 5] - data_copy = data.copy() - - _testcapi.sequence_set_slice(data, 1, 3, [8, 9]) - data_copy[1:3] = [8, 9] - self.assertEqual(data, data_copy) - self.assertEqual(data, [1, 8, 9, 4, 5]) - - # Custom class: - class Custom: - def __setitem__(self, index, value): - self.index = index - self.value = value - - c = Custom() - _testcapi.sequence_set_slice(c, 0, 5, 'abc') - self.assertEqual(c.index, slice(0, 5)) - self.assertEqual(c.value, 'abc') - - # Immutable sequences must raise: - bad_seq1 = (1, 2, 3, 4) - with self.assertRaises(TypeError): - _testcapi.sequence_set_slice(bad_seq1, 1, 3, (8, 9)) - self.assertEqual(bad_seq1, (1, 2, 3, 4)) - - bad_seq2 = 'abcd' - with self.assertRaises(TypeError): - _testcapi.sequence_set_slice(bad_seq2, 1, 3, 'xy') - self.assertEqual(bad_seq2, 'abcd') - - # Not a sequence: - with self.assertRaises(TypeError): - _testcapi.sequence_set_slice(None, 1, 3, 'xy') - - def test_sequence_del_slice(self): - # Correct case: - data = [1, 2, 3, 4, 5] - data_copy = data.copy() - - _testcapi.sequence_del_slice(data, 1, 3) - del data_copy[1:3] - self.assertEqual(data, data_copy) - self.assertEqual(data, [1, 4, 5]) - - # Custom class: - class Custom: - def __delitem__(self, index): - self.index = index - - c = Custom() - _testcapi.sequence_del_slice(c, 0, 5) - self.assertEqual(c.index, slice(0, 5)) - - # Immutable sequences must raise: - bad_seq1 = (1, 2, 3, 4) - with self.assertRaises(TypeError): - _testcapi.sequence_del_slice(bad_seq1, 1, 3) - self.assertEqual(bad_seq1, (1, 2, 3, 4)) - - bad_seq2 = 'abcd' - with self.assertRaises(TypeError): - _testcapi.sequence_del_slice(bad_seq2, 1, 3) - self.assertEqual(bad_seq2, 'abcd') - - # Not a sequence: - with self.assertRaises(TypeError): - _testcapi.sequence_del_slice(None, 1, 3) - - mapping = {1: 'a', 2: 'b', 3: 'c'} - with self.assertRaises(KeyError): - _testcapi.sequence_del_slice(mapping, 1, 3) - self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'}) - @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), 'need _testcapi.negative_refcount') def test_negative_refcount(self): diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index d7a48e55b10180..7a159760e98e25 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -455,8 +455,8 @@ def __init__(self): self.attr = 1 a = A() - self.assertEqual(_testcapi.hasattr_string(a, "attr"), True) - self.assertEqual(_testcapi.hasattr_string(a, "noattr"), False) + self.assertEqual(_testcapi.object_hasattrstring(a, b"attr"), 1) + self.assertEqual(_testcapi.object_hasattrstring(a, b"noattr"), 0) self.assertIsNone(sys.exception()) def testDel(self): diff --git a/Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst b/Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst new file mode 100644 index 00000000000000..dd6becf6b00130 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst @@ -0,0 +1,2 @@ +Add the C API test for functions in the Mapping Protocol, the Sequence +Protocol and some functions in the Object Protocol. diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 0fc7955cd9b7c2..3e01e25056dfa8 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -168,7 +168,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/abstract.c b/Modules/_testcapi/abstract.c new file mode 100644 index 00000000000000..9715efb821740b --- /dev/null +++ b/Modules/_testcapi/abstract.c @@ -0,0 +1,535 @@ +#include // ptrdiff_t + +#define PY_SSIZE_T_CLEAN +#include "parts.h" + +#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); + +#define RETURN_INT(value) do { \ + int _ret = (value); \ + if (_ret == -1) { \ + return NULL; \ + } \ + return PyLong_FromLong(_ret); \ + } while (0) + +#define RETURN_SIZE(value) do { \ + Py_ssize_t _ret = (value); \ + if (_ret == -1) { \ + return NULL; \ + } \ + return PyLong_FromSsize_t(_ret); \ + } while (0) + + +static PyObject * +object_getattr(PyObject *self, PyObject *args) +{ + PyObject *obj, *attr_name; + if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(attr_name); + return PyObject_GetAttr(obj, attr_name); +} + +static PyObject * +object_getattrstring(PyObject *self, PyObject *args) +{ + PyObject *obj; + const char *attr_name; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) { + return NULL; + } + NULLABLE(obj); + return PyObject_GetAttrString(obj, attr_name); +} + +static PyObject * +object_hasattr(PyObject *self, PyObject *args) +{ + PyObject *obj, *attr_name; + if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(attr_name); + return PyLong_FromLong(PyObject_HasAttr(obj, attr_name)); +} + +static PyObject * +object_hasattrstring(PyObject *self, PyObject *args) +{ + PyObject *obj; + const char *attr_name; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) { + return NULL; + } + NULLABLE(obj); + return PyLong_FromLong(PyObject_HasAttrString(obj, attr_name)); +} + +static PyObject * +object_setattr(PyObject *self, PyObject *args) +{ + PyObject *obj, *attr_name, *value; + if (!PyArg_ParseTuple(args, "OOO", &obj, &attr_name, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(attr_name); + NULLABLE(value); + RETURN_INT(PyObject_SetAttr(obj, attr_name, value)); +} + +static PyObject * +object_setattrstring(PyObject *self, PyObject *args) +{ + PyObject *obj, *value; + const char *attr_name; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#O", &obj, &attr_name, &size, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyObject_SetAttrString(obj, attr_name, value)); +} + +static PyObject * +object_delattr(PyObject *self, PyObject *args) +{ + PyObject *obj, *attr_name; +if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(attr_name); + RETURN_INT(PyObject_DelAttr(obj, attr_name)); +} + +static PyObject * +object_delattrstring(PyObject *self, PyObject *args) +{ + PyObject *obj; + const char *attr_name; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) { + return NULL; + } + NULLABLE(obj); + RETURN_INT(PyObject_DelAttrString(obj, attr_name)); +} + + +static PyObject * +mapping_check(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyMapping_Check(obj)); +} + +static PyObject * +mapping_size(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyMapping_Size(obj)); +} + +static PyObject * +mapping_length(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyMapping_Length(obj)); +} + +static PyObject * +object_getitem(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key; + if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + return PyObject_GetItem(mapping, key); +} + +static PyObject * +mapping_getitemstring(PyObject *self, PyObject *args) +{ + PyObject *mapping; + const char *key; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) { + return NULL; + } + NULLABLE(mapping); + return PyMapping_GetItemString(mapping, key); +} + +static PyObject * +mapping_haskey(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key; + if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + return PyLong_FromLong(PyMapping_HasKey(mapping, key)); +} + +static PyObject * +mapping_haskeystring(PyObject *self, PyObject *args) +{ + PyObject *mapping; + const char *key; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) { + return NULL; + } + NULLABLE(mapping); + return PyLong_FromLong(PyMapping_HasKeyString(mapping, key)); +} + +static PyObject * +object_setitem(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key, *value; + if (!PyArg_ParseTuple(args, "OOO", &mapping, &key, &value)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + NULLABLE(value); + RETURN_INT(PyObject_SetItem(mapping, key, value)); +} + +static PyObject * +mapping_setitemstring(PyObject *self, PyObject *args) +{ + PyObject *mapping, *value; + const char *key; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#O", &mapping, &key, &size, &value)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(value); + RETURN_INT(PyMapping_SetItemString(mapping, key, value)); +} + +static PyObject * +object_delitem(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key; + if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + RETURN_INT(PyObject_DelItem(mapping, key)); +} + +static PyObject * +mapping_delitem(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key; + if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + RETURN_INT(PyMapping_DelItem(mapping, key)); +} + +static PyObject * +mapping_delitemstring(PyObject *self, PyObject *args) +{ + PyObject *mapping; + const char *key; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) { + return NULL; + } + NULLABLE(mapping); + RETURN_INT(PyMapping_DelItemString(mapping, key)); +} + +static PyObject * +mapping_keys(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyMapping_Keys(obj); +} + +static PyObject * +mapping_values(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyMapping_Values(obj); +} + +static PyObject * +mapping_items(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyMapping_Items(obj); +} + + +static PyObject * +sequence_check(PyObject* self, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PySequence_Check(obj)); +} + +static PyObject * +sequence_size(PyObject* self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PySequence_Size(obj)); +} + +static PyObject * +sequence_length(PyObject* self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PySequence_Length(obj)); +} + +static PyObject * +sequence_concat(PyObject *self, PyObject *args) +{ + PyObject *seq1, *seq2; + if (!PyArg_ParseTuple(args, "OO", &seq1, &seq2)) { + return NULL; + } + NULLABLE(seq1); + NULLABLE(seq2); + + return PySequence_Concat(seq1, seq2); +} + +static PyObject * +sequence_repeat(PyObject *self, PyObject *args) +{ + PyObject *seq; + Py_ssize_t count; + if (!PyArg_ParseTuple(args, "On", &seq, &count)) { + return NULL; + } + NULLABLE(seq); + + return PySequence_Repeat(seq, count); +} + +static PyObject * +sequence_inplaceconcat(PyObject *self, PyObject *args) +{ + PyObject *seq1, *seq2; + if (!PyArg_ParseTuple(args, "OO", &seq1, &seq2)) { + return NULL; + } + NULLABLE(seq1); + NULLABLE(seq2); + + return PySequence_InPlaceConcat(seq1, seq2); +} + +static PyObject * +sequence_inplacerepeat(PyObject *self, PyObject *args) +{ + PyObject *seq; + Py_ssize_t count; + if (!PyArg_ParseTuple(args, "On", &seq, &count)) { + return NULL; + } + NULLABLE(seq); + + return PySequence_InPlaceRepeat(seq, count); +} + +static PyObject * +sequence_getitem(PyObject *self, PyObject *args) +{ + PyObject *seq; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &seq, &i)) { + return NULL; + } + NULLABLE(seq); + + return PySequence_GetItem(seq, i); +} + +static PyObject * +sequence_setitem(PyObject *self, PyObject *args) +{ + Py_ssize_t i; + PyObject *seq, *val; + if (!PyArg_ParseTuple(args, "OnO", &seq, &i, &val)) { + return NULL; + } + NULLABLE(seq); + NULLABLE(val); + + RETURN_INT(PySequence_SetItem(seq, i, val)); +} + + +static PyObject * +sequence_delitem(PyObject *self, PyObject *args) +{ + Py_ssize_t i; + PyObject *seq; + if (!PyArg_ParseTuple(args, "On", &seq, &i)) { + return NULL; + } + NULLABLE(seq); + + RETURN_INT(PySequence_DelItem(seq, i)); +} + +static PyObject * +sequence_setslice(PyObject* self, PyObject *args) +{ + PyObject *sequence, *obj; + Py_ssize_t i1, i2; + if (!PyArg_ParseTuple(args, "OnnO", &sequence, &i1, &i2, &obj)) { + return NULL; + } + NULLABLE(sequence); + NULLABLE(obj); + + RETURN_INT(PySequence_SetSlice(sequence, i1, i2, obj)); +} + +static PyObject * +sequence_delslice(PyObject *self, PyObject *args) +{ + PyObject *sequence; + Py_ssize_t i1, i2; + if (!PyArg_ParseTuple(args, "Onn", &sequence, &i1, &i2)) { + return NULL; + } + NULLABLE(sequence); + + RETURN_INT(PySequence_DelSlice(sequence, i1, i2)); +} + +static PyObject * +sequence_count(PyObject *self, PyObject *args) +{ + PyObject *seq, *value; + if (!PyArg_ParseTuple(args, "OO", &seq, &value)) { + return NULL; + } + NULLABLE(seq); + NULLABLE(value); + + RETURN_SIZE(PySequence_Count(seq, value)); +} + +static PyObject * +sequence_contains(PyObject *self, PyObject *args) +{ + PyObject *seq, *value; + if (!PyArg_ParseTuple(args, "OO", &seq, &value)) { + return NULL; + } + NULLABLE(seq); + NULLABLE(value); + + RETURN_INT(PySequence_Contains(seq, value)); +} + +static PyObject * +sequence_index(PyObject *self, PyObject *args) +{ + PyObject *seq, *value; + if (!PyArg_ParseTuple(args, "OO", &seq, &value)) { + return NULL; + } + NULLABLE(seq); + NULLABLE(value); + + RETURN_SIZE(PySequence_Index(seq, value)); +} + +static PyObject * +sequence_list(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PySequence_List(obj); +} + +static PyObject * +sequence_tuple(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PySequence_Tuple(obj); +} + + +static PyMethodDef test_methods[] = { + {"object_getattr", object_getattr, METH_VARARGS}, + {"object_getattrstring", object_getattrstring, METH_VARARGS}, + {"object_hasattr", object_hasattr, METH_VARARGS}, + {"object_hasattrstring", object_hasattrstring, METH_VARARGS}, + {"object_setattr", object_setattr, METH_VARARGS}, + {"object_setattrstring", object_setattrstring, METH_VARARGS}, + {"object_delattr", object_delattr, METH_VARARGS}, + {"object_delattrstring", object_delattrstring, METH_VARARGS}, + + {"mapping_check", mapping_check, METH_O}, + {"mapping_size", mapping_size, METH_O}, + {"mapping_length", mapping_length, METH_O}, + {"object_getitem", object_getitem, METH_VARARGS}, + {"mapping_getitemstring", mapping_getitemstring, METH_VARARGS}, + {"mapping_haskey", mapping_haskey, METH_VARARGS}, + {"mapping_haskeystring", mapping_haskeystring, METH_VARARGS}, + {"object_setitem", object_setitem, METH_VARARGS}, + {"mapping_setitemstring", mapping_setitemstring, METH_VARARGS}, + {"object_delitem", object_delitem, METH_VARARGS}, + {"mapping_delitem", mapping_delitem, METH_VARARGS}, + {"mapping_delitemstring", mapping_delitemstring, METH_VARARGS}, + {"mapping_keys", mapping_keys, METH_O}, + {"mapping_values", mapping_values, METH_O}, + {"mapping_items", mapping_items, METH_O}, + + {"sequence_check", sequence_check, METH_O}, + {"sequence_size", sequence_size, METH_O}, + {"sequence_length", sequence_length, METH_O}, + {"sequence_concat", sequence_concat, METH_VARARGS}, + {"sequence_repeat", sequence_repeat, METH_VARARGS}, + {"sequence_inplaceconcat", sequence_inplaceconcat, METH_VARARGS}, + {"sequence_inplacerepeat", sequence_inplacerepeat, METH_VARARGS}, + {"sequence_getitem", sequence_getitem, METH_VARARGS}, + {"sequence_setitem", sequence_setitem, METH_VARARGS}, + {"sequence_delitem", sequence_delitem, METH_VARARGS}, + {"sequence_setslice", sequence_setslice, METH_VARARGS}, + {"sequence_delslice", sequence_delslice, METH_VARARGS}, + {"sequence_count", sequence_count, METH_VARARGS}, + {"sequence_contains", sequence_contains, METH_VARARGS}, + {"sequence_index", sequence_index, METH_VARARGS}, + {"sequence_list", sequence_list, METH_O}, + {"sequence_tuple", sequence_tuple, METH_O}, + + {NULL}, +}; + +int +_PyTestCapi_Init_Abstract(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/dict.c b/Modules/_testcapi/dict.c new file mode 100644 index 00000000000000..c0f26e799b5f19 --- /dev/null +++ b/Modules/_testcapi/dict.c @@ -0,0 +1,323 @@ +#include // ptrdiff_t + +#define PY_SSIZE_T_CLEAN +#include "parts.h" + +#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); + +#define RETURN_INT(value) do { \ + int _ret = (value); \ + if (_ret == -1) { \ + return NULL; \ + } \ + return PyLong_FromLong(_ret); \ + } while (0) + +#define RETURN_SIZE(value) do { \ + Py_ssize_t _ret = (value); \ + if (_ret == -1) { \ + return NULL; \ + } \ + return PyLong_FromSsize_t(_ret); \ + } while (0) + + +static PyObject * +dict_check(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyDict_Check(obj)); +} + +static PyObject * +dict_checkexact(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyDict_CheckExact(obj)); +} + +static PyObject * +dict_new(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyDict_New(); +} + +static PyObject * +dictproxy_new(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyDictProxy_New(obj); +} + +static PyObject * +dict_clear(PyObject *self, PyObject *obj) +{ + PyDict_Clear(obj); + Py_RETURN_NONE; +} + +static PyObject * +dict_copy(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyDict_Copy(obj); +} + +static PyObject * +dict_contains(PyObject *self, PyObject *args) +{ + PyObject *obj, *key; + if (!PyArg_ParseTuple(args, "OO", &obj, &key)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(key); + RETURN_INT(PyDict_Contains(obj, key)); +} + +static PyObject * +dict_size(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyDict_Size(obj)); +} + +static PyObject * +dict_getitem(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key; + if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + PyObject *value = PyDict_GetItem(mapping, key); + if (value == NULL) { + if (PyErr_Occurred()) { + return NULL; + } + return Py_NewRef(PyExc_KeyError); + } + return Py_NewRef(value); +} + +static PyObject * +dict_getitemstring(PyObject *self, PyObject *args) +{ + PyObject *mapping; + const char *key; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) { + return NULL; + } + NULLABLE(mapping); + PyObject *value = PyDict_GetItemString(mapping, key); + if (value == NULL) { + if (PyErr_Occurred()) { + return NULL; + } + return Py_NewRef(PyExc_KeyError); + } + return Py_NewRef(value); +} + +static PyObject * +dict_getitemwitherror(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key; + if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + PyObject *value = PyDict_GetItemWithError(mapping, key); + if (value == NULL) { + if (PyErr_Occurred()) { + return NULL; + } + return Py_NewRef(PyExc_KeyError); + } + return Py_NewRef(value); +} + +static PyObject * +dict_setitem(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key, *value; + if (!PyArg_ParseTuple(args, "OOO", &mapping, &key, &value)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + NULLABLE(value); + RETURN_INT(PyDict_SetItem(mapping, key, value)); +} + +static PyObject * +dict_setitemstring(PyObject *self, PyObject *args) +{ + PyObject *mapping, *value; + const char *key; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#O", &mapping, &key, &size, &value)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(value); + RETURN_INT(PyDict_SetItemString(mapping, key, value)); +} + +static PyObject * +dict_setdefault(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key, *defaultobj; + if (!PyArg_ParseTuple(args, "OOO", &mapping, &key, &defaultobj)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + NULLABLE(defaultobj); + return PyDict_SetDefault(mapping, key, defaultobj); +} + +static PyObject * +dict_delitem(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key; + if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(key); + RETURN_INT(PyDict_DelItem(mapping, key)); +} + +static PyObject * +dict_delitemstring(PyObject *self, PyObject *args) +{ + PyObject *mapping; + const char *key; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) { + return NULL; + } + NULLABLE(mapping); + RETURN_INT(PyDict_DelItemString(mapping, key)); +} + +static PyObject * +dict_keys(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyDict_Keys(obj); +} + +static PyObject * +dict_values(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyDict_Values(obj); +} + +static PyObject * +dict_items(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PyDict_Items(obj); +} + +static PyObject * +dict_next(PyObject *self, PyObject *args) +{ + PyObject *mapping, *key, *value; + Py_ssize_t pos; + if (!PyArg_ParseTuple(args, "On", &mapping, &pos)) { + return NULL; + } + NULLABLE(mapping); + int rc = PyDict_Next(mapping, &pos, &key, &value); + if (rc != 0) { + return Py_BuildValue("inOO", rc, pos, key, value); + } + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +dict_merge(PyObject *self, PyObject *args) +{ + PyObject *mapping, *mapping2; + int override; + if (!PyArg_ParseTuple(args, "OOi", &mapping, &mapping2, &override)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(mapping2); + RETURN_INT(PyDict_Merge(mapping, mapping2, override)); +} + +static PyObject * +dict_update(PyObject *self, PyObject *args) +{ + PyObject *mapping, *mapping2; + if (!PyArg_ParseTuple(args, "OO", &mapping, &mapping2)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(mapping2); + RETURN_INT(PyDict_Update(mapping, mapping2)); +} + +static PyObject * +dict_mergefromseq2(PyObject *self, PyObject *args) +{ + PyObject *mapping, *seq; + int override; + if (!PyArg_ParseTuple(args, "OOi", &mapping, &seq, &override)) { + return NULL; + } + NULLABLE(mapping); + NULLABLE(seq); + RETURN_INT(PyDict_MergeFromSeq2(mapping, seq, override)); +} + + +static PyMethodDef test_methods[] = { + {"dict_check", dict_check, METH_O}, + {"dict_checkexact", dict_checkexact, METH_O}, + {"dict_new", dict_new, METH_NOARGS}, + {"dictproxy_new", dictproxy_new, METH_O}, + {"dict_clear", dict_clear, METH_O}, + {"dict_copy", dict_copy, METH_O}, + {"dict_size", dict_size, METH_O}, + {"dict_getitem", dict_getitem, METH_VARARGS}, + {"dict_getitemwitherror", dict_getitemwitherror, METH_VARARGS}, + {"dict_getitemstring", dict_getitemstring, METH_VARARGS}, + {"dict_contains", dict_contains, METH_VARARGS}, + {"dict_setitem", dict_setitem, METH_VARARGS}, + {"dict_setitemstring", dict_setitemstring, METH_VARARGS}, + {"dict_delitem", dict_delitem, METH_VARARGS}, + {"dict_delitemstring", dict_delitemstring, METH_VARARGS}, + {"dict_setdefault", dict_setdefault, METH_VARARGS}, + {"dict_keys", dict_keys, METH_O}, + {"dict_values", dict_values, METH_O}, + {"dict_items", dict_items, METH_O}, + {"dict_next", dict_next, METH_VARARGS}, + {"dict_merge", dict_merge, METH_VARARGS}, + {"dict_update", dict_update, METH_VARARGS}, + {"dict_mergefromseq2", dict_mergefromseq2, METH_VARARGS}, + + {NULL}, +}; + +int +_PyTestCapi_Init_Dict(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index d1991ac6b464f2..f37be9b67a3d78 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -26,6 +26,7 @@ int _PyTestCapi_Init_Vectorcall(PyObject *module); int _PyTestCapi_Init_Heaptype(PyObject *module); +int _PyTestCapi_Init_Abstract(PyObject *module); int _PyTestCapi_Init_Unicode(PyObject *module); int _PyTestCapi_Init_GetArgs(PyObject *module); int _PyTestCapi_Init_PyTime(PyObject *module); @@ -35,6 +36,7 @@ int _PyTestCapi_Init_Mem(PyObject *module); int _PyTestCapi_Init_Watchers(PyObject *module); int _PyTestCapi_Init_Long(PyObject *module); int _PyTestCapi_Init_Float(PyObject *module); +int _PyTestCapi_Init_Dict(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 098d2cfa6d8ad8..ee6f02dd8ab48b 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1988,7 +1988,7 @@ return_result_with_error(PyObject *self, PyObject *args) Py_RETURN_NONE; } -static PyObject* +static PyObject * getitem_with_error(PyObject *self, PyObject *args) { PyObject *map, *key; @@ -2065,90 +2065,6 @@ py_w_stopcode(PyObject *self, PyObject *args) #endif -static PyObject * -get_mapping_keys(PyObject* self, PyObject *obj) -{ - return PyMapping_Keys(obj); -} - -static PyObject * -get_mapping_values(PyObject* self, PyObject *obj) -{ - return PyMapping_Values(obj); -} - -static PyObject * -get_mapping_items(PyObject* self, PyObject *obj) -{ - return PyMapping_Items(obj); -} - -static PyObject * -test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args)) -{ - PyObject *context = PyDict_New(); - PyObject *val = PyLong_FromLong(1); - - // Since this uses `const char*` it is easier to test this in C: - PyDict_SetItemString(context, "a", val); - if (!PyMapping_HasKeyString(context, "a")) { - PyErr_SetString(PyExc_RuntimeError, - "Existing mapping key does not exist"); - return NULL; - } - if (PyMapping_HasKeyString(context, "b")) { - PyErr_SetString(PyExc_RuntimeError, - "Missing mapping key exists"); - return NULL; - } - - Py_DECREF(val); - Py_DECREF(context); - Py_RETURN_NONE; -} - -static PyObject * -mapping_has_key(PyObject* self, PyObject *args) -{ - PyObject *context, *key; - if (!PyArg_ParseTuple(args, "OO", &context, &key)) { - return NULL; - } - return PyLong_FromLong(PyMapping_HasKey(context, key)); -} - -static PyObject * -sequence_set_slice(PyObject* self, PyObject *args) -{ - PyObject *sequence, *obj; - Py_ssize_t i1, i2; - if (!PyArg_ParseTuple(args, "OnnO", &sequence, &i1, &i2, &obj)) { - return NULL; - } - - int res = PySequence_SetSlice(sequence, i1, i2, obj); - if (res == -1) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject * -sequence_del_slice(PyObject* self, PyObject *args) -{ - PyObject *sequence; - Py_ssize_t i1, i2; - if (!PyArg_ParseTuple(args, "Onn", &sequence, &i1, &i2)) { - return NULL; - } - - int res = PySequence_DelSlice(sequence, i1, i2); - if (res == -1) { - return NULL; - } - Py_RETURN_NONE; -} - static PyObject * test_pythread_tss_key_state(PyObject *self, PyObject *args) { @@ -2252,72 +2168,6 @@ negative_refcount(PyObject *self, PyObject *Py_UNUSED(args)) #endif -static PyObject * -sequence_getitem(PyObject *self, PyObject *args) -{ - PyObject *seq; - Py_ssize_t i; - if (!PyArg_ParseTuple(args, "On", &seq, &i)) { - return NULL; - } - return PySequence_GetItem(seq, i); -} - - -static PyObject * -sequence_setitem(PyObject *self, PyObject *args) -{ - Py_ssize_t i; - PyObject *seq, *val; - if (!PyArg_ParseTuple(args, "OnO", &seq, &i, &val)) { - return NULL; - } - if (PySequence_SetItem(seq, i, val)) { - return NULL; - } - Py_RETURN_NONE; -} - - -static PyObject * -sequence_delitem(PyObject *self, PyObject *args) -{ - Py_ssize_t i; - PyObject *seq; - if (!PyArg_ParseTuple(args, "On", &seq, &i)) { - return NULL; - } - if (PySequence_DelItem(seq, i)) { - return NULL; - } - Py_RETURN_NONE; -} - -static PyObject * -hasattr_string(PyObject *self, PyObject* args) -{ - PyObject* obj; - PyObject* attr_name; - - if (!PyArg_UnpackTuple(args, "hasattr_string", 2, 2, &obj, &attr_name)) { - return NULL; - } - - if (!PyUnicode_Check(attr_name)) { - PyErr_SetString(PyExc_TypeError, "attribute name must a be string"); - return PyErr_Occurred(); - } - - const char *name_str = PyUnicode_AsUTF8(attr_name); - if (PyObject_HasAttrString(obj, name_str)) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } -} - - /* Functions for testing C calling conventions (METH_*) are named meth_*, * e.g. "meth_varargs" for METH_VARARGS. * @@ -3459,23 +3309,12 @@ static PyMethodDef TestMethods[] = { #ifdef W_STOPCODE {"W_STOPCODE", py_w_stopcode, METH_VARARGS}, #endif - {"get_mapping_keys", get_mapping_keys, METH_O}, - {"get_mapping_values", get_mapping_values, METH_O}, - {"get_mapping_items", get_mapping_items, METH_O}, - {"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS}, - {"mapping_has_key", mapping_has_key, METH_VARARGS}, - {"sequence_set_slice", sequence_set_slice, METH_VARARGS}, - {"sequence_del_slice", sequence_del_slice, METH_VARARGS}, {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS}, {"hamt", new_hamt, METH_NOARGS}, {"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL}, #ifdef Py_REF_DEBUG {"negative_refcount", negative_refcount, METH_NOARGS}, #endif - {"sequence_getitem", sequence_getitem, METH_VARARGS}, - {"sequence_setitem", sequence_setitem, METH_VARARGS}, - {"sequence_delitem", sequence_delitem, METH_VARARGS}, - {"hasattr_string", hasattr_string, METH_VARARGS}, {"meth_varargs", meth_varargs, METH_VARARGS}, {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS}, {"meth_o", meth_o, METH_O}, @@ -4116,6 +3955,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Heaptype(m) < 0) { return NULL; } + if (_PyTestCapi_Init_Abstract(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Unicode(m) < 0) { return NULL; } @@ -4143,6 +3985,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Float(m) < 0) { return NULL; } + if (_PyTestCapi_Init_Dict(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Structmember(m) < 0) { return NULL; } diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 3db9426d1a25ff..1843b58de9d151 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -99,7 +99,9 @@ + + @@ -131,4 +133,4 @@ - \ No newline at end of file + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index 8df4874659fa1c..61322332af7d1e 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -27,9 +27,15 @@ Source Files + + Source Files + Source Files + + Source Files + Source Files @@ -75,4 +81,4 @@ Resource Files - \ No newline at end of file + From ea6865242c184c8afc816e0211652f0d04d9b8f8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:29:42 -0700 Subject: [PATCH 0548/1206] [3.12] gh-107715: Escape class name in regular expression (GH-107716) (#107726) * gh-107715: Escape class name in regular expression (GH-107716) This patch escapes the class name before embedding it in the regular expression for `pat` in `doctest.DocTestFinder._find_lineno`. While class names do not ordinarily contain special characters, it is possible to encounter these when a class is created dynamically. Escaping the name will correctly return `None` in this scenario, rather than potentially matching a different class or raising `re.error` depending on the symbols used. (cherry picked from commit 85793278793708ad6b7132a54ac9fb4b2c5bcac1) Co-authored-by: Gertjan van Zwieten * Update 2023-08-07-14-12-07.gh-issue-107715.238r2f.rst --------- Co-authored-by: Gertjan van Zwieten Co-authored-by: Serhiy Storchaka --- Lib/doctest.py | 2 +- .../next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst diff --git a/Lib/doctest.py b/Lib/doctest.py index 2776d74bf9b586..a63df46a112e64 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1110,7 +1110,7 @@ def _find_lineno(self, obj, source_lines): if source_lines is None: return None pat = re.compile(r'^\s*class\s*%s\b' % - getattr(obj, '__name__', '-')) + re.escape(getattr(obj, '__name__', '-'))) for i, line in enumerate(source_lines): if pat.match(line): lineno = i diff --git a/Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst b/Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst new file mode 100644 index 00000000000000..4bf08c071df2f9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst @@ -0,0 +1 @@ +Fix :meth:`doctest.DocTestFinder.find` in presence of class names with special characters. Patch by Gertjan van Zwieten. From 6fd572f3b3dcc00cd80ba8e9a5a7c3a9cefc60cb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:30:31 -0700 Subject: [PATCH 0549/1206] [3.12] gh-100814: Fix exception for invalid callable value of Tkinter image option (GH-107692) (#107722) gh-100814: Fix exception for invalid callable value of Tkinter image option (GH-107692) Passing a callable object as an option value to a Tkinter image now raises the expected TclError instead of an AttributeError. (cherry picked from commit 50e3cc9748eb2103eb7ed6cc5a74d177df3cfb13) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tkinter/test_images.py | 16 ++++++++++++++++ Lib/tkinter/__init__.py | 4 ---- ...023-08-06-15-29-00.gh-issue-100814.h195gW.rst | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py index b6f8b79ae689fa..94cfe7df0be26e 100644 --- a/Lib/test/test_tkinter/test_images.py +++ b/Lib/test/test_tkinter/test_images.py @@ -144,6 +144,14 @@ def test_configure_foreground(self): self.assertEqual(image['foreground'], '-foreground {} {} #000000 yellow') + def test_bug_100814(self): + # gh-100814: Passing a callable option value causes AttributeError. + with self.assertRaises(tkinter.TclError): + tkinter.BitmapImage('::img::test', master=self.root, spam=print) + image = tkinter.BitmapImage('::img::test', master=self.root) + with self.assertRaises(tkinter.TclError): + image.configure(spam=print) + class PhotoImageTest(AbstractTkTest, unittest.TestCase): @@ -274,6 +282,14 @@ def test_configure_palette(self): image.configure(palette='3/4/2') self.assertEqual(image['palette'], '3/4/2') + def test_bug_100814(self): + # gh-100814: Passing a callable option value causes AttributeError. + with self.assertRaises(tkinter.TclError): + tkinter.PhotoImage('::img::test', master=self.root, spam=print) + image = tkinter.PhotoImage('::img::test', master=self.root) + with self.assertRaises(tkinter.TclError): + image.configure(spam=print) + def test_blank(self): image = self.create() image.blank() diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index c675c511e04533..c59f8d11e8a9da 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -4069,8 +4069,6 @@ def __init__(self, imgtype, name=None, cnf={}, master=None, **kw): elif kw: cnf = kw options = () for k, v in cnf.items(): - if callable(v): - v = self._register(v) options = options + ('-'+k, v) self.tk.call(('image', 'create', imgtype, name,) + options) self.name = name @@ -4097,8 +4095,6 @@ def configure(self, **kw): for k, v in _cnfmerge(kw).items(): if v is not None: if k[-1] == '_': k = k[:-1] - if callable(v): - v = self._register(v) res = res + ('-'+k, v) self.tk.call((self.name, 'config') + res) diff --git a/Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst b/Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst new file mode 100644 index 00000000000000..86cb7bf79f3078 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst @@ -0,0 +1,2 @@ +Passing a callable object as an option value to a Tkinter image now raises +the expected TclError instead of an AttributeError. From 220d7e3120ffa23d01f91b7ad89f488b4dda3ef0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:30:58 -0700 Subject: [PATCH 0550/1206] [3.12] Docs: Fix more Sphinx annotations in ctypes.rst (GH-107708) (#107717) Docs: Fix more Sphinx annotations in ctypes.rst (GH-107708) (cherry picked from commit 8c9af6b9a0d6fc9cb237e96588d8dcab727e32b8) Co-authored-by: Erlend E. Aasland --- Doc/conf.py | 1 + Doc/library/ctypes.rst | 85 +++++++++++++++++++++--------------------- Doc/tools/.nitignore | 1 - 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index fd115f7551f44c..8224b248062f4d 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -94,6 +94,7 @@ ('c:func', 'sprintf'), ('c:func', 'stat'), ('c:func', 'system'), + ('c:func', 'time'), ('c:func', 'vsnprintf'), # Standard C types ('c:type', 'FILE'), diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 3c794beca32c14..cd5c41e9b59c97 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -41,7 +41,7 @@ You load libraries by accessing them as attributes of these objects. *cdll* loads libraries which export functions using the standard ``cdecl`` calling convention, while *windll* libraries call functions using the ``stdcall`` calling convention. *oledll* also uses the ``stdcall`` calling convention, and -assumes the functions return a Windows :c:type:`HRESULT` error code. The error +assumes the functions return a Windows :c:type:`!HRESULT` error code. The error code is used to automatically raise an :class:`OSError` exception when the function call fails. @@ -477,7 +477,7 @@ Return types By default functions are assumed to return the C :c:expr:`int` type. Other -return types can be specified by setting the :attr:`restype` attribute of the +return types can be specified by setting the :attr:`~_FuncPtr.restype` attribute of the function object. The C prototype of :c:func:`time` is ``time_t time(time_t *)``. Because :c:type:`time_t` @@ -495,7 +495,7 @@ To call the function with a ``NULL`` pointer as first argument, use ``None``:: >>> print(libc.time(None)) # doctest: +SKIP 1150640792 -Here is a more advanced example, it uses the :func:`strchr` function, which expects +Here is a more advanced example, it uses the :func:`!strchr` function, which expects a string pointer and a char, and returns a pointer to a string:: >>> strchr = libc.strchr @@ -528,7 +528,7 @@ single character Python bytes object into a C char: >>> You can also use a callable Python object (a function or a class for example) as -the :attr:`restype` attribute, if the foreign function returns an integer. The +the :attr:`~_FuncPtr.restype` attribute, if the foreign function returns an integer. The callable will be called with the *integer* the C function returns, and the result of this call will be used as the result of your function call. This is useful to check for error return values and automatically raise an exception:: @@ -556,7 +556,8 @@ get the string representation of an error code, and *returns* an exception. :func:`GetLastError` to retrieve it. Please note that a much more powerful error checking mechanism is available -through the :attr:`errcheck` attribute; see the reference manual for details. +through the :attr:`~_FuncPtr.errcheck` attribute; +see the reference manual for details. .. _ctypes-passing-pointers: @@ -594,7 +595,7 @@ Structures and unions Structures and unions must derive from the :class:`Structure` and :class:`Union` base classes which are defined in the :mod:`ctypes` module. Each subclass must -define a :attr:`_fields_` attribute. :attr:`_fields_` must be a list of +define a :attr:`~Structure._fields_` attribute. :attr:`!_fields_` must be a list of *2-tuples*, containing a *field name* and a *field type*. The field type must be a :mod:`ctypes` type like :class:`c_int`, or any other @@ -666,9 +667,9 @@ Structure/union alignment and byte order By default, Structure and Union fields are aligned in the same way the C compiler does it. It is possible to override this behavior by specifying a -:attr:`_pack_` class attribute in the subclass definition. This must be set to a -positive integer and specifies the maximum alignment for the fields. This is -what ``#pragma pack(n)`` also does in MSVC. +:attr:`~Structure._pack_` class attribute in the subclass definition. +This must be set to a positive integer and specifies the maximum alignment for the fields. +This is what ``#pragma pack(n)`` also does in MSVC. :mod:`ctypes` uses the native byte order for Structures and Unions. To build structures with non-native byte order, you can use one of the @@ -684,7 +685,7 @@ Bit fields in structures and unions It is possible to create structures and unions containing bit fields. Bit fields are only possible for integer fields, the bit width is specified as the third -item in the :attr:`_fields_` tuples:: +item in the :attr:`~Structure._fields_` tuples:: >>> class Int(Structure): ... _fields_ = [("first_16", c_int, 16), @@ -876,7 +877,7 @@ pointer types. So, for ``POINTER(c_int)``, ctypes accepts an array of c_int:: >>> In addition, if a function argument is explicitly declared to be a pointer type -(such as ``POINTER(c_int)``) in :attr:`_FuncPtr.argtypes`, an object of the pointed +(such as ``POINTER(c_int)``) in :attr:`~_FuncPtr.argtypes`, an object of the pointed type (``c_int`` in this case) can be passed to the function. ctypes will apply the required :func:`byref` conversion in this case automatically. @@ -952,8 +953,8 @@ work:: >>> because the new ``class cell`` is not available in the class statement itself. -In :mod:`ctypes`, we can define the ``cell`` class and set the :attr:`_fields_` -attribute later, after the class statement:: +In :mod:`ctypes`, we can define the ``cell`` class and set the +:attr:`~Structure._fields_` attribute later, after the class statement:: >>> from ctypes import * >>> class cell(Structure): @@ -1003,8 +1004,8 @@ argument, and the callback functions expected argument types as the remaining arguments. I will present an example here which uses the standard C library's -:c:func:`qsort` function, that is used to sort items with the help of a callback -function. :c:func:`qsort` will be used to sort an array of integers:: +:c:func:`!qsort` function, that is used to sort items with the help of a callback +function. :c:func:`!qsort` will be used to sort an array of integers:: >>> IntArray5 = c_int * 5 >>> ia = IntArray5(5, 1, 7, 33, 99) @@ -1012,7 +1013,7 @@ function. :c:func:`qsort` will be used to sort an array of integers:: >>> qsort.restype = None >>> -:func:`qsort` must be called with a pointer to the data to sort, the number of +:func:`!qsort` must be called with a pointer to the data to sort, the number of items in the data array, the size of one item, and a pointer to the comparison function, the callback. The callback will then be called with two pointers to items, and it must return a negative integer if the first item is smaller than @@ -1104,7 +1105,7 @@ Some shared libraries not only export functions, they also export variables. An example in the Python library itself is the :c:data:`Py_Version`, Python runtime version number encoded in a single constant integer. -:mod:`ctypes` can access values like this with the :meth:`in_dll` class methods of +:mod:`ctypes` can access values like this with the :meth:`~_CData.in_dll` class methods of the type. *pythonapi* is a predefined symbol giving access to the Python C api:: @@ -1294,13 +1295,13 @@ Finding shared libraries When programming in a compiled language, shared libraries are accessed when compiling/linking a program, and when the program is run. -The purpose of the :func:`find_library` function is to locate a library in a way +The purpose of the :func:`~ctypes.util.find_library` function is to locate a library in a way similar to what the compiler or runtime loader does (on platforms with several versions of a shared library the most recent should be loaded), while the ctypes library loaders act like when a program is run, and call the runtime loader directly. -The :mod:`ctypes.util` module provides a function which can help to determine +The :mod:`!ctypes.util` module provides a function which can help to determine the library to load. @@ -1315,7 +1316,7 @@ the library to load. The exact functionality is system dependent. -On Linux, :func:`find_library` tries to run external programs +On Linux, :func:`~ctypes.util.find_library` tries to run external programs (``/sbin/ldconfig``, ``gcc``, ``objdump`` and ``ld``) to find the library file. It returns the filename of the library file. @@ -1334,7 +1335,7 @@ Here are some examples:: 'libbz2.so.1.0' >>> -On macOS, :func:`find_library` tries several predefined naming schemes and paths +On macOS, :func:`~ctypes.util.find_library` tries several predefined naming schemes and paths to locate the library, and returns a full pathname if successful:: >>> from ctypes.util import find_library @@ -1348,13 +1349,13 @@ to locate the library, and returns a full pathname if successful:: '/System/Library/Frameworks/AGL.framework/AGL' >>> -On Windows, :func:`find_library` searches along the system search path, and +On Windows, :func:`~ctypes.util.find_library` searches along the system search path, and returns the full pathname, but since there is no predefined naming scheme a call like ``find_library("c")`` will fail and return ``None``. If wrapping a shared library with :mod:`ctypes`, it *may* be better to determine the shared library name at development time, and hardcode that into the wrapper -module instead of using :func:`find_library` to locate the library at runtime. +module instead of using :func:`~ctypes.util.find_library` to locate the library at runtime. .. _ctypes-loading-shared-libraries: @@ -1439,9 +1440,9 @@ function exported by these libraries, and reacquired afterwards. All these classes can be instantiated by calling them with at least one argument, the pathname of the shared library. If you have an existing handle to an already loaded shared library, it can be passed as the ``handle`` named -parameter, otherwise the underlying platforms :c:func:`!dlopen` or :c:func:`LoadLibrary` -function is used to load the library into the process, and to get a handle to -it. +parameter, otherwise the underlying platforms :c:func:`!dlopen` or +:c:func:`!LoadLibrary` function is used to load the library into +the process, and to get a handle to it. The *mode* parameter can be used to specify how the library is loaded. For details, consult the :manpage:`dlopen(3)` manpage. On Windows, *mode* is @@ -1461,7 +1462,7 @@ to a new value and returns the former value. The *use_last_error* parameter, when set to true, enables the same mechanism for the Windows error code which is managed by the :func:`GetLastError` and -:func:`SetLastError` Windows API functions; :func:`ctypes.get_last_error` and +:func:`!SetLastError` Windows API functions; :func:`ctypes.get_last_error` and :func:`ctypes.set_last_error` are used to request and change the ctypes private copy of the windows error code. @@ -1533,7 +1534,7 @@ attribute of the loader instance. Class which loads shared libraries. *dlltype* should be one of the :class:`CDLL`, :class:`PyDLL`, :class:`WinDLL`, or :class:`OleDLL` types. - :meth:`__getattr__` has special behavior: It allows loading a shared library by + :meth:`!__getattr__` has special behavior: It allows loading a shared library by accessing it as attribute of a library loader instance. The result is cached, so repeated attribute accesses return the same library each time. @@ -1578,7 +1579,7 @@ object is available: An instance of :class:`PyDLL` that exposes Python C API functions as attributes. Note that all these functions are assumed to return C :c:expr:`int`, which is of course not always the truth, so you have to assign - the correct :attr:`restype` attribute to use these functions. + the correct :attr:`!restype` attribute to use these functions. .. audit-event:: ctypes.dlopen name ctypes.LibraryLoader @@ -1630,7 +1631,7 @@ They are instances of a private class: the callable will be called with this integer, allowing further processing or error checking. Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as - :attr:`restype` and assign a callable to the :attr:`errcheck` attribute. + :attr:`!restype` and assign a callable to the :attr:`errcheck` attribute. .. attribute:: argtypes @@ -1662,7 +1663,7 @@ They are instances of a private class: :module: *result* is what the foreign function returns, as specified by the - :attr:`restype` attribute. + :attr:`!restype` attribute. *func* is the foreign function object itself, this allows reusing the same callable object to check or post process the results of several @@ -1772,7 +1773,7 @@ different ways, depending on the type and number of the parameters in the call: COM methods use a special calling convention: They require a pointer to the COM interface as first argument, in addition to those parameters that - are specified in the :attr:`~_FuncPtr.argtypes` tuple. + are specified in the :attr:`!argtypes` tuple. The optional *paramflags* parameter creates foreign function wrappers with much more functionality than the features described above. @@ -1847,7 +1848,7 @@ value if there is a single one, or a tuple containing the output parameter values when there are more than one, so the GetWindowRect function now returns a RECT instance, when called. -Output parameters can be combined with the :attr:`errcheck` protocol to do +Output parameters can be combined with the :attr:`~_FuncPtr.errcheck` protocol to do further output processing and error checking. The win32 ``GetWindowRect`` api function returns a ``BOOL`` to signal success or failure, so this function could do the error checking, and raises an exception when the api call failed:: @@ -1860,7 +1861,7 @@ do the error checking, and raises an exception when the api call failed:: >>> GetWindowRect.errcheck = errcheck >>> -If the :attr:`errcheck` function returns the argument tuple it receives +If the :attr:`~_FuncPtr.errcheck` function returns the argument tuple it receives unchanged, :mod:`ctypes` continues the normal processing it does on the output parameters. If you want to return a tuple of window coordinates instead of a ``RECT`` instance, you can retrieve the fields in the function and return them @@ -2010,7 +2011,7 @@ Utility functions .. function:: get_last_error() Windows only: returns the current value of the ctypes-private copy of the system - :data:`LastError` variable in the calling thread. + :data:`!LastError` variable in the calling thread. .. audit-event:: ctypes.get_last_error "" ctypes.get_last_error @@ -2063,7 +2064,7 @@ Utility functions .. function:: set_last_error(value) Windows only: set the current value of the ctypes-private copy of the system - :data:`LastError` variable in the calling thread to *value* and return the + :data:`!LastError` variable in the calling thread to *value* and return the previous value. .. audit-event:: ctypes.set_last_error error ctypes.set_last_error @@ -2225,13 +2226,13 @@ Fundamental data types Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a -:attr:`restype` of :class:`c_char_p`, you will always receive a Python bytes +:attr:`~_FuncPtr.restype` of :class:`c_char_p`, you will always receive a Python bytes object, *not* a :class:`c_char_p` instance. .. XXX above is false, it actually returns a Unicode string Subclasses of fundamental data types do *not* inherit this behavior. So, if a -foreign functions :attr:`restype` is a subclass of :class:`c_void_p`, you will +foreign functions :attr:`!restype` is a subclass of :class:`c_void_p`, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the ``value`` attribute. @@ -2430,7 +2431,7 @@ These are the fundamental ctypes data types: .. class:: HRESULT - Windows only: Represents a :c:type:`HRESULT` value, which contains success or + Windows only: Represents a :c:type:`!HRESULT` value, which contains success or error information for a function or method call. @@ -2439,9 +2440,9 @@ These are the fundamental ctypes data types: Represents the C :c:expr:`PyObject *` datatype. Calling this without an argument creates a ``NULL`` :c:expr:`PyObject *` pointer. -The :mod:`ctypes.wintypes` module provides quite some other Windows specific -data types, for example :c:type:`HWND`, :c:type:`WPARAM`, or :c:type:`DWORD`. Some -useful structures like :c:type:`MSG` or :c:type:`RECT` are also defined. +The :mod:`!ctypes.wintypes` module provides quite some other Windows specific +data types, for example :c:type:`!HWND`, :c:type:`!WPARAM`, or :c:type:`!DWORD`. +Some useful structures like :c:type:`!MSG` or :c:type:`!RECT` are also defined. .. _ctypes-structured-data-types: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index b3ef4a63731959..8e9ac17135ebec 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -69,7 +69,6 @@ Doc/library/configparser.rst Doc/library/contextlib.rst Doc/library/copy.rst Doc/library/csv.rst -Doc/library/ctypes.rst Doc/library/datetime.rst Doc/library/dbm.rst Doc/library/decimal.rst From 91d935b47b47f5fa5c3eb0ee5e45a627f79babef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:32:04 -0700 Subject: [PATCH 0551/1206] [3.12] gh-104496: Use correct Tcl or Tk version in Tkinter tests (GH-107688) (#107709) gh-104496: Use correct Tcl or Tk version in Tkinter tests (GH-107688) In future Tcl and Tk versions can be desynchronized. (cherry picked from commit 3c8e8f3ceeae08fc43d885f5a4c65a3ee4b1a2c8) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tcl.py | 13 ++----------- Lib/test/test_tkinter/support.py | 18 +++++++++--------- Lib/test/test_tkinter/test_images.py | 6 +++--- Lib/test/test_tkinter/test_widgets.py | 16 ++++++++-------- Lib/test/test_tkinter/widget_tests.py | 6 +++--- Lib/test/test_ttk/test_style.py | 2 +- Lib/test/test_ttk/test_widgets.py | 8 ++++---- 7 files changed, 30 insertions(+), 39 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index d07b83acb1b505..ebdb58f91d3d8a 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -20,14 +20,6 @@ tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.'))) -_tk_patchlevel = None -def get_tk_patchlevel(): - global _tk_patchlevel - if _tk_patchlevel is None: - tcl = Tcl() - _tk_patchlevel = tcl.info_patchlevel() - return _tk_patchlevel - class TkinterTest(unittest.TestCase): @@ -571,7 +563,6 @@ def test_splitlist(self): (1, '2', (3.4,)) if self.wantobjects else ('1', '2', '3.4')), ] - tk_patchlevel = get_tk_patchlevel() if not self.wantobjects: expected = ('12', '\u20ac', '\xe2\x82\xac', '3.4') else: @@ -580,8 +571,8 @@ def test_splitlist(self): (call('dict', 'create', 12, '\u20ac', b'\xe2\x82\xac', (3.4,)), expected), ] - dbg_info = ('want objects? %s, Tcl version: %s, Tk patchlevel: %s' - % (self.wantobjects, tcl_version, tk_patchlevel)) + dbg_info = ('want objects? %s, Tcl version: %s, Tcl patchlevel: %s' + % (self.wantobjects, tcl_version, self.interp.info_patchlevel())) for arg, res in testcases: self.assertEqual(splitlist(arg), res, 'arg=%a, %s' % (arg, dbg_info)) diff --git a/Lib/test/test_tkinter/support.py b/Lib/test/test_tkinter/support.py index 9154ebac5c48f8..10e64bf40a4afa 100644 --- a/Lib/test/test_tkinter/support.py +++ b/Lib/test/test_tkinter/support.py @@ -79,28 +79,28 @@ def simulate_mouse_click(widget, x, y): import _tkinter tcl_version = tuple(map(int, _tkinter.TCL_VERSION.split('.'))) +tk_version = tuple(map(int, _tkinter.TK_VERSION.split('.'))) -def requires_tcl(*version): - if len(version) <= 2: - return unittest.skipUnless(tcl_version >= version, - 'requires Tcl version >= ' + '.'.join(map(str, version))) +def requires_tk(*version): + if len(version) <= 2 and tk_version >= version: + return lambda test: test def deco(test): @functools.wraps(test) def newtest(self): - if get_tk_patchlevel() < version: - self.skipTest('requires Tcl version >= ' + + root = getattr(self, 'root', None) + if get_tk_patchlevel(root) < version: + self.skipTest('requires Tk version >= ' + '.'.join(map(str, version))) test(self) return newtest return deco _tk_patchlevel = None -def get_tk_patchlevel(): +def get_tk_patchlevel(root): global _tk_patchlevel if _tk_patchlevel is None: - tcl = tkinter.Tcl() - _tk_patchlevel = tcl.info_patchlevel() + _tk_patchlevel = tkinter._parse_version(root.tk.globalgetvar('tk_patchLevel')) return _tk_patchlevel units = { diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py index 94cfe7df0be26e..9f49d6efc7892e 100644 --- a/Lib/test/test_tkinter/test_images.py +++ b/Lib/test/test_tkinter/test_images.py @@ -2,7 +2,7 @@ import tkinter from test import support from test.support import os_helper -from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest, requires_tcl +from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest, requires_tk support.requires('gui') @@ -221,11 +221,11 @@ def test_create_from_gif_file(self): def test_create_from_gif_data(self): self.check_create_from_data('gif') - @requires_tcl(8, 6) + @requires_tk(8, 6) def test_create_from_png_file(self): self.check_create_from_file('png') - @requires_tcl(8, 6) + @requires_tk(8, 6) def test_create_from_png_data(self): self.check_create_from_data('png') diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 34e67c0cbc44a3..d3f942db7baf9a 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -4,7 +4,7 @@ import os from test.support import requires -from test.test_tkinter.support import (requires_tcl, +from test.test_tkinter.support import (requires_tk, get_tk_patchlevel, widget_eq, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import ( @@ -613,7 +613,7 @@ def test_configure_inactiveselectbackground(self): widget = self.create() self.checkColorParam(widget, 'inactiveselectbackground') - @requires_tcl(8, 6) + @requires_tk(8, 6) def test_configure_insertunfocussed(self): widget = self.create() self.checkEnumParam(widget, 'insertunfocussed', @@ -924,7 +924,7 @@ def test_coords(self): for i in range(4): self.assertIsInstance(coords[i], float) - @requires_tcl(8, 6) + @requires_tk(8, 6) def test_moveto(self): widget = self.create() i1 = widget.create_rectangle(1, 1, 20, 20, tags='group') @@ -969,7 +969,7 @@ def test_configure_activestyle(self): self.checkEnumParam(widget, 'activestyle', 'dotbox', 'none', 'underline') - test_configure_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify) + test_configure_justify = requires_tk(8, 6, 5)(StandardOptionsTests.test_configure_justify) def test_configure_listvariable(self): widget = self.create() @@ -1108,7 +1108,7 @@ def test_configure_digits(self): def test_configure_from(self): widget = self.create() - conv = float if get_tk_patchlevel() >= (8, 6, 10) else float_round + conv = float if get_tk_patchlevel(self.root) >= (8, 6, 10) else float_round self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv) def test_configure_label(self): @@ -1235,19 +1235,19 @@ def test_configure_opaqueresize(self): widget = self.create() self.checkBooleanParam(widget, 'opaqueresize') - @requires_tcl(8, 6, 5) + @requires_tk(8, 6, 5) def test_configure_proxybackground(self): widget = self.create() self.checkColorParam(widget, 'proxybackground') - @requires_tcl(8, 6, 5) + @requires_tk(8, 6, 5) def test_configure_proxyborderwidth(self): widget = self.create() self.checkPixelsParam(widget, 'proxyborderwidth', 0, 1.3, 2.9, 6, -2, '10p', conv=False) - @requires_tcl(8, 6, 5) + @requires_tk(8, 6, 5) def test_configure_proxyrelief(self): widget = self.create() self.checkReliefParam(widget, 'proxyrelief') diff --git a/Lib/test/test_tkinter/widget_tests.py b/Lib/test/test_tkinter/widget_tests.py index 85b0511aba3c7a..514b42bea764a9 100644 --- a/Lib/test/test_tkinter/widget_tests.py +++ b/Lib/test/test_tkinter/widget_tests.py @@ -1,7 +1,7 @@ # Common tests for test_tkinter/test_widgets.py and test_ttk/test_widgets.py import tkinter -from test.test_tkinter.support import (AbstractTkTest, tcl_version, +from test.test_tkinter.support import (AbstractTkTest, tk_version, pixels_conv, tcl_obj_eq) import test.support @@ -22,7 +22,7 @@ def scaling(self): return self._scaling def _str(self, value): - if not self._stringify and self.wantobjects and tcl_version >= (8, 6): + if not self._stringify and self.wantobjects and tk_version >= (8, 6): return value if isinstance(value, tuple): return ' '.join(map(self._str, value)) @@ -156,7 +156,7 @@ def checkReliefParam(self, widget, name): 'flat', 'groove', 'raised', 'ridge', 'solid', 'sunken') errmsg='bad relief "spam": must be '\ 'flat, groove, raised, ridge, solid, or sunken' - if tcl_version < (8, 6): + if tk_version < (8, 6): errmsg = None self.checkInvalidParam(widget, name, 'spam', errmsg=errmsg) diff --git a/Lib/test/test_ttk/test_style.py b/Lib/test/test_ttk/test_style.py index 0ec95cf6b5ffc9..f9c56ec2357451 100644 --- a/Lib/test/test_ttk/test_style.py +++ b/Lib/test/test_ttk/test_style.py @@ -170,7 +170,7 @@ def test_map_custom_copy(self): newname = f'C.{name}' self.assertEqual(style.map(newname), {}) style.map(newname, **default) - if theme == 'alt' and name == '.' and get_tk_patchlevel() < (8, 6, 1): + if theme == 'alt' and name == '.' and get_tk_patchlevel(self.root) < (8, 6, 1): default['embossed'] = [('disabled', '1')] self.assertEqual(style.map(newname), default) for key, value in default.items(): diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 79d65b496abdc6..fd1a748a498ac5 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -5,7 +5,7 @@ import sys from test.test_ttk_textonly import MockTclObj -from test.test_tkinter.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, +from test.test_tkinter.support import (AbstractTkTest, tk_version, get_tk_patchlevel, simulate_mouse_click, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import (add_standard_options, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests) @@ -19,7 +19,7 @@ def test_configure_class(self): widget = self.create() self.assertEqual(widget['class'], '') errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): + if get_tk_patchlevel(self.root) < (8, 6, 0, 'beta', 3): errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) widget2 = self.create(class_='Foo') @@ -560,7 +560,7 @@ def test_configure_orient(self): widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0, 'beta', 3): + if get_tk_patchlevel(self.root) < (8, 6, 0, 'beta', 3): errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'orient', 'horizontal', errmsg=errmsg) @@ -1526,7 +1526,7 @@ def test_heading(self): def test_heading_callback(self): def simulate_heading_click(x, y): - if tcl_version >= (8, 6): + if tk_version >= (8, 6): self.assertEqual(self.tv.identify_column(x), '#0') self.assertEqual(self.tv.identify_region(x, y), 'heading') simulate_mouse_click(self.tv, x, y) From 305169e795172baf4e65cde20f563cbafa274606 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:17:23 -0700 Subject: [PATCH 0552/1206] [3.12] GH-92584: Drop reference to Distutils in ``site.USER_BASE`` (GH-108031) (#108039) GH-92584: Drop reference to Distutils in ``site.USER_BASE`` (GH-108031) Drop reference to Distutils in ``site.USER_BASE`` (cherry picked from commit f2a9dfdee9de381e4adf29a7f1e2aec56580bfda) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/site.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/site.rst b/Doc/library/site.rst index 44f90a3b9e496f..ff9e9107f9d163 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -189,7 +189,7 @@ Module contents :func:`getuserbase` hasn't been called yet. Default value is :file:`~/.local` for UNIX and macOS non-framework builds, :file:`~/Library/Python/{X.Y}` for macOS framework builds, and - :file:`{%APPDATA%}\\Python` for Windows. This value is used by Distutils to + :file:`{%APPDATA%}\\Python` for Windows. This value is used to compute the installation directories for scripts, data files, Python modules, etc. for the :ref:`user installation scheme `. See also :envvar:`PYTHONUSERBASE`. From 6bab8ef3ad4a3cbc1f096e3b81d7d06c1714622b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:18:01 -0700 Subject: [PATCH 0553/1206] [3.12] Remove Sphinx problem matcher to avoid annotating unchanged files (GH-108005) (#108049) Remove Sphinx problem matcher to avoid annotating unchanged files (GH-108005) (cherry picked from commit 0d7f5d3ba3641f8c7d32facbb177bf70ee7520d1) Co-authored-by: Hugo van Kemenade --- .github/problem-matchers/sphinx.json | 40 ---------------------------- .github/workflows/reusable-docs.yml | 4 --- 2 files changed, 44 deletions(-) delete mode 100644 .github/problem-matchers/sphinx.json diff --git a/.github/problem-matchers/sphinx.json b/.github/problem-matchers/sphinx.json deleted file mode 100644 index 09848608a7b034..00000000000000 --- a/.github/problem-matchers/sphinx.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "problemMatcher": [ - { - "owner": "sphinx-problem-matcher", - "pattern": [ - { - "regexp": "^(.*):(\\d+):\\s+(\\w*):\\s+(.*)$", - "file": 1, - "line": 2, - "severity": 3, - "message": 4 - } - ] - }, - { - "owner": "sphinx-problem-matcher-loose", - "pattern": [ - { - "_comment": "A bit of a looser pattern, doesn't look for line numbers, just looks for file names relying on them to start with / and end with .rst", - "regexp": "(\/.*\\.rst):\\s+(\\w*):\\s+(.*)$", - "file": 1, - "severity": 2, - "message": 3 - } - ] - }, - { - "owner": "sphinx-problem-matcher-loose-no-severity", - "pattern": [ - { - "_comment": "Looks for file names ending with .rst and line numbers but without severity", - "regexp": "^(.*\\.rst):(\\d+):(.*)$", - "file": 1, - "line": 2, - "message": 3 - } - ] - } - ] -} \ No newline at end of file diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index b39d8cea6421ea..77142a64a4b224 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -18,8 +18,6 @@ jobs: timeout-minutes: 60 steps: - uses: actions/checkout@v3 - - name: Register Sphinx problem matcher - run: echo "::add-matcher::.github/problem-matchers/sphinx.json" - name: 'Set up Python' uses: actions/setup-python@v4 with: @@ -83,8 +81,6 @@ jobs: timeout-minutes: 60 steps: - uses: actions/checkout@v3 - - name: Register Sphinx problem matcher - run: echo "::add-matcher::.github/problem-matchers/sphinx.json" - uses: actions/cache@v3 with: path: ~/.cache/pip From 84a4370e31632fb04590131ed24329c60cf2f356 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:18:24 -0700 Subject: [PATCH 0554/1206] [3.12] gh-91051: fix type watcher test to be robust to existing watcher (GH-107989) (#108053) gh-91051: fix type watcher test to be robust to existing watcher (GH-107989) (cherry picked from commit fce93c80ae2d792b8ca443b044e28abbf28bb89a) Co-authored-by: Carl Meyer --- Lib/test/test_capi/test_watchers.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py index 10b76e163bfb21..6b8855ec219d27 100644 --- a/Lib/test/test_capi/test_watchers.py +++ b/Lib/test/test_capi/test_watchers.py @@ -351,12 +351,10 @@ def test_clear_unassigned_watcher_id(self): self.clear_watcher(1) def test_no_more_ids_available(self): - contexts = [self.watcher() for i in range(self.TYPE_MAX_WATCHERS)] - with ExitStack() as stack: - for ctx in contexts: - stack.enter_context(ctx) - with self.assertRaisesRegex(RuntimeError, r"no more type watcher IDs"): - self.add_watcher() + with self.assertRaisesRegex(RuntimeError, r"no more type watcher IDs"): + with ExitStack() as stack: + for _ in range(self.TYPE_MAX_WATCHERS + 1): + stack.enter_context(self.watcher()) class TestCodeObjectWatchers(unittest.TestCase): From 2a00cf2db8a19533dc7d71276ce6a77f6a103c65 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:18:57 -0700 Subject: [PATCH 0555/1206] [3.12] GH-92584: Remove reference to Distutils in ``cx_Freeze``'s description (GH-108047) (#108057) GH-92584: Remove reference to Distutils in ``cx_Freeze``'s description (GH-108047) Remove reference to Distutils in ``cx_Freeze``'s description (cherry picked from commit 57fcf96e4f21b8955b3ae4b4d70e4b756949712f) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/using/windows.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index b7e4b2b48a6012..1c305d983dfa41 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -1246,8 +1246,8 @@ shipped with PyWin32. It is an embeddable IDE with a built-in debugger. cx_Freeze --------- -`cx_Freeze `_ is a ``distutils`` -extension which wraps Python scripts into executable Windows programs +`cx_Freeze `_ +wraps Python scripts into executable Windows programs (:file:`{*}.exe` files). When you have done this, you can distribute your application without requiring your users to install Python. From ede98958810b76694cf756d305b564cd6adc1a48 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 17 Aug 2023 00:19:48 +0100 Subject: [PATCH 0556/1206] [3.12] gh-106242: Fix path truncation in os.path.normpath (GH-106816) (#107981) * gh-106242: Fix path truncation in os.path.normpath (GH-106816) * gh-106242: Minor fixup to avoid compiler warnings --------- Co-authored-by: Finn Womack Co-authored-by: Serhiy Storchaka --- Include/internal/pycore_fileutils.h | 3 +- Lib/test/test_genericpath.py | 4 +++ ...-08-14-23-11-11.gh-issue-106242.71HMym.rst | 1 + Modules/posixmodule.c | 4 ++- Python/fileutils.c | 29 ++++++++++++++----- 5 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index ef6642d00f1b54..7c2b6ec0bffef5 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -252,7 +252,8 @@ extern int _Py_add_relfile(wchar_t *dirname, const wchar_t *relfile, size_t bufsize); extern size_t _Py_find_basename(const wchar_t *filename); -PyAPI_FUNC(wchar_t *) _Py_normpath(wchar_t *path, Py_ssize_t size); +PyAPI_FUNC(wchar_t*) _Py_normpath(wchar_t *path, Py_ssize_t size); +extern wchar_t *_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *length); // The Windows Games API family does not provide these functions // so provide our own implementations. Remove them in case they get added diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py index 489044f8090d3b..4f311c2d498e9f 100644 --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -460,6 +460,10 @@ def test_normpath_issue5827(self): for path in ('', '.', '/', '\\', '///foo/.//bar//'): self.assertIsInstance(self.pathmodule.normpath(path), str) + def test_normpath_issue106242(self): + for path in ('\x00', 'foo\x00bar', '\x00\x00', '\x00foo', 'foo\x00'): + self.assertEqual(self.pathmodule.normpath(path), path) + def test_abspath_issue3426(self): # Check that abspath returns unicode when the arg is unicode # with both ASCII and non-ASCII cwds. diff --git a/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst b/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst new file mode 100644 index 00000000000000..44237a9f15708c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst @@ -0,0 +1 @@ +Fixes :func:`os.path.normpath` to handle embedded null characters without truncating the path. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 342f393b1f0f9c..b9f45c0ce5543d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5275,7 +5275,9 @@ os__path_normpath_impl(PyObject *module, PyObject *path) if (!buffer) { return NULL; } - PyObject *result = PyUnicode_FromWideChar(_Py_normpath(buffer, len), -1); + Py_ssize_t norm_len; + wchar_t *norm_path = _Py_normpath_and_size(buffer, len, &norm_len); + PyObject *result = PyUnicode_FromWideChar(norm_path, norm_len); PyMem_Free(buffer); return result; } diff --git a/Python/fileutils.c b/Python/fileutils.c index f137ee936502c1..268ffa3d61a470 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -2377,12 +2377,14 @@ _Py_find_basename(const wchar_t *filename) path, which will be within the original buffer. Guaranteed to not make the path longer, and will not fail. 'size' is the length of the path, if known. If -1, the first null character will be assumed - to be the end of the path. */ + to be the end of the path. 'normsize' will be set to contain the + length of the resulting normalized path. */ wchar_t * -_Py_normpath(wchar_t *path, Py_ssize_t size) +_Py_normpath_and_size(wchar_t *path, Py_ssize_t size, Py_ssize_t *normsize) { assert(path != NULL); - if (!path[0] || size == 0) { + if ((size < 0 && !path[0]) || size == 0) { + *normsize = 0; return path; } wchar_t *pEnd = size >= 0 ? &path[size] : NULL; @@ -2431,11 +2433,7 @@ _Py_normpath(wchar_t *path, Py_ssize_t size) *p2++ = lastC = *p1; } } - if (sepCount) { - minP2 = p2; // Invalid path - } else { - minP2 = p2 - 1; // Absolute path has SEP at minP2 - } + minP2 = p2 - 1; } #else // Skip past two leading SEPs @@ -2495,13 +2493,28 @@ _Py_normpath(wchar_t *path, Py_ssize_t size) while (--p2 != minP2 && *p2 == SEP) { *p2 = L'\0'; } + } else { + --p2; } + *normsize = p2 - path + 1; #undef SEP_OR_END #undef IS_SEP #undef IS_END return path; } +/* In-place path normalisation. Returns the start of the normalized + path, which will be within the original buffer. Guaranteed to not + make the path longer, and will not fail. 'size' is the length of + the path, if known. If -1, the first null character will be assumed + to be the end of the path. */ +wchar_t * +_Py_normpath(wchar_t *path, Py_ssize_t size) +{ + Py_ssize_t norm_length; + return _Py_normpath_and_size(path, size, &norm_length); +} + /* Get the current directory. buflen is the buffer size in wide characters including the null character. Decode the path from the locale encoding. From 277bf80238c944f4edada9b5f1885e3567f5fc63 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 17 Aug 2023 02:20:23 +0300 Subject: [PATCH 0557/1206] [3.12] gh-107298: Fix C API Buffer documentation (GH-108011). (#108048) (cherry picked from commit c2941cba7a986e6158eebb2a0bf33906dcd78616) Co-authored-by: Victor Stinner --- Doc/c-api/buffer.rst | 22 +++++++++++++--------- Doc/c-api/typeobj.rst | 2 +- Doc/tools/.nitignore | 1 - 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index ba391a5279f205..e572815ffd6259 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -163,13 +163,6 @@ a buffer, see :c:func:`PyObject_GetBuffer`. and :c:member:`~Py_buffer.suboffsets` MUST be ``NULL``. The maximum number of dimensions is given by :c:macro:`PyBUF_MAX_NDIM`. - .. :c:macro:: PyBUF_MAX_NDIM - - The maximum number of dimensions the memory represents. - Exporters MUST respect this limit, consumers of multi-dimensional - buffers SHOULD be able to handle up to :c:macro:`!PyBUF_MAX_NDIM` dimensions. - Currently set to 64. - .. c:member:: Py_ssize_t *shape An array of :c:type:`Py_ssize_t` of length :c:member:`~Py_buffer.ndim` @@ -221,6 +214,17 @@ a buffer, see :c:func:`PyObject_GetBuffer`. freed when the buffer is released. The consumer MUST NOT alter this value. + +Constants: + +.. c:macro:: PyBUF_MAX_NDIM + + The maximum number of dimensions the memory represents. + Exporters MUST respect this limit, consumers of multi-dimensional + buffers SHOULD be able to handle up to :c:macro:`!PyBUF_MAX_NDIM` dimensions. + Currently set to 64. + + .. _buffer-request-types: Buffer request types @@ -444,7 +448,7 @@ Buffer-related functions Send a request to *exporter* to fill in *view* as specified by *flags*. If the exporter cannot provide a buffer of the exact type, it MUST raise - :c:data:`PyExc_BufferError`, set ``view->obj`` to ``NULL`` and + :exc:`BufferError`, set ``view->obj`` to ``NULL`` and return ``-1``. On success, fill in *view*, set ``view->obj`` to a new reference @@ -531,7 +535,7 @@ Buffer-related functions and :c:macro:`PyBUF_WRITABLE` is set in *flags*. On success, set ``view->obj`` to a new reference to *exporter* and - return 0. Otherwise, raise :c:data:`PyExc_BufferError`, set + return 0. Otherwise, raise :exc:`BufferError`, set ``view->obj`` to ``NULL`` and return ``-1``; If this function is used as part of a :ref:`getbufferproc `, diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index faa183e27fcfa2..d394ce10504b0e 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2443,7 +2443,7 @@ Buffer Object Structures Except for point (3), an implementation of this function MUST take these steps: - (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, + (1) Check if the request can be met. If not, raise :exc:`BufferError`, set :c:expr:`view->obj` to ``NULL`` and return ``-1``. (2) Fill in the requested fields. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 8e9ac17135ebec..9a0a6c2561d122 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -4,7 +4,6 @@ # to help avoid merge conflicts. Doc/c-api/arg.rst -Doc/c-api/buffer.rst Doc/c-api/datetime.rst Doc/c-api/descriptor.rst Doc/c-api/dict.rst From 589bc198d01aa8c128ad403cb0c9399689047a82 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:20:49 -0700 Subject: [PATCH 0558/1206] [3.12] GH-92584: Remove references to Distutils in ``PYTHONUSERBASE`` (GH-108040) (#108060) GH-92584: Remove references to Distutils in ``PYTHONUSERBASE`` (GH-108040) Remove references to Distutils in ``PYTHONUSERBASE`` (cherry picked from commit 636ca313b2f7ce09a311889995778dccae8ebe40) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/using/cmdline.rst | 4 ++-- Misc/python.man | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 4bf67eb439ec6c..23c89400f152b1 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -811,8 +811,8 @@ conflict. Defines the :data:`user base directory `, which is used to compute the path of the :data:`user site-packages directory ` - and :ref:`Distutils installation paths ` for - ``python setup.py install --user``. + and :ref:`installation paths ` for + ``python -m pip install --user``. .. seealso:: diff --git a/Misc/python.man b/Misc/python.man index bf7cf767d164a6..9f89c94adf5028 100644 --- a/Misc/python.man +++ b/Misc/python.man @@ -592,8 +592,8 @@ works on Mac OS X. .IP PYTHONUSERBASE Defines the user base directory, which is used to compute the path of the user .IR site-packages -directory and Distutils installation paths for -.IR "python setup\.py install \-\-user" . +directory and installation paths for +.IR "python \-m pip install \-\-user" . .IP PYTHONPROFILEIMPORTTIME If this environment variable is set to a non-empty string, Python will show how long each import takes. This is exactly equivalent to setting From 2cbb452b10a1adf3a564f91949815170446523f9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:21:08 -0700 Subject: [PATCH 0559/1206] [3.12] GH-92584: Redirect macOS package installation to the PPUG (GH-108044) (#108058) GH-92584: Redirect macOS package installation to the PPUG (GH-108044) (cherry picked from commit 902864256cb261428ae9682ca0ffddd597e1f894) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/using/mac.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index 65178272862168..eb1413af2cbc3d 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -125,13 +125,9 @@ http://www.hashcollision.org/hkn/python/idle_intro/index.html. Installing Additional Python Packages ===================================== -There are several methods to install additional Python packages: +This section has moved to the `Python Packaging User Guide`_. -* Packages can be installed via the standard Python distutils mode (``python - setup.py install``). - -* Many packages can also be installed via the :program:`setuptools` extension - or :program:`pip` wrapper, see https://pip.pypa.io/. +.. _Python Packaging User Guide: https://packaging.python.org/en/latest/tutorials/installing-packages/ GUI Programming on the Mac From 931df0a47cfa5f6ed321c5bab6f0884bd524d1a0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:30:08 -0700 Subject: [PATCH 0560/1206] [3.12] GH-92584: Remove references to Distutils in configure.rst (GH-108043) (#108063) GH-92584: Remove references to Distutils in configure.rst (GH-108043) Remove references to Distutils in configure.rst (cherry picked from commit e88eb3775ecdcb3af6c6d694a935b7fa5f41e5ce) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/using/configure.rst | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 924e73dc54da2e..441d346a1a38a0 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -686,7 +686,6 @@ Main files of the build system * :file:`pyconfig.h` (created by :file:`configure`); * :file:`Modules/Setup`: C extensions built by the Makefile using :file:`Module/makesetup` shell script; -* :file:`setup.py`: C extensions built using the ``setuptools`` package. Main build steps ---------------- @@ -695,8 +694,7 @@ Main build steps * A static ``libpython`` library (``.a``) is created from objects files. * ``python.o`` and the static ``libpython`` library are linked into the final ``python`` program. -* C extensions are built by the Makefile (see :file:`Modules/Setup`) - and ``python setup.py build``. +* C extensions are built by the Makefile (see :file:`Modules/Setup`). Main Makefile targets --------------------- @@ -748,9 +746,6 @@ Example on Linux x86-64:: At the beginning of the files, C extensions are built as built-in modules. Extensions defined after the ``*shared*`` marker are built as dynamic libraries. -The :file:`setup.py` script only builds C extensions as shared libraries using -the :mod:`distutils` module. - The :c:macro:`PyAPI_FUNC()`, :c:macro:`PyAPI_API()` and :c:macro:`PyMODINIT_FUNC()` macros of :file:`Include/pyport.h` are defined differently depending if the ``Py_BUILD_CORE_MODULE`` macro is defined: @@ -784,7 +779,7 @@ Preprocessor flags headers in a nonstandard directory ````. Both :envvar:`CPPFLAGS` and :envvar:`LDFLAGS` need to contain the shell's - value for setup.py to be able to build extension modules using the + value to be able to build extension modules using the directories specified in the environment variables. .. envvar:: BASECPPFLAGS @@ -821,8 +816,8 @@ Compiler flags .. envvar:: CFLAGS_NODIST :envvar:`CFLAGS_NODIST` is used for building the interpreter and stdlib C - extensions. Use it when a compiler flag should *not* be part of the - distutils :envvar:`CFLAGS` once Python is installed (:issue:`21121`). + extensions. Use it when a compiler flag should *not* be part of + :envvar:`CFLAGS` once Python is installed (:gh:`65320`). In particular, :envvar:`CFLAGS` should not contain: @@ -952,7 +947,7 @@ Linker flags :envvar:`LDFLAGS_NODIST` is used in the same manner as :envvar:`CFLAGS_NODIST`. Use it when a linker flag should *not* be part of - the distutils :envvar:`LDFLAGS` once Python is installed (:issue:`35257`). + :envvar:`LDFLAGS` once Python is installed (:gh:`65320`). In particular, :envvar:`LDFLAGS` should not contain: @@ -974,7 +969,7 @@ Linker flags directory ````. Both :envvar:`CPPFLAGS` and :envvar:`LDFLAGS` need to contain the shell's - value for setup.py to be able to build extension modules using the + value to be able to build extension modules using the directories specified in the environment variables. .. envvar:: LIBS From 25763030074e678b7e2d17a868355131f52d9a6b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Aug 2023 03:50:46 -0700 Subject: [PATCH 0561/1206] [3.12] GH-107987: Remove the Distributing Python Modules guide (GH-108016) (#108081) GH-107987: Remove the Distributing Python Modules guide (GH-108016) (cherry picked from commit 33e6e3fec02ff3035dec52692542d3dd10124bef) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/conf.py | 2 - Doc/contents.rst | 1 - Doc/distributing/index.rst | 175 +++---------------------------------- Doc/installing/index.rst | 4 +- Doc/tutorial/venv.rst | 4 +- 5 files changed, 16 insertions(+), 170 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index 8224b248062f4d..c1a7ab52257074 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -283,8 +283,6 @@ latex_documents = [ ('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'), - ('distributing/index', 'distributing.tex', - 'Distributing Python Modules', _stdauthor, 'manual'), ('extending/index', 'extending.tex', 'Extending and Embedding Python', _stdauthor, 'manual'), ('installing/index', 'installing.tex', diff --git a/Doc/contents.rst b/Doc/contents.rst index 464f93bdf85f95..59cc541d4cb998 100644 --- a/Doc/contents.rst +++ b/Doc/contents.rst @@ -11,7 +11,6 @@ library/index.rst extending/index.rst c-api/index.rst - distributing/index.rst installing/index.rst howto/index.rst faq/index.rst diff --git a/Doc/distributing/index.rst b/Doc/distributing/index.rst index d237f8f082d87b..2430564b45d6d2 100644 --- a/Doc/distributing/index.rst +++ b/Doc/distributing/index.rst @@ -1,174 +1,19 @@ +:orphan: + +.. This page is retained solely for existing links to /distributing/index.html. + Direct readers to the PPUG instead. + .. _distributing-index: ############################### Distributing Python Modules ############################### -:Email: distutils-sig@python.org - - -As a popular open source development project, Python has an active -supporting community of contributors and users that also make their software -available for other Python developers to use under open source license terms. - -This allows Python users to share and collaborate effectively, benefiting -from the solutions others have already created to common (and sometimes -even rare!) problems, as well as potentially contributing their own -solutions to the common pool. - -This guide covers the distribution part of the process. For a guide to -installing other Python projects, refer to the -:ref:`installation guide `. - .. note:: - For corporate and other institutional users, be aware that many - organisations have their own policies around using and contributing to - open source software. Please take such policies into account when making - use of the distribution and installation tools provided with Python. - - -Key terms -========= - -* the `Python Package Index `__ is a public - repository of open source licensed packages made available for use by - other Python users -* the `Python Packaging Authority - `__ are the group of - developers and documentation authors responsible for the maintenance and - evolution of the standard packaging tools and the associated metadata and - file format standards. They maintain a variety of tools, documentation - and issue trackers on `GitHub `__. -* ``distutils`` is the original build and distribution system first added - to the Python standard library in 1998. While direct use of ``distutils`` - is being phased out, it still laid the foundation for the current packaging - and distribution infrastructure, and it not only remains part of the - standard library, but its name lives on in other ways (such as the name - of the mailing list used to coordinate Python packaging standards - development). -* `setuptools`_ is a (largely) drop-in replacement for ``distutils`` first - published in 2004. Its most notable addition over the unmodified - ``distutils`` tools was the ability to declare dependencies on other - packages. It is currently recommended as a more regularly updated - alternative to ``distutils`` that offers consistent support for more - recent packaging standards across a wide range of Python versions. -* `wheel`_ (in this context) is a project that adds the ``bdist_wheel`` - command to ``distutils``/`setuptools`_. This produces a cross platform - binary packaging format (called "wheels" or "wheel files" and defined in - :pep:`427`) that allows Python libraries, even those including binary - extensions, to be installed on a system without needing to be built - locally. - -.. _setuptools: https://setuptools.readthedocs.io/en/latest/ -.. _wheel: https://wheel.readthedocs.io/ - -Open source licensing and collaboration -======================================= - -In most parts of the world, software is automatically covered by copyright. -This means that other developers require explicit permission to copy, use, -modify and redistribute the software. - -Open source licensing is a way of explicitly granting such permission in a -relatively consistent way, allowing developers to share and collaborate -efficiently by making common solutions to various problems freely available. -This leaves many developers free to spend more time focusing on the problems -that are relatively unique to their specific situation. - -The distribution tools provided with Python are designed to make it -reasonably straightforward for developers to make their own contributions -back to that common pool of software if they choose to do so. - -The same distribution tools can also be used to distribute software within -an organisation, regardless of whether that software is published as open -source software or not. - - -Installing the tools -==================== - -The standard library does not include build tools that support modern -Python packaging standards, as the core development team has found that it -is important to have standard tools that work consistently, even on older -versions of Python. - -The currently recommended build and distribution tools can be installed -by invoking the ``pip`` module at the command line:: - - python -m pip install setuptools wheel twine - -.. note:: - - For POSIX users (including macOS and Linux users), these instructions - assume the use of a :term:`virtual environment`. - - For Windows users, these instructions assume that the option to - adjust the system PATH environment variable was selected when installing - Python. - -The Python Packaging User Guide includes more details on the `currently -recommended tools`_. - -.. _currently recommended tools: https://packaging.python.org/guides/tool-recommendations/#packaging-tool-recommendations - -.. index:: - single: Python Package Index (PyPI) - single: PyPI; (see Python Package Index (PyPI)) - -.. _publishing-python-packages: - -Reading the Python Packaging User Guide -======================================= - -The Python Packaging User Guide covers the various key steps and elements -involved in creating and publishing a project: - -* `Project structure`_ -* `Building and packaging the project`_ -* `Uploading the project to the Python Package Index`_ -* `The .pypirc file`_ - -.. _Project structure: https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects -.. _Building and packaging the project: https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files -.. _Uploading the project to the Python Package Index: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives -.. _The .pypirc file: https://packaging.python.org/specifications/pypirc/ - - -How do I...? -============ - -These are quick answers or links for some common tasks. - -... choose a name for my project? ---------------------------------- - -This isn't an easy topic, but here are a few tips: - -* check the Python Package Index to see if the name is already in use -* check popular hosting sites like GitHub, Bitbucket, etc to see if there - is already a project with that name -* check what comes up in a web search for the name you're considering -* avoid particularly common words, especially ones with multiple meanings, - as they can make it difficult for users to find your software when - searching for it - - -... create and distribute binary extensions? --------------------------------------------- - -This is actually quite a complex topic, with a variety of alternatives -available depending on exactly what you're aiming to achieve. See the -Python Packaging User Guide for more information and recommendations. - -.. seealso:: - - `Python Packaging User Guide: Binary Extensions - `__ - -.. other topics: + Information and guidance on distributing Python modules and packages + has been moved to the `Python Packaging User Guide`_, + and the tutorial on `packaging Python projects`_. - Once the Development & Deployment part of PPUG is fleshed out, some of - those sections should be linked from new questions here (most notably, - we should have a question about avoiding depending on PyPI that links to - https://packaging.python.org/en/latest/mirrors/) + .. _Python Packaging User Guide: https://packaging.python.org/ + .. _packaging Python projects: https://packaging.python.org/en/latest/tutorials/packaging-projects/ diff --git a/Doc/installing/index.rst b/Doc/installing/index.rst index 5aec5178d48f3d..a46c1caefe4d8a 100644 --- a/Doc/installing/index.rst +++ b/Doc/installing/index.rst @@ -19,7 +19,9 @@ solutions to the common pool. This guide covers the installation part of the process. For a guide to creating and sharing your own Python projects, refer to the -:ref:`distribution guide `. +`Python packaging user guide`_. + +.. _Python Packaging User Guide: https://packaging.python.org/en/latest/tutorials/packaging-projects/ .. note:: diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index d1bba098d7d23b..a6dead2eac11f6 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -207,4 +207,6 @@ necessary packages with ``install -r``: ``pip`` has many more options. Consult the :ref:`installing-index` guide for complete documentation for ``pip``. When you've written a package and want to make it available on the Python Package Index, -consult the :ref:`distributing-index` guide. +consult the `Python packaging user guide`_. + +.. _Python Packaging User Guide: https://packaging.python.org/en/latest/tutorials/packaging-projects/ From e0244e85d09a3d2a40211c587891d908c35d277c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Aug 2023 03:51:07 -0700 Subject: [PATCH 0562/1206] [3.12] gh-108000: Test that `lambda` also has `__type_params__` (GH-108002) (#108019) gh-108000: Test that `lambda` also has `__type_params__` (GH-108002) (cherry picked from commit a8d440b3837273926af5ce996162b019290ddad5) Co-authored-by: Nikita Sobolev --- Lib/test/test_funcattrs.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index e08d72877d8aef..35b473d5e9a0b4 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -194,16 +194,19 @@ def test___qualname__(self): def test___type_params__(self): def generic[T](): pass def not_generic(): pass + lambda_ = lambda: ... T, = generic.__type_params__ self.assertIsInstance(T, typing.TypeVar) self.assertEqual(generic.__type_params__, (T,)) - self.assertEqual(not_generic.__type_params__, ()) - with self.assertRaises(TypeError): - del not_generic.__type_params__ - with self.assertRaises(TypeError): - not_generic.__type_params__ = 42 - not_generic.__type_params__ = (T,) - self.assertEqual(not_generic.__type_params__, (T,)) + for func in (not_generic, lambda_): + with self.subTest(func=func): + self.assertEqual(func.__type_params__, ()) + with self.assertRaises(TypeError): + del func.__type_params__ + with self.assertRaises(TypeError): + func.__type_params__ = 42 + func.__type_params__ = (T,) + self.assertEqual(func.__type_params__, (T,)) def test___code__(self): num_one, num_two = 7, 8 From 125aab99ab3d11eaca8e4248548856a077355391 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Aug 2023 03:52:08 -0700 Subject: [PATCH 0563/1206] [3.12] gh-107298: Add standard exceptions and warnings in the nitpick_ignore list (GH-108029) (#108070) gh-107298: Add standard exceptions and warnings in the nitpick_ignore list (GH-108029) (cherry picked from commit c9d83f93d804b80ee14480466ebee63a6f97dac2) Co-authored-by: Serhiy Storchaka --- Doc/conf.py | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/Doc/conf.py b/Doc/conf.py index c1a7ab52257074..a8805bd4653a8a 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -157,6 +157,77 @@ ('envvar', 'USER'), ('envvar', 'USERNAME'), ('envvar', 'USERPROFILE'), +] + +# Temporary undocumented names. +# In future this list must be empty. +nitpick_ignore += [ + # C API: Standard Python exception classes + ('c:data', 'PyExc_ArithmeticError'), + ('c:data', 'PyExc_AssertionError'), + ('c:data', 'PyExc_AttributeError'), + ('c:data', 'PyExc_BaseException'), + ('c:data', 'PyExc_BlockingIOError'), + ('c:data', 'PyExc_BrokenPipeError'), + ('c:data', 'PyExc_BufferError'), + ('c:data', 'PyExc_ChildProcessError'), + ('c:data', 'PyExc_ConnectionAbortedError'), + ('c:data', 'PyExc_ConnectionError'), + ('c:data', 'PyExc_ConnectionRefusedError'), + ('c:data', 'PyExc_ConnectionResetError'), + ('c:data', 'PyExc_EOFError'), + ('c:data', 'PyExc_Exception'), + ('c:data', 'PyExc_FileExistsError'), + ('c:data', 'PyExc_FileNotFoundError'), + ('c:data', 'PyExc_FloatingPointError'), + ('c:data', 'PyExc_GeneratorExit'), + ('c:data', 'PyExc_ImportError'), + ('c:data', 'PyExc_IndentationError'), + ('c:data', 'PyExc_IndexError'), + ('c:data', 'PyExc_InterruptedError'), + ('c:data', 'PyExc_IsADirectoryError'), + ('c:data', 'PyExc_KeyboardInterrupt'), + ('c:data', 'PyExc_KeyError'), + ('c:data', 'PyExc_LookupError'), + ('c:data', 'PyExc_MemoryError'), + ('c:data', 'PyExc_ModuleNotFoundError'), + ('c:data', 'PyExc_NameError'), + ('c:data', 'PyExc_NotADirectoryError'), + ('c:data', 'PyExc_NotImplementedError'), + ('c:data', 'PyExc_OSError'), + ('c:data', 'PyExc_OverflowError'), + ('c:data', 'PyExc_PermissionError'), + ('c:data', 'PyExc_ProcessLookupError'), + ('c:data', 'PyExc_RecursionError'), + ('c:data', 'PyExc_ReferenceError'), + ('c:data', 'PyExc_RuntimeError'), + ('c:data', 'PyExc_StopAsyncIteration'), + ('c:data', 'PyExc_StopIteration'), + ('c:data', 'PyExc_SyntaxError'), + ('c:data', 'PyExc_SystemError'), + ('c:data', 'PyExc_SystemExit'), + ('c:data', 'PyExc_TabError'), + ('c:data', 'PyExc_TimeoutError'), + ('c:data', 'PyExc_TypeError'), + ('c:data', 'PyExc_UnboundLocalError'), + ('c:data', 'PyExc_UnicodeDecodeError'), + ('c:data', 'PyExc_UnicodeEncodeError'), + ('c:data', 'PyExc_UnicodeError'), + ('c:data', 'PyExc_UnicodeTranslateError'), + ('c:data', 'PyExc_ValueError'), + ('c:data', 'PyExc_ZeroDivisionError'), + # C API: Standard Python warning classes + ('c:data', 'PyExc_BytesWarning'), + ('c:data', 'PyExc_DeprecationWarning'), + ('c:data', 'PyExc_FutureWarning'), + ('c:data', 'PyExc_ImportWarning'), + ('c:data', 'PyExc_PendingDeprecationWarning'), + ('c:data', 'PyExc_ResourceWarning'), + ('c:data', 'PyExc_RuntimeWarning'), + ('c:data', 'PyExc_SyntaxWarning'), + ('c:data', 'PyExc_UnicodeWarning'), + ('c:data', 'PyExc_UserWarning'), + ('c:data', 'PyExc_Warning'), # Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot # be resolved, as the method is currently undocumented. For context, see # https://github.com/python/cpython/pull/103289. From 41c951b62f9c08b5965ca670e660955f95a8cdf5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Aug 2023 03:52:48 -0700 Subject: [PATCH 0564/1206] [3.12] gh-107298: Fix some references in the C API documentation (GH-108072) (#108074) gh-107298: Fix some references in the C API documentation (GH-108072) (cherry picked from commit f51f0466c07eabc6177c2f64f70c952dada050e8) Co-authored-by: Serhiy Storchaka --- Doc/c-api/typeobj.rst | 2 +- Doc/extending/extending.rst | 4 ++-- Doc/using/configure.rst | 4 ++-- Doc/whatsnew/2.2.rst | 2 +- Doc/whatsnew/2.3.rst | 2 +- Doc/whatsnew/2.4.rst | 2 +- Doc/whatsnew/2.6.rst | 6 +++--- Doc/whatsnew/2.7.rst | 12 ++++++------ Doc/whatsnew/3.0.rst | 2 +- Doc/whatsnew/3.1.rst | 2 +- Doc/whatsnew/3.2.rst | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index d394ce10504b0e..cd037b4de882e1 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1697,7 +1697,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) to a pointer, are valid C99 address constants. However, the unary '&' operator applied to a non-static variable - like :c:func:`PyBaseObject_Type` is not required to produce an address + like :c:data:`PyBaseObject_Type` is not required to produce an address constant. Compilers may support this (gcc does), MSVC does not. Both compilers are strictly standard conforming in this particular behavior. diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 72e30a68828072..68f8e0c6674657 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -242,7 +242,7 @@ needed to ensure that it will not be discarded, causing :c:data:`!SpamError` to become a dangling pointer. Should it become a dangling pointer, C code which raises the exception could cause a core dump or other unintended side effects. -We discuss the use of ``PyMODINIT_FUNC`` as a function return type later in this +We discuss the use of :c:macro:`PyMODINIT_FUNC` as a function return type later in this sample. The :exc:`!spam.error` exception can be raised in your extension module using a @@ -363,7 +363,7 @@ only non-\ ``static`` item defined in the module file:: return PyModule_Create(&spammodule); } -Note that PyMODINIT_FUNC declares the function as ``PyObject *`` return type, +Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` return type, declares any special linkage declarations required by the platform, and for C++ declares the function as ``extern "C"``. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 441d346a1a38a0..f4adea82a87c38 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -746,8 +746,8 @@ Example on Linux x86-64:: At the beginning of the files, C extensions are built as built-in modules. Extensions defined after the ``*shared*`` marker are built as dynamic libraries. -The :c:macro:`PyAPI_FUNC()`, :c:macro:`PyAPI_API()` and -:c:macro:`PyMODINIT_FUNC()` macros of :file:`Include/pyport.h` are defined +The :c:macro:`PyAPI_FUNC()`, :c:macro:`PyAPI_DATA()` and +:c:macro:`PyMODINIT_FUNC` macros of :file:`Include/pyport.h` are defined differently depending if the ``Py_BUILD_CORE_MODULE`` macro is defined: * Use ``Py_EXPORTED_SYMBOL`` if the ``Py_BUILD_CORE_MODULE`` is defined diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 44e9bd8d492bfc..7de48a40263034 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -1109,7 +1109,7 @@ code, none of the changes described here will affect you very much. definition tables to simplify implementation of methods with no arguments or a single untyped argument. Calling such methods is more efficient than calling a corresponding method that uses :c:macro:`METH_VARARGS`. Also, the old - :c:macro:`METH_OLDARGS` style of writing C methods is now officially deprecated. + :c:macro:`!METH_OLDARGS` style of writing C methods is now officially deprecated. * Two new wrapper functions, :c:func:`PyOS_snprintf` and :c:func:`PyOS_vsnprintf` were added to provide cross-platform implementations for the relatively new diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index 3dfe509e1d1c08..a9c44d501701c8 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1886,7 +1886,7 @@ Changes to Python's build process and to the C API include: (:file:`libpython2.3.so`) by supplying :option:`!--enable-shared` when running Python's :program:`configure` script. (Contributed by Ondrej Palkovsky.) -* The :c:macro:`DL_EXPORT` and :c:macro:`DL_IMPORT` macros are now deprecated. +* The :c:macro:`!DL_EXPORT` and :c:macro:`!DL_IMPORT` macros are now deprecated. Initialization functions for Python extension modules should now be declared using the new macro :c:macro:`PyMODINIT_FUNC`, while the Python core will generally use the :c:macro:`PyAPI_FUNC` and :c:macro:`PyAPI_DATA` macros. diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index a00c4360b9c685..4272928fb67894 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1476,7 +1476,7 @@ Some of the changes to Python's build process and to the C API are: :c:func:`PyArg_ParseTupleAndKeywords` but takes a :c:type:`va_list` instead of a number of arguments. (Contributed by Greg Chapman.) -* A new method flag, :c:macro:`METH_COEXISTS`, allows a function defined in slots +* A new method flag, :c:macro:`METH_COEXIST`, allows a function defined in slots to co-exist with a :c:type:`PyCFunction` having the same name. This can halve the access time for a method such as :meth:`set.__contains__`. (Contributed by Raymond Hettinger.) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 2b8fa1546a5884..563fa461d2a868 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -3060,9 +3060,9 @@ Changes to Python's build process and to the C API include: * Some macros were renamed in both 3.0 and 2.6 to make it clearer that they are macros, - not functions. :c:macro:`Py_Size()` became :c:macro:`Py_SIZE()`, - :c:macro:`Py_Type()` became :c:macro:`Py_TYPE()`, and - :c:macro:`Py_Refcnt()` became :c:macro:`Py_REFCNT()`. + not functions. :c:macro:`!Py_Size()` became :c:macro:`Py_SIZE()`, + :c:macro:`!Py_Type()` became :c:macro:`Py_TYPE()`, and + :c:macro:`!Py_Refcnt()` became :c:macro:`Py_REFCNT()`. The mixed-case macros are still available in Python 2.6 for backward compatibility. (:issue:`1629`) diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index cf8b00fd30979f..76beb4d746a190 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2287,10 +2287,10 @@ object, and then get the ``void *`` pointer, which will usually point to an array of pointers to the module's various API functions. There is an existing data type already used for this, -:c:type:`PyCObject`, but it doesn't provide type safety. Evil code +:c:type:`!PyCObject`, but it doesn't provide type safety. Evil code written in pure Python could cause a segmentation fault by taking a -:c:type:`PyCObject` from module A and somehow substituting it for the -:c:type:`PyCObject` in module B. Capsules know their own name, +:c:type:`!PyCObject` from module A and somehow substituting it for the +:c:type:`!PyCObject` in module B. Capsules know their own name, and getting the pointer requires providing the name: .. code-block:: c @@ -2310,10 +2310,10 @@ detect the mismatched name and return false. Refer to :ref:`using-capsules` for more information on using these objects. Python 2.7 now uses capsules internally to provide various -extension-module APIs, but the :c:func:`PyCObject_AsVoidPtr` was +extension-module APIs, but the :c:func:`!PyCObject_AsVoidPtr` was modified to handle capsules, preserving compile-time compatibility -with the :c:type:`CObject` interface. Use of -:c:func:`PyCObject_AsVoidPtr` will signal a +with the :c:type:`!PyCObject` interface. Use of +:c:func:`!PyCObject_AsVoidPtr` will signal a :exc:`PendingDeprecationWarning`, which is silent by default. Implemented in Python 3.1 and backported to 2.7 by Larry Hastings; diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index 379c74981fbf08..4f8b05efd44643 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -875,7 +875,7 @@ to the C API. * Renamed the boolean conversion C-level slot and method: ``nb_nonzero`` is now ``nb_bool``. -* Removed :c:macro:`METH_OLDARGS` and :c:macro:`WITH_CYCLE_GC` from the C API. +* Removed :c:macro:`!METH_OLDARGS` and :c:macro:`!WITH_CYCLE_GC` from the C API. .. ====================================================================== diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst index e4365d44928b5b..ceef622f9f8daa 100644 --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -510,7 +510,7 @@ Changes to Python's build process and to the C API include: (Contributed by Mark Dickinson; :issue:`5914`.) -* Added :c:type:`PyCapsule` as a replacement for the :c:type:`PyCObject` API. +* Added :c:type:`PyCapsule` as a replacement for the :c:type:`!PyCObject` API. The principal difference is that the new type has a well defined interface for passing typing safety information and a less complicated signature for calling a destructor. The old type had a problematic API and is now diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index ec4d8a0312b6b3..ec554aacb096cf 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -2658,7 +2658,7 @@ require changes to your code: * "t#" format has been removed: use "s#" or "s*" instead * "w" and "w#" formats has been removed: use "w*" instead -* The :c:type:`PyCObject` type, deprecated in 3.1, has been removed. To wrap +* The :c:type:`!PyCObject` type, deprecated in 3.1, has been removed. To wrap opaque C pointers in Python objects, the :c:type:`PyCapsule` API should be used instead; the new type has a well-defined interface for passing typing safety information and a less complicated signature for calling a destructor. From 560e8595cb34b995310157c6e7a0ca2ecf559885 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 17 Aug 2023 11:53:26 +0100 Subject: [PATCH 0565/1206] [3.12] GH-92584: Remove Installing Python Modules (Distutils version) (GH-108020) (#108062) * [3.12] GH-92584: Remove Installing Python Modules (Distutils version) (GH-108020). (cherry picked from commit fbb7cbc0e92168077fd56de942901511e99ca60a) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/contents.rst | 7 - Doc/extending/building.rst | 1 + Doc/install/index.rst | 1081 ------------------------------------ Doc/library/site.rst | 2 +- Doc/using/cmdline.rst | 2 +- 5 files changed, 3 insertions(+), 1090 deletions(-) delete mode 100644 Doc/install/index.rst diff --git a/Doc/contents.rst b/Doc/contents.rst index 59cc541d4cb998..24ceacb0076b5e 100644 --- a/Doc/contents.rst +++ b/Doc/contents.rst @@ -20,10 +20,3 @@ bugs.rst copyright.rst license.rst - -.. to include legacy packaging docs in build - -.. toctree:: - :hidden: - - install/index.rst diff --git a/Doc/extending/building.rst b/Doc/extending/building.rst index 880bb33ee56718..ddde567f6f3efa 100644 --- a/Doc/extending/building.rst +++ b/Doc/extending/building.rst @@ -45,6 +45,7 @@ See the *"Multiple modules in one library"* section in :pep:`489` for details. .. highlight:: c +.. _install-index: .. _setuptools-index: Building C and C++ Extensions with setuptools diff --git a/Doc/install/index.rst b/Doc/install/index.rst deleted file mode 100644 index ffb4a202fe89f2..00000000000000 --- a/Doc/install/index.rst +++ /dev/null @@ -1,1081 +0,0 @@ -.. highlight:: none - -.. _install-index: - -******************************************** - Installing Python Modules (Legacy version) -******************************************** - -:Author: Greg Ward - -.. TODO: Fill in XXX comments - -.. note:: - - The entire ``distutils`` package has been deprecated and will be - removed in Python 3.12. This documentation is retained as a - reference only, and will be removed with the package. See the - :ref:`What's New ` entry for more information. - -.. seealso:: - - :ref:`installing-index` - The up to date module installation documentation. For regular Python - usage, you almost certainly want that document rather than this one. - -.. note:: - - This document is being retained solely until the ``setuptools`` documentation - at https://setuptools.readthedocs.io/en/latest/setuptools.html - independently covers all of the relevant information currently included here. - -.. note:: - - This guide only covers the basic tools for building and distributing - extensions that are provided as part of this version of Python. Third party - tools offer easier to use and more secure alternatives. Refer to the `quick - recommendations section `__ - in the Python Packaging User Guide for more information. - - -.. _inst-intro: - - -Introduction -============ - -In Python 2.0, the ``distutils`` API was first added to the standard library. -This provided Linux distro maintainers with a standard way of converting -Python projects into Linux distro packages, and system administrators with a -standard way of installing them directly onto target systems. - -In the many years since Python 2.0 was released, tightly coupling the build -system and package installer to the language runtime release cycle has turned -out to be problematic, and it is now recommended that projects use the -``pip`` package installer and the ``setuptools`` build system, rather than -using ``distutils`` directly. - -See :ref:`installing-index` and :ref:`distributing-index` for more details. - -This legacy documentation is being retained only until we're confident that the -``setuptools`` documentation covers everything needed. - -.. _inst-new-standard: - -Distutils based source distributions ------------------------------------- - -If you download a module source distribution, you can tell pretty quickly if it -was packaged and distributed in the standard way, i.e. using the Distutils. -First, the distribution's name and version number will be featured prominently -in the name of the downloaded archive, e.g. :file:`foo-1.0.tar.gz` or -:file:`widget-0.9.7.zip`. Next, the archive will unpack into a similarly named -directory: :file:`foo-1.0` or :file:`widget-0.9.7`. Additionally, the -distribution will contain a setup script :file:`setup.py`, and a file named -:file:`README.txt` or possibly just :file:`README`, which should explain that -building and installing the module distribution is a simple matter of running -one command from a terminal:: - - python setup.py install - -For Windows, this command should be run from a command prompt window -(:menuselection:`Start --> Accessories`):: - - setup.py install - -If all these things are true, then you already know how to build and install the -modules you've just downloaded: Run the command above. Unless you need to -install things in a non-standard way or customize the build process, you don't -really need this manual. Or rather, the above command is everything you need to -get out of this manual. - - -.. _inst-standard-install: - -Standard Build and Install -========================== - -As described in section :ref:`inst-new-standard`, building and installing a module -distribution using the Distutils is usually one simple command to run from a -terminal:: - - python setup.py install - - -.. _inst-platform-variations: - -Platform variations -------------------- - -You should always run the setup command from the distribution root directory, -i.e. the top-level subdirectory that the module source distribution unpacks -into. For example, if you've just downloaded a module source distribution -:file:`foo-1.0.tar.gz` onto a Unix system, the normal thing to do is:: - - gunzip -c foo-1.0.tar.gz | tar xf - # unpacks into directory foo-1.0 - cd foo-1.0 - python setup.py install - -On Windows, you'd probably download :file:`foo-1.0.zip`. If you downloaded the -archive file to :file:`C:\\Temp`, then it would unpack into -:file:`C:\\Temp\\foo-1.0`; you can use either an archive manipulator with a -graphical user interface (such as WinZip) or a command-line tool (such as -:program:`unzip` or :program:`pkunzip`) to unpack the archive. Then, open a -command prompt window and run:: - - cd c:\Temp\foo-1.0 - python setup.py install - - -.. _inst-splitting-up: - -Splitting the job up --------------------- - -Running ``setup.py install`` builds and installs all modules in one run. If you -prefer to work incrementally---especially useful if you want to customize the -build process, or if things are going wrong---you can use the setup script to do -one thing at a time. This is particularly helpful when the build and install -will be done by different users---for example, you might want to build a module -distribution and hand it off to a system administrator for installation (or do -it yourself, with super-user privileges). - -For example, you can build everything in one step, and then install everything -in a second step, by invoking the setup script twice:: - - python setup.py build - python setup.py install - -If you do this, you will notice that running the :command:`install` command -first runs the :command:`build` command, which---in this case---quickly notices -that it has nothing to do, since everything in the :file:`build` directory is -up-to-date. - -You may not need this ability to break things down often if all you do is -install modules downloaded off the 'net, but it's very handy for more advanced -tasks. If you get into distributing your own Python modules and extensions, -you'll run lots of individual Distutils commands on their own. - - -.. _inst-how-build-works: - -How building works ------------------- - -As implied above, the :command:`build` command is responsible for putting the -files to install into a *build directory*. By default, this is :file:`build` -under the distribution root; if you're excessively concerned with speed, or want -to keep the source tree pristine, you can change the build directory with the -:option:`!--build-base` option. For example:: - - python setup.py build --build-base=/path/to/pybuild/foo-1.0 - -(Or you could do this permanently with a directive in your system or personal -Distutils configuration file; see section :ref:`inst-config-files`.) Normally, this -isn't necessary. - -The default layout for the build tree is as follows:: - - --- build/ --- lib/ - or - --- build/ --- lib./ - temp./ - -where ```` expands to a brief description of the current OS/hardware -platform and Python version. The first form, with just a :file:`lib` directory, -is used for "pure module distributions"---that is, module distributions that -include only pure Python modules. If a module distribution contains any -extensions (modules written in C/C++), then the second form, with two ```` -directories, is used. In that case, the :file:`temp.{plat}` directory holds -temporary files generated by the compile/link process that don't actually get -installed. In either case, the :file:`lib` (or :file:`lib.{plat}`) directory -contains all Python modules (pure Python and extensions) that will be installed. - -In the future, more directories will be added to handle Python scripts, -documentation, binary executables, and whatever else is needed to handle the job -of installing Python modules and applications. - - -.. _inst-how-install-works: - -How installation works ----------------------- - -After the :command:`build` command runs (whether you run it explicitly, or the -:command:`install` command does it for you), the work of the :command:`install` -command is relatively simple: all it has to do is copy everything under -:file:`build/lib` (or :file:`build/lib.{plat}`) to your chosen installation -directory. - -If you don't choose an installation directory---i.e., if you just run ``setup.py -install``\ ---then the :command:`install` command installs to the standard -location for third-party Python modules. This location varies by platform and -by how you built/installed Python itself. On Unix (and macOS, which is also -Unix-based), it also depends on whether the module distribution being installed -is pure Python or contains extensions ("non-pure"): - -.. tabularcolumns:: |l|l|l|l| - -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Platform | Standard installation location | Default value | Notes | -+=================+=====================================================+==================================================+=======+ -| Unix (pure) | :file:`{prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Unix (non-pure) | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Windows | :file:`{prefix}\\Lib\\site-packages` | :file:`C:\\Python{XY}\\Lib\\site-packages` | \(2) | -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ - -Notes: - -(1) - Most Linux distributions include Python as a standard part of the system, so - :file:`{prefix}` and :file:`{exec-prefix}` are usually both :file:`/usr` on - Linux. If you build Python yourself on Linux (or any Unix-like system), the - default :file:`{prefix}` and :file:`{exec-prefix}` are :file:`/usr/local`. - -(2) - The default installation directory on Windows was :file:`C:\\Program - Files\\Python` under Python 1.6a1, 1.5.2, and earlier. - -:file:`{prefix}` and :file:`{exec-prefix}` stand for the directories that Python -is installed to, and where it finds its libraries at run-time. They are always -the same under Windows, and very often the same under Unix and macOS. You -can find out what your Python installation uses for :file:`{prefix}` and -:file:`{exec-prefix}` by running Python in interactive mode and typing a few -simple commands. Under Unix, just type ``python`` at the shell prompt. Under -Windows, choose :menuselection:`Start --> Programs --> Python X.Y --> -Python (command line)`. Once the interpreter is started, you type Python code -at the prompt. For example, on my Linux system, I type the three Python -statements shown below, and get the output as shown, to find out my -:file:`{prefix}` and :file:`{exec-prefix}`: - -.. code-block:: pycon - - Python 2.4 (#26, Aug 7 2004, 17:19:02) - Type "help", "copyright", "credits" or "license" for more information. - >>> import sys - >>> sys.prefix - '/usr' - >>> sys.exec_prefix - '/usr' - -A few other placeholders are used in this document: :file:`{X.Y}` stands for the -version of Python, for example ``3.2``; :file:`{abiflags}` will be replaced by -the value of :data:`sys.abiflags` or the empty string for platforms which don't -define ABI flags; :file:`{distname}` will be replaced by the name of the module -distribution being installed. Dots and capitalization are important in the -paths; for example, a value that uses ``python3.2`` on UNIX will typically use -``Python32`` on Windows. - -If you don't want to install modules to the standard location, or if you don't -have permission to write there, then you need to read about alternate -installations in section :ref:`inst-alt-install`. If you want to customize your -installation directories more heavily, see section :ref:`inst-custom-install` on -custom installations. - - -.. _inst-alt-install: - -Alternate Installation -====================== - -Often, it is necessary or desirable to install modules to a location other than -the standard location for third-party Python modules. For example, on a Unix -system you might not have permission to write to the standard third-party module -directory. Or you might wish to try out a module before making it a standard -part of your local Python installation. This is especially true when upgrading -a distribution already present: you want to make sure your existing base of -scripts still works with the new version before actually upgrading. - -The Distutils :command:`install` command is designed to make installing module -distributions to an alternate location simple and painless. The basic idea is -that you supply a base directory for the installation, and the -:command:`install` command picks a set of directories (called an *installation -scheme*) under this base directory in which to install files. The details -differ across platforms, so read whichever of the following sections applies to -you. - -Note that the various alternate installation schemes are mutually exclusive: you -can pass ``--user``, or ``--home``, or ``--prefix`` and ``--exec-prefix``, or -``--install-base`` and ``--install-platbase``, but you can't mix from these -groups. - - -.. _inst-alt-install-user: - -Alternate installation: the user scheme ---------------------------------------- - -This scheme is designed to be the most convenient solution for users that don't -have write permission to the global site-packages directory or don't want to -install into it. It is enabled with a simple option:: - - python setup.py install --user - -Files will be installed into subdirectories of :const:`site.USER_BASE` (written -as :file:`{userbase}` hereafter). This scheme installs pure Python modules and -extension modules in the same location (also known as :const:`site.USER_SITE`). -Here are the values for UNIX, including macOS: - -=============== =========================================================== -Type of file Installation directory -=============== =========================================================== -modules :file:`{userbase}/lib/python{X.Y}/site-packages` -scripts :file:`{userbase}/bin` -data :file:`{userbase}` -C headers :file:`{userbase}/include/python{X.Y}{abiflags}/{distname}` -=============== =========================================================== - -And here are the values used on Windows: - -=============== =========================================================== -Type of file Installation directory -=============== =========================================================== -modules :file:`{userbase}\\Python{XY}\\site-packages` -scripts :file:`{userbase}\\Python{XY}\\Scripts` -data :file:`{userbase}` -C headers :file:`{userbase}\\Python{XY}\\Include\\{distname}` -=============== =========================================================== - -The advantage of using this scheme compared to the other ones described below is -that the user site-packages directory is under normal conditions always included -in :data:`sys.path` (see :mod:`site` for more information), which means that -there is no additional step to perform after running the :file:`setup.py` script -to finalize the installation. - -The :command:`build_ext` command also has a ``--user`` option to add -:file:`{userbase}/include` to the compiler search path for header files and -:file:`{userbase}/lib` to the compiler search path for libraries as well as to -the runtime search path for shared C libraries (rpath). - - -.. _inst-alt-install-home: - -Alternate installation: the home scheme ---------------------------------------- - -The idea behind the "home scheme" is that you build and maintain a personal -stash of Python modules. This scheme's name is derived from the idea of a -"home" directory on Unix, since it's not unusual for a Unix user to make their -home directory have a layout similar to :file:`/usr/` or :file:`/usr/local/`. -This scheme can be used by anyone, regardless of the operating system they -are installing for. - -Installing a new module distribution is as simple as :: - - python setup.py install --home=

- -where you can supply any directory you like for the :option:`!--home` option. On -Unix, lazy typists can just type a tilde (``~``); the :command:`install` command -will expand this to your home directory:: - - python setup.py install --home=~ - -To make Python find the distributions installed with this scheme, you may have -to :ref:`modify Python's search path ` or edit -:mod:`!sitecustomize` (see :mod:`site`) to call :func:`site.addsitedir` or edit -:data:`sys.path`. - -The :option:`!--home` option defines the installation base directory. Files are -installed to the following directories under the installation base as follows: - -=============== =========================================================== -Type of file Installation directory -=============== =========================================================== -modules :file:`{home}/lib/python` -scripts :file:`{home}/bin` -data :file:`{home}` -C headers :file:`{home}/include/python/{distname}` -=============== =========================================================== - -(Mentally replace slashes with backslashes if you're on Windows.) - - -.. _inst-alt-install-prefix-unix: - -Alternate installation: Unix (the prefix scheme) ------------------------------------------------- - -The "prefix scheme" is useful when you wish to use one Python installation to -perform the build/install (i.e., to run the setup script), but install modules -into the third-party module directory of a different Python installation (or -something that looks like a different Python installation). If this sounds a -trifle unusual, it is---that's why the user and home schemes come before. However, -there are at least two known cases where the prefix scheme will be useful. - -First, consider that many Linux distributions put Python in :file:`/usr`, rather -than the more traditional :file:`/usr/local`. This is entirely appropriate, -since in those cases Python is part of "the system" rather than a local add-on. -However, if you are installing Python modules from source, you probably want -them to go in :file:`/usr/local/lib/python2.{X}` rather than -:file:`/usr/lib/python2.{X}`. This can be done with :: - - /usr/bin/python setup.py install --prefix=/usr/local - -Another possibility is a network filesystem where the name used to write to a -remote directory is different from the name used to read it: for example, the -Python interpreter accessed as :file:`/usr/local/bin/python` might search for -modules in :file:`/usr/local/lib/python2.{X}`, but those modules would have to -be installed to, say, :file:`/mnt/{@server}/export/lib/python2.{X}`. This could -be done with :: - - /usr/local/bin/python setup.py install --prefix=/mnt/@server/export - -In either case, the :option:`!--prefix` option defines the installation base, and -the :option:`!--exec-prefix` option defines the platform-specific installation -base, which is used for platform-specific files. (Currently, this just means -non-pure module distributions, but could be expanded to C libraries, binary -executables, etc.) If :option:`!--exec-prefix` is not supplied, it defaults to -:option:`!--prefix`. Files are installed as follows: - -================= ========================================================== -Type of file Installation directory -================= ========================================================== -Python modules :file:`{prefix}/lib/python{X.Y}/site-packages` -extension modules :file:`{exec-prefix}/lib/python{X.Y}/site-packages` -scripts :file:`{prefix}/bin` -data :file:`{prefix}` -C headers :file:`{prefix}/include/python{X.Y}{abiflags}/{distname}` -================= ========================================================== - -There is no requirement that :option:`!--prefix` or :option:`!--exec-prefix` -actually point to an alternate Python installation; if the directories listed -above do not already exist, they are created at installation time. - -Incidentally, the real reason the prefix scheme is important is simply that a -standard Unix installation uses the prefix scheme, but with :option:`!--prefix` -and :option:`!--exec-prefix` supplied by Python itself as ``sys.prefix`` and -``sys.exec_prefix``. Thus, you might think you'll never use the prefix scheme, -but every time you run ``python setup.py install`` without any other options, -you're using it. - -Note that installing extensions to an alternate Python installation has no -effect on how those extensions are built: in particular, the Python header files -(:file:`Python.h` and friends) installed with the Python interpreter used to run -the setup script will be used in compiling extensions. It is your -responsibility to ensure that the interpreter used to run extensions installed -in this way is compatible with the interpreter used to build them. The best way -to do this is to ensure that the two interpreters are the same version of Python -(possibly different builds, or possibly copies of the same build). (Of course, -if your :option:`!--prefix` and :option:`!--exec-prefix` don't even point to an -alternate Python installation, this is immaterial.) - - -.. _inst-alt-install-prefix-windows: - -Alternate installation: Windows (the prefix scheme) ---------------------------------------------------- - -Windows has no concept of a user's home directory, and since the standard Python -installation under Windows is simpler than under Unix, the :option:`!--prefix` -option has traditionally been used to install additional packages in separate -locations on Windows. :: - - python setup.py install --prefix="\Temp\Python" - -to install modules to the :file:`\\Temp\\Python` directory on the current drive. - -The installation base is defined by the :option:`!--prefix` option; the -:option:`!--exec-prefix` option is not supported under Windows, which means that -pure Python modules and extension modules are installed into the same location. -Files are installed as follows: - -=============== ========================================================== -Type of file Installation directory -=============== ========================================================== -modules :file:`{prefix}\\Lib\\site-packages` -scripts :file:`{prefix}\\Scripts` -data :file:`{prefix}` -C headers :file:`{prefix}\\Include\\{distname}` -=============== ========================================================== - - -.. _inst-custom-install: - -Custom Installation -=================== - -Sometimes, the alternate installation schemes described in section -:ref:`inst-alt-install` just don't do what you want. You might want to tweak just -one or two directories while keeping everything under the same base directory, -or you might want to completely redefine the installation scheme. In either -case, you're creating a *custom installation scheme*. - -To create a custom installation scheme, you start with one of the alternate -schemes and override some of the installation directories used for the various -types of files, using these options: - -====================== ======================= -Type of file Override option -====================== ======================= -Python modules ``--install-purelib`` -extension modules ``--install-platlib`` -all modules ``--install-lib`` -scripts ``--install-scripts`` -data ``--install-data`` -C headers ``--install-headers`` -====================== ======================= - -These override options can be relative, absolute, -or explicitly defined in terms of one of the installation base directories. -(There are two installation base directories, and they are normally the -same---they only differ when you use the Unix "prefix scheme" and supply -different ``--prefix`` and ``--exec-prefix`` options; using ``--install-lib`` -will override values computed or given for ``--install-purelib`` and -``--install-platlib``, and is recommended for schemes that don't make a -difference between Python and extension modules.) - -For example, say you're installing a module distribution to your home directory -under Unix---but you want scripts to go in :file:`~/scripts` rather than -:file:`~/bin`. As you might expect, you can override this directory with the -:option:`!--install-scripts` option; in this case, it makes most sense to supply -a relative path, which will be interpreted relative to the installation base -directory (your home directory, in this case):: - - python setup.py install --home=~ --install-scripts=scripts - -Another Unix example: suppose your Python installation was built and installed -with a prefix of :file:`/usr/local/python`, so under a standard installation -scripts will wind up in :file:`/usr/local/python/bin`. If you want them in -:file:`/usr/local/bin` instead, you would supply this absolute directory for the -:option:`!--install-scripts` option:: - - python setup.py install --install-scripts=/usr/local/bin - -(This performs an installation using the "prefix scheme", where the prefix is -whatever your Python interpreter was installed with--- :file:`/usr/local/python` -in this case.) - -If you maintain Python on Windows, you might want third-party modules to live in -a subdirectory of :file:`{prefix}`, rather than right in :file:`{prefix}` -itself. This is almost as easy as customizing the script installation -directory---you just have to remember that there are two types of modules -to worry about, Python and extension modules, which can conveniently be both -controlled by one option:: - - python setup.py install --install-lib=Site - -The specified installation directory is relative to :file:`{prefix}`. Of -course, you also have to ensure that this directory is in Python's module -search path, such as by putting a :file:`.pth` file in a site directory (see -:mod:`site`). See section :ref:`inst-search-path` to find out how to modify -Python's search path. - -If you want to define an entire installation scheme, you just have to supply all -of the installation directory options. The recommended way to do this is to -supply relative paths; for example, if you want to maintain all Python -module-related files under :file:`python` in your home directory, and you want a -separate directory for each platform that you use your home directory from, you -might define the following installation scheme:: - - python setup.py install --home=~ \ - --install-purelib=python/lib \ - --install-platlib=python/lib.$PLAT \ - --install-scripts=python/scripts - --install-data=python/data - -or, equivalently, :: - - python setup.py install --home=~/python \ - --install-purelib=lib \ - --install-platlib='lib.$PLAT' \ - --install-scripts=scripts - --install-data=data - -``$PLAT`` is not (necessarily) an environment variable---it will be expanded by -the Distutils as it parses your command line options, just as it does when -parsing your configuration file(s). - -Obviously, specifying the entire installation scheme every time you install a -new module distribution would be very tedious. Thus, you can put these options -into your Distutils config file (see section :ref:`inst-config-files`): - -.. code-block:: ini - - [install] - install-base=$HOME - install-purelib=python/lib - install-platlib=python/lib.$PLAT - install-scripts=python/scripts - install-data=python/data - -or, equivalently, - -.. code-block:: ini - - [install] - install-base=$HOME/python - install-purelib=lib - install-platlib=lib.$PLAT - install-scripts=scripts - install-data=data - -Note that these two are *not* equivalent if you supply a different installation -base directory when you run the setup script. For example, :: - - python setup.py install --install-base=/tmp - -would install pure modules to :file:`/tmp/python/lib` in the first case, and -to :file:`/tmp/lib` in the second case. (For the second case, you probably -want to supply an installation base of :file:`/tmp/python`.) - -You probably noticed the use of ``$HOME`` and ``$PLAT`` in the sample -configuration file input. These are Distutils configuration variables, which -bear a strong resemblance to environment variables. In fact, you can use -environment variables in config files on platforms that have such a notion but -the Distutils additionally define a few extra variables that may not be in your -environment, such as ``$PLAT``. (And of course, on systems that don't have -environment variables, such as Mac OS 9, the configuration variables supplied by -the Distutils are the only ones you can use.) See section :ref:`inst-config-files` -for details. - -.. note:: When a :ref:`virtual environment ` is activated, any options - that change the installation path will be ignored from all distutils configuration - files to prevent inadvertently installing projects outside of the virtual - environment. - -.. XXX need some Windows examples---when would custom installation schemes be - needed on those platforms? - - -.. XXX Move this to Doc/using - -.. _inst-search-path: - -Modifying Python's Search Path ------------------------------- - -When the Python interpreter executes an :keyword:`import` statement, it searches -for both Python code and extension modules along a search path. A default value -for the path is configured into the Python binary when the interpreter is built. -You can determine the path by importing the :mod:`sys` module and printing the -value of ``sys.path``. :: - - $ python - Python 2.2 (#11, Oct 3 2002, 13:31:27) - [GCC 2.96 20000731 (Red Hat Linux 7.3 2.96-112)] on linux2 - Type "help", "copyright", "credits" or "license" for more information. - >>> import sys - >>> sys.path - ['', '/usr/local/lib/python2.3', '/usr/local/lib/python2.3/plat-linux2', - '/usr/local/lib/python2.3/lib-tk', '/usr/local/lib/python2.3/lib-dynload', - '/usr/local/lib/python2.3/site-packages'] - >>> - -The null string in ``sys.path`` represents the current working directory. - -The expected convention for locally installed packages is to put them in the -:file:`{...}/site-packages/` directory, but you may want to install Python -modules into some arbitrary directory. For example, your site may have a -convention of keeping all software related to the web server under :file:`/www`. -Add-on Python modules might then belong in :file:`/www/python`, and in order to -import them, this directory must be added to ``sys.path``. There are several -different ways to add the directory. - -The most convenient way is to add a path configuration file to a directory -that's already on Python's path, usually to the :file:`.../site-packages/` -directory. Path configuration files have an extension of :file:`.pth`, and each -line must contain a single path that will be appended to ``sys.path``. (Because -the new paths are appended to ``sys.path``, modules in the added directories -will not override standard modules. This means you can't use this mechanism for -installing fixed versions of standard modules.) - -Paths can be absolute or relative, in which case they're relative to the -directory containing the :file:`.pth` file. See the documentation of -the :mod:`site` module for more information. - -A slightly less convenient way is to edit the :file:`site.py` file in Python's -standard library, and modify ``sys.path``. :file:`site.py` is automatically -imported when the Python interpreter is executed, unless the :option:`-S` switch -is supplied to suppress this behaviour. So you could simply edit -:file:`site.py` and add two lines to it: - -.. code-block:: python - - import sys - sys.path.append('/www/python/') - -However, if you reinstall the same minor version of Python (perhaps when -upgrading from 2.2 to 2.2.2, for example) :file:`site.py` will be overwritten by -the stock version. You'd have to remember that it was modified and save a copy -before doing the installation. - -There are two environment variables that can modify ``sys.path``. -:envvar:`PYTHONHOME` sets an alternate value for the prefix of the Python -installation. For example, if :envvar:`PYTHONHOME` is set to ``/www/python``, -the search path will be set to ``['', '/www/python/lib/pythonX.Y/', -'/www/python/lib/pythonX.Y/plat-linux2', ...]``. - -The :envvar:`PYTHONPATH` variable can be set to a list of paths that will be -added to the beginning of ``sys.path``. For example, if :envvar:`PYTHONPATH` is -set to ``/www/python:/opt/py``, the search path will begin with -``['/www/python', '/opt/py']``. (Note that directories must exist in order to -be added to ``sys.path``; the :mod:`site` module removes paths that don't -exist.) - -Finally, ``sys.path`` is just a regular Python list, so any Python application -can modify it by adding or removing entries. - - -.. _inst-config-files: - -Distutils Configuration Files -============================= - -As mentioned above, you can use Distutils configuration files to record personal -or site preferences for any Distutils options. That is, any option to any -command can be stored in one of two or three (depending on your platform) -configuration files, which will be consulted before the command-line is parsed. -This means that configuration files will override default values, and the -command-line will in turn override configuration files. Furthermore, if -multiple configuration files apply, values from "earlier" files are overridden -by "later" files. - - -.. _inst-config-filenames: - -Location and names of config files ----------------------------------- - -The names and locations of the configuration files vary slightly across -platforms. On Unix and macOS, the three configuration files (in the order -they are processed) are: - -+--------------+----------------------------------------------------------+-------+ -| Type of file | Location and filename | Notes | -+==============+==========================================================+=======+ -| system | :file:`{prefix}/lib/python{ver}/distutils/distutils.cfg` | \(1) | -+--------------+----------------------------------------------------------+-------+ -| personal | :file:`$HOME/.pydistutils.cfg` | \(2) | -+--------------+----------------------------------------------------------+-------+ -| local | :file:`setup.cfg` | \(3) | -+--------------+----------------------------------------------------------+-------+ - -And on Windows, the configuration files are: - -+--------------+-------------------------------------------------+-------+ -| Type of file | Location and filename | Notes | -+==============+=================================================+=======+ -| system | :file:`{prefix}\\Lib\\distutils\\distutils.cfg` | \(4) | -+--------------+-------------------------------------------------+-------+ -| personal | :file:`%HOME%\\pydistutils.cfg` | \(5) | -+--------------+-------------------------------------------------+-------+ -| local | :file:`setup.cfg` | \(3) | -+--------------+-------------------------------------------------+-------+ - -On all platforms, the "personal" file can be temporarily disabled by -passing the ``--no-user-cfg`` option. - -Notes: - -(1) - Strictly speaking, the system-wide configuration file lives in the directory - where the Distutils are installed; under Python 1.6 and later on Unix, this is - as shown. For Python 1.5.2, the Distutils will normally be installed to - :file:`{prefix}/lib/python1.5/site-packages/distutils`, so the system - configuration file should be put there under Python 1.5.2. - -(2) - On Unix, if the :envvar:`HOME` environment variable is not defined, the user's - home directory will be determined with the :func:`~pwd.getpwuid` function from the - standard :mod:`pwd` module. This is done by the :func:`os.path.expanduser` - function used by Distutils. - -(3) - I.e., in the current directory (usually the location of the setup script). - -(4) - (See also note (1).) Under Python 1.6 and later, Python's default "installation - prefix" is :file:`C:\\Python`, so the system configuration file is normally - :file:`C:\\Python\\Lib\\distutils\\distutils.cfg`. Under Python 1.5.2, the - default prefix was :file:`C:\\Program Files\\Python`, and the Distutils were not - part of the standard library---so the system configuration file would be - :file:`C:\\Program Files\\Python\\distutils\\distutils.cfg` in a standard Python - 1.5.2 installation under Windows. - -(5) - On Windows, if the :envvar:`HOME` environment variable is not defined, - :envvar:`USERPROFILE` then :envvar:`HOMEDRIVE` and :envvar:`HOMEPATH` will - be tried. This is done by the :func:`os.path.expanduser` function used - by Distutils. - - -.. _inst-config-syntax: - -Syntax of config files ----------------------- - -The Distutils configuration files all have the same syntax. The config files -are grouped into sections. There is one section for each Distutils command, -plus a ``global`` section for global options that affect every command. Each -section consists of one option per line, specified as ``option=value``. - -For example, the following is a complete config file that just forces all -commands to run quietly by default: - -.. code-block:: ini - - [global] - verbose=0 - -If this is installed as the system config file, it will affect all processing of -any Python module distribution by any user on the current system. If it is -installed as your personal config file (on systems that support them), it will -affect only module distributions processed by you. And if it is used as the -:file:`setup.cfg` for a particular module distribution, it affects only that -distribution. - -You could override the default "build base" directory and make the -:command:`build\*` commands always forcibly rebuild all files with the -following: - -.. code-block:: ini - - [build] - build-base=blib - force=1 - -which corresponds to the command-line arguments :: - - python setup.py build --build-base=blib --force - -except that including the :command:`build` command on the command-line means -that command will be run. Including a particular command in config files has no -such implication; it only means that if the command is run, the options in the -config file will apply. (Or if other commands that derive values from it are -run, they will use the values in the config file.) - -You can find out the complete list of options for any command using the -:option:`!--help` option, e.g.:: - - python setup.py build --help - -and you can find out the complete list of global options by using -:option:`!--help` without a command:: - - python setup.py --help - -See also the "Reference" section of the "Distributing Python Modules" manual. - - -.. _inst-building-ext: - -Building Extensions: Tips and Tricks -==================================== - -Whenever possible, the Distutils try to use the configuration information made -available by the Python interpreter used to run the :file:`setup.py` script. -For example, the same compiler and linker flags used to compile Python will also -be used for compiling extensions. Usually this will work well, but in -complicated situations this might be inappropriate. This section discusses how -to override the usual Distutils behaviour. - - -.. _inst-tweak-flags: - -Tweaking compiler/linker flags ------------------------------- - -Compiling a Python extension written in C or C++ will sometimes require -specifying custom flags for the compiler and linker in order to use a particular -library or produce a special kind of object code. This is especially true if the -extension hasn't been tested on your platform, or if you're trying to -cross-compile Python. - -In the most general case, the extension author might have foreseen that -compiling the extensions would be complicated, and provided a :file:`Setup` file -for you to edit. This will likely only be done if the module distribution -contains many separate extension modules, or if they often require elaborate -sets of compiler flags in order to work. - -A :file:`Setup` file, if present, is parsed in order to get a list of extensions -to build. Each line in a :file:`Setup` describes a single module. Lines have -the following structure:: - - module ... [sourcefile ...] [cpparg ...] [library ...] - - -Let's examine each of the fields in turn. - -* *module* is the name of the extension module to be built, and should be a - valid Python identifier. You can't just change this in order to rename a module - (edits to the source code would also be needed), so this should be left alone. - -* *sourcefile* is anything that's likely to be a source code file, at least - judging by the filename. Filenames ending in :file:`.c` are assumed to be - written in C, filenames ending in :file:`.C`, :file:`.cc`, and :file:`.c++` are - assumed to be C++, and filenames ending in :file:`.m` or :file:`.mm` are assumed - to be in Objective C. - -* *cpparg* is an argument for the C preprocessor, and is anything starting with - :option:`!-I`, :option:`!-D`, :option:`!-U` or :option:`!-C`. - -* *library* is anything ending in :file:`.a` or beginning with :option:`!-l` or - :option:`!-L`. - -If a particular platform requires a special library on your platform, you can -add it by editing the :file:`Setup` file and running ``python setup.py build``. -For example, if the module defined by the line :: - - foo foomodule.c - -must be linked with the math library :file:`libm.a` on your platform, simply add -:option:`!-lm` to the line:: - - foo foomodule.c -lm - -Arbitrary switches intended for the compiler or the linker can be supplied with -the :option:`!-Xcompiler` *arg* and :option:`!-Xlinker` *arg* options:: - - foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm - -The next option after :option:`!-Xcompiler` and :option:`!-Xlinker` will be -appended to the proper command line, so in the above example the compiler will -be passed the :option:`!-o32` option, and the linker will be passed -:option:`!-shared`. If a compiler option requires an argument, you'll have to -supply multiple :option:`!-Xcompiler` options; for example, to pass ``-x c++`` -the :file:`Setup` file would have to contain ``-Xcompiler -x -Xcompiler c++``. - -Compiler flags can also be supplied through setting the :envvar:`CFLAGS` -environment variable. If set, the contents of :envvar:`CFLAGS` will be added to -the compiler flags specified in the :file:`Setup` file. - - -.. _inst-non-ms-compilers: - -Using non-Microsoft compilers on Windows ----------------------------------------- - -.. sectionauthor:: Rene Liebscher - - - -Borland/CodeGear C++ -^^^^^^^^^^^^^^^^^^^^ - -This subsection describes the necessary steps to use Distutils with the Borland -C++ compiler version 5.5. First you have to know that Borland's object file -format (OMF) is different from the format used by the Python version you can -download from the Python or ActiveState web site. (Python is built with -Microsoft Visual C++, which uses COFF as the object file format.) For this -reason you have to convert Python's library :file:`python25.lib` into the -Borland format. You can do this as follows: - -.. Should we mention that users have to create cfg-files for the compiler? -.. see also http://community.borland.com/article/0,1410,21205,00.html - -:: - - coff2omf python25.lib python25_bcpp.lib - -The :file:`coff2omf` program comes with the Borland compiler. The file -:file:`python25.lib` is in the :file:`Libs` directory of your Python -installation. If your extension uses other libraries (zlib, ...) you have to -convert them too. - -The converted files have to reside in the same directories as the normal -libraries. - -How does Distutils manage to use these libraries with their changed names? If -the extension needs a library (eg. :file:`foo`) Distutils checks first if it -finds a library with suffix :file:`_bcpp` (eg. :file:`foo_bcpp.lib`) and then -uses this library. In the case it doesn't find such a special library it uses -the default name (:file:`foo.lib`.) [#]_ - -To let Distutils compile your extension with Borland C++ you now have to type:: - - python setup.py build --compiler=bcpp - -If you want to use the Borland C++ compiler as the default, you could specify -this in your personal or system-wide configuration file for Distutils (see -section :ref:`inst-config-files`.) - - -.. seealso:: - - `C++Builder Compiler `_ - Information about the free C++ compiler from Borland, including links to the - download pages. - - `Creating Python Extensions Using Borland's Free Compiler `_ - Document describing how to use Borland's free command-line C++ compiler to build - Python. - - -GNU C / Cygwin / MinGW -^^^^^^^^^^^^^^^^^^^^^^ - -This section describes the necessary steps to use Distutils with the GNU C/C++ -compilers in their Cygwin and MinGW distributions. [#]_ For a Python interpreter -that was built with Cygwin, everything should work without any of these -following steps. - -Not all extensions can be built with MinGW or Cygwin, but many can. Extensions -most likely to not work are those that use C++ or depend on Microsoft Visual C -extensions. - -To let Distutils compile your extension with Cygwin you have to type:: - - python setup.py build --compiler=cygwin - -and for Cygwin in no-cygwin mode [#]_ or for MinGW type:: - - python setup.py build --compiler=mingw32 - -If you want to use any of these options/compilers as default, you should -consider writing it in your personal or system-wide configuration file for -Distutils (see section :ref:`inst-config-files`.) - -Older Versions of Python and MinGW -"""""""""""""""""""""""""""""""""" -The following instructions only apply if you're using a version of Python -inferior to 2.4.1 with a MinGW inferior to 3.0.0 (with -binutils-2.13.90-20030111-1). - -These compilers require some special libraries. This task is more complex than -for Borland's C++, because there is no program to convert the library. First -you have to create a list of symbols which the Python DLL exports. (You can find -a good program for this task at -https://sourceforge.net/projects/mingw/files/MinGW/Extension/pexports/). - -.. I don't understand what the next line means. --amk -.. (inclusive the references on data structures.) - -:: - - pexports python25.dll >python25.def - -The location of an installed :file:`python25.dll` will depend on the -installation options and the version and language of Windows. In a "just for -me" installation, it will appear in the root of the installation directory. In -a shared installation, it will be located in the system directory. - -Then you can create from these information an import library for gcc. :: - - /cygwin/bin/dlltool --dllname python25.dll --def python25.def --output-lib libpython25.a - -The resulting library has to be placed in the same directory as -:file:`python25.lib`. (Should be the :file:`libs` directory under your Python -installation directory.) - -If your extension uses other libraries (zlib,...) you might have to convert -them too. The converted files have to reside in the same directories as the -normal libraries do. - - -.. seealso:: - - `Building Python modules on MS Windows platform with MinGW `_ - Information about building the required libraries for the MinGW environment. - - -.. rubric:: Footnotes - -.. [#] This also means you could replace all existing COFF-libraries with OMF-libraries - of the same name. - -.. [#] Check https://www.sourceware.org/cygwin/ for more information - -.. [#] Then you have no POSIX emulation available, but you also don't need - :file:`cygwin1.dll`. diff --git a/Doc/library/site.rst b/Doc/library/site.rst index ff9e9107f9d163..ea3b2e996574ef 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -191,7 +191,7 @@ Module contents :file:`~/Library/Python/{X.Y}` for macOS framework builds, and :file:`{%APPDATA%}\\Python` for Windows. This value is used to compute the installation directories for scripts, data files, Python modules, - etc. for the :ref:`user installation scheme `. + etc. for the user installation scheme. See also :envvar:`PYTHONUSERBASE`. diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 23c89400f152b1..921b6a6961c7b2 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -811,7 +811,7 @@ conflict. Defines the :data:`user base directory `, which is used to compute the path of the :data:`user site-packages directory ` - and :ref:`installation paths ` for + and installation paths for ``python -m pip install --user``. .. seealso:: From 2166a407b29d7dc944e6d9159a4f6b8ffb6dc5e6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Aug 2023 03:53:59 -0700 Subject: [PATCH 0566/1206] [3.12] gh-107909: Test explicit `object` base in PEP695 generic classes (GH-108001) (#108022) gh-107909: Test explicit `object` base in PEP695 generic classes (GH-108001) (cherry picked from commit b61f5995aebb93496e968ca8d307375fa86d9329) Co-authored-by: Nikita Sobolev --- Lib/test/test_type_params.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index bced641a9661fd..0045057f181e1c 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -148,6 +148,10 @@ def test_disallowed_expressions(self): check_syntax_error(self, "def f[T: [(x := 3) for _ in range(2)]](): pass") check_syntax_error(self, "type T = [(x := 3) for _ in range(2)]") + def test_incorrect_mro_explicit_object(self): + with self.assertRaisesRegex(TypeError, r"\(MRO\) for bases object, Generic"): + class My[X](object): ... + class TypeParamsNonlocalTest(unittest.TestCase): def test_nonlocal_disallowed_01(self): From 9342ac314985face0ae117c8f10296904f30f71a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:40:09 -0700 Subject: [PATCH 0567/1206] [3.12] gh-107801: Document SEEK_HOLE and SEEK_DATA (GH-107936) (#108086) gh-107801: Document SEEK_HOLE and SEEK_DATA (GH-107936) (cherry picked from commit 8a19f225b948db1eebe1d9fc71a486258841f578) Co-authored-by: Erlend E. Aasland Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Antoine Pitrou --- Doc/library/os.rst | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 9735baa5bc0f3a..94b76e4052b94b 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1171,6 +1171,10 @@ as internal buffering of data. current position; :const:`SEEK_END` or ``2`` to set it relative to the end of the file. Return the new cursor position in bytes, starting from the beginning. + .. versionchanged:: 3.3 + + Add support for :const:`SEEK_HOLE` and :const:`SEEK_DATA`. + .. data:: SEEK_SET SEEK_CUR @@ -1179,9 +1183,30 @@ as internal buffering of data. Parameters to the :func:`lseek` function. Their values are 0, 1, and 2, respectively. + +.. data:: SEEK_HOLE + SEEK_DATA + + Parameters to the :func:`lseek` function and the :meth:`~io.IOBase.seek` + method on file objects, for seeking file data and holes on sparsely + allocated files. + + :data:`!SEEK_DATA` + Adjust the file offset to the next location containing data, + relative to the seek position. + + :data:`!SEEK_HOLE` + Adjust the file offset to the next location containing a hole, + relative to the seek position. + A hole is defined as a sequence of zeros. + + .. note:: + + These operations only make sense for filesystems that support them. + + .. availability:: Linux >= 3.1, macOS, Unix + .. versionadded:: 3.3 - Some operating systems could support additional values, like - :const:`os.SEEK_HOLE` or :const:`os.SEEK_DATA`. .. function:: open(path, flags, mode=0o777, *, dir_fd=None) From 60edc70a9374f1cc6ecff5974e438d58fec29985 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Aug 2023 01:55:33 -0700 Subject: [PATCH 0568/1206] [3.12] Docs: Fix Sphinx warnings in io.rst (GH-107903) (#108093) Docs: Fix Sphinx warnings in io.rst (GH-107903) - Mark up parameter and argument names properly - If possible, link to docs for methods like `seek`, `tell`, `write`, `read`, etc. (cherry picked from commit 5c76899dadf3bdcfdedf6f30b3ab9742cb87af04) Co-authored-by: Erlend E. Aasland Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: T. Wouters --- Doc/library/io.rst | 71 ++++++++++++++++++++++---------------------- Doc/tools/.nitignore | 1 - 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 7eec1f87583b87..66273d9ed1ff0a 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -38,9 +38,9 @@ location), or only sequential access (for example in the case of a socket or pipe). All streams are careful about the type of data you give to them. For example -giving a :class:`str` object to the ``write()`` method of a binary stream +giving a :class:`str` object to the :meth:`!write` method of a binary stream will raise a :exc:`TypeError`. So will giving a :class:`bytes` object to the -``write()`` method of a text stream. +:meth:`!write` method of a text stream. .. versionchanged:: 3.3 Operations that used to raise :exc:`IOError` now raise :exc:`OSError`, since @@ -146,7 +146,7 @@ Opt-in EncodingWarning See :pep:`597` for more details. To find where the default locale encoding is used, you can enable -the ``-X warn_default_encoding`` command line option or set the +the :option:`-X warn_default_encoding <-X>` command line option or set the :envvar:`PYTHONWARNDEFAULTENCODING` environment variable, which will emit an :exc:`EncodingWarning` when the default encoding is used. @@ -175,7 +175,7 @@ High-level Module Interface .. audit-event:: open path,mode,flags io.open This function raises an :ref:`auditing event ` ``open`` with - arguments ``path``, ``mode`` and ``flags``. The ``mode`` and ``flags`` + arguments *path*, *mode* and *flags*. The *mode* and *flags* arguments may have been modified or inferred from the original call. @@ -184,10 +184,10 @@ High-level Module Interface Opens the provided file with mode ``'rb'``. This function should be used when the intent is to treat the contents as executable code. - ``path`` should be a :class:`str` and an absolute path. + *path* should be a :class:`str` and an absolute path. The behavior of this function may be overridden by an earlier call to the - :c:func:`PyFile_SetOpenCodeHook`. However, assuming that ``path`` is a + :c:func:`PyFile_SetOpenCodeHook`. However, assuming that *path* is a :class:`str` and an absolute path, ``open_code(path)`` should always behave the same as ``open(path, 'rb')``. Overriding the behavior is intended for additional validation or preprocessing of the file. @@ -258,7 +258,7 @@ standard stream implementations. The abstract base classes also provide default implementations of some methods in order to help implementation of concrete stream classes. For example, :class:`BufferedIOBase` provides unoptimized implementations of - :meth:`~IOBase.readinto` and :meth:`~IOBase.readline`. + :meth:`!readinto` and :meth:`!readline`. At the top of the I/O hierarchy is the abstract base class :class:`IOBase`. It defines the basic interface to a stream. Note, however, that there is no @@ -320,8 +320,8 @@ I/O Base Classes implementations represent a file that cannot be read, written or seeked. - Even though :class:`IOBase` does not declare :meth:`read` - or :meth:`write` because their signatures will vary, implementations and + Even though :class:`IOBase` does not declare :meth:`!read` + or :meth:`!write` because their signatures will vary, implementations and clients should consider those methods part of the interface. Also, implementations may raise a :exc:`ValueError` (or :exc:`UnsupportedOperation`) when operations they do not support are called. @@ -379,8 +379,8 @@ I/O Base Classes .. method:: readable() - Return ``True`` if the stream can be read from. If ``False``, :meth:`read` - will raise :exc:`OSError`. + Return ``True`` if the stream can be read from. + If ``False``, :meth:`!read` will raise :exc:`OSError`. .. method:: readline(size=-1, /) @@ -401,25 +401,25 @@ I/O Base Classes hint. Note that it's already possible to iterate on file objects using ``for - line in file: ...`` without calling ``file.readlines()``. + line in file: ...`` without calling :meth:`!file.readlines`. .. method:: seek(offset, whence=SEEK_SET, /) Change the stream position to the given byte *offset*. *offset* is interpreted relative to the position indicated by *whence*. The default - value for *whence* is :data:`SEEK_SET`. Values for *whence* are: + value for *whence* is :data:`!SEEK_SET`. Values for *whence* are: - * :data:`SEEK_SET` or ``0`` -- start of the stream (the default); + * :data:`!SEEK_SET` or ``0`` -- start of the stream (the default); *offset* should be zero or positive - * :data:`SEEK_CUR` or ``1`` -- current stream position; *offset* may + * :data:`!SEEK_CUR` or ``1`` -- current stream position; *offset* may be negative - * :data:`SEEK_END` or ``2`` -- end of the stream; *offset* is usually + * :data:`!SEEK_END` or ``2`` -- end of the stream; *offset* is usually negative Return the new absolute position. .. versionadded:: 3.1 - The ``SEEK_*`` constants. + The :data:`!SEEK_*` constants. .. versionadded:: 3.3 Some operating systems could support additional values, like @@ -450,7 +450,7 @@ I/O Base Classes .. method:: writable() Return ``True`` if the stream supports writing. If ``False``, - :meth:`write` and :meth:`truncate` will raise :exc:`OSError`. + :meth:`!write` and :meth:`truncate` will raise :exc:`OSError`. .. method:: writelines(lines, /) @@ -654,8 +654,9 @@ Raw File I/O implies writing, so this mode behaves in a similar way to ``'w'``. Add a ``'+'`` to the mode to allow simultaneous reading and writing. - The :meth:`read` (when called with a positive argument), :meth:`readinto` - and :meth:`write` methods on this class will only make one system call. + The :meth:`~RawIOBase.read` (when called with a positive argument), + :meth:`~RawIOBase.readinto` and :meth:`~RawIOBase.write` methods on this + class will only make one system call. A custom opener can be used by passing a callable as *opener*. The underlying file descriptor for the file object is then obtained by calling *opener* with @@ -791,8 +792,8 @@ than raw I/O does. object under various conditions, including: * when the buffer gets too small for all pending data; - * when :meth:`flush()` is called; - * when a :meth:`seek()` is requested (for :class:`BufferedRandom` objects); + * when :meth:`flush` is called; + * when a :meth:`~IOBase.seek` is requested (for :class:`BufferedRandom` objects); * when the :class:`BufferedWriter` object is closed or destroyed. The constructor creates a :class:`BufferedWriter` for the given writeable @@ -826,8 +827,8 @@ than raw I/O does. :data:`DEFAULT_BUFFER_SIZE`. :class:`BufferedRandom` is capable of anything :class:`BufferedReader` or - :class:`BufferedWriter` can do. In addition, :meth:`seek` and :meth:`tell` - are guaranteed to be implemented. + :class:`BufferedWriter` can do. In addition, :meth:`~IOBase.seek` and + :meth:`~IOBase.tell` are guaranteed to be implemented. .. class:: BufferedRWPair(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE, /) @@ -904,7 +905,7 @@ Text I/O .. method:: readline(size=-1, /) - Read until newline or EOF and return a single ``str``. If the stream is + Read until newline or EOF and return a single :class:`str`. If the stream is already at EOF, an empty string is returned. If *size* is specified, at most *size* characters will be read. @@ -913,22 +914,22 @@ Text I/O Change the stream position to the given *offset*. Behaviour depends on the *whence* parameter. The default value for *whence* is - :data:`SEEK_SET`. + :data:`!SEEK_SET`. - * :data:`SEEK_SET` or ``0``: seek from the start of the stream + * :data:`!SEEK_SET` or ``0``: seek from the start of the stream (the default); *offset* must either be a number returned by :meth:`TextIOBase.tell`, or zero. Any other *offset* value produces undefined behaviour. - * :data:`SEEK_CUR` or ``1``: "seek" to the current position; + * :data:`!SEEK_CUR` or ``1``: "seek" to the current position; *offset* must be zero, which is a no-operation (all other values are unsupported). - * :data:`SEEK_END` or ``2``: seek to the end of the stream; + * :data:`!SEEK_END` or ``2``: seek to the end of the stream; *offset* must be zero (all other values are unsupported). Return the new absolute position as an opaque number. .. versionadded:: 3.1 - The ``SEEK_*`` constants. + The :data:`!SEEK_*` constants. .. method:: tell() @@ -988,10 +989,10 @@ Text I/O takes place. If *newline* is any of the other legal values, any ``'\n'`` characters written are translated to the given string. - If *line_buffering* is ``True``, :meth:`flush` is implied when a call to + If *line_buffering* is ``True``, :meth:`~IOBase.flush` is implied when a call to write contains a newline character or a carriage return. - If *write_through* is ``True``, calls to :meth:`write` are guaranteed + If *write_through* is ``True``, calls to :meth:`~BufferedIOBase.write` are guaranteed not to be buffered: any data written on the :class:`TextIOWrapper` object is immediately handled to its underlying binary *buffer*. @@ -1070,7 +1071,7 @@ Text I/O .. method:: getvalue() - Return a ``str`` containing the entire contents of the buffer. + Return a :class:`str` containing the entire contents of the buffer. Newlines are decoded as if by :meth:`~TextIOBase.read`, although the stream position is not changed. @@ -1125,7 +1126,7 @@ Text I/O over a binary storage (such as a file) is significantly slower than binary I/O over the same storage, because it requires conversions between unicode and binary data using a character codec. This can become noticeable handling huge amounts of text data like large log files. Also, -:meth:`TextIOWrapper.tell` and :meth:`TextIOWrapper.seek` are both quite slow +:meth:`~TextIOBase.tell` and :meth:`~TextIOBase.seek` are both quite slow due to the reconstruction algorithm used. :class:`StringIO`, however, is a native in-memory unicode container and will @@ -1135,7 +1136,7 @@ Multi-threading ^^^^^^^^^^^^^^^ :class:`FileIO` objects are thread-safe to the extent that the operating system -calls (such as ``read(2)`` under Unix) they wrap are thread-safe too. +calls (such as :manpage:`read(2)` under Unix) they wrap are thread-safe too. Binary buffered objects (instances of :class:`BufferedReader`, :class:`BufferedWriter`, :class:`BufferedRandom` and :class:`BufferedRWPair`) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 9a0a6c2561d122..f7f2d6d8f3289a 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -100,7 +100,6 @@ Doc/library/http.server.rst Doc/library/importlib.resources.rst Doc/library/importlib.rst Doc/library/inspect.rst -Doc/library/io.rst Doc/library/locale.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst From 2b8e0207cb91c5377ea82638d038e737070c64bb Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 18 Aug 2023 14:16:42 +0200 Subject: [PATCH 0569/1206] [3.12] gh-107801: Improve the docs of the SEEK_* constants (#108099) (#108108) (cherry picked from commit 02079b010c39a89b284e8f0bb6d5f378e554260e) --- Doc/library/os.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 94b76e4052b94b..4668984b10c690 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1180,16 +1180,26 @@ as internal buffering of data. SEEK_CUR SEEK_END - Parameters to the :func:`lseek` function. Their values are 0, 1, and 2, - respectively. + Parameters to the :func:`lseek` function and the :meth:`~io.IOBase.seek` + method on :term:`file-like objects `, + for whence to adjust the file position indicator. + + :const:`SEEK_SET` + Adjust the file position relative to the beginning of the file. + :const:`SEEK_CUR` + Adjust the file position relative to the current file position. + :const:`SEEK_END` + Adjust the file position relative to the end of the file. + + Their values are 0, 1, and 2, respectively. .. data:: SEEK_HOLE SEEK_DATA Parameters to the :func:`lseek` function and the :meth:`~io.IOBase.seek` - method on file objects, for seeking file data and holes on sparsely - allocated files. + method on :term:`file-like objects `, + for seeking file data and holes on sparsely allocated files. :data:`!SEEK_DATA` Adjust the file offset to the next location containing data, From af6e5fa718535b4ccbfa47f382584878aaa69bc2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Aug 2023 05:17:12 -0700 Subject: [PATCH 0570/1206] [3.12] Docs: emphasise warning and add accurate markups for sys.unraisablehook (GH-108105) (#108109) Docs: emphasise warning and add accurate markups for sys.unraisablehook (GH-108105) (cherry picked from commit cc58ec9724772a8d5c4a5c9a6525f9f96e994227) Co-authored-by: Erlend E. Aasland --- Doc/library/sys.rst | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 33391d11ab392d..b6346bafbf625e 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1811,35 +1811,39 @@ always available. The *unraisable* argument has the following attributes: - * *exc_type*: Exception type. - * *exc_value*: Exception value, can be ``None``. - * *exc_traceback*: Exception traceback, can be ``None``. - * *err_msg*: Error message, can be ``None``. - * *object*: Object causing the exception, can be ``None``. + * :attr:`!exc_type`: Exception type. + * :attr:`!exc_value`: Exception value, can be ``None``. + * :attr:`!exc_traceback`: Exception traceback, can be ``None``. + * :attr:`!err_msg`: Error message, can be ``None``. + * :attr:`!object`: Object causing the exception, can be ``None``. - The default hook formats *err_msg* and *object* as: + The default hook formats :attr:`!err_msg` and :attr:`!object` as: ``f'{err_msg}: {object!r}'``; use "Exception ignored in" error message - if *err_msg* is ``None``. + if :attr:`!err_msg` is ``None``. :func:`sys.unraisablehook` can be overridden to control how unraisable exceptions are handled. - Storing *exc_value* using a custom hook can create a reference cycle. It - should be cleared explicitly to break the reference cycle when the - exception is no longer needed. + .. seealso:: + + :func:`excepthook` which handles uncaught exceptions. + + .. warning:: - Storing *object* using a custom hook can resurrect it if it is set to an - object which is being finalized. Avoid storing *object* after the custom - hook completes to avoid resurrecting objects. + Storing :attr:`!exc_value` using a custom hook can create a reference cycle. + It should be cleared explicitly to break the reference cycle when the + exception is no longer needed. - See also :func:`excepthook` which handles uncaught exceptions. + Storing :attr:`!object` using a custom hook can resurrect it if it is set to an + object which is being finalized. Avoid storing :attr:`!object` after the custom + hook completes to avoid resurrecting objects. .. audit-event:: sys.unraisablehook hook,unraisable sys.unraisablehook Raise an auditing event ``sys.unraisablehook`` with arguments - ``hook``, ``unraisable`` when an exception that cannot be handled occurs. - The ``unraisable`` object is the same as what will be passed to the hook. - If no hook has been set, ``hook`` may be ``None``. + *hook*, *unraisable* when an exception that cannot be handled occurs. + The *unraisable* object is the same as what will be passed to the hook. + If no hook has been set, *hook* may be ``None``. .. versionadded:: 3.8 From 359cff5c41f87fed3506e6a9a41b6828f4f5cd40 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 18 Aug 2023 13:30:34 -0700 Subject: [PATCH 0571/1206] [3.12] gh-107565: Update multissltests and GitHub CI workflows to use OpenSSL 1.1.1v, 3.0.10, and 3.1.2. (GH-108118) Co-authored-by: Ned Deily --- .github/workflows/build.yml | 8 ++++---- .../2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst | 2 ++ Tools/ssl/multissltests.py | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20208dbdd2f5f9..ea6d43947449f1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -287,7 +287,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1u + OPENSSL_VER: 1.1.1v PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v3 @@ -356,7 +356,7 @@ jobs: strategy: fail-fast: false matrix: - openssl_ver: [1.1.1u, 3.0.9, 3.1.1] + openssl_ver: [1.1.1v, 3.0.10, 3.1.2] env: OPENSSL_VER: ${{ matrix.openssl_ver }} MULTISSL_DIR: ${{ github.workspace }}/multissl @@ -408,7 +408,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_hypothesis == 'true' env: - OPENSSL_VER: 1.1.1u + OPENSSL_VER: 1.1.1v PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v3 @@ -517,7 +517,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1u + OPENSSL_VER: 1.1.1v PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst b/Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst new file mode 100644 index 00000000000000..c43ee680e8158e --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst @@ -0,0 +1,2 @@ +Update multissltests and GitHub CI workflows to use OpenSSL 1.1.1v, 3.0.10, +and 3.1.2. diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index f9809c9b54665b..fc261c770d6944 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -46,9 +46,9 @@ ] OPENSSL_RECENT_VERSIONS = [ - "1.1.1u", - "3.0.9", - "3.1.1", + "1.1.1v", + "3.0.10", + "3.1.2", ] LIBRESSL_OLD_VERSIONS = [ From daed54d8de1f45a5ca07ea8dd37bee5882769bd7 Mon Sep 17 00:00:00 2001 From: "C.A.M. Gerlach" Date: Fri, 18 Aug 2023 16:21:16 -0500 Subject: [PATCH 0572/1206] [3.12] gh-101100: Docs: Check Sphinx warnings and fail if improved (GH-106460) (#108116) * gh-101100: Docs: Check Sphinx warnings and fail if improved (#106460) (cherry picked from commit 806d7c98a5da5c1fd2e52a5b666f36ca4f545092) * [3.12] gh-101100: Docs: Check Sphinx warnings and fail if improved (GH-106460). (cherry picked from commit 806d7c98a5da5c1fd2e52a5b666f36ca4f545092) Co-authored-by: Hugo van Kemenade --------- Co-authored-by: Hugo van Kemenade --- .github/workflows/reusable-docs.yml | 27 ++--- Doc/tools/.nitignore | 8 +- Doc/tools/check-warnings.py | 149 ++++++++++++++++++++++++++++ Doc/tools/touch-clean-files.py | 65 ------------ Doc/tools/warnings-to-gh-actions.py | 25 ----- 5 files changed, 161 insertions(+), 113 deletions(-) create mode 100644 Doc/tools/check-warnings.py delete mode 100644 Doc/tools/touch-clean-files.py delete mode 100644 Doc/tools/warnings-to-gh-actions.py diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 77142a64a4b224..39e5ad62924ad3 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -26,10 +26,8 @@ jobs: cache-dependency-path: 'Doc/requirements.txt' - name: 'Install build dependencies' run: make -C Doc/ venv - - name: 'Build HTML documentation' - run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html - # Add pull request annotations for Sphinx nitpicks (missing references) + # To annotate PRs with Sphinx nitpicks (missing references) - name: 'Get list of changed files' if: github.event_name == 'pull_request' id: changed_files @@ -37,24 +35,19 @@ jobs: with: filter: "Doc/**" format: csv # works for paths with spaces - - name: 'Build changed files in nit-picky mode' - if: github.event_name == 'pull_request' + - name: 'Build HTML documentation' continue-on-error: true run: | set -Eeuo pipefail - # Mark files the pull request modified - python Doc/tools/touch-clean-files.py --clean '${{ steps.changed_files.outputs.added_modified }}' - # Build docs with the '-n' (nit-picky) option; convert warnings to annotations - make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n --keep-going" html 2>&1 | - python Doc/tools/warnings-to-gh-actions.py - - # Ensure some files always pass Sphinx nit-picky mode (no missing references) - - name: 'Build known-good files in nit-picky mode' + # Build docs with the '-n' (nit-picky) option; write warnings to file + make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going -w sphinx-warnings.txt" html + - name: 'Check warnings' + if: github.event_name == 'pull_request' run: | - # Mark files that must pass nit-picky - python Doc/tools/touch-clean-files.py - # Build docs with the '-n' (nit-picky) option, convert warnings to errors (-W) - make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going" html 2>&1 + python Doc/tools/check-warnings.py \ + --check-and-annotate '${{ steps.changed_files.outputs.added_modified }}' \ + --fail-if-regression \ + --fail-if-improved # This build doesn't use problem matchers or check annotations build_doc_oldest_supported_sphinx: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index f7f2d6d8f3289a..88ac905467299a 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -1,17 +1,14 @@ # All RST files under Doc/ -- except these -- must pass Sphinx nit-picky mode, -# as tested on the CI via touch-clean-files.py in doc.yml. -# Add blank lines between files and keep them sorted lexicographically -# to help avoid merge conflicts. +# as tested on the CI via check-warnings.py in reusable-docs.yml. +# Keep lines sorted lexicographically to help avoid merge conflicts. Doc/c-api/arg.rst Doc/c-api/datetime.rst Doc/c-api/descriptor.rst -Doc/c-api/dict.rst Doc/c-api/exceptions.rst Doc/c-api/file.rst Doc/c-api/float.rst Doc/c-api/gcsupport.rst -Doc/c-api/import.rst Doc/c-api/init.rst Doc/c-api/init_config.rst Doc/c-api/intro.rst @@ -58,7 +55,6 @@ Doc/library/bz2.rst Doc/library/calendar.rst Doc/library/cgi.rst Doc/library/chunk.rst -Doc/library/cmath.rst Doc/library/cmd.rst Doc/library/codecs.rst Doc/library/collections.abc.rst diff --git a/Doc/tools/check-warnings.py b/Doc/tools/check-warnings.py new file mode 100644 index 00000000000000..c17d0f51cd1272 --- /dev/null +++ b/Doc/tools/check-warnings.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +""" +Check the output of running Sphinx in nit-picky mode (missing references). +""" +import argparse +import csv +import os +import re +import sys +from pathlib import Path + +# Exclude these whether they're dirty or clean, +# because they trigger a rebuild of dirty files. +EXCLUDE_FILES = { + "Doc/whatsnew/changelog.rst", +} + +# Subdirectories of Doc/ to exclude. +EXCLUDE_SUBDIRS = { + ".env", + ".venv", + "env", + "includes", + "venv", +} + +PATTERN = re.compile(r"(?P[^:]+):(?P\d+): WARNING: (?P.+)") + + +def check_and_annotate(warnings: list[str], files_to_check: str) -> None: + """ + Convert Sphinx warning messages to GitHub Actions. + + Converts lines like: + .../Doc/library/cgi.rst:98: WARNING: reference target not found + to: + ::warning file=.../Doc/library/cgi.rst,line=98::reference target not found + + Non-matching lines are echoed unchanged. + + see: + https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message + """ + files_to_check = next(csv.reader([files_to_check])) + for warning in warnings: + if any(filename in warning for filename in files_to_check): + if match := PATTERN.fullmatch(warning): + print("::warning file={file},line={line}::{msg}".format_map(match)) + + +def fail_if_regression( + warnings: list[str], files_with_expected_nits: set[str], files_with_nits: set[str] +) -> int: + """ + Ensure some files always pass Sphinx nit-picky mode (no missing references). + These are files which are *not* in .nitignore. + """ + all_rst = { + str(rst) + for rst in Path("Doc/").rglob("*.rst") + if rst.parts[1] not in EXCLUDE_SUBDIRS + } + should_be_clean = all_rst - files_with_expected_nits - EXCLUDE_FILES + problem_files = sorted(should_be_clean & files_with_nits) + if problem_files: + print("\nError: must not contain warnings:\n") + for filename in problem_files: + print(filename) + for warning in warnings: + if filename in warning: + if match := PATTERN.fullmatch(warning): + print(" {line}: {msg}".format_map(match)) + return -1 + return 0 + + +def fail_if_improved( + files_with_expected_nits: set[str], files_with_nits: set[str] +) -> int: + """ + We may have fixed warnings in some files so that the files are now completely clean. + Good news! Let's add them to .nitignore to prevent regression. + """ + files_with_no_nits = files_with_expected_nits - files_with_nits + if files_with_no_nits: + print("\nCongratulations! You improved:\n") + for filename in sorted(files_with_no_nits): + print(filename) + print("\nPlease remove from Doc/tools/.nitignore\n") + return -1 + return 0 + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument( + "--check-and-annotate", + help="Comma-separated list of files to check, " + "and annotate those with warnings on GitHub Actions", + ) + parser.add_argument( + "--fail-if-regression", + action="store_true", + help="Fail if known-good files have warnings", + ) + parser.add_argument( + "--fail-if-improved", + action="store_true", + help="Fail if new files with no nits are found", + ) + args = parser.parse_args() + exit_code = 0 + + wrong_directory_msg = "Must run this script from the repo root" + assert Path("Doc").exists() and Path("Doc").is_dir(), wrong_directory_msg + + with Path("Doc/sphinx-warnings.txt").open() as f: + warnings = f.read().splitlines() + + cwd = str(Path.cwd()) + os.path.sep + files_with_nits = { + warning.removeprefix(cwd).split(":")[0] + for warning in warnings + if "Doc/" in warning + } + + with Path("Doc/tools/.nitignore").open() as clean_files: + files_with_expected_nits = { + filename.strip() + for filename in clean_files + if filename.strip() and not filename.startswith("#") + } + + if args.check_and_annotate: + check_and_annotate(warnings, args.check_and_annotate) + + if args.fail_if_regression: + exit_code += fail_if_regression( + warnings, files_with_expected_nits, files_with_nits + ) + + if args.fail_if_improved: + exit_code += fail_if_improved(files_with_expected_nits, files_with_nits) + + return exit_code + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/Doc/tools/touch-clean-files.py b/Doc/tools/touch-clean-files.py deleted file mode 100644 index 2b045bd68a0cf0..00000000000000 --- a/Doc/tools/touch-clean-files.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -""" -Touch files that must pass Sphinx nit-picky mode -so they are rebuilt and we can catch regressions. -""" -import argparse -import csv -import sys -from pathlib import Path - -wrong_directory_msg = "Must run this script from the repo root" -assert Path("Doc").exists() and Path("Doc").is_dir(), wrong_directory_msg - -# Exclude these whether they're dirty or clean, -# because they trigger a rebuild of dirty files. -EXCLUDE_FILES = { - Path("Doc/whatsnew/changelog.rst"), -} - -# Subdirectories of Doc/ to exclude. -EXCLUDE_SUBDIRS = { - ".env", - ".venv", - "env", - "includes", - "venv", -} - -ALL_RST = { - rst for rst in Path("Doc/").rglob("*.rst") if rst.parts[1] not in EXCLUDE_SUBDIRS -} - - -parser = argparse.ArgumentParser( - description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter -) -parser.add_argument("-c", "--clean", help="Comma-separated list of clean files") -args = parser.parse_args() - -if args.clean: - clean_files = next(csv.reader([args.clean])) - CLEAN = { - Path(filename.strip()) - for filename in clean_files - if Path(filename.strip()).is_file() - } -elif args.clean is not None: - print( - "Not touching any files: an empty string `--clean` arg value passed.", - ) - sys.exit(0) -else: - with Path("Doc/tools/.nitignore").open() as ignored_files: - IGNORED = { - Path(filename.strip()) - for filename in ignored_files - if filename.strip() and not filename.startswith("#") - } - CLEAN = ALL_RST - IGNORED - EXCLUDE_FILES - -print("Touching:") -for filename in sorted(CLEAN): - print(filename) - filename.touch() -print(f"Touched {len(CLEAN)} files") diff --git a/Doc/tools/warnings-to-gh-actions.py b/Doc/tools/warnings-to-gh-actions.py deleted file mode 100644 index da33a4ede07abc..00000000000000 --- a/Doc/tools/warnings-to-gh-actions.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python3 - -""" -Convert Sphinx warning messages to GitHub Actions. - -Converts lines like: - .../Doc/library/cgi.rst:98: WARNING: reference target not found -to: - ::warning file=.../Doc/library/cgi.rst,line=98::reference target not found - -Non-matching lines are echoed unchanged. - -see: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message -""" - -import re -import sys - -pattern = re.compile(r'(?P[^:]+):(?P\d+): WARNING: (?P.+)') - -for line in sys.stdin: - if match := pattern.fullmatch(line.strip()): - print('::warning file={file},line={line}::{msg}'.format_map(match)) - else: - print(line) From a1808b835876ee70020ad9dbba40614439a5cdde Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Aug 2023 15:59:32 -0700 Subject: [PATCH 0573/1206] [3.12] gh-107565: Update macOS installer to use OpenSSL 3.0.10. (GH-107897) (#108121) gh-107565: Update macOS installer to use OpenSSL 3.0.10. (GH-107897) (cherry picked from commit dc7b630b2359663bb7b8212d9f2f720c978d3daa) Co-authored-by: Ned Deily --- Mac/BuildScript/build-installer.py | 6 +++--- .../macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 0fc25ec74565df..c108ee21a7a2a3 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -246,9 +246,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 3.0.9", - url="https://www.openssl.org/source/openssl-3.0.9.tar.gz", - checksum='eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90', + name="OpenSSL 3.0.10", + url="https://www.openssl.org/source/openssl-3.0.10.tar.gz", + checksum='1761d4f5b13a1028b9b6f3d4b8e17feb0cedc9370f6afe61d7193d2cdce83323', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst b/Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst new file mode 100644 index 00000000000000..c238c4760239e1 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst @@ -0,0 +1 @@ +Update macOS installer to use OpenSSL 3.0.10. From 71e3581c969e8a7dbfd21db2407af498fd0027e3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:00:09 -0700 Subject: [PATCH 0574/1206] [3.12] gh-101100: Only show GitHub check annotations on changed doc paragraphs (GH-108065) (#108127) gh-101100: Only show GitHub check annotations on changed doc paragraphs (GH-108065) * Only show GitHub check annotations on changed doc paragraphs * Improve check-warnings script arg parsing following Hugo's suggestions * Factor filtering warnings by modified diffs into helper function * Build docs on unmerged branch so warning lines match & avoid deep clone --------- (cherry picked from commit eb953d6e4484339067837020f77eecac61f8d4f8) Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- .github/workflows/reusable-docs.yml | 33 +++-- Doc/tools/check-warnings.py | 206 +++++++++++++++++++++++++--- 2 files changed, 208 insertions(+), 31 deletions(-) diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 39e5ad62924ad3..6150b1a7d416a3 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -16,8 +16,30 @@ jobs: name: 'Docs' runs-on: ubuntu-latest timeout-minutes: 60 + env: + branch_base: 'origin/${{ github.event.pull_request.base.ref }}' + branch_pr: 'origin/${{ github.event.pull_request.head.ref }}' + refspec_base: '+${{ github.event.pull_request.base.sha }}:remotes/origin/${{ github.event.pull_request.base.ref }}' + refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}' steps: - - uses: actions/checkout@v3 + - name: 'Check out latest PR branch commit' + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + # Adapted from https://github.com/actions/checkout/issues/520#issuecomment-1167205721 + - name: 'Fetch commits to get branch diff' + run: | + # Fetch enough history to find a common ancestor commit (aka merge-base): + git fetch origin ${{ env.refspec_pr }} --depth=$(( ${{ github.event.pull_request.commits }} + 1 )) \ + --no-tags --prune --no-recurse-submodules + + # This should get the oldest commit in the local fetched history (which may not be the commit the PR branched from): + COMMON_ANCESTOR=$( git rev-list --first-parent --max-parents=0 --max-count=1 ${{ env.branch_pr }} ) + DATE=$( git log --date=iso8601 --format=%cd "${COMMON_ANCESTOR}" ) + + # Get all commits since that commit date from the base branch (eg: master or main): + git fetch origin ${{ env.refspec_base }} --shallow-since="${DATE}" \ + --no-tags --prune --no-recurse-submodules - name: 'Set up Python' uses: actions/setup-python@v4 with: @@ -28,13 +50,6 @@ jobs: run: make -C Doc/ venv # To annotate PRs with Sphinx nitpicks (missing references) - - name: 'Get list of changed files' - if: github.event_name == 'pull_request' - id: changed_files - uses: Ana06/get-changed-files@v2.2.0 - with: - filter: "Doc/**" - format: csv # works for paths with spaces - name: 'Build HTML documentation' continue-on-error: true run: | @@ -45,7 +60,7 @@ jobs: if: github.event_name == 'pull_request' run: | python Doc/tools/check-warnings.py \ - --check-and-annotate '${{ steps.changed_files.outputs.added_modified }}' \ + --annotate-diff '${{ env.branch_base }}' '${{ env.branch_pr }}' \ --fail-if-regression \ --fail-if-improved diff --git a/Doc/tools/check-warnings.py b/Doc/tools/check-warnings.py index c17d0f51cd1272..809a8d63087e12 100644 --- a/Doc/tools/check-warnings.py +++ b/Doc/tools/check-warnings.py @@ -2,12 +2,16 @@ """ Check the output of running Sphinx in nit-picky mode (missing references). """ +from __future__ import annotations + import argparse -import csv +import itertools import os import re +import subprocess import sys from pathlib import Path +from typing import TextIO # Exclude these whether they're dirty or clean, # because they trigger a rebuild of dirty files. @@ -24,28 +28,178 @@ "venv", } -PATTERN = re.compile(r"(?P[^:]+):(?P\d+): WARNING: (?P.+)") +# Regex pattern to match the parts of a Sphinx warning +WARNING_PATTERN = re.compile( + r"(?P([A-Za-z]:[\\/])?[^:]+):(?P\d+): WARNING: (?P.+)" +) + +# Regex pattern to match the line numbers in a Git unified diff +DIFF_PATTERN = re.compile( + r"^@@ -(?P\d+)(?:,(?P\d+))? \+(?P\d+)(?:,(?P\d+))? @@", + flags=re.MULTILINE, +) + + +def get_diff_files(ref_a: str, ref_b: str, filter_mode: str = "") -> set[Path]: + """List the files changed between two Git refs, filtered by change type.""" + added_files_result = subprocess.run( + [ + "git", + "diff", + f"--diff-filter={filter_mode}", + "--name-only", + f"{ref_a}...{ref_b}", + "--", + ], + stdout=subprocess.PIPE, + check=True, + text=True, + encoding="UTF-8", + ) + + added_files = added_files_result.stdout.strip().split("\n") + return {Path(file.strip()) for file in added_files if file.strip()} + + +def get_diff_lines(ref_a: str, ref_b: str, file: Path) -> list[int]: + """List the lines changed between two Git refs for a specific file.""" + diff_output = subprocess.run( + [ + "git", + "diff", + "--unified=0", + f"{ref_a}...{ref_b}", + "--", + str(file), + ], + stdout=subprocess.PIPE, + check=True, + text=True, + encoding="UTF-8", + ) + + # Scrape line offsets + lengths from diff and convert to line numbers + line_matches = DIFF_PATTERN.finditer(diff_output.stdout) + # Removed and added line counts are 1 if not printed + line_match_values = [ + line_match.groupdict(default=1) for line_match in line_matches + ] + line_ints = [ + (int(match_value["lineb"]), int(match_value["added"])) + for match_value in line_match_values + ] + line_ranges = [ + range(line_b, line_b + added) for line_b, added in line_ints + ] + line_numbers = list(itertools.chain(*line_ranges)) + + return line_numbers + + +def get_para_line_numbers(file_obj: TextIO) -> list[list[int]]: + """Get the line numbers of text in a file object, grouped by paragraph.""" + paragraphs = [] + prev_line = None + for lineno, line in enumerate(file_obj): + lineno = lineno + 1 + if prev_line is None or (line.strip() and not prev_line.strip()): + paragraph = [lineno - 1] + paragraphs.append(paragraph) + paragraph.append(lineno) + prev_line = line + return paragraphs + + +def filter_and_parse_warnings( + warnings: list[str], files: set[Path] +) -> list[re.Match[str]]: + """Get the warnings matching passed files and parse them with regex.""" + filtered_warnings = [ + warning + for warning in warnings + if any(str(file) in warning for file in files) + ] + warning_matches = [ + WARNING_PATTERN.fullmatch(warning.strip()) + for warning in filtered_warnings + ] + non_null_matches = [warning for warning in warning_matches if warning] + return non_null_matches + + +def filter_warnings_by_diff( + warnings: list[re.Match[str]], ref_a: str, ref_b: str, file: Path +) -> list[re.Match[str]]: + """Filter the passed per-file warnings to just those on changed lines.""" + diff_lines = get_diff_lines(ref_a, ref_b, file) + with file.open(encoding="UTF-8") as file_obj: + paragraphs = get_para_line_numbers(file_obj) + touched_paras = [ + para_lines + for para_lines in paragraphs + if set(diff_lines) & set(para_lines) + ] + touched_para_lines = set(itertools.chain(*touched_paras)) + warnings_infile = [ + warning for warning in warnings if str(file) in warning["file"] + ] + warnings_touched = [ + warning + for warning in warnings_infile + if int(warning["line"]) in touched_para_lines + ] + return warnings_touched + +def process_touched_warnings( + warnings: list[str], ref_a: str, ref_b: str +) -> list[re.Match[str]]: + """Filter a list of Sphinx warnings to those affecting touched lines.""" + added_files, modified_files = tuple( + get_diff_files(ref_a, ref_b, filter_mode=mode) for mode in ("A", "M") + ) + + warnings_added = filter_and_parse_warnings(warnings, added_files) + warnings_modified = filter_and_parse_warnings(warnings, modified_files) + + modified_files_warned = { + file + for file in modified_files + if any(str(file) in warning["file"] for warning in warnings_modified) + } -def check_and_annotate(warnings: list[str], files_to_check: str) -> None: + warnings_modified_touched = [ + filter_warnings_by_diff(warnings_modified, ref_a, ref_b, file) + for file in modified_files_warned + ] + warnings_touched = warnings_added + list( + itertools.chain(*warnings_modified_touched) + ) + + return warnings_touched + + +def annotate_diff( + warnings: list[str], ref_a: str = "main", ref_b: str = "HEAD" +) -> None: """ - Convert Sphinx warning messages to GitHub Actions. + Convert Sphinx warning messages to GitHub Actions for changed paragraphs. Converts lines like: .../Doc/library/cgi.rst:98: WARNING: reference target not found to: ::warning file=.../Doc/library/cgi.rst,line=98::reference target not found - Non-matching lines are echoed unchanged. - - see: + See: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message """ - files_to_check = next(csv.reader([files_to_check])) - for warning in warnings: - if any(filename in warning for filename in files_to_check): - if match := PATTERN.fullmatch(warning): - print("::warning file={file},line={line}::{msg}".format_map(match)) + warnings_touched = process_touched_warnings(warnings, ref_a, ref_b) + print("Emitting doc warnings matching modified lines:") + for warning in warnings_touched: + print("::warning file={file},line={line}::{msg}".format_map(warning)) + print(warning[0]) + if not warnings_touched: + print("None") def fail_if_regression( @@ -68,7 +222,7 @@ def fail_if_regression( print(filename) for warning in warnings: if filename in warning: - if match := PATTERN.fullmatch(warning): + if match := WARNING_PATTERN.fullmatch(warning): print(" {line}: {msg}".format_map(match)) return -1 return 0 @@ -91,12 +245,14 @@ def fail_if_improved( return 0 -def main() -> int: +def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument( - "--check-and-annotate", - help="Comma-separated list of files to check, " - "and annotate those with warnings on GitHub Actions", + "--annotate-diff", + nargs="*", + metavar=("BASE_REF", "HEAD_REF"), + help="Add GitHub Actions annotations on the diff for warnings on " + "lines changed between the given refs (main and HEAD, by default)", ) parser.add_argument( "--fail-if-regression", @@ -108,13 +264,19 @@ def main() -> int: action="store_true", help="Fail if new files with no nits are found", ) - args = parser.parse_args() + + args = parser.parse_args(argv) + if args.annotate_diff is not None and len(args.annotate_diff) > 2: + parser.error( + "--annotate-diff takes between 0 and 2 ref args, not " + f"{len(args.annotate_diff)} {tuple(args.annotate_diff)}" + ) exit_code = 0 wrong_directory_msg = "Must run this script from the repo root" assert Path("Doc").exists() and Path("Doc").is_dir(), wrong_directory_msg - with Path("Doc/sphinx-warnings.txt").open() as f: + with Path("Doc/sphinx-warnings.txt").open(encoding="UTF-8") as f: warnings = f.read().splitlines() cwd = str(Path.cwd()) + os.path.sep @@ -124,15 +286,15 @@ def main() -> int: if "Doc/" in warning } - with Path("Doc/tools/.nitignore").open() as clean_files: + with Path("Doc/tools/.nitignore").open(encoding="UTF-8") as clean_files: files_with_expected_nits = { filename.strip() for filename in clean_files if filename.strip() and not filename.startswith("#") } - if args.check_and_annotate: - check_and_annotate(warnings, args.check_and_annotate) + if args.annotate_diff is not None: + annotate_diff(warnings, *args.annotate_diff) if args.fail_if_regression: exit_code += fail_if_regression( From 28074306578fb7e67667ee64cd7d66509d63c21c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:00:31 -0700 Subject: [PATCH 0575/1206] [3.12] Docs: format sys.float_info properly (GH-108107) (#108130) Docs: format sys.float_info properly (GH-108107) - Normalise capitalisation and punctuation - Use attribute markup for named tuple attributes - Use :c:macro: markup for C macros - Use a list for the 'rounds' attribute values - Use list-table, for better .rst readability - Remove one unneeded sys.float_info.dig link (cherry picked from commit ca0c6c1f1ef79d10bc49b61d638d87cde265aa94) Co-authored-by: Erlend E. Aasland Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/sys.rst | 125 ++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 52 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index b6346bafbf625e..334a2b077dd6fb 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -574,61 +574,82 @@ always available. programming language; see section 5.2.4.2.2 of the 1999 ISO/IEC C standard [C99]_, 'Characteristics of floating types', for details. - .. tabularcolumns:: |l|l|L| - - +---------------------+---------------------+--------------------------------------------------+ - | attribute | float.h macro | explanation | - +=====================+=====================+==================================================+ - | ``epsilon`` | ``DBL_EPSILON`` | difference between 1.0 and the least value | - | | | greater than 1.0 that is representable as a float| - | | | | - | | | See also :func:`math.ulp`. | - +---------------------+---------------------+--------------------------------------------------+ - | ``dig`` | ``DBL_DIG`` | maximum number of decimal digits that can be | - | | | faithfully represented in a float; see below | - +---------------------+---------------------+--------------------------------------------------+ - | ``mant_dig`` | ``DBL_MANT_DIG`` | float precision: the number of base-``radix`` | - | | | digits in the significand of a float | - +---------------------+---------------------+--------------------------------------------------+ - | ``max`` | ``DBL_MAX`` | maximum representable positive finite float | - +---------------------+---------------------+--------------------------------------------------+ - | ``max_exp`` | ``DBL_MAX_EXP`` | maximum integer *e* such that ``radix**(e-1)`` is| - | | | a representable finite float | - +---------------------+---------------------+--------------------------------------------------+ - | ``max_10_exp`` | ``DBL_MAX_10_EXP`` | maximum integer *e* such that ``10**e`` is in the| - | | | range of representable finite floats | - +---------------------+---------------------+--------------------------------------------------+ - | ``min`` | ``DBL_MIN`` | minimum representable positive *normalized* float| - | | | | - | | | Use :func:`math.ulp(0.0) ` to get the | - | | | smallest positive *denormalized* representable | - | | | float. | - +---------------------+---------------------+--------------------------------------------------+ - | ``min_exp`` | ``DBL_MIN_EXP`` | minimum integer *e* such that ``radix**(e-1)`` is| - | | | a normalized float | - +---------------------+---------------------+--------------------------------------------------+ - | ``min_10_exp`` | ``DBL_MIN_10_EXP`` | minimum integer *e* such that ``10**e`` is a | - | | | normalized float | - +---------------------+---------------------+--------------------------------------------------+ - | ``radix`` | ``FLT_RADIX`` | radix of exponent representation | - +---------------------+---------------------+--------------------------------------------------+ - | ``rounds`` | ``FLT_ROUNDS`` | integer representing the rounding mode for | - | | | floating-point arithmetic. This reflects the | - | | | value of the system ``FLT_ROUNDS`` macro at | - | | | interpreter startup time: | - | | | ``-1`` indeterminable, | - | | | ``0`` toward zero, | - | | | ``1`` to nearest, | - | | | ``2`` toward positive infinity, | - | | | ``3`` toward negative infinity | - | | | | - | | | All other values for ``FLT_ROUNDS`` characterize | - | | | implementation-defined rounding behavior. | - +---------------------+---------------------+--------------------------------------------------+ + .. list-table:: Attributes of the :data:`!float_info` :term:`named tuple` + :header-rows: 1 + + * - attribute + - float.h macro + - explanation + + * - .. attribute:: float_info.epsilon + - :c:macro:`!DBL_EPSILON` + - difference between 1.0 and the least value greater than 1.0 that is + representable as a float. + + See also :func:`math.ulp`. + + * - .. attribute:: float_info.dig + - :c:macro:`!DBL_DIG` + - The maximum number of decimal digits that can be faithfully + represented in a float; see below. + + * - .. attribute:: float_info.mant_dig + - :c:macro:`!DBL_MANT_DIG` + - Float precision: the number of base-``radix`` digits in the + significand of a float. + + * - .. attribute:: float_info.max + - :c:macro:`!DBL_MAX` + - The maximum representable positive finite float. + + * - .. attribute:: float_info.max_exp + - :c:macro:`!DBL_MAX_EXP` + - The maximum integer *e* such that ``radix**(e-1)`` is a representable + finite float. + + * - .. attribute:: float_info.max_10_exp + - :c:macro:`!DBL_MAX_10_EXP` + - The maximum integer *e* such that ``10**e`` is in the range of + representable finite floats. + + * - .. attribute:: float_info.min + - :c:macro:`!DBL_MIN` + - The minimum representable positive *normalized* float. + + Use :func:`math.ulp(0.0) ` to get the smallest positive + *denormalized* representable float. + + * - .. attribute:: float_info.min_exp + - :c:macro:`!DBL_MIN_EXP` + - The minimum integer *e* such that ``radix**(e-1)`` is a normalized + float. + + * - .. attribute:: float_info.min_10_exp + - :c:macro:`!DBL_MIN_10_EXP` + - The minimum integer *e* such that ``10**e`` is a normalized float. + + * - .. attribute:: float_info.radix + - :c:macro:`!FLT_RADIX` + - The radix of exponent representation. + + * - .. attribute:: float_info.rounds + - :c:macro:`!FLT_ROUNDS` + - An integer representing the rounding mode for floating-point arithmetic. + This reflects the value of the system :c:macro:`!FLT_ROUNDS` macro + at interpreter startup time: + + * ``-1``: indeterminable + * ``0``: toward zero + * ``1``: to nearest + * ``2``: toward positive infinity + * ``3``: toward negative infinity + + All other values for :c:macro:`!FLT_ROUNDS` characterize + implementation-defined rounding behavior. The attribute :attr:`sys.float_info.dig` needs further explanation. If ``s`` is any string representing a decimal number with at most - :attr:`sys.float_info.dig` significant digits, then converting ``s`` to a + :attr:`!sys.float_info.dig` significant digits, then converting ``s`` to a float and back again will recover a string representing the same decimal value:: From 41634edb2b54f488aac286b938a3590f5dac154c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 20 Aug 2023 01:05:00 +0200 Subject: [PATCH 0576/1206] [3.12] gh-107801: Improve the accuracy of os.lseek docs (#107935) (#108136) - name the last parameter *whence*, like it is for seek() methods on file objects - add param docstrings - structure the valid *whence* params (cherry picked from commit dd4442c8f597af1ec3eaf20f7ad89c4ac7e2dbc9) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/os.rst | 17 +++++++++++------ Modules/clinic/posixmodule.c.h | 17 +++++++++++++---- Modules/posixmodule.c | 13 +++++++++---- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 4668984b10c690..7d63ac15027d51 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1163,17 +1163,22 @@ as internal buffering of data. .. versionadded:: 3.11 -.. function:: lseek(fd, pos, how, /) +.. function:: lseek(fd, pos, whence, /) Set the current position of file descriptor *fd* to position *pos*, modified - by *how*: :const:`SEEK_SET` or ``0`` to set the position relative to the - beginning of the file; :const:`SEEK_CUR` or ``1`` to set it relative to the - current position; :const:`SEEK_END` or ``2`` to set it relative to the end of - the file. Return the new cursor position in bytes, starting from the beginning. + by *whence*, and return the new position in bytes relative to + the start of the file. + Valid values for *whence* are: + + * :const:`SEEK_SET` or ``0`` -- set *pos* relative to the beginning of the file + * :const:`SEEK_CUR` or ``1`` -- set *pos* relative to the current file position + * :const:`SEEK_END` or ``2`` -- set *pos* relative to the end of the file + * :const:`SEEK_HOLE` -- set *pos* to the next data location, relative to *pos* + * :const:`SEEK_DATA` -- set *pos* to the next data hole, relative to *pos* .. versionchanged:: 3.3 - Add support for :const:`SEEK_HOLE` and :const:`SEEK_DATA`. + Add support for :const:`!SEEK_HOLE` and :const:`!SEEK_DATA`. .. data:: SEEK_SET diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 3312bd667694dd..5924c4ab03943a 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -6496,13 +6496,22 @@ os_lockf(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #endif /* defined(HAVE_LOCKF) */ PyDoc_STRVAR(os_lseek__doc__, -"lseek($module, fd, position, how, /)\n" +"lseek($module, fd, position, whence, /)\n" "--\n" "\n" "Set the position of a file descriptor. Return the new position.\n" "\n" -"Return the new cursor position in number of bytes\n" -"relative to the beginning of the file."); +" fd\n" +" An open file descriptor, as returned by os.open().\n" +" position\n" +" Position, interpreted relative to \'whence\'.\n" +" whence\n" +" The relative position to seek from. Valid values are:\n" +" - SEEK_SET: seek from the start of the file.\n" +" - SEEK_CUR: seek from the current file position.\n" +" - SEEK_END: seek from the end of the file.\n" +"\n" +"The return value is the number of bytes relative to the beginning of the file."); #define OS_LSEEK_METHODDEF \ {"lseek", _PyCFunction_CAST(os_lseek), METH_FASTCALL, os_lseek__doc__}, @@ -11990,4 +11999,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=9d8b0d6717c9af54 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6646be70849f971f input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b9f45c0ce5543d..44cc31bd4bd702 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10421,19 +10421,24 @@ os_lockf_impl(PyObject *module, int fd, int command, Py_off_t length) os.lseek -> Py_off_t fd: int + An open file descriptor, as returned by os.open(). position: Py_off_t - how: int + Position, interpreted relative to 'whence'. + whence as how: int + The relative position to seek from. Valid values are: + - SEEK_SET: seek from the start of the file. + - SEEK_CUR: seek from the current file position. + - SEEK_END: seek from the end of the file. / Set the position of a file descriptor. Return the new position. -Return the new cursor position in number of bytes -relative to the beginning of the file. +The return value is the number of bytes relative to the beginning of the file. [clinic start generated code]*/ static Py_off_t os_lseek_impl(PyObject *module, int fd, Py_off_t position, int how) -/*[clinic end generated code: output=971e1efb6b30bd2f input=902654ad3f96a6d3]*/ +/*[clinic end generated code: output=971e1efb6b30bd2f input=f096e754c5367504]*/ { Py_off_t result; From 0c21298f2bc17966498f13995586890488a6f8f1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 20 Aug 2023 01:07:41 +0200 Subject: [PATCH 0577/1206] [3.12] gh-108083: Don't ignore exceptions in sqlite3.Connection.__init__() and .close() (#108084) (#108141) - Add explanatory comments - Add return value to connection_close() for propagating errors - Always check the return value of connection_exec_stmt() - Assert pre/post state in remove_callbacks() - Don't log unraisable exceptions in case of interpreter shutdown - Make sure we're not initialized if reinit fails - Try to close the database even if ROLLBACK fails (cherry picked from commit fd195092204aa7fc9f13c5c6d423bc723d0b3520) Co-authored-by: Victor Stinner Co-authored-by: Serhiy Storchaka --- ...-08-17-12-59-35.gh-issue-108083.9J7UcT.rst | 3 + Modules/_sqlite/connection.c | 106 +++++++++++++----- 2 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst diff --git a/Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst b/Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst new file mode 100644 index 00000000000000..ff499ced73a309 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst @@ -0,0 +1,3 @@ +Fix bugs in the constructor of :mod:`sqlite3.Connection` and +:meth:`sqlite3.Connection.close` where exceptions could be leaked. Patch by +Erlend E. Aasland. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 82d23c2c30b798..12e5c135aafa50 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -146,7 +146,7 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); static void free_callback_context(callback_context *ctx); static void set_callback_context(callback_context **ctx_pp, callback_context *ctx); -static void connection_close(pysqlite_Connection *self); +static int connection_close(pysqlite_Connection *self); PyObject *_pysqlite_query_execute(pysqlite_Cursor *, int, PyObject *, PyObject *); static PyObject * @@ -244,10 +244,13 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, } if (self->initialized) { + self->initialized = 0; + PyTypeObject *tp = Py_TYPE(self); tp->tp_clear((PyObject *)self); - connection_close(self); - self->initialized = 0; + if (connection_close(self) < 0) { + return -1; + } } // Create and configure SQLite database object. @@ -331,7 +334,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, self->initialized = 1; if (autocommit == AUTOCOMMIT_DISABLED) { - (void)connection_exec_stmt(self, "BEGIN"); + if (connection_exec_stmt(self, "BEGIN") < 0) { + return -1; + } } return 0; @@ -401,52 +406,88 @@ free_callback_contexts(pysqlite_Connection *self) static void remove_callbacks(sqlite3 *db) { + assert(db != NULL); + /* None of these APIs can fail, as long as they are given a valid + * database pointer. */ + int rc; #ifdef HAVE_TRACE_V2 - sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0); + rc = sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0); + assert(rc == SQLITE_OK), (void)rc; #else sqlite3_trace(db, 0, (void*)0); #endif + sqlite3_progress_handler(db, 0, 0, (void *)0); - (void)sqlite3_set_authorizer(db, NULL, NULL); + + rc = sqlite3_set_authorizer(db, NULL, NULL); + assert(rc == SQLITE_OK), (void)rc; } -static void +static int connection_close(pysqlite_Connection *self) { - if (self->db) { - if (self->autocommit == AUTOCOMMIT_DISABLED && - !sqlite3_get_autocommit(self->db)) - { - /* If close is implicitly called as a result of interpreter - * tear-down, we must not call back into Python. */ - if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) { - remove_callbacks(self->db); - } - (void)connection_exec_stmt(self, "ROLLBACK"); + if (self->db == NULL) { + return 0; + } + + int rc = 0; + if (self->autocommit == AUTOCOMMIT_DISABLED && + !sqlite3_get_autocommit(self->db)) + { + if (connection_exec_stmt(self, "ROLLBACK") < 0) { + rc = -1; } + } - free_callback_contexts(self); + sqlite3 *db = self->db; + self->db = NULL; - sqlite3 *db = self->db; - self->db = NULL; + Py_BEGIN_ALLOW_THREADS + /* The v2 close call always returns SQLITE_OK if given a valid database + * pointer (which we do), so we can safely ignore the return value */ + (void)sqlite3_close_v2(db); + Py_END_ALLOW_THREADS - Py_BEGIN_ALLOW_THREADS - int rc = sqlite3_close_v2(db); - assert(rc == SQLITE_OK), (void)rc; - Py_END_ALLOW_THREADS - } + free_callback_contexts(self); + return rc; } static void -connection_dealloc(pysqlite_Connection *self) +connection_finalize(PyObject *self) { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - tp->tp_clear((PyObject *)self); + pysqlite_Connection *con = (pysqlite_Connection *)self; + PyObject *exc = PyErr_GetRaisedException(); + + /* If close is implicitly called as a result of interpreter + * tear-down, we must not call back into Python. */ + PyInterpreterState *interp = PyInterpreterState_Get(); + int teardown = _Py_IsInterpreterFinalizing(interp); + if (teardown && con->db) { + remove_callbacks(con->db); + } /* Clean up if user has not called .close() explicitly. */ - connection_close(self); + if (connection_close(con) < 0) { + if (teardown) { + PyErr_Clear(); + } + else { + PyErr_WriteUnraisable((PyObject *)self); + } + } + + PyErr_SetRaisedException(exc); +} +static void +connection_dealloc(PyObject *self) +{ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + return; + } + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_clear(self); tp->tp_free(self); Py_DECREF(tp); } @@ -594,7 +635,9 @@ pysqlite_connection_close_impl(pysqlite_Connection *self) pysqlite_close_all_blobs(self); Py_CLEAR(self->statement_cache); - connection_close(self); + if (connection_close(self) < 0) { + return NULL; + } Py_RETURN_NONE; } @@ -2582,6 +2625,7 @@ static struct PyMemberDef connection_members[] = }; static PyType_Slot connection_slots[] = { + {Py_tp_finalize, connection_finalize}, {Py_tp_dealloc, connection_dealloc}, {Py_tp_doc, (void *)connection_doc}, {Py_tp_methods, connection_methods}, From 540c0d99eabcdaedd7f6b56406abc08a628188b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:08:14 -0700 Subject: [PATCH 0578/1206] [3.12] Docs: Remove links to external C functions and macros in os.rst (GH-108138) (#108143) Docs: Remove links to external C functions and macros in os.rst (GH-108138) (cherry picked from commit c31c61c04e55ef431615ffec959d84ac73a3db81) Co-authored-by: Erlend E. Aasland Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/os.rst | 52 ++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 7d63ac15027d51..4f4d8c99023529 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -215,7 +215,7 @@ process and user. On some platforms, including FreeBSD and macOS, setting ``environ`` may cause memory leaks. Refer to the system documentation for - :c:func:`putenv`. + :c:func:`!putenv`. You can delete items in this mapping to unset environment variables. :func:`unsetenv` will be called automatically when an item is deleted from @@ -564,7 +564,7 @@ process and user. .. note:: On some platforms, including FreeBSD and macOS, setting ``environ`` may - cause memory leaks. Refer to the system documentation for :c:func:`putenv`. + cause memory leaks. Refer to the system documentation for :c:func:`!putenv`. .. audit-event:: os.putenv key,value os.putenv @@ -646,7 +646,7 @@ process and user. .. function:: setpgrp() - Call the system call :c:func:`setpgrp` or ``setpgrp(0, 0)`` depending on + Call the system call :c:func:`!setpgrp` or ``setpgrp(0, 0)`` depending on which version is implemented (if any). See the Unix manual for the semantics. .. availability:: Unix, not Emscripten, not WASI. @@ -654,7 +654,7 @@ process and user. .. function:: setpgid(pid, pgrp, /) - Call the system call :c:func:`setpgid` to set the process group id of the + Call the system call :c:func:`!setpgid` to set the process group id of the process with id *pid* to the process group with id *pgrp*. See the Unix manual for the semantics. @@ -1077,7 +1077,7 @@ as internal buffering of data. .. function:: fsync(fd) Force write of file with filedescriptor *fd* to disk. On Unix, this calls the - native :c:func:`fsync` function; on Windows, the MS :c:func:`_commit` function. + native :c:func:`!fsync` function; on Windows, the MS :c:func:`!_commit` function. If you're starting with a buffered Python :term:`file object` *f*, first do ``f.flush()``, and then do ``os.fsync(f.fileno())``, to ensure that all internal @@ -2304,7 +2304,7 @@ features: .. function:: lstat(path, *, dir_fd=None) - Perform the equivalent of an :c:func:`lstat` system call on the given path. + Perform the equivalent of an :c:func:`!lstat` system call on the given path. Similar to :func:`~os.stat`, but does not follow symbolic links. Return a :class:`stat_result` object. @@ -3147,14 +3147,16 @@ features: Windows file attributes: ``dwFileAttributes`` member of the ``BY_HANDLE_FILE_INFORMATION`` structure returned by - :c:func:`GetFileInformationByHandle`. See the ``FILE_ATTRIBUTE_*`` + :c:func:`!GetFileInformationByHandle`. + See the :const:`!FILE_ATTRIBUTE_* ` constants in the :mod:`stat` module. .. attribute:: st_reparse_tag - When :attr:`st_file_attributes` has the ``FILE_ATTRIBUTE_REPARSE_POINT`` + When :attr:`st_file_attributes` has the :const:`~stat.FILE_ATTRIBUTE_REPARSE_POINT` set, this field contains the tag identifying the type of reparse point. - See the ``IO_REPARSE_TAG_*`` constants in the :mod:`stat` module. + See the :const:`IO_REPARSE_TAG_* ` + constants in the :mod:`stat` module. The standard module :mod:`stat` defines functions and constants that are useful for extracting information from a :c:struct:`stat` structure. (On @@ -3212,7 +3214,7 @@ features: .. function:: statvfs(path) - Perform a :c:func:`statvfs` system call on the given path. The return value is + Perform a :c:func:`!statvfs` system call on the given path. The return value is an object whose attributes describe the filesystem on the given path, and correspond to the members of the :c:struct:`statvfs` structure, namely: :attr:`f_bsize`, :attr:`f_frsize`, :attr:`f_blocks`, :attr:`f_bfree`, @@ -4303,7 +4305,7 @@ written in Python, such as a mail server's external command delivery program. setpgroup=None, resetids=False, setsid=False, setsigmask=(), \ setsigdef=(), scheduler=None) - Wraps the :c:func:`posix_spawn` C library API for use from Python. + Wraps the :c:func:`!posix_spawn` C library API for use from Python. Most users should use :func:`subprocess.run` instead of :func:`posix_spawn`. @@ -4339,16 +4341,16 @@ written in Python, such as a mail server's external command delivery program. Performs ``os.dup2(fd, new_fd)``. These tuples correspond to the C library - :c:func:`posix_spawn_file_actions_addopen`, - :c:func:`posix_spawn_file_actions_addclose`, and - :c:func:`posix_spawn_file_actions_adddup2` API calls used to prepare - for the :c:func:`posix_spawn` call itself. + :c:func:`!posix_spawn_file_actions_addopen`, + :c:func:`!posix_spawn_file_actions_addclose`, and + :c:func:`!posix_spawn_file_actions_adddup2` API calls used to prepare + for the :c:func:`!posix_spawn` call itself. The *setpgroup* argument will set the process group of the child to the value specified. If the value specified is 0, the child's process group ID will be made the same as its process ID. If the value of *setpgroup* is not set, the child will inherit the parent's process group ID. This argument corresponds - to the C library :c:macro:`POSIX_SPAWN_SETPGROUP` flag. + to the C library :c:macro:`!POSIX_SPAWN_SETPGROUP` flag. If the *resetids* argument is ``True`` it will reset the effective UID and GID of the child to the real UID and GID of the parent process. If the @@ -4356,27 +4358,27 @@ written in Python, such as a mail server's external command delivery program. the parent. In either case, if the set-user-ID and set-group-ID permission bits are enabled on the executable file, their effect will override the setting of the effective UID and GID. This argument corresponds to the C - library :c:macro:`POSIX_SPAWN_RESETIDS` flag. + library :c:macro:`!POSIX_SPAWN_RESETIDS` flag. If the *setsid* argument is ``True``, it will create a new session ID - for ``posix_spawn``. *setsid* requires :c:macro:`POSIX_SPAWN_SETSID` - or :c:macro:`POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError` + for ``posix_spawn``. *setsid* requires :c:macro:`!POSIX_SPAWN_SETSID` + or :c:macro:`!POSIX_SPAWN_SETSID_NP` flag. Otherwise, :exc:`NotImplementedError` is raised. The *setsigmask* argument will set the signal mask to the signal set specified. If the parameter is not used, then the child inherits the parent's signal mask. This argument corresponds to the C library - :c:macro:`POSIX_SPAWN_SETSIGMASK` flag. + :c:macro:`!POSIX_SPAWN_SETSIGMASK` flag. The *sigdef* argument will reset the disposition of all signals in the set specified. This argument corresponds to the C library - :c:macro:`POSIX_SPAWN_SETSIGDEF` flag. + :c:macro:`!POSIX_SPAWN_SETSIGDEF` flag. The *scheduler* argument must be a tuple containing the (optional) scheduler policy and an instance of :class:`sched_param` with the scheduler parameters. A value of ``None`` in the place of the scheduler policy indicates that is not being provided. This argument is a combination of the C library - :c:macro:`POSIX_SPAWN_SETSCHEDPARAM` and :c:macro:`POSIX_SPAWN_SETSCHEDULER` + :c:macro:`!POSIX_SPAWN_SETSCHEDPARAM` and :c:macro:`!POSIX_SPAWN_SETSCHEDULER` flags. .. audit-event:: os.posix_spawn path,argv,env os.posix_spawn @@ -4389,7 +4391,7 @@ written in Python, such as a mail server's external command delivery program. setpgroup=None, resetids=False, setsid=False, setsigmask=(), \ setsigdef=(), scheduler=None) - Wraps the :c:func:`posix_spawnp` C library API for use from Python. + Wraps the :c:func:`!posix_spawnp` C library API for use from Python. Similar to :func:`posix_spawn` except that the system searches for the *executable* file in the list of directories specified by the @@ -4570,7 +4572,7 @@ written in Python, such as a mail server's external command delivery program. Use *show_cmd* to override the default window style. Whether this has any effect will depend on the application being launched. Values are integers as - supported by the Win32 :c:func:`ShellExecute` function. + supported by the Win32 :c:func:`!ShellExecute` function. :func:`startfile` returns as soon as the associated application is launched. There is no option to wait for the application to close, and no way to retrieve @@ -4580,7 +4582,7 @@ written in Python, such as a mail server's external command delivery program. :func:`os.path.normpath` function to ensure that paths are properly encoded for Win32. - To reduce interpreter startup overhead, the Win32 :c:func:`ShellExecute` + To reduce interpreter startup overhead, the Win32 :c:func:`!ShellExecute` function is not resolved until this function is first called. If the function cannot be resolved, :exc:`NotImplementedError` will be raised. From 0e5eee0130bb4924264250da60c2d636d357dc4d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 19 Aug 2023 16:08:40 -0700 Subject: [PATCH 0579/1206] [3.12] gh-107980: fix doc role for asyncio.timeouts (GH-108126) (#108152) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-107980: fix doc role for asyncio.timeouts (GH-108126) (cherry picked from commit a47c13cae5b32e6f3d7532cc6dbb4e1ac31219de) Co-authored-by: Tin Tvrtković --- Doc/library/asyncio-task.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index d07fbae287e535..f488aa73a62f02 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -628,9 +628,9 @@ Shielding From Cancellation Timeouts ======== -.. coroutinefunction:: timeout(delay) +.. function:: timeout(delay) - An :ref:`asynchronous context manager ` + Return an :ref:`asynchronous context manager ` that can be used to limit the amount of time spent waiting on something. @@ -721,7 +721,7 @@ Timeouts .. versionadded:: 3.11 -.. coroutinefunction:: timeout_at(when) +.. function:: timeout_at(when) Similar to :func:`asyncio.timeout`, except *when* is the absolute time to stop waiting, or ``None``. From a4a494aff481e210ce2658ecd9f32304c1e27f90 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 06:48:46 -0700 Subject: [PATCH 0580/1206] [3.12] Fix misspellings in sysconfig docs (GH-108156) (#108157) Fix misspellings in sysconfig docs (GH-108156) (cherry picked from commit 1dc0c58d2b17819720d184ec0287a8a9b1dc347e) Co-authored-by: Rafael Fontenelle --- Doc/library/sysconfig.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index c805c50ffc689f..26344ea4e7e2ab 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -84,13 +84,13 @@ Python currently supports nine schemes: through Distutils and the *user* option is used. This scheme defines paths located under the user home directory. - *posix_venv*: scheme for :mod:`Python virtual environments ` on POSIX - platforms; by default it is the same as *posix_prefix* . + platforms; by default it is the same as *posix_prefix*. - *nt*: scheme for NT platforms like Windows. - *nt_user*: scheme for NT platforms, when the *user* option is used. - *nt_venv*: scheme for :mod:`Python virtual environments ` on NT - platforms; by default it is the same as *nt* . -- *venv*: a scheme with values from ether *posix_venv* or *nt_venv* depending - on the platform Python runs on + platforms; by default it is the same as *nt*. +- *venv*: a scheme with values from either *posix_venv* or *nt_venv* depending + on the platform Python runs on. - *osx_framework_user*: scheme for macOS, when the *user* option is used. Each scheme is itself composed of a series of paths and each path has a unique @@ -187,7 +187,7 @@ identifier. Python currently uses eight paths: platform is used. If *vars* is provided, it must be a dictionary of variables that will update - the dictionary return by :func:`get_config_vars`. + the dictionary returned by :func:`get_config_vars`. If *expand* is set to ``False``, the path will not be expanded using the variables. From 1e46f1a9a438f11f7a69844c6701bca2016b1e8b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 06:49:03 -0700 Subject: [PATCH 0581/1206] [3.12] Fix patchcheck for `asyncio.tasks` (GH-108159) (#108160) Fix patchcheck for `asyncio.tasks` (GH-108159) (cherry picked from commit b1e5d2c601bbd3d435b60deef4818f3622bdfca3) Co-authored-by: Kumar Aditya --- Lib/asyncio/tasks.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 8d5bde09ea9b5b..152c9f8afcc062 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -944,21 +944,21 @@ def callback(): def create_eager_task_factory(custom_task_constructor): """Create a function suitable for use as a task factory on an event-loop. - Example usage: + Example usage: - loop.set_task_factory( - asyncio.create_eager_task_factory(my_task_constructor)) + loop.set_task_factory( + asyncio.create_eager_task_factory(my_task_constructor)) - Now, tasks created will be started immediately (rather than being first - scheduled to an event loop). The constructor argument can be any callable - that returns a Task-compatible object and has a signature compatible - with `Task.__init__`; it must have the `eager_start` keyword argument. + Now, tasks created will be started immediately (rather than being first + scheduled to an event loop). The constructor argument can be any callable + that returns a Task-compatible object and has a signature compatible + with `Task.__init__`; it must have the `eager_start` keyword argument. - Most applications will use `Task` for `custom_task_constructor` and in + Most applications will use `Task` for `custom_task_constructor` and in this case there's no need to call `create_eager_task_factory()` directly. Instead the global `eager_task_factory` instance can be used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`. - """ + """ def factory(loop, coro, *, name=None, context=None): return custom_task_constructor( From fbe1cff015f0ae792005b443fe9fb4a5137ccc77 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 06:49:32 -0700 Subject: [PATCH 0582/1206] [3.12] gh-107619: Extend functools LRU cache docs with generators and async functions (GH-107934) (#108161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-107619: Extend functools LRU cache docs with generators and async functions (GH-107934) (cherry picked from commit 1a713eac47b26899044752f02cbfcb4d628dda2a) Co-authored-by: Hadházy Tamás <85063808+Hels15@users.noreply.github.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Kumar Aditya --- Doc/library/functools.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 40f43f8b3519cd..f736eb0aca1ac5 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -226,8 +226,9 @@ The :mod:`functools` module defines the following functions: In general, the LRU cache should only be used when you want to reuse previously computed values. Accordingly, it doesn't make sense to cache - functions with side-effects, functions that need to create distinct mutable - objects on each call, or impure functions such as time() or random(). + functions with side-effects, functions that need to create + distinct mutable objects on each call (such as generators and async functions), + or impure functions such as time() or random(). Example of an LRU cache for static web content:: From 590bc6a226f6425970197ff5c3a57beeaa99cdca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 06:50:09 -0700 Subject: [PATCH 0583/1206] [3.12] gh-107659: Improve wording of the description of `ctypes.pointer` and `ctypes.POINTER` (GH-107769) (#108163) gh-107659: Improve wording of the description of `ctypes.pointer` and `ctypes.POINTER` (GH-107769) (cherry picked from commit beffb30dc7a07044f4198245d049ddda1f4b24db) Co-authored-by: Tomas R Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Kumar Aditya --- Doc/library/ctypes.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index cd5c41e9b59c97..19cee10711fb89 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2029,17 +2029,17 @@ Utility functions specifying an address, or a ctypes instance. -.. function:: POINTER(type) +.. function:: POINTER(type, /) - This factory function creates and returns a new ctypes pointer type. Pointer - types are cached and reused internally, so calling this function repeatedly is - cheap. *type* must be a ctypes type. + Create and return a new ctypes pointer type. Pointer types are cached and + reused internally, so calling this function repeatedly is cheap. + *type* must be a ctypes type. -.. function:: pointer(obj) +.. function:: pointer(obj, /) - This function creates a new pointer instance, pointing to *obj*. The returned - object is of the type ``POINTER(type(obj))``. + Create a new pointer instance, pointing to *obj*. + The returned object is of the type ``POINTER(type(obj))``. Note: If you just want to pass a pointer to an object to a foreign function call, you should use ``byref(obj)`` which is much faster. From ff125c4bd8694808892475ad6b63821fb7ea4338 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 06:50:29 -0700 Subject: [PATCH 0584/1206] [3.12] Docs: Fix Sphinx warnings in license.rst (GH-108142) (#108167) Docs: Fix Sphinx warnings in license.rst (GH-108142) - Fix links to stdlib modules - Silence links to external functions (cherry picked from commit 4d4393139fae39db26dead33529b6ae0bafbfc58) Co-authored-by: Erlend E. Aasland --- Doc/license.rst | 10 +++++----- Doc/tools/.nitignore | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Doc/license.rst b/Doc/license.rst index 812a0adffe1a49..1b209922b09528 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -352,8 +352,8 @@ the verbatim comments from the original code:: Sockets ------- -The :mod:`socket` module uses the functions, :func:`getaddrinfo`, and -:func:`getnameinfo`, which are coded in separate source files from the WIDE +The :mod:`socket` module uses the functions, :c:func:`!getaddrinfo`, and +:c:func:`!getnameinfo`, which are coded in separate source files from the WIDE Project, https://www.wide.ad.jp/. :: Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -387,7 +387,7 @@ Project, https://www.wide.ad.jp/. :: Asynchronous socket services ---------------------------- -The :mod:`test.support.asynchat` and :mod:`test.support.asyncore` +The :mod:`!test.support.asynchat` and :mod:`!test.support.asyncore` modules contain the following notice:: Copyright 1996 by Sam Rushing @@ -539,7 +539,7 @@ The :mod:`xmlrpc.client` module contains the following notice:: test_epoll ---------- -The :mod:`test_epoll` module contains the following notice:: +The :mod:`!test.test_epoll` module contains the following notice:: Copyright (c) 2001-2006 Twisted Matrix Laboratories. @@ -844,7 +844,7 @@ and later releases derived from that, the Apache License v2 applies:: expat ----- -The :mod:`pyexpat` extension is built using an included copy of the expat +The :mod:`pyexpat ` extension is built using an included copy of the expat sources unless the build is configured ``--with-system-expat``:: Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 88ac905467299a..d55b611a055752 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -176,7 +176,6 @@ Doc/library/xml.sax.rst Doc/library/xmlrpc.client.rst Doc/library/xmlrpc.server.rst Doc/library/zlib.rst -Doc/license.rst Doc/reference/compound_stmts.rst Doc/reference/datamodel.rst Doc/reference/expressions.rst From 7f5a741a28a7b87c9cdb1db87fcb3f0b9ed8ac2a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 07:44:43 -0700 Subject: [PATCH 0585/1206] [3.12] Resolve reference warnings in faq/programming.rst (GH-108150) (#108170) Resolve reference warnings in faq/programming.rst (GH-108150) (cherry picked from commit a390ec20f5a85b9c16e8708f117667783d08863c) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/faq/programming.rst | 6 +++--- Doc/tools/.nitignore | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index ab5618db84f77e..f43f69b8a1ea91 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -454,7 +454,7 @@ There are two factors that produce this result: (the list), and both ``x`` and ``y`` refer to it. 2) Lists are :term:`mutable`, which means that you can change their content. -After the call to :meth:`~list.append`, the content of the mutable object has +After the call to :meth:`!append`, the content of the mutable object has changed from ``[]`` to ``[10]``. Since both the variables refer to the same object, using either name accesses the modified value ``[10]``. @@ -1397,7 +1397,7 @@ To see why this happens, you need to know that (a) if an object implements an :meth:`~object.__iadd__` magic method, it gets called when the ``+=`` augmented assignment is executed, and its return value is what gets used in the assignment statement; -and (b) for lists, :meth:`!__iadd__` is equivalent to calling :meth:`~list.extend` on the list +and (b) for lists, :meth:`!__iadd__` is equivalent to calling :meth:`!extend` on the list and returning the list. That's why we say that for lists, ``+=`` is a "shorthand" for :meth:`!list.extend`:: @@ -1903,7 +1903,7 @@ identity tests. This prevents the code from being confused by objects such as ``float('NaN')`` that are not equal to themselves. For example, here is the implementation of -:meth:`collections.abc.Sequence.__contains__`:: +:meth:`!collections.abc.Sequence.__contains__`:: def __contains__(self, value): for v in self: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index d55b611a055752..a0a121b4b9dbe6 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -28,7 +28,6 @@ Doc/extending/newtypes.rst Doc/faq/design.rst Doc/faq/gui.rst Doc/faq/library.rst -Doc/faq/programming.rst Doc/glossary.rst Doc/howto/descriptor.rst Doc/howto/enum.rst From 97d67e9dabb3d66525a46dc4d802195ced24e6ef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 14:07:24 -0700 Subject: [PATCH 0586/1206] [3.12] gh-107915: Handle errors in C API functions PyErr_Set*() and PyErr_Format() (GH-107918) (#108134) * gh-107915: Handle errors in C API functions PyErr_Set*() and PyErr_Format() (GH-107918) Such C API functions as PyErr_SetString(), PyErr_Format(), PyErr_SetFromErrnoWithFilename() and many others no longer crash or ignore errors if it failed to format the error message or decode the filename. Instead, they keep a corresponding error. (cherry picked from commit 633ea217a85f6b6ba5bdbc73094254d5811b3485) Co-authored-by: Serhiy Storchaka * Define PY_SSIZE_T_CLEAN. --------- Co-authored-by: Serhiy Storchaka --- Lib/test/test_capi/test_exceptions.py | 81 +++++++++++++++++++ ...-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst | 4 + Modules/_testcapi/clinic/exceptions.c.h | 64 ++++++++++++++- Modules/_testcapi/exceptions.c | 42 ++++++++++ Python/errors.c | 37 +++++++-- 5 files changed, 219 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index 118b575cba6df7..b96cc7922a0ee7 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -1,9 +1,12 @@ +import errno +import os import re import sys import unittest from test import support from test.support import import_helper +from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE from test.support.script_helper import assert_python_failure from test.support.testcase import ExceptionIsLikeMixin @@ -12,6 +15,8 @@ # Skip this test if the _testcapi module isn't available. _testcapi = import_helper.import_module('_testcapi') +NULL = None + class Test_Exceptions(unittest.TestCase): def test_exception(self): @@ -189,6 +194,82 @@ def __repr__(self): self.assertEqual(exc.__notes__[0], 'Normalization failed: type=Broken args=') + def test_set_string(self): + """Test PyErr_SetString()""" + setstring = _testcapi.err_setstring + with self.assertRaises(ZeroDivisionError) as e: + setstring(ZeroDivisionError, b'error') + self.assertEqual(e.exception.args, ('error',)) + with self.assertRaises(ZeroDivisionError) as e: + setstring(ZeroDivisionError, 'помилка'.encode()) + self.assertEqual(e.exception.args, ('помилка',)) + + with self.assertRaises(UnicodeDecodeError): + setstring(ZeroDivisionError, b'\xff') + self.assertRaises(SystemError, setstring, list, b'error') + # CRASHES setstring(ZeroDivisionError, NULL) + # CRASHES setstring(NULL, b'error') + + def test_format(self): + """Test PyErr_Format()""" + import_helper.import_module('ctypes') + from ctypes import pythonapi, py_object, c_char_p, c_int + name = "PyErr_Format" + PyErr_Format = getattr(pythonapi, name) + PyErr_Format.argtypes = (py_object, c_char_p,) + PyErr_Format.restype = py_object + with self.assertRaises(ZeroDivisionError) as e: + PyErr_Format(ZeroDivisionError, b'%s %d', b'error', c_int(42)) + self.assertEqual(e.exception.args, ('error 42',)) + with self.assertRaises(ZeroDivisionError) as e: + PyErr_Format(ZeroDivisionError, b'%s', 'помилка'.encode()) + self.assertEqual(e.exception.args, ('помилка',)) + + with self.assertRaisesRegex(OverflowError, 'not in range'): + PyErr_Format(ZeroDivisionError, b'%c', c_int(-1)) + with self.assertRaisesRegex(ValueError, 'format string'): + PyErr_Format(ZeroDivisionError, b'\xff') + self.assertRaises(SystemError, PyErr_Format, list, b'error') + # CRASHES PyErr_Format(ZeroDivisionError, NULL) + # CRASHES PyErr_Format(py_object(), b'error') + + def test_setfromerrnowithfilename(self): + """Test PyErr_SetFromErrnoWithFilename()""" + setfromerrnowithfilename = _testcapi.err_setfromerrnowithfilename + ENOENT = errno.ENOENT + with self.assertRaises(FileNotFoundError) as e: + setfromerrnowithfilename(ENOENT, OSError, b'file') + self.assertEqual(e.exception.args, + (ENOENT, 'No such file or directory')) + self.assertEqual(e.exception.errno, ENOENT) + self.assertEqual(e.exception.filename, 'file') + + with self.assertRaises(FileNotFoundError) as e: + setfromerrnowithfilename(ENOENT, OSError, os.fsencode(TESTFN)) + self.assertEqual(e.exception.filename, TESTFN) + + if TESTFN_UNDECODABLE: + with self.assertRaises(FileNotFoundError) as e: + setfromerrnowithfilename(ENOENT, OSError, TESTFN_UNDECODABLE) + self.assertEqual(e.exception.filename, + os.fsdecode(TESTFN_UNDECODABLE)) + + with self.assertRaises(FileNotFoundError) as e: + setfromerrnowithfilename(ENOENT, OSError, NULL) + self.assertIsNone(e.exception.filename) + + with self.assertRaises(OSError) as e: + setfromerrnowithfilename(0, OSError, b'file') + self.assertEqual(e.exception.args, (0, 'Error')) + self.assertEqual(e.exception.errno, 0) + self.assertEqual(e.exception.filename, 'file') + + with self.assertRaises(ZeroDivisionError) as e: + setfromerrnowithfilename(ENOENT, ZeroDivisionError, b'file') + self.assertEqual(e.exception.args, + (ENOENT, 'No such file or directory', 'file')) + # CRASHES setfromerrnowithfilename(ENOENT, NULL, b'error') + class Test_PyUnstable_Exc_PrepReraiseStar(ExceptionIsLikeMixin, unittest.TestCase): diff --git a/Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst b/Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst new file mode 100644 index 00000000000000..58ee3f169a28cc --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst @@ -0,0 +1,4 @@ +Such C API functions as ``PyErr_SetString()``, ``PyErr_Format()``, +``PyErr_SetFromErrnoWithFilename()`` and many others no longer crash or +ignore errors if it failed to format the error message or decode the +filename. Instead, they keep a corresponding error. diff --git a/Modules/_testcapi/clinic/exceptions.c.h b/Modules/_testcapi/clinic/exceptions.c.h index 01730ffa2ed036..16954a5ebf3e58 100644 --- a/Modules/_testcapi/clinic/exceptions.c.h +++ b/Modules/_testcapi/clinic/exceptions.c.h @@ -215,6 +215,68 @@ _testcapi_exc_set_object_fetch(PyObject *module, PyObject *const *args, Py_ssize return return_value; } +PyDoc_STRVAR(_testcapi_err_setstring__doc__, +"err_setstring($module, exc, value, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_ERR_SETSTRING_METHODDEF \ + {"err_setstring", _PyCFunction_CAST(_testcapi_err_setstring), METH_FASTCALL, _testcapi_err_setstring__doc__}, + +static PyObject * +_testcapi_err_setstring_impl(PyObject *module, PyObject *exc, + const char *value, Py_ssize_t value_length); + +static PyObject * +_testcapi_err_setstring(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc; + const char *value; + Py_ssize_t value_length; + + if (!_PyArg_ParseStack(args, nargs, "Oz#:err_setstring", + &exc, &value, &value_length)) { + goto exit; + } + return_value = _testcapi_err_setstring_impl(module, exc, value, value_length); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_err_setfromerrnowithfilename__doc__, +"err_setfromerrnowithfilename($module, error, exc, value, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_ERR_SETFROMERRNOWITHFILENAME_METHODDEF \ + {"err_setfromerrnowithfilename", _PyCFunction_CAST(_testcapi_err_setfromerrnowithfilename), METH_FASTCALL, _testcapi_err_setfromerrnowithfilename__doc__}, + +static PyObject * +_testcapi_err_setfromerrnowithfilename_impl(PyObject *module, int error, + PyObject *exc, const char *value, + Py_ssize_t value_length); + +static PyObject * +_testcapi_err_setfromerrnowithfilename(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int error; + PyObject *exc; + const char *value; + Py_ssize_t value_length; + + if (!_PyArg_ParseStack(args, nargs, "iOz#:err_setfromerrnowithfilename", + &error, &exc, &value, &value_length)) { + goto exit; + } + return_value = _testcapi_err_setfromerrnowithfilename_impl(module, error, exc, value, value_length); + +exit: + return return_value; +} + PyDoc_STRVAR(_testcapi_raise_exception__doc__, "raise_exception($module, exception, num_args, /)\n" "--\n" @@ -426,4 +488,4 @@ _testcapi_unstable_exc_prep_reraise_star(PyObject *module, PyObject *const *args exit: return return_value; } -/*[clinic end generated code: output=fd6aef54f195c77b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d574342d716e98b5 input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index a627bf1717fe0c..4ae9ba4044df84 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -1,6 +1,9 @@ +#define PY_SSIZE_T_CLEAN #include "parts.h" #include "clinic/exceptions.c.h" +#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); + /*[clinic input] module _testcapi [clinic start generated code]*/ @@ -129,6 +132,43 @@ _testcapi_exc_set_object_fetch_impl(PyObject *module, PyObject *exc, return value; } +/*[clinic input] +_testcapi.err_setstring + exc: object + value: str(zeroes=True, accept={robuffer, str, NoneType}) + / +[clinic start generated code]*/ + +static PyObject * +_testcapi_err_setstring_impl(PyObject *module, PyObject *exc, + const char *value, Py_ssize_t value_length) +/*[clinic end generated code: output=fba8705e5703dd3f input=e8a95fad66d9004b]*/ +{ + NULLABLE(exc); + PyErr_SetString(exc, value); + return NULL; +} + +/*[clinic input] +_testcapi.err_setfromerrnowithfilename + error: int + exc: object + value: str(zeroes=True, accept={robuffer, str, NoneType}) + / +[clinic start generated code]*/ + +static PyObject * +_testcapi_err_setfromerrnowithfilename_impl(PyObject *module, int error, + PyObject *exc, const char *value, + Py_ssize_t value_length) +/*[clinic end generated code: output=d02df5749a01850e input=ff7c384234bf097f]*/ +{ + NULLABLE(exc); + errno = error; + PyErr_SetFromErrnoWithFilename(exc, value); + return NULL; +} + /*[clinic input] _testcapi.raise_exception exception as exc: object @@ -338,6 +378,8 @@ static PyMethodDef test_methods[] = { _TESTCAPI_MAKE_EXCEPTION_WITH_DOC_METHODDEF _TESTCAPI_EXC_SET_OBJECT_METHODDEF _TESTCAPI_EXC_SET_OBJECT_FETCH_METHODDEF + _TESTCAPI_ERR_SETSTRING_METHODDEF + _TESTCAPI_ERR_SETFROMERRNOWITHFILENAME_METHODDEF _TESTCAPI_RAISE_EXCEPTION_METHODDEF _TESTCAPI_RAISE_MEMORYERROR_METHODDEF _TESTCAPI_SET_EXC_INFO_METHODDEF diff --git a/Python/errors.c b/Python/errors.c index a8000ac94918db..f1d3007b9fdf8c 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -292,8 +292,10 @@ _PyErr_SetString(PyThreadState *tstate, PyObject *exception, const char *string) { PyObject *value = PyUnicode_FromString(string); - _PyErr_SetObject(tstate, exception, value); - Py_XDECREF(value); + if (value != NULL) { + _PyErr_SetObject(tstate, exception, value); + Py_DECREF(value); + } } void @@ -915,7 +917,13 @@ PyErr_SetFromErrnoWithFilenameObjects(PyObject *exc, PyObject *filenameObject, P PyObject * PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename) { - PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; + PyObject *name = NULL; + if (filename) { + name = PyUnicode_DecodeFSDefault(filename); + if (name == NULL) { + return NULL; + } + } PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, NULL); Py_XDECREF(name); return result; @@ -1012,7 +1020,13 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilename( int ierr, const char *filename) { - PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; + PyObject *name = NULL; + if (filename) { + name = PyUnicode_DecodeFSDefault(filename); + if (name == NULL) { + return NULL; + } + } PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObjects(exc, ierr, name, @@ -1036,7 +1050,13 @@ PyObject *PyErr_SetFromWindowsErrWithFilename( int ierr, const char *filename) { - PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; + PyObject *name = NULL; + if (filename) { + name = PyUnicode_DecodeFSDefault(filename); + if (name == NULL) { + return NULL; + } + } PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObjects( PyExc_OSError, ierr, name, NULL); @@ -1161,9 +1181,10 @@ _PyErr_FormatV(PyThreadState *tstate, PyObject *exception, _PyErr_Clear(tstate); string = PyUnicode_FromFormatV(format, vargs); - - _PyErr_SetObject(tstate, exception, string); - Py_XDECREF(string); + if (string != NULL) { + _PyErr_SetObject(tstate, exception, string); + Py_DECREF(string); + } return NULL; } From fa6cd7f43f3f8ce9b31051b30438549b2c6bc255 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 20 Aug 2023 23:08:16 +0200 Subject: [PATCH 0587/1206] [3.12] Docs: Fix Sphinx warnings in logging.rst (GH-108139) (#108174) (cherry picked from commit c735e79afb62324624864e1943f84825249f58ed) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- Doc/library/logging.rst | 38 ++++++++++++++++++++------------------ Doc/tools/.nitignore | 1 - 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index a92ef1787af744..edec0e0cdfa997 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -439,7 +439,7 @@ Handler Objects Handlers have the following attributes and methods. Note that :class:`Handler` is never instantiated directly; this class acts as a base for more useful -subclasses. However, the :meth:`__init__` method in subclasses needs to call +subclasses. However, the :meth:`!__init__` method in subclasses needs to call :meth:`Handler.__init__`. .. class:: Handler @@ -1015,23 +1015,25 @@ information into logging calls. For a usage example, see the section on 'extra'. The return value is a (*msg*, *kwargs*) tuple which has the (possibly modified) versions of the arguments passed in. -In addition to the above, :class:`LoggerAdapter` supports the following -methods of :class:`Logger`: :meth:`~Logger.debug`, :meth:`~Logger.info`, -:meth:`~Logger.warning`, :meth:`~Logger.error`, :meth:`~Logger.exception`, -:meth:`~Logger.critical`, :meth:`~Logger.log`, :meth:`~Logger.isEnabledFor`, -:meth:`~Logger.getEffectiveLevel`, :meth:`~Logger.setLevel` and -:meth:`~Logger.hasHandlers`. These methods have the same signatures as their -counterparts in :class:`Logger`, so you can use the two types of instances -interchangeably. + In addition to the above, :class:`LoggerAdapter` supports the following + methods of :class:`Logger`: :meth:`~Logger.debug`, :meth:`~Logger.info`, + :meth:`~Logger.warning`, :meth:`~Logger.error`, :meth:`~Logger.exception`, + :meth:`~Logger.critical`, :meth:`~Logger.log`, :meth:`~Logger.isEnabledFor`, + :meth:`~Logger.getEffectiveLevel`, :meth:`~Logger.setLevel` and + :meth:`~Logger.hasHandlers`. These methods have the same signatures as their + counterparts in :class:`Logger`, so you can use the two types of instances + interchangeably. -.. versionchanged:: 3.2 - The :meth:`~Logger.isEnabledFor`, :meth:`~Logger.getEffectiveLevel`, - :meth:`~Logger.setLevel` and :meth:`~Logger.hasHandlers` methods were added - to :class:`LoggerAdapter`. These methods delegate to the underlying logger. + .. versionchanged:: 3.2 + + The :meth:`~Logger.isEnabledFor`, :meth:`~Logger.getEffectiveLevel`, + :meth:`~Logger.setLevel` and :meth:`~Logger.hasHandlers` methods were added + to :class:`LoggerAdapter`. These methods delegate to the underlying logger. + + .. versionchanged:: 3.6 -.. versionchanged:: 3.6 - Attribute :attr:`manager` and method :meth:`_log` were added, which - delegate to the underlying logger and allow adapters to be nested. + Attribute :attr:`!manager` and method :meth:`!_log` were added, which + delegate to the underlying logger and allow adapters to be nested. Thread Safety @@ -1415,8 +1417,8 @@ functions. .. function:: setLoggerClass(klass) Tells the logging system to use the class *klass* when instantiating a logger. - The class should define :meth:`__init__` such that only a name argument is - required, and the :meth:`__init__` should call :meth:`Logger.__init__`. This + The class should define :meth:`!__init__` such that only a name argument is + required, and the :meth:`!__init__` should call :meth:`!Logger.__init__`. This function is typically called before any loggers are instantiated by applications which need to use custom logger behavior. After this call, as at any other time, do not instantiate loggers directly using the subclass: continue to use diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index a0a121b4b9dbe6..4dc8bd9ea70501 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -98,7 +98,6 @@ Doc/library/inspect.rst Doc/library/locale.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst -Doc/library/logging.rst Doc/library/lzma.rst Doc/library/mailbox.rst Doc/library/mmap.rst From 399825ed26e0a1873082348f911f34106fc72973 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 20 Aug 2023 23:08:39 +0200 Subject: [PATCH 0588/1206] [3.12] Docs: Fix Sphinx warnings in sys.rst (#108106) (#108178) (cherry picked from commit 29fa7afef94d74e18d97485c085d1ccf80c16ca3) - Mark up named tuple attributes as attributes - Remove links for external functions - io.BufferedIOBase has no 'buffer' attribute; remove the link and mark up using :attr:`!buffer` - (Re)format some tables as bullet lists: - sys._emscripten_info - sys.hash_info - sys.int_info - sys.thread_info - In the paragraphs mentioning 'f_trace_lines' and 'f_trace_opcodes', add links to the frame objects reference. Co-authored-by: Alex Waygood Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/sys.rst | 265 ++++++++++++++++++++++----------------- Doc/library/textwrap.rst | 2 +- Doc/tools/.nitignore | 1 - 3 files changed, 153 insertions(+), 115 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 334a2b077dd6fb..e7b34a83ebe9a7 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -333,23 +333,21 @@ always available. *wasm32-emscripten* platform. The named tuple is provisional and may change in the future. - .. tabularcolumns:: |l|L| - - +-----------------------------+----------------------------------------------+ - | Attribute | Explanation | - +=============================+==============================================+ - | :const:`emscripten_version` | Emscripten version as tuple of ints | - | | (major, minor, micro), e.g. ``(3, 1, 8)``. | - +-----------------------------+----------------------------------------------+ - | :const:`runtime` | Runtime string, e.g. browser user agent, | - | | ``'Node.js v14.18.2'``, or ``'UNKNOWN'``. | - +-----------------------------+----------------------------------------------+ - | :const:`pthreads` | ``True`` if Python is compiled with | - | | Emscripten pthreads support. | - +-----------------------------+----------------------------------------------+ - | :const:`shared_memory` | ``True`` if Python is compiled with shared | - | | memory support. | - +-----------------------------+----------------------------------------------+ + .. attribute:: _emscripten_info.emscripten_version + + Emscripten version as tuple of ints (major, minor, micro), e.g. ``(3, 1, 8)``. + + .. attribute:: _emscripten_info.runtime + + Runtime string, e.g. browser user agent, ``'Node.js v14.18.2'``, or ``'UNKNOWN'``. + + .. attribute:: _emscripten_info.pthreads + + ``True`` if Python is compiled with Emscripten pthreads support. + + .. attribute:: _emscripten_info.shared_memory + + ``True`` if Python is compiled with shared memory support. .. availability:: Emscripten. @@ -515,28 +513,62 @@ always available. The :term:`named tuple` *flags* exposes the status of command line flags. The attributes are read only. - ============================== ============================================================================================================== - attribute flag - ============================== ============================================================================================================== - :const:`debug` :option:`-d` - :const:`inspect` :option:`-i` - :const:`interactive` :option:`-i` - :const:`isolated` :option:`-I` - :const:`optimize` :option:`-O` or :option:`-OO` - :const:`dont_write_bytecode` :option:`-B` - :const:`no_user_site` :option:`-s` - :const:`no_site` :option:`-S` - :const:`ignore_environment` :option:`-E` - :const:`verbose` :option:`-v` - :const:`bytes_warning` :option:`-b` - :const:`quiet` :option:`-q` - :const:`hash_randomization` :option:`-R` - :const:`dev_mode` :option:`-X dev <-X>` (:ref:`Python Development Mode `) - :const:`utf8_mode` :option:`-X utf8 <-X>` - :const:`safe_path` :option:`-P` - :const:`int_max_str_digits` :option:`-X int_max_str_digits <-X>` (:ref:`integer string conversion length limitation `) - :const:`warn_default_encoding` :option:`-X warn_default_encoding <-X>` - ============================== ============================================================================================================== + .. list-table:: + + * - .. attribute:: flags.debug + - :option:`-d` + + * - .. attribute:: flags.inspect + - :option:`-i` + + * - .. attribute:: flags.interactive + - :option:`-i` + + * - .. attribute:: flags.isolated + - :option:`-I` + + * - .. attribute:: flags.optimize + - :option:`-O` or :option:`-OO` + + * - .. attribute:: flags.dont_write_bytecode + - :option:`-B` + + * - .. attribute:: flags.no_user_site + - :option:`-s` + + * - .. attribute:: flags.no_site + - :option:`-S` + + * - .. attribute:: flags.ignore_environment + - :option:`-E` + + * - .. attribute:: flags.verbose + - :option:`-v` + + * - .. attribute:: flags.bytes_warning + - :option:`-b` + + * - .. attribute:: flags.quiet + - :option:`-q` + + * - .. attribute:: flags.hash_randomization + - :option:`-R` + + * - .. attribute:: flags.dev_mode + - :option:`-X dev <-X>` (:ref:`Python Development Mode `) + + * - .. attribute:: flags.utf8_mode + - :option:`-X utf8 <-X>` + + * - .. attribute:: flags.safe_path + - :option:`-P` + + * - .. attribute:: flags.int_max_str_digits + - :option:`-X int_max_str_digits <-X>` + (:ref:`integer string conversion length limitation `) + + * - .. attribute:: flags.warn_default_encoding + - :option:`-X warn_default_encoding <-X>` .. versionchanged:: 3.2 Added ``quiet`` attribute for the new :option:`-q` flag. @@ -923,8 +955,8 @@ always available. | | a domain controller. | +---------------------------------------+---------------------------------+ - This function wraps the Win32 :c:func:`GetVersionEx` function; see the - Microsoft documentation on :c:func:`OSVERSIONINFOEX` for more information + This function wraps the Win32 :c:func:`!GetVersionEx` function; see the + Microsoft documentation on :c:func:`!OSVERSIONINFOEX` for more information about these fields. *platform_version* returns the major version, minor version and @@ -982,28 +1014,37 @@ always available. implementation. For more details about hashing of numeric types, see :ref:`numeric-hash`. - +---------------------+--------------------------------------------------+ - | attribute | explanation | - +=====================+==================================================+ - | :const:`width` | width in bits used for hash values | - +---------------------+--------------------------------------------------+ - | :const:`modulus` | prime modulus P used for numeric hash scheme | - +---------------------+--------------------------------------------------+ - | :const:`inf` | hash value returned for a positive infinity | - +---------------------+--------------------------------------------------+ - | :const:`nan` | (this attribute is no longer used) | - +---------------------+--------------------------------------------------+ - | :const:`imag` | multiplier used for the imaginary part of a | - | | complex number | - +---------------------+--------------------------------------------------+ - | :const:`algorithm` | name of the algorithm for hashing of str, bytes, | - | | and memoryview | - +---------------------+--------------------------------------------------+ - | :const:`hash_bits` | internal output size of the hash algorithm | - +---------------------+--------------------------------------------------+ - | :const:`seed_bits` | size of the seed key of the hash algorithm | - +---------------------+--------------------------------------------------+ + .. attribute:: hash_info.width + + The width in bits used for hash values + + .. attribute:: hash_info.modulus + The prime modulus P used for numeric hash scheme + + .. attribute:: hash_info.inf + + The hash value returned for a positive infinity + + .. attribute:: hash_info.nan + + (This attribute is no longer used) + + .. attribute:: hash_info.imag + + The multiplier used for the imaginary part of a complex number + + .. attribute:: hash_info.algorithm + + The name of the algorithm for hashing of str, bytes, and memoryview + + .. attribute:: hash_info.hash_bits + + The internal output size of the hash algorithm + + .. attribute:: hash_info.seed_bits + + The size of the seed key of the hash algorithm .. versionadded:: 3.2 @@ -1081,32 +1122,31 @@ always available. A :term:`named tuple` that holds information about Python's internal representation of integers. The attributes are read only. - .. tabularcolumns:: |l|L| - - +----------------------------------------+-----------------------------------------------+ - | Attribute | Explanation | - +========================================+===============================================+ - | :const:`bits_per_digit` | number of bits held in each digit. Python | - | | integers are stored internally in base | - | | ``2**int_info.bits_per_digit`` | - +----------------------------------------+-----------------------------------------------+ - | :const:`sizeof_digit` | size in bytes of the C type used to | - | | represent a digit | - +----------------------------------------+-----------------------------------------------+ - | :const:`default_max_str_digits` | default value for | - | | :func:`sys.get_int_max_str_digits` when it | - | | is not otherwise explicitly configured. | - +----------------------------------------+-----------------------------------------------+ - | :const:`str_digits_check_threshold` | minimum non-zero value for | - | | :func:`sys.set_int_max_str_digits`, | - | | :envvar:`PYTHONINTMAXSTRDIGITS`, or | - | | :option:`-X int_max_str_digits <-X>`. | - +----------------------------------------+-----------------------------------------------+ + .. attribute:: int_info.bits_per_digit + + The number of bits held in each digit. + Python integers are stored internally in base ``2**int_info.bits_per_digit``. + + .. attribute:: int_info.sizeof_digit + + The size in bytes of the C type used to represent a digit. + + .. attribute:: int_info.default_max_str_digits + + The default value for :func:`sys.get_int_max_str_digits` + when it is not otherwise explicitly configured. + + .. attribute:: int_info.str_digits_check_threshold + + The minimum non-zero value for :func:`sys.set_int_max_str_digits`, + :envvar:`PYTHONINTMAXSTRDIGITS`, or :option:`-X int_max_str_digits <-X>`. .. versionadded:: 3.1 .. versionchanged:: 3.11 - Added ``default_max_str_digits`` and ``str_digits_check_threshold``. + + Added :attr:`~int_info.default_max_str_digits` and + :attr:`~int_info.str_digits_check_threshold`. .. data:: __interactivehook__ @@ -1533,7 +1573,7 @@ always available. :file:`Objects/lnotab_notes.txt` for a detailed explanation of how this works. Per-line events may be disabled for a frame by setting - :attr:`f_trace_lines` to :const:`False` on that frame. + :attr:`!f_trace_lines` to :const:`False` on that :ref:`frame `. ``'return'`` A function (or other code block) is about to return. The local trace @@ -1551,8 +1591,8 @@ always available. opcode details). The local trace function is called; *arg* is ``None``; the return value specifies the new local trace function. Per-opcode events are not emitted by default: they must be explicitly - requested by setting :attr:`f_trace_opcodes` to :const:`True` on the - frame. + requested by setting :attr:`!f_trace_opcodes` to :const:`True` on the + :ref:`frame `. Note that as an exception is propagated down the chain of callers, an ``'exception'`` event is generated at each level. @@ -1581,8 +1621,8 @@ always available. .. versionchanged:: 3.7 - ``'opcode'`` event type added; :attr:`f_trace_lines` and - :attr:`f_trace_opcodes` attributes added to frames + ``'opcode'`` event type added; :attr:`!f_trace_lines` and + :attr:`!f_trace_opcodes` attributes added to frames .. function:: set_asyncgen_hooks(firstiter, finalizer) @@ -1739,7 +1779,7 @@ always available. However, if you are writing a library (and do not control in which context its code will be executed), be aware that the standard streams may be replaced with file-like objects like :class:`io.StringIO` which - do not support the :attr:`~io.BufferedIOBase.buffer` attribute. + do not support the :attr:!buffer` attribute. .. data:: __stdin__ @@ -1787,29 +1827,28 @@ always available. A :term:`named tuple` holding information about the thread implementation. - .. tabularcolumns:: |l|p{0.7\linewidth}| - - +------------------+---------------------------------------------------------+ - | Attribute | Explanation | - +==================+=========================================================+ - | :const:`name` | Name of the thread implementation: | - | | | - | | * ``'nt'``: Windows threads | - | | * ``'pthread'``: POSIX threads | - | | * ``'pthread-stubs'``: stub POSIX threads | - | | (on WebAssembly platforms without threading support) | - | | * ``'solaris'``: Solaris threads | - +------------------+---------------------------------------------------------+ - | :const:`lock` | Name of the lock implementation: | - | | | - | | * ``'semaphore'``: a lock uses a semaphore | - | | * ``'mutex+cond'``: a lock uses a mutex | - | | and a condition variable | - | | * ``None`` if this information is unknown | - +------------------+---------------------------------------------------------+ - | :const:`version` | Name and version of the thread library. It is a string, | - | | or ``None`` if this information is unknown. | - +------------------+---------------------------------------------------------+ + .. attribute:: thread_info.name + + The name of the thread implementation: + + * ``"nt"``: Windows threads + * ``"pthread"``: POSIX threads + * ``"pthread-stubs"``: stub POSIX threads + (on WebAssembly platforms without threading support) + * ``"solaris"``: Solaris threads + + .. attribute:: thread_info.lock + + The name of the lock implementation: + + * ``"semaphore"``: a lock uses a semaphore + * ``"mutex+cond"``: a lock uses a mutex and a condition variable + * ``None`` if this information is unknown + + .. attribute:: thread_info.version + + The name and version of the thread library. + It is a string, or ``None`` if this information is unknown. .. versionadded:: 3.3 diff --git a/Doc/library/textwrap.rst b/Doc/library/textwrap.rst index a150eefbf932ef..e2952ce3cc2ca3 100644 --- a/Doc/library/textwrap.rst +++ b/Doc/library/textwrap.rst @@ -60,7 +60,7 @@ functions should be good enough; otherwise, you should use an instance of First the whitespace in *text* is collapsed (all whitespace is replaced by single spaces). If the result fits in the *width*, it is returned. Otherwise, enough words are dropped from the end so that the remaining words - plus the :attr:`.placeholder` fit within :attr:`.width`:: + plus the *placeholder* fit within *width*:: >>> textwrap.shorten("Hello world!", width=12) 'Hello world!' diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 4dc8bd9ea70501..ba976bc50cf201 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -136,7 +136,6 @@ Doc/library/stdtypes.rst Doc/library/string.rst Doc/library/subprocess.rst Doc/library/sunau.rst -Doc/library/sys.rst Doc/library/sys_path_init.rst Doc/library/syslog.rst Doc/library/tarfile.rst From a6f15af866c4584b970c72b805a2a4a6f3f63b83 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 14:08:57 -0700 Subject: [PATCH 0589/1206] [3.12] Resolve reference warnings in faq/design.rst (GH-108148) (#108180) Resolve reference warnings in faq/design.rst (GH-108148) (cherry picked from commit 92815cc7cf3df8ab702c7cea4efaef349a4b0480) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/faq/design.rst | 4 ++-- Doc/tools/.nitignore | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 11d01374dc1e79..ae02c443e5938b 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -584,9 +584,9 @@ exhaustive test suites that exercise every line of code in a module. An appropriate testing discipline can help build large complex applications in Python as well as having interface specifications would. In fact, it can be better because an interface specification cannot test certain properties of a -program. For example, the :meth:`list.append` method is expected to add new elements +program. For example, the :meth:`!list.append` method is expected to add new elements to the end of some internal list; an interface specification cannot test that -your :meth:`list.append` implementation will actually do this correctly, but it's +your :meth:`!list.append` implementation will actually do this correctly, but it's trivial to check this property in a test suite. Writing test suites is very helpful, and you might want to design your code to diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index ba976bc50cf201..5a28274cff6c4f 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -25,7 +25,6 @@ Doc/c-api/typeobj.rst Doc/c-api/unicode.rst Doc/extending/extending.rst Doc/extending/newtypes.rst -Doc/faq/design.rst Doc/faq/gui.rst Doc/faq/library.rst Doc/glossary.rst From f2cc00527efeb69497e4304e826dd3a518005d1a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 20 Aug 2023 14:09:18 -0700 Subject: [PATCH 0590/1206] [3.12] Resolve reference warnings in faq/library.rst (GH-108149) (#108182) Resolve reference warnings in faq/library.rst (GH-108149) (cherry picked from commit 6323bc33ff9f445a947adf4af42b8be7e44c730c) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Erlend E. Aasland Co-authored-by: Hugo van Kemenade --- Doc/faq/library.rst | 13 ++++++++----- Doc/tools/.nitignore | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index b43c7505c0401c..c69910718f0c92 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -111,7 +111,7 @@ Is there an equivalent to C's onexit() in Python? ------------------------------------------------- The :mod:`atexit` module provides a register function that is similar to C's -:c:func:`onexit`. +:c:func:`!onexit`. Why don't my signal handlers work? @@ -397,7 +397,7 @@ These aren't:: D[x] = D[x] + 1 Operations that replace other objects may invoke those other objects' -:meth:`__del__` method when their reference count reaches zero, and that can +:meth:`~object.__del__` method when their reference count reaches zero, and that can affect things. This is especially true for the mass updates to dictionaries and lists. When in doubt, use a mutex! @@ -765,14 +765,17 @@ The :mod:`select` module is commonly used to help with asynchronous I/O on sockets. To prevent the TCP connect from blocking, you can set the socket to non-blocking -mode. Then when you do the :meth:`socket.connect`, you will either connect immediately +mode. Then when you do the :meth:`~socket.socket.connect`, +you will either connect immediately (unlikely) or get an exception that contains the error number as ``.errno``. ``errno.EINPROGRESS`` indicates that the connection is in progress, but hasn't finished yet. Different OSes will return different values, so you're going to have to check what's returned on your system. -You can use the :meth:`socket.connect_ex` method to avoid creating an exception. It will -just return the errno value. To poll, you can call :meth:`socket.connect_ex` again later +You can use the :meth:`~socket.socket.connect_ex` method +to avoid creating an exception. +It will just return the errno value. +To poll, you can call :meth:`~socket.socket.connect_ex` again later -- ``0`` or ``errno.EISCONN`` indicate that you're connected -- or you can pass this socket to :meth:`select.select` to check if it's writable. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 5a28274cff6c4f..b1894c4d3df370 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -26,7 +26,6 @@ Doc/c-api/unicode.rst Doc/extending/extending.rst Doc/extending/newtypes.rst Doc/faq/gui.rst -Doc/faq/library.rst Doc/glossary.rst Doc/howto/descriptor.rst Doc/howto/enum.rst From 9cd15cab772e9e6073b3074ab6ef85db83a0e40c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 04:16:53 -0700 Subject: [PATCH 0591/1206] [3.12] Docs: document 'manager' and '_log' attrs of logging.Logging (GH-108145) (#108190) Docs: document 'manager' and '_log' attrs of logging.Logging (GH-108145) (cherry picked from commit f904aa4e1f6943e5bd9a8a73cf762f063e6fa247) Authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- Doc/library/logging.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index edec0e0cdfa997..d369c53f0f919c 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -1015,6 +1015,14 @@ information into logging calls. For a usage example, see the section on 'extra'. The return value is a (*msg*, *kwargs*) tuple which has the (possibly modified) versions of the arguments passed in. + .. attribute:: manager + + Delegates to the underlying :attr:`!manager`` on *logger*. + + .. attribute:: _log + + Delegates to the underlying :meth:`!_log`` method on *logger*. + In addition to the above, :class:`LoggerAdapter` supports the following methods of :class:`Logger`: :meth:`~Logger.debug`, :meth:`~Logger.info`, :meth:`~Logger.warning`, :meth:`~Logger.error`, :meth:`~Logger.exception`, From 639ffd5aa0fcc1a66cb99ce2afa31a93e7e5f7b4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 04:18:04 -0700 Subject: [PATCH 0592/1206] [3.12] gh-107895: Fix test_asyncio.test_runners when run it in CPython's "development mode" (GH-108168) (#108196) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-107895: Fix test_asyncio.test_runners when run it in CPython's "development mode" (GH-108168) (cherry picked from commit 014a5b71e7538926ae1c03c8c5ea13c96e741be3) Co-authored-by: Joon Hwan 김준환 --- Lib/test/test_asyncio/test_runners.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_asyncio/test_runners.py b/Lib/test/test_asyncio/test_runners.py index 811cf8b72488b8..0a1ad070c0c1ff 100644 --- a/Lib/test/test_asyncio/test_runners.py +++ b/Lib/test/test_asyncio/test_runners.py @@ -101,11 +101,14 @@ async def main(expected): loop = asyncio.get_event_loop() self.assertIs(loop.get_debug(), expected) - asyncio.run(main(False)) + asyncio.run(main(False), debug=False) asyncio.run(main(True), debug=True) with mock.patch('asyncio.coroutines._is_debug_mode', lambda: True): asyncio.run(main(True)) asyncio.run(main(False), debug=False) + with mock.patch('asyncio.coroutines._is_debug_mode', lambda: False): + asyncio.run(main(True), debug=True) + asyncio.run(main(False)) def test_asyncio_run_from_running_loop(self): async def main(): From f798a6360b038a3fc47509101eb77bcc1c9b6662 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 04:20:21 -0700 Subject: [PATCH 0593/1206] [3.12] Improve references in the tutorial (GH-108069) (#108203) Improve references in the tutorial (GH-108069) * Use full qualified names for references (even if they do not work now, they will work in future). * Silence references to examples. (cherry picked from commit 622ddc41674c2566062af82f7b079aa01d2aae8c) Co-authored-by: Serhiy Storchaka --- Doc/tools/.nitignore | 2 -- Doc/tutorial/classes.rst | 43 +++++++++++++++++---------------- Doc/tutorial/controlflow.rst | 2 +- Doc/tutorial/datastructures.rst | 12 ++++----- Doc/tutorial/inputoutput.rst | 8 +++--- Doc/tutorial/modules.rst | 30 +++++++++++------------ 6 files changed, 48 insertions(+), 49 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index b1894c4d3df370..ada46064e358e2 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -180,9 +180,7 @@ Doc/tutorial/appendix.rst Doc/tutorial/classes.rst Doc/tutorial/controlflow.rst Doc/tutorial/datastructures.rst -Doc/tutorial/inputoutput.rst Doc/tutorial/introduction.rst -Doc/tutorial/modules.rst Doc/using/cmdline.rst Doc/using/configure.rst Doc/using/windows.rst diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index 06445e000c1ef6..91a3b73d2b55aa 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -91,7 +91,7 @@ Attributes may be read-only or writable. In the latter case, assignment to attributes is possible. Module attributes are writable: you can write ``modname.the_answer = 42``. Writable attributes may also be deleted with the :keyword:`del` statement. For example, ``del modname.the_answer`` will remove -the attribute :attr:`the_answer` from the object named by ``modname``. +the attribute :attr:`!the_answer` from the object named by ``modname``. Namespaces are created at different moments and have different lifetimes. The namespace containing the built-in names is created when the Python interpreter @@ -249,7 +249,7 @@ created. This is basically a wrapper around the contents of the namespace created by the class definition; we'll learn more about class objects in the next section. The original local scope (the one in effect just before the class definition was entered) is reinstated, and the class object is bound here to the -class name given in the class definition header (:class:`ClassName` in the +class name given in the class definition header (:class:`!ClassName` in the example). @@ -291,20 +291,20 @@ variable ``x``. The instantiation operation ("calling" a class object) creates an empty object. Many classes like to create objects with instances customized to a specific initial state. Therefore a class may define a special method named -:meth:`__init__`, like this:: +:meth:`~object.__init__`, like this:: def __init__(self): self.data = [] -When a class defines an :meth:`__init__` method, class instantiation -automatically invokes :meth:`__init__` for the newly created class instance. So +When a class defines an :meth:`~object.__init__` method, class instantiation +automatically invokes :meth:`!__init__` for the newly created class instance. So in this example, a new, initialized instance can be obtained by:: x = MyClass() -Of course, the :meth:`__init__` method may have arguments for greater +Of course, the :meth:`~object.__init__` method may have arguments for greater flexibility. In that case, arguments given to the class instantiation operator -are passed on to :meth:`__init__`. For example, :: +are passed on to :meth:`!__init__`. For example, :: >>> class Complex: ... def __init__(self, realpart, imagpart): @@ -328,7 +328,7 @@ attribute names: data attributes and methods. *data attributes* correspond to "instance variables" in Smalltalk, and to "data members" in C++. Data attributes need not be declared; like local variables, they spring into existence when they are first assigned to. For example, if -``x`` is the instance of :class:`MyClass` created above, the following piece of +``x`` is the instance of :class:`!MyClass` created above, the following piece of code will print the value ``16``, without leaving a trace:: x.counter = 1 @@ -363,7 +363,7 @@ Usually, a method is called right after it is bound:: x.f() -In the :class:`MyClass` example, this will return the string ``'hello world'``. +In the :class:`!MyClass` example, this will return the string ``'hello world'``. However, it is not necessary to call a method right away: ``x.f`` is a method object, and can be stored away and called at a later time. For example:: @@ -375,7 +375,7 @@ will continue to print ``hello world`` until the end of time. What exactly happens when a method is called? You may have noticed that ``x.f()`` was called without an argument above, even though the function -definition for :meth:`f` specified an argument. What happened to the argument? +definition for :meth:`!f` specified an argument. What happened to the argument? Surely Python raises an exception when a function that requires an argument is called without any --- even if the argument isn't actually used... @@ -532,9 +532,9 @@ variable in the class is also ok. For example:: h = g -Now ``f``, ``g`` and ``h`` are all attributes of class :class:`C` that refer to +Now ``f``, ``g`` and ``h`` are all attributes of class :class:`!C` that refer to function objects, and consequently they are all methods of instances of -:class:`C` --- ``h`` being exactly equivalent to ``g``. Note that this practice +:class:`!C` --- ``h`` being exactly equivalent to ``g``. Note that this practice usually only serves to confuse the reader of a program. Methods may call other methods by using method attributes of the ``self`` @@ -581,7 +581,7 @@ this:: . -The name :class:`BaseClassName` must be defined in a +The name :class:`!BaseClassName` must be defined in a namespace accessible from the scope containing the derived class definition. In place of a base class name, other arbitrary expressions are also allowed. This can be useful, for example, when the base @@ -645,9 +645,9 @@ multiple base classes looks like this:: For most purposes, in the simplest cases, you can think of the search for attributes inherited from a parent class as depth-first, left-to-right, not searching twice in the same class where there is an overlap in the hierarchy. -Thus, if an attribute is not found in :class:`DerivedClassName`, it is searched -for in :class:`Base1`, then (recursively) in the base classes of :class:`Base1`, -and if it was not found there, it was searched for in :class:`Base2`, and so on. +Thus, if an attribute is not found in :class:`!DerivedClassName`, it is searched +for in :class:`!Base1`, then (recursively) in the base classes of :class:`!Base1`, +and if it was not found there, it was searched for in :class:`!Base2`, and so on. In fact, it is slightly more complex than that; the method resolution order changes dynamically to support cooperative calls to :func:`super`. This @@ -760,7 +760,8 @@ is to use :mod:`dataclasses` for this purpose:: A piece of Python code that expects a particular abstract data type can often be passed a class that emulates the methods of that data type instead. For instance, if you have a function that formats some data from a file object, you -can define a class with methods :meth:`read` and :meth:`!readline` that get the +can define a class with methods :meth:`~io.TextIOBase.read` and +:meth:`~io.TextIOBase.readline` that get the data from a string buffer instead, and pass it as an argument. .. (Unfortunately, this technique has its limitations: a class can't define @@ -769,7 +770,7 @@ data from a string buffer instead, and pass it as an argument. not cause the interpreter to read further input from it.) Instance method objects have attributes, too: ``m.__self__`` is the instance -object with the method :meth:`m`, and ``m.__func__`` is the function object +object with the method :meth:`!m`, and ``m.__func__`` is the function object corresponding to the method. @@ -818,9 +819,9 @@ using the :func:`next` built-in function; this example shows how it all works:: StopIteration Having seen the mechanics behind the iterator protocol, it is easy to add -iterator behavior to your classes. Define an :meth:`__iter__` method which +iterator behavior to your classes. Define an :meth:`~container.__iter__` method which returns an object with a :meth:`~iterator.__next__` method. If the class -defines :meth:`__next__`, then :meth:`__iter__` can just return ``self``:: +defines :meth:`!__next__`, then :meth:`!__iter__` can just return ``self``:: class Reverse: """Iterator for looping over a sequence backwards.""" @@ -879,7 +880,7 @@ easy to create:: Anything that can be done with generators can also be done with class-based iterators as described in the previous section. What makes generators so -compact is that the :meth:`__iter__` and :meth:`~generator.__next__` methods +compact is that the :meth:`~iterator.__iter__` and :meth:`~generator.__next__` methods are created automatically. Another key feature is that the local variables and execution state are diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 138d87f892e891..4bcc3768111ccd 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -534,7 +534,7 @@ This example, as usual, demonstrates some new Python features: Different types define different methods. Methods of different types may have the same name without causing ambiguity. (It is possible to define your own object types and methods, using *classes*, see :ref:`tut-classes`) - The method :meth:`append` shown in the example is defined for list objects; it + The method :meth:`~list.append` shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent to ``result = result + [a]``, but more efficient. diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index c8e89d9b79bddd..87614d082a1d4e 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -143,8 +143,8 @@ Using Lists as Stacks The list methods make it very easy to use a list as a stack, where the last element added is the first element retrieved ("last-in, first-out"). To add an -item to the top of the stack, use :meth:`append`. To retrieve an item from the -top of the stack, use :meth:`pop` without an explicit index. For example:: +item to the top of the stack, use :meth:`~list.append`. To retrieve an item from the +top of the stack, use :meth:`~list.pop` without an explicit index. For example:: >>> stack = [3, 4, 5] >>> stack.append(6) @@ -341,7 +341,7 @@ The :keyword:`!del` statement ============================= There is a way to remove an item from a list given its index instead of its -value: the :keyword:`del` statement. This differs from the :meth:`pop` method +value: the :keyword:`del` statement. This differs from the :meth:`~list.pop` method which returns a value. The :keyword:`!del` statement can also be used to remove slices from a list or clear the entire list (which we did earlier by assignment of an empty list to the slice). For example:: @@ -501,8 +501,8 @@ any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can't use lists as keys, since lists can be modified in place using index -assignments, slice assignments, or methods like :meth:`append` and -:meth:`extend`. +assignments, slice assignments, or methods like :meth:`~list.append` and +:meth:`~list.extend`. It is best to think of a dictionary as a set of *key: value* pairs, with the requirement that the keys are unique (within one dictionary). A pair of @@ -567,7 +567,7 @@ Looping Techniques ================== When looping through dictionaries, the key and corresponding value can be -retrieved at the same time using the :meth:`items` method. :: +retrieved at the same time using the :meth:`~dict.items` method. :: >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'} >>> for k, v in knights.items(): diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index f5cdd84cbadefe..fe9ca9ccb9c7e0 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -15,7 +15,7 @@ Fancier Output Formatting ========================= So far we've encountered two ways of writing values: *expression statements* and -the :func:`print` function. (A third way is using the :meth:`write` method +the :func:`print` function. (A third way is using the :meth:`~io.TextIOBase.write` method of file objects; the standard output file can be referenced as ``sys.stdout``. See the Library Reference for more information on this.) @@ -456,8 +456,8 @@ to the very file end with ``seek(0, 2)``) and the only valid *offset* values are those returned from the ``f.tell()``, or zero. Any other *offset* value produces undefined behaviour. -File objects have some additional methods, such as :meth:`~file.isatty` and -:meth:`~file.truncate` which are less frequently used; consult the Library +File objects have some additional methods, such as :meth:`~io.IOBase.isatty` and +:meth:`~io.IOBase.truncate` which are less frequently used; consult the Library Reference for a complete guide to file objects. @@ -469,7 +469,7 @@ Saving structured data with :mod:`json` .. index:: pair: module; json Strings can easily be written to and read from a file. Numbers take a bit more -effort, since the :meth:`read` method only returns strings, which will have to +effort, since the :meth:`~io.TextIOBase.read` method only returns strings, which will have to be passed to a function like :func:`int`, which takes a string like ``'123'`` and returns its numeric value 123. When you want to save more complex data types like nested lists and dictionaries, parsing and serializing by hand diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index 734dd1cfe6871a..bf9e8e0b7b8066 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -183,7 +183,7 @@ The Module Search Path .. index:: triple: module; search; path -When a module named :mod:`spam` is imported, the interpreter first searches for +When a module named :mod:`!spam` is imported, the interpreter first searches for a built-in module with that name. These module names are listed in :data:`sys.builtin_module_names`. If not found, it then searches for a file named :file:`spam.py` in a list of directories given by the variable @@ -389,7 +389,7 @@ Packages ======== Packages are a way of structuring Python's module namespace by using "dotted -module names". For example, the module name :mod:`A.B` designates a submodule +module names". For example, the module name :mod:`!A.B` designates a submodule named ``B`` in a package named ``A``. Just like the use of modules saves the authors of different modules from having to worry about each other's global variable names, the use of dotted module names saves the authors of multi-module @@ -448,7 +448,7 @@ example:: import sound.effects.echo -This loads the submodule :mod:`sound.effects.echo`. It must be referenced with +This loads the submodule :mod:`!sound.effects.echo`. It must be referenced with its full name. :: sound.effects.echo.echofilter(input, output, delay=0.7, atten=4) @@ -457,7 +457,7 @@ An alternative way of importing the submodule is:: from sound.effects import echo -This also loads the submodule :mod:`echo`, and makes it available without its +This also loads the submodule :mod:`!echo`, and makes it available without its package prefix, so it can be used as follows:: echo.echofilter(input, output, delay=0.7, atten=4) @@ -466,8 +466,8 @@ Yet another variation is to import the desired function or variable directly:: from sound.effects.echo import echofilter -Again, this loads the submodule :mod:`echo`, but this makes its function -:func:`echofilter` directly available:: +Again, this loads the submodule :mod:`!echo`, but this makes its function +:func:`!echofilter` directly available:: echofilter(input, output, delay=0.7, atten=4) @@ -510,7 +510,7 @@ code:: __all__ = ["echo", "surround", "reverse"] This would mean that ``from sound.effects import *`` would import the three -named submodules of the :mod:`sound.effects` package. +named submodules of the :mod:`!sound.effects` package. Be aware that submodules might become shadowed by locally defined names. For example, if you added a ``reverse`` function to the @@ -529,8 +529,8 @@ would only import the two submodules ``echo`` and ``surround``, but *not* the return msg[::-1] # in the case of a 'from sound.effects import *' If ``__all__`` is not defined, the statement ``from sound.effects import *`` -does *not* import all submodules from the package :mod:`sound.effects` into the -current namespace; it only ensures that the package :mod:`sound.effects` has +does *not* import all submodules from the package :mod:`!sound.effects` into the +current namespace; it only ensures that the package :mod:`!sound.effects` has been imported (possibly running any initialization code in :file:`__init__.py`) and then imports whatever names are defined in the package. This includes any names defined (and submodules explicitly loaded) by :file:`__init__.py`. It @@ -541,8 +541,8 @@ previous :keyword:`import` statements. Consider this code:: import sound.effects.surround from sound.effects import * -In this example, the :mod:`echo` and :mod:`surround` modules are imported in the -current namespace because they are defined in the :mod:`sound.effects` package +In this example, the :mod:`!echo` and :mod:`!surround` modules are imported in the +current namespace because they are defined in the :mod:`!sound.effects` package when the ``from...import`` statement is executed. (This also works when ``__all__`` is defined.) @@ -561,15 +561,15 @@ packages. Intra-package References ------------------------ -When packages are structured into subpackages (as with the :mod:`sound` package +When packages are structured into subpackages (as with the :mod:`!sound` package in the example), you can use absolute imports to refer to submodules of siblings -packages. For example, if the module :mod:`sound.filters.vocoder` needs to use -the :mod:`echo` module in the :mod:`sound.effects` package, it can use ``from +packages. For example, if the module :mod:`!sound.filters.vocoder` needs to use +the :mod:`!echo` module in the :mod:`!sound.effects` package, it can use ``from sound.effects import echo``. You can also write relative imports, with the ``from module import name`` form of import statement. These imports use leading dots to indicate the current and -parent packages involved in the relative import. From the :mod:`surround` +parent packages involved in the relative import. From the :mod:`!surround` module for example, you might use:: from . import echo From 1ce8b92ce92e9a44ac804ea4e4c61d08d7e89a2e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 05:31:11 -0700 Subject: [PATCH 0594/1206] [3.12] gh-105736: Sync pure python version of OrderedDict with the C version (GH-108098) (#108200) gh-105736: Sync pure python version of OrderedDict with the C version (GH-108098) (cherry picked from commit 20cc90c0df3e368fe7cb63d958f0b17a78fa9d0a) Co-authored-by: Raymond Hettinger --- Lib/collections/__init__.py | 16 +++++++++------- Lib/test/test_ordered_dict.py | 11 +++++++++++ ...023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst | 3 +++ 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index 03ca2d7e18f6f0..8652dc8a4ec450 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -95,17 +95,19 @@ class OrderedDict(dict): # Individual links are kept alive by the hard reference in self.__map. # Those hard references disappear when a key is deleted from an OrderedDict. + def __new__(cls, /, *args, **kwds): + "Create the ordered dict object and set up the underlying structures." + self = dict.__new__(cls) + self.__hardroot = _Link() + self.__root = root = _proxy(self.__hardroot) + root.prev = root.next = root + self.__map = {} + return self + def __init__(self, other=(), /, **kwds): '''Initialize an ordered dictionary. The signature is the same as regular dictionaries. Keyword argument order is preserved. ''' - try: - self.__root - except AttributeError: - self.__hardroot = _Link() - self.__root = root = _proxy(self.__hardroot) - root.prev = root.next = root - self.__map = {} self.__update(other, **kwds) def __setitem__(self, key, value, diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index decbcc2419c9fc..4571b23dfe7c1a 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -122,6 +122,17 @@ def items(self): self.OrderedDict(Spam()) self.assertEqual(calls, ['keys']) + def test_overridden_init(self): + # Sync-up pure Python OD class with C class where + # a consistent internal state is created in __new__ + # rather than __init__. + OrderedDict = self.OrderedDict + class ODNI(OrderedDict): + def __init__(*args, **kwargs): + pass + od = ODNI() + od['a'] = 1 # This used to fail because __init__ was bypassed + def test_fromkeys(self): OrderedDict = self.OrderedDict od = OrderedDict.fromkeys('abc') diff --git a/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst b/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst new file mode 100644 index 00000000000000..f051317d141ff5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst @@ -0,0 +1,3 @@ +Harmonized the pure Python version of OrderedDict with the C version. Now, +both versions set up their internal state in `__new__`. Formerly, the pure +Python version did the set up in `__init__`. From 238c8d236bca2fab43453d09af69eba2bab1fcb0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 05:33:46 -0700 Subject: [PATCH 0595/1206] [3.12] gh-107916: Save the error code before decoding the filename in PyErr_SetFromErrnoWithFilename() etc (GH-107929) (#108205) gh-107916: Save the error code before decoding the filename in PyErr_SetFromErrnoWithFilename() etc (GH-107929) (cherry picked from commit 80bdebdd8593f007a2232ec04a7729bba6ebf12c) Co-authored-by: Serhiy Storchaka --- .../C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst | 4 ++++ Python/errors.c | 8 ++++++++ 2 files changed, 12 insertions(+) create mode 100644 Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst diff --git a/Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst b/Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst new file mode 100644 index 00000000000000..f1f16609b118ba --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst @@ -0,0 +1,4 @@ +C API functions :c:func:`PyErr_SetFromErrnoWithFilename`, +:c:func:`PyErr_SetExcFromWindowsErrWithFilename` and +:c:func:`PyErr_SetFromWindowsErrWithFilename` save now the error code before +calling :c:func:`PyUnicode_DecodeFSDefault`. diff --git a/Python/errors.c b/Python/errors.c index f1d3007b9fdf8c..6c46d1f2136654 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -919,10 +919,12 @@ PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename) { PyObject *name = NULL; if (filename) { + int i = errno; name = PyUnicode_DecodeFSDefault(filename); if (name == NULL) { return NULL; } + errno = i; } PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, NULL); Py_XDECREF(name); @@ -1022,6 +1024,9 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilename( { PyObject *name = NULL; if (filename) { + if ((DWORD)ierr == 0) { + ierr = (int)GetLastError(); + } name = PyUnicode_DecodeFSDefault(filename); if (name == NULL) { return NULL; @@ -1052,6 +1057,9 @@ PyObject *PyErr_SetFromWindowsErrWithFilename( { PyObject *name = NULL; if (filename) { + if ((DWORD)ierr == 0) { + ierr = (int)GetLastError(); + } name = PyUnicode_DecodeFSDefault(filename); if (name == NULL) { return NULL; From e1b069fe06d953500c2c906d26c2a06eddff5523 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 05:35:18 -0700 Subject: [PATCH 0596/1206] [3.12] gh-107396: tarfiles: set self.exception before _init_read_gz() (GH-107485) (#108207) gh-107396: tarfiles: set self.exception before _init_read_gz() (GH-107485) In the stack call of: _init_read_gz() ``` _read, tarfile.py:548 read, tarfile.py:526 _init_read_gz, tarfile.py:491 ``` a try;except exists that uses `self.exception`, so it needs to be set before calling _init_read_gz(). (cherry picked from commit 37135d25e269ede92bc7da363bebfa574782e59a) Co-authored-by: balmeida-nokia <83089745+balmeida-nokia@users.noreply.github.com> --- Lib/tarfile.py | 2 +- Lib/test/test_tarfile.py | 17 +++++++++++++++++ ...23-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 7781a430839ea5..50212d3f7d8799 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -372,8 +372,8 @@ def __init__(self, name, mode, comptype, fileobj, bufsize, self.zlib = zlib self.crc = zlib.crc32(b"") if mode == "r": - self._init_read_gz() self.exception = zlib.error + self._init_read_gz() else: self._init_write_gz(compresslevel) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index e8d322d20a5a8e..4077a758e3cf17 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -915,6 +915,23 @@ class LzmaDetectReadTest(LzmaTest, DetectReadTest): pass +class GzipBrokenHeaderCorrectException(GzipTest, unittest.TestCase): + """ + See: https://github.com/python/cpython/issues/107396 + """ + def runTest(self): + f = io.BytesIO( + b'\x1f\x8b' # header + b'\x08' # compression method + b'\x04' # flags + b'\0\0\0\0\0\0' # timestamp, compression data, OS ID + b'\0\x01' # size + b'\0\0\0\0\0' # corrupt data (zeros) + ) + with self.assertRaises(tarfile.ReadError): + tarfile.open(fileobj=f, mode='r|gz') + + class MemberReadTest(ReadTest, unittest.TestCase): def _test_member(self, tarinfo, chksum=None, **kwargs): diff --git a/Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst b/Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst new file mode 100644 index 00000000000000..73bff4bdbe024d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst @@ -0,0 +1 @@ +tarfiles; Fixed use before assignment of self.exception for gzip decompression From a909ec399d977f5fdfef13c6ad55bf07ae2b8275 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 06:31:40 -0700 Subject: [PATCH 0597/1206] [3.12] gh-107845: Fix symlink handling for tarfile.data_filter (GH-107846) (#108211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-107845: Fix symlink handling for tarfile.data_filter (GH-107846) (cherry picked from commit acbd3f9c5c5f23e95267714e41236140d84fe962) Co-authored-by: Petr Viktorin Co-authored-by: Victor Stinner Co-authored-by: Lumír 'Frenzy' Balhar --- Doc/library/tarfile.rst | 5 + Lib/tarfile.py | 11 +- Lib/test/test_tarfile.py | 146 +++++++++++++++++- ...-08-10-17-36-22.gh-issue-107845.dABiMJ.rst | 3 + 4 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 7a5bdaaf065fe4..574ea337e71b79 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -735,6 +735,11 @@ A ``TarInfo`` object has the following public data attributes: Name of the target file name, which is only present in :class:`TarInfo` objects of type :const:`LNKTYPE` and :const:`SYMTYPE`. + For symbolic links (``SYMTYPE``), the *linkname* is relative to the directory + that contains the link. + For hard links (``LNKTYPE``), the *linkname* is relative to the root of + the archive. + .. attribute:: TarInfo.uid :type: int diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 50212d3f7d8799..02f5e3b66c0766 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -742,7 +742,7 @@ def __init__(self, tarinfo): class AbsoluteLinkError(FilterError): def __init__(self, tarinfo): self.tarinfo = tarinfo - super().__init__(f'{tarinfo.name!r} is a symlink to an absolute path') + super().__init__(f'{tarinfo.name!r} is a link to an absolute path') class LinkOutsideDestinationError(FilterError): def __init__(self, tarinfo, path): @@ -802,7 +802,14 @@ def _get_filtered_attrs(member, dest_path, for_data=True): if member.islnk() or member.issym(): if os.path.isabs(member.linkname): raise AbsoluteLinkError(member) - target_path = os.path.realpath(os.path.join(dest_path, member.linkname)) + if member.issym(): + target_path = os.path.join(dest_path, + os.path.dirname(name), + member.linkname) + else: + target_path = os.path.join(dest_path, + member.linkname) + target_path = os.path.realpath(target_path) if os.path.commonpath([target_path, dest_path]) != dest_path: raise LinkOutsideDestinationError(member, target_path) return new_attrs diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 4077a758e3cf17..013c62630bc44b 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -3331,10 +3331,12 @@ def __exit__(self, *exc): self.bio = None def add(self, name, *, type=None, symlink_to=None, hardlink_to=None, - mode=None, **kwargs): + mode=None, size=None, **kwargs): """Add a member to the test archive. Call within `with`.""" name = str(name) tarinfo = tarfile.TarInfo(name).replace(**kwargs) + if size is not None: + tarinfo.size = size if mode: tarinfo.mode = _filemode_to_int(mode) if symlink_to is not None: @@ -3410,7 +3412,8 @@ def check_context(self, tar, filter): raise self.raised_exception self.assertEqual(self.expected_paths, set()) - def expect_file(self, name, type=None, symlink_to=None, mode=None): + def expect_file(self, name, type=None, symlink_to=None, mode=None, + size=None): """Check a single file. See check_context.""" if self.raised_exception: raise self.raised_exception @@ -3439,6 +3442,8 @@ def expect_file(self, name, type=None, symlink_to=None, mode=None): self.assertTrue(path.is_fifo()) else: raise NotImplementedError(type) + if size is not None: + self.assertEqual(path.stat().st_size, size) for parent in path.parents: self.expected_paths.discard(parent) @@ -3485,8 +3490,15 @@ def test_parent_symlink(self): # Test interplaying symlinks # Inspired by 'dirsymlink2a' in jwilk/traversal-archives with ArchiveMaker() as arc: + + # `current` links to `.` which is both: + # - the destination directory + # - `current` itself arc.add('current', symlink_to='.') + + # effectively points to ./../ arc.add('parent', symlink_to='current/..') + arc.add('parent/evil') if os_helper.can_symlink(): @@ -3528,9 +3540,46 @@ def test_parent_symlink(self): def test_parent_symlink2(self): # Test interplaying symlinks # Inspired by 'dirsymlink2b' in jwilk/traversal-archives + + # Posix and Windows have different pathname resolution: + # either symlink or a '..' component resolve first. + # Let's see which we are on. + if os_helper.can_symlink(): + testpath = os.path.join(TEMPDIR, 'resolution_test') + os.mkdir(testpath) + + # testpath/current links to `.` which is all of: + # - `testpath` + # - `testpath/current` + # - `testpath/current/current` + # - etc. + os.symlink('.', os.path.join(testpath, 'current')) + + # we'll test where `testpath/current/../file` ends up + with open(os.path.join(testpath, 'current', '..', 'file'), 'w'): + pass + + if os.path.exists(os.path.join(testpath, 'file')): + # Windows collapses 'current\..' to '.' first, leaving + # 'testpath\file' + dotdot_resolves_early = True + elif os.path.exists(os.path.join(testpath, '..', 'file')): + # Posix resolves 'current' to '.' first, leaving + # 'testpath/../file' + dotdot_resolves_early = False + else: + raise AssertionError('Could not determine link resolution') + with ArchiveMaker() as arc: + + # `current` links to `.` which is both the destination directory + # and `current` itself arc.add('current', symlink_to='.') + + # `current/parent` is also available as `./parent`, + # and effectively points to `./../` arc.add('current/parent', symlink_to='..') + arc.add('parent/evil') with self.check_context(arc.open(), 'fully_trusted'): @@ -3544,6 +3593,7 @@ def test_parent_symlink2(self): with self.check_context(arc.open(), 'tar'): if os_helper.can_symlink(): + # Fail when extracting a file outside destination self.expect_exception( tarfile.OutsideDestinationError, "'parent/evil' would be extracted to " @@ -3554,10 +3604,24 @@ def test_parent_symlink2(self): self.expect_file('parent/evil') with self.check_context(arc.open(), 'data'): - self.expect_exception( - tarfile.LinkOutsideDestinationError, - """'current/parent' would link to ['"].*['"], """ - + "which is outside the destination") + if os_helper.can_symlink(): + if dotdot_resolves_early: + # Fail when extracting a file outside destination + self.expect_exception( + tarfile.OutsideDestinationError, + "'parent/evil' would be extracted to " + + """['"].*evil['"], which is outside """ + + "the destination") + else: + # Fail as soon as we have a symlink outside the destination + self.expect_exception( + tarfile.LinkOutsideDestinationError, + "'current/parent' would link to " + + """['"].*outerdir['"], which is outside """ + + "the destination") + else: + self.expect_file('current/') + self.expect_file('parent/evil') @symlink_test def test_absolute_symlink(self): @@ -3587,12 +3651,30 @@ def test_absolute_symlink(self): with self.check_context(arc.open(), 'data'): self.expect_exception( tarfile.AbsoluteLinkError, - "'parent' is a symlink to an absolute path") + "'parent' is a link to an absolute path") + + def test_absolute_hardlink(self): + # Test hardlink to an absolute path + # Inspired by 'dirsymlink' in https://github.com/jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('parent', hardlink_to=self.outerdir / 'foo') + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_exception(KeyError, ".*foo. not found") + + with self.check_context(arc.open(), 'tar'): + self.expect_exception(KeyError, ".*foo. not found") + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.AbsoluteLinkError, + "'parent' is a link to an absolute path") @symlink_test def test_sly_relative0(self): # Inspired by 'relative0' in jwilk/traversal-archives with ArchiveMaker() as arc: + # points to `../../tmp/moo` arc.add('../moo', symlink_to='..//tmp/moo') try: @@ -3643,6 +3725,56 @@ def test_sly_relative2(self): + """['"].*moo['"], which is outside the """ + "destination") + @symlink_test + def test_deep_symlink(self): + # Test that symlinks and hardlinks inside a directory + # point to the correct file (`target` of size 3). + # If links aren't supported we get a copy of the file. + with ArchiveMaker() as arc: + arc.add('targetdir/target', size=3) + # a hardlink's linkname is relative to the archive + arc.add('linkdir/hardlink', hardlink_to=os.path.join( + 'targetdir', 'target')) + # a symlink's linkname is relative to the link's directory + arc.add('linkdir/symlink', symlink_to=os.path.join( + '..', 'targetdir', 'target')) + + for filter in 'tar', 'data', 'fully_trusted': + with self.check_context(arc.open(), filter): + self.expect_file('targetdir/target', size=3) + self.expect_file('linkdir/hardlink', size=3) + if os_helper.can_symlink(): + self.expect_file('linkdir/symlink', size=3, + symlink_to='../targetdir/target') + else: + self.expect_file('linkdir/symlink', size=3) + + @symlink_test + def test_chains(self): + # Test chaining of symlinks/hardlinks. + # Symlinks are created before the files they point to. + with ArchiveMaker() as arc: + arc.add('linkdir/symlink', symlink_to='hardlink') + arc.add('symlink2', symlink_to=os.path.join( + 'linkdir', 'hardlink2')) + arc.add('targetdir/target', size=3) + arc.add('linkdir/hardlink', hardlink_to='targetdir/target') + arc.add('linkdir/hardlink2', hardlink_to='linkdir/symlink') + + for filter in 'tar', 'data', 'fully_trusted': + with self.check_context(arc.open(), filter): + self.expect_file('targetdir/target', size=3) + self.expect_file('linkdir/hardlink', size=3) + self.expect_file('linkdir/hardlink2', size=3) + if os_helper.can_symlink(): + self.expect_file('linkdir/symlink', size=3, + symlink_to='hardlink') + self.expect_file('symlink2', size=3, + symlink_to='linkdir/hardlink2') + else: + self.expect_file('linkdir/symlink', size=3) + self.expect_file('symlink2', size=3) + def test_modes(self): # Test how file modes are extracted # (Note that the modes are ignored on platforms without working chmod) diff --git a/Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst b/Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst new file mode 100644 index 00000000000000..32c1fb93f4ab2c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst @@ -0,0 +1,3 @@ +:func:`tarfile.data_filter` now takes the location of symlinks into account +when determining their target, so it will no longer reject some valid +tarballs with ``LinkOutsideDestinationError``. From 90a22eae452e2f50b7be9db81003e3e849480215 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 21 Aug 2023 16:32:33 +0300 Subject: [PATCH 0598/1206] [3.12] Run sphinx-lint on Misc/NEWS.d/next/ (GH-108212) (#108213) Run sphinx-lint on Misc/NEWS.d/next/ --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 85a6de4abe0146..451cbe8bc84820 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,5 +14,5 @@ repos: hooks: - id: sphinx-lint args: [--enable=default-role] - files: ^Doc/ + files: ^Doc/|^Misc/NEWS.d/next/ types: [rst] From f04024d5880d0ff8888ae3899074aeddf5473bfc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:18:42 -0700 Subject: [PATCH 0599/1206] [3.12] gh-107905: Test raising `__value__` for `TypeAliasType` (GH-107997) (#108217) gh-107905: Test raising `__value__` for `TypeAliasType` (GH-107997) (cherry picked from commit 13104f3b7412dce9bf7cfd09bf2d6dad1f3cc2ed) Co-authored-by: Nikita Sobolev --- Lib/test/test_type_aliases.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index 0ce97f57de6860..8f0a998e1f3dc1 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -168,6 +168,24 @@ def test_recursive_repr(self): self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]), "GenericRecursive[GenericRecursive[int]]") + def test_raising(self): + type MissingName = list[_My_X] + with self.assertRaisesRegex( + NameError, + "cannot access free variable '_My_X' where it is not associated with a value", + ): + MissingName.__value__ + _My_X = int + self.assertEqual(MissingName.__value__, list[int]) + del _My_X + # Cache should still work: + self.assertEqual(MissingName.__value__, list[int]) + + # Explicit exception: + type ExprException = 1 / 0 + with self.assertRaises(ZeroDivisionError): + ExprException.__value__ + class TypeAliasConstructorTest(unittest.TestCase): def test_basic(self): From bc97eb76bb674d76b907e7031f1b7ea11b68121b Mon Sep 17 00:00:00 2001 From: "T. Wouters" Date: Mon, 21 Aug 2023 21:39:45 +0200 Subject: [PATCH 0600/1206] [3.12] Fix sphinx-lint issue now that lint runs on Misc/NEWS.d (#108237) Fix lint warnings in Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst (effectively a backport of GH-108212). --- .../Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst b/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst index f051317d141ff5..1d959a3b22284c 100644 --- a/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst +++ b/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst @@ -1,3 +1,3 @@ -Harmonized the pure Python version of OrderedDict with the C version. Now, -both versions set up their internal state in `__new__`. Formerly, the pure -Python version did the set up in `__init__`. +Harmonized the pure Python version of :class:`~collections.OrderedDict` with the C version. Now, +both versions set up their internal state in ``__new__``. Formerly, the pure +Python version did the set up in ``__init__``. From a27f18a3824365173c4102179ecd28aab72690f8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:40:08 -0700 Subject: [PATCH 0601/1206] [3.12] docs: fix grammar in isolating-extensions.rst (GH-108037) (#108218) docs: fix grammar in isolating-extensions.rst (GH-108037) (cherry picked from commit 47022a079eb9d2a2af781abae3de4a71f80247c2) Co-authored-by: David Lechner --- Doc/howto/isolating-extensions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 2551fbe87b5c2a..8f3787f2d2f145 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -64,7 +64,7 @@ Enter Per-Module State Instead of focusing on per-interpreter state, Python's C API is evolving to better support the more granular *per-module* state. -This means that C-level data is be attached to a *module object*. +This means that C-level data should be attached to a *module object*. Each interpreter creates its own module object, keeping the data separate. For testing the isolation, multiple module objects corresponding to a single extension can even be loaded in a single interpreter. From 78a2a8c026aa082a3ca71e5c86d2303a364c97be Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:43:28 -0700 Subject: [PATCH 0602/1206] [3.12] gh-107298: Fix references to deprecated and removed PyUnicode C API (GH-108077) (#108225) gh-107298: Fix references to deprecated and removed PyUnicode C API (GH-108077) (cherry picked from commit db55383829ccd5ce80c551d60f26851346741fdf) Co-authored-by: Serhiy Storchaka --- Doc/whatsnew/3.11.rst | 26 ++++++++-------- Doc/whatsnew/3.3.rst | 66 ++++++++++++++++++++-------------------- Doc/whatsnew/3.6.rst | 6 ++-- Doc/whatsnew/3.9.rst | 4 +-- Misc/NEWS.d/3.11.0b1.rst | 6 ++-- 5 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 712af6217b6a43..0ac8d02ab15c8c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2591,22 +2591,22 @@ Pending Removal in Python 3.12 The following C APIs have been deprecated in earlier Python releases, and will be removed in Python 3.12. -* :c:func:`PyUnicode_AS_DATA` -* :c:func:`PyUnicode_AS_UNICODE` -* :c:func:`PyUnicode_AsUnicodeAndSize` -* :c:func:`PyUnicode_AsUnicode` -* :c:func:`PyUnicode_FromUnicode` -* :c:func:`PyUnicode_GET_DATA_SIZE` -* :c:func:`PyUnicode_GET_SIZE` -* :c:func:`PyUnicode_GetSize` +* :c:func:`!PyUnicode_AS_DATA` +* :c:func:`!PyUnicode_AS_UNICODE` +* :c:func:`!PyUnicode_AsUnicodeAndSize` +* :c:func:`!PyUnicode_AsUnicode` +* :c:func:`!PyUnicode_FromUnicode` +* :c:func:`!PyUnicode_GET_DATA_SIZE` +* :c:func:`!PyUnicode_GET_SIZE` +* :c:func:`!PyUnicode_GetSize` * :c:func:`PyUnicode_IS_COMPACT` * :c:func:`PyUnicode_IS_READY` * :c:func:`PyUnicode_READY` -* :c:func:`Py_UNICODE_WSTR_LENGTH` -* :c:func:`_PyUnicode_AsUnicode` -* :c:macro:`PyUnicode_WCHAR_KIND` +* :c:func:`!PyUnicode_WSTR_LENGTH` +* :c:func:`!_PyUnicode_AsUnicode` +* :c:macro:`!PyUnicode_WCHAR_KIND` * :c:type:`PyUnicodeObject` -* :c:func:`PyUnicode_InternImmortal()` +* :c:func:`!PyUnicode_InternImmortal` .. _whatsnew311-c-api-removed: @@ -2614,7 +2614,7 @@ and will be removed in Python 3.12. Removed ------- -* :c:func:`PyFrame_BlockSetup` and :c:func:`PyFrame_BlockPop` have been +* :c:func:`!PyFrame_BlockSetup` and :c:func:`!PyFrame_BlockPop` have been removed. (Contributed by Mark Shannon in :issue:`40222`.) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 1414b2f79a67d0..8cf7ad57475b29 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -249,7 +249,7 @@ Changes introduced by :pep:`393` are the following: non-BMP code points. * The value of :data:`sys.maxunicode` is now always ``1114111`` (``0x10FFFF`` - in hexadecimal). The :c:func:`PyUnicode_GetMax` function still returns + in hexadecimal). The :c:func:`!PyUnicode_GetMax` function still returns either ``0xFFFF`` or ``0x10FFFF`` for backward compatibility, and it should not be used with the new Unicode API (see :issue:`13054`). @@ -2196,7 +2196,7 @@ Changes to Python's build process and to the C API include: * :c:macro:`PyUnicode_DATA`, :c:macro:`PyUnicode_1BYTE_DATA`, :c:macro:`PyUnicode_2BYTE_DATA`, :c:macro:`PyUnicode_4BYTE_DATA` * :c:macro:`PyUnicode_KIND` with :c:enum:`PyUnicode_Kind` enum: - :c:data:`PyUnicode_WCHAR_KIND`, :c:data:`PyUnicode_1BYTE_KIND`, + :c:data:`!PyUnicode_WCHAR_KIND`, :c:data:`PyUnicode_1BYTE_KIND`, :c:data:`PyUnicode_2BYTE_KIND`, :c:data:`PyUnicode_4BYTE_KIND` * :c:macro:`PyUnicode_READ`, :c:macro:`PyUnicode_READ_CHAR`, :c:macro:`PyUnicode_WRITE` * :c:macro:`PyUnicode_MAX_CHAR_VALUE` @@ -2270,58 +2270,58 @@ removed in Python 4. All functions using this type are deprecated: Unicode functions and methods using :c:type:`Py_UNICODE` and :c:expr:`Py_UNICODE*` types: -* :c:macro:`PyUnicode_FromUnicode`: use :c:func:`PyUnicode_FromWideChar` or +* :c:macro:`!PyUnicode_FromUnicode`: use :c:func:`PyUnicode_FromWideChar` or :c:func:`PyUnicode_FromKindAndData` -* :c:macro:`PyUnicode_AS_UNICODE`, :c:func:`PyUnicode_AsUnicode`, - :c:func:`PyUnicode_AsUnicodeAndSize`: use :c:func:`PyUnicode_AsWideCharString` -* :c:macro:`PyUnicode_AS_DATA`: use :c:macro:`PyUnicode_DATA` with +* :c:macro:`!PyUnicode_AS_UNICODE`, :c:func:`!PyUnicode_AsUnicode`, + :c:func:`!PyUnicode_AsUnicodeAndSize`: use :c:func:`PyUnicode_AsWideCharString` +* :c:macro:`!PyUnicode_AS_DATA`: use :c:macro:`PyUnicode_DATA` with :c:macro:`PyUnicode_READ` and :c:macro:`PyUnicode_WRITE` -* :c:macro:`PyUnicode_GET_SIZE`, :c:func:`PyUnicode_GetSize`: use +* :c:macro:`!PyUnicode_GET_SIZE`, :c:func:`!PyUnicode_GetSize`: use :c:macro:`PyUnicode_GET_LENGTH` or :c:func:`PyUnicode_GetLength` -* :c:macro:`PyUnicode_GET_DATA_SIZE`: use +* :c:macro:`!PyUnicode_GET_DATA_SIZE`: use ``PyUnicode_GET_LENGTH(str) * PyUnicode_KIND(str)`` (only work on ready strings) -* :c:func:`PyUnicode_AsUnicodeCopy`: use :c:func:`PyUnicode_AsUCS4Copy` or +* :c:func:`!PyUnicode_AsUnicodeCopy`: use :c:func:`PyUnicode_AsUCS4Copy` or :c:func:`PyUnicode_AsWideCharString` -* :c:func:`PyUnicode_GetMax` +* :c:func:`!PyUnicode_GetMax` Functions and macros manipulating Py_UNICODE* strings: -* :c:macro:`Py_UNICODE_strlen`: use :c:func:`PyUnicode_GetLength` or +* :c:macro:`!Py_UNICODE_strlen()`: use :c:func:`PyUnicode_GetLength` or :c:macro:`PyUnicode_GET_LENGTH` -* :c:macro:`Py_UNICODE_strcat`: use :c:func:`PyUnicode_CopyCharacters` or +* :c:macro:`!Py_UNICODE_strcat()`: use :c:func:`PyUnicode_CopyCharacters` or :c:func:`PyUnicode_FromFormat` -* :c:macro:`Py_UNICODE_strcpy`, :c:macro:`Py_UNICODE_strncpy`, - :c:macro:`Py_UNICODE_COPY`: use :c:func:`PyUnicode_CopyCharacters` or +* :c:macro:`!Py_UNICODE_strcpy()`, :c:macro:`!Py_UNICODE_strncpy()`, + :c:macro:`!Py_UNICODE_COPY()`: use :c:func:`PyUnicode_CopyCharacters` or :c:func:`PyUnicode_Substring` -* :c:macro:`Py_UNICODE_strcmp`: use :c:func:`PyUnicode_Compare` -* :c:macro:`Py_UNICODE_strncmp`: use :c:func:`PyUnicode_Tailmatch` -* :c:macro:`Py_UNICODE_strchr`, :c:macro:`Py_UNICODE_strrchr`: use +* :c:macro:`!Py_UNICODE_strcmp()`: use :c:func:`PyUnicode_Compare` +* :c:macro:`!Py_UNICODE_strncmp()`: use :c:func:`PyUnicode_Tailmatch` +* :c:macro:`!Py_UNICODE_strchr()`, :c:macro:`!Py_UNICODE_strrchr()`: use :c:func:`PyUnicode_FindChar` -* :c:macro:`Py_UNICODE_FILL`: use :c:func:`PyUnicode_Fill` -* :c:macro:`Py_UNICODE_MATCH` +* :c:macro:`!Py_UNICODE_FILL()`: use :c:func:`PyUnicode_Fill` +* :c:macro:`!Py_UNICODE_MATCH` Encoders: -* :c:func:`PyUnicode_Encode`: use :c:func:`PyUnicode_AsEncodedObject` -* :c:func:`PyUnicode_EncodeUTF7` -* :c:func:`PyUnicode_EncodeUTF8`: use :c:func:`PyUnicode_AsUTF8` or +* :c:func:`!PyUnicode_Encode`: use :c:func:`PyUnicode_AsEncodedObject` +* :c:func:`!PyUnicode_EncodeUTF7` +* :c:func:`!PyUnicode_EncodeUTF8`: use :c:func:`PyUnicode_AsUTF8` or :c:func:`PyUnicode_AsUTF8String` -* :c:func:`PyUnicode_EncodeUTF32` -* :c:func:`PyUnicode_EncodeUTF16` -* :c:func:`PyUnicode_EncodeUnicodeEscape` use +* :c:func:`!PyUnicode_EncodeUTF32` +* :c:func:`!PyUnicode_EncodeUTF16` +* :c:func:`!PyUnicode_EncodeUnicodeEscape` use :c:func:`PyUnicode_AsUnicodeEscapeString` -* :c:func:`PyUnicode_EncodeRawUnicodeEscape` use +* :c:func:`!PyUnicode_EncodeRawUnicodeEscape` use :c:func:`PyUnicode_AsRawUnicodeEscapeString` -* :c:func:`PyUnicode_EncodeLatin1`: use :c:func:`PyUnicode_AsLatin1String` -* :c:func:`PyUnicode_EncodeASCII`: use :c:func:`PyUnicode_AsASCIIString` -* :c:func:`PyUnicode_EncodeCharmap` -* :c:func:`PyUnicode_TranslateCharmap` -* :c:func:`PyUnicode_EncodeMBCS`: use :c:func:`PyUnicode_AsMBCSString` or +* :c:func:`!PyUnicode_EncodeLatin1`: use :c:func:`PyUnicode_AsLatin1String` +* :c:func:`!PyUnicode_EncodeASCII`: use :c:func:`PyUnicode_AsASCIIString` +* :c:func:`!PyUnicode_EncodeCharmap` +* :c:func:`!PyUnicode_TranslateCharmap` +* :c:func:`!PyUnicode_EncodeMBCS`: use :c:func:`PyUnicode_AsMBCSString` or :c:func:`PyUnicode_EncodeCodePage` (with ``CP_ACP`` code_page) -* :c:func:`PyUnicode_EncodeDecimal`, - :c:func:`PyUnicode_TransformDecimalToASCII` +* :c:func:`!PyUnicode_EncodeDecimal`, + :c:func:`!PyUnicode_TransformDecimalToASCII` Deprecated features diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 1093d24531505b..be20ee1afb4e83 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2066,9 +2066,9 @@ environment. (Contributed by Brett Cannon in :issue:`25154`.) Deprecated functions and types of the C API ------------------------------------------- -Undocumented functions :c:func:`PyUnicode_AsEncodedObject`, -:c:func:`PyUnicode_AsDecodedObject`, :c:func:`PyUnicode_AsEncodedUnicode` -and :c:func:`PyUnicode_AsDecodedUnicode` are deprecated now. +Undocumented functions :c:func:`!PyUnicode_AsEncodedObject`, +:c:func:`!PyUnicode_AsDecodedObject`, :c:func:`!PyUnicode_AsEncodedUnicode` +and :c:func:`!PyUnicode_AsDecodedUnicode` are deprecated now. Use the :ref:`generic codec based API ` instead. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 666d53ed6da7ba..664c8d8a545db0 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1370,8 +1370,8 @@ Porting to Python 3.9 (Contributed by Victor Stinner in :issue:`40241`.) * The ``Py_UNICODE_COPY``, ``Py_UNICODE_FILL``, ``PyUnicode_WSTR_LENGTH``, - :c:func:`PyUnicode_FromUnicode`, :c:func:`PyUnicode_AsUnicode`, - ``_PyUnicode_AsUnicode``, and :c:func:`PyUnicode_AsUnicodeAndSize` are + :c:func:`!PyUnicode_FromUnicode`, :c:func:`!PyUnicode_AsUnicode`, + ``_PyUnicode_AsUnicode``, and :c:func:`!PyUnicode_AsUnicodeAndSize` are marked as deprecated in C. They have been deprecated by :pep:`393` since Python 3.3. (Contributed by Inada Naoki in :issue:`36346`.) diff --git a/Misc/NEWS.d/3.11.0b1.rst b/Misc/NEWS.d/3.11.0b1.rst index 6b601489a77285..1da722b21680ee 100644 --- a/Misc/NEWS.d/3.11.0b1.rst +++ b/Misc/NEWS.d/3.11.0b1.rst @@ -2068,9 +2068,9 @@ casts when the Python C API is used in C++. Patch by Victor Stinner. .. nonce: Cx-95G .. section: C API -Mark functions as deprecated by :pep:`623`: :c:func:`PyUnicode_AS_DATA`, -:c:func:`PyUnicode_AS_UNICODE`, :c:func:`PyUnicode_GET_DATA_SIZE`, -:c:func:`PyUnicode_GET_SIZE`. Patch by Victor Stinner. +Mark functions as deprecated by :pep:`623`: :c:func:`!PyUnicode_AS_DATA`, +:c:func:`!PyUnicode_AS_UNICODE`, :c:func:`!PyUnicode_GET_DATA_SIZE`, +:c:func:`!PyUnicode_GET_SIZE`. Patch by Victor Stinner. .. From f51cdfaaac71f2279156af5ffd042122443699d9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:44:08 -0700 Subject: [PATCH 0603/1206] [3.12] gh-108224: Fix asyncio doc inconsistency (GH-108230) (#108231) gh-108224: Fix asyncio doc inconsistency (GH-108230) (Spawning subprocesses does not require the event loop to run in the main thread -- only signal handling does.) (cherry picked from commit 1cc391d9e2ea24ca750005335507b52933fc0b52) Co-authored-by: temach --- Doc/library/asyncio-dev.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst index c7d97008fb490e..a9c3a0183bb72d 100644 --- a/Doc/library/asyncio-dev.rst +++ b/Doc/library/asyncio-dev.rst @@ -99,7 +99,7 @@ To schedule a coroutine object from a different OS thread, the # Wait for the result: result = future.result() -To handle signals and to execute subprocesses, the event loop must be +To handle signals the event loop must be run in the main thread. The :meth:`loop.run_in_executor` method can be used with a From 47f60c3f67b2914af0c85227ddffc583cea72791 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 21 Aug 2023 22:44:45 +0300 Subject: [PATCH 0604/1206] [3.12] gh-107298: Fix C API datetime documentation (GH-108034). (#108234) (cherry picked from commit d63972e289e05b0d82e59f32f107312a8b3de7b5) --- Doc/c-api/datetime.rst | 71 +++++++++++++++++++++++++++++++++--------- Doc/tools/.nitignore | 1 - 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst index 72fc07afbf1f4d..97522da773477e 100644 --- a/Doc/c-api/datetime.rst +++ b/Doc/c-api/datetime.rst @@ -8,11 +8,54 @@ DateTime Objects Various date and time objects are supplied by the :mod:`datetime` module. Before using any of these functions, the header file :file:`datetime.h` must be included in your source (note that this is not included by :file:`Python.h`), -and the macro :c:macro:`PyDateTime_IMPORT` must be invoked, usually as part of +and the macro :c:macro:`!PyDateTime_IMPORT` must be invoked, usually as part of the module initialisation function. The macro puts a pointer to a C structure -into a static variable, :c:data:`PyDateTimeAPI`, that is used by the following +into a static variable, :c:data:`!PyDateTimeAPI`, that is used by the following macros. +.. c:type:: PyDateTime_Date + + This subtype of :c:type:`PyObject` represents a Python date object. + +.. c:type:: PyDateTime_DateTime + + This subtype of :c:type:`PyObject` represents a Python datetime object. + +.. c:type:: PyDateTime_Time + + This subtype of :c:type:`PyObject` represents a Python time object. + +.. c:type:: PyDateTime_Delta + + This subtype of :c:type:`PyObject` represents the difference between two datetime values. + +.. c:var:: PyTypeObject PyDateTime_DateType + + This instance of :c:type:`PyTypeObject` represents the Python date type; + it is the same object as :class:`datetime.date` in the Python layer. + +.. c:var:: PyTypeObject PyDateTime_DateTimeType + + This instance of :c:type:`PyTypeObject` represents the Python datetime type; + it is the same object as :class:`datetime.datetime` in the Python layer. + +.. c:var:: PyTypeObject PyDateTime_TimeType + + This instance of :c:type:`PyTypeObject` represents the Python time type; + it is the same object as :class:`datetime.time` in the Python layer. + +.. c:var:: PyTypeObject PyDateTime_DeltaType + + This instance of :c:type:`PyTypeObject` represents Python type for + the difference between two datetime values; + it is the same object as :class:`datetime.timedelta` in the Python layer. + +.. c:var:: PyTypeObject PyDateTime_TZInfoType + + This instance of :c:type:`PyTypeObject` represents the Python time zone info type; + it is the same object as :class:`datetime.tzinfo` in the Python layer. + + Macro for access to the UTC singleton: .. c:var:: PyObject* PyDateTime_TimeZone_UTC @@ -28,7 +71,7 @@ Type-check macros: .. c:function:: int PyDate_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DateType` or a subtype of - :c:data:`PyDateTime_DateType`. *ob* must not be ``NULL``. This function always + :c:data:`!PyDateTime_DateType`. *ob* must not be ``NULL``. This function always succeeds. @@ -41,7 +84,7 @@ Type-check macros: .. c:function:: int PyDateTime_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DateTimeType` or a subtype of - :c:data:`PyDateTime_DateTimeType`. *ob* must not be ``NULL``. This function always + :c:data:`!PyDateTime_DateTimeType`. *ob* must not be ``NULL``. This function always succeeds. @@ -54,7 +97,7 @@ Type-check macros: .. c:function:: int PyTime_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_TimeType` or a subtype of - :c:data:`PyDateTime_TimeType`. *ob* must not be ``NULL``. This function always + :c:data:`!PyDateTime_TimeType`. *ob* must not be ``NULL``. This function always succeeds. @@ -67,7 +110,7 @@ Type-check macros: .. c:function:: int PyDelta_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_DeltaType` or a subtype of - :c:data:`PyDateTime_DeltaType`. *ob* must not be ``NULL``. This function always + :c:data:`!PyDateTime_DeltaType`. *ob* must not be ``NULL``. This function always succeeds. @@ -80,7 +123,7 @@ Type-check macros: .. c:function:: int PyTZInfo_Check(PyObject *ob) Return true if *ob* is of type :c:data:`PyDateTime_TZInfoType` or a subtype of - :c:data:`PyDateTime_TZInfoType`. *ob* must not be ``NULL``. This function always + :c:data:`!PyDateTime_TZInfoType`. *ob* must not be ``NULL``. This function always succeeds. @@ -133,7 +176,7 @@ Macros to create objects: :class:`datetime.timedelta` objects. -.. c:function:: PyObject* PyTimeZone_FromOffset(PyDateTime_DeltaType* offset) +.. c:function:: PyObject* PyTimeZone_FromOffset(PyObject *offset) Return a :class:`datetime.timezone` object with an unnamed fixed offset represented by the *offset* argument. @@ -141,7 +184,7 @@ Macros to create objects: .. versionadded:: 3.7 -.. c:function:: PyObject* PyTimeZone_FromOffsetAndName(PyDateTime_DeltaType* offset, PyUnicode* name) +.. c:function:: PyObject* PyTimeZone_FromOffsetAndName(PyObject *offset, PyObject *name) Return a :class:`datetime.timezone` object with a fixed offset represented by the *offset* argument and with tzname *name*. @@ -150,8 +193,8 @@ Macros to create objects: Macros to extract fields from date objects. The argument must be an instance of -:c:data:`PyDateTime_Date`, including subclasses (such as -:c:data:`PyDateTime_DateTime`). The argument must not be ``NULL``, and the type is +:c:type:`PyDateTime_Date`, including subclasses (such as +:c:type:`PyDateTime_DateTime`). The argument must not be ``NULL``, and the type is not checked: .. c:function:: int PyDateTime_GET_YEAR(PyDateTime_Date *o) @@ -170,7 +213,7 @@ not checked: Macros to extract fields from datetime objects. The argument must be an -instance of :c:data:`PyDateTime_DateTime`, including subclasses. The argument +instance of :c:type:`PyDateTime_DateTime`, including subclasses. The argument must not be ``NULL``, and the type is not checked: .. c:function:: int PyDateTime_DATE_GET_HOUR(PyDateTime_DateTime *o) @@ -208,7 +251,7 @@ must not be ``NULL``, and the type is not checked: Macros to extract fields from time objects. The argument must be an instance of -:c:data:`PyDateTime_Time`, including subclasses. The argument must not be ``NULL``, +:c:type:`PyDateTime_Time`, including subclasses. The argument must not be ``NULL``, and the type is not checked: .. c:function:: int PyDateTime_TIME_GET_HOUR(PyDateTime_Time *o) @@ -246,7 +289,7 @@ and the type is not checked: Macros to extract fields from time delta objects. The argument must be an -instance of :c:data:`PyDateTime_Delta`, including subclasses. The argument must +instance of :c:type:`PyDateTime_Delta`, including subclasses. The argument must not be ``NULL``, and the type is not checked: .. c:function:: int PyDateTime_DELTA_GET_DAYS(PyDateTime_Delta *o) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index ada46064e358e2..4eb466a909a495 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -3,7 +3,6 @@ # Keep lines sorted lexicographically to help avoid merge conflicts. Doc/c-api/arg.rst -Doc/c-api/datetime.rst Doc/c-api/descriptor.rst Doc/c-api/exceptions.rst Doc/c-api/file.rst From b26a7b78c9658a9b888f56ce3dc8cfae127d1eca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 03:00:07 -0700 Subject: [PATCH 0605/1206] [3.12] Fix test_generators: save/restore warnings filters (GH-108246) (#108249) Fix test_generators: save/restore warnings filters (GH-108246) Previously, depending on existing filters, the test could modify the warnings and so fail as "env changed". (cherry picked from commit 531930f47f6b2a548d31e62cb4ad3e215a24bf53) Co-authored-by: Victor Stinner --- Lib/test/test_generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 31680b5a92e0f3..1ee9958445bf18 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -2176,6 +2176,7 @@ def printsolution(self, x): caught ValueError (xyz) >>> import warnings +>>> old_filters = warnings.filters.copy() >>> warnings.filterwarnings("ignore", category=DeprecationWarning) # Filter DeprecationWarning: regarding the (type, val, tb) signature of throw(). @@ -2249,8 +2250,7 @@ def printsolution(self, x): ... ValueError: 7 ->>> warnings.filters.pop(0) -('ignore', None, , None, 0) +>>> warnings.filters[:] = old_filters # Re-enable DeprecationWarning: the (type, val, tb) exception representation is deprecated, # and may be removed in a future version of Python. From dd73f2f76ab1eabe92a2ca820430be723df31cde Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 03:01:24 -0700 Subject: [PATCH 0606/1206] [3.12] gh-106242: Make ntpath.realpath errors consistent with abspath when there are embedded nulls (GH-108248) (#108251) gh-106242: Make ntpath.realpath errors consistent with abspath when there are embedded nulls (GH-108248) * gh-106242: Make ntpath.realpath errors consistent with abspath when there are embedded nulls * Update 2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst mention Windows and the former incorrect ValueError. --------- (cherry picked from commit de33b5c662ea8d35d81ed857c6a39e34ab94c510) Co-authored-by: Steve Dower Co-authored-by: Gregory P. Smith --- Lib/ntpath.py | 12 ++++++++++++ Lib/test/test_ntpath.py | 6 ++++++ .../2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst | 4 ++++ 3 files changed, 22 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst diff --git a/Lib/ntpath.py b/Lib/ntpath.py index dadcdc0c495da1..df3402d46c9cc6 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -721,6 +721,14 @@ def realpath(path, *, strict=False): try: path = _getfinalpathname(path) initial_winerror = 0 + except ValueError as ex: + # gh-106242: Raised for embedded null characters + # In strict mode, we convert into an OSError. + # Non-strict mode returns the path as-is, since we've already + # made it absolute. + if strict: + raise OSError(str(ex)) from None + path = normpath(path) except OSError as ex: if strict: raise @@ -740,6 +748,10 @@ def realpath(path, *, strict=False): try: if _getfinalpathname(spath) == path: path = spath + except ValueError as ex: + # Unexpected, as an invalid path should not have gained a prefix + # at any point, but we ignore this error just in case. + pass except OSError as ex: # If the path does not exist and originally did not exist, then # strip the prefix anyway. diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 78e1cb582512b0..d91dcdfb0c5fac 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -394,6 +394,10 @@ def test_realpath_basic(self): d = drives.pop().encode() self.assertEqual(ntpath.realpath(d), d) + # gh-106242: Embedded nulls and non-strict fallback to abspath + self.assertEqual(ABSTFN + "\0spam", + ntpath.realpath(os_helper.TESTFN + "\0spam", strict=False)) + @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') def test_realpath_strict(self): @@ -404,6 +408,8 @@ def test_realpath_strict(self): self.addCleanup(os_helper.unlink, ABSTFN) self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN, strict=True) self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN + "2", strict=True) + # gh-106242: Embedded nulls should raise OSError (not ValueError) + self.assertRaises(OSError, ntpath.realpath, ABSTFN + "\0spam", strict=True) @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') diff --git a/Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst b/Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst new file mode 100644 index 00000000000000..ffe42ec5dc3faf --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst @@ -0,0 +1,4 @@ +Fixes :func:`~os.path.realpath` to behave consistently when passed a path +containing an embedded null character on Windows. In strict mode, it now +raises :exc:`OSError` instead of the unexpected :exc:`ValueError`, and in +non-strict mode will make the path absolute. From ef4d427fd8ed89fcfb5a0fada4c24abec12991e5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 22 Aug 2023 12:01:38 +0200 Subject: [PATCH 0607/1206] [3.12] gh-107801: Improve the accuracy of io.TextIOWrapper.seek docs (#107933) (#108262) (cherry picked from commit 7f87ebbc3f52680c939791f397b9a478edf0c8d4) Clearly document the supported seek() operations: - Rewind to the start of the stream - Restore a previous stream position (given by tell()) - Fast-forward to the end of the stream --- Doc/library/io.rst | 16 ++++++++++++++++ Modules/_io/clinic/textio.c.h | 24 +++++++++++++++++++++--- Modules/_io/textio.c | 20 ++++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 66273d9ed1ff0a..792bf43d9811bb 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -1044,6 +1044,22 @@ Text I/O .. versionchanged:: 3.11 The method supports ``encoding="locale"`` option. + .. method:: seek(cookie, whence=os.SEEK_SET, /) + + Set the stream position. + Return the new stream position as an :class:`int`. + + Four operations are supported, + given by the following argument combinations: + + * ``seek(0, SEEK_SET)``: Rewind to the start of the stream. + * ``seek(cookie, SEEK_SET)``: Restore a previous position; + *cookie* **must be** a number returned by :meth:`!tell`. + * ``seek(0, SEEK_END)``: Fast-forward to the end of the stream. + * ``seek(0, SEEK_CUR)``: Leave the current stream position unchanged. + + Any other argument combinations are invalid, + and may raise exceptions. .. class:: StringIO(initial_value='', newline='\n') diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 33fc23bd4c0c69..63ec56311e2a63 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -759,9 +759,27 @@ _io_TextIOWrapper_readline(textio *self, PyObject *const *args, Py_ssize_t nargs } PyDoc_STRVAR(_io_TextIOWrapper_seek__doc__, -"seek($self, cookie, whence=0, /)\n" +"seek($self, cookie, whence=os.SEEK_SET, /)\n" "--\n" -"\n"); +"\n" +"Set the stream position, and return the new stream position.\n" +"\n" +" cookie\n" +" Zero or an opaque number returned by tell().\n" +" whence\n" +" The relative position to seek from.\n" +"\n" +"Four operations are supported, given by the following argument\n" +"combinations:\n" +"\n" +"- seek(0, SEEK_SET): Rewind to the start of the stream.\n" +"- seek(cookie, SEEK_SET): Restore a previous position;\n" +" \'cookie\' must be a number returned by tell().\n" +"- seek(0, SEEK_END): Fast-forward to the end of the stream.\n" +"- seek(0, SEEK_CUR): Leave the current stream position unchanged.\n" +"\n" +"Any other argument combinations are invalid,\n" +"and may raise exceptions."); #define _IO_TEXTIOWRAPPER_SEEK_METHODDEF \ {"seek", _PyCFunction_CAST(_io_TextIOWrapper_seek), METH_FASTCALL, _io_TextIOWrapper_seek__doc__}, @@ -960,4 +978,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=42f592331302973f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fc02f9e59bfa9956 input=a9049054013a1b77]*/ diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 46411c70a96753..ff6023c8ef9283 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -2438,13 +2438,29 @@ _textiowrapper_encoder_setstate(textio *self, cookie_type *cookie) /*[clinic input] _io.TextIOWrapper.seek cookie as cookieObj: object - whence: int = 0 + Zero or an opaque number returned by tell(). + whence: int(c_default='0') = os.SEEK_SET + The relative position to seek from. / + +Set the stream position, and return the new stream position. + +Four operations are supported, given by the following argument +combinations: + +- seek(0, SEEK_SET): Rewind to the start of the stream. +- seek(cookie, SEEK_SET): Restore a previous position; + 'cookie' must be a number returned by tell(). +- seek(0, SEEK_END): Fast-forward to the end of the stream. +- seek(0, SEEK_CUR): Leave the current stream position unchanged. + +Any other argument combinations are invalid, +and may raise exceptions. [clinic start generated code]*/ static PyObject * _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) -/*[clinic end generated code: output=0a15679764e2d04d input=0458abeb3d7842be]*/ +/*[clinic end generated code: output=0a15679764e2d04d input=0f68adcb02cf2823]*/ { PyObject *posobj; cookie_type cookie; From 149d70c2546d9615e6292135430795c3cf2b50fe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 03:02:32 -0700 Subject: [PATCH 0608/1206] [3.12] gh-108179: Add error message for parser stack overflows (GH-108256) (#108263) gh-108179: Add error message for parser stack overflows (GH-108256) (cherry picked from commit 86617518c4ac824e2b6dc20691ba5a08df04f285) Co-authored-by: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> --- Lib/test/test_syntax.py | 2 +- Parser/parser.c | 1590 ++++++++-------------- Parser/pegen.h | 2 + Parser/pegen_errors.c | 8 + Tools/peg_generator/pegen/c_generator.py | 3 +- 5 files changed, 542 insertions(+), 1063 deletions(-) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index f3d6cd7bad0eec..4c988382f8b411 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -2335,7 +2335,7 @@ def test_error_on_parser_stack_overflow(self): source = "-" * 100000 + "4" for mode in ["exec", "eval", "single"]: with self.subTest(mode=mode): - with self.assertRaises(MemoryError): + with self.assertRaisesRegex(MemoryError, r"too complex"): compile(source, "", mode) @support.cpython_only diff --git a/Parser/parser.c b/Parser/parser.c index f2ea8f59b00567..860bbea4431c08 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -1126,8 +1126,7 @@ static mod_ty file_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1173,8 +1172,7 @@ static mod_ty interactive_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1217,8 +1215,7 @@ static mod_ty eval_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1267,8 +1264,7 @@ static mod_ty func_type_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1329,8 +1325,7 @@ static expr_ty fstring_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1379,8 +1374,7 @@ static asdl_stmt_seq* statements_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1423,8 +1417,7 @@ static asdl_stmt_seq* statement_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1491,8 +1484,7 @@ static asdl_stmt_seq* statement_newline_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1623,8 +1615,7 @@ static asdl_stmt_seq* simple_stmts_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -1717,8 +1708,7 @@ static stmt_ty simple_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -2099,8 +2089,7 @@ static stmt_ty compound_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -2290,8 +2279,7 @@ static stmt_ty assignment_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -2509,8 +2497,7 @@ static expr_ty annotated_rhs_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -2580,8 +2567,7 @@ static AugOperator* augassign_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -2912,8 +2898,7 @@ static stmt_ty return_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -2977,8 +2962,7 @@ static stmt_ty raise_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3078,8 +3062,7 @@ static stmt_ty global_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3143,8 +3126,7 @@ static stmt_ty nonlocal_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3208,8 +3190,7 @@ static stmt_ty del_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3294,8 +3275,7 @@ static stmt_ty yield_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3356,8 +3336,7 @@ static stmt_ty assert_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3424,8 +3403,7 @@ static stmt_ty import_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3501,8 +3479,7 @@ static stmt_ty import_name_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3568,8 +3545,7 @@ static stmt_ty import_from_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3688,8 +3664,7 @@ static asdl_alias_seq* import_from_targets_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3824,8 +3799,7 @@ static asdl_alias_seq* import_from_as_names_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3868,8 +3842,7 @@ static alias_ty import_from_as_name_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3933,8 +3906,7 @@ static asdl_alias_seq* dotted_as_names_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -3977,8 +3949,7 @@ static alias_ty dotted_as_name_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4044,8 +4015,7 @@ static expr_ty dotted_name_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, dotted_name_type, &_res)) { @@ -4079,8 +4049,7 @@ static expr_ty dotted_name_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4148,8 +4117,7 @@ static asdl_stmt_seq* block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4244,8 +4212,7 @@ static asdl_expr_seq* decorators_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4288,8 +4255,7 @@ static stmt_ty class_def_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4356,8 +4322,7 @@ static stmt_ty class_def_raw_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4452,8 +4417,7 @@ static stmt_ty function_def_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4521,8 +4485,7 @@ static stmt_ty function_def_raw_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4692,8 +4655,7 @@ static arguments_ty params_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4755,8 +4717,7 @@ static arguments_ty parameters_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -4919,8 +4880,7 @@ static asdl_arg_seq* slash_no_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5000,8 +4960,7 @@ static SlashWithDefault* slash_with_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5090,8 +5049,7 @@ static StarEtc* star_etc_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5252,8 +5210,7 @@ static arg_ty kwds_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5318,8 +5275,7 @@ static arg_ty param_no_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5399,8 +5355,7 @@ static arg_ty param_no_default_star_annotation_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5478,8 +5433,7 @@ static NameDefaultPair* param_with_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5565,8 +5519,7 @@ static NameDefaultPair* param_maybe_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5650,8 +5603,7 @@ static arg_ty param_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5715,8 +5667,7 @@ static arg_ty param_star_annotation_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5780,8 +5731,7 @@ static expr_ty annotation_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5827,8 +5777,7 @@ static expr_ty star_annotation_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5874,8 +5823,7 @@ static expr_ty default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -5943,8 +5891,7 @@ static stmt_ty if_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -6084,8 +6031,7 @@ static stmt_ty elif_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -6222,8 +6168,7 @@ static asdl_stmt_seq* else_block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -6291,8 +6236,7 @@ static stmt_ty while_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -6388,8 +6332,7 @@ static stmt_ty for_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -6586,8 +6529,7 @@ static stmt_ty with_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -6856,8 +6798,7 @@ static withitem_ty with_item_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -6955,8 +6896,7 @@ static stmt_ty try_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7145,8 +7085,7 @@ static excepthandler_ty except_block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7299,8 +7238,7 @@ static excepthandler_ty except_star_block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7414,8 +7352,7 @@ static asdl_stmt_seq* finally_block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7485,8 +7422,7 @@ static stmt_ty match_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7584,8 +7520,7 @@ static expr_ty subject_expr_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7671,8 +7606,7 @@ static match_case_ty case_block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7746,8 +7680,7 @@ static expr_ty guard_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7793,8 +7726,7 @@ static pattern_ty patterns_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7874,8 +7806,7 @@ static pattern_ty pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -7932,8 +7863,7 @@ static pattern_ty as_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8019,8 +7949,7 @@ static pattern_ty or_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8089,8 +8018,7 @@ static pattern_ty closed_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8272,8 +8200,7 @@ static pattern_ty literal_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8507,8 +8434,7 @@ static expr_ty literal_expr_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8696,8 +8622,7 @@ static expr_ty complex_number_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8803,8 +8728,7 @@ static expr_ty signed_number_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8887,8 +8811,7 @@ static expr_ty signed_real_number_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -8971,8 +8894,7 @@ static expr_ty real_number_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9015,8 +8937,7 @@ static expr_ty imaginary_number_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9059,8 +8980,7 @@ static pattern_ty capture_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9121,8 +9041,7 @@ static expr_ty pattern_capture_target_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9169,8 +9088,7 @@ static pattern_ty wildcard_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9231,8 +9149,7 @@ static pattern_ty value_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9297,8 +9214,7 @@ static expr_ty attr_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, attr_type, &_res)) { @@ -9332,8 +9248,7 @@ static expr_ty attr_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9401,8 +9316,7 @@ static expr_ty name_or_attr_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9459,8 +9373,7 @@ static pattern_ty group_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9509,8 +9422,7 @@ static pattern_ty sequence_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9616,8 +9528,7 @@ static asdl_seq* open_sequence_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9666,8 +9577,7 @@ static asdl_seq* maybe_sequence_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9714,8 +9624,7 @@ static pattern_ty maybe_star_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9772,8 +9681,7 @@ static pattern_ty star_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -9882,8 +9790,7 @@ static pattern_ty mapping_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10082,8 +9989,7 @@ static asdl_seq* items_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10121,8 +10027,7 @@ static KeyPatternPair* key_value_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10171,8 +10076,7 @@ static expr_ty double_star_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10223,8 +10127,7 @@ static pattern_ty class_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10454,8 +10357,7 @@ static asdl_pattern_seq* positional_patterns_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10498,8 +10400,7 @@ static asdl_seq* keyword_patterns_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10537,8 +10438,7 @@ static KeyPatternPair* keyword_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10587,8 +10487,7 @@ static stmt_ty type_alias_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10661,8 +10560,7 @@ static asdl_type_param_seq* type_params_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10711,8 +10609,7 @@ static asdl_type_param_seq* type_param_seq_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10764,8 +10661,7 @@ static type_param_ty type_param_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -10972,8 +10868,7 @@ static expr_ty type_param_bound_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11019,8 +10914,7 @@ static expr_ty expressions_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11148,8 +11042,7 @@ static expr_ty expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11303,8 +11196,7 @@ static expr_ty yield_expr_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11410,8 +11302,7 @@ static expr_ty star_expressions_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11534,8 +11425,7 @@ static expr_ty star_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11623,8 +11513,7 @@ static asdl_expr_seq* star_named_expressions_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11671,8 +11560,7 @@ static expr_ty star_named_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11755,8 +11643,7 @@ static expr_ty assignment_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11830,8 +11717,7 @@ static expr_ty named_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11909,8 +11795,7 @@ static expr_ty disjunction_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -11998,8 +11883,7 @@ static expr_ty conjunction_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12087,8 +11971,7 @@ static expr_ty inversion_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12176,8 +12059,7 @@ static expr_ty comparison_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12270,8 +12152,7 @@ static CmpopExprPair* compare_op_bitwise_or_pair_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12480,8 +12361,7 @@ static CmpopExprPair* eq_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12527,8 +12407,7 @@ static CmpopExprPair* noteq_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12574,8 +12453,7 @@ static CmpopExprPair* lte_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12621,8 +12499,7 @@ static CmpopExprPair* lt_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12668,8 +12545,7 @@ static CmpopExprPair* gte_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12715,8 +12591,7 @@ static CmpopExprPair* gt_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12762,8 +12637,7 @@ static CmpopExprPair* notin_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12812,8 +12686,7 @@ static CmpopExprPair* in_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12859,8 +12732,7 @@ static CmpopExprPair* isnot_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12909,8 +12781,7 @@ static CmpopExprPair* is_bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -12958,8 +12829,7 @@ static expr_ty bitwise_or_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, bitwise_or_type, &_res)) { @@ -12993,8 +12863,7 @@ static expr_ty bitwise_or_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -13082,8 +12951,7 @@ static expr_ty bitwise_xor_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, bitwise_xor_type, &_res)) { @@ -13117,8 +12985,7 @@ static expr_ty bitwise_xor_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -13206,8 +13073,7 @@ static expr_ty bitwise_and_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, bitwise_and_type, &_res)) { @@ -13241,8 +13107,7 @@ static expr_ty bitwise_and_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -13330,8 +13195,7 @@ static expr_ty shift_expr_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, shift_expr_type, &_res)) { @@ -13365,8 +13229,7 @@ static expr_ty shift_expr_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -13493,8 +13356,7 @@ static expr_ty sum_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, sum_type, &_res)) { @@ -13528,8 +13390,7 @@ static expr_ty sum_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -13662,8 +13523,7 @@ static expr_ty term_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, term_type, &_res)) { @@ -13697,8 +13557,7 @@ static expr_ty term_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -13940,8 +13799,7 @@ static expr_ty factor_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -14101,8 +13959,7 @@ static expr_ty power_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -14188,8 +14045,7 @@ static expr_ty await_primary_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -14284,8 +14140,7 @@ static expr_ty primary_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, primary_type, &_res)) { @@ -14319,8 +14174,7 @@ static expr_ty primary_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -14526,8 +14380,7 @@ static expr_ty slices_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -14618,8 +14471,7 @@ static expr_ty slice_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -14723,8 +14575,7 @@ static expr_ty atom_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15006,8 +14857,7 @@ static expr_ty group_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15075,8 +14925,7 @@ static expr_ty lambdef_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15146,8 +14995,7 @@ static arguments_ty lambda_params_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15209,8 +15057,7 @@ static arguments_ty lambda_parameters_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15375,8 +15222,7 @@ static asdl_arg_seq* lambda_slash_no_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15456,8 +15302,7 @@ static SlashWithDefault* lambda_slash_with_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15545,8 +15390,7 @@ static StarEtc* lambda_star_etc_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15674,8 +15518,7 @@ static arg_ty lambda_kwds_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15740,8 +15583,7 @@ static arg_ty lambda_param_no_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15813,8 +15655,7 @@ static NameDefaultPair* lambda_param_with_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15892,8 +15733,7 @@ static NameDefaultPair* lambda_param_maybe_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -15971,8 +15811,7 @@ static arg_ty lambda_param_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16033,8 +15872,7 @@ static expr_ty fstring_middle_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16098,8 +15936,7 @@ static expr_ty fstring_replacement_field_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16194,8 +16031,7 @@ static ResultTokenWithMetadata* fstring_conversion_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16241,8 +16077,7 @@ static ResultTokenWithMetadata* fstring_full_format_spec_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16306,8 +16141,7 @@ static expr_ty fstring_format_spec_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16369,8 +16203,7 @@ static expr_ty string_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16413,8 +16246,7 @@ static expr_ty strings_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16480,8 +16312,7 @@ static expr_ty list_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16548,8 +16379,7 @@ static expr_ty tuple_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16616,8 +16446,7 @@ static expr_ty set_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16684,8 +16513,7 @@ static expr_ty dict_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16777,8 +16605,7 @@ static asdl_seq* double_starred_kvpairs_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16825,8 +16652,7 @@ static KeyValuePair* double_starred_kvpair_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16891,8 +16717,7 @@ static KeyValuePair* kvpair_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16941,8 +16766,7 @@ static asdl_comprehension_seq* for_if_clauses_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -16988,8 +16812,7 @@ static comprehension_ty for_if_clause_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17116,8 +16939,7 @@ static expr_ty listcomp_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17206,8 +17028,7 @@ static expr_ty setcomp_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17298,8 +17119,7 @@ static expr_ty genexp_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17388,8 +17208,7 @@ static expr_ty dictcomp_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17478,8 +17297,7 @@ static expr_ty arguments_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17554,8 +17372,7 @@ static expr_ty args_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17655,8 +17472,7 @@ static asdl_seq* kwargs_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17743,8 +17559,7 @@ static expr_ty starred_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17827,8 +17642,7 @@ static KeywordOrStarred* kwarg_or_starred_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -17938,8 +17752,7 @@ static KeywordOrStarred* kwarg_or_double_starred_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18061,8 +17874,7 @@ static expr_ty star_targets_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18156,8 +17968,7 @@ static asdl_expr_seq* star_targets_list_seq_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18204,8 +18015,7 @@ static asdl_expr_seq* star_targets_tuple_seq_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18282,8 +18092,7 @@ static expr_ty star_target_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18374,8 +18183,7 @@ static expr_ty target_with_star_atom_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18516,8 +18324,7 @@ static expr_ty star_atom_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18677,8 +18484,7 @@ static expr_ty single_target_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18772,8 +18578,7 @@ static expr_ty single_subscript_attribute_target_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -18893,8 +18698,7 @@ static expr_ty t_primary_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } expr_ty _res = NULL; if (_PyPegen_is_memoized(p, t_primary_type, &_res)) { @@ -18928,8 +18732,7 @@ static expr_ty t_primary_raw(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -19150,8 +18953,7 @@ static void * t_lookahead_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -19227,8 +19029,7 @@ static asdl_expr_seq* del_targets_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -19278,8 +19079,7 @@ static expr_ty del_target_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -19416,8 +19216,7 @@ static expr_ty del_t_atom_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -19584,8 +19383,7 @@ static asdl_expr_seq* type_expressions_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -19829,8 +19627,7 @@ static Token* func_type_comment_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -19923,8 +19720,7 @@ static void * invalid_arguments_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -20167,8 +19963,7 @@ static void * invalid_kwarg_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -20314,8 +20109,7 @@ expression_without_invalid_rule(Parser *p) int _prev_call_invalid = p->call_invalid_rules; p->call_invalid_rules = 0; if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->call_invalid_rules = _prev_call_invalid; @@ -20434,8 +20228,7 @@ static void * invalid_legacy_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -20486,8 +20279,7 @@ static void * invalid_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -20603,8 +20395,7 @@ static void * invalid_named_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -20730,8 +20521,7 @@ static void * invalid_assignment_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -20936,8 +20726,7 @@ static expr_ty invalid_ann_assign_target_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21024,8 +20813,7 @@ static void * invalid_del_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21071,8 +20859,7 @@ static void * invalid_block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21120,8 +20907,7 @@ static void * invalid_comprehension_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21239,8 +21025,7 @@ static void * invalid_dict_comprehension_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21301,8 +21086,7 @@ static void * invalid_parameters_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21519,8 +21303,7 @@ static void * invalid_default_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21569,8 +21352,7 @@ static void * invalid_star_etc_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21712,8 +21494,7 @@ static void * invalid_kwds_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21828,8 +21609,7 @@ static void * invalid_parameters_helper_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -21897,8 +21677,7 @@ static void * invalid_lambda_parameters_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22117,8 +21896,7 @@ static void * invalid_lambda_parameters_helper_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22183,8 +21961,7 @@ static void * invalid_lambda_star_etc_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22299,8 +22076,7 @@ static void * invalid_lambda_kwds_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22415,8 +22191,7 @@ static void * invalid_double_type_comments_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22471,8 +22246,7 @@ static void * invalid_with_item_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22523,8 +22297,7 @@ static void * invalid_for_target_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22574,8 +22347,7 @@ static void * invalid_group_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22657,8 +22429,7 @@ static void * invalid_import_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22710,8 +22481,7 @@ static void * invalid_import_from_targets_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22762,8 +22532,7 @@ static void * invalid_with_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22862,8 +22631,7 @@ static void * invalid_with_stmt_indent_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -22974,8 +22742,7 @@ static void * invalid_try_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23154,8 +22921,7 @@ static void * invalid_except_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23313,8 +23079,7 @@ static void * invalid_finally_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23367,8 +23132,7 @@ static void * invalid_except_stmt_indent_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23459,8 +23223,7 @@ static void * invalid_except_star_stmt_indent_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23523,8 +23286,7 @@ static void * invalid_match_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23610,8 +23372,7 @@ static void * invalid_case_block_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23703,8 +23464,7 @@ static void * invalid_as_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23785,8 +23545,7 @@ static void * invalid_class_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23836,8 +23595,7 @@ static asdl_pattern_seq* invalid_class_argument_pattern_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23892,8 +23650,7 @@ static void * invalid_if_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -23979,8 +23736,7 @@ static void * invalid_elif_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24064,8 +23820,7 @@ static void * invalid_else_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24118,8 +23873,7 @@ static void * invalid_while_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24205,8 +23959,7 @@ static void * invalid_for_stmt_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24311,8 +24064,7 @@ static void * invalid_def_raw_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24386,8 +24138,7 @@ static void * invalid_class_def_raw_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24482,8 +24233,7 @@ static void * invalid_double_starred_kvpairs_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24592,8 +24342,7 @@ static void * invalid_kvpair_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24700,8 +24449,7 @@ static void * invalid_starred_expression_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -24764,8 +24512,7 @@ static void * invalid_replacement_field_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25125,8 +24872,7 @@ static void * invalid_conversion_character_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25197,8 +24943,7 @@ static asdl_seq * _loop0_1_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25265,8 +25010,7 @@ static asdl_seq * _loop0_2_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25333,8 +25077,7 @@ static asdl_seq * _loop0_3_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25401,8 +25144,7 @@ static asdl_seq * _loop1_4_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25474,8 +25216,7 @@ static asdl_seq * _loop0_6_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25551,8 +25292,7 @@ static asdl_seq * _gather_5_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25593,8 +25333,7 @@ static void * _tmp_7_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25651,8 +25390,7 @@ static void * _tmp_8_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25728,8 +25466,7 @@ static void * _tmp_9_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25786,8 +25523,7 @@ static void * _tmp_10_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25844,8 +25580,7 @@ static void * _tmp_11_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25902,8 +25637,7 @@ static void * _tmp_12_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -25949,8 +25683,7 @@ static void * _tmp_13_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26018,8 +25751,7 @@ static void * _tmp_14_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26065,8 +25797,7 @@ static asdl_seq * _loop1_15_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26138,8 +25869,7 @@ static void * _tmp_16_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26196,8 +25926,7 @@ static void * _tmp_17_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26254,8 +25983,7 @@ static void * _tmp_18_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26301,8 +26029,7 @@ static asdl_seq * _loop0_20_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26378,8 +26105,7 @@ static asdl_seq * _gather_19_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26420,8 +26146,7 @@ static asdl_seq * _loop0_22_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26497,8 +26222,7 @@ static asdl_seq * _gather_21_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26539,8 +26263,7 @@ static void * _tmp_23_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26597,8 +26320,7 @@ static void * _tmp_24_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26644,8 +26366,7 @@ static asdl_seq * _loop0_25_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26712,8 +26433,7 @@ static asdl_seq * _loop1_26_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26785,8 +26505,7 @@ static asdl_seq * _loop0_28_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26862,8 +26581,7 @@ static asdl_seq * _gather_27_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26904,8 +26622,7 @@ static void * _tmp_29_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -26951,8 +26668,7 @@ static asdl_seq * _loop0_31_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27028,8 +26744,7 @@ static asdl_seq * _gather_30_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27070,8 +26785,7 @@ static void * _tmp_32_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27117,8 +26831,7 @@ static asdl_seq * _loop1_33_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27190,8 +26903,7 @@ static void * _tmp_34_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27240,8 +26952,7 @@ static void * _tmp_35_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27287,8 +26998,7 @@ static void * _tmp_36_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27334,8 +27044,7 @@ static asdl_seq * _loop0_37_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27402,8 +27111,7 @@ static asdl_seq * _loop0_38_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27470,8 +27178,7 @@ static asdl_seq * _loop0_39_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27538,8 +27245,7 @@ static asdl_seq * _loop1_40_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27611,8 +27317,7 @@ static asdl_seq * _loop0_41_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27679,8 +27384,7 @@ static asdl_seq * _loop1_42_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27752,8 +27456,7 @@ static asdl_seq * _loop1_43_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27825,8 +27528,7 @@ static asdl_seq * _loop1_44_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27898,8 +27600,7 @@ static asdl_seq * _loop0_45_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -27966,8 +27667,7 @@ static asdl_seq * _loop1_46_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28039,8 +27739,7 @@ static asdl_seq * _loop0_47_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28107,8 +27806,7 @@ static asdl_seq * _loop1_48_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28180,8 +27878,7 @@ static asdl_seq * _loop0_49_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28248,8 +27945,7 @@ static asdl_seq * _loop0_50_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28316,8 +28012,7 @@ static asdl_seq * _loop1_51_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28389,8 +28084,7 @@ static asdl_seq * _loop0_53_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28466,8 +28160,7 @@ static asdl_seq * _gather_52_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28508,8 +28201,7 @@ static asdl_seq * _loop0_55_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28585,8 +28277,7 @@ static asdl_seq * _gather_54_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28627,8 +28318,7 @@ static asdl_seq * _loop0_57_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28704,8 +28394,7 @@ static asdl_seq * _gather_56_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28746,8 +28435,7 @@ static asdl_seq * _loop0_59_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28823,8 +28511,7 @@ static asdl_seq * _gather_58_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28865,8 +28552,7 @@ static void * _tmp_60_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -28942,8 +28628,7 @@ static asdl_seq * _loop1_61_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29015,8 +28700,7 @@ static asdl_seq * _loop1_62_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29088,8 +28772,7 @@ static void * _tmp_63_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29135,8 +28818,7 @@ static void * _tmp_64_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29182,8 +28864,7 @@ static asdl_seq * _loop1_65_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29255,8 +28936,7 @@ static asdl_seq * _loop0_67_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29332,8 +29012,7 @@ static asdl_seq * _gather_66_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29374,8 +29053,7 @@ static void * _tmp_68_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29432,8 +29110,7 @@ static void * _tmp_69_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29490,8 +29167,7 @@ static void * _tmp_70_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29567,8 +29243,7 @@ static void * _tmp_71_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29644,8 +29319,7 @@ static asdl_seq * _loop0_73_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29721,8 +29395,7 @@ static asdl_seq * _gather_72_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29763,8 +29436,7 @@ static asdl_seq * _loop0_75_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29840,8 +29512,7 @@ static asdl_seq * _gather_74_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29882,8 +29553,7 @@ static void * _tmp_76_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -29940,8 +29610,7 @@ static asdl_seq * _loop0_78_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30017,8 +29686,7 @@ static asdl_seq * _gather_77_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30059,8 +29727,7 @@ static asdl_seq * _loop0_80_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30136,8 +29803,7 @@ static asdl_seq * _gather_79_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30178,8 +29844,7 @@ static asdl_seq * _loop0_82_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30255,8 +29920,7 @@ static asdl_seq * _gather_81_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30297,8 +29961,7 @@ static asdl_seq * _loop1_83_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30370,8 +30033,7 @@ static asdl_seq * _loop1_84_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30443,8 +30105,7 @@ static asdl_seq * _loop0_86_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30520,8 +30181,7 @@ static asdl_seq * _gather_85_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30562,8 +30222,7 @@ static asdl_seq * _loop1_87_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30635,8 +30294,7 @@ static asdl_seq * _loop1_88_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30708,8 +30366,7 @@ static asdl_seq * _loop1_89_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30781,8 +30438,7 @@ static void * _tmp_90_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30825,8 +30481,7 @@ static asdl_seq * _loop0_92_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30902,8 +30557,7 @@ static asdl_seq * _gather_91_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30944,8 +30598,7 @@ static void * _tmp_93_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -30991,8 +30644,7 @@ static void * _tmp_94_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31049,8 +30701,7 @@ static void * _tmp_95_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31126,8 +30777,7 @@ static void * _tmp_96_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31184,8 +30834,7 @@ static void * _tmp_97_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31280,8 +30929,7 @@ static void * _tmp_98_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31338,8 +30986,7 @@ static asdl_seq * _loop0_99_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31406,8 +31053,7 @@ static asdl_seq * _loop0_100_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31474,8 +31120,7 @@ static asdl_seq * _loop0_101_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31542,8 +31187,7 @@ static asdl_seq * _loop1_102_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31615,8 +31259,7 @@ static asdl_seq * _loop0_103_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31683,8 +31326,7 @@ static asdl_seq * _loop1_104_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31756,8 +31398,7 @@ static asdl_seq * _loop1_105_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31829,8 +31470,7 @@ static asdl_seq * _loop1_106_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31902,8 +31542,7 @@ static asdl_seq * _loop0_107_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -31970,8 +31609,7 @@ static asdl_seq * _loop1_108_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32043,8 +31681,7 @@ static asdl_seq * _loop0_109_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32111,8 +31748,7 @@ static asdl_seq * _loop1_110_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32184,8 +31820,7 @@ static asdl_seq * _loop0_111_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32252,8 +31887,7 @@ static asdl_seq * _loop1_112_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32325,8 +31959,7 @@ static void * _tmp_113_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32383,8 +32016,7 @@ static asdl_seq * _loop0_114_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32451,8 +32083,7 @@ static asdl_seq * _loop1_115_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32524,8 +32155,7 @@ static void * _tmp_116_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32574,8 +32204,7 @@ static asdl_seq * _loop0_118_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32651,8 +32280,7 @@ static asdl_seq * _gather_117_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32693,8 +32321,7 @@ static asdl_seq * _loop1_119_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32766,8 +32393,7 @@ static asdl_seq * _loop0_120_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32834,8 +32460,7 @@ static asdl_seq * _loop0_121_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32902,8 +32527,7 @@ static void * _tmp_122_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -32962,8 +32586,7 @@ static asdl_seq * _loop0_124_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33040,8 +32663,7 @@ static asdl_seq * _gather_123_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33082,8 +32704,7 @@ static void * _tmp_125_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33129,8 +32750,7 @@ static asdl_seq * _loop0_127_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33206,8 +32826,7 @@ static asdl_seq * _gather_126_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33248,8 +32867,7 @@ static asdl_seq * _loop0_129_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33325,8 +32943,7 @@ static asdl_seq * _gather_128_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33367,8 +32984,7 @@ static asdl_seq * _loop0_131_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33444,8 +33060,7 @@ static asdl_seq * _gather_130_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33486,8 +33101,7 @@ static asdl_seq * _loop0_133_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33563,8 +33177,7 @@ static asdl_seq * _gather_132_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33605,8 +33218,7 @@ static asdl_seq * _loop0_134_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33673,8 +33285,7 @@ static asdl_seq * _loop0_136_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33750,8 +33361,7 @@ static asdl_seq * _gather_135_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33792,8 +33402,7 @@ static asdl_seq * _loop1_137_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33865,8 +33474,7 @@ static void * _tmp_138_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33906,8 +33514,7 @@ static asdl_seq * _loop0_140_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -33983,8 +33590,7 @@ static asdl_seq * _gather_139_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34025,8 +33631,7 @@ static asdl_seq * _loop0_142_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34102,8 +33707,7 @@ static asdl_seq * _gather_141_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34144,8 +33748,7 @@ static asdl_seq * _loop0_144_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34221,8 +33824,7 @@ static asdl_seq * _gather_143_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34263,8 +33865,7 @@ static asdl_seq * _loop0_146_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34340,8 +33941,7 @@ static asdl_seq * _gather_145_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34382,8 +33982,7 @@ static asdl_seq * _loop0_148_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34459,8 +34058,7 @@ static asdl_seq * _gather_147_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34501,8 +34099,7 @@ static void * _tmp_149_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34543,8 +34140,7 @@ static void * _tmp_150_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34604,8 +34200,7 @@ static void * _tmp_151_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34646,8 +34241,7 @@ static void * _tmp_152_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34704,8 +34298,7 @@ static void * _tmp_153_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34781,8 +34374,7 @@ static void * _tmp_154_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34823,8 +34415,7 @@ static void * _tmp_155_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34884,8 +34475,7 @@ static void * _tmp_156_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -34942,8 +34532,7 @@ static void * _tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35000,8 +34589,7 @@ static void * _tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35058,8 +34646,7 @@ static void * _tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35192,8 +34779,7 @@ static void * _tmp_160_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35250,8 +34836,7 @@ static asdl_seq * _loop0_161_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35318,8 +34903,7 @@ static asdl_seq * _loop0_162_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35386,8 +34970,7 @@ static asdl_seq * _loop0_163_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35454,8 +35037,7 @@ static void * _tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35512,8 +35094,7 @@ static void * _tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35589,8 +35170,7 @@ static void * _tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35647,8 +35227,7 @@ static void * _tmp_167_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35705,8 +35284,7 @@ static void * _tmp_168_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35763,8 +35341,7 @@ static asdl_seq * _loop0_169_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35831,8 +35408,7 @@ static asdl_seq * _loop0_170_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35899,8 +35475,7 @@ static asdl_seq * _loop0_171_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -35967,8 +35542,7 @@ static asdl_seq * _loop1_172_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36040,8 +35614,7 @@ static void * _tmp_173_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36098,8 +35671,7 @@ static asdl_seq * _loop0_174_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36166,8 +35738,7 @@ static void * _tmp_175_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36224,8 +35795,7 @@ static asdl_seq * _loop0_176_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36292,8 +35862,7 @@ static asdl_seq * _loop1_177_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36365,8 +35934,7 @@ static void * _tmp_178_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36423,8 +35991,7 @@ static void * _tmp_179_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36484,8 +36051,7 @@ static void * _tmp_180_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36542,8 +36108,7 @@ static asdl_seq * _loop0_181_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36610,8 +36175,7 @@ static void * _tmp_182_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36668,8 +36232,7 @@ static void * _tmp_183_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36745,8 +36308,7 @@ static asdl_seq * _loop1_184_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36818,8 +36380,7 @@ static void * _tmp_185_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36876,8 +36437,7 @@ static asdl_seq * _loop0_186_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -36944,8 +36504,7 @@ static asdl_seq * _loop0_187_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37012,8 +36571,7 @@ static asdl_seq * _loop0_188_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37080,8 +36638,7 @@ static asdl_seq * _loop0_190_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37157,8 +36714,7 @@ static asdl_seq * _gather_189_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37199,8 +36755,7 @@ static void * _tmp_191_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37257,8 +36812,7 @@ static asdl_seq * _loop0_192_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37325,8 +36879,7 @@ static void * _tmp_193_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37383,8 +36936,7 @@ static asdl_seq * _loop0_194_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37451,8 +37003,7 @@ static asdl_seq * _loop1_195_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37524,8 +37075,7 @@ static asdl_seq * _loop1_196_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37597,8 +37147,7 @@ static void * _tmp_197_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37658,8 +37207,7 @@ static void * _tmp_198_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37716,8 +37264,7 @@ static asdl_seq * _loop0_199_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37784,8 +37331,7 @@ static void * _tmp_200_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37842,8 +37388,7 @@ static void * _tmp_201_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37919,8 +37464,7 @@ static void * _tmp_202_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -37996,8 +37540,7 @@ static asdl_seq * _loop0_204_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38073,8 +37616,7 @@ static asdl_seq * _gather_203_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38115,8 +37657,7 @@ static asdl_seq * _loop0_206_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38192,8 +37733,7 @@ static asdl_seq * _gather_205_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38234,8 +37774,7 @@ static asdl_seq * _loop0_208_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38311,8 +37850,7 @@ static asdl_seq * _gather_207_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38353,8 +37891,7 @@ static asdl_seq * _loop0_210_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38430,8 +37967,7 @@ static asdl_seq * _gather_209_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38472,8 +38008,7 @@ static asdl_seq * _loop0_212_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38549,8 +38084,7 @@ static asdl_seq * _gather_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38591,8 +38125,7 @@ static void * _tmp_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38649,8 +38182,7 @@ static asdl_seq * _loop0_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38717,8 +38249,7 @@ static asdl_seq * _loop1_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38790,8 +38321,7 @@ static void * _tmp_216_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38832,8 +38362,7 @@ static asdl_seq * _loop0_217_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38900,8 +38429,7 @@ static asdl_seq * _loop1_218_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -38973,8 +38501,7 @@ static void * _tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39016,8 +38543,7 @@ static void * _tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39058,8 +38584,7 @@ static void * _tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39100,8 +38625,7 @@ static void * _tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39158,8 +38682,7 @@ static void * _tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39200,8 +38723,7 @@ static void * _tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39242,8 +38764,7 @@ static void * _tmp_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39284,8 +38805,7 @@ static void * _tmp_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39326,8 +38846,7 @@ static void * _tmp_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39372,8 +38891,7 @@ static void * _tmp_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39418,8 +38936,7 @@ static asdl_seq * _loop0_230_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39495,8 +39012,7 @@ static asdl_seq * _gather_229_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39537,8 +39053,7 @@ static void * _tmp_231_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39595,8 +39110,7 @@ static void * _tmp_232_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39653,8 +39167,7 @@ static void * _tmp_233_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39711,8 +39224,7 @@ static void * _tmp_234_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39769,8 +39281,7 @@ static void * _tmp_235_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39865,8 +39376,7 @@ static void * _tmp_236_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -39923,8 +39433,7 @@ static void * _tmp_237_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40000,8 +39509,7 @@ static void * _tmp_238_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40058,8 +39566,7 @@ static void * _tmp_239_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40116,8 +39623,7 @@ static void * _tmp_240_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40158,8 +39664,7 @@ static void * _tmp_241_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40216,8 +39721,7 @@ static void * _tmp_242_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40274,8 +39778,7 @@ static void * _tmp_243_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40316,8 +39819,7 @@ static asdl_seq * _loop0_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40384,8 +39886,7 @@ static void * _tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40442,8 +39943,7 @@ static void * _tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40484,8 +39984,7 @@ static void * _tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40542,8 +40041,7 @@ static void * _tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40589,8 +40087,7 @@ static void * _tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40647,8 +40144,7 @@ static void * _tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40705,8 +40201,7 @@ static void * _tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40755,8 +40250,7 @@ static void * _tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40802,8 +40296,7 @@ static void * _tmp_253_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40849,8 +40342,7 @@ static void * _tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40896,8 +40388,7 @@ static void * _tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -40943,8 +40434,7 @@ static void * _tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41001,8 +40491,7 @@ static void * _tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41059,8 +40548,7 @@ static void * _tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41106,8 +40594,7 @@ static void * _tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41153,8 +40640,7 @@ static void * _tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41213,8 +40699,7 @@ static void * _tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41260,8 +40745,7 @@ static void * _tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41307,8 +40791,7 @@ static void * _tmp_263_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41349,8 +40832,7 @@ static void * _tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41391,8 +40873,7 @@ static void * _tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41449,8 +40930,7 @@ static void * _tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41507,8 +40987,7 @@ static void * _tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41550,8 +41029,7 @@ static void * _tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41593,8 +41071,7 @@ static void * _tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41636,8 +41113,7 @@ static void * _tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41679,8 +41155,7 @@ static void * _tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41721,8 +41196,7 @@ static void * _tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41781,8 +41255,7 @@ static void * _tmp_273_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41823,8 +41296,7 @@ static void * _tmp_274_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41865,8 +41337,7 @@ static void * _tmp_275_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; @@ -41907,8 +41378,7 @@ static void * _tmp_276_rule(Parser *p) { if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); + _Pypegen_stack_overflow(p); } if (p->error_indicator) { p->level--; diff --git a/Parser/pegen.h b/Parser/pegen.h index fe13d10e6b83e3..a8bfa786b96115 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -168,6 +168,8 @@ void *_PyPegen_raise_error_known_location(Parser *p, PyObject *errtype, Py_ssize_t end_lineno, Py_ssize_t end_col_offset, const char *errmsg, va_list va); void _Pypegen_set_syntax_error(Parser* p, Token* last_token); +void _Pypegen_stack_overflow(Parser *p); + Py_LOCAL_INLINE(void *) RAISE_ERROR_KNOWN_LOCATION(Parser *p, PyObject *errtype, Py_ssize_t lineno, Py_ssize_t col_offset, diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index af529057f50e70..b2fca019f6819c 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -453,3 +453,11 @@ _Pypegen_set_syntax_error(Parser* p, Token* last_token) { // generic SyntaxError we just raised if errors are found. _PyPegen_tokenize_full_source_to_check_for_errors(p); } + +void +_Pypegen_stack_overflow(Parser *p) +{ + p->error_indicator = 1; + PyErr_SetString(PyExc_MemoryError, + "Parser stack overflowed - Python source too complex to parse"); +} diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index f57b6275f671d3..301949bdae96fe 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -375,8 +375,7 @@ def __init__( def add_level(self) -> None: self.print("if (p->level++ == MAXSTACK) {") with self.indent(): - self.print("p->error_indicator = 1;") - self.print("PyErr_NoMemory();") + self.print("_Pypegen_stack_overflow(p);") self.print("}") def remove_level(self) -> None: From 4ee945479243125ea5c50be526e754df4ab9c749 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 07:15:34 -0700 Subject: [PATCH 0609/1206] [3.12] gh-107901: Fix missing line number on BACKWARD_JUMP at the end of a for loop (GH-108242) (#108275) gh-107901: Fix missing line number on BACKWARD_JUMP at the end of a for loop (GH-108242) (cherry picked from commit a1cc74c4eebc55795877eb3be019a1bec34402f8) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/test/test_compile.py | 14 ++++++++++++++ .../2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst | 1 + Python/flowgraph.c | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 142d3f5c125b6d..55e55c7d2884d0 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1031,6 +1031,20 @@ async def test(aseq): code_lines = self.get_code_lines(test.__code__) self.assertEqual(expected_lines, code_lines) + def test_lineno_of_backward_jump(self): + # Issue gh-107901 + def f(): + for i in x: + if y: + pass + + linenos = list(inst.positions.lineno + for inst in dis.get_instructions(f.__code__) + if inst.opname == 'JUMP_BACKWARD') + + self.assertTrue(len(linenos) > 0) + self.assertTrue(all(l is not None for l in linenos)) + def test_big_dict_literal(self): # The compiler has a flushing point in "compiler_dict" that calls compiles # a portion of the dictionary literal when the loop that iterates over the items diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst new file mode 100644 index 00000000000000..112e093736dd5d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst @@ -0,0 +1 @@ +Fix missing line number on :opcode:`JUMP_BACKWARD` at the end of a for loop. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index f8039a4985d948..4fe581beb5fc63 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -450,7 +450,7 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { if (backwards_jump == NULL) { return ERROR; } - basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION); + basicblock_addop(backwards_jump, JUMP, target->b_label.id, last->i_loc); backwards_jump->b_instr[0].i_target = target; last->i_opcode = reversed_opcode; last->i_target = b->b_next; From a2b680d9e994973e7a5a53671e1a733882d29f28 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 07:15:59 -0700 Subject: [PATCH 0610/1206] [3.12] gh-106971: Docs: Add missing issue reference (GH-106992) (#108283) gh-106971: Docs: Add missing issue reference (GH-106992) (cherry picked from commit c556f9a3c9af48c9af9e1f298be638553a6c886e) Co-authored-by: Junya Fukuda Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index bf9eadcaefc853..2084f4ed0b9bcb 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1201,7 +1201,7 @@ Pending Removal in Python 3.14 is deprecated and will raise an exception in Python 3.14. * Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable - bases using the C API. + bases using the C API (:gh:`95388`). * ``__package__`` and ``__cached__`` will cease to be set or taken into consideration by the import system (:gh:`97879`). From e5d779c0e296ed6247d911231dad39c16dec0172 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 07:16:31 -0700 Subject: [PATCH 0611/1206] [3.12] gh-107298: Fix numerous ref errors and typos in the C API docs (GH-108258) (#108284) gh-107298: Fix numerous ref errors and typos in the C API docs (GH-108258) (cherry picked from commit d7202e4879bf4e7e00a69500ddcb3143864139b4) Co-authored-by: Serhiy Storchaka --- Doc/c-api/exceptions.rst | 14 +++++++++----- Doc/c-api/init_config.rst | 4 ++++ Doc/c-api/module.rst | 4 ++++ Doc/c-api/unicode.rst | 2 +- Doc/extending/newtypes.rst | 2 +- Doc/tools/.nitignore | 1 - Doc/whatsnew/2.2.rst | 12 ++++++------ Doc/whatsnew/2.3.rst | 2 +- Doc/whatsnew/2.4.rst | 2 +- Doc/whatsnew/2.5.rst | 10 +++++----- Doc/whatsnew/2.6.rst | 8 ++++---- Doc/whatsnew/2.7.rst | 10 +++++----- Doc/whatsnew/3.0.rst | 4 ++-- Doc/whatsnew/3.1.rst | 4 ++-- Doc/whatsnew/3.10.rst | 4 ++-- Doc/whatsnew/3.11.rst | 26 +++++++++++++------------- Doc/whatsnew/3.2.rst | 14 +++++++------- Doc/whatsnew/3.3.rst | 4 ++-- Doc/whatsnew/3.5.rst | 4 ++-- Doc/whatsnew/3.8.rst | 16 ++++++++-------- Doc/whatsnew/3.9.rst | 12 ++++++------ Misc/NEWS.d/3.11.0a1.rst | 18 +++++++++--------- Misc/NEWS.d/3.8.0a1.rst | 4 ++-- Misc/NEWS.d/3.8.0a4.rst | 2 +- Misc/NEWS.d/3.8.0b1.rst | 2 +- Misc/NEWS.d/3.9.0a1.rst | 6 +++--- Misc/NEWS.d/3.9.0a5.rst | 4 ++-- 27 files changed, 103 insertions(+), 92 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index f1d6c995188abb..6e2ac0a40a5f1b 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -222,17 +222,21 @@ For convenience, some of these functions will always return a .. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilename(int ierr, const char *filename) - Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, but the - filename is given as a C string. *filename* is decoded from the filesystem - encoding (:func:`os.fsdecode`). + Similar to :c:func:`PyErr_SetFromWindowsErr`, with the additional behavior + that if *filename* is not ``NULL``, it is decoded from the filesystem + encoding (:func:`os.fsdecode`) and passed to the constructor of + :exc:`OSError` as a third parameter to be used to define the + :attr:`!filename` attribute of the exception instance. .. availability:: Windows. .. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObject(PyObject *type, int ierr, PyObject *filename) - Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, with an - additional parameter specifying the exception type to be raised. + Similar to :c:func:`PyErr_SetExcFromWindowsErr`, with the additional behavior + that if *filename* is not ``NULL``, it is passed to the constructor of + :exc:`OSError` as a third parameter to be used to define the + :attr:`!filename` attribute of the exception instance. .. availability:: Windows. diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 96705c804f11d7..7c5465b5bfa204 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -82,6 +82,8 @@ PyWideStringList If *length* is non-zero, *items* must be non-``NULL`` and all strings must be non-``NULL``. + .. c:namespace:: NULL + Methods: .. c:function:: PyStatus PyWideStringList_Append(PyWideStringList *list, const wchar_t *item) @@ -101,6 +103,8 @@ PyWideStringList Python must be preinitialized to call this function. + .. c:namespace:: PyWideStringList + Structure fields: .. c:member:: Py_ssize_t length diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index cb6b0a47681e95..f941f0c7d42b2b 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -338,6 +338,7 @@ The available slot types are: The *value* pointer of this slot must point to a function of the signature: .. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def) + :noindex: The function receives a :py:class:`~importlib.machinery.ModuleSpec` instance, as defined in :PEP:`451`, and the module definition. @@ -372,6 +373,7 @@ The available slot types are: The signature of the function is: .. c:function:: int exec_module(PyObject* module) + :noindex: If multiple ``Py_mod_exec`` slots are specified, they are processed in the order they appear in the *m_slots* array. @@ -380,6 +382,8 @@ The available slot types are: Specifies one of the following values: + .. c:namespace:: NULL + .. c:macro:: Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED The module does not support being imported in subinterpreters. diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 586ad182e3a459..c10c15111cd908 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -1299,7 +1299,7 @@ the user settings on the machine running the codec. Encode the Unicode object using the specified code page and return a Python bytes object. Return ``NULL`` if an exception was raised by the codec. Use - :c:macro:`CP_ACP` code page to get the MBCS encoder. + :c:macro:`!CP_ACP` code page to get the MBCS encoder. .. versionadded:: 3.3 diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 386b3c8f4452c3..9f166eb8a4c3ff 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -298,7 +298,7 @@ have an associated doc string simply by providing the text in the table. An application can use the introspection API to retrieve the descriptor from the class object, and get the doc string using its :attr:`__doc__` attribute. -As with the :c:member:`~PyTypeObject.tp_methods` table, a sentinel entry with a :c:member:`~PyMethodDef.name` value +As with the :c:member:`~PyTypeObject.tp_methods` table, a sentinel entry with a :c:member:`~PyMethodDef.ml_name` value of ``NULL`` is required. .. XXX Descriptors need to be explained in more detail somewhere, but not here. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 4eb466a909a495..2ba307df21d853 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -21,7 +21,6 @@ Doc/c-api/structures.rst Doc/c-api/sys.rst Doc/c-api/type.rst Doc/c-api/typeobj.rst -Doc/c-api/unicode.rst Doc/extending/extending.rst Doc/extending/newtypes.rst Doc/faq/gui.rst diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 7de48a40263034..d9ead57413cbbf 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -1078,17 +1078,17 @@ code, none of the changes described here will affect you very much. To upgrade an extension module to the new API, perform the following steps: -* Rename :c:func:`Py_TPFLAGS_GC` to :c:func:`PyTPFLAGS_HAVE_GC`. +* Rename :c:macro:`!Py_TPFLAGS_GC` to :c:macro:`Py_TPFLAGS_HAVE_GC`. * Use :c:func:`PyObject_GC_New` or :c:func:`PyObject_GC_NewVar` to allocate objects, and :c:func:`PyObject_GC_Del` to deallocate them. -* Rename :c:func:`PyObject_GC_Init` to :c:func:`PyObject_GC_Track` and - :c:func:`PyObject_GC_Fini` to :c:func:`PyObject_GC_UnTrack`. +* Rename :c:func:`!PyObject_GC_Init` to :c:func:`PyObject_GC_Track` and + :c:func:`!PyObject_GC_Fini` to :c:func:`PyObject_GC_UnTrack`. -* Remove :c:func:`PyGC_HEAD_SIZE` from object size calculations. +* Remove :c:macro:`!PyGC_HEAD_SIZE` from object size calculations. -* Remove calls to :c:func:`PyObject_AS_GC` and :c:func:`PyObject_FROM_GC`. +* Remove calls to :c:func:`!PyObject_AS_GC` and :c:func:`!PyObject_FROM_GC`. * A new ``et`` format sequence was added to :c:func:`PyArg_ParseTuple`; ``et`` takes both a parameter and an encoding name, and converts the parameter to the @@ -1219,7 +1219,7 @@ Some of the more notable changes are: operator, but these features were rarely used and therefore buggy. The :meth:`tolist` method and the :attr:`start`, :attr:`stop`, and :attr:`step` attributes are also being deprecated. At the C level, the fourth argument to - the :c:func:`PyRange_New` function, ``repeat``, has also been deprecated. + the :c:func:`!PyRange_New` function, ``repeat``, has also been deprecated. * There were a bunch of patches to the dictionary implementation, mostly to fix potential core dumps if a dictionary contains objects that sneakily changed diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index a9c44d501701c8..c06fd9582627e2 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1897,7 +1897,7 @@ Changes to Python's build process and to the C API include: but will also mean that you can't get help for Python's built-ins. (Contributed by Gustavo Niemeyer.) -* The :c:func:`PyArg_NoArgs` macro is now deprecated, and code that uses it +* The :c:func:`!PyArg_NoArgs` macro is now deprecated, and code that uses it should be changed. For Python 2.2 and later, the method definition table can specify the :c:macro:`METH_NOARGS` flag, signalling that there are no arguments, and the argument checking can then be removed. If compatibility with pre-2.2 diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 4272928fb67894..ceda03afd5f4f6 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -1468,7 +1468,7 @@ Some of the changes to Python's build process and to the C API are: *X* is a NaN. (Contributed by Tim Peters.) * C code can avoid unnecessary locking by using the new - :c:func:`PyEval_ThreadsInitialized` function to tell if any thread operations + :c:func:`!PyEval_ThreadsInitialized` function to tell if any thread operations have been performed. If this function returns false, no lock operations are needed. (Contributed by Nick Coghlan.) diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index a15eefc2953f40..f58b3ede27facc 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -2119,9 +2119,9 @@ Changes to Python's build process and to the C API include: the various AST nodes in :file:`Parser/Python.asdl`. A Python script reads this file and generates a set of C structure definitions in :file:`Include/Python-ast.h`. The :c:func:`PyParser_ASTFromString` and - :c:func:`PyParser_ASTFromFile`, defined in :file:`Include/pythonrun.h`, take + :c:func:`!PyParser_ASTFromFile`, defined in :file:`Include/pythonrun.h`, take Python source as input and return the root of an AST representing the contents. - This AST can then be turned into a code object by :c:func:`PyAST_Compile`. For + This AST can then be turned into a code object by :c:func:`!PyAST_Compile`. For more information, read the source code, and then ask questions on python-dev. The AST code was developed under Jeremy Hylton's management, and implemented by @@ -2172,7 +2172,7 @@ Changes to Python's build process and to the C API include: ``Py_LOCAL(type)`` declares the function as returning a value of the specified *type* and uses a fast-calling qualifier. ``Py_LOCAL_INLINE(type)`` does the same thing and also requests the - function be inlined. If :c:func:`PY_LOCAL_AGGRESSIVE` is defined before + function be inlined. If macro :c:macro:`!PY_LOCAL_AGGRESSIVE` is defined before :file:`python.h` is included, a set of more aggressive optimizations are enabled for the module; you should benchmark the results to find out if these optimizations actually make the code faster. (Contributed by Fredrik Lundh at @@ -2181,7 +2181,7 @@ Changes to Python's build process and to the C API include: * ``PyErr_NewException(name, base, dict)`` can now accept a tuple of base classes as its *base* argument. (Contributed by Georg Brandl.) -* The :c:func:`PyErr_Warn` function for issuing warnings is now deprecated in +* The :c:func:`!PyErr_Warn` function for issuing warnings is now deprecated in favour of ``PyErr_WarnEx(category, message, stacklevel)`` which lets you specify the number of stack frames separating this function and the caller. A *stacklevel* of 1 is the function calling :c:func:`PyErr_WarnEx`, 2 is the @@ -2191,7 +2191,7 @@ Changes to Python's build process and to the C API include: compiled with a C++ compiler without errors. (Implemented by Anthony Baxter, Martin von Löwis, Skip Montanaro.) -* The :c:func:`PyRange_New` function was removed. It was never documented, never +* The :c:func:`!PyRange_New` function was removed. It was never documented, never used in the core code, and had dangerously lax error checking. In the unlikely case that your extensions were using it, you can replace it by something like the following:: diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 563fa461d2a868..b975aea7d6894a 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -977,7 +977,7 @@ can be used to include Unicode characters:: print len(s) # 12 Unicode characters At the C level, Python 3.0 will rename the existing 8-bit -string type, called :c:type:`PyStringObject` in Python 2.x, +string type, called :c:type:`!PyStringObject` in Python 2.x, to :c:type:`PyBytesObject`. Python 2.6 uses ``#define`` to support using the names :c:func:`PyBytesObject`, :c:func:`PyBytes_Check`, :c:func:`PyBytes_FromStringAndSize`, @@ -3012,11 +3012,11 @@ Changes to Python's build process and to the C API include: bug occurred if one thread closed a file object while another thread was reading from or writing to the object. In 2.6 file objects have a reference count, manipulated by the - :c:func:`PyFile_IncUseCount` and :c:func:`PyFile_DecUseCount` + :c:func:`!PyFile_IncUseCount` and :c:func:`!PyFile_DecUseCount` functions. File objects can't be closed unless the reference count - is zero. :c:func:`PyFile_IncUseCount` should be called while the GIL + is zero. :c:func:`!PyFile_IncUseCount` should be called while the GIL is still held, before carrying out an I/O operation using the - ``FILE *`` pointer, and :c:func:`PyFile_DecUseCount` should be called + ``FILE *`` pointer, and :c:func:`!PyFile_DecUseCount` should be called immediately after the GIL is re-acquired. (Contributed by Antoine Pitrou and Gregory P. Smith.) diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 76beb4d746a190..eda6c8be38ad08 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2152,7 +2152,7 @@ Changes to Python's build process and to the C API include: * New function: stemming from the rewrite of string-to-float conversion, a new :c:func:`PyOS_string_to_double` function was added. The old - :c:func:`PyOS_ascii_strtod` and :c:func:`PyOS_ascii_atof` functions + :c:func:`!PyOS_ascii_strtod` and :c:func:`!PyOS_ascii_atof` functions are now deprecated. * New function: :c:func:`PySys_SetArgvEx` sets the value of @@ -2195,13 +2195,13 @@ Changes to Python's build process and to the C API include: .. XXX these macros don't seem to be described in the c-api docs. -* Removed function: :c:macro:`PyEval_CallObject` is now only available +* Removed function: :c:func:`!PyEval_CallObject` is now only available as a macro. A function version was being kept around to preserve ABI linking compatibility, but that was in 1997; it can certainly be deleted by now. (Removed by Antoine Pitrou; :issue:`8276`.) -* New format codes: the :c:func:`PyFormat_FromString`, - :c:func:`PyFormat_FromStringV`, and :c:func:`PyErr_Format` functions now +* New format codes: the :c:func:`!PyString_FromFormat`, + :c:func:`!PyString_FromFormatV`, and :c:func:`PyErr_Format` functions now accept ``%lld`` and ``%llu`` format codes for displaying C's :c:expr:`long long` types. (Contributed by Mark Dickinson; :issue:`7228`.) @@ -2540,7 +2540,7 @@ For C extensions: instead of triggering a :exc:`DeprecationWarning` (:issue:`5080`). * Use the new :c:func:`PyOS_string_to_double` function instead of the old - :c:func:`PyOS_ascii_strtod` and :c:func:`PyOS_ascii_atof` functions, + :c:func:`!PyOS_ascii_strtod` and :c:func:`!PyOS_ascii_atof` functions, which are now deprecated. For applications that embed Python: diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index 4f8b05efd44643..4bd53fb14ccb53 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -865,8 +865,8 @@ to the C API. * No more C API support for restricted execution. -* :c:func:`PyNumber_Coerce`, :c:func:`PyNumber_CoerceEx`, - :c:func:`PyMember_Get`, and :c:func:`PyMember_Set` C APIs are removed. +* :c:func:`!PyNumber_Coerce`, :c:func:`!PyNumber_CoerceEx`, + :c:func:`!PyMember_Get`, and :c:func:`!PyMember_Set` C APIs are removed. * New C API :c:func:`PyImport_ImportModuleNoBlock`, works like :c:func:`PyImport_ImportModule` but won't block on the import lock diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst index ceef622f9f8daa..cc6619c53cd626 100644 --- a/Doc/whatsnew/3.1.rst +++ b/Doc/whatsnew/3.1.rst @@ -501,12 +501,12 @@ Changes to Python's build process and to the C API include: (Contributed by Mark Dickinson and Lisandro Dalcrin; :issue:`5175`.) -* Deprecated :c:func:`PyNumber_Int`. Use :c:func:`PyNumber_Long` instead. +* Deprecated :c:func:`!PyNumber_Int`. Use :c:func:`PyNumber_Long` instead. (Contributed by Mark Dickinson; :issue:`4910`.) * Added a new :c:func:`PyOS_string_to_double` function to replace the - deprecated functions :c:func:`PyOS_ascii_strtod` and :c:func:`PyOS_ascii_atof`. + deprecated functions :c:func:`!PyOS_ascii_strtod` and :c:func:`!PyOS_ascii_atof`. (Contributed by Mark Dickinson; :issue:`5914`.) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 92d23462acc57c..47a6f3e1c0839b 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1819,8 +1819,8 @@ Removed into their code. (Contributed by Dong-hee Na and Terry J. Reedy in :issue:`42299`.) -* Removed the :c:func:`PyModule_GetWarningsModule` function that was useless - now due to the _warnings module was converted to a builtin module in 2.6. +* Removed the :c:func:`!PyModule_GetWarningsModule` function that was useless + now due to the :mod:`!_warnings` module was converted to a builtin module in 2.6. (Contributed by Hai Shi in :issue:`42599`.) * Remove deprecated aliases to :ref:`collections-abstract-base-classes` from diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 0ac8d02ab15c8c..6112e807a1225e 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2216,7 +2216,7 @@ New Features * :c:func:`PyBuffer_SizeFromFormat` * :c:func:`PyBuffer_ToContiguous` * :c:func:`PyBuffer_FromContiguous` - * :c:func:`PyBuffer_CopyData` + * :c:func:`PyObject_CopyData` * :c:func:`PyBuffer_IsContiguous` * :c:func:`PyBuffer_FillContiguousStrides` * :c:func:`PyBuffer_FillInfo` @@ -2562,18 +2562,18 @@ Deprecated * Deprecate the following functions to configure the Python initialization: - * :c:func:`PySys_AddWarnOptionUnicode` - * :c:func:`PySys_AddWarnOption` - * :c:func:`PySys_AddXOption` - * :c:func:`PySys_HasWarnOptions` - * :c:func:`PySys_SetArgvEx` - * :c:func:`PySys_SetArgv` - * :c:func:`PySys_SetPath` - * :c:func:`Py_SetPath` - * :c:func:`Py_SetProgramName` - * :c:func:`Py_SetPythonHome` - * :c:func:`Py_SetStandardStreamEncoding` - * :c:func:`_Py_SetProgramFullPath` + * :c:func:`!PySys_AddWarnOptionUnicode` + * :c:func:`!PySys_AddWarnOption` + * :c:func:`!PySys_AddXOption` + * :c:func:`!PySys_HasWarnOptions` + * :c:func:`!PySys_SetArgvEx` + * :c:func:`!PySys_SetArgv` + * :c:func:`!PySys_SetPath` + * :c:func:`!Py_SetPath` + * :c:func:`!Py_SetProgramName` + * :c:func:`!Py_SetPythonHome` + * :c:func:`!Py_SetStandardStreamEncoding` + * :c:func:`!_Py_SetProgramFullPath` Use the new :c:type:`PyConfig` API of the :ref:`Python Initialization Configuration ` instead (:pep:`587`). diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index ec554aacb096cf..ba1cb4ae006234 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -2569,7 +2569,7 @@ Changes to Python's build process and to the C API include: to set :data:`sys.argv` without also modifying :data:`sys.path` (:issue:`5753`). -* :c:macro:`PyEval_CallObject` is now only available in macro form. The +* :c:func:`!PyEval_CallObject` is now only available in macro form. The function declaration, which was kept for backwards compatibility reasons, is now removed -- the macro was introduced in 1997 (:issue:`8276`). @@ -2731,15 +2731,15 @@ require changes to your code: (Contributed by Antoine Pitrou, :issue:`10272`.) -* The misleading functions :c:func:`PyEval_AcquireLock()` and - :c:func:`PyEval_ReleaseLock()` have been officially deprecated. The - thread-state aware APIs (such as :c:func:`PyEval_SaveThread()` - and :c:func:`PyEval_RestoreThread()`) should be used instead. +* The misleading functions :c:func:`!PyEval_AcquireLock` and + :c:func:`!PyEval_ReleaseLock` have been officially deprecated. The + thread-state aware APIs (such as :c:func:`PyEval_SaveThread` + and :c:func:`PyEval_RestoreThread`) should be used instead. * Due to security risks, :func:`asyncore.handle_accept` has been deprecated, and a new function, :func:`asyncore.handle_accepted`, was added to replace it. (Contributed by Giampaolo Rodola in :issue:`6706`.) -* Due to the new :term:`GIL` implementation, :c:func:`PyEval_InitThreads()` - cannot be called before :c:func:`Py_Initialize()` anymore. +* Due to the new :term:`GIL` implementation, :c:func:`!PyEval_InitThreads` + cannot be called before :c:func:`Py_Initialize` anymore. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 8cf7ad57475b29..8d2bd0a2ae8da0 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2304,7 +2304,7 @@ Functions and macros manipulating Py_UNICODE* strings: Encoders: -* :c:func:`!PyUnicode_Encode`: use :c:func:`PyUnicode_AsEncodedObject` +* :c:func:`!PyUnicode_Encode`: use :c:func:`!PyUnicode_AsEncodedObject` * :c:func:`!PyUnicode_EncodeUTF7` * :c:func:`!PyUnicode_EncodeUTF8`: use :c:func:`PyUnicode_AsUTF8` or :c:func:`PyUnicode_AsUTF8String` @@ -2462,7 +2462,7 @@ Porting C code -------------- * In the course of changes to the buffer API the undocumented - :c:member:`~Py_buffer.smalltable` member of the + :c:member:`!smalltable` member of the :c:type:`Py_buffer` structure has been removed and the layout of the :c:type:`PyMemoryViewObject` has changed. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 002d829e78bb3a..3c0d8d665c3949 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -2512,7 +2512,7 @@ Changes in the Python API Changes in the C API -------------------- -* The undocumented :c:member:`~PyMemoryViewObject.format` member of the +* The undocumented :c:member:`!format` member of the (non-public) :c:type:`PyMemoryViewObject` structure has been removed. All extensions relying on the relevant parts in ``memoryobject.h`` must be rebuilt. @@ -2520,7 +2520,7 @@ Changes in the C API * The :c:type:`PyMemAllocator` structure was renamed to :c:type:`PyMemAllocatorEx` and a new ``calloc`` field was added. -* Removed non-documented macro :c:macro:`PyObject_REPR` which leaked references. +* Removed non-documented macro :c:macro:`!PyObject_REPR()` which leaked references. Use format character ``%R`` in :c:func:`PyUnicode_FromFormat`-like functions to format the :func:`repr` of the object. (Contributed by Serhiy Storchaka in :issue:`22453`.) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 3397de5d3e8c47..329fe8cb410dab 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1574,12 +1574,12 @@ Build and C API Changes * :c:func:`Py_INCREF`, :c:func:`Py_DECREF` * :c:func:`Py_XINCREF`, :c:func:`Py_XDECREF` * :c:func:`PyObject_INIT`, :c:func:`PyObject_INIT_VAR` - * Private functions: :c:func:`_PyObject_GC_TRACK`, - :c:func:`_PyObject_GC_UNTRACK`, :c:func:`_Py_Dealloc` + * Private functions: :c:func:`!_PyObject_GC_TRACK`, + :c:func:`!_PyObject_GC_UNTRACK`, :c:func:`!_Py_Dealloc` (Contributed by Victor Stinner in :issue:`35059`.) -* The :c:func:`PyByteArray_Init` and :c:func:`PyByteArray_Fini` functions have +* The :c:func:`!PyByteArray_Init` and :c:func:`!PyByteArray_Fini` functions have been removed. They did nothing since Python 2.7.4 and Python 3.2.0, were excluded from the limited API (stable ABI), and were not documented. (Contributed by Victor Stinner in :issue:`35713`.) @@ -1628,7 +1628,7 @@ Build and C API Changes parameter for indicating the number of positional-only arguments. (Contributed by Pablo Galindo in :issue:`37221`.) -* :c:func:`Py_SetPath` now sets :data:`sys.executable` to the program full +* :c:func:`!Py_SetPath` now sets :data:`sys.executable` to the program full path (:c:func:`Py_GetProgramFullPath`) rather than to the program name (:c:func:`Py_GetProgramName`). (Contributed by Victor Stinner in :issue:`38234`.) @@ -1845,11 +1845,11 @@ Changes in Python behavior always use ``sys.platform.startswith('aix')``. (Contributed by M. Felt in :issue:`36588`.) -* :c:func:`PyEval_AcquireLock` and :c:func:`PyEval_AcquireThread` now +* :c:func:`!PyEval_AcquireLock` and :c:func:`!PyEval_AcquireThread` now terminate the current thread if called while the interpreter is finalizing, making them consistent with :c:func:`PyEval_RestoreThread`, :c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`. If this - behavior is not desired, guard the call by checking :c:func:`_Py_IsFinalizing` + behavior is not desired, guard the call by checking :c:func:`!_Py_IsFinalizing` or :func:`sys.is_finalizing`. (Contributed by Joannah Nanjekye in :issue:`36475`.) @@ -2021,7 +2021,7 @@ Changes in the C API *cf_flags*. (Contributed by Guido van Rossum in :issue:`35766`.) -* The :c:func:`PyEval_ReInitThreads` function has been removed from the C API. +* The :c:func:`!PyEval_ReInitThreads` function has been removed from the C API. It should not be called explicitly: use :c:func:`PyOS_AfterFork_Child` instead. (Contributed by Victor Stinner in :issue:`36728`.) @@ -2121,7 +2121,7 @@ Changes in the C API (Contributed by Antoine Pitrou in :issue:`32388`.) -* The functions :c:func:`PyNode_AddChild` and :c:func:`PyParser_AddToken` now accept +* The functions :c:func:`!PyNode_AddChild` and :c:func:`!PyParser_AddToken` now accept two additional ``int`` arguments *end_lineno* and *end_col_offset*. * The :file:`libpython38.a` file to allow MinGW tools to link directly against diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 664c8d8a545db0..6829970900930a 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -870,9 +870,9 @@ Deprecated users can leverage the Abstract Syntax Tree (AST) generation and compilation stage, using the :mod:`ast` module. -* The Public C API functions :c:func:`PyParser_SimpleParseStringFlags`, - :c:func:`PyParser_SimpleParseStringFlagsFilename`, - :c:func:`PyParser_SimpleParseFileFlags` and :c:func:`PyNode_Compile` +* The Public C API functions :c:func:`!PyParser_SimpleParseStringFlags`, + :c:func:`!PyParser_SimpleParseStringFlagsFilename`, + :c:func:`!PyParser_SimpleParseFileFlags` and :c:func:`!PyNode_Compile` are deprecated and will be removed in Python 3.10 together with the old parser. * Using :data:`NotImplemented` in a boolean context has been deprecated, @@ -923,10 +923,10 @@ Deprecated (Contributed by Batuhan Taskaya in :issue:`39639` and :issue:`39969` and Serhiy Storchaka in :issue:`39988`.) -* The :c:func:`PyEval_InitThreads` and :c:func:`PyEval_ThreadsInitialized` +* The :c:func:`!PyEval_InitThreads` and :c:func:`!PyEval_ThreadsInitialized` functions are now deprecated and will be removed in Python 3.11. Calling - :c:func:`PyEval_InitThreads` now does nothing. The :term:`GIL` is initialized - by :c:func:`Py_Initialize()` since Python 3.7. + :c:func:`!PyEval_InitThreads` now does nothing. The :term:`GIL` is initialized + by :c:func:`Py_Initialize` since Python 3.7. (Contributed by Victor Stinner in :issue:`39877`.) * Passing ``None`` as the first argument to the :func:`shlex.split` function diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index a9ff21149a87d0..d4d6be870f1701 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -5036,15 +5036,15 @@ Limited API. Deprecate the following functions to configure the Python initialization: -* :c:func:`PySys_AddWarnOptionUnicode` -* :c:func:`PySys_AddWarnOption` -* :c:func:`PySys_AddXOption` -* :c:func:`PySys_HasWarnOptions` -* :c:func:`Py_SetPath` -* :c:func:`Py_SetProgramName` -* :c:func:`Py_SetPythonHome` -* :c:func:`Py_SetStandardStreamEncoding` -* :c:func:`_Py_SetProgramFullPath` +* :c:func:`!PySys_AddWarnOptionUnicode` +* :c:func:`!PySys_AddWarnOption` +* :c:func:`!PySys_AddXOption` +* :c:func:`!PySys_HasWarnOptions` +* :c:func:`!Py_SetPath` +* :c:func:`!Py_SetProgramName` +* :c:func:`!Py_SetPythonHome` +* :c:func:`!Py_SetStandardStreamEncoding` +* :c:func:`!_Py_SetProgramFullPath` Use the new :c:type:`PyConfig` API of the :ref:`Python Initialization Configuration ` instead (:pep:`587`). diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index a3bf6ff3c54b4e..c5a4e407e85c92 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -8765,7 +8765,7 @@ for relative path to files in current directory. .. nonce: fmehdG .. section: C API -The :c:func:`PyByteArray_Init` and :c:func:`PyByteArray_Fini` functions have +The :c:func:`!PyByteArray_Init` and :c:func:`!PyByteArray_Fini` functions have been removed. They did nothing since Python 2.7.4 and Python 3.2.0, were excluded from the limited API (stable ABI), and were not documented. @@ -8836,7 +8836,7 @@ Py_LIMITED_API. Patch by Arthur Neufeld. .. nonce: gFd85N .. section: C API -The :c:func:`_PyObject_GC_TRACK` and :c:func:`_PyObject_GC_UNTRACK` macros +The :c:func:`!_PyObject_GC_TRACK` and :c:func:`!_PyObject_GC_UNTRACK` macros have been removed from the public C API. .. diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst index 524a05a7ae9704..2ce60f39539e8c 100644 --- a/Misc/NEWS.d/3.8.0a4.rst +++ b/Misc/NEWS.d/3.8.0a4.rst @@ -124,7 +124,7 @@ Galindo. .. nonce: CjRps3 .. section: Core and Builtins -:c:func:`PyEval_AcquireLock` and :c:func:`PyEval_AcquireThread` now +:c:func:`!PyEval_AcquireLock` and :c:func:`!PyEval_AcquireThread` now terminate the current thread if called while the interpreter is finalizing, making them consistent with :c:func:`PyEval_RestoreThread`, :c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`. diff --git a/Misc/NEWS.d/3.8.0b1.rst b/Misc/NEWS.d/3.8.0b1.rst index 5285770de13186..f8f180bc731fd5 100644 --- a/Misc/NEWS.d/3.8.0b1.rst +++ b/Misc/NEWS.d/3.8.0b1.rst @@ -2047,6 +2047,6 @@ unbound methods. These are objects supporting the optimization given by the .. nonce: FR-dMP .. section: C API -The :c:func:`PyEval_ReInitThreads` function has been removed from the C API. +The :c:func:`!PyEval_ReInitThreads` function has been removed from the C API. It should not be called explicitly: use :c:func:`PyOS_AfterFork_Child` instead. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 85473da78bd438..367c194c1ea181 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -5535,7 +5535,7 @@ Tyler Kieft. .. nonce: d0bhEA .. section: C API -:c:func:`Py_SetPath` now sets :data:`sys.executable` to the program full +:c:func:`!Py_SetPath` now sets :data:`sys.executable` to the program full path (:c:func:`Py_GetProgramFullPath`) rather than to the program name (:c:func:`Py_GetProgramName`). @@ -5546,8 +5546,8 @@ path (:c:func:`Py_GetProgramFullPath`) rather than to the program name .. nonce: ZbquVK .. section: C API -Python ignored arguments passed to :c:func:`Py_SetPath`, -:c:func:`Py_SetPythonHome` and :c:func:`Py_SetProgramName`: fix Python +Python ignored arguments passed to :c:func:`!Py_SetPath`, +:c:func:`!Py_SetPythonHome` and :c:func:`!Py_SetProgramName`: fix Python initialization to use specified arguments. .. diff --git a/Misc/NEWS.d/3.9.0a5.rst b/Misc/NEWS.d/3.9.0a5.rst index 8a1219501e81bf..19ad20ad3db042 100644 --- a/Misc/NEWS.d/3.9.0a5.rst +++ b/Misc/NEWS.d/3.9.0a5.rst @@ -1234,8 +1234,8 @@ method name in the SystemError "bad call flags" error message to ease debug. .. nonce: GOYtIm .. section: C API -Deprecated :c:func:`PyEval_InitThreads` and -:c:func:`PyEval_ThreadsInitialized`. Calling :c:func:`PyEval_InitThreads` +Deprecated :c:func:`!PyEval_InitThreads` and +:c:func:`!PyEval_ThreadsInitialized`. Calling :c:func:`!PyEval_InitThreads` now does nothing. .. From 68fd6db9817d8b0b083a8f9372da5feba2f24db1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 07:17:03 -0700 Subject: [PATCH 0612/1206] [3.12] Docs: align the param spec of sqlite3.Connection methods with the implementation (GH-108285) (#108287) Docs: align the param spec of sqlite3.Connection methods with the implementation (GH-108285) - no parameters of create_aggregate() are positional-only - all parameters of create_collation() are positional-only (cherry picked from commit 893215a4e7f59eabb8ccdf188c4b9b1de5bd8966) Co-authored-by: Erlend E. Aasland --- Doc/library/sqlite3.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 23a22e637c0a93..93ca46811f1c0a 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -755,7 +755,7 @@ Connection objects ('acbd18db4cc2f85cedef654fccc4a4d8',) - .. method:: create_aggregate(name, /, n_arg, aggregate_class) + .. method:: create_aggregate(name, n_arg, aggregate_class) Create or remove a user-defined SQL aggregate function. @@ -895,7 +895,7 @@ Connection objects [('a', 9), ('b', 12), ('c', 16), ('d', 12), ('e', 9)] - .. method:: create_collation(name, callable) + .. method:: create_collation(name, callable, /) Create a collation named *name* using the collating function *callable*. *callable* is passed two :class:`string ` arguments, From 1dbf11814f32c7d4c1fc66cb0a29aa3667962b0d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 11:34:56 -0700 Subject: [PATCH 0613/1206] [3.12] gh-107700: [Enum] Document that `EnumType` was added in 3.11 (GH-108260) (#108301) (cherry picked from commit e8ef0bdd8c613a722bf7965bf1da912882141a52) Co-authored-by: Nikita Sobolev --- Doc/library/enum.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index e9c4f0e2c5f59b..7653865f0b9b36 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -241,6 +241,10 @@ Data Types >>> list(reversed(Color)) [, , ] + .. versionadded:: 3.11 + + Before 3.11 ``enum`` used ``EnumMeta`` type, which is kept as an alias. + .. class:: Enum From 256586ab8776e4526ca594b4866b9a3492e628f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 22 Aug 2023 21:03:20 +0200 Subject: [PATCH 0614/1206] [3.12] gh-108310: Fix CVE-2023-40217: Check for & avoid the ssl pre-close flaw (#108316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instances of `ssl.SSLSocket` were vulnerable to a bypass of the TLS handshake and included protections (like certificate verification) and treating sent unencrypted data as if it were post-handshake TLS encrypted data. The vulnerability is caused when a socket is connected, data is sent by the malicious peer and stored in a buffer, and then the malicious peer closes the socket within a small timing window before the other peers’ TLS handshake can begin. After this sequence of events the closed socket will not immediately attempt a TLS handshake due to not being connected but will also allow the buffered data to be read as if a successful TLS handshake had occurred. Co-authored-by: Gregory P. Smith [Google LLC] --- Lib/ssl.py | 31 ++- Lib/test/test_ssl.py | 211 ++++++++++++++++++ ...-08-22-17-39-12.gh-issue-108310.fVM3sg.rst | 7 + 3 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst diff --git a/Lib/ssl.py b/Lib/ssl.py index 1d5873726441e4..ff363c75e7dfd8 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -975,7 +975,7 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True, ) self = cls.__new__(cls, **kwargs) super(SSLSocket, self).__init__(**kwargs) - self.settimeout(sock.gettimeout()) + sock_timeout = sock.gettimeout() sock.detach() self._context = context @@ -994,9 +994,38 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True, if e.errno != errno.ENOTCONN: raise connected = False + blocking = self.getblocking() + self.setblocking(False) + try: + # We are not connected so this is not supposed to block, but + # testing revealed otherwise on macOS and Windows so we do + # the non-blocking dance regardless. Our raise when any data + # is found means consuming the data is harmless. + notconn_pre_handshake_data = self.recv(1) + except OSError as e: + # EINVAL occurs for recv(1) on non-connected on unix sockets. + if e.errno not in (errno.ENOTCONN, errno.EINVAL): + raise + notconn_pre_handshake_data = b'' + self.setblocking(blocking) + if notconn_pre_handshake_data: + # This prevents pending data sent to the socket before it was + # closed from escaping to the caller who could otherwise + # presume it came through a successful TLS connection. + reason = "Closed before TLS handshake with data in recv buffer." + notconn_pre_handshake_data_error = SSLError(e.errno, reason) + # Add the SSLError attributes that _ssl.c always adds. + notconn_pre_handshake_data_error.reason = reason + notconn_pre_handshake_data_error.library = None + try: + self.close() + except OSError: + pass + raise notconn_pre_handshake_data_error else: connected = True + self.settimeout(sock_timeout) # Must come after setblocking() calls. self._connected = connected if connected: # create the SSL object diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 6117ca3fdba1b7..ad5377ec059c0b 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -10,11 +10,14 @@ from test.support import threading_helper from test.support import warnings_helper from test.support import asyncore +import re import socket import select +import struct import time import enum import gc +import http.client import os import errno import pprint @@ -4659,6 +4662,214 @@ def sni_cb(sock, servername, ctx): s.connect((HOST, server.port)) +def set_socket_so_linger_on_with_zero_timeout(sock): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) + + +class TestPreHandshakeClose(unittest.TestCase): + """Verify behavior of close sockets with received data before to the handshake. + """ + + class SingleConnectionTestServerThread(threading.Thread): + + def __init__(self, *, name, call_after_accept): + self.call_after_accept = call_after_accept + self.received_data = b'' # set by .run() + self.wrap_error = None # set by .run() + self.listener = None # set by .start() + self.port = None # set by .start() + super().__init__(name=name) + + def __enter__(self): + self.start() + return self + + def __exit__(self, *args): + try: + if self.listener: + self.listener.close() + except OSError: + pass + self.join() + self.wrap_error = None # avoid dangling references + + def start(self): + self.ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + self.ssl_ctx.verify_mode = ssl.CERT_REQUIRED + self.ssl_ctx.load_verify_locations(cafile=ONLYCERT) + self.ssl_ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY) + self.listener = socket.socket() + self.port = socket_helper.bind_port(self.listener) + self.listener.settimeout(2.0) + self.listener.listen(1) + super().start() + + def run(self): + conn, address = self.listener.accept() + self.listener.close() + with conn: + if self.call_after_accept(conn): + return + try: + tls_socket = self.ssl_ctx.wrap_socket(conn, server_side=True) + except OSError as err: # ssl.SSLError inherits from OSError + self.wrap_error = err + else: + try: + self.received_data = tls_socket.recv(400) + except OSError: + pass # closed, protocol error, etc. + + def non_linux_skip_if_other_okay_error(self, err): + if sys.platform == "linux": + return # Expect the full test setup to always work on Linux. + if (isinstance(err, ConnectionResetError) or + (isinstance(err, OSError) and err.errno == errno.EINVAL) or + re.search('wrong.version.number', getattr(err, "reason", ""), re.I)): + # On Windows the TCP RST leads to a ConnectionResetError + # (ECONNRESET) which Linux doesn't appear to surface to userspace. + # If wrap_socket() winds up on the "if connected:" path and doing + # the actual wrapping... we get an SSLError from OpenSSL. Typically + # WRONG_VERSION_NUMBER. While appropriate, neither is the scenario + # we're specifically trying to test. The way this test is written + # is known to work on Linux. We'll skip it anywhere else that it + # does not present as doing so. + self.skipTest(f"Could not recreate conditions on {sys.platform}:" + f" {err=}") + # If maintaining this conditional winds up being a problem. + # just turn this into an unconditional skip anything but Linux. + # The important thing is that our CI has the logic covered. + + def test_preauth_data_to_tls_server(self): + server_accept_called = threading.Event() + ready_for_server_wrap_socket = threading.Event() + + def call_after_accept(unused): + server_accept_called.set() + if not ready_for_server_wrap_socket.wait(2.0): + raise RuntimeError("wrap_socket event never set, test may fail.") + return False # Tell the server thread to continue. + + server = self.SingleConnectionTestServerThread( + call_after_accept=call_after_accept, + name="preauth_data_to_tls_server") + self.enterContext(server) # starts it & unittest.TestCase stops it. + + with socket.socket() as client: + client.connect(server.listener.getsockname()) + # This forces an immediate connection close via RST on .close(). + set_socket_so_linger_on_with_zero_timeout(client) + client.setblocking(False) + + server_accept_called.wait() + client.send(b"DELETE /data HTTP/1.0\r\n\r\n") + client.close() # RST + + ready_for_server_wrap_socket.set() + server.join() + wrap_error = server.wrap_error + self.assertEqual(b"", server.received_data) + self.assertIsInstance(wrap_error, OSError) # All platforms. + self.non_linux_skip_if_other_okay_error(wrap_error) + self.assertIsInstance(wrap_error, ssl.SSLError) + self.assertIn("before TLS handshake with data", wrap_error.args[1]) + self.assertIn("before TLS handshake with data", wrap_error.reason) + self.assertNotEqual(0, wrap_error.args[0]) + self.assertIsNone(wrap_error.library, msg="attr must exist") + + def test_preauth_data_to_tls_client(self): + client_can_continue_with_wrap_socket = threading.Event() + + def call_after_accept(conn_to_client): + # This forces an immediate connection close via RST on .close(). + set_socket_so_linger_on_with_zero_timeout(conn_to_client) + conn_to_client.send( + b"HTTP/1.0 307 Temporary Redirect\r\n" + b"Location: https://example.com/someone-elses-server\r\n" + b"\r\n") + conn_to_client.close() # RST + client_can_continue_with_wrap_socket.set() + return True # Tell the server to stop. + + server = self.SingleConnectionTestServerThread( + call_after_accept=call_after_accept, + name="preauth_data_to_tls_client") + self.enterContext(server) # starts it & unittest.TestCase stops it. + # Redundant; call_after_accept sets SO_LINGER on the accepted conn. + set_socket_so_linger_on_with_zero_timeout(server.listener) + + with socket.socket() as client: + client.connect(server.listener.getsockname()) + if not client_can_continue_with_wrap_socket.wait(2.0): + self.fail("test server took too long.") + ssl_ctx = ssl.create_default_context() + try: + tls_client = ssl_ctx.wrap_socket( + client, server_hostname="localhost") + except OSError as err: # SSLError inherits from OSError + wrap_error = err + received_data = b"" + else: + wrap_error = None + received_data = tls_client.recv(400) + tls_client.close() + + server.join() + self.assertEqual(b"", received_data) + self.assertIsInstance(wrap_error, OSError) # All platforms. + self.non_linux_skip_if_other_okay_error(wrap_error) + self.assertIsInstance(wrap_error, ssl.SSLError) + self.assertIn("before TLS handshake with data", wrap_error.args[1]) + self.assertIn("before TLS handshake with data", wrap_error.reason) + self.assertNotEqual(0, wrap_error.args[0]) + self.assertIsNone(wrap_error.library, msg="attr must exist") + + def test_https_client_non_tls_response_ignored(self): + + server_responding = threading.Event() + + class SynchronizedHTTPSConnection(http.client.HTTPSConnection): + def connect(self): + http.client.HTTPConnection.connect(self) + # Wait for our fault injection server to have done its thing. + if not server_responding.wait(1.0) and support.verbose: + sys.stdout.write("server_responding event never set.") + self.sock = self._context.wrap_socket( + self.sock, server_hostname=self.host) + + def call_after_accept(conn_to_client): + # This forces an immediate connection close via RST on .close(). + set_socket_so_linger_on_with_zero_timeout(conn_to_client) + conn_to_client.send( + b"HTTP/1.0 402 Payment Required\r\n" + b"\r\n") + conn_to_client.close() # RST + server_responding.set() + return True # Tell the server to stop. + + server = self.SingleConnectionTestServerThread( + call_after_accept=call_after_accept, + name="non_tls_http_RST_responder") + self.enterContext(server) # starts it & unittest.TestCase stops it. + # Redundant; call_after_accept sets SO_LINGER on the accepted conn. + set_socket_so_linger_on_with_zero_timeout(server.listener) + + connection = SynchronizedHTTPSConnection( + f"localhost", + port=server.port, + context=ssl.create_default_context(), + timeout=2.0, + ) + # There are lots of reasons this raises as desired, long before this + # test was added. Sending the request requires a successful TLS wrapped + # socket; that fails if the connection is broken. It may seem pointless + # to test this. It serves as an illustration of something that we never + # want to happen... properly not happening. + with self.assertRaises(OSError) as err_ctx: + connection.request("HEAD", "/test", headers={"Host": "localhost"}) + response = connection.getresponse() + + class TestEnumerations(unittest.TestCase): def test_tlsversion(self): diff --git a/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst b/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst new file mode 100644 index 00000000000000..403c77a9d480ee --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst @@ -0,0 +1,7 @@ +Fixed an issue where instances of :class:`ssl.SSLSocket` were vulnerable to +a bypass of the TLS handshake and included protections (like certificate +verification) and treating sent unencrypted data as if it were +post-handshake TLS encrypted data. Security issue reported as +`CVE-2023-40217 +`_ by +Aapo Oksman. Patch by Gregory P. Smith. From 3cdaa6a7941696c30c774f9dc5b0bad72f8f07e2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 12:37:14 -0700 Subject: [PATCH 0615/1206] [3.12] gh-105857: Document that asyncio subprocess std{in,out,err} can be file handles (GH-107986) (#108332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 13966da71b693b1fae1a8ef66e34e2f0a90ec6c0) Co-authored-by: Hadházy Tamás <85063808+Hels15@users.noreply.github.com> --- Doc/library/asyncio-eventloop.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 8f2d8f336c82bb..04af53b980ff9e 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1442,6 +1442,7 @@ async/await code consider using the high-level * *stdin* can be any of these: * a file-like object + * an existing file descriptor (a positive integer), for example those created with :meth:`os.pipe()` * the :const:`subprocess.PIPE` constant (default) which will create a new pipe and connect it, * the value ``None`` which will make the subprocess inherit the file From fad80598dc0c5a6c1b9bc9802e80a0f9686628fe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 12:38:13 -0700 Subject: [PATCH 0616/1206] [3.12] Document 3.13, 3.14 and future removals (GH-108055) (#108331) (cherry picked from commit 39de79b345f925ce3bbb79b33534872fe0c90877) Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 2084f4ed0b9bcb..dca4fd999621d0 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1113,6 +1113,10 @@ Modules (see :pep:`594`): * :mod:`uu` * :mod:`xdrlib` +Other modules: + +* :mod:`!lib2to3`, and the :program:`2to3` program (:gh:`84540`) + APIs: * :class:`!configparser.LegacyInterpolation` (:gh:`90765`) @@ -1146,6 +1150,10 @@ Pending Removal in Python 3.14 Use :class:`ast.Constant` instead. (Contributed by Serhiy Storchaka in :gh:`90953`.) +* :mod:`asyncio`: the *msg* parameter of both + :meth:`asyncio.Future.cancel` and + :meth:`asyncio.Task.cancel` (:gh:`90985`) + * :mod:`collections.abc`: Deprecated :class:`collections.abc.ByteString`. Prefer :class:`Sequence` or :class:`collections.abc.Buffer`. For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. @@ -1212,12 +1220,17 @@ Pending Removal in Python 3.14 May be removed in 3.14. (Contributed by Nikita Sobolev in :gh:`101866`.) +* Creating :c:data:`immutable types ` with mutable + bases using the C API (:gh:`95388`) + Pending Removal in Future Versions ---------------------------------- The following APIs were deprecated in earlier Python versions and will be removed, although there is currently no date scheduled for their removal. +* :mod:`array`'s ``'u'`` format code (:gh:`57281`) + * :class:`typing.Text` (:gh:`92332`) * Currently Python accepts numeric literals immediately followed by keywords, From ca47a2183a35d4b71cc062c926b7f96112fdf5ce Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 22 Aug 2023 22:06:07 +0200 Subject: [PATCH 0617/1206] [3.12] gh-106016: Add Lib/test/test_module/ directory (#108293) (#108306) gh-106016: Add Lib/test/test_module/ directory (#108293) * Move Python scripts related to test_module to this new directory: good_getattr.py and bad_getattrX.py scripts. * Move Lib/test/test_module.py to Lib/test/test_module/__init__.py. (cherry picked from commit adfc118fdab66882599e01a84c22bd897055f3f1) --- .../__init__.py} | 36 +++++++++---------- Lib/test/{ => test_module}/bad_getattr.py | 0 Lib/test/{ => test_module}/bad_getattr2.py | 0 Lib/test/{ => test_module}/bad_getattr3.py | 0 Lib/test/{ => test_module}/good_getattr.py | 0 Makefile.pre.in | 1 + 6 files changed, 19 insertions(+), 18 deletions(-) rename Lib/test/{test_module.py => test_module/__init__.py} (92%) rename Lib/test/{ => test_module}/bad_getattr.py (100%) rename Lib/test/{ => test_module}/bad_getattr2.py (100%) rename Lib/test/{ => test_module}/bad_getattr3.py (100%) rename Lib/test/{ => test_module}/good_getattr.py (100%) diff --git a/Lib/test/test_module.py b/Lib/test/test_module/__init__.py similarity index 92% rename from Lib/test/test_module.py rename to Lib/test/test_module/__init__.py index c7eb92290e1b6d..cfc4d9ccf1cc81 100644 --- a/Lib/test/test_module.py +++ b/Lib/test/test_module/__init__.py @@ -126,8 +126,8 @@ def test_weakref(self): self.assertIs(wr(), None) def test_module_getattr(self): - import test.good_getattr as gga - from test.good_getattr import test + import test.test_module.good_getattr as gga + from test.test_module.good_getattr import test self.assertEqual(test, "There is test") self.assertEqual(gga.x, 1) self.assertEqual(gga.y, 2) @@ -135,46 +135,46 @@ def test_module_getattr(self): "Deprecated, use whatever instead"): gga.yolo self.assertEqual(gga.whatever, "There is whatever") - del sys.modules['test.good_getattr'] + del sys.modules['test.test_module.good_getattr'] def test_module_getattr_errors(self): - import test.bad_getattr as bga - from test import bad_getattr2 + import test.test_module.bad_getattr as bga + from test.test_module import bad_getattr2 self.assertEqual(bga.x, 1) self.assertEqual(bad_getattr2.x, 1) with self.assertRaises(TypeError): bga.nope with self.assertRaises(TypeError): bad_getattr2.nope - del sys.modules['test.bad_getattr'] - if 'test.bad_getattr2' in sys.modules: - del sys.modules['test.bad_getattr2'] + del sys.modules['test.test_module.bad_getattr'] + if 'test.test_module.bad_getattr2' in sys.modules: + del sys.modules['test.test_module.bad_getattr2'] def test_module_dir(self): - import test.good_getattr as gga + import test.test_module.good_getattr as gga self.assertEqual(dir(gga), ['a', 'b', 'c']) - del sys.modules['test.good_getattr'] + del sys.modules['test.test_module.good_getattr'] def test_module_dir_errors(self): - import test.bad_getattr as bga - from test import bad_getattr2 + import test.test_module.bad_getattr as bga + from test.test_module import bad_getattr2 with self.assertRaises(TypeError): dir(bga) with self.assertRaises(TypeError): dir(bad_getattr2) - del sys.modules['test.bad_getattr'] - if 'test.bad_getattr2' in sys.modules: - del sys.modules['test.bad_getattr2'] + del sys.modules['test.test_module.bad_getattr'] + if 'test.test_module.bad_getattr2' in sys.modules: + del sys.modules['test.test_module.bad_getattr2'] def test_module_getattr_tricky(self): - from test import bad_getattr3 + from test.test_module import bad_getattr3 # these lookups should not crash with self.assertRaises(AttributeError): bad_getattr3.one with self.assertRaises(AttributeError): bad_getattr3.delgetattr - if 'test.bad_getattr3' in sys.modules: - del sys.modules['test.bad_getattr3'] + if 'test.test_module.bad_getattr3' in sys.modules: + del sys.modules['test.test_module.bad_getattr3'] def test_module_repr_minimal(self): # reprs when modules have no __file__, __name__, or __loader__ diff --git a/Lib/test/bad_getattr.py b/Lib/test/test_module/bad_getattr.py similarity index 100% rename from Lib/test/bad_getattr.py rename to Lib/test/test_module/bad_getattr.py diff --git a/Lib/test/bad_getattr2.py b/Lib/test/test_module/bad_getattr2.py similarity index 100% rename from Lib/test/bad_getattr2.py rename to Lib/test/test_module/bad_getattr2.py diff --git a/Lib/test/bad_getattr3.py b/Lib/test/test_module/bad_getattr3.py similarity index 100% rename from Lib/test/bad_getattr3.py rename to Lib/test/test_module/bad_getattr3.py diff --git a/Lib/test/good_getattr.py b/Lib/test/test_module/good_getattr.py similarity index 100% rename from Lib/test/good_getattr.py rename to Lib/test/test_module/good_getattr.py diff --git a/Makefile.pre.in b/Makefile.pre.in index a74f4fd66d3235..d9d56bb45ce712 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2192,6 +2192,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_lib2to3/data \ test/test_lib2to3/data/fixers \ test/test_lib2to3/data/fixers/myfixes \ + test/test_module \ test/test_peg_generator \ test/test_sqlite3 \ test/test_tkinter \ From b539dd3073f9e37de25f73ad19d188cd56cc19b4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:06:33 -0700 Subject: [PATCH 0618/1206] [3.12] gh-108303: Add Lib/test/test_cppext/ sub-directory (GH-108325) (#108328) gh-108303: Add Lib/test/test_cppext/ sub-directory (GH-108325) * Move test_cppext to its own directory * Rename setup_testcppext.py to setup.py * Rename _testcppext.cpp to extension.cpp * The source (extension.cpp) is now also copied by the test. (cherry picked from commit 21dda09600848ac280481f7c64f8d9516dc69bb2) Co-authored-by: Victor Stinner --- Lib/test/{test_cppext.py => test_cppext/__init__.py} | 8 ++++---- Lib/test/{_testcppext.cpp => test_cppext/extension.cpp} | 2 ++ Lib/test/{setup_testcppext.py => test_cppext/setup.py} | 3 +-- Makefile.pre.in | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) rename Lib/test/{test_cppext.py => test_cppext/__init__.py} (91%) rename Lib/test/{_testcppext.cpp => test_cppext/extension.cpp} (99%) rename Lib/test/{setup_testcppext.py => test_cppext/setup.py} (93%) diff --git a/Lib/test/test_cppext.py b/Lib/test/test_cppext/__init__.py similarity index 91% rename from Lib/test/test_cppext.py rename to Lib/test/test_cppext/__init__.py index e2fedc9735079f..f3d32a3c7612c9 100644 --- a/Lib/test/test_cppext.py +++ b/Lib/test/test_cppext/__init__.py @@ -11,9 +11,8 @@ MS_WINDOWS = (sys.platform == 'win32') - - -SETUP_TESTCPPEXT = support.findfile('setup_testcppext.py') +SOURCE = os.path.join(os.path.dirname(__file__), 'extension.cpp') +SETUP = os.path.join(os.path.dirname(__file__), 'setup.py') @support.requires_subprocess() @@ -42,7 +41,8 @@ def check_build(self, std_cpp03, extension_name): def _check_build(self, std_cpp03, extension_name, python_exe): pkg_dir = 'pkg' os.mkdir(pkg_dir) - shutil.copy(SETUP_TESTCPPEXT, os.path.join(pkg_dir, "setup.py")) + shutil.copy(SETUP, os.path.join(pkg_dir, os.path.basename(SETUP))) + shutil.copy(SOURCE, os.path.join(pkg_dir, os.path.basename(SOURCE))) def run_cmd(operation, cmd): env = os.environ.copy() diff --git a/Lib/test/_testcppext.cpp b/Lib/test/test_cppext/extension.cpp similarity index 99% rename from Lib/test/_testcppext.cpp rename to Lib/test/test_cppext/extension.cpp index 82b471312dd2b9..90669b10cb2c6d 100644 --- a/Lib/test/_testcppext.cpp +++ b/Lib/test/test_cppext/extension.cpp @@ -1,5 +1,7 @@ // gh-91321: Very basic C++ test extension to check that the Python C API is // compatible with C++ and does not emit C++ compiler warnings. +// +// The code is only built, not executed. // Always enable assertions #undef NDEBUG diff --git a/Lib/test/setup_testcppext.py b/Lib/test/test_cppext/setup.py similarity index 93% rename from Lib/test/setup_testcppext.py rename to Lib/test/test_cppext/setup.py index 22fe750085fd70..6867094a420436 100644 --- a/Lib/test/setup_testcppext.py +++ b/Lib/test/test_cppext/setup.py @@ -2,7 +2,6 @@ # compatible with C++ and does not emit C++ compiler warnings. import os import sys -from test import support from setuptools import setup, Extension @@ -10,7 +9,7 @@ MS_WINDOWS = (sys.platform == 'win32') -SOURCE = support.findfile('_testcppext.cpp') +SOURCE = 'extension.cpp' if not MS_WINDOWS: # C++ compiler flags for GCC and clang CPPFLAGS = [ diff --git a/Makefile.pre.in b/Makefile.pre.in index d9d56bb45ce712..ae6a12c2a2c430 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2132,6 +2132,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/support/_hypothesis_stubs \ test/test_asyncio \ test/test_capi \ + test/test_cppext \ test/test_ctypes \ test/test_email \ test/test_email/data \ From 92cbe739d42acde858e27d9c06524312dda7534e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:06:53 -0700 Subject: [PATCH 0619/1206] [3.12] Docs: Add link to skip to datetime's format codes (GH-108027) (#108329) Docs: Add link to skip to datetime's format codes (GH-108027) (cherry picked from commit 35cb1605d08a77f1c18bd476b26391acaaa35599) Co-authored-by: Hugo van Kemenade --- Doc/library/datetime.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index bed19ad145a20c..400c369a9bb736 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -19,6 +19,10 @@ The :mod:`datetime` module supplies classes for manipulating dates and times. While date and time arithmetic is supported, the focus of the implementation is on efficient attribute extraction for output formatting and manipulation. +.. tip:: + + Skip to :ref:`the format codes `. + .. seealso:: Module :mod:`calendar` @@ -2322,6 +2326,8 @@ versus :meth:`strptime`: +----------------+--------------------------------------------------------+------------------------------------------------------------------------------+ + .. _format-codes: + :meth:`strftime` and :meth:`strptime` Format Codes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 200af4294e9a99bf0d4f535c43f75f304eb53497 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:07:15 -0700 Subject: [PATCH 0620/1206] [3.12] GH-92584: Remove distutils from the newtypes tutorial includes (GH-108024) (#108333) GH-92584: Remove distutils from the newtypes tutorial includes (GH-108024) (cherry picked from commit e97b7bef4fbe71821d59d2f41f311e514fd29e39) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/extending/newtypes_tutorial.rst | 54 +++++++++++++-------------- Doc/includes/{ => newtypes}/custom.c | 0 Doc/includes/{ => newtypes}/custom2.c | 0 Doc/includes/{ => newtypes}/custom3.c | 0 Doc/includes/{ => newtypes}/custom4.c | 0 Doc/includes/newtypes/pyproject.toml | 7 ++++ Doc/includes/newtypes/setup.py | 8 ++++ Doc/includes/{ => newtypes}/sublist.c | 0 Doc/includes/{ => newtypes}/test.py | 7 ---- Doc/includes/setup.py | 9 ----- 10 files changed, 42 insertions(+), 43 deletions(-) rename Doc/includes/{ => newtypes}/custom.c (100%) rename Doc/includes/{ => newtypes}/custom2.c (100%) rename Doc/includes/{ => newtypes}/custom3.c (100%) rename Doc/includes/{ => newtypes}/custom4.c (100%) create mode 100644 Doc/includes/newtypes/pyproject.toml create mode 100644 Doc/includes/newtypes/setup.py rename Doc/includes/{ => newtypes}/sublist.c (100%) rename Doc/includes/{ => newtypes}/test.py (94%) delete mode 100644 Doc/includes/setup.py diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index f8684df5dd8299..c2bc5f699a1599 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -45,7 +45,7 @@ extension module :mod:`!custom`: allows defining heap-allocated extension types using the :c:func:`PyType_FromSpec` function, which isn't covered in this tutorial. -.. literalinclude:: ../includes/custom.c +.. literalinclude:: ../includes/newtypes/custom.c Now that's quite a bit to take in at once, but hopefully bits will seem familiar from the previous chapter. This file defines three things: @@ -196,36 +196,32 @@ This adds the type to the module dictionary. This allows us to create >>> mycustom = custom.Custom() That's it! All that remains is to build it; put the above code in a file called -:file:`custom.c` and: +:file:`custom.c`, + +.. literalinclude:: ../includes/newtypes/pyproject.toml + +in a file called :file:`pyproject.toml`, and .. code-block:: python - from distutils.core import setup, Extension - setup(name="custom", version="1.0", - ext_modules=[Extension("custom", ["custom.c"])]) + from setuptools import Extension, setup + setup(ext_modules=[Extension("custom", ["custom.c"])]) in a file called :file:`setup.py`; then typing .. code-block:: shell-session - $ python setup.py build + $ python -m pip install . -at a shell should produce a file :file:`custom.so` in a subdirectory; move to -that directory and fire up Python --- you should be able to ``import custom`` and -play around with Custom objects. +in a shell should produce a file :file:`custom.so` in a subdirectory +and install it; now fire up Python --- you should be able to ``import custom`` +and play around with ``Custom`` objects. That wasn't so hard, was it? Of course, the current Custom type is pretty uninteresting. It has no data and doesn't do anything. It can't even be subclassed. -.. note:: - While this documentation showcases the standard :mod:`!distutils` module - for building C extensions, it is recommended in real-world use cases to - use the newer and better-maintained ``setuptools`` library. Documentation - on how to do this is out of scope for this document and can be found in - the `Python Packaging User's Guide `_. - Adding data and methods to the Basic example ============================================ @@ -234,7 +230,7 @@ Let's extend the basic example to add some data and methods. Let's also make the type usable as a base class. We'll create a new module, :mod:`!custom2` that adds these capabilities: -.. literalinclude:: ../includes/custom2.c +.. literalinclude:: ../includes/newtypes/custom2.c This version of the module has a number of changes. @@ -516,17 +512,21 @@ We rename :c:func:`!PyInit_custom` to :c:func:`!PyInit_custom2`, update the module name in the :c:type:`PyModuleDef` struct, and update the full class name in the :c:type:`PyTypeObject` struct. -Finally, we update our :file:`setup.py` file to build the new module: +Finally, we update our :file:`setup.py` file to include the new module, .. code-block:: python - from distutils.core import setup, Extension - setup(name="custom", version="1.0", - ext_modules=[ - Extension("custom", ["custom.c"]), - Extension("custom2", ["custom2.c"]), - ]) + from setuptools import Extension, setup + setup(ext_modules=[ + Extension("custom", ["custom.c"]), + Extension("custom2", ["custom2.c"]), + ]) + +and then we re-install so that we can ``import custom2``: + +.. code-block:: shell-session + $ python -m pip install . Providing finer control over data attributes ============================================ @@ -537,7 +537,7 @@ version of our module, the instance variables :attr:`!first` and :attr:`!last` could be set to non-string values or even deleted. We want to make sure that these attributes always contain strings. -.. literalinclude:: ../includes/custom3.c +.. literalinclude:: ../includes/newtypes/custom3.c To provide greater control, over the :attr:`!first` and :attr:`!last` attributes, @@ -684,7 +684,7 @@ To allow a :class:`!Custom` instance participating in a reference cycle to be properly detected and collected by the cyclic GC, our :class:`!Custom` type needs to fill two additional slots and to enable a flag that enables these slots: -.. literalinclude:: ../includes/custom4.c +.. literalinclude:: ../includes/newtypes/custom4.c First, the traversal method lets the cyclic GC know about subobjects that could @@ -808,7 +808,7 @@ increases an internal counter: >>> print(s.increment()) 2 -.. literalinclude:: ../includes/sublist.c +.. literalinclude:: ../includes/newtypes/sublist.c As you can see, the source code closely resembles the :class:`!Custom` examples in diff --git a/Doc/includes/custom.c b/Doc/includes/newtypes/custom.c similarity index 100% rename from Doc/includes/custom.c rename to Doc/includes/newtypes/custom.c diff --git a/Doc/includes/custom2.c b/Doc/includes/newtypes/custom2.c similarity index 100% rename from Doc/includes/custom2.c rename to Doc/includes/newtypes/custom2.c diff --git a/Doc/includes/custom3.c b/Doc/includes/newtypes/custom3.c similarity index 100% rename from Doc/includes/custom3.c rename to Doc/includes/newtypes/custom3.c diff --git a/Doc/includes/custom4.c b/Doc/includes/newtypes/custom4.c similarity index 100% rename from Doc/includes/custom4.c rename to Doc/includes/newtypes/custom4.c diff --git a/Doc/includes/newtypes/pyproject.toml b/Doc/includes/newtypes/pyproject.toml new file mode 100644 index 00000000000000..ea7937a3171473 --- /dev/null +++ b/Doc/includes/newtypes/pyproject.toml @@ -0,0 +1,7 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "custom" +version = "1" diff --git a/Doc/includes/newtypes/setup.py b/Doc/includes/newtypes/setup.py new file mode 100644 index 00000000000000..67f83673bcc657 --- /dev/null +++ b/Doc/includes/newtypes/setup.py @@ -0,0 +1,8 @@ +from setuptools import Extension, setup +setup(ext_modules=[ + Extension("custom", ["custom.c"]), + Extension("custom2", ["custom2.c"]), + Extension("custom3", ["custom3.c"]), + Extension("custom4", ["custom4.c"]), + Extension("sublist", ["sublist.c"]), +]) diff --git a/Doc/includes/sublist.c b/Doc/includes/newtypes/sublist.c similarity index 100% rename from Doc/includes/sublist.c rename to Doc/includes/newtypes/sublist.c diff --git a/Doc/includes/test.py b/Doc/includes/newtypes/test.py similarity index 94% rename from Doc/includes/test.py rename to Doc/includes/newtypes/test.py index 09ebe3fec0bdbe..55a5cf9f68b94a 100644 --- a/Doc/includes/test.py +++ b/Doc/includes/newtypes/test.py @@ -187,13 +187,6 @@ >>> gc.enable() """ -import os -import sys -from distutils.util import get_platform -PLAT_SPEC = "%s-%d.%d" % (get_platform(), *sys.version_info[:2]) -src = os.path.join("build", "lib.%s" % PLAT_SPEC) -sys.path.append(src) - if __name__ == "__main__": import doctest, __main__ doctest.testmod(__main__) diff --git a/Doc/includes/setup.py b/Doc/includes/setup.py deleted file mode 100644 index a38a39de3e7c86..00000000000000 --- a/Doc/includes/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -from distutils.core import setup, Extension -setup(name="noddy", version="1.0", - ext_modules=[ - Extension("noddy", ["noddy.c"]), - Extension("noddy2", ["noddy2.c"]), - Extension("noddy3", ["noddy3.c"]), - Extension("noddy4", ["noddy4.c"]), - Extension("shoddy", ["shoddy.c"]), - ]) From 314c98d293765fb6b930c840e6f6ba80f201b3f7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Aug 2023 02:01:19 -0700 Subject: [PATCH 0621/1206] [3.12] gh-107136: Remove Plausible for docs metrics (GH-107856) (#108334) (cherry picked from commit fc23f34cc9701949e6832eb32f26ea89f6622b82) Co-authored-by: Hugo van Kemenade --- Doc/tools/templates/layout.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index 80103158ea01e6..9498b2ccc5af92 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -26,9 +26,6 @@ {% endblock %} {% block extrahead %} - {% if builder == "html" %} - - {% endif %} {% if builder != "htmlhelp" %} {% if pagename == 'whatsnew/changelog' and not embedded %} From 61dbf46ae3df9d772bfd91b89ab61baeff97a12d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Aug 2023 03:09:55 -0700 Subject: [PATCH 0622/1206] [3.12] gh-108342: Break ref cycle in SSLSocket._create() exc (GH-108344) (#108348) Explicitly break a reference cycle when SSLSocket._create() raises an exception. Clear the variable storing the exception, since the exception traceback contains the variables and so creates a reference cycle. This test leak was introduced by the test added for the fix of GH-108310. (cherry picked from commit 64f99350351bc46e016b2286f36ba7cd669b79e3) Co-authored-by: Victor Stinner --- Lib/ssl.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/ssl.py b/Lib/ssl.py index ff363c75e7dfd8..c4c5a4ca894ee5 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -1021,7 +1021,11 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True, self.close() except OSError: pass - raise notconn_pre_handshake_data_error + try: + raise notconn_pre_handshake_data_error + finally: + # Explicitly break the reference cycle. + notconn_pre_handshake_data_error = None else: connected = True From 0d6e657689c58cbd790dec2f71f0879e1ed3d4a3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Aug 2023 04:45:37 -0700 Subject: [PATCH 0623/1206] [3.12] gh-105776: Fix test_cppext when CC contains -std=c11 option (GH-108343) (#108345) gh-105776: Fix test_cppext when CC contains -std=c11 option (GH-108343) Fix test_cppext when the C compiler command has the "-std=c11" option. Remove "-std=" options from the compiler command. (cherry picked from commit 9173b2bbe13aeccc075b571da05c653a2a91de1b) Co-authored-by: Victor Stinner --- Lib/test/test_cppext/setup.py | 13 +++++++++++++ .../2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst | 2 ++ 2 files changed, 15 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst diff --git a/Lib/test/test_cppext/setup.py b/Lib/test/test_cppext/setup.py index 6867094a420436..976633bc33889c 100644 --- a/Lib/test/test_cppext/setup.py +++ b/Lib/test/test_cppext/setup.py @@ -1,7 +1,9 @@ # gh-91321: Build a basic C++ test extension to check that the Python C API is # compatible with C++ and does not emit C++ compiler warnings. import os +import shlex import sys +import sysconfig from setuptools import setup, Extension @@ -30,6 +32,17 @@ def main(): cppflags = [*CPPFLAGS, f'-std={std}'] + # gh-105776: When "gcc -std=11" is used as the C++ compiler, -std=c11 + # option emits a C++ compiler warning. Remove "-std11" option from the + # CC command. + cmd = (sysconfig.get_config_var('CC') or '') + if cmd is not None: + cmd = shlex.split(cmd) + cmd = [arg for arg in cmd if not arg.startswith('-std=')] + cmd = shlex.join(cmd) + # CC env var overrides sysconfig CC variable in setuptools + os.environ['CC'] = cmd + cpp_ext = Extension( name, sources=[SOURCE], diff --git a/Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst b/Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst new file mode 100644 index 00000000000000..0e0a3aa9b11e68 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst @@ -0,0 +1,2 @@ +Fix test_cppext when the C compiler command ``-std=c11`` option: remove +``-std=`` options from the compiler command. Patch by Victor Stinner. From 3aa7df6544950c21be57bd4bee5edbef4d196fce Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Aug 2023 04:46:03 -0700 Subject: [PATCH 0624/1206] [3.12] gh-108267: Dataclasses docs: Fix object.__setattr__ typo (GH-108355) (#108358) gh-108267: Dataclasses docs: Fix object.__setattr__ typo (GH-108355) Fixed a sentence in dataclasses.rst Changed "__setattr__" to "object.__setattr__" in a section that was specifically supposed to refer to the __setattr__ method of the object class. Also suppressed the link to the data model docs for __setattr__, since we're talking about a specific __setattr__ implementation, not __setattr__ methods in general. (cherry picked from commit 79fdacc0059a3959074d2d9d054653eae1dcfe06) Co-authored-by: FrozenBob <30644137+FrozenBob@users.noreply.github.com> --- Doc/library/dataclasses.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 535a60ccca8d07..d68748767c5e37 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -609,7 +609,7 @@ methods will raise a :exc:`FrozenInstanceError` when invoked. There is a tiny performance penalty when using ``frozen=True``: :meth:`~object.__init__` cannot use simple assignment to initialize fields, and -must use :meth:`~object.__setattr__`. +must use :meth:`!object.__setattr__`. Inheritance ----------- From 9cf49aaaa0a08d430cd54a1c9ea022d40463bbfe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Aug 2023 16:44:07 -0700 Subject: [PATCH 0625/1206] [3.12] gh-77377: Ensure multiprocessing SemLock is valid for spawn-based Process before serializing it (GH-107275) (#108377) gh-77377: Ensure multiprocessing SemLock is valid for spawn-based Process before serializing it (GH-107275) Ensure multiprocessing SemLock is valid for spawn Process before serializing it. Creating a multiprocessing SemLock with a fork context, and then trying to pass it to a spawn-created Process, would segfault if not detected early. --------- (cherry picked from commit 1700d34d314f5304a7a75363bda295a8c15c371f) Co-authored-by: albanD Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Antoine Pitrou --- Lib/multiprocessing/synchronize.py | 9 ++++++-- Lib/test/_test_multiprocessing.py | 22 +++++++++++++++++++ ...3-07-25-22-35-35.gh-issue-77377.EHAbXx.rst | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py index 42624b543601a1..2328d332123082 100644 --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -50,8 +50,8 @@ class SemLock(object): def __init__(self, kind, value, maxvalue, *, ctx): if ctx is None: ctx = context._default_context.get_context() - name = ctx.get_start_method() - unlink_now = sys.platform == 'win32' or name == 'fork' + self.is_fork_ctx = ctx.get_start_method() == 'fork' + unlink_now = sys.platform == 'win32' or self.is_fork_ctx for i in range(100): try: sl = self._semlock = _multiprocessing.SemLock( @@ -103,6 +103,11 @@ def __getstate__(self): if sys.platform == 'win32': h = context.get_spawning_popen().duplicate_for_child(sl.handle) else: + if self.is_fork_ctx: + raise RuntimeError('A SemLock created in a fork context is being ' + 'shared with a process in a spawn context. This is ' + 'not supported. Please use the same context to create ' + 'multiprocessing objects and Process.') h = sl.handle return (h, sl.kind, sl.maxvalue, sl.name) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 4afbe172a1eefa..1afb8735a2f55d 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5383,6 +5383,28 @@ def test_preload_resources(self): print(err) self.fail("failed spawning forkserver or grandchild") + @unittest.skipIf(sys.platform == "win32", + "Only Spawn on windows so no risk of mixing") + @only_run_in_spawn_testsuite("avoids redundant testing.") + def test_mixed_startmethod(self): + # Fork-based locks cannot be used with spawned process + for process_method in ["spawn", "forkserver"]: + queue = multiprocessing.get_context("fork").Queue() + process_ctx = multiprocessing.get_context(process_method) + p = process_ctx.Process(target=close_queue, args=(queue,)) + err_msg = "A SemLock created in a fork" + with self.assertRaisesRegex(RuntimeError, err_msg): + p.start() + + # non-fork-based locks can be used with all other start methods + for queue_method in ["spawn", "forkserver"]: + for process_method in multiprocessing.get_all_start_methods(): + queue = multiprocessing.get_context(queue_method).Queue() + process_ctx = multiprocessing.get_context(process_method) + p = process_ctx.Process(target=close_queue, args=(queue,)) + p.start() + p.join() + @unittest.skipIf(sys.platform == "win32", "test semantics don't make sense on Windows") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst new file mode 100644 index 00000000000000..194851dea13352 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst @@ -0,0 +1 @@ +Ensure that multiprocessing synchronization objects created in a fork context are not sent to a different process created in a spawn context. This changes a segfault into an actionable RuntimeError in the parent process. From b312d4fd7e40f891f7f1ab8664c9a8472a986856 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 23 Aug 2023 16:44:50 -0700 Subject: [PATCH 0626/1206] [3.12] gh-70766: Mention the object getstate caveat in 3.11 What's new. (GH-108379) (#108384) gh-70766: Mention the object getstate caveat in 3.11 What's new. (GH-108379) (cherry picked from commit b6be18812c68fce5ab56c266dc5fc5a3cceb09c0) Co-authored-by: Gregory P. Smith --- Doc/whatsnew/3.11.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 6112e807a1225e..394cb78400043f 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -459,6 +459,10 @@ Other Language Changes :class:`collections.OrderedDict`, :class:`collections.deque`, :class:`weakref.WeakSet`, and :class:`datetime.tzinfo` now copies and pickles instance attributes implemented as :term:`slots <__slots__>`. + This change has an unintended side effect: It trips up a small minority + of existing Python projects not expecting :meth:`object.__getstate__` to + exist. See the later comments on :gh:`70766` for discussions of what + workarounds such code may need. (Contributed by Serhiy Storchaka in :issue:`26579`.) .. _whatsnew311-pythonsafepath: From 9903fe1c2af17e16ceac3b2a30dac37cc2fa7463 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 24 Aug 2023 01:20:40 -0700 Subject: [PATCH 0627/1206] [3.12] gh-108388: regrtest splits test_asyncio package (GH-108393) (#108397) gh-108388: regrtest splits test_asyncio package (GH-108393) Currently, test_asyncio package is only splitted into sub-tests when using command "./python -m test". With this change, it's also splitted when passing it on the command line: "./python -m test test_asyncio". Remove the concept of "STDTESTS". Python is now mature enough to not have to bother with that anymore. Removing STDTESTS simplify the code. (cherry picked from commit 174e9da0836844a2138cc8915dd305cb2cd7a583) Co-authored-by: Victor Stinner --- Lib/test/libregrtest/main.py | 25 +++++++------- Lib/test/libregrtest/runtest.py | 58 ++++++++++++++++----------------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 9001ca33b6166a..3df95db3eb6e1d 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -11,8 +11,8 @@ import unittest from test.libregrtest.cmdline import _parse_args from test.libregrtest.runtest import ( - findtests, runtest, get_abs_module, is_failed, - STDTESTS, NOTTESTS, PROGRESS_MIN_TIME, + findtests, split_test_packages, runtest, get_abs_module, is_failed, + PROGRESS_MIN_TIME, Passed, Failed, EnvChanged, Skipped, ResourceDenied, Interrupted, ChildError, DidNotRun) from test.libregrtest.setup import setup_tests @@ -246,26 +246,23 @@ def find_tests(self, tests): # add default PGO tests if no tests are specified setup_pgo_tests(self.ns) - stdtests = STDTESTS[:] - nottests = NOTTESTS.copy() + exclude = set() if self.ns.exclude: for arg in self.ns.args: - if arg in stdtests: - stdtests.remove(arg) - nottests.add(arg) + exclude.add(arg) self.ns.args = [] - # if testdir is set, then we are not running the python tests suite, so - # don't add default tests to be executed or skipped (pass empty values) - if self.ns.testdir: - alltests = findtests(self.ns.testdir, list(), set()) - else: - alltests = findtests(self.ns.testdir, stdtests, nottests) + alltests = findtests(testdir=self.ns.testdir, exclude=exclude) if not self.ns.fromfile: - self.selected = self.tests or self.ns.args or alltests + self.selected = self.tests or self.ns.args + if self.selected: + self.selected = split_test_packages(self.selected) + else: + self.selected = alltests else: self.selected = self.tests + if self.ns.single: self.selected = self.selected[:1] try: diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index 61595277ed6d5a..e927079da47a85 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -125,24 +125,6 @@ def __str__(self) -> str: # the test is running in background PROGRESS_MIN_TIME = 30.0 # seconds -# small set of tests to determine if we have a basically functioning interpreter -# (i.e. if any of these fail, then anything else is likely to follow) -STDTESTS = [ - 'test_grammar', - 'test_opcodes', - 'test_dict', - 'test_builtin', - 'test_exceptions', - 'test_types', - 'test_unittest', - 'test_doctest', - 'test_doctest2', - 'test_support' -] - -# set of tests that we don't want to be executed when using regrtest -NOTTESTS = set() - #If these test directories are encountered recurse into them and treat each # test_ .py or dir as a separate test module. This can increase parallelism. # Beware this can't generally be done for any directory with sub-tests as the @@ -166,22 +148,38 @@ def findtestdir(path=None): return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir -def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS, *, split_test_dirs=SPLITTESTDIRS, base_mod=""): +def findtests(*, testdir=None, exclude=(), + split_test_dirs=SPLITTESTDIRS, base_mod=""): """Return a list of all applicable test modules.""" testdir = findtestdir(testdir) - names = os.listdir(testdir) tests = [] - others = set(stdtests) | nottests - for name in names: + for name in os.listdir(testdir): mod, ext = os.path.splitext(name) - if mod[:5] == "test_" and mod not in others: - if mod in split_test_dirs: - subdir = os.path.join(testdir, mod) - mod = f"{base_mod or 'test'}.{mod}" - tests.extend(findtests(subdir, [], nottests, split_test_dirs=split_test_dirs, base_mod=mod)) - elif ext in (".py", ""): - tests.append(f"{base_mod}.{mod}" if base_mod else mod) - return stdtests + sorted(tests) + if (not mod.startswith("test_")) or (mod in exclude): + continue + if mod in split_test_dirs: + subdir = os.path.join(testdir, mod) + mod = f"{base_mod or 'test'}.{mod}" + tests.extend(findtests(testdir=subdir, exclude=exclude, + split_test_dirs=split_test_dirs, base_mod=mod)) + elif ext in (".py", ""): + tests.append(f"{base_mod}.{mod}" if base_mod else mod) + return sorted(tests) + + +def split_test_packages(tests, *, testdir=None, exclude=(), + split_test_dirs=SPLITTESTDIRS): + testdir = findtestdir(testdir) + splitted = [] + for name in tests: + if name in split_test_dirs: + subdir = os.path.join(testdir, name) + splitted.extend(findtests(testdir=subdir, exclude=exclude, + split_test_dirs=split_test_dirs, + base_mod=name)) + else: + splitted.append(name) + return splitted def get_abs_module(ns: Namespace, test_name: str) -> str: From 459f24aef09dce122362ee2f234e97916cbf1e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Thu, 24 Aug 2023 12:08:43 +0200 Subject: [PATCH 0628/1206] [3.12] gh-108342: Make ssl TestPreHandshakeClose more reliable (GH-108370) (#108404) * In preauth tests of test_ssl, explicitly break reference cycles invoving SingleConnectionTestServerThread to make sure that the thread is deleted. Otherwise, the test marks the environment as altered because the threading module sees a "dangling thread" (SingleConnectionTestServerThread). This test leak was introduced by the test added for the fix of issue gh-108310. * Use support.SHORT_TIMEOUT instead of hardcoded 1.0 or 2.0 seconds timeout. * SingleConnectionTestServerThread.run() catchs TimeoutError * Fix a race condition (missing synchronization) in test_preauth_data_to_tls_client(): the server now waits until the client connect() completed in call_after_accept(). * test_https_client_non_tls_response_ignored() calls server.join() explicitly. * Replace "localhost" with server.listener.getsockname()[0]. (cherry picked from commit 592bacb6fc0833336c0453e818e9b95016e9fd47) Co-authored-by: Victor Stinner --- Lib/test/test_ssl.py | 102 ++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index ad5377ec059c0b..4e49dc5640d3f5 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -4672,12 +4672,16 @@ class TestPreHandshakeClose(unittest.TestCase): class SingleConnectionTestServerThread(threading.Thread): - def __init__(self, *, name, call_after_accept): + def __init__(self, *, name, call_after_accept, timeout=None): self.call_after_accept = call_after_accept self.received_data = b'' # set by .run() self.wrap_error = None # set by .run() self.listener = None # set by .start() self.port = None # set by .start() + if timeout is None: + self.timeout = support.SHORT_TIMEOUT + else: + self.timeout = timeout super().__init__(name=name) def __enter__(self): @@ -4700,13 +4704,19 @@ def start(self): self.ssl_ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY) self.listener = socket.socket() self.port = socket_helper.bind_port(self.listener) - self.listener.settimeout(2.0) + self.listener.settimeout(self.timeout) self.listener.listen(1) super().start() def run(self): - conn, address = self.listener.accept() - self.listener.close() + try: + conn, address = self.listener.accept() + except TimeoutError: + # on timeout, just close the listener + return + finally: + self.listener.close() + with conn: if self.call_after_accept(conn): return @@ -4734,8 +4744,13 @@ def non_linux_skip_if_other_okay_error(self, err): # we're specifically trying to test. The way this test is written # is known to work on Linux. We'll skip it anywhere else that it # does not present as doing so. - self.skipTest(f"Could not recreate conditions on {sys.platform}:" - f" {err=}") + try: + self.skipTest(f"Could not recreate conditions on {sys.platform}:" + f" {err=}") + finally: + # gh-108342: Explicitly break the reference cycle + err = None + # If maintaining this conditional winds up being a problem. # just turn this into an unconditional skip anything but Linux. # The important thing is that our CI has the logic covered. @@ -4746,7 +4761,7 @@ def test_preauth_data_to_tls_server(self): def call_after_accept(unused): server_accept_called.set() - if not ready_for_server_wrap_socket.wait(2.0): + if not ready_for_server_wrap_socket.wait(support.SHORT_TIMEOUT): raise RuntimeError("wrap_socket event never set, test may fail.") return False # Tell the server thread to continue. @@ -4767,20 +4782,31 @@ def call_after_accept(unused): ready_for_server_wrap_socket.set() server.join() + wrap_error = server.wrap_error - self.assertEqual(b"", server.received_data) - self.assertIsInstance(wrap_error, OSError) # All platforms. - self.non_linux_skip_if_other_okay_error(wrap_error) - self.assertIsInstance(wrap_error, ssl.SSLError) - self.assertIn("before TLS handshake with data", wrap_error.args[1]) - self.assertIn("before TLS handshake with data", wrap_error.reason) - self.assertNotEqual(0, wrap_error.args[0]) - self.assertIsNone(wrap_error.library, msg="attr must exist") + server.wrap_error = None + try: + self.assertEqual(b"", server.received_data) + self.assertIsInstance(wrap_error, OSError) # All platforms. + self.non_linux_skip_if_other_okay_error(wrap_error) + self.assertIsInstance(wrap_error, ssl.SSLError) + self.assertIn("before TLS handshake with data", wrap_error.args[1]) + self.assertIn("before TLS handshake with data", wrap_error.reason) + self.assertNotEqual(0, wrap_error.args[0]) + self.assertIsNone(wrap_error.library, msg="attr must exist") + finally: + # gh-108342: Explicitly break the reference cycle + wrap_error = None + server = None def test_preauth_data_to_tls_client(self): + server_can_continue_with_wrap_socket = threading.Event() client_can_continue_with_wrap_socket = threading.Event() def call_after_accept(conn_to_client): + if not server_can_continue_with_wrap_socket.wait(support.SHORT_TIMEOUT): + print("ERROR: test client took too long") + # This forces an immediate connection close via RST on .close(). set_socket_so_linger_on_with_zero_timeout(conn_to_client) conn_to_client.send( @@ -4800,8 +4826,10 @@ def call_after_accept(conn_to_client): with socket.socket() as client: client.connect(server.listener.getsockname()) - if not client_can_continue_with_wrap_socket.wait(2.0): - self.fail("test server took too long.") + server_can_continue_with_wrap_socket.set() + + if not client_can_continue_with_wrap_socket.wait(support.SHORT_TIMEOUT): + self.fail("test server took too long") ssl_ctx = ssl.create_default_context() try: tls_client = ssl_ctx.wrap_socket( @@ -4815,24 +4843,31 @@ def call_after_accept(conn_to_client): tls_client.close() server.join() - self.assertEqual(b"", received_data) - self.assertIsInstance(wrap_error, OSError) # All platforms. - self.non_linux_skip_if_other_okay_error(wrap_error) - self.assertIsInstance(wrap_error, ssl.SSLError) - self.assertIn("before TLS handshake with data", wrap_error.args[1]) - self.assertIn("before TLS handshake with data", wrap_error.reason) - self.assertNotEqual(0, wrap_error.args[0]) - self.assertIsNone(wrap_error.library, msg="attr must exist") + try: + self.assertEqual(b"", received_data) + self.assertIsInstance(wrap_error, OSError) # All platforms. + self.non_linux_skip_if_other_okay_error(wrap_error) + self.assertIsInstance(wrap_error, ssl.SSLError) + self.assertIn("before TLS handshake with data", wrap_error.args[1]) + self.assertIn("before TLS handshake with data", wrap_error.reason) + self.assertNotEqual(0, wrap_error.args[0]) + self.assertIsNone(wrap_error.library, msg="attr must exist") + finally: + # gh-108342: Explicitly break the reference cycle + wrap_error = None + server = None def test_https_client_non_tls_response_ignored(self): - server_responding = threading.Event() class SynchronizedHTTPSConnection(http.client.HTTPSConnection): def connect(self): + # Call clear text HTTP connect(), not the encrypted HTTPS (TLS) + # connect(): wrap_socket() is called manually below. http.client.HTTPConnection.connect(self) + # Wait for our fault injection server to have done its thing. - if not server_responding.wait(1.0) and support.verbose: + if not server_responding.wait(support.SHORT_TIMEOUT) and support.verbose: sys.stdout.write("server_responding event never set.") self.sock = self._context.wrap_socket( self.sock, server_hostname=self.host) @@ -4847,28 +4882,33 @@ def call_after_accept(conn_to_client): server_responding.set() return True # Tell the server to stop. + timeout = 2.0 server = self.SingleConnectionTestServerThread( call_after_accept=call_after_accept, - name="non_tls_http_RST_responder") + name="non_tls_http_RST_responder", + timeout=timeout) self.enterContext(server) # starts it & unittest.TestCase stops it. # Redundant; call_after_accept sets SO_LINGER on the accepted conn. set_socket_so_linger_on_with_zero_timeout(server.listener) connection = SynchronizedHTTPSConnection( - f"localhost", + server.listener.getsockname()[0], port=server.port, context=ssl.create_default_context(), - timeout=2.0, + timeout=timeout, ) + # There are lots of reasons this raises as desired, long before this # test was added. Sending the request requires a successful TLS wrapped # socket; that fails if the connection is broken. It may seem pointless # to test this. It serves as an illustration of something that we never # want to happen... properly not happening. - with self.assertRaises(OSError) as err_ctx: + with self.assertRaises(OSError): connection.request("HEAD", "/test", headers={"Host": "localhost"}) response = connection.getresponse() + server.join() + class TestEnumerations(unittest.TestCase): From 20357ed2a434fc59a9cd33c162594e8f792813b4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 24 Aug 2023 03:30:16 -0700 Subject: [PATCH 0629/1206] [3.12] gh-108111: Flush gzip write buffer before seeking, fixing bad writes (GH-108341) (#108402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-108111: Flush gzip write buffer before seeking, fixing bad writes (GH-108341) (cherry picked from commit 2eb60c1934f47671e6b3c9b90b6d9f1912d829a0) Co-authored-by: Chris Markiewicz Co-authored-by: Åukasz Langa --- Lib/gzip.py | 3 +++ Lib/test/test_gzip.py | 12 ++++++++++++ Misc/ACKS | 1 + .../2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst | 2 ++ 4 files changed, 18 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst diff --git a/Lib/gzip.py b/Lib/gzip.py index cf8b675064ce89..177f9080dc5af8 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -401,6 +401,9 @@ def seekable(self): def seek(self, offset, whence=io.SEEK_SET): if self.mode == WRITE: + self._check_not_closed() + # Flush buffer to ensure validity of self.offset + self._buffer.flush() if whence != io.SEEK_SET: if whence == io.SEEK_CUR: offset = self.offset + offset diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index b06b3b09411d62..128f933787a3f6 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -665,6 +665,18 @@ def flush(self, mode=-1): ] self.assertEqual(fc.modes, expected_modes) + def test_write_seek_write(self): + # Make sure that offset is up-to-date before seeking + # See issue GH-108111 + b = io.BytesIO() + message = b"important message here." + with gzip.GzipFile(fileobj=b, mode='w') as f: + f.write(message) + f.seek(len(message)) + f.write(message) + data = b.getvalue() + self.assertEqual(gzip.decompress(data), message * 2) + class TestOpen(BaseTest): def test_binary_modes(self): diff --git a/Misc/ACKS b/Misc/ACKS index 645ad5b700baaa..d16ec34a1f0906 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1149,6 +1149,7 @@ Colin Marc Vincent Marchetti David Marek Doug Marien +Chris Markiewicz Sven Marnach John Marshall Alex Martelli diff --git a/Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst b/Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst new file mode 100644 index 00000000000000..8eafa6cfbbf8cf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst @@ -0,0 +1,2 @@ +Fix a regression introduced in GH-101251 for 3.12, resulting in an incorrect +offset calculation in :meth:`gzip.GzipFile.seek`. From 09487a202fdcbc94089794ad80158d3847d4a6f8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 24 Aug 2023 03:30:57 -0700 Subject: [PATCH 0630/1206] [3.12] gh-107432 Update Porting Python 2 Code to Python 3 how-to (GH-107434) (#108409) gh-107432 Update Porting Python 2 Code to Python 3 how-to (GH-107434) https://docs.python.org/3/howto/pyporting.htmlGH-porting-python-2-code-to-python-3 was written for another time. In this patch: - material that frames Python 3 as "new" is removed - descriptions and directions have been trimmed (cherry picked from commit 809ea7c4b6c2b818ae510f1f58e82b6b05ed4ef9) Co-authored-by: Daniele Procida --- Doc/howto/pyporting.rst | 215 ++++++++++++++++++---------------------- 1 file changed, 94 insertions(+), 121 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst index baea3e85c3b84b..6c30a0dd7d6bcc 100644 --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -1,49 +1,47 @@ .. _pyporting-howto: -********************************* -Porting Python 2 Code to Python 3 -********************************* +************************************* +How to port Python 2 Code to Python 3 +************************************* :author: Brett Cannon .. topic:: Abstract - With Python 3 being the future of Python while Python 2 is still in active - use, it is good to have your project available for both major releases of - Python. This guide is meant to help you figure out how best to support both - Python 2 & 3 simultaneously. + Python 2 reached its official end-of-life at the start of 2020. This means + that no new bug reports, fixes, or changes will be made to Python 2 - it's + no longer supported. + + This guide is intended to provide you with a path to Python 3 for your + code, that includes compatibility with Python 2 as a first step. If you are looking to port an extension module instead of pure Python code, please see :ref:`cporting-howto`. - If you would like to read one core Python developer's take on why Python 3 - came into existence, you can read Nick Coghlan's `Python 3 Q & A`_ or - Brett Cannon's `Why Python 3 exists`_. - + The archived python-porting_ mailing list may contain some useful guidance. - For help with porting, you can view the archived python-porting_ mailing list. The Short Explanation ===================== -To make your project be single-source Python 2/3 compatible, the basic steps +To achieve Python 2/3 compatibility in a single code base, the basic steps are: #. Only worry about supporting Python 2.7 #. Make sure you have good test coverage (coverage.py_ can help; ``python -m pip install coverage``) -#. Learn the differences between Python 2 & 3 +#. Learn the differences between Python 2 and 3 #. Use Futurize_ (or Modernize_) to update your code (e.g. ``python -m pip install future``) #. Use Pylint_ to help make sure you don't regress on your Python 3 support (``python -m pip install pylint``) #. Use caniusepython3_ to find out which of your dependencies are blocking your use of Python 3 (``python -m pip install caniusepython3``) #. Once your dependencies are no longer blocking you, use continuous integration - to make sure you stay compatible with Python 2 & 3 (tox_ can help test + to make sure you stay compatible with Python 2 and 3 (tox_ can help test against multiple versions of Python; ``python -m pip install tox``) #. Consider using optional static type checking to make sure your type usage - works in both Python 2 & 3 (e.g. use mypy_ to check your typing under both - Python 2 & Python 3; ``python -m pip install mypy``). + works in both Python 2 and 3 (e.g. use mypy_ to check your typing under both + Python 2 and Python 3; ``python -m pip install mypy``). .. note:: @@ -55,43 +53,30 @@ are: Details ======= -A key point about supporting Python 2 & 3 simultaneously is that you can start -**today**! Even if your dependencies are not supporting Python 3 yet that does -not mean you can't modernize your code **now** to support Python 3. Most changes -required to support Python 3 lead to cleaner code using newer practices even in -Python 2 code. +Even if other factors - say, dependencies over which you have no control - +still require you to support Python 2, that does not prevent you taking the +step of including Python 3 support. -Another key point is that modernizing your Python 2 code to also support -Python 3 is largely automated for you. While you might have to make some API -decisions thanks to Python 3 clarifying text data versus binary data, the -lower-level work is now mostly done for you and thus can at least benefit from -the automated changes immediately. +Most changes required to support Python 3 lead to cleaner code using newer +practices even in Python 2 code. -Keep those key points in mind while you read on about the details of porting -your code to support Python 2 & 3 simultaneously. +Different versions of Python 2 +------------------------------ -Drop support for Python 2.6 and older -------------------------------------- +Ideally, your code should be compatible with Python 2.7, which was the +last supported version of Python 2. -While you can make Python 2.5 work with Python 3, it is **much** easier if you -only have to work with Python 2.7. If dropping Python 2.5 is not an -option then the six_ project can help you support Python 2.5 & 3 simultaneously -(``python -m pip install six``). Do realize, though, that nearly all the projects listed -in this HOWTO will not be available to you. +Some of the tools mentioned in this guide will not work with Python 2.6. -If you are able to skip Python 2.5 and older, then the required changes -to your code should continue to look and feel like idiomatic Python code. At -worst you will have to use a function instead of a method in some instances or -have to import a function instead of using a built-in one, but otherwise the -overall transformation should not feel foreign to you. +If absolutely necessary, the six_ project can help you support Python 2.5 and +3 simultaneously. Do realize, though, that nearly all the projects listed in +this guide will not be available to you. -But you should aim for only supporting Python 2.7. Python 2.6 is no longer -freely supported and thus is not receiving bugfixes. This means **you** will have -to work around any issues you come across with Python 2.6. There are also some -tools mentioned in this HOWTO which do not support Python 2.6 (e.g., Pylint_), -and this will become more commonplace as time goes on. It will simply be easier -for you if you only support the versions of Python that you have to support. +If you are able to skip Python 2.5 and older, the required changes to your +code will be minimal. At worst you will have to use a function instead of a +method in some instances or have to import a function instead of using a +built-in one. Make sure you specify the proper version support in your ``setup.py`` file @@ -118,62 +103,57 @@ coverage). If you don't already have a tool to measure test coverage then coverage.py_ is recommended. -Learn the differences between Python 2 & 3 -------------------------------------------- +Be aware of the differences between Python 2 and 3 +-------------------------------------------------- Once you have your code well-tested you are ready to begin porting your code to Python 3! But to fully understand how your code is going to change and what you want to look out for while you code, you will want to learn what changes -Python 3 makes in terms of Python 2. Typically the two best ways of doing that -is reading the :ref:`"What's New" ` doc for each release of Python 3 and the -`Porting to Python 3`_ book (which is free online). There is also a handy -`cheat sheet`_ from the Python-Future project. +Python 3 makes in terms of Python 2. + +Some resources for understanding the differences and their implications for you +code: + +* the :ref:`"What's New" ` doc for each release of Python 3 +* the `Porting to Python 3`_ book (which is free online) +* the handy `cheat sheet`_ from the Python-Future project. Update your code ---------------- -Once you feel like you know what is different in Python 3 compared to Python 2, -it's time to update your code! You have a choice between two tools in porting -your code automatically: Futurize_ and Modernize_. Which tool you choose will -depend on how much like Python 3 you want your code to be. Futurize_ does its -best to make Python 3 idioms and practices exist in Python 2, e.g. backporting -the ``bytes`` type from Python 3 so that you have semantic parity between the -major versions of Python. Modernize_, -on the other hand, is more conservative and targets a Python 2/3 subset of -Python, directly relying on six_ to help provide compatibility. As Python 3 is -the future, it might be best to consider Futurize to begin adjusting to any new -practices that Python 3 introduces which you are not accustomed to yet. - -Regardless of which tool you choose, they will update your code to run under -Python 3 while staying compatible with the version of Python 2 you started with. -Depending on how conservative you want to be, you may want to run the tool over -your test suite first and visually inspect the diff to make sure the -transformation is accurate. After you have transformed your test suite and -verified that all the tests still pass as expected, then you can transform your -application code knowing that any tests which fail is a translation failure. +There are tools available that can port your code automatically. + +Futurize_ does its best to make Python 3 idioms and practices exist in Python +2, e.g. backporting the ``bytes`` type from Python 3 so that you have +semantic parity between the major versions of Python. This is the better +approach for most cases. + +Modernize_, on the other hand, is more conservative and targets a Python 2/3 +subset of Python, directly relying on six_ to help provide compatibility. + +A good approach is to run the tool over your test suite first and visually +inspect the diff to make sure the transformation is accurate. After you have +transformed your test suite and verified that all the tests still pass as +expected, then you can transform your application code knowing that any tests +which fail is a translation failure. Unfortunately the tools can't automate everything to make your code work under -Python 3 and so there are a handful of things you will need to update manually -to get full Python 3 support (which of these steps are necessary vary between -the tools). Read the documentation for the tool you choose to use to see what it -fixes by default and what it can do optionally to know what will (not) be fixed -for you and what you may have to fix on your own (e.g. using ``io.open()`` over -the built-in ``open()`` function is off by default in Modernize). Luckily, -though, there are only a couple of things to watch out for which can be -considered large issues that may be hard to debug if not watched for. +Python 3, and you will also need to read the tools' documentation in case some +options you need are turned off by default. +Key issues to be aware of and check for: Division ++++++++ -In Python 3, ``5 / 2 == 2.5`` and not ``2``; all division between ``int`` values -result in a ``float``. This change has actually been planned since Python 2.2 -which was released in 2002. Since then users have been encouraged to add -``from __future__ import division`` to any and all files which use the ``/`` and -``//`` operators or to be running the interpreter with the ``-Q`` flag. If you -have not been doing this then you will need to go through your code and do two -things: +In Python 3, ``5 / 2 == 2.5`` and not ``2`` as it was in Python 2; all +division between ``int`` values result in a ``float``. This change has +actually been planned since Python 2.2 which was released in 2002. Since then +users have been encouraged to add ``from __future__ import division`` to any +and all files which use the ``/`` and ``//`` operators or to be running the +interpreter with the ``-Q`` flag. If you have not been doing this then you +will need to go through your code and do two things: #. Add ``from __future__ import division`` to your files #. Update any division operator as necessary to either use ``//`` to use floor @@ -197,30 +177,29 @@ specific type. This complicated the situation especially for anyone supporting multiple languages as APIs wouldn't bother explicitly supporting ``unicode`` when they claimed text data support. -To make the distinction between text and binary data clearer and more -pronounced, Python 3 did what most languages created in the age of the internet -have done and made text and binary data distinct types that cannot blindly be -mixed together (Python predates widespread access to the internet). For any code -that deals only with text or only binary data, this separation doesn't pose an -issue. But for code that has to deal with both, it does mean you might have to -now care about when you are using text compared to binary data, which is why -this cannot be entirely automated. - -To start, you will need to decide which APIs take text and which take binary -(it is **highly** recommended you don't design APIs that can take both due to -the difficulty of keeping the code working; as stated earlier it is difficult to -do well). In Python 2 this means making sure the APIs that take text can work -with ``unicode`` and those that work with binary data work with the -``bytes`` type from Python 3 (which is a subset of ``str`` in Python 2 and acts -as an alias for ``bytes`` type in Python 2). Usually the biggest issue is -realizing which methods exist on which types in Python 2 & 3 simultaneously -(for text that's ``unicode`` in Python 2 and ``str`` in Python 3, for binary -that's ``str``/``bytes`` in Python 2 and ``bytes`` in Python 3). The following -table lists the **unique** methods of each data type across Python 2 & 3 -(e.g., the ``decode()`` method is usable on the equivalent binary data type in -either Python 2 or 3, but it can't be used by the textual data type consistently -between Python 2 and 3 because ``str`` in Python 3 doesn't have the method). Do -note that as of Python 3.5 the ``__mod__`` method was added to the bytes type. +Python 3 made text and binary data distinct types that cannot simply be mixed +together. For any code that deals only with text or only binary data, this +separation doesn't pose an issue. But for code that has to deal with both, it +does mean you might have to now care about when you are using text compared +to binary data, which is why this cannot be entirely automated. + +Decide which APIs take text and which take binary (it is **highly** recommended +you don't design APIs that can take both due to the difficulty of keeping the +code working; as stated earlier it is difficult to do well). In Python 2 this +means making sure the APIs that take text can work with ``unicode`` and those +that work with binary data work with the ``bytes`` type from Python 3 +(which is a subset of ``str`` in Python 2 and acts as an alias for ``bytes`` +type in Python 2). Usually the biggest issue is realizing which methods exist +on which types in Python 2 and 3 simultaneously (for text that's ``unicode`` +in Python 2 and ``str`` in Python 3, for binary that's ``str``/``bytes`` in +Python 2 and ``bytes`` in Python 3). + +The following table lists the **unique** methods of each data type across +Python 2 and 3 (e.g., the ``decode()`` method is usable on the equivalent binary +data type in either Python 2 or 3, but it can't be used by the textual data +type consistently between Python 2 and 3 because ``str`` in Python 3 doesn't +have the method). Do note that as of Python 3.5 the ``__mod__`` method was +added to the bytes type. ======================== ===================== **Text data** **Binary data** @@ -246,12 +225,11 @@ having to keep track of what type of data you are working with. The next issue is making sure you know whether the string literals in your code represent text or binary data. You should add a ``b`` prefix to any literal that presents binary data. For text you should add a ``u`` prefix to -the text literal. (there is a :mod:`__future__` import to force all unspecified +the text literal. (There is a :mod:`__future__` import to force all unspecified literals to be Unicode, but usage has shown it isn't as effective as adding a ``b`` or ``u`` prefix to all literals explicitly) -As part of this dichotomy you also need to be careful about opening files. -Unless you have been working on Windows, there is a chance you have not always +You also need to be careful about opening files. Possibly you have not always bothered to add the ``b`` mode when opening a binary file (e.g., ``rb`` for binary reading). Under Python 3, binary files and text files are clearly distinct and mutually incompatible; see the :mod:`io` module for details. @@ -265,7 +243,7 @@ outdated practice of using :func:`codecs.open` as that's only necessary for keeping compatibility with Python 2.5. The constructors of both ``str`` and ``bytes`` have different semantics for the -same arguments between Python 2 & 3. Passing an integer to ``bytes`` in Python 2 +same arguments between Python 2 and 3. Passing an integer to ``bytes`` in Python 2 will give you the string representation of the integer: ``bytes(3) == '3'``. But in Python 3, an integer argument to ``bytes`` will give you a bytes object as long as the integer specified, filled with null bytes: @@ -400,7 +378,7 @@ Use continuous integration to stay compatible --------------------------------------------- Once you are able to fully run under Python 3 you will want to make sure your -code always works under both Python 2 & 3. Probably the best tool for running +code always works under both Python 2 and 3. Probably the best tool for running your tests under multiple Python interpreters is tox_. You can then integrate tox with your continuous integration system so that you never accidentally break Python 2 or 3 support. @@ -413,11 +391,6 @@ separation of text/binary data handling or indexing on bytes you wouldn't easily find the mistake. This flag will raise an exception when these kinds of comparisons occur, making the mistake much easier to track down. -And that's mostly it! At this point your code base is compatible with both -Python 2 and 3 simultaneously. Your testing will also be set up so that you -don't accidentally break Python 2 or 3 compatibility regardless of which version -you typically run your tests under while developing. - Consider using optional static type checking -------------------------------------------- From 22621907eea3f0ed4ccf5a69bcef70a70396b36b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Aug 2023 09:15:53 -0700 Subject: [PATCH 0631/1206] [3.12] gh-108388: Split test_multiprocessing_spawn (GH-108396) (#108442) gh-108388: Split test_multiprocessing_spawn (GH-108396) Split test_multiprocessing_fork, test_multiprocessing_forkserver and test_multiprocessing_spawn into test packages. Each package is made of 4 sub-tests: processes, threads, manager and misc. It allows running more tests in parallel and so reduce the total test duration. (cherry picked from commit aa9a359ca2663195b0f04eef46109c28c4ff74d3) Co-authored-by: Victor Stinner --- Lib/test/_test_multiprocessing.py | 10 +++++++++- Lib/test/libregrtest/runtest.py | 3 +++ .../__init__.py} | 11 ++++------- Lib/test/test_multiprocessing_fork/test_manager.py | 7 +++++++ Lib/test/test_multiprocessing_fork/test_misc.py | 7 +++++++ Lib/test/test_multiprocessing_fork/test_processes.py | 7 +++++++ Lib/test/test_multiprocessing_fork/test_threads.py | 7 +++++++ .../__init__.py} | 11 ++++------- .../test_multiprocessing_forkserver/test_manager.py | 7 +++++++ .../test_multiprocessing_forkserver/test_misc.py | 7 +++++++ .../test_processes.py | 7 +++++++ .../test_multiprocessing_forkserver/test_threads.py | 7 +++++++ Lib/test/test_multiprocessing_spawn.py | 12 ------------ Lib/test/test_multiprocessing_spawn/__init__.py | 9 +++++++++ Lib/test/test_multiprocessing_spawn/test_manager.py | 7 +++++++ Lib/test/test_multiprocessing_spawn/test_misc.py | 7 +++++++ .../test_multiprocessing_spawn/test_processes.py | 7 +++++++ Lib/test/test_multiprocessing_spawn/test_threads.py | 7 +++++++ .../2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst | 4 ++++ 19 files changed, 117 insertions(+), 27 deletions(-) rename Lib/test/{test_multiprocessing_fork.py => test_multiprocessing_fork/__init__.py} (66%) create mode 100644 Lib/test/test_multiprocessing_fork/test_manager.py create mode 100644 Lib/test/test_multiprocessing_fork/test_misc.py create mode 100644 Lib/test/test_multiprocessing_fork/test_processes.py create mode 100644 Lib/test/test_multiprocessing_fork/test_threads.py rename Lib/test/{test_multiprocessing_forkserver.py => test_multiprocessing_forkserver/__init__.py} (58%) create mode 100644 Lib/test/test_multiprocessing_forkserver/test_manager.py create mode 100644 Lib/test/test_multiprocessing_forkserver/test_misc.py create mode 100644 Lib/test/test_multiprocessing_forkserver/test_processes.py create mode 100644 Lib/test/test_multiprocessing_forkserver/test_threads.py delete mode 100644 Lib/test/test_multiprocessing_spawn.py create mode 100644 Lib/test/test_multiprocessing_spawn/__init__.py create mode 100644 Lib/test/test_multiprocessing_spawn/test_manager.py create mode 100644 Lib/test/test_multiprocessing_spawn/test_misc.py create mode 100644 Lib/test/test_multiprocessing_spawn/test_processes.py create mode 100644 Lib/test/test_multiprocessing_spawn/test_threads.py create mode 100644 Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 1afb8735a2f55d..19e1086639bfed 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -6088,7 +6088,8 @@ class ThreadsMixin(BaseMixin): # Functions used to create test cases from the base ones in this module # -def install_tests_in_module_dict(remote_globs, start_method): +def install_tests_in_module_dict(remote_globs, start_method, + only_type=None, exclude_types=False): __module__ = remote_globs['__name__'] local_globs = globals() ALL_TYPES = {'processes', 'threads', 'manager'} @@ -6101,6 +6102,10 @@ def install_tests_in_module_dict(remote_globs, start_method): continue assert set(base.ALLOWED_TYPES) <= ALL_TYPES, base.ALLOWED_TYPES for type_ in base.ALLOWED_TYPES: + if only_type and type_ != only_type: + continue + if exclude_types: + continue newname = 'With' + type_.capitalize() + name[1:] Mixin = local_globs[type_.capitalize() + 'Mixin'] class Temp(base, Mixin, unittest.TestCase): @@ -6111,6 +6116,9 @@ class Temp(base, Mixin, unittest.TestCase): Temp.__module__ = __module__ remote_globs[newname] = Temp elif issubclass(base, unittest.TestCase): + if only_type: + continue + class Temp(base, object): pass Temp.__name__ = Temp.__qualname__ = name diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index e927079da47a85..cddb37c87aa4d4 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -132,6 +132,9 @@ def __str__(self) -> str: SPLITTESTDIRS = { "test_asyncio", + "test_multiprocessing_fork", + "test_multiprocessing_forkserver", + "test_multiprocessing_spawn", } # Storage of uncollectable objects diff --git a/Lib/test/test_multiprocessing_fork.py b/Lib/test/test_multiprocessing_fork/__init__.py similarity index 66% rename from Lib/test/test_multiprocessing_fork.py rename to Lib/test/test_multiprocessing_fork/__init__.py index 5000edb7c5c299..aa1fff50b28f5f 100644 --- a/Lib/test/test_multiprocessing_fork.py +++ b/Lib/test/test_multiprocessing_fork/__init__.py @@ -1,7 +1,6 @@ -import unittest -import test._test_multiprocessing - +import os.path import sys +import unittest from test import support if support.PGO: @@ -13,7 +12,5 @@ if sys.platform == 'darwin': raise unittest.SkipTest("test may crash on macOS (bpo-33725)") -test._test_multiprocessing.install_tests_in_module_dict(globals(), 'fork') - -if __name__ == '__main__': - unittest.main() +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_multiprocessing_fork/test_manager.py b/Lib/test/test_multiprocessing_fork/test_manager.py new file mode 100644 index 00000000000000..9efbb83bbb73bf --- /dev/null +++ b/Lib/test/test_multiprocessing_fork/test_manager.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'fork', only_type="manager") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_fork/test_misc.py b/Lib/test/test_multiprocessing_fork/test_misc.py new file mode 100644 index 00000000000000..891a494020c3a1 --- /dev/null +++ b/Lib/test/test_multiprocessing_fork/test_misc.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'fork', exclude_types=True) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_fork/test_processes.py b/Lib/test/test_multiprocessing_fork/test_processes.py new file mode 100644 index 00000000000000..e64e9afc0100e8 --- /dev/null +++ b/Lib/test/test_multiprocessing_fork/test_processes.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'fork', only_type="processes") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_fork/test_threads.py b/Lib/test/test_multiprocessing_fork/test_threads.py new file mode 100644 index 00000000000000..1670e34cb17f25 --- /dev/null +++ b/Lib/test/test_multiprocessing_fork/test_threads.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'fork', only_type="threads") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_forkserver.py b/Lib/test/test_multiprocessing_forkserver/__init__.py similarity index 58% rename from Lib/test/test_multiprocessing_forkserver.py rename to Lib/test/test_multiprocessing_forkserver/__init__.py index 6ad5faf9e8a329..d91715a344dfa7 100644 --- a/Lib/test/test_multiprocessing_forkserver.py +++ b/Lib/test/test_multiprocessing_forkserver/__init__.py @@ -1,7 +1,6 @@ -import unittest -import test._test_multiprocessing - +import os.path import sys +import unittest from test import support if support.PGO: @@ -10,7 +9,5 @@ if sys.platform == "win32": raise unittest.SkipTest("forkserver is not available on Windows") -test._test_multiprocessing.install_tests_in_module_dict(globals(), 'forkserver') - -if __name__ == '__main__': - unittest.main() +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_multiprocessing_forkserver/test_manager.py b/Lib/test/test_multiprocessing_forkserver/test_manager.py new file mode 100644 index 00000000000000..14f8f10dfb4e2f --- /dev/null +++ b/Lib/test/test_multiprocessing_forkserver/test_manager.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'forkserver', only_type="manager") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_forkserver/test_misc.py b/Lib/test/test_multiprocessing_forkserver/test_misc.py new file mode 100644 index 00000000000000..9cae1b50f71e00 --- /dev/null +++ b/Lib/test/test_multiprocessing_forkserver/test_misc.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'forkserver', exclude_types=True) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_forkserver/test_processes.py b/Lib/test/test_multiprocessing_forkserver/test_processes.py new file mode 100644 index 00000000000000..360967cf1ae152 --- /dev/null +++ b/Lib/test/test_multiprocessing_forkserver/test_processes.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'forkserver', only_type="processes") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_forkserver/test_threads.py b/Lib/test/test_multiprocessing_forkserver/test_threads.py new file mode 100644 index 00000000000000..719c752aa05350 --- /dev/null +++ b/Lib/test/test_multiprocessing_forkserver/test_threads.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'forkserver', only_type="threads") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_spawn.py b/Lib/test/test_multiprocessing_spawn.py deleted file mode 100644 index 6558952308f25c..00000000000000 --- a/Lib/test/test_multiprocessing_spawn.py +++ /dev/null @@ -1,12 +0,0 @@ -import unittest -import test._test_multiprocessing - -from test import support - -if support.PGO: - raise unittest.SkipTest("test is not helpful for PGO") - -test._test_multiprocessing.install_tests_in_module_dict(globals(), 'spawn') - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_multiprocessing_spawn/__init__.py b/Lib/test/test_multiprocessing_spawn/__init__.py new file mode 100644 index 00000000000000..3fd0f9b390612a --- /dev/null +++ b/Lib/test/test_multiprocessing_spawn/__init__.py @@ -0,0 +1,9 @@ +import os.path +import unittest +from test import support + +if support.PGO: + raise unittest.SkipTest("test is not helpful for PGO") + +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_multiprocessing_spawn/test_manager.py b/Lib/test/test_multiprocessing_spawn/test_manager.py new file mode 100644 index 00000000000000..b40bea0bf61581 --- /dev/null +++ b/Lib/test/test_multiprocessing_spawn/test_manager.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'spawn', only_type="manager") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_spawn/test_misc.py b/Lib/test/test_multiprocessing_spawn/test_misc.py new file mode 100644 index 00000000000000..32f37c5cc81ee1 --- /dev/null +++ b/Lib/test/test_multiprocessing_spawn/test_misc.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'spawn', exclude_types=True) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_spawn/test_processes.py b/Lib/test/test_multiprocessing_spawn/test_processes.py new file mode 100644 index 00000000000000..af764b0d8483ab --- /dev/null +++ b/Lib/test/test_multiprocessing_spawn/test_processes.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'spawn', only_type="processes") + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_multiprocessing_spawn/test_threads.py b/Lib/test/test_multiprocessing_spawn/test_threads.py new file mode 100644 index 00000000000000..c1257749b9c419 --- /dev/null +++ b/Lib/test/test_multiprocessing_spawn/test_threads.py @@ -0,0 +1,7 @@ +import unittest +from test._test_multiprocessing import install_tests_in_module_dict + +install_tests_in_module_dict(globals(), 'spawn', only_type="threads") + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst b/Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst new file mode 100644 index 00000000000000..8cf77b1cc187f1 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst @@ -0,0 +1,4 @@ +Split test_multiprocessing_fork, test_multiprocessing_forkserver and +test_multiprocessing_spawn into test packages. Each package is made of 4 +sub-tests: processes, threads, manager and misc. It allows running more tests +in parallel and so reduce the total test duration. Patch by Victor Stinner. From 0eb6d87304b5ca8ed84e5c885e2cef3eb24a3e3a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Aug 2023 09:18:24 -0700 Subject: [PATCH 0632/1206] [3.12] gh-80527: Change support.requires_legacy_unicode_capi() (GH-108438) (#108446) gh-80527: Change support.requires_legacy_unicode_capi() (GH-108438) The decorator now requires to be called with parenthesis: @support.requires_legacy_unicode_capi() instead of: @support.requires_legacy_unicode_capi The implementation now only imports _testcapi when the decorator is called, so "import test.support" no longer imports the _testcapi extension. (cherry picked from commit 995f4c48e11349fbfb9233e02b732d4534d3008e) Co-authored-by: Victor Stinner --- Lib/test/support/__init__.py | 15 ++++++++------- Lib/test/test_capi/test_getargs.py | 8 ++++---- Lib/test/test_csv.py | 2 +- Lib/test/test_decimal.py | 4 ++-- Lib/test/test_unicode.py | 4 ++-- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index c3c3cf0a71596c..ef7b5c814d5d47 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -21,11 +21,6 @@ from .testresult import get_test_runner -try: - from _testcapi import unicode_legacy_string -except ImportError: - unicode_legacy_string = None - __all__ = [ # globals "PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast", @@ -507,8 +502,14 @@ def has_no_debug_ranges(): def requires_debug_ranges(reason='requires co_positions / debug_ranges'): return unittest.skipIf(has_no_debug_ranges(), reason) -requires_legacy_unicode_capi = unittest.skipUnless(unicode_legacy_string, - 'requires legacy Unicode C API') +def requires_legacy_unicode_capi(): + try: + from _testcapi import unicode_legacy_string + except ImportError: + unicode_legacy_string = None + + return unittest.skipUnless(unicode_legacy_string, + 'requires legacy Unicode C API') # Is not actually used in tests, but is kept for compatibility. is_jython = sys.platform.startswith('java') diff --git a/Lib/test/test_capi/test_getargs.py b/Lib/test/test_capi/test_getargs.py index 3792d1a6515b44..ec4100e976e50d 100644 --- a/Lib/test/test_capi/test_getargs.py +++ b/Lib/test/test_capi/test_getargs.py @@ -1021,7 +1021,7 @@ def test_et_hash(self): buf = bytearray() self.assertRaises(ValueError, getargs_et_hash, 'abc\xe9', 'latin1', buf) - @support.requires_legacy_unicode_capi + @support.requires_legacy_unicode_capi() def test_u(self): from _testcapi import getargs_u with self.assertWarns(DeprecationWarning): @@ -1037,7 +1037,7 @@ def test_u(self): with self.assertWarns(DeprecationWarning): self.assertRaises(TypeError, getargs_u, None) - @support.requires_legacy_unicode_capi + @support.requires_legacy_unicode_capi() def test_u_hash(self): from _testcapi import getargs_u_hash with self.assertWarns(DeprecationWarning): @@ -1053,7 +1053,7 @@ def test_u_hash(self): with self.assertWarns(DeprecationWarning): self.assertRaises(TypeError, getargs_u_hash, None) - @support.requires_legacy_unicode_capi + @support.requires_legacy_unicode_capi() def test_Z(self): from _testcapi import getargs_Z with self.assertWarns(DeprecationWarning): @@ -1069,7 +1069,7 @@ def test_Z(self): with self.assertWarns(DeprecationWarning): self.assertIsNone(getargs_Z(None)) - @support.requires_legacy_unicode_capi + @support.requires_legacy_unicode_capi() def test_Z_hash(self): from _testcapi import getargs_Z_hash with self.assertWarns(DeprecationWarning): diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index de7ac97d72cb8e..bc9961e0831f0e 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -282,7 +282,7 @@ def test_writerows_errors(self): self.assertRaises(OSError, writer.writerows, BadIterable()) @support.cpython_only - @support.requires_legacy_unicode_capi + @support.requires_legacy_unicode_capi() @warnings_helper.ignore_warnings(category=DeprecationWarning) def test_writerows_legacy_strings(self): import _testcapi diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index d0ba34803c21e6..4d3ea732212905 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -587,7 +587,7 @@ def test_explicit_from_string(self): self.assertRaises(InvalidOperation, Decimal, "1_2_\u00003") @cpython_only - @requires_legacy_unicode_capi + @requires_legacy_unicode_capi() @warnings_helper.ignore_warnings(category=DeprecationWarning) def test_from_legacy_strings(self): import _testcapi @@ -2919,7 +2919,7 @@ def test_none_args(self): Overflow]) @cpython_only - @requires_legacy_unicode_capi + @requires_legacy_unicode_capi() @warnings_helper.ignore_warnings(category=DeprecationWarning) def test_from_legacy_strings(self): import _testcapi diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 4ebbb9d32a3d75..2fd66c93f9f319 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -814,7 +814,7 @@ def test_isidentifier(self): self.assertFalse("0".isidentifier()) @support.cpython_only - @support.requires_legacy_unicode_capi + @support.requires_legacy_unicode_capi() @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_isidentifier_legacy(self): u = 'ð–€ð–“ð–Žð–ˆð–”ð–‰ð–Š' @@ -2491,7 +2491,7 @@ def test_getnewargs(self): self.assertEqual(len(args), 1) @support.cpython_only - @support.requires_legacy_unicode_capi + @support.requires_legacy_unicode_capi() @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_resize(self): for length in range(1, 100, 7): From 9a225d7d5b0530ee73fa00d4816897997a9eb733 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 25 Aug 2023 18:19:53 +0200 Subject: [PATCH 0633/1206] [3.12] gh-108314: PyDict_GetItemString() mentions UTF-8 (#108448) gh-108314: PyDict_GetItemString() mentions UTF-8 PyDict_GetItemString(), PyDict_SetItemString() and PyDict_DelItemString() expects a UTF-8 encoding string for the key. --- Doc/c-api/dict.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index bd0c36a217e2ce..f668f845de610e 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -73,7 +73,7 @@ Dictionary Objects .. index:: single: PyUnicode_FromString() Insert *val* into the dictionary *p* using *key* as a key. *key* should - be a :c:expr:`const char*`. The key object is created using + be a :c:expr:`const char*` UTF-8 encoded bytes string. The key object is created using ``PyUnicode_FromString(key)``. Return ``0`` on success or ``-1`` on failure. This function *does not* steal a reference to *val*. @@ -88,7 +88,8 @@ Dictionary Objects .. c:function:: int PyDict_DelItemString(PyObject *p, const char *key) - Remove the entry in dictionary *p* which has a key specified by the string *key*. + Remove the entry in dictionary *p* which has a key specified by the UTF-8 + encoded bytes string *key*. If *key* is not in the dictionary, :exc:`KeyError` is raised. Return ``0`` on success or ``-1`` on failure. @@ -120,7 +121,8 @@ Dictionary Objects .. c:function:: PyObject* PyDict_GetItemString(PyObject *p, const char *key) This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a - :c:expr:`const char*`, rather than a :c:expr:`PyObject*`. + :c:expr:`const char*` UTF-8 encoded bytes string, rather than a + :c:expr:`PyObject*`. .. note:: From c5448ab6d45452eb976618013514f2eb89d4eea4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Aug 2023 09:20:38 -0700 Subject: [PATCH 0634/1206] [3.12] GH-108202: Document ``calendar`` exceptions (GH-108398) (#108467) GH-108202: Document ``calendar`` exceptions (GH-108398) (cherry picked from commit 135098743a0fae0efbcd98e35458e5bc721702e9) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/calendar.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 07d04a1c7b582a..3c097f4cf7abd9 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -469,6 +469,29 @@ The :mod:`calendar` module exports the following data attributes: Aliases for day numbers, where ``MONDAY`` is ``0`` and ``SUNDAY`` is ``6``. + +The :mod:`calendar` module defines the following exceptions: + +.. exception:: IllegalMonthError(month) + + A subclass of :exc:`ValueError`, + raised when the given month number is outside of the range 1-12 (inclusive). + + .. attribute:: month + + The invalid month number. + + +.. exception:: IllegalWeekdayError(weekday) + + A subclass of :exc:`ValueError`, + raised when the given weekday number is outside of the range 0-6 (inclusive). + + .. attribute:: weekday + + The invalid weekday number. + + .. seealso:: Module :mod:`datetime` From b28aaf98be0d42ccd687daa341de421422c07253 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Aug 2023 09:22:06 -0700 Subject: [PATCH 0635/1206] [3.12] gh-108418: Speed up bigmem compression tests in dry mode (GH-108419) (#108473) gh-108418: Speed up bigmem compression tests in dry mode (GH-108419) Only generate and compress small amount of random data in dry run. (cherry picked from commit 4ae3edf3008b70e20663143553a736d80ff3a501) Co-authored-by: Serhiy Storchaka --- Lib/test/test_bz2.py | 4 ++-- Lib/test/test_lzma.py | 4 ++-- Lib/test/test_zlib.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index e4dd7fc2100b62..1f0b9adc3698b4 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -721,10 +721,10 @@ def testEOFError(self): @bigmemtest(size=_4G + 100, memuse=3.3) def testDecompress4G(self, size): # "Test BZ2Decompressor.decompress() with >4GiB input" - blocksize = 10 * 1024 * 1024 + blocksize = min(10 * 1024 * 1024, size) block = random.randbytes(blocksize) try: - data = block * (size // blocksize + 1) + data = block * ((size-1) // blocksize + 1) compressed = bz2.compress(data) bz2d = BZ2Decompressor() decompressed = bz2d.decompress(compressed) diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py index ac53bdda2f1747..13b200912f6abd 100644 --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -352,10 +352,10 @@ def test_compressor_bigmem(self, size): @bigmemtest(size=_4G + 100, memuse=3) def test_decompressor_bigmem(self, size): lzd = LZMADecompressor() - blocksize = 10 * 1024 * 1024 + blocksize = min(10 * 1024 * 1024, size) block = random.randbytes(blocksize) try: - input = block * (size // blocksize + 1) + input = block * ((size-1) // blocksize + 1) cdata = lzma.compress(input) ddata = lzd.decompress(cdata) self.assertEqual(ddata, input) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 2113757254c0ed..55306c63cd4e16 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -989,10 +989,10 @@ def testEOFError(self): @bigmemtest(size=_4G + 100, memuse=3.3) def testDecompress4G(self, size): # "Test zlib._ZlibDecompressor.decompress() with >4GiB input" - blocksize = 10 * 1024 * 1024 + blocksize = min(10 * 1024 * 1024, size) block = random.randbytes(blocksize) try: - data = block * (size // blocksize + 1) + data = block * ((size-1) // blocksize + 1) compressed = zlib.compress(data) zlibd = zlib._ZlibDecompressor() decompressed = zlibd.decompress(compressed) From 334da81992201f3e3049358a1a9de84761da4538 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Aug 2023 09:22:45 -0700 Subject: [PATCH 0636/1206] [3.12] Datamodel: Add headings to the standard type hierarchy (GH-108146) (#108477) Datamodel: Add headings to the standard type hierarchy (GH-108146) Dedent content according to the new layout. (cherry picked from commit 2b7bff0655a4caf51cd1a9e5bf85b3b96dd031c9) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/reference/datamodel.rst | 2104 ++++++++++++++++++----------------- 1 file changed, 1104 insertions(+), 1000 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 4bc49a5a83d7a4..27b68d38e13030 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -141,1095 +141,1199 @@ Some of the type descriptions below contain a paragraph listing 'special attributes.' These are attributes that provide access to the implementation and are not intended for general use. Their definition may change in the future. + None - .. index:: pair: object; None +---- + +.. index:: pair: object; None + +This type has a single value. There is a single object with this value. This +object is accessed through the built-in name ``None``. It is used to signify the +absence of a value in many situations, e.g., it is returned from functions that +don't explicitly return anything. Its truth value is false. - This type has a single value. There is a single object with this value. This - object is accessed through the built-in name ``None``. It is used to signify the - absence of a value in many situations, e.g., it is returned from functions that - don't explicitly return anything. Its truth value is false. NotImplemented - .. index:: pair: object; NotImplemented +-------------- + +.. index:: pair: object; NotImplemented - This type has a single value. There is a single object with this value. This - object is accessed through the built-in name ``NotImplemented``. Numeric methods - and rich comparison methods should return this value if they do not implement the - operation for the operands provided. (The interpreter will then try the - reflected operation, or some other fallback, depending on the operator.) It - should not be evaluated in a boolean context. +This type has a single value. There is a single object with this value. This +object is accessed through the built-in name ``NotImplemented``. Numeric methods +and rich comparison methods should return this value if they do not implement the +operation for the operands provided. (The interpreter will then try the +reflected operation, or some other fallback, depending on the operator.) It +should not be evaluated in a boolean context. - See - :ref:`implementing-the-arithmetic-operations` - for more details. +See +:ref:`implementing-the-arithmetic-operations` +for more details. - .. versionchanged:: 3.9 - Evaluating ``NotImplemented`` in a boolean context is deprecated. While - it currently evaluates as true, it will emit a :exc:`DeprecationWarning`. - It will raise a :exc:`TypeError` in a future version of Python. +.. versionchanged:: 3.9 + Evaluating ``NotImplemented`` in a boolean context is deprecated. While + it currently evaluates as true, it will emit a :exc:`DeprecationWarning`. + It will raise a :exc:`TypeError` in a future version of Python. Ellipsis - .. index:: - pair: object; Ellipsis - single: ...; ellipsis literal +-------- +.. index:: + pair: object; Ellipsis + single: ...; ellipsis literal + +This type has a single value. There is a single object with this value. This +object is accessed through the literal ``...`` or the built-in name +``Ellipsis``. Its truth value is true. - This type has a single value. There is a single object with this value. This - object is accessed through the literal ``...`` or the built-in name - ``Ellipsis``. Its truth value is true. :class:`numbers.Number` - .. index:: pair: object; numeric +----------------------- + +.. index:: pair: object; numeric + +These are created by numeric literals and returned as results by arithmetic +operators and arithmetic built-in functions. Numeric objects are immutable; +once created their value never changes. Python numbers are of course strongly +related to mathematical numbers, but subject to the limitations of numerical +representation in computers. + +The string representations of the numeric classes, computed by +:meth:`~object.__repr__` and :meth:`~object.__str__`, have the following +properties: + +* They are valid numeric literals which, when passed to their + class constructor, produce an object having the value of the + original numeric. + +* The representation is in base 10, when possible. + +* Leading zeros, possibly excepting a single zero before a + decimal point, are not shown. - These are created by numeric literals and returned as results by arithmetic - operators and arithmetic built-in functions. Numeric objects are immutable; - once created their value never changes. Python numbers are of course strongly - related to mathematical numbers, but subject to the limitations of numerical - representation in computers. +* Trailing zeros, possibly excepting a single zero after a + decimal point, are not shown. - The string representations of the numeric classes, computed by - :meth:`~object.__repr__` and :meth:`~object.__str__`, have the following - properties: +* A sign is shown only when the number is negative. - * They are valid numeric literals which, when passed to their - class constructor, produce an object having the value of the - original numeric. +Python distinguishes between integers, floating point numbers, and complex +numbers: - * The representation is in base 10, when possible. - * Leading zeros, possibly excepting a single zero before a - decimal point, are not shown. +:class:`numbers.Integral` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. index:: pair: object; integer - * Trailing zeros, possibly excepting a single zero after a - decimal point, are not shown. +These represent elements from the mathematical set of integers (positive and +negative). - * A sign is shown only when the number is negative. +.. note:: + .. index:: pair: integer; representation - Python distinguishes between integers, floating point numbers, and complex - numbers: + The rules for integer representation are intended to give the most meaningful + interpretation of shift and mask operations involving negative integers. - :class:`numbers.Integral` - .. index:: pair: object; integer +There are two types of integers: - These represent elements from the mathematical set of integers (positive and - negative). +Integers (:class:`int`) + These represent numbers in an unlimited range, subject to available (virtual) + memory only. For the purpose of shift and mask operations, a binary + representation is assumed, and negative numbers are represented in a variant of + 2's complement which gives the illusion of an infinite string of sign bits + extending to the left. - There are two types of integers: +Booleans (:class:`bool`) + .. index:: + pair: object; Boolean + single: False + single: True - Integers (:class:`int`) - These represent numbers in an unlimited range, subject to available (virtual) - memory only. For the purpose of shift and mask operations, a binary - representation is assumed, and negative numbers are represented in a variant of - 2's complement which gives the illusion of an infinite string of sign bits - extending to the left. + These represent the truth values False and True. The two objects representing + the values ``False`` and ``True`` are the only Boolean objects. The Boolean type is a + subtype of the integer type, and Boolean values behave like the values 0 and 1, + respectively, in almost all contexts, the exception being that when converted to + a string, the strings ``"False"`` or ``"True"`` are returned, respectively. - Booleans (:class:`bool`) - .. index:: - pair: object; Boolean - single: False - single: True - These represent the truth values False and True. The two objects representing - the values ``False`` and ``True`` are the only Boolean objects. The Boolean type is a - subtype of the integer type, and Boolean values behave like the values 0 and 1, - respectively, in almost all contexts, the exception being that when converted to - a string, the strings ``"False"`` or ``"True"`` are returned, respectively. +:class:`numbers.Real` (:class:`float`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. index:: + pair: object; floating point + pair: floating point; number + pair: C; language + pair: Java; language - .. index:: pair: integer; representation +These represent machine-level double precision floating point numbers. You are +at the mercy of the underlying machine architecture (and C or Java +implementation) for the accepted range and handling of overflow. Python does not +support single-precision floating point numbers; the savings in processor and +memory usage that are usually the reason for using these are dwarfed by the +overhead of using objects in Python, so there is no reason to complicate the +language with two kinds of floating point numbers. - The rules for integer representation are intended to give the most meaningful - interpretation of shift and mask operations involving negative integers. - :class:`numbers.Real` (:class:`float`) - .. index:: - pair: object; floating point - pair: floating point; number - pair: C; language - pair: Java; language +:class:`numbers.Complex` (:class:`complex`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - These represent machine-level double precision floating point numbers. You are - at the mercy of the underlying machine architecture (and C or Java - implementation) for the accepted range and handling of overflow. Python does not - support single-precision floating point numbers; the savings in processor and - memory usage that are usually the reason for using these are dwarfed by the - overhead of using objects in Python, so there is no reason to complicate the - language with two kinds of floating point numbers. +.. index:: + pair: object; complex + pair: complex; number - :class:`numbers.Complex` (:class:`complex`) - .. index:: - pair: object; complex - pair: complex; number +These represent complex numbers as a pair of machine-level double precision +floating point numbers. The same caveats apply as for floating point numbers. +The real and imaginary parts of a complex number ``z`` can be retrieved through +the read-only attributes ``z.real`` and ``z.imag``. - These represent complex numbers as a pair of machine-level double precision - floating point numbers. The same caveats apply as for floating point numbers. - The real and imaginary parts of a complex number ``z`` can be retrieved through - the read-only attributes ``z.real`` and ``z.imag``. Sequences +--------- + +.. index:: + pair: built-in function; len + pair: object; sequence + single: index operation + single: item selection + single: subscription + +These represent finite ordered sets indexed by non-negative numbers. The +built-in function :func:`len` returns the number of items of a sequence. When +the length of a sequence is *n*, the index set contains the numbers 0, 1, +..., *n*-1. Item *i* of sequence *a* is selected by ``a[i]``. + +.. index:: single: slicing + +Sequences also support slicing: ``a[i:j]`` selects all items with index *k* such +that *i* ``<=`` *k* ``<`` *j*. When used as an expression, a slice is a +sequence of the same type. This implies that the index set is renumbered so +that it starts at 0. + +Some sequences also support "extended slicing" with a third "step" parameter: +``a[i:j:k]`` selects all items of *a* with index *x* where ``x = i + n*k``, *n* +``>=`` ``0`` and *i* ``<=`` *x* ``<`` *j*. + +Sequences are distinguished according to their mutability: + + +Immutable sequences +^^^^^^^^^^^^^^^^^^^ + +.. index:: + pair: object; immutable sequence + pair: object; immutable + +An object of an immutable sequence type cannot change once it is created. (If +the object contains references to other objects, these other objects may be +mutable and may be changed; however, the collection of objects directly +referenced by an immutable object cannot change.) + +The following types are immutable sequences: + +.. index:: + single: string; immutable sequences + +Strings .. index:: - pair: built-in function; len - pair: object; sequence - single: index operation - single: item selection - single: subscription - - These represent finite ordered sets indexed by non-negative numbers. The - built-in function :func:`len` returns the number of items of a sequence. When - the length of a sequence is *n*, the index set contains the numbers 0, 1, - ..., *n*-1. Item *i* of sequence *a* is selected by ``a[i]``. - - .. index:: single: slicing - - Sequences also support slicing: ``a[i:j]`` selects all items with index *k* such - that *i* ``<=`` *k* ``<`` *j*. When used as an expression, a slice is a - sequence of the same type. This implies that the index set is renumbered so - that it starts at 0. - - Some sequences also support "extended slicing" with a third "step" parameter: - ``a[i:j:k]`` selects all items of *a* with index *x* where ``x = i + n*k``, *n* - ``>=`` ``0`` and *i* ``<=`` *x* ``<`` *j*. - - Sequences are distinguished according to their mutability: - - Immutable sequences - .. index:: - pair: object; immutable sequence - pair: object; immutable - - An object of an immutable sequence type cannot change once it is created. (If - the object contains references to other objects, these other objects may be - mutable and may be changed; however, the collection of objects directly - referenced by an immutable object cannot change.) - - The following types are immutable sequences: - - .. index:: - single: string; immutable sequences - - Strings - .. index:: - pair: built-in function; chr - pair: built-in function; ord - single: character - single: integer - single: Unicode - - A string is a sequence of values that represent Unicode code points. - All the code points in the range ``U+0000 - U+10FFFF`` can be - represented in a string. Python doesn't have a :c:expr:`char` type; - instead, every code point in the string is represented as a string - object with length ``1``. The built-in function :func:`ord` - converts a code point from its string form to an integer in the - range ``0 - 10FFFF``; :func:`chr` converts an integer in the range - ``0 - 10FFFF`` to the corresponding length ``1`` string object. - :meth:`str.encode` can be used to convert a :class:`str` to - :class:`bytes` using the given text encoding, and - :meth:`bytes.decode` can be used to achieve the opposite. - - Tuples - .. index:: - pair: object; tuple - pair: singleton; tuple - pair: empty; tuple - - The items of a tuple are arbitrary Python objects. Tuples of two or - more items are formed by comma-separated lists of expressions. A tuple - of one item (a 'singleton') can be formed by affixing a comma to an - expression (an expression by itself does not create a tuple, since - parentheses must be usable for grouping of expressions). An empty - tuple can be formed by an empty pair of parentheses. - - Bytes - .. index:: bytes, byte - - A bytes object is an immutable array. The items are 8-bit bytes, - represented by integers in the range 0 <= x < 256. Bytes literals - (like ``b'abc'``) and the built-in :func:`bytes()` constructor - can be used to create bytes objects. Also, bytes objects can be - decoded to strings via the :meth:`~bytes.decode` method. - - Mutable sequences - .. index:: - pair: object; mutable sequence - pair: object; mutable - pair: assignment; statement - single: subscription - single: slicing - - Mutable sequences can be changed after they are created. The subscription and - slicing notations can be used as the target of assignment and :keyword:`del` - (delete) statements. - - There are currently two intrinsic mutable sequence types: - - Lists - .. index:: pair: object; list - - The items of a list are arbitrary Python objects. Lists are formed by - placing a comma-separated list of expressions in square brackets. (Note - that there are no special cases needed to form lists of length 0 or 1.) - - Byte Arrays - .. index:: bytearray - - A bytearray object is a mutable array. They are created by the built-in - :func:`bytearray` constructor. Aside from being mutable - (and hence unhashable), byte arrays otherwise provide the same interface - and functionality as immutable :class:`bytes` objects. - - .. index:: pair: module; array - - The extension module :mod:`array` provides an additional example of a - mutable sequence type, as does the :mod:`collections` module. + pair: built-in function; chr + pair: built-in function; ord + single: character + single: integer + single: Unicode + + A string is a sequence of values that represent Unicode code points. + All the code points in the range ``U+0000 - U+10FFFF`` can be + represented in a string. Python doesn't have a :c:expr:`char` type; + instead, every code point in the string is represented as a string + object with length ``1``. The built-in function :func:`ord` + converts a code point from its string form to an integer in the + range ``0 - 10FFFF``; :func:`chr` converts an integer in the range + ``0 - 10FFFF`` to the corresponding length ``1`` string object. + :meth:`str.encode` can be used to convert a :class:`str` to + :class:`bytes` using the given text encoding, and + :meth:`bytes.decode` can be used to achieve the opposite. + +Tuples + .. index:: + pair: object; tuple + pair: singleton; tuple + pair: empty; tuple + + The items of a tuple are arbitrary Python objects. Tuples of two or + more items are formed by comma-separated lists of expressions. A tuple + of one item (a 'singleton') can be formed by affixing a comma to an + expression (an expression by itself does not create a tuple, since + parentheses must be usable for grouping of expressions). An empty + tuple can be formed by an empty pair of parentheses. + +Bytes + .. index:: bytes, byte + + A bytes object is an immutable array. The items are 8-bit bytes, + represented by integers in the range 0 <= x < 256. Bytes literals + (like ``b'abc'``) and the built-in :func:`bytes()` constructor + can be used to create bytes objects. Also, bytes objects can be + decoded to strings via the :meth:`~bytes.decode` method. + + +Mutable sequences +^^^^^^^^^^^^^^^^^ + +.. index:: + pair: object; mutable sequence + pair: object; mutable + pair: assignment; statement + single: subscription + single: slicing + +Mutable sequences can be changed after they are created. The subscription and +slicing notations can be used as the target of assignment and :keyword:`del` +(delete) statements. + +.. note:: + .. index:: pair: module; array + .. index:: pair: module; collections + + The :mod:`collections` and :mod:`array` module provide + additional examples of mutable sequence types. + +There are currently two intrinsic mutable sequence types: + +Lists + .. index:: pair: object; list + + The items of a list are arbitrary Python objects. Lists are formed by + placing a comma-separated list of expressions in square brackets. (Note + that there are no special cases needed to form lists of length 0 or 1.) + +Byte Arrays + .. index:: bytearray + + A bytearray object is a mutable array. They are created by the built-in + :func:`bytearray` constructor. Aside from being mutable + (and hence unhashable), byte arrays otherwise provide the same interface + and functionality as immutable :class:`bytes` objects. + Set types - .. index:: - pair: built-in function; len - pair: object; set type +--------- + +.. index:: + pair: built-in function; len + pair: object; set type + +These represent unordered, finite sets of unique, immutable objects. As such, +they cannot be indexed by any subscript. However, they can be iterated over, and +the built-in function :func:`len` returns the number of items in a set. Common +uses for sets are fast membership testing, removing duplicates from a sequence, +and computing mathematical operations such as intersection, union, difference, +and symmetric difference. - These represent unordered, finite sets of unique, immutable objects. As such, - they cannot be indexed by any subscript. However, they can be iterated over, and - the built-in function :func:`len` returns the number of items in a set. Common - uses for sets are fast membership testing, removing duplicates from a sequence, - and computing mathematical operations such as intersection, union, difference, - and symmetric difference. +For set elements, the same immutability rules apply as for dictionary keys. Note +that numeric types obey the normal rules for numeric comparison: if two numbers +compare equal (e.g., ``1`` and ``1.0``), only one of them can be contained in a +set. - For set elements, the same immutability rules apply as for dictionary keys. Note - that numeric types obey the normal rules for numeric comparison: if two numbers - compare equal (e.g., ``1`` and ``1.0``), only one of them can be contained in a - set. +There are currently two intrinsic set types: - There are currently two intrinsic set types: - Sets - .. index:: pair: object; set +Sets + .. index:: pair: object; set - These represent a mutable set. They are created by the built-in :func:`set` - constructor and can be modified afterwards by several methods, such as - :meth:`~set.add`. + These represent a mutable set. They are created by the built-in :func:`set` + constructor and can be modified afterwards by several methods, such as + :meth:`~set.add`. - Frozen sets - .. index:: pair: object; frozenset - These represent an immutable set. They are created by the built-in - :func:`frozenset` constructor. As a frozenset is immutable and - :term:`hashable`, it can be used again as an element of another set, or as - a dictionary key. +Frozen sets + .. index:: pair: object; frozenset + + These represent an immutable set. They are created by the built-in + :func:`frozenset` constructor. As a frozenset is immutable and + :term:`hashable`, it can be used again as an element of another set, or as + a dictionary key. + Mappings - .. index:: - pair: built-in function; len - single: subscription - pair: object; mapping - - These represent finite sets of objects indexed by arbitrary index sets. The - subscript notation ``a[k]`` selects the item indexed by ``k`` from the mapping - ``a``; this can be used in expressions and as the target of assignments or - :keyword:`del` statements. The built-in function :func:`len` returns the number - of items in a mapping. - - There is currently a single intrinsic mapping type: - - Dictionaries - .. index:: pair: object; dictionary - - These represent finite sets of objects indexed by nearly arbitrary values. The - only types of values not acceptable as keys are values containing lists or - dictionaries or other mutable types that are compared by value rather than by - object identity, the reason being that the efficient implementation of - dictionaries requires a key's hash value to remain constant. Numeric types used - for keys obey the normal rules for numeric comparison: if two numbers compare - equal (e.g., ``1`` and ``1.0``) then they can be used interchangeably to index - the same dictionary entry. - - Dictionaries preserve insertion order, meaning that keys will be produced - in the same order they were added sequentially over the dictionary. - Replacing an existing key does not change the order, however removing a key - and re-inserting it will add it to the end instead of keeping its old place. - - Dictionaries are mutable; they can be created by the ``{...}`` notation (see - section :ref:`dict`). - - .. index:: - pair: module; dbm.ndbm - pair: module; dbm.gnu - - The extension modules :mod:`dbm.ndbm` and :mod:`dbm.gnu` provide - additional examples of mapping types, as does the :mod:`collections` - module. - - .. versionchanged:: 3.7 - Dictionaries did not preserve insertion order in versions of Python before 3.6. - In CPython 3.6, insertion order was preserved, but it was considered - an implementation detail at that time rather than a language guarantee. +-------- + +.. index:: + pair: built-in function; len + single: subscription + pair: object; mapping + +These represent finite sets of objects indexed by arbitrary index sets. The +subscript notation ``a[k]`` selects the item indexed by ``k`` from the mapping +``a``; this can be used in expressions and as the target of assignments or +:keyword:`del` statements. The built-in function :func:`len` returns the number +of items in a mapping. + +There is currently a single intrinsic mapping type: + + +Dictionaries +^^^^^^^^^^^^ + +.. index:: pair: object; dictionary + +These represent finite sets of objects indexed by nearly arbitrary values. The +only types of values not acceptable as keys are values containing lists or +dictionaries or other mutable types that are compared by value rather than by +object identity, the reason being that the efficient implementation of +dictionaries requires a key's hash value to remain constant. Numeric types used +for keys obey the normal rules for numeric comparison: if two numbers compare +equal (e.g., ``1`` and ``1.0``) then they can be used interchangeably to index +the same dictionary entry. + +Dictionaries preserve insertion order, meaning that keys will be produced +in the same order they were added sequentially over the dictionary. +Replacing an existing key does not change the order, however removing a key +and re-inserting it will add it to the end instead of keeping its old place. + +Dictionaries are mutable; they can be created by the ``{...}`` notation (see +section :ref:`dict`). + +.. index:: + pair: module; dbm.ndbm + pair: module; dbm.gnu + +The extension modules :mod:`dbm.ndbm` and :mod:`dbm.gnu` provide +additional examples of mapping types, as does the :mod:`collections` +module. + +.. versionchanged:: 3.7 + Dictionaries did not preserve insertion order in versions of Python before 3.6. + In CPython 3.6, insertion order was preserved, but it was considered + an implementation detail at that time rather than a language guarantee. + Callable types - .. index:: - pair: object; callable - pair: function; call - single: invocation - pair: function; argument - - These are the types to which the function call operation (see section - :ref:`calls`) can be applied: - - User-defined functions - .. index:: - pair: user-defined; function - pair: object; function - pair: object; user-defined function - - A user-defined function object is created by a function definition (see - section :ref:`function`). It should be called with an argument list - containing the same number of items as the function's formal parameter - list. - - Special attributes: - - .. tabularcolumns:: |l|L|l| - - .. index:: - single: __doc__ (function attribute) - single: __name__ (function attribute) - single: __module__ (function attribute) - single: __dict__ (function attribute) - single: __defaults__ (function attribute) - single: __closure__ (function attribute) - single: __code__ (function attribute) - single: __globals__ (function attribute) - single: __annotations__ (function attribute) - single: __kwdefaults__ (function attribute) - single: __type_params__ (function attribute) - pair: global; namespace - - +-------------------------+-------------------------------+-----------+ - | Attribute | Meaning | | - +=========================+===============================+===========+ - | :attr:`__doc__` | The function's documentation | Writable | - | | string, or ``None`` if | | - | | unavailable; not inherited by | | - | | subclasses. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`~definition.\ | The function's name. | Writable | - | __name__` | | | - +-------------------------+-------------------------------+-----------+ - | :attr:`~definition.\ | The function's | Writable | - | __qualname__` | :term:`qualified name`. | | - | | | | - | | .. versionadded:: 3.3 | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__module__` | The name of the module the | Writable | - | | function was defined in, or | | - | | ``None`` if unavailable. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__defaults__` | A tuple containing default | Writable | - | | argument values for those | | - | | arguments that have defaults, | | - | | or ``None`` if no arguments | | - | | have a default value. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__code__` | The code object representing | Writable | - | | the compiled function body. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__globals__` | A reference to the dictionary | Read-only | - | | that holds the function's | | - | | global variables --- the | | - | | global namespace of the | | - | | module in which the function | | - | | was defined. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`~object.__dict__`| The namespace supporting | Writable | - | | arbitrary function | | - | | attributes. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__closure__` | ``None`` or a tuple of cells | Read-only | - | | that contain bindings for the | | - | | function's free variables. | | - | | See below for information on | | - | | the ``cell_contents`` | | - | | attribute. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__annotations__` | A dict containing annotations | Writable | - | | of parameters. The keys of | | - | | the dict are the parameter | | - | | names, and ``'return'`` for | | - | | the return annotation, if | | - | | provided. For more | | - | | information on working with | | - | | this attribute, see | | - | | :ref:`annotations-howto`. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__kwdefaults__` | A dict containing defaults | Writable | - | | for keyword-only parameters. | | - +-------------------------+-------------------------------+-----------+ - | :attr:`__type_params__` | A tuple containing the | Writable | - | | :ref:`type parameters | | - | | ` of a | | - | | :ref:`generic function | | - | | `. | | - +-------------------------+-------------------------------+-----------+ - - Most of the attributes labelled "Writable" check the type of the assigned value. - - Function objects also support getting and setting arbitrary attributes, which - can be used, for example, to attach metadata to functions. Regular attribute - dot-notation is used to get and set such attributes. *Note that the current - implementation only supports function attributes on user-defined functions. - Function attributes on built-in functions may be supported in the future.* - - A cell object has the attribute ``cell_contents``. This can be used to get - the value of the cell, as well as set the value. - - Additional information about a function's definition can be retrieved from its - code object; see the description of internal types below. The - :data:`cell ` type can be accessed in the :mod:`types` - module. - - Instance methods - .. index:: - pair: object; method - pair: object; user-defined method - pair: user-defined; method - - An instance method object combines a class, a class instance and any - callable object (normally a user-defined function). - - .. index:: - single: __func__ (method attribute) - single: __self__ (method attribute) - single: __doc__ (method attribute) - single: __name__ (method attribute) - single: __module__ (method attribute) - - Special read-only attributes: :attr:`__self__` is the class instance object, - :attr:`__func__` is the function object; :attr:`__doc__` is the method's - documentation (same as ``__func__.__doc__``); :attr:`~definition.__name__` is the - method name (same as ``__func__.__name__``); :attr:`__module__` is the - name of the module the method was defined in, or ``None`` if unavailable. - - Methods also support accessing (but not setting) the arbitrary function - attributes on the underlying function object. - - User-defined method objects may be created when getting an attribute of a - class (perhaps via an instance of that class), if that attribute is a - user-defined function object or a class method object. - - When an instance method object is created by retrieving a user-defined - function object from a class via one of its instances, its - :attr:`__self__` attribute is the instance, and the method object is said - to be bound. The new method's :attr:`__func__` attribute is the original - function object. - - When an instance method object is created by retrieving a class method - object from a class or instance, its :attr:`__self__` attribute is the - class itself, and its :attr:`__func__` attribute is the function object - underlying the class method. - - When an instance method object is called, the underlying function - (:attr:`__func__`) is called, inserting the class instance - (:attr:`__self__`) in front of the argument list. For instance, when - :class:`C` is a class which contains a definition for a function - :meth:`f`, and ``x`` is an instance of :class:`C`, calling ``x.f(1)`` is - equivalent to calling ``C.f(x, 1)``. - - When an instance method object is derived from a class method object, the - "class instance" stored in :attr:`__self__` will actually be the class - itself, so that calling either ``x.f(1)`` or ``C.f(1)`` is equivalent to - calling ``f(C,1)`` where ``f`` is the underlying function. - - Note that the transformation from function object to instance method - object happens each time the attribute is retrieved from the instance. In - some cases, a fruitful optimization is to assign the attribute to a local - variable and call that local variable. Also notice that this - transformation only happens for user-defined functions; other callable - objects (and all non-callable objects) are retrieved without - transformation. It is also important to note that user-defined functions - which are attributes of a class instance are not converted to bound - methods; this *only* happens when the function is an attribute of the - class. - - Generator functions - .. index:: - single: generator; function - single: generator; iterator - - A function or method which uses the :keyword:`yield` statement (see section - :ref:`yield`) is called a :dfn:`generator function`. Such a function, when - called, always returns an :term:`iterator` object which can be used to - execute the body of the function: calling the iterator's - :meth:`iterator.__next__` method will cause the function to execute until - it provides a value using the :keyword:`!yield` statement. When the - function executes a :keyword:`return` statement or falls off the end, a - :exc:`StopIteration` exception is raised and the iterator will have - reached the end of the set of values to be returned. - - Coroutine functions - .. index:: - single: coroutine; function - - A function or method which is defined using :keyword:`async def` is called - a :dfn:`coroutine function`. Such a function, when called, returns a - :term:`coroutine` object. It may contain :keyword:`await` expressions, - as well as :keyword:`async with` and :keyword:`async for` statements. See - also the :ref:`coroutine-objects` section. - - Asynchronous generator functions - .. index:: - single: asynchronous generator; function - single: asynchronous generator; asynchronous iterator - - A function or method which is defined using :keyword:`async def` and - which uses the :keyword:`yield` statement is called a - :dfn:`asynchronous generator function`. Such a function, when called, - returns an :term:`asynchronous iterator` object which can be used in an - :keyword:`async for` statement to execute the body of the function. - - Calling the asynchronous iterator's - :meth:`aiterator.__anext__ ` method - will return an :term:`awaitable` which when awaited - will execute until it provides a value using the :keyword:`yield` - expression. When the function executes an empty :keyword:`return` - statement or falls off the end, a :exc:`StopAsyncIteration` exception - is raised and the asynchronous iterator will have reached the end of - the set of values to be yielded. - - Built-in functions - .. index:: - pair: object; built-in function - pair: object; function - pair: C; language - - A built-in function object is a wrapper around a C function. Examples of - built-in functions are :func:`len` and :func:`math.sin` (:mod:`math` is a - standard built-in module). The number and type of the arguments are - determined by the C function. Special read-only attributes: - :attr:`__doc__` is the function's documentation string, or ``None`` if - unavailable; :attr:`~definition.__name__` is the function's name; :attr:`__self__` is - set to ``None`` (but see the next item); :attr:`__module__` is the name of - the module the function was defined in or ``None`` if unavailable. - - Built-in methods - .. index:: - pair: object; built-in method - pair: object; method - pair: built-in; method - - This is really a different disguise of a built-in function, this time containing - an object passed to the C function as an implicit extra argument. An example of - a built-in method is ``alist.append()``, assuming *alist* is a list object. In - this case, the special read-only attribute :attr:`__self__` is set to the object - denoted by *alist*. - - Classes - Classes are callable. These objects normally act as factories for new - instances of themselves, but variations are possible for class types that - override :meth:`~object.__new__`. The arguments of the call are passed to - :meth:`__new__` and, in the typical case, to :meth:`~object.__init__` to - initialize the new instance. - - Class Instances - Instances of arbitrary classes can be made callable by defining a - :meth:`~object.__call__` method in their class. +-------------- + +.. index:: + pair: object; callable + pair: function; call + single: invocation + pair: function; argument + +These are the types to which the function call operation (see section +:ref:`calls`) can be applied: + + +User-defined functions +^^^^^^^^^^^^^^^^^^^^^^ + +.. index:: + pair: user-defined; function + pair: object; function + pair: object; user-defined function + +A user-defined function object is created by a function definition (see +section :ref:`function`). It should be called with an argument list +containing the same number of items as the function's formal parameter +list. + +Special attributes: + +.. tabularcolumns:: |l|L|l| + +.. index:: + single: __doc__ (function attribute) + single: __name__ (function attribute) + single: __module__ (function attribute) + single: __dict__ (function attribute) + single: __defaults__ (function attribute) + single: __closure__ (function attribute) + single: __code__ (function attribute) + single: __globals__ (function attribute) + single: __annotations__ (function attribute) + single: __kwdefaults__ (function attribute) + single: __type_params__ (function attribute) + pair: global; namespace + ++-------------------------+-------------------------------+-----------+ +| Attribute | Meaning | | ++=========================+===============================+===========+ +| :attr:`__doc__` | The function's documentation | Writable | +| | string, or ``None`` if | | +| | unavailable; not inherited by | | +| | subclasses. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`~definition.\ | The function's name. | Writable | +| __name__` | | | ++-------------------------+-------------------------------+-----------+ +| :attr:`~definition.\ | The function's | Writable | +| __qualname__` | :term:`qualified name`. | | +| | | | +| | .. versionadded:: 3.3 | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__module__` | The name of the module the | Writable | +| | function was defined in, or | | +| | ``None`` if unavailable. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__defaults__` | A tuple containing default | Writable | +| | argument values for those | | +| | arguments that have defaults, | | +| | or ``None`` if no arguments | | +| | have a default value. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__code__` | The code object representing | Writable | +| | the compiled function body. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__globals__` | A reference to the dictionary | Read-only | +| | that holds the function's | | +| | global variables --- the | | +| | global namespace of the | | +| | module in which the function | | +| | was defined. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`~object.__dict__`| The namespace supporting | Writable | +| | arbitrary function | | +| | attributes. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__closure__` | ``None`` or a tuple of cells | Read-only | +| | that contain bindings for the | | +| | function's free variables. | | +| | See below for information on | | +| | the ``cell_contents`` | | +| | attribute. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__annotations__` | A dict containing annotations | Writable | +| | of parameters. The keys of | | +| | the dict are the parameter | | +| | names, and ``'return'`` for | | +| | the return annotation, if | | +| | provided. For more | | +| | information on working with | | +| | this attribute, see | | +| | :ref:`annotations-howto`. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__kwdefaults__` | A dict containing defaults | Writable | +| | for keyword-only parameters. | | ++-------------------------+-------------------------------+-----------+ +| :attr:`__type_params__` | A tuple containing the | Writable | +| | :ref:`type parameters | | +| | ` of a | | +| | :ref:`generic function | | +| | `. | | ++-------------------------+-------------------------------+-----------+ + +Most of the attributes labelled "Writable" check the type of the assigned value. + +Function objects also support getting and setting arbitrary attributes, which +can be used, for example, to attach metadata to functions. Regular attribute +dot-notation is used to get and set such attributes. *Note that the current +implementation only supports function attributes on user-defined functions. +Function attributes on built-in functions may be supported in the future.* + +A cell object has the attribute ``cell_contents``. This can be used to get +the value of the cell, as well as set the value. + +Additional information about a function's definition can be retrieved from its +code object; see the description of internal types below. The +:data:`cell ` type can be accessed in the :mod:`types` +module. + + +Instance methods +^^^^^^^^^^^^^^^^ + +.. index:: + pair: object; method + pair: object; user-defined method + pair: user-defined; method + +An instance method object combines a class, a class instance and any +callable object (normally a user-defined function). + +.. index:: + single: __func__ (method attribute) + single: __self__ (method attribute) + single: __doc__ (method attribute) + single: __name__ (method attribute) + single: __module__ (method attribute) + +Special read-only attributes: :attr:`__self__` is the class instance object, +:attr:`__func__` is the function object; :attr:`__doc__` is the method's +documentation (same as ``__func__.__doc__``); :attr:`~definition.__name__` is the +method name (same as ``__func__.__name__``); :attr:`__module__` is the +name of the module the method was defined in, or ``None`` if unavailable. + +Methods also support accessing (but not setting) the arbitrary function +attributes on the underlying function object. + +User-defined method objects may be created when getting an attribute of a +class (perhaps via an instance of that class), if that attribute is a +user-defined function object or a class method object. + +When an instance method object is created by retrieving a user-defined +function object from a class via one of its instances, its +:attr:`__self__` attribute is the instance, and the method object is said +to be bound. The new method's :attr:`__func__` attribute is the original +function object. + +When an instance method object is created by retrieving a class method +object from a class or instance, its :attr:`__self__` attribute is the +class itself, and its :attr:`__func__` attribute is the function object +underlying the class method. + +When an instance method object is called, the underlying function +(:attr:`__func__`) is called, inserting the class instance +(:attr:`__self__`) in front of the argument list. For instance, when +:class:`C` is a class which contains a definition for a function +:meth:`f`, and ``x`` is an instance of :class:`C`, calling ``x.f(1)`` is +equivalent to calling ``C.f(x, 1)``. + +When an instance method object is derived from a class method object, the +"class instance" stored in :attr:`__self__` will actually be the class +itself, so that calling either ``x.f(1)`` or ``C.f(1)`` is equivalent to +calling ``f(C,1)`` where ``f`` is the underlying function. + +Note that the transformation from function object to instance method +object happens each time the attribute is retrieved from the instance. In +some cases, a fruitful optimization is to assign the attribute to a local +variable and call that local variable. Also notice that this +transformation only happens for user-defined functions; other callable +objects (and all non-callable objects) are retrieved without +transformation. It is also important to note that user-defined functions +which are attributes of a class instance are not converted to bound +methods; this *only* happens when the function is an attribute of the +class. + + +Generator functions +^^^^^^^^^^^^^^^^^^^ + +.. index:: + single: generator; function + single: generator; iterator + +A function or method which uses the :keyword:`yield` statement (see section +:ref:`yield`) is called a :dfn:`generator function`. Such a function, when +called, always returns an :term:`iterator` object which can be used to +execute the body of the function: calling the iterator's +:meth:`iterator.__next__` method will cause the function to execute until +it provides a value using the :keyword:`!yield` statement. When the +function executes a :keyword:`return` statement or falls off the end, a +:exc:`StopIteration` exception is raised and the iterator will have +reached the end of the set of values to be returned. + + +Coroutine functions +^^^^^^^^^^^^^^^^^^^ + +.. index:: + single: coroutine; function + +A function or method which is defined using :keyword:`async def` is called +a :dfn:`coroutine function`. Such a function, when called, returns a +:term:`coroutine` object. It may contain :keyword:`await` expressions, +as well as :keyword:`async with` and :keyword:`async for` statements. See +also the :ref:`coroutine-objects` section. + + +Asynchronous generator functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. index:: + single: asynchronous generator; function + single: asynchronous generator; asynchronous iterator + +A function or method which is defined using :keyword:`async def` and +which uses the :keyword:`yield` statement is called a +:dfn:`asynchronous generator function`. Such a function, when called, +returns an :term:`asynchronous iterator` object which can be used in an +:keyword:`async for` statement to execute the body of the function. + +Calling the asynchronous iterator's +:meth:`aiterator.__anext__ ` method +will return an :term:`awaitable` which when awaited +will execute until it provides a value using the :keyword:`yield` +expression. When the function executes an empty :keyword:`return` +statement or falls off the end, a :exc:`StopAsyncIteration` exception +is raised and the asynchronous iterator will have reached the end of +the set of values to be yielded. + + +Built-in functions +^^^^^^^^^^^^^^^^^^ + +.. index:: + pair: object; built-in function + pair: object; function + pair: C; language + +A built-in function object is a wrapper around a C function. Examples of +built-in functions are :func:`len` and :func:`math.sin` (:mod:`math` is a +standard built-in module). The number and type of the arguments are +determined by the C function. Special read-only attributes: +:attr:`__doc__` is the function's documentation string, or ``None`` if +unavailable; :attr:`~definition.__name__` is the function's name; :attr:`__self__` is +set to ``None`` (but see the next item); :attr:`__module__` is the name of +the module the function was defined in or ``None`` if unavailable. + + +Built-in methods +^^^^^^^^^^^^^^^^ + +.. index:: + pair: object; built-in method + pair: object; method + pair: built-in; method + +This is really a different disguise of a built-in function, this time containing +an object passed to the C function as an implicit extra argument. An example of +a built-in method is ``alist.append()``, assuming *alist* is a list object. In +this case, the special read-only attribute :attr:`__self__` is set to the object +denoted by *alist*. + + +Classes +^^^^^^^ + +Classes are callable. These objects normally act as factories for new +instances of themselves, but variations are possible for class types that +override :meth:`~object.__new__`. The arguments of the call are passed to +:meth:`__new__` and, in the typical case, to :meth:`~object.__init__` to +initialize the new instance. + + +Class Instances +^^^^^^^^^^^^^^^ + +Instances of arbitrary classes can be made callable by defining a +:meth:`~object.__call__` method in their class. Modules - .. index:: - pair: statement; import - pair: object; module - - Modules are a basic organizational unit of Python code, and are created by - the :ref:`import system ` as invoked either by the - :keyword:`import` statement, or by calling - functions such as :func:`importlib.import_module` and built-in - :func:`__import__`. A module object has a namespace implemented by a - dictionary object (this is the dictionary referenced by the ``__globals__`` - attribute of functions defined in the module). Attribute references are - translated to lookups in this dictionary, e.g., ``m.x`` is equivalent to - ``m.__dict__["x"]``. A module object does not contain the code object used - to initialize the module (since it isn't needed once the initialization is - done). - - Attribute assignment updates the module's namespace dictionary, e.g., - ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``. +------- - .. index:: - single: __name__ (module attribute) - single: __doc__ (module attribute) - single: __file__ (module attribute) - single: __annotations__ (module attribute) - pair: module; namespace +.. index:: + pair: statement; import + pair: object; module + +Modules are a basic organizational unit of Python code, and are created by +the :ref:`import system ` as invoked either by the +:keyword:`import` statement, or by calling +functions such as :func:`importlib.import_module` and built-in +:func:`__import__`. A module object has a namespace implemented by a +dictionary object (this is the dictionary referenced by the ``__globals__`` +attribute of functions defined in the module). Attribute references are +translated to lookups in this dictionary, e.g., ``m.x`` is equivalent to +``m.__dict__["x"]``. A module object does not contain the code object used +to initialize the module (since it isn't needed once the initialization is +done). + +Attribute assignment updates the module's namespace dictionary, e.g., +``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``. - Predefined (writable) attributes: +.. index:: + single: __name__ (module attribute) + single: __doc__ (module attribute) + single: __file__ (module attribute) + single: __annotations__ (module attribute) + pair: module; namespace - :attr:`__name__` - The module's name. +Predefined (writable) attributes: - :attr:`__doc__` - The module's documentation string, or ``None`` if - unavailable. + :attr:`__name__` + The module's name. - :attr:`__file__` - The pathname of the file from which the - module was loaded, if it was loaded from a file. - The :attr:`__file__` - attribute may be missing for certain types of modules, such as C modules - that are statically linked into the interpreter. For extension modules - loaded dynamically from a shared library, it's the pathname of the shared - library file. + :attr:`__doc__` + The module's documentation string, or ``None`` if + unavailable. - :attr:`__annotations__` - A dictionary containing - :term:`variable annotations ` collected during - module body execution. For best practices on working - with :attr:`__annotations__`, please see :ref:`annotations-howto`. + :attr:`__file__` + The pathname of the file from which the + module was loaded, if it was loaded from a file. + The :attr:`__file__` + attribute may be missing for certain types of modules, such as C modules + that are statically linked into the interpreter. For extension modules + loaded dynamically from a shared library, it's the pathname of the shared + library file. - .. index:: single: __dict__ (module attribute) + :attr:`__annotations__` + A dictionary containing + :term:`variable annotations ` collected during + module body execution. For best practices on working + with :attr:`__annotations__`, please see :ref:`annotations-howto`. - Special read-only attribute: :attr:`~object.__dict__` is the module's - namespace as a dictionary object. +.. index:: single: __dict__ (module attribute) - .. impl-detail:: +Special read-only attribute: :attr:`~object.__dict__` is the module's +namespace as a dictionary object. + +.. impl-detail:: + + Because of the way CPython clears module dictionaries, the module + dictionary will be cleared when the module falls out of scope even if the + dictionary still has live references. To avoid this, copy the dictionary + or keep the module around while using its dictionary directly. - Because of the way CPython clears module dictionaries, the module - dictionary will be cleared when the module falls out of scope even if the - dictionary still has live references. To avoid this, copy the dictionary - or keep the module around while using its dictionary directly. Custom classes - Custom class types are typically created by class definitions (see section - :ref:`class`). A class has a namespace implemented by a dictionary object. - Class attribute references are translated to lookups in this dictionary, e.g., - ``C.x`` is translated to ``C.__dict__["x"]`` (although there are a number of - hooks which allow for other means of locating attributes). When the attribute - name is not found there, the attribute search continues in the base classes. - This search of the base classes uses the C3 method resolution order which - behaves correctly even in the presence of 'diamond' inheritance structures - where there are multiple inheritance paths leading back to a common ancestor. - Additional details on the C3 MRO used by Python can be found in the - documentation accompanying the 2.3 release at - https://www.python.org/download/releases/2.3/mro/. - - .. XXX: Could we add that MRO doc as an appendix to the language ref? +-------------- + +Custom class types are typically created by class definitions (see section +:ref:`class`). A class has a namespace implemented by a dictionary object. +Class attribute references are translated to lookups in this dictionary, e.g., +``C.x`` is translated to ``C.__dict__["x"]`` (although there are a number of +hooks which allow for other means of locating attributes). When the attribute +name is not found there, the attribute search continues in the base classes. +This search of the base classes uses the C3 method resolution order which +behaves correctly even in the presence of 'diamond' inheritance structures +where there are multiple inheritance paths leading back to a common ancestor. +Additional details on the C3 MRO used by Python can be found in the +documentation accompanying the 2.3 release at +https://www.python.org/download/releases/2.3/mro/. + +.. XXX: Could we add that MRO doc as an appendix to the language ref? - .. index:: - pair: object; class - pair: object; class instance - pair: object; instance - pair: class object; call - single: container - pair: object; dictionary - pair: class; attribute +.. index:: + pair: object; class + pair: object; class instance + pair: object; instance + pair: class object; call + single: container + pair: object; dictionary + pair: class; attribute - When a class attribute reference (for class :class:`C`, say) would yield a - class method object, it is transformed into an instance method object whose - :attr:`__self__` attribute is :class:`C`. When it would yield a static - method object, it is transformed into the object wrapped by the static method - object. See section :ref:`descriptors` for another way in which attributes - retrieved from a class may differ from those actually contained in its - :attr:`~object.__dict__`. +When a class attribute reference (for class :class:`C`, say) would yield a +class method object, it is transformed into an instance method object whose +:attr:`__self__` attribute is :class:`C`. When it would yield a static +method object, it is transformed into the object wrapped by the static method +object. See section :ref:`descriptors` for another way in which attributes +retrieved from a class may differ from those actually contained in its +:attr:`~object.__dict__`. - .. index:: triple: class; attribute; assignment +.. index:: triple: class; attribute; assignment - Class attribute assignments update the class's dictionary, never the dictionary - of a base class. +Class attribute assignments update the class's dictionary, never the dictionary +of a base class. - .. index:: pair: class object; call +.. index:: pair: class object; call - A class object can be called (see above) to yield a class instance (see below). +A class object can be called (see above) to yield a class instance (see below). - .. index:: - single: __name__ (class attribute) - single: __module__ (class attribute) - single: __dict__ (class attribute) - single: __bases__ (class attribute) - single: __doc__ (class attribute) - single: __annotations__ (class attribute) - single: __type_params__ (class attribute) +.. index:: + single: __name__ (class attribute) + single: __module__ (class attribute) + single: __dict__ (class attribute) + single: __bases__ (class attribute) + single: __doc__ (class attribute) + single: __annotations__ (class attribute) + single: __type_params__ (class attribute) + +Special attributes: - Special attributes: + :attr:`~definition.__name__` + The class name. - :attr:`~definition.__name__` - The class name. + :attr:`__module__` + The name of the module in which the class was defined. - :attr:`__module__` - The name of the module in which the class was defined. + :attr:`~object.__dict__` + The dictionary containing the class's namespace. - :attr:`~object.__dict__` - The dictionary containing the class's namespace. + :attr:`~class.__bases__` + A tuple containing the base classes, in the order of + their occurrence in the base class list. - :attr:`~class.__bases__` - A tuple containing the base classes, in the order of - their occurrence in the base class list. + :attr:`__doc__` + The class's documentation string, or ``None`` if undefined. - :attr:`__doc__` - The class's documentation string, or ``None`` if undefined. + :attr:`__annotations__` + A dictionary containing + :term:`variable annotations ` + collected during class body execution. For best practices on + working with :attr:`__annotations__`, please see + :ref:`annotations-howto`. - :attr:`__annotations__` - A dictionary containing - :term:`variable annotations ` - collected during class body execution. For best practices on - working with :attr:`__annotations__`, please see - :ref:`annotations-howto`. + :attr:`__type_params__` + A tuple containing the :ref:`type parameters ` of + a :ref:`generic class `. - :attr:`__type_params__` - A tuple containing the :ref:`type parameters ` of - a :ref:`generic class `. Class instances - .. index:: - pair: object; class instance - pair: object; instance - pair: class; instance - pair: class instance; attribute - - A class instance is created by calling a class object (see above). A class - instance has a namespace implemented as a dictionary which is the first place - in which attribute references are searched. When an attribute is not found - there, and the instance's class has an attribute by that name, the search - continues with the class attributes. If a class attribute is found that is a - user-defined function object, it is transformed into an instance method - object whose :attr:`__self__` attribute is the instance. Static method and - class method objects are also transformed; see above under "Classes". See - section :ref:`descriptors` for another way in which attributes of a class - retrieved via its instances may differ from the objects actually stored in - the class's :attr:`~object.__dict__`. If no class attribute is found, and the - object's class has a :meth:`~object.__getattr__` method, that is called to satisfy - the lookup. - - .. index:: triple: class instance; attribute; assignment - - Attribute assignments and deletions update the instance's dictionary, never a - class's dictionary. If the class has a :meth:`~object.__setattr__` or - :meth:`~object.__delattr__` method, this is called instead of updating the instance - dictionary directly. +--------------- - .. index:: - pair: object; numeric - pair: object; sequence - pair: object; mapping +.. index:: + pair: object; class instance + pair: object; instance + pair: class; instance + pair: class instance; attribute + +A class instance is created by calling a class object (see above). A class +instance has a namespace implemented as a dictionary which is the first place +in which attribute references are searched. When an attribute is not found +there, and the instance's class has an attribute by that name, the search +continues with the class attributes. If a class attribute is found that is a +user-defined function object, it is transformed into an instance method +object whose :attr:`__self__` attribute is the instance. Static method and +class method objects are also transformed; see above under "Classes". See +section :ref:`descriptors` for another way in which attributes of a class +retrieved via its instances may differ from the objects actually stored in +the class's :attr:`~object.__dict__`. If no class attribute is found, and the +object's class has a :meth:`~object.__getattr__` method, that is called to satisfy +the lookup. + +.. index:: triple: class instance; attribute; assignment + +Attribute assignments and deletions update the instance's dictionary, never a +class's dictionary. If the class has a :meth:`~object.__setattr__` or +:meth:`~object.__delattr__` method, this is called instead of updating the instance +dictionary directly. - Class instances can pretend to be numbers, sequences, or mappings if they have - methods with certain special names. See section :ref:`specialnames`. +.. index:: + pair: object; numeric + pair: object; sequence + pair: object; mapping - .. index:: - single: __dict__ (instance attribute) - single: __class__ (instance attribute) +Class instances can pretend to be numbers, sequences, or mappings if they have +methods with certain special names. See section :ref:`specialnames`. + +.. index:: + single: __dict__ (instance attribute) + single: __class__ (instance attribute) + +Special attributes: :attr:`~object.__dict__` is the attribute dictionary; +:attr:`~instance.__class__` is the instance's class. - Special attributes: :attr:`~object.__dict__` is the attribute dictionary; - :attr:`~instance.__class__` is the instance's class. I/O objects (also known as file objects) - .. index:: - pair: built-in function; open - pair: module; io - single: popen() (in module os) - single: makefile() (socket method) - single: sys.stdin - single: sys.stdout - single: sys.stderr - single: stdio - single: stdin (in module sys) - single: stdout (in module sys) - single: stderr (in module sys) - - A :term:`file object` represents an open file. Various shortcuts are - available to create file objects: the :func:`open` built-in function, and - also :func:`os.popen`, :func:`os.fdopen`, and the - :meth:`~socket.socket.makefile` method of socket objects (and perhaps by - other functions or methods provided by extension modules). - - The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are - initialized to file objects corresponding to the interpreter's standard - input, output and error streams; they are all open in text mode and - therefore follow the interface defined by the :class:`io.TextIOBase` - abstract class. +---------------------------------------- + +.. index:: + pair: built-in function; open + pair: module; io + single: popen() (in module os) + single: makefile() (socket method) + single: sys.stdin + single: sys.stdout + single: sys.stderr + single: stdio + single: stdin (in module sys) + single: stdout (in module sys) + single: stderr (in module sys) + +A :term:`file object` represents an open file. Various shortcuts are +available to create file objects: the :func:`open` built-in function, and +also :func:`os.popen`, :func:`os.fdopen`, and the +:meth:`~socket.socket.makefile` method of socket objects (and perhaps by +other functions or methods provided by extension modules). + +The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are +initialized to file objects corresponding to the interpreter's standard +input, output and error streams; they are all open in text mode and +therefore follow the interface defined by the :class:`io.TextIOBase` +abstract class. + Internal types - .. index:: - single: internal type - single: types, internal - - A few types used internally by the interpreter are exposed to the user. Their - definitions may change with future versions of the interpreter, but they are - mentioned here for completeness. - - .. index:: bytecode, object; code, code object - - Code objects - Code objects represent *byte-compiled* executable Python code, or :term:`bytecode`. - The difference between a code object and a function object is that the function - object contains an explicit reference to the function's globals (the module in - which it was defined), while a code object contains no context; also the default - argument values are stored in the function object, not in the code object - (because they represent values calculated at run-time). Unlike function - objects, code objects are immutable and contain no references (directly or - indirectly) to mutable objects. - - .. index:: - single: co_argcount (code object attribute) - single: co_posonlyargcount (code object attribute) - single: co_kwonlyargcount (code object attribute) - single: co_code (code object attribute) - single: co_consts (code object attribute) - single: co_filename (code object attribute) - single: co_firstlineno (code object attribute) - single: co_flags (code object attribute) - single: co_lnotab (code object attribute) - single: co_name (code object attribute) - single: co_names (code object attribute) - single: co_nlocals (code object attribute) - single: co_stacksize (code object attribute) - single: co_varnames (code object attribute) - single: co_cellvars (code object attribute) - single: co_freevars (code object attribute) - single: co_qualname (code object attribute) - - Special read-only attributes: :attr:`co_name` gives the function name; - :attr:`co_qualname` gives the fully qualified function name; - :attr:`co_argcount` is the total number of positional arguments - (including positional-only arguments and arguments with default values); - :attr:`co_posonlyargcount` is the number of positional-only arguments - (including arguments with default values); :attr:`co_kwonlyargcount` is - the number of keyword-only arguments (including arguments with default - values); :attr:`co_nlocals` is the number of local variables used by the - function (including arguments); :attr:`co_varnames` is a tuple containing - the names of the local variables (starting with the argument names); - :attr:`co_cellvars` is a tuple containing the names of local variables - that are referenced by nested functions; :attr:`co_freevars` is a tuple - containing the names of free variables; :attr:`co_code` is a string - representing the sequence of bytecode instructions; :attr:`co_consts` is - a tuple containing the literals used by the bytecode; :attr:`co_names` is - a tuple containing the names used by the bytecode; :attr:`co_filename` is - the filename from which the code was compiled; :attr:`co_firstlineno` is - the first line number of the function; :attr:`co_lnotab` is a string - encoding the mapping from bytecode offsets to line numbers (for details - see the source code of the interpreter, is deprecated since 3.12 - and may be removed in 3.14); :attr:`co_stacksize` is the - required stack size; :attr:`co_flags` is an integer encoding a number - of flags for the interpreter. - - .. index:: pair: object; generator - - The following flag bits are defined for :attr:`co_flags`: bit ``0x04`` is set if - the function uses the ``*arguments`` syntax to accept an arbitrary number of - positional arguments; bit ``0x08`` is set if the function uses the - ``**keywords`` syntax to accept arbitrary keyword arguments; bit ``0x20`` is set - if the function is a generator. - - Future feature declarations (``from __future__ import division``) also use bits - in :attr:`co_flags` to indicate whether a code object was compiled with a - particular feature enabled: bit ``0x2000`` is set if the function was compiled - with future division enabled; bits ``0x10`` and ``0x1000`` were used in earlier - versions of Python. - - Other bits in :attr:`co_flags` are reserved for internal use. - - .. index:: single: documentation string - - If a code object represents a function, the first item in :attr:`co_consts` is - the documentation string of the function, or ``None`` if undefined. - - .. method:: codeobject.co_positions() - - Returns an iterable over the source code positions of each bytecode - instruction in the code object. - - The iterator returns tuples containing the ``(start_line, end_line, - start_column, end_column)``. The *i-th* tuple corresponds to the - position of the source code that compiled to the *i-th* instruction. - Column information is 0-indexed utf-8 byte offsets on the given source - line. - - This positional information can be missing. A non-exhaustive lists of - cases where this may happen: - - - Running the interpreter with :option:`-X` ``no_debug_ranges``. - - Loading a pyc file compiled while using :option:`-X` ``no_debug_ranges``. - - Position tuples corresponding to artificial instructions. - - Line and column numbers that can't be represented due to - implementation specific limitations. - - When this occurs, some or all of the tuple elements can be - :const:`None`. - - .. versionadded:: 3.11 - - .. note:: - This feature requires storing column positions in code objects which may - result in a small increase of disk usage of compiled Python files or - interpreter memory usage. To avoid storing the extra information and/or - deactivate printing the extra traceback information, the - :option:`-X` ``no_debug_ranges`` command line flag or the :envvar:`PYTHONNODEBUGRANGES` - environment variable can be used. - - .. _frame-objects: - - Frame objects - .. index:: pair: object; frame - - Frame objects represent execution frames. They may occur in traceback objects - (see below), and are also passed to registered trace functions. - - .. index:: - single: f_back (frame attribute) - single: f_code (frame attribute) - single: f_globals (frame attribute) - single: f_locals (frame attribute) - single: f_lasti (frame attribute) - single: f_builtins (frame attribute) - - Special read-only attributes: :attr:`f_back` is to the previous stack frame - (towards the caller), or ``None`` if this is the bottom stack frame; - :attr:`f_code` is the code object being executed in this frame; :attr:`f_locals` - is the dictionary used to look up local variables; :attr:`f_globals` is used for - global variables; :attr:`f_builtins` is used for built-in (intrinsic) names; - :attr:`f_lasti` gives the precise instruction (this is an index into the - bytecode string of the code object). - - Accessing ``f_code`` raises an :ref:`auditing event ` - ``object.__getattr__`` with arguments ``obj`` and ``"f_code"``. - - .. index:: - single: f_trace (frame attribute) - single: f_trace_lines (frame attribute) - single: f_trace_opcodes (frame attribute) - single: f_lineno (frame attribute) - - Special writable attributes: :attr:`f_trace`, if not ``None``, is a function - called for various events during code execution (this is used by the debugger). - Normally an event is triggered for each new source line - this can be - disabled by setting :attr:`f_trace_lines` to :const:`False`. - - Implementations *may* allow per-opcode events to be requested by setting - :attr:`f_trace_opcodes` to :const:`True`. Note that this may lead to - undefined interpreter behaviour if exceptions raised by the trace - function escape to the function being traced. - - :attr:`f_lineno` is the current line number of the frame --- writing to this - from within a trace function jumps to the given line (only for the bottom-most - frame). A debugger can implement a Jump command (aka Set Next Statement) - by writing to f_lineno. - - Frame objects support one method: - - .. method:: frame.clear() - - This method clears all references to local variables held by the - frame. Also, if the frame belonged to a generator, the generator - is finalized. This helps break reference cycles involving frame - objects (for example when catching an exception and storing its - traceback for later use). - - :exc:`RuntimeError` is raised if the frame is currently executing. - - .. versionadded:: 3.4 - - .. _traceback-objects: - - Traceback objects - .. index:: - pair: object; traceback - pair: stack; trace - pair: exception; handler - pair: execution; stack - single: exc_info (in module sys) - single: last_traceback (in module sys) - single: sys.exc_info - single: sys.exception - single: sys.last_traceback - - Traceback objects represent a stack trace of an exception. A traceback object - is implicitly created when an exception occurs, and may also be explicitly - created by calling :class:`types.TracebackType`. - - For implicitly created tracebacks, when the search for an exception handler - unwinds the execution stack, at each unwound level a traceback object is - inserted in front of the current traceback. When an exception handler is - entered, the stack trace is made available to the program. (See section - :ref:`try`.) It is accessible as the third item of the - tuple returned by ``sys.exc_info()``, and as the ``__traceback__`` attribute - of the caught exception. - - When the program contains no suitable - handler, the stack trace is written (nicely formatted) to the standard error - stream; if the interpreter is interactive, it is also made available to the user - as ``sys.last_traceback``. - - For explicitly created tracebacks, it is up to the creator of the traceback - to determine how the ``tb_next`` attributes should be linked to form a - full stack trace. - - .. index:: - single: tb_frame (traceback attribute) - single: tb_lineno (traceback attribute) - single: tb_lasti (traceback attribute) - pair: statement; try - - Special read-only attributes: - :attr:`tb_frame` points to the execution frame of the current level; - :attr:`tb_lineno` gives the line number where the exception occurred; - :attr:`tb_lasti` indicates the precise instruction. - The line number and last instruction in the traceback may differ from the - line number of its frame object if the exception occurred in a - :keyword:`try` statement with no matching except clause or with a - finally clause. - - Accessing ``tb_frame`` raises an :ref:`auditing event ` - ``object.__getattr__`` with arguments ``obj`` and ``"tb_frame"``. - - .. index:: - single: tb_next (traceback attribute) - - Special writable attribute: :attr:`tb_next` is the next level in the stack - trace (towards the frame where the exception occurred), or ``None`` if - there is no next level. - - .. versionchanged:: 3.7 - Traceback objects can now be explicitly instantiated from Python code, - and the ``tb_next`` attribute of existing instances can be updated. - - Slice objects - .. index:: pair: built-in function; slice - - Slice objects are used to represent slices for - :meth:`~object.__getitem__` - methods. They are also created by the built-in :func:`slice` function. - - .. index:: - single: start (slice object attribute) - single: stop (slice object attribute) - single: step (slice object attribute) - - Special read-only attributes: :attr:`~slice.start` is the lower bound; - :attr:`~slice.stop` is the upper bound; :attr:`~slice.step` is the step - value; each is ``None`` if omitted. These attributes can have any type. - - Slice objects support one method: - - .. method:: slice.indices(self, length) - - This method takes a single integer argument *length* and computes - information about the slice that the slice object would describe if - applied to a sequence of *length* items. It returns a tuple of three - integers; respectively these are the *start* and *stop* indices and the - *step* or stride length of the slice. Missing or out-of-bounds indices - are handled in a manner consistent with regular slices. - - Static method objects - Static method objects provide a way of defeating the transformation of function - objects to method objects described above. A static method object is a wrapper - around any other object, usually a user-defined method object. When a static - method object is retrieved from a class or a class instance, the object actually - returned is the wrapped object, which is not subject to any further - transformation. Static method objects are also callable. Static method - objects are created by the built-in :func:`staticmethod` constructor. - - Class method objects - A class method object, like a static method object, is a wrapper around another - object that alters the way in which that object is retrieved from classes and - class instances. The behaviour of class method objects upon such retrieval is - described above, under "User-defined methods". Class method objects are created - by the built-in :func:`classmethod` constructor. +-------------- + +.. index:: + single: internal type + single: types, internal + +A few types used internally by the interpreter are exposed to the user. Their +definitions may change with future versions of the interpreter, but they are +mentioned here for completeness. + +.. index:: bytecode, object; code, code object + + +Code objects +^^^^^^^^^^^^ + +Code objects represent *byte-compiled* executable Python code, or :term:`bytecode`. +The difference between a code object and a function object is that the function +object contains an explicit reference to the function's globals (the module in +which it was defined), while a code object contains no context; also the default +argument values are stored in the function object, not in the code object +(because they represent values calculated at run-time). Unlike function +objects, code objects are immutable and contain no references (directly or +indirectly) to mutable objects. + +.. index:: + single: co_argcount (code object attribute) + single: co_posonlyargcount (code object attribute) + single: co_kwonlyargcount (code object attribute) + single: co_code (code object attribute) + single: co_consts (code object attribute) + single: co_filename (code object attribute) + single: co_firstlineno (code object attribute) + single: co_flags (code object attribute) + single: co_lnotab (code object attribute) + single: co_name (code object attribute) + single: co_names (code object attribute) + single: co_nlocals (code object attribute) + single: co_stacksize (code object attribute) + single: co_varnames (code object attribute) + single: co_cellvars (code object attribute) + single: co_freevars (code object attribute) + single: co_qualname (code object attribute) + +Special read-only attributes: :attr:`co_name` gives the function name; +:attr:`co_qualname` gives the fully qualified function name; +:attr:`co_argcount` is the total number of positional arguments +(including positional-only arguments and arguments with default values); +:attr:`co_posonlyargcount` is the number of positional-only arguments +(including arguments with default values); :attr:`co_kwonlyargcount` is +the number of keyword-only arguments (including arguments with default +values); :attr:`co_nlocals` is the number of local variables used by the +function (including arguments); :attr:`co_varnames` is a tuple containing +the names of the local variables (starting with the argument names); +:attr:`co_cellvars` is a tuple containing the names of local variables +that are referenced by nested functions; :attr:`co_freevars` is a tuple +containing the names of free variables; :attr:`co_code` is a string +representing the sequence of bytecode instructions; :attr:`co_consts` is +a tuple containing the literals used by the bytecode; :attr:`co_names` is +a tuple containing the names used by the bytecode; :attr:`co_filename` is +the filename from which the code was compiled; :attr:`co_firstlineno` is +the first line number of the function; :attr:`co_lnotab` is a string +encoding the mapping from bytecode offsets to line numbers (for details +see the source code of the interpreter, is deprecated since 3.12 +and may be removed in 3.14); :attr:`co_stacksize` is the +required stack size; :attr:`co_flags` is an integer encoding a number +of flags for the interpreter. + +.. index:: pair: object; generator + +The following flag bits are defined for :attr:`co_flags`: bit ``0x04`` is set if +the function uses the ``*arguments`` syntax to accept an arbitrary number of +positional arguments; bit ``0x08`` is set if the function uses the +``**keywords`` syntax to accept arbitrary keyword arguments; bit ``0x20`` is set +if the function is a generator. + +Future feature declarations (``from __future__ import division``) also use bits +in :attr:`co_flags` to indicate whether a code object was compiled with a +particular feature enabled: bit ``0x2000`` is set if the function was compiled +with future division enabled; bits ``0x10`` and ``0x1000`` were used in earlier +versions of Python. + +Other bits in :attr:`co_flags` are reserved for internal use. + +.. index:: single: documentation string + +If a code object represents a function, the first item in :attr:`co_consts` is +the documentation string of the function, or ``None`` if undefined. + +.. method:: codeobject.co_positions() + + Returns an iterable over the source code positions of each bytecode + instruction in the code object. + + The iterator returns tuples containing the ``(start_line, end_line, + start_column, end_column)``. The *i-th* tuple corresponds to the + position of the source code that compiled to the *i-th* instruction. + Column information is 0-indexed utf-8 byte offsets on the given source + line. + + This positional information can be missing. A non-exhaustive lists of + cases where this may happen: + + - Running the interpreter with :option:`-X` ``no_debug_ranges``. + - Loading a pyc file compiled while using :option:`-X` ``no_debug_ranges``. + - Position tuples corresponding to artificial instructions. + - Line and column numbers that can't be represented due to + implementation specific limitations. + + When this occurs, some or all of the tuple elements can be + :const:`None`. + + .. versionadded:: 3.11 + + .. note:: + This feature requires storing column positions in code objects which may + result in a small increase of disk usage of compiled Python files or + interpreter memory usage. To avoid storing the extra information and/or + deactivate printing the extra traceback information, the + :option:`-X` ``no_debug_ranges`` command line flag or the :envvar:`PYTHONNODEBUGRANGES` + environment variable can be used. + + +.. _frame-objects: + +Frame objects +^^^^^^^^^^^^^ + +.. index:: pair: object; frame + +Frame objects represent execution frames. They may occur in traceback objects +(see below), and are also passed to registered trace functions. + +.. index:: + single: f_back (frame attribute) + single: f_code (frame attribute) + single: f_globals (frame attribute) + single: f_locals (frame attribute) + single: f_lasti (frame attribute) + single: f_builtins (frame attribute) + +Special read-only attributes: :attr:`f_back` is to the previous stack frame +(towards the caller), or ``None`` if this is the bottom stack frame; +:attr:`f_code` is the code object being executed in this frame; :attr:`f_locals` +is the dictionary used to look up local variables; :attr:`f_globals` is used for +global variables; :attr:`f_builtins` is used for built-in (intrinsic) names; +:attr:`f_lasti` gives the precise instruction (this is an index into the +bytecode string of the code object). + +Accessing ``f_code`` raises an :ref:`auditing event ` +``object.__getattr__`` with arguments ``obj`` and ``"f_code"``. + +.. index:: + single: f_trace (frame attribute) + single: f_trace_lines (frame attribute) + single: f_trace_opcodes (frame attribute) + single: f_lineno (frame attribute) + +Special writable attributes: :attr:`f_trace`, if not ``None``, is a function +called for various events during code execution (this is used by the debugger). +Normally an event is triggered for each new source line - this can be +disabled by setting :attr:`f_trace_lines` to :const:`False`. + +Implementations *may* allow per-opcode events to be requested by setting +:attr:`f_trace_opcodes` to :const:`True`. Note that this may lead to +undefined interpreter behaviour if exceptions raised by the trace +function escape to the function being traced. + +:attr:`f_lineno` is the current line number of the frame --- writing to this +from within a trace function jumps to the given line (only for the bottom-most +frame). A debugger can implement a Jump command (aka Set Next Statement) +by writing to f_lineno. + +Frame objects support one method: + +.. method:: frame.clear() + + This method clears all references to local variables held by the + frame. Also, if the frame belonged to a generator, the generator + is finalized. This helps break reference cycles involving frame + objects (for example when catching an exception and storing its + traceback for later use). + + :exc:`RuntimeError` is raised if the frame is currently executing. + + .. versionadded:: 3.4 + + +.. _traceback-objects: + +Traceback objects +^^^^^^^^^^^^^^^^^ + +.. index:: + pair: object; traceback + pair: stack; trace + pair: exception; handler + pair: execution; stack + single: exc_info (in module sys) + single: last_traceback (in module sys) + single: sys.exc_info + single: sys.exception + single: sys.last_traceback + +Traceback objects represent a stack trace of an exception. A traceback object +is implicitly created when an exception occurs, and may also be explicitly +created by calling :class:`types.TracebackType`. + +For implicitly created tracebacks, when the search for an exception handler +unwinds the execution stack, at each unwound level a traceback object is +inserted in front of the current traceback. When an exception handler is +entered, the stack trace is made available to the program. (See section +:ref:`try`.) It is accessible as the third item of the +tuple returned by ``sys.exc_info()``, and as the ``__traceback__`` attribute +of the caught exception. + +When the program contains no suitable +handler, the stack trace is written (nicely formatted) to the standard error +stream; if the interpreter is interactive, it is also made available to the user +as ``sys.last_traceback``. + +For explicitly created tracebacks, it is up to the creator of the traceback +to determine how the ``tb_next`` attributes should be linked to form a +full stack trace. + +.. index:: + single: tb_frame (traceback attribute) + single: tb_lineno (traceback attribute) + single: tb_lasti (traceback attribute) + pair: statement; try + +Special read-only attributes: +:attr:`tb_frame` points to the execution frame of the current level; +:attr:`tb_lineno` gives the line number where the exception occurred; +:attr:`tb_lasti` indicates the precise instruction. +The line number and last instruction in the traceback may differ from the +line number of its frame object if the exception occurred in a +:keyword:`try` statement with no matching except clause or with a +finally clause. + +Accessing ``tb_frame`` raises an :ref:`auditing event ` +``object.__getattr__`` with arguments ``obj`` and ``"tb_frame"``. + +.. index:: + single: tb_next (traceback attribute) + +Special writable attribute: :attr:`tb_next` is the next level in the stack +trace (towards the frame where the exception occurred), or ``None`` if +there is no next level. + +.. versionchanged:: 3.7 + Traceback objects can now be explicitly instantiated from Python code, + and the ``tb_next`` attribute of existing instances can be updated. + + +Slice objects +^^^^^^^^^^^^^ + +.. index:: pair: built-in function; slice + +Slice objects are used to represent slices for +:meth:`~object.__getitem__` +methods. They are also created by the built-in :func:`slice` function. + +.. index:: + single: start (slice object attribute) + single: stop (slice object attribute) + single: step (slice object attribute) + +Special read-only attributes: :attr:`~slice.start` is the lower bound; +:attr:`~slice.stop` is the upper bound; :attr:`~slice.step` is the step +value; each is ``None`` if omitted. These attributes can have any type. + +Slice objects support one method: + +.. method:: slice.indices(self, length) + + This method takes a single integer argument *length* and computes + information about the slice that the slice object would describe if + applied to a sequence of *length* items. It returns a tuple of three + integers; respectively these are the *start* and *stop* indices and the + *step* or stride length of the slice. Missing or out-of-bounds indices + are handled in a manner consistent with regular slices. + + +Static method objects +^^^^^^^^^^^^^^^^^^^^^ + +Static method objects provide a way of defeating the transformation of function +objects to method objects described above. A static method object is a wrapper +around any other object, usually a user-defined method object. When a static +method object is retrieved from a class or a class instance, the object actually +returned is the wrapped object, which is not subject to any further +transformation. Static method objects are also callable. Static method +objects are created by the built-in :func:`staticmethod` constructor. + + +Class method objects +^^^^^^^^^^^^^^^^^^^^ + +A class method object, like a static method object, is a wrapper around another +object that alters the way in which that object is retrieved from classes and +class instances. The behaviour of class method objects upon such retrieval is +described above, under "User-defined methods". Class method objects are created +by the built-in :func:`classmethod` constructor. .. _specialnames: From ce37fbc778cbe330cc69e588ed89c7c8123d622c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 25 Aug 2023 09:23:11 -0700 Subject: [PATCH 0637/1206] [3.12] Docs: Datamodel: Merge "Notes on using __slots__" with the parent section (GH-108400) (#108474) Docs: Datamodel: Merge "Notes on using __slots__" with the parent section (GH-108400) (cherry picked from commit 7f5b1a06612bf1454232ac634ad4d2c845f77b37) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/reference/datamodel.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 27b68d38e13030..4c2d03eacdc277 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2024,8 +2024,7 @@ Attribute lookup speed can be significantly improved as well. .. _datamodel-note-slots: -Notes on using *__slots__* -"""""""""""""""""""""""""" +Notes on using *__slots__*: * When inheriting from a class without *__slots__*, the :attr:`~object.__dict__` and From bba9aa60ae7e80fbc4bd8c74554b54fc1e35a1e6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 27 Aug 2023 01:20:33 +0200 Subject: [PATCH 0638/1206] [3.12] gh-108388: Convert test_concurrent_futures to package (#108401) (#108443) gh-108388: Convert test_concurrent_futures to package (#108401) Convert test_concurrent_futures to a package of sub-tests. (cherry picked from commit aa6f787faa4bc45006da4dc2f942fb9b82c98836) --- Lib/test/libregrtest/runtest.py | 1 + Lib/test/test_concurrent_futures.py | 1677 ----------------- Lib/test/test_concurrent_futures/__init__.py | 16 + Lib/test/test_concurrent_futures/executor.py | 107 ++ .../test_as_completed.py | 115 ++ .../test_concurrent_futures/test_deadlock.py | 253 +++ .../test_concurrent_futures/test_future.py | 291 +++ Lib/test/test_concurrent_futures/test_init.py | 117 ++ .../test_process_pool.py | 202 ++ .../test_concurrent_futures/test_shutdown.py | 343 ++++ .../test_thread_pool.py | 98 + Lib/test/test_concurrent_futures/test_wait.py | 161 ++ Lib/test/test_concurrent_futures/util.py | 141 ++ ...-08-24-06-10-36.gh-issue-108388.YCVB0D.rst | 2 + 14 files changed, 1847 insertions(+), 1677 deletions(-) delete mode 100644 Lib/test/test_concurrent_futures.py create mode 100644 Lib/test/test_concurrent_futures/__init__.py create mode 100644 Lib/test/test_concurrent_futures/executor.py create mode 100644 Lib/test/test_concurrent_futures/test_as_completed.py create mode 100644 Lib/test/test_concurrent_futures/test_deadlock.py create mode 100644 Lib/test/test_concurrent_futures/test_future.py create mode 100644 Lib/test/test_concurrent_futures/test_init.py create mode 100644 Lib/test/test_concurrent_futures/test_process_pool.py create mode 100644 Lib/test/test_concurrent_futures/test_shutdown.py create mode 100644 Lib/test/test_concurrent_futures/test_thread_pool.py create mode 100644 Lib/test/test_concurrent_futures/test_wait.py create mode 100644 Lib/test/test_concurrent_futures/util.py create mode 100644 Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index cddb37c87aa4d4..fd49927679bdea 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -132,6 +132,7 @@ def __str__(self) -> str: SPLITTESTDIRS = { "test_asyncio", + "test_concurrent_futures", "test_multiprocessing_fork", "test_multiprocessing_forkserver", "test_multiprocessing_spawn", diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py deleted file mode 100644 index 39dbe234e765e8..00000000000000 --- a/Lib/test/test_concurrent_futures.py +++ /dev/null @@ -1,1677 +0,0 @@ -from test import support -from test.support import import_helper -from test.support import threading_helper - -# Skip tests if _multiprocessing wasn't built. -import_helper.import_module('_multiprocessing') - -from test.support import hashlib_helper -from test.support.script_helper import assert_python_ok - -import contextlib -import itertools -import logging -from logging.handlers import QueueHandler -import os -import queue -import signal -import sys -import threading -import time -import unittest -import weakref -from pickle import PicklingError - -from concurrent import futures -from concurrent.futures._base import ( - PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future, - BrokenExecutor) -from concurrent.futures.process import BrokenProcessPool, _check_system_limits - -import multiprocessing.process -import multiprocessing.util -import multiprocessing as mp - - -if support.check_sanitizer(address=True, memory=True): - # bpo-46633: Skip the test because it is too slow when Python is built - # with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions. - raise unittest.SkipTest("test too slow on ASAN/MSAN build") - - -def create_future(state=PENDING, exception=None, result=None): - f = Future() - f._state = state - f._exception = exception - f._result = result - return f - - -PENDING_FUTURE = create_future(state=PENDING) -RUNNING_FUTURE = create_future(state=RUNNING) -CANCELLED_FUTURE = create_future(state=CANCELLED) -CANCELLED_AND_NOTIFIED_FUTURE = create_future(state=CANCELLED_AND_NOTIFIED) -EXCEPTION_FUTURE = create_future(state=FINISHED, exception=OSError()) -SUCCESSFUL_FUTURE = create_future(state=FINISHED, result=42) - -INITIALIZER_STATUS = 'uninitialized' - -def mul(x, y): - return x * y - -def capture(*args, **kwargs): - return args, kwargs - -def sleep_and_raise(t): - time.sleep(t) - raise Exception('this is an exception') - -def sleep_and_print(t, msg): - time.sleep(t) - print(msg) - sys.stdout.flush() - -def init(x): - global INITIALIZER_STATUS - INITIALIZER_STATUS = x - -def get_init_status(): - return INITIALIZER_STATUS - -def init_fail(log_queue=None): - if log_queue is not None: - logger = logging.getLogger('concurrent.futures') - logger.addHandler(QueueHandler(log_queue)) - logger.setLevel('CRITICAL') - logger.propagate = False - time.sleep(0.1) # let some futures be scheduled - raise ValueError('error in initializer') - - -class MyObject(object): - def my_method(self): - pass - - -class EventfulGCObj(): - def __init__(self, mgr): - self.event = mgr.Event() - - def __del__(self): - self.event.set() - - -def make_dummy_object(_): - return MyObject() - - -class BaseTestCase(unittest.TestCase): - def setUp(self): - self._thread_key = threading_helper.threading_setup() - - def tearDown(self): - support.reap_children() - threading_helper.threading_cleanup(*self._thread_key) - - -class ExecutorMixin: - worker_count = 5 - executor_kwargs = {} - - def setUp(self): - super().setUp() - - self.t1 = time.monotonic() - if hasattr(self, "ctx"): - self.executor = self.executor_type( - max_workers=self.worker_count, - mp_context=self.get_context(), - **self.executor_kwargs) - else: - self.executor = self.executor_type( - max_workers=self.worker_count, - **self.executor_kwargs) - - def tearDown(self): - self.executor.shutdown(wait=True) - self.executor = None - - dt = time.monotonic() - self.t1 - if support.verbose: - print("%.2fs" % dt, end=' ') - self.assertLess(dt, 300, "synchronization issue: test lasted too long") - - super().tearDown() - - def get_context(self): - return mp.get_context(self.ctx) - - -class ThreadPoolMixin(ExecutorMixin): - executor_type = futures.ThreadPoolExecutor - - -class ProcessPoolForkMixin(ExecutorMixin): - executor_type = futures.ProcessPoolExecutor - ctx = "fork" - - def get_context(self): - try: - _check_system_limits() - except NotImplementedError: - self.skipTest("ProcessPoolExecutor unavailable on this system") - if sys.platform == "win32": - self.skipTest("require unix system") - return super().get_context() - - -class ProcessPoolSpawnMixin(ExecutorMixin): - executor_type = futures.ProcessPoolExecutor - ctx = "spawn" - - def get_context(self): - try: - _check_system_limits() - except NotImplementedError: - self.skipTest("ProcessPoolExecutor unavailable on this system") - return super().get_context() - - -class ProcessPoolForkserverMixin(ExecutorMixin): - executor_type = futures.ProcessPoolExecutor - ctx = "forkserver" - - def get_context(self): - try: - _check_system_limits() - except NotImplementedError: - self.skipTest("ProcessPoolExecutor unavailable on this system") - if sys.platform == "win32": - self.skipTest("require unix system") - return super().get_context() - - -def create_executor_tests(mixin, bases=(BaseTestCase,), - executor_mixins=(ThreadPoolMixin, - ProcessPoolForkMixin, - ProcessPoolForkserverMixin, - ProcessPoolSpawnMixin)): - def strip_mixin(name): - if name.endswith(('Mixin', 'Tests')): - return name[:-5] - elif name.endswith('Test'): - return name[:-4] - else: - return name - - for exe in executor_mixins: - name = ("%s%sTest" - % (strip_mixin(exe.__name__), strip_mixin(mixin.__name__))) - cls = type(name, (mixin,) + (exe,) + bases, {}) - globals()[name] = cls - - -class InitializerMixin(ExecutorMixin): - worker_count = 2 - - def setUp(self): - global INITIALIZER_STATUS - INITIALIZER_STATUS = 'uninitialized' - self.executor_kwargs = dict(initializer=init, - initargs=('initialized',)) - super().setUp() - - def test_initializer(self): - futures = [self.executor.submit(get_init_status) - for _ in range(self.worker_count)] - - for f in futures: - self.assertEqual(f.result(), 'initialized') - - -class FailingInitializerMixin(ExecutorMixin): - worker_count = 2 - - def setUp(self): - if hasattr(self, "ctx"): - # Pass a queue to redirect the child's logging output - self.mp_context = self.get_context() - self.log_queue = self.mp_context.Queue() - self.executor_kwargs = dict(initializer=init_fail, - initargs=(self.log_queue,)) - else: - # In a thread pool, the child shares our logging setup - # (see _assert_logged()) - self.mp_context = None - self.log_queue = None - self.executor_kwargs = dict(initializer=init_fail) - super().setUp() - - def test_initializer(self): - with self._assert_logged('ValueError: error in initializer'): - try: - future = self.executor.submit(get_init_status) - except BrokenExecutor: - # Perhaps the executor is already broken - pass - else: - with self.assertRaises(BrokenExecutor): - future.result() - - # At some point, the executor should break - for _ in support.sleeping_retry(support.SHORT_TIMEOUT, - "executor not broken"): - if self.executor._broken: - break - - # ... and from this point submit() is guaranteed to fail - with self.assertRaises(BrokenExecutor): - self.executor.submit(get_init_status) - - @contextlib.contextmanager - def _assert_logged(self, msg): - if self.log_queue is not None: - yield - output = [] - try: - while True: - output.append(self.log_queue.get_nowait().getMessage()) - except queue.Empty: - pass - else: - with self.assertLogs('concurrent.futures', 'CRITICAL') as cm: - yield - output = cm.output - self.assertTrue(any(msg in line for line in output), - output) - - -create_executor_tests(InitializerMixin) -create_executor_tests(FailingInitializerMixin) - - -class ExecutorShutdownTest: - def test_run_after_shutdown(self): - self.executor.shutdown() - self.assertRaises(RuntimeError, - self.executor.submit, - pow, 2, 5) - - def test_interpreter_shutdown(self): - # Test the atexit hook for shutdown of worker threads and processes - rc, out, err = assert_python_ok('-c', """if 1: - from concurrent.futures import {executor_type} - from time import sleep - from test.test_concurrent_futures import sleep_and_print - if __name__ == "__main__": - context = '{context}' - if context == "": - t = {executor_type}(5) - else: - from multiprocessing import get_context - context = get_context(context) - t = {executor_type}(5, mp_context=context) - t.submit(sleep_and_print, 1.0, "apple") - """.format(executor_type=self.executor_type.__name__, - context=getattr(self, "ctx", ""))) - # Errors in atexit hooks don't change the process exit code, check - # stderr manually. - self.assertFalse(err) - self.assertEqual(out.strip(), b"apple") - - def test_submit_after_interpreter_shutdown(self): - # Test the atexit hook for shutdown of worker threads and processes - rc, out, err = assert_python_ok('-c', """if 1: - import atexit - @atexit.register - def run_last(): - try: - t.submit(id, None) - except RuntimeError: - print("runtime-error") - raise - from concurrent.futures import {executor_type} - if __name__ == "__main__": - context = '{context}' - if not context: - t = {executor_type}(5) - else: - from multiprocessing import get_context - context = get_context(context) - t = {executor_type}(5, mp_context=context) - t.submit(id, 42).result() - """.format(executor_type=self.executor_type.__name__, - context=getattr(self, "ctx", ""))) - # Errors in atexit hooks don't change the process exit code, check - # stderr manually. - self.assertIn("RuntimeError: cannot schedule new futures", err.decode()) - self.assertEqual(out.strip(), b"runtime-error") - - def test_hang_issue12364(self): - fs = [self.executor.submit(time.sleep, 0.1) for _ in range(50)] - self.executor.shutdown() - for f in fs: - f.result() - - def test_cancel_futures(self): - assert self.worker_count <= 5, "test needs few workers" - fs = [self.executor.submit(time.sleep, .1) for _ in range(50)] - self.executor.shutdown(cancel_futures=True) - # We can't guarantee the exact number of cancellations, but we can - # guarantee that *some* were cancelled. With few workers, many of - # the submitted futures should have been cancelled. - cancelled = [fut for fut in fs if fut.cancelled()] - self.assertGreater(len(cancelled), 20) - - # Ensure the other futures were able to finish. - # Use "not fut.cancelled()" instead of "fut.done()" to include futures - # that may have been left in a pending state. - others = [fut for fut in fs if not fut.cancelled()] - for fut in others: - self.assertTrue(fut.done(), msg=f"{fut._state=}") - self.assertIsNone(fut.exception()) - - # Similar to the number of cancelled futures, we can't guarantee the - # exact number that completed. But, we can guarantee that at least - # one finished. - self.assertGreater(len(others), 0) - - def test_hang_gh83386(self): - """shutdown(wait=False) doesn't hang at exit with running futures. - - See https://github.com/python/cpython/issues/83386. - """ - if self.executor_type == futures.ProcessPoolExecutor: - raise unittest.SkipTest( - "Hangs, see https://github.com/python/cpython/issues/83386") - - rc, out, err = assert_python_ok('-c', """if True: - from concurrent.futures import {executor_type} - from test.test_concurrent_futures import sleep_and_print - if __name__ == "__main__": - if {context!r}: multiprocessing.set_start_method({context!r}) - t = {executor_type}(max_workers=3) - t.submit(sleep_and_print, 1.0, "apple") - t.shutdown(wait=False) - """.format(executor_type=self.executor_type.__name__, - context=getattr(self, 'ctx', None))) - self.assertFalse(err) - self.assertEqual(out.strip(), b"apple") - - def test_hang_gh94440(self): - """shutdown(wait=True) doesn't hang when a future was submitted and - quickly canceled right before shutdown. - - See https://github.com/python/cpython/issues/94440. - """ - if not hasattr(signal, 'alarm'): - raise unittest.SkipTest( - "Tested platform does not support the alarm signal") - - def timeout(_signum, _frame): - raise RuntimeError("timed out waiting for shutdown") - - kwargs = {} - if getattr(self, 'ctx', None): - kwargs['mp_context'] = self.get_context() - executor = self.executor_type(max_workers=1, **kwargs) - executor.submit(int).result() - old_handler = signal.signal(signal.SIGALRM, timeout) - try: - signal.alarm(5) - executor.submit(int).cancel() - executor.shutdown(wait=True) - finally: - signal.alarm(0) - signal.signal(signal.SIGALRM, old_handler) - - -class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase): - def test_threads_terminate(self): - def acquire_lock(lock): - lock.acquire() - - sem = threading.Semaphore(0) - for i in range(3): - self.executor.submit(acquire_lock, sem) - self.assertEqual(len(self.executor._threads), 3) - for i in range(3): - sem.release() - self.executor.shutdown() - for t in self.executor._threads: - t.join() - - def test_context_manager_shutdown(self): - with futures.ThreadPoolExecutor(max_workers=5) as e: - executor = e - self.assertEqual(list(e.map(abs, range(-5, 5))), - [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) - - for t in executor._threads: - t.join() - - def test_del_shutdown(self): - executor = futures.ThreadPoolExecutor(max_workers=5) - res = executor.map(abs, range(-5, 5)) - threads = executor._threads - del executor - - for t in threads: - t.join() - - # Make sure the results were all computed before the - # executor got shutdown. - assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) - - def test_shutdown_no_wait(self): - # Ensure that the executor cleans up the threads when calling - # shutdown with wait=False - executor = futures.ThreadPoolExecutor(max_workers=5) - res = executor.map(abs, range(-5, 5)) - threads = executor._threads - executor.shutdown(wait=False) - for t in threads: - t.join() - - # Make sure the results were all computed before the - # executor got shutdown. - assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) - - - def test_thread_names_assigned(self): - executor = futures.ThreadPoolExecutor( - max_workers=5, thread_name_prefix='SpecialPool') - executor.map(abs, range(-5, 5)) - threads = executor._threads - del executor - support.gc_collect() # For PyPy or other GCs. - - for t in threads: - self.assertRegex(t.name, r'^SpecialPool_[0-4]$') - t.join() - - def test_thread_names_default(self): - executor = futures.ThreadPoolExecutor(max_workers=5) - executor.map(abs, range(-5, 5)) - threads = executor._threads - del executor - support.gc_collect() # For PyPy or other GCs. - - for t in threads: - # Ensure that our default name is reasonably sane and unique when - # no thread_name_prefix was supplied. - self.assertRegex(t.name, r'ThreadPoolExecutor-\d+_[0-4]$') - t.join() - - def test_cancel_futures_wait_false(self): - # Can only be reliably tested for TPE, since PPE often hangs with - # `wait=False` (even without *cancel_futures*). - rc, out, err = assert_python_ok('-c', """if True: - from concurrent.futures import ThreadPoolExecutor - from test.test_concurrent_futures import sleep_and_print - if __name__ == "__main__": - t = ThreadPoolExecutor() - t.submit(sleep_and_print, .1, "apple") - t.shutdown(wait=False, cancel_futures=True) - """) - # Errors in atexit hooks don't change the process exit code, check - # stderr manually. - self.assertFalse(err) - self.assertEqual(out.strip(), b"apple") - - -class ProcessPoolShutdownTest(ExecutorShutdownTest): - def test_processes_terminate(self): - def acquire_lock(lock): - lock.acquire() - - mp_context = self.get_context() - if mp_context.get_start_method(allow_none=False) == "fork": - # fork pre-spawns, not on demand. - expected_num_processes = self.worker_count - else: - expected_num_processes = 3 - - sem = mp_context.Semaphore(0) - for _ in range(3): - self.executor.submit(acquire_lock, sem) - self.assertEqual(len(self.executor._processes), expected_num_processes) - for _ in range(3): - sem.release() - processes = self.executor._processes - self.executor.shutdown() - - for p in processes.values(): - p.join() - - def test_context_manager_shutdown(self): - with futures.ProcessPoolExecutor( - max_workers=5, mp_context=self.get_context()) as e: - processes = e._processes - self.assertEqual(list(e.map(abs, range(-5, 5))), - [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) - - for p in processes.values(): - p.join() - - def test_del_shutdown(self): - executor = futures.ProcessPoolExecutor( - max_workers=5, mp_context=self.get_context()) - res = executor.map(abs, range(-5, 5)) - executor_manager_thread = executor._executor_manager_thread - processes = executor._processes - call_queue = executor._call_queue - executor_manager_thread = executor._executor_manager_thread - del executor - support.gc_collect() # For PyPy or other GCs. - - # Make sure that all the executor resources were properly cleaned by - # the shutdown process - executor_manager_thread.join() - for p in processes.values(): - p.join() - call_queue.join_thread() - - # Make sure the results were all computed before the - # executor got shutdown. - assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) - - def test_shutdown_no_wait(self): - # Ensure that the executor cleans up the processes when calling - # shutdown with wait=False - executor = futures.ProcessPoolExecutor( - max_workers=5, mp_context=self.get_context()) - res = executor.map(abs, range(-5, 5)) - processes = executor._processes - call_queue = executor._call_queue - executor_manager_thread = executor._executor_manager_thread - executor.shutdown(wait=False) - - # Make sure that all the executor resources were properly cleaned by - # the shutdown process - executor_manager_thread.join() - for p in processes.values(): - p.join() - call_queue.join_thread() - - # Make sure the results were all computed before the executor got - # shutdown. - assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) - - -create_executor_tests(ProcessPoolShutdownTest, - executor_mixins=(ProcessPoolForkMixin, - ProcessPoolForkserverMixin, - ProcessPoolSpawnMixin)) - - -class WaitTests: - def test_20369(self): - # See https://bugs.python.org/issue20369 - future = self.executor.submit(time.sleep, 1.5) - done, not_done = futures.wait([future, future], - return_when=futures.ALL_COMPLETED) - self.assertEqual({future}, done) - self.assertEqual(set(), not_done) - - - def test_first_completed(self): - future1 = self.executor.submit(mul, 21, 2) - future2 = self.executor.submit(time.sleep, 1.5) - - done, not_done = futures.wait( - [CANCELLED_FUTURE, future1, future2], - return_when=futures.FIRST_COMPLETED) - - self.assertEqual(set([future1]), done) - self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) - - def test_first_completed_some_already_completed(self): - future1 = self.executor.submit(time.sleep, 1.5) - - finished, pending = futures.wait( - [CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE, future1], - return_when=futures.FIRST_COMPLETED) - - self.assertEqual( - set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]), - finished) - self.assertEqual(set([future1]), pending) - - def test_first_exception(self): - future1 = self.executor.submit(mul, 2, 21) - future2 = self.executor.submit(sleep_and_raise, 1.5) - future3 = self.executor.submit(time.sleep, 3) - - finished, pending = futures.wait( - [future1, future2, future3], - return_when=futures.FIRST_EXCEPTION) - - self.assertEqual(set([future1, future2]), finished) - self.assertEqual(set([future3]), pending) - - def test_first_exception_some_already_complete(self): - future1 = self.executor.submit(divmod, 21, 0) - future2 = self.executor.submit(time.sleep, 1.5) - - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, - CANCELLED_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1, future2], - return_when=futures.FIRST_EXCEPTION) - - self.assertEqual(set([SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1]), finished) - self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) - - def test_first_exception_one_already_failed(self): - future1 = self.executor.submit(time.sleep, 2) - - finished, pending = futures.wait( - [EXCEPTION_FUTURE, future1], - return_when=futures.FIRST_EXCEPTION) - - self.assertEqual(set([EXCEPTION_FUTURE]), finished) - self.assertEqual(set([future1]), pending) - - def test_all_completed(self): - future1 = self.executor.submit(divmod, 2, 0) - future2 = self.executor.submit(mul, 2, 21) - - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - future1, - future2], - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - future1, - future2]), finished) - self.assertEqual(set(), pending) - - def test_timeout(self): - future1 = self.executor.submit(mul, 6, 7) - future2 = self.executor.submit(time.sleep, 6) - - finished, pending = futures.wait( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1, future2], - timeout=5, - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1]), finished) - self.assertEqual(set([future2]), pending) - - -class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests, BaseTestCase): - - def test_pending_calls_race(self): - # Issue #14406: multi-threaded race condition when waiting on all - # futures. - event = threading.Event() - def future_func(): - event.wait() - oldswitchinterval = sys.getswitchinterval() - sys.setswitchinterval(1e-6) - try: - fs = {self.executor.submit(future_func) for i in range(100)} - event.set() - futures.wait(fs, return_when=futures.ALL_COMPLETED) - finally: - sys.setswitchinterval(oldswitchinterval) - - -create_executor_tests(WaitTests, - executor_mixins=(ProcessPoolForkMixin, - ProcessPoolForkserverMixin, - ProcessPoolSpawnMixin)) - - -class AsCompletedTests: - def test_no_timeout(self): - future1 = self.executor.submit(mul, 2, 21) - future2 = self.executor.submit(mul, 7, 6) - - completed = set(futures.as_completed( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1, future2])) - self.assertEqual(set( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1, future2]), - completed) - - def test_future_times_out(self): - """Test ``futures.as_completed`` timing out before - completing it's final future.""" - already_completed = {CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE} - - for timeout in (0, 0.01): - with self.subTest(timeout): - - future = self.executor.submit(time.sleep, 0.1) - completed_futures = set() - try: - for f in futures.as_completed( - already_completed | {future}, - timeout - ): - completed_futures.add(f) - except futures.TimeoutError: - pass - - # Check that ``future`` wasn't completed. - self.assertEqual(completed_futures, already_completed) - - def test_duplicate_futures(self): - # Issue 20367. Duplicate futures should not raise exceptions or give - # duplicate responses. - # Issue #31641: accept arbitrary iterables. - future1 = self.executor.submit(time.sleep, 2) - completed = [ - f for f in futures.as_completed(itertools.repeat(future1, 3)) - ] - self.assertEqual(len(completed), 1) - - def test_free_reference_yielded_future(self): - # Issue #14406: Generator should not keep references - # to finished futures. - futures_list = [Future() for _ in range(8)] - futures_list.append(create_future(state=CANCELLED_AND_NOTIFIED)) - futures_list.append(create_future(state=FINISHED, result=42)) - - with self.assertRaises(futures.TimeoutError): - for future in futures.as_completed(futures_list, timeout=0): - futures_list.remove(future) - wr = weakref.ref(future) - del future - support.gc_collect() # For PyPy or other GCs. - self.assertIsNone(wr()) - - futures_list[0].set_result("test") - for future in futures.as_completed(futures_list): - futures_list.remove(future) - wr = weakref.ref(future) - del future - support.gc_collect() # For PyPy or other GCs. - self.assertIsNone(wr()) - if futures_list: - futures_list[0].set_result("test") - - def test_correct_timeout_exception_msg(self): - futures_list = [CANCELLED_AND_NOTIFIED_FUTURE, PENDING_FUTURE, - RUNNING_FUTURE, SUCCESSFUL_FUTURE] - - with self.assertRaises(futures.TimeoutError) as cm: - list(futures.as_completed(futures_list, timeout=0)) - - self.assertEqual(str(cm.exception), '2 (of 4) futures unfinished') - - -create_executor_tests(AsCompletedTests) - - -class ExecutorTest: - # Executor.shutdown() and context manager usage is tested by - # ExecutorShutdownTest. - def test_submit(self): - future = self.executor.submit(pow, 2, 8) - self.assertEqual(256, future.result()) - - def test_submit_keyword(self): - future = self.executor.submit(mul, 2, y=8) - self.assertEqual(16, future.result()) - future = self.executor.submit(capture, 1, self=2, fn=3) - self.assertEqual(future.result(), ((1,), {'self': 2, 'fn': 3})) - with self.assertRaises(TypeError): - self.executor.submit(fn=capture, arg=1) - with self.assertRaises(TypeError): - self.executor.submit(arg=1) - - def test_map(self): - self.assertEqual( - list(self.executor.map(pow, range(10), range(10))), - list(map(pow, range(10), range(10)))) - - self.assertEqual( - list(self.executor.map(pow, range(10), range(10), chunksize=3)), - list(map(pow, range(10), range(10)))) - - def test_map_exception(self): - i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5]) - self.assertEqual(i.__next__(), (0, 1)) - self.assertEqual(i.__next__(), (0, 1)) - self.assertRaises(ZeroDivisionError, i.__next__) - - def test_map_timeout(self): - results = [] - try: - for i in self.executor.map(time.sleep, - [0, 0, 6], - timeout=5): - results.append(i) - except futures.TimeoutError: - pass - else: - self.fail('expected TimeoutError') - - self.assertEqual([None, None], results) - - def test_shutdown_race_issue12456(self): - # Issue #12456: race condition at shutdown where trying to post a - # sentinel in the call queue blocks (the queue is full while processes - # have exited). - self.executor.map(str, [2] * (self.worker_count + 1)) - self.executor.shutdown() - - @support.cpython_only - def test_no_stale_references(self): - # Issue #16284: check that the executors don't unnecessarily hang onto - # references. - my_object = MyObject() - my_object_collected = threading.Event() - my_object_callback = weakref.ref( - my_object, lambda obj: my_object_collected.set()) - # Deliberately discarding the future. - self.executor.submit(my_object.my_method) - del my_object - - collected = my_object_collected.wait(timeout=support.SHORT_TIMEOUT) - self.assertTrue(collected, - "Stale reference not collected within timeout.") - - def test_max_workers_negative(self): - for number in (0, -1): - with self.assertRaisesRegex(ValueError, - "max_workers must be greater " - "than 0"): - self.executor_type(max_workers=number) - - def test_free_reference(self): - # Issue #14406: Result iterator should not keep an internal - # reference to result objects. - for obj in self.executor.map(make_dummy_object, range(10)): - wr = weakref.ref(obj) - del obj - support.gc_collect() # For PyPy or other GCs. - self.assertIsNone(wr()) - - -class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase): - def test_map_submits_without_iteration(self): - """Tests verifying issue 11777.""" - finished = [] - def record_finished(n): - finished.append(n) - - self.executor.map(record_finished, range(10)) - self.executor.shutdown(wait=True) - self.assertCountEqual(finished, range(10)) - - def test_default_workers(self): - executor = self.executor_type() - expected = min(32, (os.cpu_count() or 1) + 4) - self.assertEqual(executor._max_workers, expected) - - def test_saturation(self): - executor = self.executor_type(4) - def acquire_lock(lock): - lock.acquire() - - sem = threading.Semaphore(0) - for i in range(15 * executor._max_workers): - executor.submit(acquire_lock, sem) - self.assertEqual(len(executor._threads), executor._max_workers) - for i in range(15 * executor._max_workers): - sem.release() - executor.shutdown(wait=True) - - def test_idle_thread_reuse(self): - executor = self.executor_type() - executor.submit(mul, 21, 2).result() - executor.submit(mul, 6, 7).result() - executor.submit(mul, 3, 14).result() - self.assertEqual(len(executor._threads), 1) - executor.shutdown(wait=True) - - @unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork') - def test_hang_global_shutdown_lock(self): - # bpo-45021: _global_shutdown_lock should be reinitialized in the child - # process, otherwise it will never exit - def submit(pool): - pool.submit(submit, pool) - - with futures.ThreadPoolExecutor(1) as pool: - pool.submit(submit, pool) - - for _ in range(50): - with futures.ProcessPoolExecutor(1, mp_context=mp.get_context('fork')) as workers: - workers.submit(tuple) - - def test_executor_map_current_future_cancel(self): - stop_event = threading.Event() - log = [] - - def log_n_wait(ident): - log.append(f"{ident=} started") - try: - stop_event.wait() - finally: - log.append(f"{ident=} stopped") - - with self.executor_type(max_workers=1) as pool: - # submit work to saturate the pool - fut = pool.submit(log_n_wait, ident="first") - try: - with contextlib.closing( - pool.map(log_n_wait, ["second", "third"], timeout=0) - ) as gen: - with self.assertRaises(TimeoutError): - next(gen) - finally: - stop_event.set() - fut.result() - # ident='second' is cancelled as a result of raising a TimeoutError - # ident='third' is cancelled because it remained in the collection of futures - self.assertListEqual(log, ["ident='first' started", "ident='first' stopped"]) - - -class ProcessPoolExecutorTest(ExecutorTest): - - @unittest.skipUnless(sys.platform=='win32', 'Windows-only process limit') - def test_max_workers_too_large(self): - with self.assertRaisesRegex(ValueError, - "max_workers must be <= 61"): - futures.ProcessPoolExecutor(max_workers=62) - - def test_killed_child(self): - # When a child process is abruptly terminated, the whole pool gets - # "broken". - futures = [self.executor.submit(time.sleep, 3)] - # Get one of the processes, and terminate (kill) it - p = next(iter(self.executor._processes.values())) - p.terminate() - for fut in futures: - self.assertRaises(BrokenProcessPool, fut.result) - # Submitting other jobs fails as well. - self.assertRaises(BrokenProcessPool, self.executor.submit, pow, 2, 8) - - def test_map_chunksize(self): - def bad_map(): - list(self.executor.map(pow, range(40), range(40), chunksize=-1)) - - ref = list(map(pow, range(40), range(40))) - self.assertEqual( - list(self.executor.map(pow, range(40), range(40), chunksize=6)), - ref) - self.assertEqual( - list(self.executor.map(pow, range(40), range(40), chunksize=50)), - ref) - self.assertEqual( - list(self.executor.map(pow, range(40), range(40), chunksize=40)), - ref) - self.assertRaises(ValueError, bad_map) - - @classmethod - def _test_traceback(cls): - raise RuntimeError(123) # some comment - - def test_traceback(self): - # We want ensure that the traceback from the child process is - # contained in the traceback raised in the main process. - future = self.executor.submit(self._test_traceback) - with self.assertRaises(Exception) as cm: - future.result() - - exc = cm.exception - self.assertIs(type(exc), RuntimeError) - self.assertEqual(exc.args, (123,)) - cause = exc.__cause__ - self.assertIs(type(cause), futures.process._RemoteTraceback) - self.assertIn('raise RuntimeError(123) # some comment', cause.tb) - - with support.captured_stderr() as f1: - try: - raise exc - except RuntimeError: - sys.excepthook(*sys.exc_info()) - self.assertIn('raise RuntimeError(123) # some comment', - f1.getvalue()) - - @hashlib_helper.requires_hashdigest('md5') - def test_ressources_gced_in_workers(self): - # Ensure that argument for a job are correctly gc-ed after the job - # is finished - mgr = self.get_context().Manager() - obj = EventfulGCObj(mgr) - future = self.executor.submit(id, obj) - future.result() - - self.assertTrue(obj.event.wait(timeout=1)) - - # explicitly destroy the object to ensure that EventfulGCObj.__del__() - # is called while manager is still running. - obj = None - support.gc_collect() - - mgr.shutdown() - mgr.join() - - def test_saturation(self): - executor = self.executor - mp_context = self.get_context() - sem = mp_context.Semaphore(0) - job_count = 15 * executor._max_workers - for _ in range(job_count): - executor.submit(sem.acquire) - self.assertEqual(len(executor._processes), executor._max_workers) - for _ in range(job_count): - sem.release() - - def test_idle_process_reuse_one(self): - executor = self.executor - assert executor._max_workers >= 4 - if self.get_context().get_start_method(allow_none=False) == "fork": - raise unittest.SkipTest("Incompatible with the fork start method.") - executor.submit(mul, 21, 2).result() - executor.submit(mul, 6, 7).result() - executor.submit(mul, 3, 14).result() - self.assertEqual(len(executor._processes), 1) - - def test_idle_process_reuse_multiple(self): - executor = self.executor - assert executor._max_workers <= 5 - if self.get_context().get_start_method(allow_none=False) == "fork": - raise unittest.SkipTest("Incompatible with the fork start method.") - executor.submit(mul, 12, 7).result() - executor.submit(mul, 33, 25) - executor.submit(mul, 25, 26).result() - executor.submit(mul, 18, 29) - executor.submit(mul, 1, 2).result() - executor.submit(mul, 0, 9) - self.assertLessEqual(len(executor._processes), 3) - executor.shutdown() - - def test_max_tasks_per_child(self): - context = self.get_context() - if context.get_start_method(allow_none=False) == "fork": - with self.assertRaises(ValueError): - self.executor_type(1, mp_context=context, max_tasks_per_child=3) - return - # not using self.executor as we need to control construction. - # arguably this could go in another class w/o that mixin. - executor = self.executor_type( - 1, mp_context=context, max_tasks_per_child=3) - f1 = executor.submit(os.getpid) - original_pid = f1.result() - # The worker pid remains the same as the worker could be reused - f2 = executor.submit(os.getpid) - self.assertEqual(f2.result(), original_pid) - self.assertEqual(len(executor._processes), 1) - f3 = executor.submit(os.getpid) - self.assertEqual(f3.result(), original_pid) - - # A new worker is spawned, with a statistically different pid, - # while the previous was reaped. - f4 = executor.submit(os.getpid) - new_pid = f4.result() - self.assertNotEqual(original_pid, new_pid) - self.assertEqual(len(executor._processes), 1) - - executor.shutdown() - - def test_max_tasks_per_child_defaults_to_spawn_context(self): - # not using self.executor as we need to control construction. - # arguably this could go in another class w/o that mixin. - executor = self.executor_type(1, max_tasks_per_child=3) - self.assertEqual(executor._mp_context.get_start_method(), "spawn") - - def test_max_tasks_early_shutdown(self): - context = self.get_context() - if context.get_start_method(allow_none=False) == "fork": - raise unittest.SkipTest("Incompatible with the fork start method.") - # not using self.executor as we need to control construction. - # arguably this could go in another class w/o that mixin. - executor = self.executor_type( - 3, mp_context=context, max_tasks_per_child=1) - futures = [] - for i in range(6): - futures.append(executor.submit(mul, i, i)) - executor.shutdown() - for i, future in enumerate(futures): - self.assertEqual(future.result(), mul(i, i)) - - -create_executor_tests(ProcessPoolExecutorTest, - executor_mixins=(ProcessPoolForkMixin, - ProcessPoolForkserverMixin, - ProcessPoolSpawnMixin)) - -def _crash(delay=None): - """Induces a segfault.""" - if delay: - time.sleep(delay) - import faulthandler - faulthandler.disable() - faulthandler._sigsegv() - - -def _crash_with_data(data): - """Induces a segfault with dummy data in input.""" - _crash() - - -def _exit(): - """Induces a sys exit with exitcode 1.""" - sys.exit(1) - - -def _raise_error(Err): - """Function that raises an Exception in process.""" - raise Err() - - -def _raise_error_ignore_stderr(Err): - """Function that raises an Exception in process and ignores stderr.""" - import io - sys.stderr = io.StringIO() - raise Err() - - -def _return_instance(cls): - """Function that returns a instance of cls.""" - return cls() - - -class CrashAtPickle(object): - """Bad object that triggers a segfault at pickling time.""" - def __reduce__(self): - _crash() - - -class CrashAtUnpickle(object): - """Bad object that triggers a segfault at unpickling time.""" - def __reduce__(self): - return _crash, () - - -class ExitAtPickle(object): - """Bad object that triggers a process exit at pickling time.""" - def __reduce__(self): - _exit() - - -class ExitAtUnpickle(object): - """Bad object that triggers a process exit at unpickling time.""" - def __reduce__(self): - return _exit, () - - -class ErrorAtPickle(object): - """Bad object that triggers an error at pickling time.""" - def __reduce__(self): - from pickle import PicklingError - raise PicklingError("Error in pickle") - - -class ErrorAtUnpickle(object): - """Bad object that triggers an error at unpickling time.""" - def __reduce__(self): - from pickle import UnpicklingError - return _raise_error_ignore_stderr, (UnpicklingError, ) - - -class ExecutorDeadlockTest: - TIMEOUT = support.SHORT_TIMEOUT - - def _fail_on_deadlock(self, executor): - # If we did not recover before TIMEOUT seconds, consider that the - # executor is in a deadlock state and forcefully clean all its - # composants. - import faulthandler - from tempfile import TemporaryFile - with TemporaryFile(mode="w+") as f: - faulthandler.dump_traceback(file=f) - f.seek(0) - tb = f.read() - for p in executor._processes.values(): - p.terminate() - # This should be safe to call executor.shutdown here as all possible - # deadlocks should have been broken. - executor.shutdown(wait=True) - print(f"\nTraceback:\n {tb}", file=sys.__stderr__) - self.fail(f"Executor deadlock:\n\n{tb}") - - - def _check_crash(self, error, func, *args, ignore_stderr=False): - # test for deadlock caused by crashes in a pool - self.executor.shutdown(wait=True) - - executor = self.executor_type( - max_workers=2, mp_context=self.get_context()) - res = executor.submit(func, *args) - - if ignore_stderr: - cm = support.captured_stderr() - else: - cm = contextlib.nullcontext() - - try: - with self.assertRaises(error): - with cm: - res.result(timeout=self.TIMEOUT) - except futures.TimeoutError: - # If we did not recover before TIMEOUT seconds, - # consider that the executor is in a deadlock state - self._fail_on_deadlock(executor) - executor.shutdown(wait=True) - - def test_error_at_task_pickle(self): - # Check problem occurring while pickling a task in - # the task_handler thread - self._check_crash(PicklingError, id, ErrorAtPickle()) - - def test_exit_at_task_unpickle(self): - # Check problem occurring while unpickling a task on workers - self._check_crash(BrokenProcessPool, id, ExitAtUnpickle()) - - def test_error_at_task_unpickle(self): - # Check problem occurring while unpickling a task on workers - self._check_crash(BrokenProcessPool, id, ErrorAtUnpickle()) - - def test_crash_at_task_unpickle(self): - # Check problem occurring while unpickling a task on workers - self._check_crash(BrokenProcessPool, id, CrashAtUnpickle()) - - def test_crash_during_func_exec_on_worker(self): - # Check problem occurring during func execution on workers - self._check_crash(BrokenProcessPool, _crash) - - def test_exit_during_func_exec_on_worker(self): - # Check problem occurring during func execution on workers - self._check_crash(SystemExit, _exit) - - def test_error_during_func_exec_on_worker(self): - # Check problem occurring during func execution on workers - self._check_crash(RuntimeError, _raise_error, RuntimeError) - - def test_crash_during_result_pickle_on_worker(self): - # Check problem occurring while pickling a task result - # on workers - self._check_crash(BrokenProcessPool, _return_instance, CrashAtPickle) - - def test_exit_during_result_pickle_on_worker(self): - # Check problem occurring while pickling a task result - # on workers - self._check_crash(SystemExit, _return_instance, ExitAtPickle) - - def test_error_during_result_pickle_on_worker(self): - # Check problem occurring while pickling a task result - # on workers - self._check_crash(PicklingError, _return_instance, ErrorAtPickle) - - def test_error_during_result_unpickle_in_result_handler(self): - # Check problem occurring while unpickling a task in - # the result_handler thread - self._check_crash(BrokenProcessPool, - _return_instance, ErrorAtUnpickle, - ignore_stderr=True) - - def test_exit_during_result_unpickle_in_result_handler(self): - # Check problem occurring while unpickling a task in - # the result_handler thread - self._check_crash(BrokenProcessPool, _return_instance, ExitAtUnpickle) - - def test_shutdown_deadlock(self): - # Test that the pool calling shutdown do not cause deadlock - # if a worker fails after the shutdown call. - self.executor.shutdown(wait=True) - with self.executor_type(max_workers=2, - mp_context=self.get_context()) as executor: - self.executor = executor # Allow clean up in fail_on_deadlock - f = executor.submit(_crash, delay=.1) - executor.shutdown(wait=True) - with self.assertRaises(BrokenProcessPool): - f.result() - - def test_shutdown_deadlock_pickle(self): - # Test that the pool calling shutdown with wait=False does not cause - # a deadlock if a task fails at pickle after the shutdown call. - # Reported in bpo-39104. - self.executor.shutdown(wait=True) - with self.executor_type(max_workers=2, - mp_context=self.get_context()) as executor: - self.executor = executor # Allow clean up in fail_on_deadlock - - # Start the executor and get the executor_manager_thread to collect - # the threads and avoid dangling thread that should be cleaned up - # asynchronously. - executor.submit(id, 42).result() - executor_manager = executor._executor_manager_thread - - # Submit a task that fails at pickle and shutdown the executor - # without waiting - f = executor.submit(id, ErrorAtPickle()) - executor.shutdown(wait=False) - with self.assertRaises(PicklingError): - f.result() - - # Make sure the executor is eventually shutdown and do not leave - # dangling threads - executor_manager.join() - - def test_crash_big_data(self): - # Test that there is a clean exception instad of a deadlock when a - # child process crashes while some data is being written into the - # queue. - # https://github.com/python/cpython/issues/94777 - self.executor.shutdown(wait=True) - data = "a" * support.PIPE_MAX_SIZE - with self.executor_type(max_workers=2, - mp_context=self.get_context()) as executor: - self.executor = executor # Allow clean up in fail_on_deadlock - with self.assertRaises(BrokenProcessPool): - list(executor.map(_crash_with_data, [data] * 10)) - - -create_executor_tests(ExecutorDeadlockTest, - executor_mixins=(ProcessPoolForkMixin, - ProcessPoolForkserverMixin, - ProcessPoolSpawnMixin)) - - -class FutureTests(BaseTestCase): - def test_done_callback_with_result(self): - callback_result = None - def fn(callback_future): - nonlocal callback_result - callback_result = callback_future.result() - - f = Future() - f.add_done_callback(fn) - f.set_result(5) - self.assertEqual(5, callback_result) - - def test_done_callback_with_exception(self): - callback_exception = None - def fn(callback_future): - nonlocal callback_exception - callback_exception = callback_future.exception() - - f = Future() - f.add_done_callback(fn) - f.set_exception(Exception('test')) - self.assertEqual(('test',), callback_exception.args) - - def test_done_callback_with_cancel(self): - was_cancelled = None - def fn(callback_future): - nonlocal was_cancelled - was_cancelled = callback_future.cancelled() - - f = Future() - f.add_done_callback(fn) - self.assertTrue(f.cancel()) - self.assertTrue(was_cancelled) - - def test_done_callback_raises(self): - with support.captured_stderr() as stderr: - raising_was_called = False - fn_was_called = False - - def raising_fn(callback_future): - nonlocal raising_was_called - raising_was_called = True - raise Exception('doh!') - - def fn(callback_future): - nonlocal fn_was_called - fn_was_called = True - - f = Future() - f.add_done_callback(raising_fn) - f.add_done_callback(fn) - f.set_result(5) - self.assertTrue(raising_was_called) - self.assertTrue(fn_was_called) - self.assertIn('Exception: doh!', stderr.getvalue()) - - def test_done_callback_already_successful(self): - callback_result = None - def fn(callback_future): - nonlocal callback_result - callback_result = callback_future.result() - - f = Future() - f.set_result(5) - f.add_done_callback(fn) - self.assertEqual(5, callback_result) - - def test_done_callback_already_failed(self): - callback_exception = None - def fn(callback_future): - nonlocal callback_exception - callback_exception = callback_future.exception() - - f = Future() - f.set_exception(Exception('test')) - f.add_done_callback(fn) - self.assertEqual(('test',), callback_exception.args) - - def test_done_callback_already_cancelled(self): - was_cancelled = None - def fn(callback_future): - nonlocal was_cancelled - was_cancelled = callback_future.cancelled() - - f = Future() - self.assertTrue(f.cancel()) - f.add_done_callback(fn) - self.assertTrue(was_cancelled) - - def test_done_callback_raises_already_succeeded(self): - with support.captured_stderr() as stderr: - def raising_fn(callback_future): - raise Exception('doh!') - - f = Future() - - # Set the result first to simulate a future that runs instantly, - # effectively allowing the callback to be run immediately. - f.set_result(5) - f.add_done_callback(raising_fn) - - self.assertIn('exception calling callback for', stderr.getvalue()) - self.assertIn('doh!', stderr.getvalue()) - - - def test_repr(self): - self.assertRegex(repr(PENDING_FUTURE), - '') - self.assertRegex(repr(RUNNING_FUTURE), - '') - self.assertRegex(repr(CANCELLED_FUTURE), - '') - self.assertRegex(repr(CANCELLED_AND_NOTIFIED_FUTURE), - '') - self.assertRegex( - repr(EXCEPTION_FUTURE), - '') - self.assertRegex( - repr(SUCCESSFUL_FUTURE), - '') - - - def test_cancel(self): - f1 = create_future(state=PENDING) - f2 = create_future(state=RUNNING) - f3 = create_future(state=CANCELLED) - f4 = create_future(state=CANCELLED_AND_NOTIFIED) - f5 = create_future(state=FINISHED, exception=OSError()) - f6 = create_future(state=FINISHED, result=5) - - self.assertTrue(f1.cancel()) - self.assertEqual(f1._state, CANCELLED) - - self.assertFalse(f2.cancel()) - self.assertEqual(f2._state, RUNNING) - - self.assertTrue(f3.cancel()) - self.assertEqual(f3._state, CANCELLED) - - self.assertTrue(f4.cancel()) - self.assertEqual(f4._state, CANCELLED_AND_NOTIFIED) - - self.assertFalse(f5.cancel()) - self.assertEqual(f5._state, FINISHED) - - self.assertFalse(f6.cancel()) - self.assertEqual(f6._state, FINISHED) - - def test_cancelled(self): - self.assertFalse(PENDING_FUTURE.cancelled()) - self.assertFalse(RUNNING_FUTURE.cancelled()) - self.assertTrue(CANCELLED_FUTURE.cancelled()) - self.assertTrue(CANCELLED_AND_NOTIFIED_FUTURE.cancelled()) - self.assertFalse(EXCEPTION_FUTURE.cancelled()) - self.assertFalse(SUCCESSFUL_FUTURE.cancelled()) - - def test_done(self): - self.assertFalse(PENDING_FUTURE.done()) - self.assertFalse(RUNNING_FUTURE.done()) - self.assertTrue(CANCELLED_FUTURE.done()) - self.assertTrue(CANCELLED_AND_NOTIFIED_FUTURE.done()) - self.assertTrue(EXCEPTION_FUTURE.done()) - self.assertTrue(SUCCESSFUL_FUTURE.done()) - - def test_running(self): - self.assertFalse(PENDING_FUTURE.running()) - self.assertTrue(RUNNING_FUTURE.running()) - self.assertFalse(CANCELLED_FUTURE.running()) - self.assertFalse(CANCELLED_AND_NOTIFIED_FUTURE.running()) - self.assertFalse(EXCEPTION_FUTURE.running()) - self.assertFalse(SUCCESSFUL_FUTURE.running()) - - def test_result_with_timeout(self): - self.assertRaises(futures.TimeoutError, - PENDING_FUTURE.result, timeout=0) - self.assertRaises(futures.TimeoutError, - RUNNING_FUTURE.result, timeout=0) - self.assertRaises(futures.CancelledError, - CANCELLED_FUTURE.result, timeout=0) - self.assertRaises(futures.CancelledError, - CANCELLED_AND_NOTIFIED_FUTURE.result, timeout=0) - self.assertRaises(OSError, EXCEPTION_FUTURE.result, timeout=0) - self.assertEqual(SUCCESSFUL_FUTURE.result(timeout=0), 42) - - def test_result_with_success(self): - # TODO(brian@sweetapp.com): This test is timing dependent. - def notification(): - # Wait until the main thread is waiting for the result. - time.sleep(1) - f1.set_result(42) - - f1 = create_future(state=PENDING) - t = threading.Thread(target=notification) - t.start() - - self.assertEqual(f1.result(timeout=5), 42) - t.join() - - def test_result_with_cancel(self): - # TODO(brian@sweetapp.com): This test is timing dependent. - def notification(): - # Wait until the main thread is waiting for the result. - time.sleep(1) - f1.cancel() - - f1 = create_future(state=PENDING) - t = threading.Thread(target=notification) - t.start() - - self.assertRaises(futures.CancelledError, - f1.result, timeout=support.SHORT_TIMEOUT) - t.join() - - def test_exception_with_timeout(self): - self.assertRaises(futures.TimeoutError, - PENDING_FUTURE.exception, timeout=0) - self.assertRaises(futures.TimeoutError, - RUNNING_FUTURE.exception, timeout=0) - self.assertRaises(futures.CancelledError, - CANCELLED_FUTURE.exception, timeout=0) - self.assertRaises(futures.CancelledError, - CANCELLED_AND_NOTIFIED_FUTURE.exception, timeout=0) - self.assertTrue(isinstance(EXCEPTION_FUTURE.exception(timeout=0), - OSError)) - self.assertEqual(SUCCESSFUL_FUTURE.exception(timeout=0), None) - - def test_exception_with_success(self): - def notification(): - # Wait until the main thread is waiting for the exception. - time.sleep(1) - with f1._condition: - f1._state = FINISHED - f1._exception = OSError() - f1._condition.notify_all() - - f1 = create_future(state=PENDING) - t = threading.Thread(target=notification) - t.start() - - self.assertTrue(isinstance(f1.exception(timeout=support.SHORT_TIMEOUT), OSError)) - t.join() - - def test_multiple_set_result(self): - f = create_future(state=PENDING) - f.set_result(1) - - with self.assertRaisesRegex( - futures.InvalidStateError, - 'FINISHED: ' - ): - f.set_result(2) - - self.assertTrue(f.done()) - self.assertEqual(f.result(), 1) - - def test_multiple_set_exception(self): - f = create_future(state=PENDING) - e = ValueError() - f.set_exception(e) - - with self.assertRaisesRegex( - futures.InvalidStateError, - 'FINISHED: ' - ): - f.set_exception(Exception()) - - self.assertEqual(f.exception(), e) - - -def setUpModule(): - unittest.addModuleCleanup(multiprocessing.util._cleanup_tests) - thread_info = threading_helper.threading_setup() - unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_concurrent_futures/__init__.py b/Lib/test/test_concurrent_futures/__init__.py new file mode 100644 index 00000000000000..430fa93aa456a2 --- /dev/null +++ b/Lib/test/test_concurrent_futures/__init__.py @@ -0,0 +1,16 @@ +import os.path +import unittest +from test import support +from test.support import import_helper + +# Skip tests if _multiprocessing wasn't built. +import_helper.import_module('_multiprocessing') + +if support.check_sanitizer(address=True, memory=True): + # gh-90791: Skip the test because it is too slow when Python is built + # with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions. + raise unittest.SkipTest("test too slow on ASAN/MSAN build") + + +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_concurrent_futures/executor.py b/Lib/test/test_concurrent_futures/executor.py new file mode 100644 index 00000000000000..36278bdd501971 --- /dev/null +++ b/Lib/test/test_concurrent_futures/executor.py @@ -0,0 +1,107 @@ +import threading +import time +import weakref +from concurrent import futures +from test import support + + +def mul(x, y): + return x * y + +def capture(*args, **kwargs): + return args, kwargs + + +class MyObject(object): + def my_method(self): + pass + + +def make_dummy_object(_): + return MyObject() + + +class ExecutorTest: + # Executor.shutdown() and context manager usage is tested by + # ExecutorShutdownTest. + def test_submit(self): + future = self.executor.submit(pow, 2, 8) + self.assertEqual(256, future.result()) + + def test_submit_keyword(self): + future = self.executor.submit(mul, 2, y=8) + self.assertEqual(16, future.result()) + future = self.executor.submit(capture, 1, self=2, fn=3) + self.assertEqual(future.result(), ((1,), {'self': 2, 'fn': 3})) + with self.assertRaises(TypeError): + self.executor.submit(fn=capture, arg=1) + with self.assertRaises(TypeError): + self.executor.submit(arg=1) + + def test_map(self): + self.assertEqual( + list(self.executor.map(pow, range(10), range(10))), + list(map(pow, range(10), range(10)))) + + self.assertEqual( + list(self.executor.map(pow, range(10), range(10), chunksize=3)), + list(map(pow, range(10), range(10)))) + + def test_map_exception(self): + i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5]) + self.assertEqual(i.__next__(), (0, 1)) + self.assertEqual(i.__next__(), (0, 1)) + self.assertRaises(ZeroDivisionError, i.__next__) + + def test_map_timeout(self): + results = [] + try: + for i in self.executor.map(time.sleep, + [0, 0, 6], + timeout=5): + results.append(i) + except futures.TimeoutError: + pass + else: + self.fail('expected TimeoutError') + + self.assertEqual([None, None], results) + + def test_shutdown_race_issue12456(self): + # Issue #12456: race condition at shutdown where trying to post a + # sentinel in the call queue blocks (the queue is full while processes + # have exited). + self.executor.map(str, [2] * (self.worker_count + 1)) + self.executor.shutdown() + + @support.cpython_only + def test_no_stale_references(self): + # Issue #16284: check that the executors don't unnecessarily hang onto + # references. + my_object = MyObject() + my_object_collected = threading.Event() + my_object_callback = weakref.ref( + my_object, lambda obj: my_object_collected.set()) + # Deliberately discarding the future. + self.executor.submit(my_object.my_method) + del my_object + + collected = my_object_collected.wait(timeout=support.SHORT_TIMEOUT) + self.assertTrue(collected, + "Stale reference not collected within timeout.") + + def test_max_workers_negative(self): + for number in (0, -1): + with self.assertRaisesRegex(ValueError, + "max_workers must be greater " + "than 0"): + self.executor_type(max_workers=number) + + def test_free_reference(self): + # Issue #14406: Result iterator should not keep an internal + # reference to result objects. + for obj in self.executor.map(make_dummy_object, range(10)): + wr = weakref.ref(obj) + del obj + support.gc_collect() # For PyPy or other GCs. + self.assertIsNone(wr()) diff --git a/Lib/test/test_concurrent_futures/test_as_completed.py b/Lib/test/test_concurrent_futures/test_as_completed.py new file mode 100644 index 00000000000000..2b3bec8cafbcb0 --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_as_completed.py @@ -0,0 +1,115 @@ +import itertools +import time +import unittest +import weakref +from concurrent import futures +from concurrent.futures._base import ( + CANCELLED_AND_NOTIFIED, FINISHED, Future) + +from test import support + +from .util import ( + PENDING_FUTURE, RUNNING_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, SUCCESSFUL_FUTURE, + create_future, create_executor_tests, setup_module) + + +def mul(x, y): + return x * y + + +class AsCompletedTests: + def test_no_timeout(self): + future1 = self.executor.submit(mul, 2, 21) + future2 = self.executor.submit(mul, 7, 6) + + completed = set(futures.as_completed( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2])) + self.assertEqual(set( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2]), + completed) + + def test_future_times_out(self): + """Test ``futures.as_completed`` timing out before + completing it's final future.""" + already_completed = {CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE} + + for timeout in (0, 0.01): + with self.subTest(timeout): + + future = self.executor.submit(time.sleep, 0.1) + completed_futures = set() + try: + for f in futures.as_completed( + already_completed | {future}, + timeout + ): + completed_futures.add(f) + except futures.TimeoutError: + pass + + # Check that ``future`` wasn't completed. + self.assertEqual(completed_futures, already_completed) + + def test_duplicate_futures(self): + # Issue 20367. Duplicate futures should not raise exceptions or give + # duplicate responses. + # Issue #31641: accept arbitrary iterables. + future1 = self.executor.submit(time.sleep, 2) + completed = [ + f for f in futures.as_completed(itertools.repeat(future1, 3)) + ] + self.assertEqual(len(completed), 1) + + def test_free_reference_yielded_future(self): + # Issue #14406: Generator should not keep references + # to finished futures. + futures_list = [Future() for _ in range(8)] + futures_list.append(create_future(state=CANCELLED_AND_NOTIFIED)) + futures_list.append(create_future(state=FINISHED, result=42)) + + with self.assertRaises(futures.TimeoutError): + for future in futures.as_completed(futures_list, timeout=0): + futures_list.remove(future) + wr = weakref.ref(future) + del future + support.gc_collect() # For PyPy or other GCs. + self.assertIsNone(wr()) + + futures_list[0].set_result("test") + for future in futures.as_completed(futures_list): + futures_list.remove(future) + wr = weakref.ref(future) + del future + support.gc_collect() # For PyPy or other GCs. + self.assertIsNone(wr()) + if futures_list: + futures_list[0].set_result("test") + + def test_correct_timeout_exception_msg(self): + futures_list = [CANCELLED_AND_NOTIFIED_FUTURE, PENDING_FUTURE, + RUNNING_FUTURE, SUCCESSFUL_FUTURE] + + with self.assertRaises(futures.TimeoutError) as cm: + list(futures.as_completed(futures_list, timeout=0)) + + self.assertEqual(str(cm.exception), '2 (of 4) futures unfinished') + + +create_executor_tests(globals(), AsCompletedTests) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/test_deadlock.py b/Lib/test/test_concurrent_futures/test_deadlock.py new file mode 100644 index 00000000000000..6b78b360d15627 --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_deadlock.py @@ -0,0 +1,253 @@ +import contextlib +import sys +import time +import unittest +from pickle import PicklingError +from concurrent import futures +from concurrent.futures.process import BrokenProcessPool + +from test import support + +from .util import ( + create_executor_tests, setup_module, + ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin) + + +def _crash(delay=None): + """Induces a segfault.""" + if delay: + time.sleep(delay) + import faulthandler + faulthandler.disable() + faulthandler._sigsegv() + + +def _crash_with_data(data): + """Induces a segfault with dummy data in input.""" + _crash() + + +def _exit(): + """Induces a sys exit with exitcode 1.""" + sys.exit(1) + + +def _raise_error(Err): + """Function that raises an Exception in process.""" + raise Err() + + +def _raise_error_ignore_stderr(Err): + """Function that raises an Exception in process and ignores stderr.""" + import io + sys.stderr = io.StringIO() + raise Err() + + +def _return_instance(cls): + """Function that returns a instance of cls.""" + return cls() + + +class CrashAtPickle(object): + """Bad object that triggers a segfault at pickling time.""" + def __reduce__(self): + _crash() + + +class CrashAtUnpickle(object): + """Bad object that triggers a segfault at unpickling time.""" + def __reduce__(self): + return _crash, () + + +class ExitAtPickle(object): + """Bad object that triggers a process exit at pickling time.""" + def __reduce__(self): + _exit() + + +class ExitAtUnpickle(object): + """Bad object that triggers a process exit at unpickling time.""" + def __reduce__(self): + return _exit, () + + +class ErrorAtPickle(object): + """Bad object that triggers an error at pickling time.""" + def __reduce__(self): + from pickle import PicklingError + raise PicklingError("Error in pickle") + + +class ErrorAtUnpickle(object): + """Bad object that triggers an error at unpickling time.""" + def __reduce__(self): + from pickle import UnpicklingError + return _raise_error_ignore_stderr, (UnpicklingError, ) + + +class ExecutorDeadlockTest: + TIMEOUT = support.SHORT_TIMEOUT + + def _fail_on_deadlock(self, executor): + # If we did not recover before TIMEOUT seconds, consider that the + # executor is in a deadlock state and forcefully clean all its + # composants. + import faulthandler + from tempfile import TemporaryFile + with TemporaryFile(mode="w+") as f: + faulthandler.dump_traceback(file=f) + f.seek(0) + tb = f.read() + for p in executor._processes.values(): + p.terminate() + # This should be safe to call executor.shutdown here as all possible + # deadlocks should have been broken. + executor.shutdown(wait=True) + print(f"\nTraceback:\n {tb}", file=sys.__stderr__) + self.fail(f"Executor deadlock:\n\n{tb}") + + + def _check_crash(self, error, func, *args, ignore_stderr=False): + # test for deadlock caused by crashes in a pool + self.executor.shutdown(wait=True) + + executor = self.executor_type( + max_workers=2, mp_context=self.get_context()) + res = executor.submit(func, *args) + + if ignore_stderr: + cm = support.captured_stderr() + else: + cm = contextlib.nullcontext() + + try: + with self.assertRaises(error): + with cm: + res.result(timeout=self.TIMEOUT) + except futures.TimeoutError: + # If we did not recover before TIMEOUT seconds, + # consider that the executor is in a deadlock state + self._fail_on_deadlock(executor) + executor.shutdown(wait=True) + + def test_error_at_task_pickle(self): + # Check problem occurring while pickling a task in + # the task_handler thread + self._check_crash(PicklingError, id, ErrorAtPickle()) + + def test_exit_at_task_unpickle(self): + # Check problem occurring while unpickling a task on workers + self._check_crash(BrokenProcessPool, id, ExitAtUnpickle()) + + def test_error_at_task_unpickle(self): + # Check problem occurring while unpickling a task on workers + self._check_crash(BrokenProcessPool, id, ErrorAtUnpickle()) + + def test_crash_at_task_unpickle(self): + # Check problem occurring while unpickling a task on workers + self._check_crash(BrokenProcessPool, id, CrashAtUnpickle()) + + def test_crash_during_func_exec_on_worker(self): + # Check problem occurring during func execution on workers + self._check_crash(BrokenProcessPool, _crash) + + def test_exit_during_func_exec_on_worker(self): + # Check problem occurring during func execution on workers + self._check_crash(SystemExit, _exit) + + def test_error_during_func_exec_on_worker(self): + # Check problem occurring during func execution on workers + self._check_crash(RuntimeError, _raise_error, RuntimeError) + + def test_crash_during_result_pickle_on_worker(self): + # Check problem occurring while pickling a task result + # on workers + self._check_crash(BrokenProcessPool, _return_instance, CrashAtPickle) + + def test_exit_during_result_pickle_on_worker(self): + # Check problem occurring while pickling a task result + # on workers + self._check_crash(SystemExit, _return_instance, ExitAtPickle) + + def test_error_during_result_pickle_on_worker(self): + # Check problem occurring while pickling a task result + # on workers + self._check_crash(PicklingError, _return_instance, ErrorAtPickle) + + def test_error_during_result_unpickle_in_result_handler(self): + # Check problem occurring while unpickling a task in + # the result_handler thread + self._check_crash(BrokenProcessPool, + _return_instance, ErrorAtUnpickle, + ignore_stderr=True) + + def test_exit_during_result_unpickle_in_result_handler(self): + # Check problem occurring while unpickling a task in + # the result_handler thread + self._check_crash(BrokenProcessPool, _return_instance, ExitAtUnpickle) + + def test_shutdown_deadlock(self): + # Test that the pool calling shutdown do not cause deadlock + # if a worker fails after the shutdown call. + self.executor.shutdown(wait=True) + with self.executor_type(max_workers=2, + mp_context=self.get_context()) as executor: + self.executor = executor # Allow clean up in fail_on_deadlock + f = executor.submit(_crash, delay=.1) + executor.shutdown(wait=True) + with self.assertRaises(BrokenProcessPool): + f.result() + + def test_shutdown_deadlock_pickle(self): + # Test that the pool calling shutdown with wait=False does not cause + # a deadlock if a task fails at pickle after the shutdown call. + # Reported in bpo-39104. + self.executor.shutdown(wait=True) + with self.executor_type(max_workers=2, + mp_context=self.get_context()) as executor: + self.executor = executor # Allow clean up in fail_on_deadlock + + # Start the executor and get the executor_manager_thread to collect + # the threads and avoid dangling thread that should be cleaned up + # asynchronously. + executor.submit(id, 42).result() + executor_manager = executor._executor_manager_thread + + # Submit a task that fails at pickle and shutdown the executor + # without waiting + f = executor.submit(id, ErrorAtPickle()) + executor.shutdown(wait=False) + with self.assertRaises(PicklingError): + f.result() + + # Make sure the executor is eventually shutdown and do not leave + # dangling threads + executor_manager.join() + + def test_crash_big_data(self): + # Test that there is a clean exception instad of a deadlock when a + # child process crashes while some data is being written into the + # queue. + # https://github.com/python/cpython/issues/94777 + self.executor.shutdown(wait=True) + data = "a" * support.PIPE_MAX_SIZE + with self.executor_type(max_workers=2, + mp_context=self.get_context()) as executor: + self.executor = executor # Allow clean up in fail_on_deadlock + with self.assertRaises(BrokenProcessPool): + list(executor.map(_crash_with_data, [data] * 10)) + + +create_executor_tests(globals(), ExecutorDeadlockTest, + executor_mixins=(ProcessPoolForkMixin, + ProcessPoolForkserverMixin, + ProcessPoolSpawnMixin)) + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/test_future.py b/Lib/test/test_concurrent_futures/test_future.py new file mode 100644 index 00000000000000..4066ea1ee4b367 --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_future.py @@ -0,0 +1,291 @@ +import threading +import time +import unittest +from concurrent import futures +from concurrent.futures._base import ( + PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future) + +from test import support + +from .util import ( + PENDING_FUTURE, RUNNING_FUTURE, CANCELLED_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, SUCCESSFUL_FUTURE, + BaseTestCase, create_future, setup_module) + + +class FutureTests(BaseTestCase): + def test_done_callback_with_result(self): + callback_result = None + def fn(callback_future): + nonlocal callback_result + callback_result = callback_future.result() + + f = Future() + f.add_done_callback(fn) + f.set_result(5) + self.assertEqual(5, callback_result) + + def test_done_callback_with_exception(self): + callback_exception = None + def fn(callback_future): + nonlocal callback_exception + callback_exception = callback_future.exception() + + f = Future() + f.add_done_callback(fn) + f.set_exception(Exception('test')) + self.assertEqual(('test',), callback_exception.args) + + def test_done_callback_with_cancel(self): + was_cancelled = None + def fn(callback_future): + nonlocal was_cancelled + was_cancelled = callback_future.cancelled() + + f = Future() + f.add_done_callback(fn) + self.assertTrue(f.cancel()) + self.assertTrue(was_cancelled) + + def test_done_callback_raises(self): + with support.captured_stderr() as stderr: + raising_was_called = False + fn_was_called = False + + def raising_fn(callback_future): + nonlocal raising_was_called + raising_was_called = True + raise Exception('doh!') + + def fn(callback_future): + nonlocal fn_was_called + fn_was_called = True + + f = Future() + f.add_done_callback(raising_fn) + f.add_done_callback(fn) + f.set_result(5) + self.assertTrue(raising_was_called) + self.assertTrue(fn_was_called) + self.assertIn('Exception: doh!', stderr.getvalue()) + + def test_done_callback_already_successful(self): + callback_result = None + def fn(callback_future): + nonlocal callback_result + callback_result = callback_future.result() + + f = Future() + f.set_result(5) + f.add_done_callback(fn) + self.assertEqual(5, callback_result) + + def test_done_callback_already_failed(self): + callback_exception = None + def fn(callback_future): + nonlocal callback_exception + callback_exception = callback_future.exception() + + f = Future() + f.set_exception(Exception('test')) + f.add_done_callback(fn) + self.assertEqual(('test',), callback_exception.args) + + def test_done_callback_already_cancelled(self): + was_cancelled = None + def fn(callback_future): + nonlocal was_cancelled + was_cancelled = callback_future.cancelled() + + f = Future() + self.assertTrue(f.cancel()) + f.add_done_callback(fn) + self.assertTrue(was_cancelled) + + def test_done_callback_raises_already_succeeded(self): + with support.captured_stderr() as stderr: + def raising_fn(callback_future): + raise Exception('doh!') + + f = Future() + + # Set the result first to simulate a future that runs instantly, + # effectively allowing the callback to be run immediately. + f.set_result(5) + f.add_done_callback(raising_fn) + + self.assertIn('exception calling callback for', stderr.getvalue()) + self.assertIn('doh!', stderr.getvalue()) + + + def test_repr(self): + self.assertRegex(repr(PENDING_FUTURE), + '') + self.assertRegex(repr(RUNNING_FUTURE), + '') + self.assertRegex(repr(CANCELLED_FUTURE), + '') + self.assertRegex(repr(CANCELLED_AND_NOTIFIED_FUTURE), + '') + self.assertRegex( + repr(EXCEPTION_FUTURE), + '') + self.assertRegex( + repr(SUCCESSFUL_FUTURE), + '') + + def test_cancel(self): + f1 = create_future(state=PENDING) + f2 = create_future(state=RUNNING) + f3 = create_future(state=CANCELLED) + f4 = create_future(state=CANCELLED_AND_NOTIFIED) + f5 = create_future(state=FINISHED, exception=OSError()) + f6 = create_future(state=FINISHED, result=5) + + self.assertTrue(f1.cancel()) + self.assertEqual(f1._state, CANCELLED) + + self.assertFalse(f2.cancel()) + self.assertEqual(f2._state, RUNNING) + + self.assertTrue(f3.cancel()) + self.assertEqual(f3._state, CANCELLED) + + self.assertTrue(f4.cancel()) + self.assertEqual(f4._state, CANCELLED_AND_NOTIFIED) + + self.assertFalse(f5.cancel()) + self.assertEqual(f5._state, FINISHED) + + self.assertFalse(f6.cancel()) + self.assertEqual(f6._state, FINISHED) + + def test_cancelled(self): + self.assertFalse(PENDING_FUTURE.cancelled()) + self.assertFalse(RUNNING_FUTURE.cancelled()) + self.assertTrue(CANCELLED_FUTURE.cancelled()) + self.assertTrue(CANCELLED_AND_NOTIFIED_FUTURE.cancelled()) + self.assertFalse(EXCEPTION_FUTURE.cancelled()) + self.assertFalse(SUCCESSFUL_FUTURE.cancelled()) + + def test_done(self): + self.assertFalse(PENDING_FUTURE.done()) + self.assertFalse(RUNNING_FUTURE.done()) + self.assertTrue(CANCELLED_FUTURE.done()) + self.assertTrue(CANCELLED_AND_NOTIFIED_FUTURE.done()) + self.assertTrue(EXCEPTION_FUTURE.done()) + self.assertTrue(SUCCESSFUL_FUTURE.done()) + + def test_running(self): + self.assertFalse(PENDING_FUTURE.running()) + self.assertTrue(RUNNING_FUTURE.running()) + self.assertFalse(CANCELLED_FUTURE.running()) + self.assertFalse(CANCELLED_AND_NOTIFIED_FUTURE.running()) + self.assertFalse(EXCEPTION_FUTURE.running()) + self.assertFalse(SUCCESSFUL_FUTURE.running()) + + def test_result_with_timeout(self): + self.assertRaises(futures.TimeoutError, + PENDING_FUTURE.result, timeout=0) + self.assertRaises(futures.TimeoutError, + RUNNING_FUTURE.result, timeout=0) + self.assertRaises(futures.CancelledError, + CANCELLED_FUTURE.result, timeout=0) + self.assertRaises(futures.CancelledError, + CANCELLED_AND_NOTIFIED_FUTURE.result, timeout=0) + self.assertRaises(OSError, EXCEPTION_FUTURE.result, timeout=0) + self.assertEqual(SUCCESSFUL_FUTURE.result(timeout=0), 42) + + def test_result_with_success(self): + # TODO(brian@sweetapp.com): This test is timing dependent. + def notification(): + # Wait until the main thread is waiting for the result. + time.sleep(1) + f1.set_result(42) + + f1 = create_future(state=PENDING) + t = threading.Thread(target=notification) + t.start() + + self.assertEqual(f1.result(timeout=5), 42) + t.join() + + def test_result_with_cancel(self): + # TODO(brian@sweetapp.com): This test is timing dependent. + def notification(): + # Wait until the main thread is waiting for the result. + time.sleep(1) + f1.cancel() + + f1 = create_future(state=PENDING) + t = threading.Thread(target=notification) + t.start() + + self.assertRaises(futures.CancelledError, + f1.result, timeout=support.SHORT_TIMEOUT) + t.join() + + def test_exception_with_timeout(self): + self.assertRaises(futures.TimeoutError, + PENDING_FUTURE.exception, timeout=0) + self.assertRaises(futures.TimeoutError, + RUNNING_FUTURE.exception, timeout=0) + self.assertRaises(futures.CancelledError, + CANCELLED_FUTURE.exception, timeout=0) + self.assertRaises(futures.CancelledError, + CANCELLED_AND_NOTIFIED_FUTURE.exception, timeout=0) + self.assertTrue(isinstance(EXCEPTION_FUTURE.exception(timeout=0), + OSError)) + self.assertEqual(SUCCESSFUL_FUTURE.exception(timeout=0), None) + + def test_exception_with_success(self): + def notification(): + # Wait until the main thread is waiting for the exception. + time.sleep(1) + with f1._condition: + f1._state = FINISHED + f1._exception = OSError() + f1._condition.notify_all() + + f1 = create_future(state=PENDING) + t = threading.Thread(target=notification) + t.start() + + self.assertTrue(isinstance(f1.exception(timeout=support.SHORT_TIMEOUT), OSError)) + t.join() + + def test_multiple_set_result(self): + f = create_future(state=PENDING) + f.set_result(1) + + with self.assertRaisesRegex( + futures.InvalidStateError, + 'FINISHED: ' + ): + f.set_result(2) + + self.assertTrue(f.done()) + self.assertEqual(f.result(), 1) + + def test_multiple_set_exception(self): + f = create_future(state=PENDING) + e = ValueError() + f.set_exception(e) + + with self.assertRaisesRegex( + futures.InvalidStateError, + 'FINISHED: ' + ): + f.set_exception(Exception()) + + self.assertEqual(f.exception(), e) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/test_init.py b/Lib/test/test_concurrent_futures/test_init.py new file mode 100644 index 00000000000000..ce01e0ff0f287a --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_init.py @@ -0,0 +1,117 @@ +import contextlib +import logging +import queue +import time +import unittest +from concurrent.futures._base import BrokenExecutor +from logging.handlers import QueueHandler + +from test import support + +from .util import ExecutorMixin, create_executor_tests, setup_module + + +INITIALIZER_STATUS = 'uninitialized' + +def init(x): + global INITIALIZER_STATUS + INITIALIZER_STATUS = x + +def get_init_status(): + return INITIALIZER_STATUS + +def init_fail(log_queue=None): + if log_queue is not None: + logger = logging.getLogger('concurrent.futures') + logger.addHandler(QueueHandler(log_queue)) + logger.setLevel('CRITICAL') + logger.propagate = False + time.sleep(0.1) # let some futures be scheduled + raise ValueError('error in initializer') + + +class InitializerMixin(ExecutorMixin): + worker_count = 2 + + def setUp(self): + global INITIALIZER_STATUS + INITIALIZER_STATUS = 'uninitialized' + self.executor_kwargs = dict(initializer=init, + initargs=('initialized',)) + super().setUp() + + def test_initializer(self): + futures = [self.executor.submit(get_init_status) + for _ in range(self.worker_count)] + + for f in futures: + self.assertEqual(f.result(), 'initialized') + + +class FailingInitializerMixin(ExecutorMixin): + worker_count = 2 + + def setUp(self): + if hasattr(self, "ctx"): + # Pass a queue to redirect the child's logging output + self.mp_context = self.get_context() + self.log_queue = self.mp_context.Queue() + self.executor_kwargs = dict(initializer=init_fail, + initargs=(self.log_queue,)) + else: + # In a thread pool, the child shares our logging setup + # (see _assert_logged()) + self.mp_context = None + self.log_queue = None + self.executor_kwargs = dict(initializer=init_fail) + super().setUp() + + def test_initializer(self): + with self._assert_logged('ValueError: error in initializer'): + try: + future = self.executor.submit(get_init_status) + except BrokenExecutor: + # Perhaps the executor is already broken + pass + else: + with self.assertRaises(BrokenExecutor): + future.result() + + # At some point, the executor should break + for _ in support.sleeping_retry(support.SHORT_TIMEOUT, + "executor not broken"): + if self.executor._broken: + break + + # ... and from this point submit() is guaranteed to fail + with self.assertRaises(BrokenExecutor): + self.executor.submit(get_init_status) + + @contextlib.contextmanager + def _assert_logged(self, msg): + if self.log_queue is not None: + yield + output = [] + try: + while True: + output.append(self.log_queue.get_nowait().getMessage()) + except queue.Empty: + pass + else: + with self.assertLogs('concurrent.futures', 'CRITICAL') as cm: + yield + output = cm.output + self.assertTrue(any(msg in line for line in output), + output) + + +create_executor_tests(globals(), InitializerMixin) +create_executor_tests(globals(), FailingInitializerMixin) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py new file mode 100644 index 00000000000000..7763a4946f110c --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -0,0 +1,202 @@ +import os +import sys +import time +import unittest +from concurrent import futures +from concurrent.futures.process import BrokenProcessPool + +from test import support +from test.support import hashlib_helper + +from .executor import ExecutorTest, mul +from .util import ( + ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin, + create_executor_tests, setup_module) + + +class EventfulGCObj(): + def __init__(self, mgr): + self.event = mgr.Event() + + def __del__(self): + self.event.set() + + +class ProcessPoolExecutorTest(ExecutorTest): + + @unittest.skipUnless(sys.platform=='win32', 'Windows-only process limit') + def test_max_workers_too_large(self): + with self.assertRaisesRegex(ValueError, + "max_workers must be <= 61"): + futures.ProcessPoolExecutor(max_workers=62) + + def test_killed_child(self): + # When a child process is abruptly terminated, the whole pool gets + # "broken". + futures = [self.executor.submit(time.sleep, 3)] + # Get one of the processes, and terminate (kill) it + p = next(iter(self.executor._processes.values())) + p.terminate() + for fut in futures: + self.assertRaises(BrokenProcessPool, fut.result) + # Submitting other jobs fails as well. + self.assertRaises(BrokenProcessPool, self.executor.submit, pow, 2, 8) + + def test_map_chunksize(self): + def bad_map(): + list(self.executor.map(pow, range(40), range(40), chunksize=-1)) + + ref = list(map(pow, range(40), range(40))) + self.assertEqual( + list(self.executor.map(pow, range(40), range(40), chunksize=6)), + ref) + self.assertEqual( + list(self.executor.map(pow, range(40), range(40), chunksize=50)), + ref) + self.assertEqual( + list(self.executor.map(pow, range(40), range(40), chunksize=40)), + ref) + self.assertRaises(ValueError, bad_map) + + @classmethod + def _test_traceback(cls): + raise RuntimeError(123) # some comment + + def test_traceback(self): + # We want ensure that the traceback from the child process is + # contained in the traceback raised in the main process. + future = self.executor.submit(self._test_traceback) + with self.assertRaises(Exception) as cm: + future.result() + + exc = cm.exception + self.assertIs(type(exc), RuntimeError) + self.assertEqual(exc.args, (123,)) + cause = exc.__cause__ + self.assertIs(type(cause), futures.process._RemoteTraceback) + self.assertIn('raise RuntimeError(123) # some comment', cause.tb) + + with support.captured_stderr() as f1: + try: + raise exc + except RuntimeError: + sys.excepthook(*sys.exc_info()) + self.assertIn('raise RuntimeError(123) # some comment', + f1.getvalue()) + + @hashlib_helper.requires_hashdigest('md5') + def test_ressources_gced_in_workers(self): + # Ensure that argument for a job are correctly gc-ed after the job + # is finished + mgr = self.get_context().Manager() + obj = EventfulGCObj(mgr) + future = self.executor.submit(id, obj) + future.result() + + self.assertTrue(obj.event.wait(timeout=1)) + + # explicitly destroy the object to ensure that EventfulGCObj.__del__() + # is called while manager is still running. + obj = None + support.gc_collect() + + mgr.shutdown() + mgr.join() + + def test_saturation(self): + executor = self.executor + mp_context = self.get_context() + sem = mp_context.Semaphore(0) + job_count = 15 * executor._max_workers + for _ in range(job_count): + executor.submit(sem.acquire) + self.assertEqual(len(executor._processes), executor._max_workers) + for _ in range(job_count): + sem.release() + + def test_idle_process_reuse_one(self): + executor = self.executor + assert executor._max_workers >= 4 + if self.get_context().get_start_method(allow_none=False) == "fork": + raise unittest.SkipTest("Incompatible with the fork start method.") + executor.submit(mul, 21, 2).result() + executor.submit(mul, 6, 7).result() + executor.submit(mul, 3, 14).result() + self.assertEqual(len(executor._processes), 1) + + def test_idle_process_reuse_multiple(self): + executor = self.executor + assert executor._max_workers <= 5 + if self.get_context().get_start_method(allow_none=False) == "fork": + raise unittest.SkipTest("Incompatible with the fork start method.") + executor.submit(mul, 12, 7).result() + executor.submit(mul, 33, 25) + executor.submit(mul, 25, 26).result() + executor.submit(mul, 18, 29) + executor.submit(mul, 1, 2).result() + executor.submit(mul, 0, 9) + self.assertLessEqual(len(executor._processes), 3) + executor.shutdown() + + def test_max_tasks_per_child(self): + context = self.get_context() + if context.get_start_method(allow_none=False) == "fork": + with self.assertRaises(ValueError): + self.executor_type(1, mp_context=context, max_tasks_per_child=3) + return + # not using self.executor as we need to control construction. + # arguably this could go in another class w/o that mixin. + executor = self.executor_type( + 1, mp_context=context, max_tasks_per_child=3) + f1 = executor.submit(os.getpid) + original_pid = f1.result() + # The worker pid remains the same as the worker could be reused + f2 = executor.submit(os.getpid) + self.assertEqual(f2.result(), original_pid) + self.assertEqual(len(executor._processes), 1) + f3 = executor.submit(os.getpid) + self.assertEqual(f3.result(), original_pid) + + # A new worker is spawned, with a statistically different pid, + # while the previous was reaped. + f4 = executor.submit(os.getpid) + new_pid = f4.result() + self.assertNotEqual(original_pid, new_pid) + self.assertEqual(len(executor._processes), 1) + + executor.shutdown() + + def test_max_tasks_per_child_defaults_to_spawn_context(self): + # not using self.executor as we need to control construction. + # arguably this could go in another class w/o that mixin. + executor = self.executor_type(1, max_tasks_per_child=3) + self.assertEqual(executor._mp_context.get_start_method(), "spawn") + + def test_max_tasks_early_shutdown(self): + context = self.get_context() + if context.get_start_method(allow_none=False) == "fork": + raise unittest.SkipTest("Incompatible with the fork start method.") + # not using self.executor as we need to control construction. + # arguably this could go in another class w/o that mixin. + executor = self.executor_type( + 3, mp_context=context, max_tasks_per_child=1) + futures = [] + for i in range(6): + futures.append(executor.submit(mul, i, i)) + executor.shutdown() + for i, future in enumerate(futures): + self.assertEqual(future.result(), mul(i, i)) + + +create_executor_tests(globals(), ProcessPoolExecutorTest, + executor_mixins=(ProcessPoolForkMixin, + ProcessPoolForkserverMixin, + ProcessPoolSpawnMixin)) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/test_shutdown.py b/Lib/test/test_concurrent_futures/test_shutdown.py new file mode 100644 index 00000000000000..45dab7a75fdd50 --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_shutdown.py @@ -0,0 +1,343 @@ +import signal +import sys +import threading +import time +import unittest +from concurrent import futures + +from test import support +from test.support.script_helper import assert_python_ok + +from .util import ( + BaseTestCase, ThreadPoolMixin, ProcessPoolForkMixin, + ProcessPoolForkserverMixin, ProcessPoolSpawnMixin, + create_executor_tests, setup_module) + + +def sleep_and_print(t, msg): + time.sleep(t) + print(msg) + sys.stdout.flush() + + +class ExecutorShutdownTest: + def test_run_after_shutdown(self): + self.executor.shutdown() + self.assertRaises(RuntimeError, + self.executor.submit, + pow, 2, 5) + + def test_interpreter_shutdown(self): + # Test the atexit hook for shutdown of worker threads and processes + rc, out, err = assert_python_ok('-c', """if 1: + from concurrent.futures import {executor_type} + from time import sleep + from test.test_concurrent_futures.test_shutdown import sleep_and_print + if __name__ == "__main__": + context = '{context}' + if context == "": + t = {executor_type}(5) + else: + from multiprocessing import get_context + context = get_context(context) + t = {executor_type}(5, mp_context=context) + t.submit(sleep_and_print, 1.0, "apple") + """.format(executor_type=self.executor_type.__name__, + context=getattr(self, "ctx", ""))) + # Errors in atexit hooks don't change the process exit code, check + # stderr manually. + self.assertFalse(err) + self.assertEqual(out.strip(), b"apple") + + def test_submit_after_interpreter_shutdown(self): + # Test the atexit hook for shutdown of worker threads and processes + rc, out, err = assert_python_ok('-c', """if 1: + import atexit + @atexit.register + def run_last(): + try: + t.submit(id, None) + except RuntimeError: + print("runtime-error") + raise + from concurrent.futures import {executor_type} + if __name__ == "__main__": + context = '{context}' + if not context: + t = {executor_type}(5) + else: + from multiprocessing import get_context + context = get_context(context) + t = {executor_type}(5, mp_context=context) + t.submit(id, 42).result() + """.format(executor_type=self.executor_type.__name__, + context=getattr(self, "ctx", ""))) + # Errors in atexit hooks don't change the process exit code, check + # stderr manually. + self.assertIn("RuntimeError: cannot schedule new futures", err.decode()) + self.assertEqual(out.strip(), b"runtime-error") + + def test_hang_issue12364(self): + fs = [self.executor.submit(time.sleep, 0.1) for _ in range(50)] + self.executor.shutdown() + for f in fs: + f.result() + + def test_cancel_futures(self): + assert self.worker_count <= 5, "test needs few workers" + fs = [self.executor.submit(time.sleep, .1) for _ in range(50)] + self.executor.shutdown(cancel_futures=True) + # We can't guarantee the exact number of cancellations, but we can + # guarantee that *some* were cancelled. With few workers, many of + # the submitted futures should have been cancelled. + cancelled = [fut for fut in fs if fut.cancelled()] + self.assertGreater(len(cancelled), 20) + + # Ensure the other futures were able to finish. + # Use "not fut.cancelled()" instead of "fut.done()" to include futures + # that may have been left in a pending state. + others = [fut for fut in fs if not fut.cancelled()] + for fut in others: + self.assertTrue(fut.done(), msg=f"{fut._state=}") + self.assertIsNone(fut.exception()) + + # Similar to the number of cancelled futures, we can't guarantee the + # exact number that completed. But, we can guarantee that at least + # one finished. + self.assertGreater(len(others), 0) + + def test_hang_gh83386(self): + """shutdown(wait=False) doesn't hang at exit with running futures. + + See https://github.com/python/cpython/issues/83386. + """ + if self.executor_type == futures.ProcessPoolExecutor: + raise unittest.SkipTest( + "Hangs, see https://github.com/python/cpython/issues/83386") + + rc, out, err = assert_python_ok('-c', """if True: + from concurrent.futures import {executor_type} + from test.test_concurrent_futures.test_shutdown import sleep_and_print + if __name__ == "__main__": + if {context!r}: multiprocessing.set_start_method({context!r}) + t = {executor_type}(max_workers=3) + t.submit(sleep_and_print, 1.0, "apple") + t.shutdown(wait=False) + """.format(executor_type=self.executor_type.__name__, + context=getattr(self, 'ctx', None))) + self.assertFalse(err) + self.assertEqual(out.strip(), b"apple") + + def test_hang_gh94440(self): + """shutdown(wait=True) doesn't hang when a future was submitted and + quickly canceled right before shutdown. + + See https://github.com/python/cpython/issues/94440. + """ + if not hasattr(signal, 'alarm'): + raise unittest.SkipTest( + "Tested platform does not support the alarm signal") + + def timeout(_signum, _frame): + raise RuntimeError("timed out waiting for shutdown") + + kwargs = {} + if getattr(self, 'ctx', None): + kwargs['mp_context'] = self.get_context() + executor = self.executor_type(max_workers=1, **kwargs) + executor.submit(int).result() + old_handler = signal.signal(signal.SIGALRM, timeout) + try: + signal.alarm(5) + executor.submit(int).cancel() + executor.shutdown(wait=True) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, old_handler) + + +class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase): + def test_threads_terminate(self): + def acquire_lock(lock): + lock.acquire() + + sem = threading.Semaphore(0) + for i in range(3): + self.executor.submit(acquire_lock, sem) + self.assertEqual(len(self.executor._threads), 3) + for i in range(3): + sem.release() + self.executor.shutdown() + for t in self.executor._threads: + t.join() + + def test_context_manager_shutdown(self): + with futures.ThreadPoolExecutor(max_workers=5) as e: + executor = e + self.assertEqual(list(e.map(abs, range(-5, 5))), + [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) + + for t in executor._threads: + t.join() + + def test_del_shutdown(self): + executor = futures.ThreadPoolExecutor(max_workers=5) + res = executor.map(abs, range(-5, 5)) + threads = executor._threads + del executor + + for t in threads: + t.join() + + # Make sure the results were all computed before the + # executor got shutdown. + assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) + + def test_shutdown_no_wait(self): + # Ensure that the executor cleans up the threads when calling + # shutdown with wait=False + executor = futures.ThreadPoolExecutor(max_workers=5) + res = executor.map(abs, range(-5, 5)) + threads = executor._threads + executor.shutdown(wait=False) + for t in threads: + t.join() + + # Make sure the results were all computed before the + # executor got shutdown. + assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) + + + def test_thread_names_assigned(self): + executor = futures.ThreadPoolExecutor( + max_workers=5, thread_name_prefix='SpecialPool') + executor.map(abs, range(-5, 5)) + threads = executor._threads + del executor + support.gc_collect() # For PyPy or other GCs. + + for t in threads: + self.assertRegex(t.name, r'^SpecialPool_[0-4]$') + t.join() + + def test_thread_names_default(self): + executor = futures.ThreadPoolExecutor(max_workers=5) + executor.map(abs, range(-5, 5)) + threads = executor._threads + del executor + support.gc_collect() # For PyPy or other GCs. + + for t in threads: + # Ensure that our default name is reasonably sane and unique when + # no thread_name_prefix was supplied. + self.assertRegex(t.name, r'ThreadPoolExecutor-\d+_[0-4]$') + t.join() + + def test_cancel_futures_wait_false(self): + # Can only be reliably tested for TPE, since PPE often hangs with + # `wait=False` (even without *cancel_futures*). + rc, out, err = assert_python_ok('-c', """if True: + from concurrent.futures import ThreadPoolExecutor + from test.test_concurrent_futures.test_shutdown import sleep_and_print + if __name__ == "__main__": + t = ThreadPoolExecutor() + t.submit(sleep_and_print, .1, "apple") + t.shutdown(wait=False, cancel_futures=True) + """) + # Errors in atexit hooks don't change the process exit code, check + # stderr manually. + self.assertFalse(err) + self.assertEqual(out.strip(), b"apple") + + +class ProcessPoolShutdownTest(ExecutorShutdownTest): + def test_processes_terminate(self): + def acquire_lock(lock): + lock.acquire() + + mp_context = self.get_context() + if mp_context.get_start_method(allow_none=False) == "fork": + # fork pre-spawns, not on demand. + expected_num_processes = self.worker_count + else: + expected_num_processes = 3 + + sem = mp_context.Semaphore(0) + for _ in range(3): + self.executor.submit(acquire_lock, sem) + self.assertEqual(len(self.executor._processes), expected_num_processes) + for _ in range(3): + sem.release() + processes = self.executor._processes + self.executor.shutdown() + + for p in processes.values(): + p.join() + + def test_context_manager_shutdown(self): + with futures.ProcessPoolExecutor( + max_workers=5, mp_context=self.get_context()) as e: + processes = e._processes + self.assertEqual(list(e.map(abs, range(-5, 5))), + [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) + + for p in processes.values(): + p.join() + + def test_del_shutdown(self): + executor = futures.ProcessPoolExecutor( + max_workers=5, mp_context=self.get_context()) + res = executor.map(abs, range(-5, 5)) + executor_manager_thread = executor._executor_manager_thread + processes = executor._processes + call_queue = executor._call_queue + executor_manager_thread = executor._executor_manager_thread + del executor + support.gc_collect() # For PyPy or other GCs. + + # Make sure that all the executor resources were properly cleaned by + # the shutdown process + executor_manager_thread.join() + for p in processes.values(): + p.join() + call_queue.join_thread() + + # Make sure the results were all computed before the + # executor got shutdown. + assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) + + def test_shutdown_no_wait(self): + # Ensure that the executor cleans up the processes when calling + # shutdown with wait=False + executor = futures.ProcessPoolExecutor( + max_workers=5, mp_context=self.get_context()) + res = executor.map(abs, range(-5, 5)) + processes = executor._processes + call_queue = executor._call_queue + executor_manager_thread = executor._executor_manager_thread + executor.shutdown(wait=False) + + # Make sure that all the executor resources were properly cleaned by + # the shutdown process + executor_manager_thread.join() + for p in processes.values(): + p.join() + call_queue.join_thread() + + # Make sure the results were all computed before the executor got + # shutdown. + assert all([r == abs(v) for r, v in zip(res, range(-5, 5))]) + + +create_executor_tests(globals(), ProcessPoolShutdownTest, + executor_mixins=(ProcessPoolForkMixin, + ProcessPoolForkserverMixin, + ProcessPoolSpawnMixin)) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/test_thread_pool.py b/Lib/test/test_concurrent_futures/test_thread_pool.py new file mode 100644 index 00000000000000..daef7b5a836825 --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_thread_pool.py @@ -0,0 +1,98 @@ +import contextlib +import multiprocessing as mp +import multiprocessing.process +import multiprocessing.util +import os +import threading +import unittest +from concurrent import futures + +from .executor import ExecutorTest, mul +from .util import BaseTestCase, ThreadPoolMixin, setup_module + + +class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest, BaseTestCase): + def test_map_submits_without_iteration(self): + """Tests verifying issue 11777.""" + finished = [] + def record_finished(n): + finished.append(n) + + self.executor.map(record_finished, range(10)) + self.executor.shutdown(wait=True) + self.assertCountEqual(finished, range(10)) + + def test_default_workers(self): + executor = self.executor_type() + expected = min(32, (os.cpu_count() or 1) + 4) + self.assertEqual(executor._max_workers, expected) + + def test_saturation(self): + executor = self.executor_type(4) + def acquire_lock(lock): + lock.acquire() + + sem = threading.Semaphore(0) + for i in range(15 * executor._max_workers): + executor.submit(acquire_lock, sem) + self.assertEqual(len(executor._threads), executor._max_workers) + for i in range(15 * executor._max_workers): + sem.release() + executor.shutdown(wait=True) + + def test_idle_thread_reuse(self): + executor = self.executor_type() + executor.submit(mul, 21, 2).result() + executor.submit(mul, 6, 7).result() + executor.submit(mul, 3, 14).result() + self.assertEqual(len(executor._threads), 1) + executor.shutdown(wait=True) + + @unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork') + def test_hang_global_shutdown_lock(self): + # bpo-45021: _global_shutdown_lock should be reinitialized in the child + # process, otherwise it will never exit + def submit(pool): + pool.submit(submit, pool) + + with futures.ThreadPoolExecutor(1) as pool: + pool.submit(submit, pool) + + for _ in range(50): + with futures.ProcessPoolExecutor(1, mp_context=mp.get_context('fork')) as workers: + workers.submit(tuple) + + def test_executor_map_current_future_cancel(self): + stop_event = threading.Event() + log = [] + + def log_n_wait(ident): + log.append(f"{ident=} started") + try: + stop_event.wait() + finally: + log.append(f"{ident=} stopped") + + with self.executor_type(max_workers=1) as pool: + # submit work to saturate the pool + fut = pool.submit(log_n_wait, ident="first") + try: + with contextlib.closing( + pool.map(log_n_wait, ["second", "third"], timeout=0) + ) as gen: + with self.assertRaises(TimeoutError): + next(gen) + finally: + stop_event.set() + fut.result() + # ident='second' is cancelled as a result of raising a TimeoutError + # ident='third' is cancelled because it remained in the collection of futures + self.assertListEqual(log, ["ident='first' started", "ident='first' stopped"]) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/test_wait.py b/Lib/test/test_concurrent_futures/test_wait.py new file mode 100644 index 00000000000000..e4bea8b05aced6 --- /dev/null +++ b/Lib/test/test_concurrent_futures/test_wait.py @@ -0,0 +1,161 @@ +import sys +import threading +import time +import unittest +from concurrent import futures + +from .util import ( + CANCELLED_FUTURE, CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + create_executor_tests, setup_module, + BaseTestCase, ThreadPoolMixin, + ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin) + + +def mul(x, y): + return x * y + +def sleep_and_raise(t): + time.sleep(t) + raise Exception('this is an exception') + + +class WaitTests: + def test_20369(self): + # See https://bugs.python.org/issue20369 + future = self.executor.submit(time.sleep, 1.5) + done, not_done = futures.wait([future, future], + return_when=futures.ALL_COMPLETED) + self.assertEqual({future}, done) + self.assertEqual(set(), not_done) + + + def test_first_completed(self): + future1 = self.executor.submit(mul, 21, 2) + future2 = self.executor.submit(time.sleep, 1.5) + + done, not_done = futures.wait( + [CANCELLED_FUTURE, future1, future2], + return_when=futures.FIRST_COMPLETED) + + self.assertEqual(set([future1]), done) + self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) + + def test_first_completed_some_already_completed(self): + future1 = self.executor.submit(time.sleep, 1.5) + + finished, pending = futures.wait( + [CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE, future1], + return_when=futures.FIRST_COMPLETED) + + self.assertEqual( + set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]), + finished) + self.assertEqual(set([future1]), pending) + + def test_first_exception(self): + future1 = self.executor.submit(mul, 2, 21) + future2 = self.executor.submit(sleep_and_raise, 1.5) + future3 = self.executor.submit(time.sleep, 3) + + finished, pending = futures.wait( + [future1, future2, future3], + return_when=futures.FIRST_EXCEPTION) + + self.assertEqual(set([future1, future2]), finished) + self.assertEqual(set([future3]), pending) + + def test_first_exception_some_already_complete(self): + future1 = self.executor.submit(divmod, 21, 0) + future2 = self.executor.submit(time.sleep, 1.5) + + finished, pending = futures.wait( + [SUCCESSFUL_FUTURE, + CANCELLED_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + future1, future2], + return_when=futures.FIRST_EXCEPTION) + + self.assertEqual(set([SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + future1]), finished) + self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) + + def test_first_exception_one_already_failed(self): + future1 = self.executor.submit(time.sleep, 2) + + finished, pending = futures.wait( + [EXCEPTION_FUTURE, future1], + return_when=futures.FIRST_EXCEPTION) + + self.assertEqual(set([EXCEPTION_FUTURE]), finished) + self.assertEqual(set([future1]), pending) + + def test_all_completed(self): + future1 = self.executor.submit(divmod, 2, 0) + future2 = self.executor.submit(mul, 2, 21) + + finished, pending = futures.wait( + [SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + future1, + future2], + return_when=futures.ALL_COMPLETED) + + self.assertEqual(set([SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + future1, + future2]), finished) + self.assertEqual(set(), pending) + + def test_timeout(self): + future1 = self.executor.submit(mul, 6, 7) + future2 = self.executor.submit(time.sleep, 6) + + finished, pending = futures.wait( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2], + timeout=5, + return_when=futures.ALL_COMPLETED) + + self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1]), finished) + self.assertEqual(set([future2]), pending) + + +class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests, BaseTestCase): + + def test_pending_calls_race(self): + # Issue #14406: multi-threaded race condition when waiting on all + # futures. + event = threading.Event() + def future_func(): + event.wait() + oldswitchinterval = sys.getswitchinterval() + sys.setswitchinterval(1e-6) + try: + fs = {self.executor.submit(future_func) for i in range(100)} + event.set() + futures.wait(fs, return_when=futures.ALL_COMPLETED) + finally: + sys.setswitchinterval(oldswitchinterval) + + +create_executor_tests(globals(), WaitTests, + executor_mixins=(ProcessPoolForkMixin, + ProcessPoolForkserverMixin, + ProcessPoolSpawnMixin)) + + +def setUpModule(): + setup_module() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_concurrent_futures/util.py b/Lib/test/test_concurrent_futures/util.py new file mode 100644 index 00000000000000..dc48bec796b87f --- /dev/null +++ b/Lib/test/test_concurrent_futures/util.py @@ -0,0 +1,141 @@ +import multiprocessing +import sys +import time +import unittest +from concurrent import futures +from concurrent.futures._base import ( + PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future, + ) +from concurrent.futures.process import _check_system_limits + +from test import support +from test.support import threading_helper + + +def create_future(state=PENDING, exception=None, result=None): + f = Future() + f._state = state + f._exception = exception + f._result = result + return f + + +PENDING_FUTURE = create_future(state=PENDING) +RUNNING_FUTURE = create_future(state=RUNNING) +CANCELLED_FUTURE = create_future(state=CANCELLED) +CANCELLED_AND_NOTIFIED_FUTURE = create_future(state=CANCELLED_AND_NOTIFIED) +EXCEPTION_FUTURE = create_future(state=FINISHED, exception=OSError()) +SUCCESSFUL_FUTURE = create_future(state=FINISHED, result=42) + + +class BaseTestCase(unittest.TestCase): + def setUp(self): + self._thread_key = threading_helper.threading_setup() + + def tearDown(self): + support.reap_children() + threading_helper.threading_cleanup(*self._thread_key) + + +class ExecutorMixin: + worker_count = 5 + executor_kwargs = {} + + def setUp(self): + super().setUp() + + self.t1 = time.monotonic() + if hasattr(self, "ctx"): + self.executor = self.executor_type( + max_workers=self.worker_count, + mp_context=self.get_context(), + **self.executor_kwargs) + else: + self.executor = self.executor_type( + max_workers=self.worker_count, + **self.executor_kwargs) + + def tearDown(self): + self.executor.shutdown(wait=True) + self.executor = None + + dt = time.monotonic() - self.t1 + if support.verbose: + print("%.2fs" % dt, end=' ') + self.assertLess(dt, 300, "synchronization issue: test lasted too long") + + super().tearDown() + + def get_context(self): + return multiprocessing.get_context(self.ctx) + + +class ThreadPoolMixin(ExecutorMixin): + executor_type = futures.ThreadPoolExecutor + + +class ProcessPoolForkMixin(ExecutorMixin): + executor_type = futures.ProcessPoolExecutor + ctx = "fork" + + def get_context(self): + try: + _check_system_limits() + except NotImplementedError: + self.skipTest("ProcessPoolExecutor unavailable on this system") + if sys.platform == "win32": + self.skipTest("require unix system") + return super().get_context() + + +class ProcessPoolSpawnMixin(ExecutorMixin): + executor_type = futures.ProcessPoolExecutor + ctx = "spawn" + + def get_context(self): + try: + _check_system_limits() + except NotImplementedError: + self.skipTest("ProcessPoolExecutor unavailable on this system") + return super().get_context() + + +class ProcessPoolForkserverMixin(ExecutorMixin): + executor_type = futures.ProcessPoolExecutor + ctx = "forkserver" + + def get_context(self): + try: + _check_system_limits() + except NotImplementedError: + self.skipTest("ProcessPoolExecutor unavailable on this system") + if sys.platform == "win32": + self.skipTest("require unix system") + return super().get_context() + + +def create_executor_tests(remote_globals, mixin, bases=(BaseTestCase,), + executor_mixins=(ThreadPoolMixin, + ProcessPoolForkMixin, + ProcessPoolForkserverMixin, + ProcessPoolSpawnMixin)): + def strip_mixin(name): + if name.endswith(('Mixin', 'Tests')): + return name[:-5] + elif name.endswith('Test'): + return name[:-4] + else: + return name + + module = remote_globals['__name__'] + for exe in executor_mixins: + name = ("%s%sTest" + % (strip_mixin(exe.__name__), strip_mixin(mixin.__name__))) + cls = type(name, (mixin,) + (exe,) + bases, {'__module__': module}) + remote_globals[name] = cls + + +def setup_module(): + unittest.addModuleCleanup(multiprocessing.util._cleanup_tests) + thread_info = threading_helper.threading_setup() + unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info) diff --git a/Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst b/Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst new file mode 100644 index 00000000000000..ddff07be024d47 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst @@ -0,0 +1,2 @@ +Convert test_concurrent_futures to a package of 7 sub-tests. Patch by Victor +Stinner. From 208741cc3098c905914ecdc1110bfd805d4bb874 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 26 Aug 2023 16:21:24 -0700 Subject: [PATCH 0639/1206] =?UTF-8?q?[3.12]=20gh-102211:=20Document=20`re.?= =?UTF-8?q?{Pattern,Match}`=E2=80=99s=20existence=20(GH-102212)=20(#108490?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-102211: Document `re.{Pattern,Match}`’s existence (GH-102212) (cherry picked from commit 6895ddf6cb2bada7e392eb971c88ded03d8fc79e) Co-authored-by: Philipp A Co-authored-by: Jelle Zijlstra Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Alex Waygood --- Doc/library/re.rst | 67 +++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 3f03f0341d8166..d4334d330aed76 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -856,18 +856,17 @@ Functions .. function:: search(pattern, string, flags=0) Scan through *string* looking for the first location where the regular expression - *pattern* produces a match, and return a corresponding :ref:`match object - `. Return ``None`` if no position in the string matches the - pattern; note that this is different from finding a zero-length match at some - point in the string. + *pattern* produces a match, and return a corresponding :class:`~re.Match`. Return + ``None`` if no position in the string matches the pattern; note that this is + different from finding a zero-length match at some point in the string. .. function:: match(pattern, string, flags=0) If zero or more characters at the beginning of *string* match the regular - expression *pattern*, return a corresponding :ref:`match object - `. Return ``None`` if the string does not match the pattern; - note that this is different from a zero-length match. + expression *pattern*, return a corresponding :class:`~re.Match`. Return + ``None`` if the string does not match the pattern; note that this is + different from a zero-length match. Note that even in :const:`MULTILINE` mode, :func:`re.match` will only match at the beginning of the string and not at the beginning of each line. @@ -879,9 +878,8 @@ Functions .. function:: fullmatch(pattern, string, flags=0) If the whole *string* matches the regular expression *pattern*, return a - corresponding :ref:`match object `. Return ``None`` if the - string does not match the pattern; note that this is different from a - zero-length match. + corresponding :class:`~re.Match`. Return ``None`` if the string does not match + the pattern; note that this is different from a zero-length match. .. versionadded:: 3.4 @@ -954,7 +952,7 @@ Functions .. function:: finditer(pattern, string, flags=0) - Return an :term:`iterator` yielding :ref:`match objects ` over + Return an :term:`iterator` yielding :class:`~re.Match` objects over all non-overlapping matches for the RE *pattern* in *string*. The *string* is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result. @@ -982,8 +980,8 @@ Functions 'static PyObject*\npy_myfunc(void)\n{' If *repl* is a function, it is called for every non-overlapping occurrence of - *pattern*. The function takes a single :ref:`match object ` - argument, and returns the replacement string. For example:: + *pattern*. The function takes a single :class:`~re.Match` argument, and returns + the replacement string. For example:: >>> def dashrepl(matchobj): ... if matchobj.group(0) == '-': return ' ' @@ -994,7 +992,7 @@ Functions >>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE) 'Baked Beans & Spam' - The pattern may be a string or a :ref:`pattern object `. + The pattern may be a string or a :class:`~re.Pattern`. The optional argument *count* is the maximum number of pattern occurrences to be replaced; *count* must be a non-negative integer. If omitted or zero, all @@ -1129,16 +1127,20 @@ Exceptions Regular Expression Objects -------------------------- -Compiled regular expression objects support the following methods and -attributes: +.. class:: Pattern + + Compiled regular expression object returned by :func:`re.compile`. + + .. versionchanged:: 3.9 + :py:class:`re.Pattern` supports ``[]`` to indicate a Unicode (str) or bytes pattern. + See :ref:`types-genericalias`. .. method:: Pattern.search(string[, pos[, endpos]]) Scan through *string* looking for the first location where this regular - expression produces a match, and return a corresponding :ref:`match object - `. Return ``None`` if no position in the string matches the - pattern; note that this is different from finding a zero-length match at some - point in the string. + expression produces a match, and return a corresponding :class:`~re.Match`. + Return ``None`` if no position in the string matches the pattern; note that + this is different from finding a zero-length match at some point in the string. The optional second parameter *pos* gives an index in the string where the search is to start; it defaults to ``0``. This is not completely equivalent to @@ -1162,9 +1164,9 @@ attributes: .. method:: Pattern.match(string[, pos[, endpos]]) If zero or more characters at the *beginning* of *string* match this regular - expression, return a corresponding :ref:`match object `. - Return ``None`` if the string does not match the pattern; note that this is - different from a zero-length match. + expression, return a corresponding :class:`~re.Match`. Return ``None`` if the + string does not match the pattern; note that this is different from a + zero-length match. The optional *pos* and *endpos* parameters have the same meaning as for the :meth:`~Pattern.search` method. :: @@ -1181,8 +1183,8 @@ attributes: .. method:: Pattern.fullmatch(string[, pos[, endpos]]) If the whole *string* matches this regular expression, return a corresponding - :ref:`match object `. Return ``None`` if the string does not - match the pattern; note that this is different from a zero-length match. + :class:`~re.Match`. Return ``None`` if the string does not match the pattern; + note that this is different from a zero-length match. The optional *pos* and *endpos* parameters have the same meaning as for the :meth:`~Pattern.search` method. :: @@ -1268,8 +1270,13 @@ when there is no match, you can test whether there was a match with a simple if match: process(match) -Match objects support the following methods and attributes: +.. class:: Match + + Match object returned by successful ``match``\ es and ``search``\ es. + .. versionchanged:: 3.9 + :py:class:`re.Match` supports ``[]`` to indicate a Unicode (str) or bytes match. + See :ref:`types-genericalias`. .. method:: Match.expand(template) @@ -1713,10 +1720,10 @@ Finding all Adverbs and their Positions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If one wants more information about all matches of a pattern than the matched -text, :func:`finditer` is useful as it provides :ref:`match objects -` instead of strings. Continuing with the previous example, if -a writer wanted to find all of the adverbs *and their positions* in -some text, they would use :func:`finditer` in the following manner:: +text, :func:`finditer` is useful as it provides :class:`~re.Match` objects +instead of strings. Continuing with the previous example, if a writer wanted +to find all of the adverbs *and their positions* in some text, they would use +:func:`finditer` in the following manner:: >>> text = "He was carefully disguised but captured quickly by police." >>> for m in re.finditer(r"\w+ly\b", text): From bbdd8895a5aced4cd4e66a5c6e3471636f28df6b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 26 Aug 2023 16:22:40 -0700 Subject: [PATCH 0640/1206] [3.12] gh-108487: Change assert that should've been DEOPT_IF (#108509) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove assert that should've been DEOPT_IF The assert(method != NULL) in CALL_NO_KW_LIST_APPEND is wrong -- this condition should lead to a deoptimization, and indeed there is a DEOPT_IF two lines later that will trigger if method == NULL. This would crash in a devious repro scenario (first seen live in boto3 tests) when compiled with assertions enabled. In a production version there is no crash, so impact is limited. (The crash also appears in main; I will prepare a separate PR.) * Add back a different assert(self != NULL) * 📜🤖 Added by blurb_it. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- .../2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst | 1 + Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst new file mode 100644 index 00000000000000..1117bcd7e9852b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst @@ -0,0 +1 @@ +Change an assert that would cause a spurious crash in a devious case that should only trigger deoptimization. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index dc2ae221f0bdb1..5e80e06205ae4e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2992,9 +2992,9 @@ dummy_func( inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) { assert(kwnames == NULL); assert(oparg == 1); - assert(method != NULL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(method != interp->callable_cache.list_append, CALL); + assert(self != NULL); DEOPT_IF(!PyList_Check(self), CALL); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b0a363ce9aa111..a3c049569268c1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4248,9 +4248,9 @@ #line 2993 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); - assert(method != NULL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(method != interp->callable_cache.list_append, CALL); + assert(self != NULL); DEOPT_IF(!PyList_Check(self), CALL); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) { From 3e2030371723e5fb7c9ccbe83cd980ce69cabc1a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 26 Aug 2023 16:24:40 -0700 Subject: [PATCH 0641/1206] [3.12] gh-107913: Fix possible losses of OSError error codes (GH-107930) (#108523) gh-107913: Fix possible losses of OSError error codes (GH-107930) Functions like PyErr_SetFromErrno() and SetFromWindowsErr() should be called immediately after using the C API which sets errno or the Windows error code. (cherry picked from commit 2b15536fa94d07e9e286826c23507402313ec7f4) Co-authored-by: Serhiy Storchaka --- ...-08-14-11-18-13.gh-issue-107913.4ooY6i.rst | 3 + Modules/_cursesmodule.c | 2 +- Modules/_io/fileio.c | 12 +- Modules/_io/winconsoleio.c | 2 +- Modules/_localemodule.c | 2 +- Modules/_multiprocessing/semaphore.c | 9 +- Modules/_ssl.c | 8 +- Modules/faulthandler.c | 3 +- Modules/fcntlmodule.c | 5 +- Modules/getpath.c | 3 +- Modules/mmapmodule.c | 2 + Modules/overlapped.c | 3 +- Modules/posixmodule.c | 128 ++++++++++++------ Modules/selectmodule.c | 4 +- Modules/socketmodule.c | 12 +- Objects/unicodeobject.c | 2 +- Python/fileutils.c | 4 +- 17 files changed, 129 insertions(+), 75 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst diff --git a/Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst b/Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst new file mode 100644 index 00000000000000..de5e21abfc3ae7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst @@ -0,0 +1,3 @@ +Fix possible losses of ``errno`` and ``winerror`` values in :exc:`OSError` +exceptions if they were cleared or modified by the cleanup code before +creating the exception object. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 5691a419a32f8e..743b9e37fbcb04 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3071,8 +3071,8 @@ _curses_getwin(PyObject *module, PyObject *file) } datalen = PyBytes_GET_SIZE(data); if (fwrite(PyBytes_AS_STRING(data), 1, datalen, fp) != datalen) { - Py_DECREF(data); PyErr_SetFromErrno(PyExc_OSError); + Py_DECREF(data); goto error; } Py_DECREF(data); diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 30944fc56bf70e..c8be9982890b97 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -394,6 +394,11 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, if (async_err) goto error; + + if (self->fd < 0) { + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); + goto error; + } } else { PyObject *fdobj; @@ -425,12 +430,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, goto error; } } - fd_is_own = 1; - if (self->fd < 0) { - PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); - goto error; - } #ifndef MS_WINDOWS if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0) @@ -1058,8 +1058,8 @@ _io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj) Py_END_ALLOW_THREADS if (ret != 0) { - Py_DECREF(posobj); PyErr_SetFromErrno(PyExc_OSError); + Py_DECREF(posobj); return NULL; } diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 15f3053957da61..7c6f226329dd35 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -378,8 +378,8 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, else self->fd = _Py_open_osfhandle_noraise(handle, _O_RDONLY | _O_BINARY); if (self->fd < 0) { - CloseHandle(handle); PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); + CloseHandle(handle); goto error; } } diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 1ada7305117bb7..cbd036fdf2a7bb 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -737,8 +737,8 @@ _locale_bindtextdomain_impl(PyObject *module, const char *domain, } current_dirname = bindtextdomain(domain, dirname); if (current_dirname == NULL) { - Py_XDECREF(dirname_bytes); PyErr_SetFromErrno(PyExc_OSError); + Py_XDECREF(dirname_bytes); return NULL; } result = PyUnicode_DecodeLocale(current_dirname, NULL); diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c index 897b8db7110a41..c7df82dfe2d0cc 100644 --- a/Modules/_multiprocessing/semaphore.c +++ b/Modules/_multiprocessing/semaphore.c @@ -516,12 +516,12 @@ _multiprocessing_SemLock_impl(PyTypeObject *type, int kind, int value, return result; failure: - if (handle != SEM_FAILED) - SEM_CLOSE(handle); - PyMem_Free(name_copy); if (!PyErr_Occurred()) { _PyMp_SetError(NULL, MP_STANDARD_ERROR); } + if (handle != SEM_FAILED) + SEM_CLOSE(handle); + PyMem_Free(name_copy); return NULL; } @@ -556,8 +556,9 @@ _multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle, if (name != NULL) { handle = sem_open(name, 0); if (handle == SEM_FAILED) { + PyErr_SetFromErrno(PyExc_OSError); PyMem_Free(name_copy); - return PyErr_SetFromErrno(PyExc_OSError); + return NULL; } } #endif diff --git a/Modules/_ssl.c b/Modules/_ssl.c index e939f95048984b..b602eb04c795a9 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3889,8 +3889,8 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, /* the password callback has already set the error information */ } else if (errno != 0) { - ERR_clear_error(); PyErr_SetFromErrno(PyExc_OSError); + ERR_clear_error(); } else { _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); @@ -3910,8 +3910,8 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, /* the password callback has already set the error information */ } else if (errno != 0) { - ERR_clear_error(); PyErr_SetFromErrno(PyExc_OSError); + ERR_clear_error(); } else { _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); @@ -4140,8 +4140,8 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self, PySSL_END_ALLOW_THREADS if (r != 1) { if (errno != 0) { - ERR_clear_error(); PyErr_SetFromErrno(PyExc_OSError); + ERR_clear_error(); } else { _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); @@ -4188,8 +4188,8 @@ _ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath) PySSL_END_ALLOW_THREADS if (dh == NULL) { if (errno != 0) { - ERR_clear_error(); PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath); + ERR_clear_error(); } else { _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 428b090193f093..3d360cb4368cca 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -414,11 +414,10 @@ faulthandler_allocate_stack(void) int err = sigaltstack(&stack, &old_stack); if (err) { + PyErr_SetFromErrno(PyExc_OSError); /* Release the stack to retry sigaltstack() next time */ PyMem_Free(stack.ss_sp); stack.ss_sp = NULL; - - PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index 6ca0b62bc5dca8..2bca40213c65b9 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -211,11 +211,12 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code, if (mutate_arg && (len <= IOCTL_BUFSZ)) { memcpy(str, buf, len); } - PyBuffer_Release(&pstr); /* No further access to str below this point */ if (ret < 0) { PyErr_SetFromErrno(PyExc_OSError); + PyBuffer_Release(&pstr); return NULL; } + PyBuffer_Release(&pstr); if (mutate_arg) { return PyLong_FromLong(ret); } @@ -240,8 +241,8 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code, ret = ioctl(fd, code, buf); Py_END_ALLOW_THREADS if (ret < 0) { - PyBuffer_Release(&pstr); PyErr_SetFromErrno(PyExc_OSError); + PyBuffer_Release(&pstr); return NULL; } PyBuffer_Release(&pstr); diff --git a/Modules/getpath.c b/Modules/getpath.c index 237fe8c0c2c221..b9914a0c8e9d03 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -341,11 +341,12 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) return NULL; } FILE *fp = _Py_wfopen(path, L"rb"); - PyMem_Free((void *)path); if (!fp) { PyErr_SetFromErrno(PyExc_OSError); + PyMem_Free((void *)path); return NULL; } + PyMem_Free((void *)path); r = PyList_New(0); if (!r) { diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 1ffadccb916253..c5e6c27f73b855 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1356,6 +1356,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset); Py_END_ALLOW_THREADS + int saved_errno = errno; if (devzero != -1) { close(devzero); } @@ -1363,6 +1364,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) if (m_obj->data == (char *)-1) { m_obj->data = NULL; Py_DECREF(m_obj); + errno = saved_errno; PyErr_SetFromErrno(PyExc_OSError); return NULL; } diff --git a/Modules/overlapped.c b/Modules/overlapped.c index ac637316583d2d..afdd78d1bc94fc 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -367,8 +367,9 @@ _overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object, &NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { + SetFromWindowsErr(0); PyMem_RawFree(pdata); - return SetFromWindowsErr(0); + return NULL; } return Py_BuildValue(F_HANDLE, NewWaitObject); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 44cc31bd4bd702..b9ca2865c0374e 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3877,9 +3877,10 @@ posix_getcwd(int use_bytes) return NULL; } if (!len) { + PyErr_SetFromWindowsErr(0); if (wbuf2 != wbuf) PyMem_RawFree(wbuf2); - return PyErr_SetFromWindowsErr(0); + return NULL; } PyObject *resobj = PyUnicode_FromWideChar(wbuf2, len); @@ -3927,8 +3928,9 @@ posix_getcwd(int use_bytes) return PyErr_NoMemory(); } if (cwd == NULL) { + posix_error(); PyMem_RawFree(buf); - return posix_error(); + return NULL; } PyObject *obj; @@ -4140,8 +4142,8 @@ _listdir_windows_no_opendir(path_t *path, PyObject *list) int error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND) goto exit; - Py_DECREF(list); - list = path_error(path); + path_error(path); + Py_CLEAR(list); goto exit; } do { @@ -4154,12 +4156,12 @@ _listdir_windows_no_opendir(path_t *path, PyObject *list) Py_SETREF(v, PyUnicode_EncodeFSDefault(v)); } if (v == NULL) { - Py_SETREF(list, NULL); + Py_CLEAR(list); break; } if (PyList_Append(list, v) != 0) { Py_DECREF(v); - Py_SETREF(list, NULL); + Py_CLEAR(list); break; } Py_DECREF(v); @@ -4170,8 +4172,8 @@ _listdir_windows_no_opendir(path_t *path, PyObject *list) /* FindNextFile sets error to ERROR_NO_MORE_FILES if it got to the end of the directory. */ if (!result && GetLastError() != ERROR_NO_MORE_FILES) { - Py_DECREF(list); - list = path_error(path); + path_error(path); + Py_CLEAR(list); goto exit; } } while (result == TRUE); @@ -4180,8 +4182,8 @@ _listdir_windows_no_opendir(path_t *path, PyObject *list) if (hFindFile != INVALID_HANDLE_VALUE) { if (FindClose(hFindFile) == FALSE) { if (list != NULL) { - Py_DECREF(list); - list = path_error(path); + path_error(path); + Py_CLEAR(list); } } } @@ -4243,7 +4245,8 @@ _posix_listdir(path_t *path, PyObject *list) } if (dirp == NULL) { - list = path_error(path); + path_error(path); + list = NULL; #ifdef HAVE_FDOPENDIR if (fd != -1) { Py_BEGIN_ALLOW_THREADS @@ -4265,8 +4268,8 @@ _posix_listdir(path_t *path, PyObject *list) if (errno == 0) { break; } else { - Py_DECREF(list); - list = path_error(path); + path_error(path); + Py_CLEAR(list); goto exit; } } @@ -6609,8 +6612,9 @@ os_execv_impl(PyObject *module, path_t *path, PyObject *argv) /* If we get here it's definitely an error */ + posix_error(); free_string_array(argvlist, argc); - return posix_error(); + return NULL; } @@ -6914,11 +6918,12 @@ parse_file_actions(PyObject *file_actions, } errno = posix_spawn_file_actions_addopen(file_actionsp, fd, PyBytes_AS_STRING(path), oflag, (mode_t)mode); - Py_DECREF(path); if (errno) { posix_error(); + Py_DECREF(path); goto fail; } + Py_DECREF(path); break; } case POSIX_SPAWN_CLOSE: { @@ -7315,12 +7320,15 @@ os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv) _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS + int saved_errno = errno; free_string_array(argvlist, argc); - if (spawnval == -1) - return posix_error(); - else - return Py_BuildValue(_Py_PARSE_INTPTR, spawnval); + if (spawnval == -1) { + errno = saved_errno; + posix_error(); + return NULL; + } + return Py_BuildValue(_Py_PARSE_INTPTR, spawnval); } /*[clinic input] @@ -7638,6 +7646,7 @@ os_fork1_impl(PyObject *module) } PyOS_BeforeFork(); pid = fork1(); + int saved_errno = errno; if (pid == 0) { /* child: this clobbers and resets the import lock. */ PyOS_AfterFork_Child(); @@ -7646,8 +7655,10 @@ os_fork1_impl(PyObject *module) /* parent: release the import lock. */ PyOS_AfterFork_Parent(); } - if (pid == -1) + if (pid == -1) { + errno = saved_errno; return posix_error(); + } return PyLong_FromPid(pid); } #endif /* HAVE_FORK1 */ @@ -7683,6 +7694,7 @@ os_fork_impl(PyObject *module) } PyOS_BeforeFork(); pid = fork(); + int saved_errno = errno; if (pid == 0) { /* child: this clobbers and resets the import lock. */ PyOS_AfterFork_Child(); @@ -7691,8 +7703,10 @@ os_fork_impl(PyObject *module) /* parent: release the import lock. */ PyOS_AfterFork_Parent(); } - if (pid == -1) + if (pid == -1) { + errno = saved_errno; return posix_error(); + } return PyLong_FromPid(pid); } #endif /* HAVE_FORK */ @@ -8229,13 +8243,17 @@ os_openpty_impl(PyObject *module) /* change permission of slave */ if (grantpt(master_fd) < 0) { + int saved_errno = errno; PyOS_setsig(SIGCHLD, sig_saved); + errno = saved_errno; goto posix_error; } /* unlock slave */ if (unlockpt(master_fd) < 0) { + int saved_errno = errno; PyOS_setsig(SIGCHLD, sig_saved); + errno = saved_errno; goto posix_error; } @@ -8599,8 +8617,9 @@ os_getgroups_impl(PyObject *module) n = getgroups(n, grouplist); if (n == -1) { + posix_error(); PyMem_Free(grouplist); - return posix_error(); + return NULL; } PyObject *result = PyList_New(n); @@ -9163,8 +9182,9 @@ os_setgroups(PyObject *module, PyObject *groups) } if (setgroups(len, grouplist) < 0) { + posix_error(); PyMem_Free(grouplist); - return posix_error(); + return NULL; } PyMem_Free(grouplist); Py_RETURN_NONE; @@ -10611,10 +10631,13 @@ os_readv_impl(PyObject *module, int fd, PyObject *buffers) Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + int saved_errno = errno; iov_cleanup(iov, buf, cnt); if (n < 0) { - if (!async_err) + if (!async_err) { + errno = saved_errno; posix_error(); + } return -1; } @@ -10663,8 +10686,11 @@ os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset) } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (n < 0) { + if (!async_err) { + posix_error(); + } Py_DECREF(buffer); - return (!async_err) ? posix_error() : NULL; + return NULL; } if (n != length) _PyBytes_Resize(&buffer, n); @@ -10761,9 +10787,11 @@ os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, #endif + int saved_errno = errno; iov_cleanup(iov, buf, cnt); if (n < 0) { if (!async_err) { + errno = saved_errno; posix_error(); } return -1; @@ -10932,24 +10960,26 @@ os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj, } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); _Py_END_SUPPRESS_IPH + int saved_errno = errno; if (sf.headers != NULL) iov_cleanup(sf.headers, hbuf, sf.hdr_cnt); if (sf.trailers != NULL) iov_cleanup(sf.trailers, tbuf, sf.trl_cnt); if (ret < 0) { - if ((errno == EAGAIN) || (errno == EBUSY)) { + if ((saved_errno == EAGAIN) || (saved_errno == EBUSY)) { if (sbytes != 0) { // some data has been sent goto done; } - else { - // no data has been sent; upper application is supposed - // to retry on EAGAIN or EBUSY - return posix_error(); - } + // no data has been sent; upper application is supposed + // to retry on EAGAIN or EBUSY } - return (!async_err) ? posix_error() : NULL; + if (!async_err) { + errno = saved_errno; + posix_error(); + } + return NULL; } goto done; @@ -11266,10 +11296,10 @@ os_writev_impl(PyObject *module, int fd, PyObject *buffers) Py_END_ALLOW_THREADS } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - iov_cleanup(iov, buf, cnt); if (result < 0 && !async_err) posix_error(); + iov_cleanup(iov, buf, cnt); return result; } #endif /* HAVE_WRITEV */ @@ -11404,13 +11434,13 @@ os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset, #endif - iov_cleanup(iov, buf, cnt); if (result < 0) { if (!async_err) { posix_error(); } - return -1; + result = -1; } + iov_cleanup(iov, buf, cnt); return result; } @@ -11972,12 +12002,13 @@ win32_putenv(PyObject *name, PyObject *value) Prefer _wputenv() to be compatible with C libraries using CRT variables and CRT functions using these variables (ex: getenv()). */ int err = _wputenv(env); - PyMem_Free(env); if (err) { posix_error(); + PyMem_Free(env); return NULL; } + PyMem_Free(env); Py_RETURN_NONE; } @@ -13819,10 +13850,12 @@ os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute, Py_END_ALLOW_THREADS; if (result < 0) { - Py_DECREF(buffer); - if (errno == ERANGE) + if (errno == ERANGE) { + Py_DECREF(buffer); continue; + } path_error(path); + Py_DECREF(buffer); return NULL; } @@ -14589,14 +14622,19 @@ DirEntry_fetch_stat(PyObject *module, DirEntry *self, int follow_symlinks) } Py_END_ALLOW_THREADS } + + int saved_errno = errno; #if defined(MS_WINDOWS) PyMem_Free(path); #else Py_DECREF(ub); #endif - if (result != 0) - return path_object_error(self->path); + if (result != 0) { + errno = saved_errno; + path_object_error(self->path); + return NULL; + } return _pystat_fromstructstat(module, &st); } @@ -14788,10 +14826,14 @@ os_DirEntry_inode_impl(DirEntry *self) wchar_t *path = PyUnicode_AsWideCharString(unicode, NULL); Py_DECREF(unicode); result = LSTAT(path, &stat); + + int saved_errno = errno; PyMem_Free(path); - if (result != 0) + if (result != 0) { + errno = saved_errno; return path_object_error(self->path); + } self->win32_file_index = stat.st_ino; self->got_file_index = 1; @@ -15355,12 +15397,12 @@ os_scandir_impl(PyObject *module, path_t *path) iterator->handle = FindFirstFileW(path_strW, &iterator->file_data); Py_END_ALLOW_THREADS - PyMem_Free(path_strW); - if (iterator->handle == INVALID_HANDLE_VALUE) { path_error(&iterator->path); + PyMem_Free(path_strW); goto error; } + PyMem_Free(path_strW); #else /* POSIX */ errno = 0; #ifdef HAVE_FDOPENDIR diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 9a4943c9eb2f75..a88c3cb81520d2 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1292,8 +1292,8 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, SOCKET fd) self->epfd = fd; } if (self->epfd < 0) { - Py_DECREF(self); PyErr_SetFromErrno(PyExc_OSError); + Py_DECREF(self); return NULL; } @@ -1971,8 +1971,8 @@ newKqueue_Object(PyTypeObject *type, SOCKET fd) self->kqfd = fd; } if (self->kqfd < 0) { - Py_DECREF(self); PyErr_SetFromErrno(PyExc_OSError); + Py_DECREF(self); return NULL; } diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 1ae7ab778290fe..4ec68e22a9f8cd 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5401,8 +5401,8 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, } if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0)) { - closesocket(fd); PyErr_SetFromWindowsErr(0); + closesocket(fd); return -1; } @@ -5616,8 +5616,9 @@ socket_gethostname(PyObject *self, PyObject *unused) name, &size)) { + PyErr_SetFromWindowsErr(0); PyMem_Free(name); - return PyErr_SetFromWindowsErr(0); + return NULL; } result = PyUnicode_FromWideChar(name, size); @@ -6215,8 +6216,8 @@ socket_dup(PyObject *self, PyObject *fdobj) } if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) { - closesocket(newfd); PyErr_SetFromWindowsErr(0); + closesocket(newfd); return NULL; } #else @@ -6663,11 +6664,12 @@ socket_inet_ntop(PyObject *self, PyObject *args) /* inet_ntop guarantee NUL-termination of resulting string. */ retval = inet_ntop(af, packed_ip.buf, ip, sizeof(ip)); - PyBuffer_Release(&packed_ip); if (!retval) { PyErr_SetFromErrno(PyExc_OSError); + PyBuffer_Release(&packed_ip); return NULL; } else { + PyBuffer_Release(&packed_ip); return PyUnicode_FromString(retval); } } @@ -7006,8 +7008,8 @@ socket_if_nameindex(PyObject *self, PyObject *arg) ni = if_nameindex(); if (ni == NULL) { - Py_DECREF(list); PyErr_SetFromErrno(PyExc_OSError); + Py_DECREF(list); return NULL; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7ead65bf98d1f1..3fbc2d297cdd56 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7060,7 +7060,7 @@ decode_code_page_errors(UINT code_page, if (err != ERROR_NO_UNICODE_TRANSLATION && err != ERROR_INSUFFICIENT_BUFFER) { - PyErr_SetFromWindowsErr(0); + PyErr_SetFromWindowsErr(err); goto error; } insize++; diff --git a/Python/fileutils.c b/Python/fileutils.c index 268ffa3d61a470..610e729feb358e 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1790,6 +1790,7 @@ _Py_fopen_obj(PyObject *path, const char *mode) Py_END_ALLOW_THREADS } while (f == NULL && errno == EINTR && !(async_err = PyErr_CheckSignals())); + int saved_errno = errno; PyMem_Free(wpath); #else PyObject *bytes; @@ -1812,13 +1813,14 @@ _Py_fopen_obj(PyObject *path, const char *mode) Py_END_ALLOW_THREADS } while (f == NULL && errno == EINTR && !(async_err = PyErr_CheckSignals())); - + int saved_errno = errno; Py_DECREF(bytes); #endif if (async_err) return NULL; if (f == NULL) { + errno = saved_errno; PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); return NULL; } From 09877a15d5a84bc1e6894cac022f18a39c67e917 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Aug 2023 07:12:57 -0700 Subject: [PATCH 0642/1206] [3.12] gh-108295: Fix crashes with TypeVar weakrefs (GH-108517) (#108527) gh-108295: Fix crashes with TypeVar weakrefs (GH-108517) (cherry picked from commit 482fad7f01567447b7259ebf58d62999fcdc5964) Co-authored-by: Jelle Zijlstra --- Lib/test/test_typing.py | 10 ++++++++++ .../2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst | 1 + Objects/typevarobject.c | 3 +++ 3 files changed, 14 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c88152de7725fb..6c9f168b63f96d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -544,6 +544,16 @@ def test_bad_var_substitution(self): with self.assertRaises(TypeError): list[T][arg] + def test_many_weakrefs(self): + # gh-108295: this used to segfault + for cls in (ParamSpec, TypeVarTuple, TypeVar): + with self.subTest(cls=cls): + vals = weakref.WeakValueDictionary() + + for x in range(100000): + vals[x] = cls(str(x)) + del vals + def template_replace(templates: list[str], replacements: dict[str, list[str]]) -> list[tuple[str]]: """Renders templates with possible combinations of replacements. diff --git a/Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst b/Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst new file mode 100644 index 00000000000000..7e61ed4de75ce6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst @@ -0,0 +1 @@ +Fix crashes related to use of weakrefs on :data:`typing.TypeVar`. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 97f39136996fcc..069e1d98ea4978 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -201,6 +201,7 @@ typevar_dealloc(PyObject *self) Py_XDECREF(tv->constraints); Py_XDECREF(tv->evaluate_constraints); _PyObject_ClearManagedDict(self); + PyObject_ClearWeakRefs(self); Py_TYPE(self)->tp_free(self); Py_DECREF(tp); @@ -743,6 +744,7 @@ paramspec_dealloc(PyObject *self) Py_DECREF(ps->name); Py_XDECREF(ps->bound); _PyObject_ClearManagedDict(self); + PyObject_ClearWeakRefs(self); Py_TYPE(self)->tp_free(self); Py_DECREF(tp); @@ -1022,6 +1024,7 @@ typevartuple_dealloc(PyObject *self) Py_DECREF(tvt->name); _PyObject_ClearManagedDict(self); + PyObject_ClearWeakRefs(self); Py_TYPE(self)->tp_free(self); Py_DECREF(tp); From 387cb9f324e122dab31a7dd09aa0ca7a2a93f7d1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Aug 2023 07:13:26 -0700 Subject: [PATCH 0643/1206] [3.12] gh-107453: Document errno.{ECANCELED,EOWNERDEAD,ENOTRECOVERABLE,ENOTSUP} (GH-107486) (#108529) gh-107453: Document errno.{ECANCELED,EOWNERDEAD,ENOTRECOVERABLE,ENOTSUP} (GH-107486) (cherry picked from commit 1ac64237e6ce965064451ed57ae37271aeb9fbd3) Co-authored-by: qqwqqw689 <114795525+qqwqqw689@users.noreply.github.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/errno.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Doc/library/errno.rst b/Doc/library/errno.rst index 5122c69697ef91..283e8b013265d9 100644 --- a/Doc/library/errno.rst +++ b/Doc/library/errno.rst @@ -511,6 +511,13 @@ defined by the module. The specific list of defined symbols is available as Operation not supported on transport endpoint +.. data:: ENOTSUP + + Operation not supported + + .. versionadded:: 3.2 + + .. data:: EPFNOSUPPORT Protocol family not supported @@ -666,3 +673,24 @@ defined by the module. The specific list of defined symbols is available as .. availability:: WASI, FreeBSD .. versionadded:: 3.11.1 + + +.. data:: ECANCELED + + Operation canceled + + .. versionadded:: 3.2 + + +.. data:: EOWNERDEAD + + Owner died + + .. versionadded:: 3.2 + + +.. data:: ENOTRECOVERABLE + + State not recoverable + + .. versionadded:: 3.2 From 0b0238d6a1e1b41be98193fd6e5857b220424adb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Aug 2023 07:15:01 -0700 Subject: [PATCH 0644/1206] [3.12] gh-105052:update timeit function's description (GH-105060) (#108534) gh-105052:update timeit function's description (GH-105060) --------- (cherry picked from commit 7096a2be33619dc02c06a6dc30aac414a9eba462) Co-authored-by: R --- Doc/library/timeit.rst | 6 ++++-- Lib/timeit.py | 18 ++++++++++++------ ...3-05-29-14-10-24.gh-issue-105052.MGFwbm.rst | 1 + 3 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst index a559e0a2eb3dad..b3d2a1b9e0600f 100644 --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -86,9 +86,11 @@ The module defines three convenience functions and a public class: .. versionchanged:: 3.7 Default value of *repeat* changed from 3 to 5. + .. function:: default_timer() - The default timer, which is always :func:`time.perf_counter`. + The default timer, which is always time.perf_counter(), returns float seconds. + An alternative, time.perf_counter_ns, returns integer nanoseconds. .. versionchanged:: 3.3 :func:`time.perf_counter` is now the default timer. @@ -124,7 +126,7 @@ The module defines three convenience functions and a public class: Time *number* executions of the main statement. This executes the setup statement once, and then returns the time it takes to execute the main - statement a number of times, measured in seconds as a float. + statement a number of times. The default timer returns seconds as a float. The argument is the number of times through the loop, defaulting to one million. The main statement, the setup statement and the timer function to be used are passed to the constructor. diff --git a/Lib/timeit.py b/Lib/timeit.py index 0cf8db67723a49..02cfafaf36e5d1 100755 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -50,9 +50,9 @@ """ import gc +import itertools import sys import time -import itertools __all__ = ["Timer", "timeit", "repeat", "default_timer"] @@ -77,9 +77,11 @@ def inner(_it, _timer{init}): return _t1 - _t0 """ + def reindent(src, indent): """Helper to reindent a multi-line statement.""" - return src.replace("\n", "\n" + " "*indent) + return src.replace("\n", "\n" + " " * indent) + class Timer: """Class for timing execution speed of small code snippets. @@ -166,7 +168,7 @@ def timeit(self, number=default_number): To be precise, this executes the setup statement once, and then returns the time it takes to execute the main statement - a number of times, as a float measured in seconds. The + a number of times, as float seconds if using the default timer. The argument is the number of times through the loop, defaulting to one million. The main statement, the setup statement and the timer function to be used are passed to the constructor. @@ -228,16 +230,19 @@ def autorange(self, callback=None): return (number, time_taken) i *= 10 + def timeit(stmt="pass", setup="pass", timer=default_timer, number=default_number, globals=None): """Convenience function to create Timer object and call timeit method.""" return Timer(stmt, setup, timer, globals).timeit(number) + def repeat(stmt="pass", setup="pass", timer=default_timer, repeat=default_repeat, number=default_number, globals=None): """Convenience function to create Timer object and call repeat method.""" return Timer(stmt, setup, timer, globals).repeat(repeat, number) + def main(args=None, *, _wrap_timer=None): """Main program, used when run as a script. @@ -269,7 +274,7 @@ def main(args=None, *, _wrap_timer=None): timer = default_timer stmt = "\n".join(args) or "pass" - number = 0 # auto-determine + number = 0 # auto-determine setup = [] repeat = default_repeat verbose = 0 @@ -286,7 +291,7 @@ def main(args=None, *, _wrap_timer=None): time_unit = a else: print("Unrecognized unit. Please select nsec, usec, msec, or sec.", - file=sys.stderr) + file=sys.stderr) return 2 if o in ("-r", "--repeat"): repeat = int(a) @@ -320,7 +325,7 @@ def callback(number, time_taken): msg = "{num} loop{s} -> {secs:.{prec}g} secs" plural = (number != 1) print(msg.format(num=number, s='s' if plural else '', - secs=time_taken, prec=precision)) + secs=time_taken, prec=precision)) try: number, _ = t.autorange(callback) except: @@ -371,5 +376,6 @@ def format_time(dt): UserWarning, '', 0) return None + if __name__ == "__main__": sys.exit(main()) diff --git a/Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst b/Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst new file mode 100644 index 00000000000000..8fdc38d439f54f --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst @@ -0,0 +1 @@ +Update ``timeit`` doc to specify that time in seconds is just the default. From 07c0e24748edc1e502c949a9f7276b6dbbff9b0d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Aug 2023 07:16:21 -0700 Subject: [PATCH 0645/1206] [3.12] Clarify distinction between datetime module and class in deprecation messages (GH-108073) (#108540) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify distinction between datetime module and class in deprecation messages (GH-108073) (cherry picked from commit 09343dba44cdb5c279ec51df34552ef451434958) Co-authored-by: Clément Robert --- Modules/_datetimemodule.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index cbc331c7e94268..d8183c63f44976 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5145,9 +5145,9 @@ static PyObject * datetime_utcnow(PyObject *cls, PyObject *dummy) { if (PyErr_WarnEx(PyExc_DeprecationWarning, - "datetime.utcnow() is deprecated and scheduled for removal in a " + "datetime.datetime.utcnow() is deprecated and scheduled for removal in a " "future version. Use timezone-aware objects to represent datetimes " - "in UTC: datetime.now(datetime.UTC).", 1)) + "in UTC: datetime.datetime.now(datetime.UTC).", 1)) { return NULL; } @@ -5188,9 +5188,9 @@ static PyObject * datetime_utcfromtimestamp(PyObject *cls, PyObject *args) { if (PyErr_WarnEx(PyExc_DeprecationWarning, - "datetime.utcfromtimestamp() is deprecated and scheduled for removal " + "datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal " "in a future version. Use timezone-aware objects to represent " - "datetimes in UTC: datetime.fromtimestamp(timestamp, datetime.UTC).", 1)) + "datetimes in UTC: datetime.datetime.fromtimestamp(timestamp, datetime.UTC).", 1)) { return NULL; } From 752d5254f57a99ac2d89034fceb3ce9fbad02440 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Aug 2023 08:00:07 -0700 Subject: [PATCH 0646/1206] [3.12] Fix grammatical error in stringprep documentation (GH-108414) (#108537) Fix grammatical error in stringprep documentation (GH-108414) Remove the word "them", which didn't make grammatical sense. (cherry picked from commit cd0a8aece974330ef44ffe4e0f2e8aa632e98438) Co-authored-by: Matthew James Kraai Co-authored-by: KRAAI, MATTHEW [VISUS] Co-authored-by: Alex Waygood --- Doc/library/stringprep.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/stringprep.rst b/Doc/library/stringprep.rst index 5cfb533d802db4..c6d78a356d97bc 100644 --- a/Doc/library/stringprep.rst +++ b/Doc/library/stringprep.rst @@ -27,7 +27,7 @@ procedure are part of the profile. One example of a ``stringprep`` profile is ``nameprep``, which is used for internationalized domain names. The module :mod:`stringprep` only exposes the tables from :rfc:`3454`. As these -tables would be very large to represent them as dictionaries or lists, the +tables would be very large to represent as dictionaries or lists, the module uses the Unicode character database internally. The module source code itself was generated using the ``mkstringprep.py`` utility. From 32d48ede2fe90f27b5ed96c8e2bd3387a795e825 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 28 Aug 2023 01:58:48 +0200 Subject: [PATCH 0647/1206] [3.12] gh-108542: Fix incorrect module name in NEWS entry for gh-105475 (#108543) (#108545) (cherry picked from commit a429eafef2d86eafc007ac19682e7d372c32da31) --- Misc/NEWS.d/3.12.0b3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/3.12.0b3.rst b/Misc/NEWS.d/3.12.0b3.rst index ffd880f8688679..2b26ac74f7689d 100644 --- a/Misc/NEWS.d/3.12.0b3.rst +++ b/Misc/NEWS.d/3.12.0b3.rst @@ -281,7 +281,7 @@ Fix bugs in :mod:`zoneinfo` where exceptions could be overwritten. .. nonce: bTcqS9 .. section: Library -Fix bugs in :mod:`pickle` where exceptions could be overwritten. +Fix bugs in :mod:`errno` where exceptions could be overwritten. .. From 311fd96dae5156b46e0eca982c12dd6bad00adf5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 27 Aug 2023 16:59:35 -0700 Subject: [PATCH 0648/1206] [3.12] Docs: Resolve Sphinx warnings in dis.rst (GH-108476) (#108546) Docs: Resolve Sphinx warnings in dis.rst (GH-108476) - Link to the code objects reference - Suppress link to deliberately undocumented builtins.__build_class__ - Suppress links for example methods (cherry picked from commit cb1184280b3fb369a07abb4153aa36829cf1df9b) Co-authored-by: Erlend E. Aasland --- Doc/library/dis.rst | 20 +++++++++++--------- Doc/reference/datamodel.rst | 4 +++- Doc/tools/.nitignore | 1 - 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 085fd2baba55c0..6fadccfc44f92f 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -43,13 +43,13 @@ interpreter. adaptive bytecode can be shown by passing ``adaptive=True``. -Example: Given the function :func:`myfunc`:: +Example: Given the function :func:`!myfunc`:: def myfunc(alist): return len(alist) the following command can be used to display the disassembly of -:func:`myfunc`: +:func:`!myfunc`: .. doctest:: @@ -793,7 +793,7 @@ iterations of the loop. .. opcode:: LOAD_BUILD_CLASS - Pushes :func:`builtins.__build_class__` onto the stack. It is later called + Pushes :func:`!builtins.__build_class__` onto the stack. It is later called to construct a class. @@ -851,14 +851,14 @@ iterations of the loop. .. opcode:: STORE_NAME (namei) Implements ``name = STACK.pop()``. *namei* is the index of *name* in the attribute - :attr:`co_names` of the code object. The compiler tries to use - :opcode:`STORE_FAST` or :opcode:`STORE_GLOBAL` if possible. + :attr:`!co_names` of the :ref:`code object `. + The compiler tries to use :opcode:`STORE_FAST` or :opcode:`STORE_GLOBAL` if possible. .. opcode:: DELETE_NAME (namei) - Implements ``del name``, where *namei* is the index into :attr:`co_names` - attribute of the code object. + Implements ``del name``, where *namei* is the index into :attr:`!co_names` + attribute of the :ref:`code object `. .. opcode:: UNPACK_SEQUENCE (count) @@ -897,7 +897,8 @@ iterations of the loop. value = STACK.pop() obj.name = value - where *namei* is the index of name in :attr:`co_names`. + where *namei* is the index of name in :attr:`!co_names` of the + :ref:`code object `. .. opcode:: DELETE_ATTR (namei) @@ -906,7 +907,8 @@ iterations of the loop. obj = STACK.pop() del obj.name - where *namei* is the index of name into :attr:`co_names`. + where *namei* is the index of name into :attr:`!co_names` of the + :ref:`code object `. .. opcode:: STORE_GLOBAL (namei) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 4c2d03eacdc277..362ac752149c05 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1039,12 +1039,14 @@ A few types used internally by the interpreter are exposed to the user. Their definitions may change with future versions of the interpreter, but they are mentioned here for completeness. -.. index:: bytecode, object; code, code object +.. _code-objects: Code objects ^^^^^^^^^^^^ +.. index:: bytecode, object; code, code object + Code objects represent *byte-compiled* executable Python code, or :term:`bytecode`. The difference between a code object and a function object is that the function object contains an explicit reference to the function's globals (the module in diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 2ba307df21d853..13fc06983dac46 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -64,7 +64,6 @@ Doc/library/dbm.rst Doc/library/decimal.rst Doc/library/devmode.rst Doc/library/difflib.rst -Doc/library/dis.rst Doc/library/doctest.rst Doc/library/email.charset.rst Doc/library/email.compat32-message.rst From f90099c3bd8ba74ac69ffd26cbc443ae3ce00e10 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 28 Aug 2023 01:59:48 +0200 Subject: [PATCH 0649/1206] [3.12] gh-107801: Document io.TextIOWrapper.tell (#108265) (#108547) (cherry picked from commit 38afa4af9bfc8297a5ee270c37f3f120a04297ea) --- Doc/library/io.rst | 10 +++++++++- Modules/_io/clinic/textio.c.h | 8 ++++++-- Modules/_io/textio.c | 7 ++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 792bf43d9811bb..25f4d0d5841333 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -1054,13 +1054,21 @@ Text I/O * ``seek(0, SEEK_SET)``: Rewind to the start of the stream. * ``seek(cookie, SEEK_SET)``: Restore a previous position; - *cookie* **must be** a number returned by :meth:`!tell`. + *cookie* **must be** a number returned by :meth:`tell`. * ``seek(0, SEEK_END)``: Fast-forward to the end of the stream. * ``seek(0, SEEK_CUR)``: Leave the current stream position unchanged. Any other argument combinations are invalid, and may raise exceptions. + .. method:: tell() + + Return the stream position as an opaque number. + The return value of :meth:`!tell` can be given as input to :meth:`seek`, + to restore a previous stream position. + + + .. class:: StringIO(initial_value='', newline='\n') A text stream using an in-memory text buffer. It inherits diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 63ec56311e2a63..4a3c133068df1d 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -815,7 +815,11 @@ _io_TextIOWrapper_seek(textio *self, PyObject *const *args, Py_ssize_t nargs) PyDoc_STRVAR(_io_TextIOWrapper_tell__doc__, "tell($self, /)\n" "--\n" -"\n"); +"\n" +"Return the stream position as an opaque number.\n" +"\n" +"The return value of tell() can be given as input to seek(), to restore a\n" +"previous stream position."); #define _IO_TEXTIOWRAPPER_TELL_METHODDEF \ {"tell", (PyCFunction)_io_TextIOWrapper_tell, METH_NOARGS, _io_TextIOWrapper_tell__doc__}, @@ -978,4 +982,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=fc02f9e59bfa9956 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a3614e1c64747ff5 input=a9049054013a1b77]*/ diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index ff6023c8ef9283..e8bf6bebad5509 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -2650,11 +2650,16 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) /*[clinic input] _io.TextIOWrapper.tell + +Return the stream position as an opaque number. + +The return value of tell() can be given as input to seek(), to restore a +previous stream position. [clinic start generated code]*/ static PyObject * _io_TextIOWrapper_tell_impl(textio *self) -/*[clinic end generated code: output=4f168c08bf34ad5f input=9a2caf88c24f9ddf]*/ +/*[clinic end generated code: output=4f168c08bf34ad5f input=0852d627d76fb520]*/ { PyObject *res; PyObject *posobj = NULL; From 5531d03d99c980d29915923e6c93028b4af083b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:24:41 -0700 Subject: [PATCH 0650/1206] [3.12] Fix typo in typing docs: Remove redundant backtick (GH-108559) (#108560) Fix typo in typing docs: Remove redundant backtick (GH-108559) (cherry picked from commit 72b615ab015ccff8a92e22c5b5f97fa8aca3ba1f) Co-authored-by: nikkie --- Doc/library/typing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index d060066c0cdea1..f36dc76c3232f7 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -462,7 +462,7 @@ contrast, a variable annotated with ``type[C]`` (or themselves -- specifically, it will accept the *class object* of ``C``. For example:: - a = 3 # Has type ``int``` + a = 3 # Has type ``int`` b = int # Has type ``type[int]`` c = type(a) # Also has type ``type[int]`` From b451e9020df6414e8c51e4e0acd41f855b8742cd Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 29 Aug 2023 00:25:35 +0200 Subject: [PATCH 0651/1206] [3.12] gh-64662: Fix virtual table support in sqlite3.Connection.iterdump (#108340) (#108563) * [3.12] gh-64662: Add virtual table support to sqlite3.Connection.iterdump (#108340) (cherry picked from commit d0160c7c22c8dff0a61c49b5304244df6e36465e) Co-authored-by: Aviv Palivoda * The _quote_value helper is not part of 3.12; spell out the replacement * With quotes * Ok, let's use explicit quoting --------- Co-authored-by: Aviv Palivoda --- Lib/sqlite3/dump.py | 20 ++++++++++++------- Lib/test/test_sqlite3/test_dump.py | 20 +++++++++++++++++++ ...3-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst | 2 ++ 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 07b9da10b920f9..1cf8759f8970f1 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -16,6 +16,7 @@ def _iterdump(connection): directly but instead called from the Connection method, iterdump(). """ + writeable_schema = False cu = connection.cursor() yield('BEGIN TRANSACTION;') @@ -42,13 +43,15 @@ def _iterdump(connection): yield('ANALYZE "sqlite_master";') elif table_name.startswith('sqlite_'): continue - # NOTE: Virtual table support not implemented - #elif sql.startswith('CREATE VIRTUAL TABLE'): - # qtable = table_name.replace("'", "''") - # yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\ - # "VALUES('table','{0}','{0}',0,'{1}');".format( - # qtable, - # sql.replace("''"))) + elif sql.startswith('CREATE VIRTUAL TABLE'): + if not writeable_schema: + writeable_schema = True + yield('PRAGMA writable_schema=ON;') + yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" + "VALUES('table','{0}','{0}',0,'{1}');".format( + table_name.replace("'", "''"), + sql.replace("'", "''"), + )) else: yield('{0};'.format(sql)) @@ -74,6 +77,9 @@ def _iterdump(connection): for name, type, sql in schema_res.fetchall(): yield('{0};'.format(sql)) + if writeable_schema: + yield('PRAGMA writable_schema=OFF;') + # gh-79009: Yield statements concerning the sqlite_sequence table at the # end of the transaction. for row in sqlite_sequence: diff --git a/Lib/test/test_sqlite3/test_dump.py b/Lib/test/test_sqlite3/test_dump.py index d0c24b9c60e613..c3ed3aefef0445 100644 --- a/Lib/test/test_sqlite3/test_dump.py +++ b/Lib/test/test_sqlite3/test_dump.py @@ -117,6 +117,26 @@ def __getitem__(self, index): got = list(self.cx.iterdump()) self.assertEqual(expected, got) + def test_dump_virtual_tables(self): + # gh-64662 + expected = [ + "BEGIN TRANSACTION;", + "PRAGMA writable_schema=ON;", + ("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)" + "VALUES('table','test','test',0,'CREATE VIRTUAL TABLE test USING fts4(example)');"), + "CREATE TABLE 'test_content'(docid INTEGER PRIMARY KEY, 'c0example');", + "CREATE TABLE 'test_docsize'(docid INTEGER PRIMARY KEY, size BLOB);", + ("CREATE TABLE 'test_segdir'(level INTEGER,idx INTEGER,start_block INTEGER," + "leaves_end_block INTEGER,end_block INTEGER,root BLOB,PRIMARY KEY(level, idx));"), + "CREATE TABLE 'test_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", + "CREATE TABLE 'test_stat'(id INTEGER PRIMARY KEY, value BLOB);", + "PRAGMA writable_schema=OFF;", + "COMMIT;" + ] + self.cu.execute("CREATE VIRTUAL TABLE test USING fts4(example)") + actual = list(self.cx.iterdump()) + self.assertEqual(expected, actual) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst b/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst new file mode 100644 index 00000000000000..1b4c33a82b0b86 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst @@ -0,0 +1,2 @@ +Fix support for virtual tables in :meth:`sqlite3.Connection.iterdump`. Patch +by Aviv Palivoda. From f5c5f32f5a36398c06611e8e2cbeda08ef777f1d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:26:29 -0700 Subject: [PATCH 0652/1206] [3.12] gh-108550: Speed up sqlite3 tests (GH-108551) (#108566) gh-108550: Speed up sqlite3 tests (GH-108551) Refactor the CLI so we can easily invoke it and mock command-line arguments. Adapt the CLI tests so we no longer have to launch a separate process. Disable the busy handler for all concurrency tests; we have full control over the order of the SQLite C API calls, so we can safely do this. The sqlite3 test suite now completes ~8 times faster than before. (cherry picked from commit 0e8b3fc718c8a1c4de558c553d9e05049c1dbec6) Co-authored-by: Erlend E. Aasland Co-authored-by: Serhiy Storchaka --- Lib/sqlite3/__main__.py | 9 +- Lib/test/test_sqlite3/test_cli.py | 148 +++++++++------------ Lib/test/test_sqlite3/test_dbapi.py | 2 +- Lib/test/test_sqlite3/test_transactions.py | 16 +-- 4 files changed, 74 insertions(+), 101 deletions(-) diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 3228dbc09d502a..10a2e9e0a202a4 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -62,7 +62,7 @@ def runsource(self, source, filename="", symbol="single"): return False -def main(): +def main(*args): parser = ArgumentParser( description="Python sqlite3 CLI", prog="python -m sqlite3", @@ -86,7 +86,7 @@ def main(): version=f"SQLite version {sqlite3.sqlite_version}", help="Print underlying SQLite library version", ) - args = parser.parse_args() + args = parser.parse_args(*args) if args.filename == ":memory:": db_name = "a transient in-memory database" @@ -120,5 +120,8 @@ def main(): finally: con.close() + sys.exit(0) -main() + +if __name__ == "__main__": + main(sys.argv) diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index d374f8ee4fc8d3..e681f5c976b7b4 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -1,42 +1,35 @@ """sqlite3 CLI tests.""" - -import sqlite3 as sqlite -import subprocess -import sys +import sqlite3 import unittest -from test.support import SHORT_TIMEOUT, requires_subprocess +from sqlite3.__main__ import main as cli from test.support.os_helper import TESTFN, unlink +from test.support import captured_stdout, captured_stderr, captured_stdin -@requires_subprocess() class CommandLineInterface(unittest.TestCase): def _do_test(self, *args, expect_success=True): - with subprocess.Popen( - [sys.executable, "-Xutf8", "-m", "sqlite3", *args], - encoding="utf-8", - bufsize=0, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) as proc: - proc.wait() - if expect_success == bool(proc.returncode): - self.fail("".join(proc.stderr)) - stdout = proc.stdout.read() - stderr = proc.stderr.read() - if expect_success: - self.assertEqual(stderr, "") - else: - self.assertEqual(stdout, "") - return stdout, stderr + with ( + captured_stdout() as out, + captured_stderr() as err, + self.assertRaises(SystemExit) as cm + ): + cli(args) + return out.getvalue(), err.getvalue(), cm.exception.code def expect_success(self, *args): - out, _ = self._do_test(*args) + out, err, code = self._do_test(*args) + self.assertEqual(code, 0, + "\n".join([f"Unexpected failure: {args=}", out, err])) + self.assertEqual(err, "") return out def expect_failure(self, *args): - _, err = self._do_test(*args, expect_success=False) + out, err, code = self._do_test(*args, expect_success=False) + self.assertNotEqual(code, 0, + "\n".join([f"Unexpected failure: {args=}", out, err])) + self.assertEqual(out, "") return err def test_cli_help(self): @@ -45,7 +38,7 @@ def test_cli_help(self): def test_cli_version(self): out = self.expect_success("-v") - self.assertIn(sqlite.sqlite_version, out) + self.assertIn(sqlite3.sqlite_version, out) def test_cli_execute_sql(self): out = self.expect_success(":memory:", "select 1") @@ -68,87 +61,68 @@ def test_cli_on_disk_db(self): self.assertIn("(0,)", out) -@requires_subprocess() class InteractiveSession(unittest.TestCase): - TIMEOUT = SHORT_TIMEOUT / 10. MEMORY_DB_MSG = "Connected to a transient in-memory database" PS1 = "sqlite> " PS2 = "... " - def start_cli(self, *args): - return subprocess.Popen( - [sys.executable, "-Xutf8", "-m", "sqlite3", *args], - encoding="utf-8", - bufsize=0, - stdin=subprocess.PIPE, - # Note: the banner is printed to stderr, the prompt to stdout. - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - - def expect_success(self, proc): - proc.wait() - if proc.returncode: - self.fail("".join(proc.stderr)) + def run_cli(self, *args, commands=()): + with ( + captured_stdin() as stdin, + captured_stdout() as stdout, + captured_stderr() as stderr, + self.assertRaises(SystemExit) as cm + ): + for cmd in commands: + stdin.write(cmd + "\n") + stdin.seek(0) + cli(args) + + out = stdout.getvalue() + err = stderr.getvalue() + self.assertEqual(cm.exception.code, 0, + f"Unexpected failure: {args=}\n{out}\n{err}") + return out, err def test_interact(self): - with self.start_cli() as proc: - out, err = proc.communicate(timeout=self.TIMEOUT) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(self.PS1, out) - self.expect_success(proc) + out, err = self.run_cli() + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(self.PS1, out) def test_interact_quit(self): - with self.start_cli() as proc: - out, err = proc.communicate(input=".quit", timeout=self.TIMEOUT) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(self.PS1, out) - self.expect_success(proc) + out, err = self.run_cli(commands=(".quit",)) + self.assertIn(self.PS1, out) def test_interact_version(self): - with self.start_cli() as proc: - out, err = proc.communicate(input=".version", timeout=self.TIMEOUT) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(sqlite.sqlite_version, out) - self.expect_success(proc) + out, err = self.run_cli(commands=(".version",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(sqlite3.sqlite_version, out) def test_interact_valid_sql(self): - with self.start_cli() as proc: - out, err = proc.communicate(input="select 1;", - timeout=self.TIMEOUT) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn("(1,)", out) - self.expect_success(proc) + out, err = self.run_cli(commands=("SELECT 1;",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn("(1,)", out) def test_interact_valid_multiline_sql(self): - with self.start_cli() as proc: - out, err = proc.communicate(input="select 1\n;", - timeout=self.TIMEOUT) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(self.PS2, out) - self.assertIn("(1,)", out) - self.expect_success(proc) + out, err = self.run_cli(commands=("SELECT 1\n;",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(self.PS2, out) + self.assertIn("(1,)", out) def test_interact_invalid_sql(self): - with self.start_cli() as proc: - out, err = proc.communicate(input="sel;", timeout=self.TIMEOUT) - self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn("OperationalError (SQLITE_ERROR)", err) - self.expect_success(proc) + out, err = self.run_cli(commands=("sel;",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn("OperationalError (SQLITE_ERROR)", err) def test_interact_on_disk_file(self): self.addCleanup(unlink, TESTFN) - with self.start_cli(TESTFN) as proc: - out, err = proc.communicate(input="create table t(t);", - timeout=self.TIMEOUT) - self.assertIn(TESTFN, err) - self.assertIn(self.PS1, out) - self.expect_success(proc) - with self.start_cli(TESTFN, "select count(t) from t") as proc: - out = proc.stdout.read() - err = proc.stderr.read() - self.assertIn("(0,)", out) - self.expect_success(proc) + + out, err = self.run_cli(TESTFN, commands=("CREATE TABLE t(t);",)) + self.assertIn(TESTFN, err) + self.assertIn(self.PS1, out) + + out, _ = self.run_cli(TESTFN, commands=("SELECT count(t) FROM t;",)) + self.assertIn("(0,)", out) if __name__ == "__main__": diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 328b0467e7fa3d..1a3bb6cc0b44a6 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1871,7 +1871,7 @@ def test_on_conflict_replace(self): @requires_subprocess() class MultiprocessTests(unittest.TestCase): - CONNECTION_TIMEOUT = SHORT_TIMEOUT / 1000. # Defaults to 30 ms + CONNECTION_TIMEOUT = 0 # Disable the busy timeout. def tearDown(self): unlink(TESTFN) diff --git a/Lib/test/test_sqlite3/test_transactions.py b/Lib/test/test_sqlite3/test_transactions.py index 5d211dd47b0b6b..2d7a932796789f 100644 --- a/Lib/test/test_sqlite3/test_transactions.py +++ b/Lib/test/test_sqlite3/test_transactions.py @@ -24,22 +24,20 @@ import sqlite3 as sqlite from contextlib import contextmanager -from test.support import LOOPBACK_TIMEOUT from test.support.os_helper import TESTFN, unlink from test.support.script_helper import assert_python_ok from test.test_sqlite3.test_dbapi import memory_database -TIMEOUT = LOOPBACK_TIMEOUT / 10 - - class TransactionTests(unittest.TestCase): def setUp(self): - self.con1 = sqlite.connect(TESTFN, timeout=TIMEOUT) + # We can disable the busy handlers, since we control + # the order of SQLite C API operations. + self.con1 = sqlite.connect(TESTFN, timeout=0) self.cur1 = self.con1.cursor() - self.con2 = sqlite.connect(TESTFN, timeout=TIMEOUT) + self.con2 = sqlite.connect(TESTFN, timeout=0) self.cur2 = self.con2.cursor() def tearDown(self): @@ -119,10 +117,8 @@ def test_raise_timeout(self): self.cur2.execute("insert into test(i) values (5)") def test_locking(self): - """ - This tests the improved concurrency with pysqlite 2.3.4. You needed - to roll back con2 before you could commit con1. - """ + # This tests the improved concurrency with pysqlite 2.3.4. You needed + # to roll back con2 before you could commit con1. self.cur1.execute("create table test(i)") self.cur1.execute("insert into test(i) values (5)") with self.assertRaises(sqlite.OperationalError): From 7c7b2bfb3f5173936443f3f270788dd6d8f2c7cc Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Mon, 28 Aug 2023 23:26:48 +0100 Subject: [PATCH 0653/1206] [3.12] GH-108202: Combine documentation of ``calendar`` constants (GH-108492) (#108579) [3.12] GH-108202: Combine documentation of ``calendar`` constants (GH-108492). (cherry picked from commit 5d936b64796261373429c86cdf90b1d8d8acefba) --- Doc/library/calendar.rst | 109 ++++++++++++++++++--------------------- Doc/whatsnew/3.12.rst | 2 +- 2 files changed, 50 insertions(+), 61 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 3c097f4cf7abd9..1868eb1cd359c4 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -28,58 +28,6 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is 2 BC, and so on. -.. class:: Day - - Enumeration defining the days of the week as integer constants, from 0 to 6. - - .. attribute:: MONDAY - - .. attribute:: TUESDAY - - .. attribute:: WEDNESDAY - - .. attribute:: THURSDAY - - .. attribute:: FRIDAY - - .. attribute:: SATURDAY - - .. attribute:: SUNDAY - - .. versionadded:: 3.12 - - -.. class:: Month - - Enumeration defining months of the year as integer constants, from 1 to 12. - - .. attribute:: JANUARY - - .. attribute:: FEBRUARY - - .. attribute:: MARCH - - .. attribute:: APRIL - - .. attribute:: MAY - - .. attribute:: JUNE - - .. attribute:: JULY - - .. attribute:: AUGUST - - .. attribute:: SEPTEMBER - - .. attribute:: OCTOBER - - .. attribute:: NOVEMBER - - .. attribute:: DECEMBER - - .. versionadded:: 3.12 - - .. class:: Calendar(firstweekday=0) Creates a :class:`Calendar` object. *firstweekday* is an integer specifying the @@ -446,6 +394,29 @@ The :mod:`calendar` module exports the following data attributes: An array that represents the abbreviated days of the week in the current locale. +.. data:: MONDAY + TUESDAY + WEDNESDAY + THURSDAY + FRIDAY + SATURDAY + SUNDAY + + Aliases for the days of the week, + where ``MONDAY`` is ``0`` and ``SUNDAY`` is ``6``. + + .. versionadded:: 3.12 + + +.. class:: Day + + Enumeration defining days of the week as integer constants. + The members of this enumeration are exported to the module scope as + :data:`MONDAY` through :data:`SUNDAY`. + + .. versionadded:: 3.12 + + .. data:: month_name An array that represents the months of the year in the current locale. This @@ -459,15 +430,33 @@ The :mod:`calendar` module exports the following data attributes: locale. This follows normal convention of January being month number 1, so it has a length of 13 and ``month_abbr[0]`` is the empty string. -.. data:: MONDAY - TUESDAY - WEDNESDAY - THURSDAY - FRIDAY - SATURDAY - SUNDAY - Aliases for day numbers, where ``MONDAY`` is ``0`` and ``SUNDAY`` is ``6``. +.. data:: JANUARY + FEBRUARY + MARCH + APRIL + MAY + JUNE + JULY + AUGUST + SEPTEMBER + OCTOBER + NOVEMBER + DECEMBER + + Aliases for the months of the year, + where ``JANUARY`` is ``1`` and ``DECEMBER`` is ``12``. + + .. versionadded:: 3.12 + + +.. class:: Month + + Enumeration defining months of the year as integer constants. + The members of this enumeration are exported to the module scope as + :data:`JANUARY` through :data:`DECEMBER`. + + .. versionadded:: 3.12 The :mod:`calendar` module defines the following exceptions: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index dca4fd999621d0..d0326e05f78ea9 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1014,7 +1014,7 @@ Deprecated (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) * :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are deprecated and - replaced by :data:`calendar.Month.JANUARY` and :data:`calendar.Month.FEBRUARY`. + replaced by :data:`calendar.JANUARY` and :data:`calendar.FEBRUARY`. (Contributed by Prince Roshan in :gh:`103636`.) * :mod:`datetime`: :class:`datetime.datetime`'s :meth:`~datetime.datetime.utcnow` and From ae9bbd16d8f093304168f0058282df930a04f710 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Aug 2023 03:38:03 -0700 Subject: [PATCH 0654/1206] [3.12] Fix misc doc typos (GH-108592) (#108594) Fix misc doc typos (GH-108592) (cherry picked from commit 88f1c5b454c34efc167a94b5e2d67ec042834e5b) Co-authored-by: xzmeng --- Doc/c-api/stable.rst | 2 +- Doc/c-api/typeobj.rst | 2 +- Doc/library/idle.rst | 2 +- Doc/library/importlib.rst | 2 +- Doc/library/sqlite3.rst | 2 +- Doc/library/statistics.rst | 2 +- Doc/library/tkinter.rst | 2 +- Doc/using/configure.rst | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst index c66b296d304adc..63a100a6f26f24 100644 --- a/Doc/c-api/stable.rst +++ b/Doc/c-api/stable.rst @@ -18,7 +18,7 @@ way; see :ref:`stable-abi-platform` below). So, code compiled for Python 3.10.0 will work on 3.10.8 and vice versa, but will need to be compiled separately for 3.9.x and 3.10.x. -There are two tiers of C API with different stability exepectations: +There are two tiers of C API with different stability expectations: - :ref:`Unstable API `, may change in minor versions without a deprecation period. It is marked by the ``PyUnstable`` prefix in names. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index cd037b4de882e1..0988090194a5fe 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1728,7 +1728,7 @@ and :c:data:`PyType_Type` effectively act as defaults.) treated as read-only. Some types may not store their dictionary in this slot. - Use :c:func:`PyType_GetDict` to retreive the dictionary for an arbitrary + Use :c:func:`PyType_GetDict` to retrieve the dictionary for an arbitrary type. .. versionchanged:: 3.12 diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index 3058bcead661f3..3211da50dc745c 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -479,7 +479,7 @@ Search and Replace Any selection becomes a search target. However, only selections within a line work because searches are only performed within lines with the -terminal newline removed. If ``[x] Regular expresion`` is checked, the +terminal newline removed. If ``[x] Regular expression`` is checked, the target is interpreted according to the Python re module. .. _completions: diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 1d378dbbdace5d..d8cc7079a1d812 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -1270,7 +1270,7 @@ an :term:`importer`. You can get the same effect as this function by implementing the basic interface of multi-phase init (:pep:`489`) and lying about - support for mulitple interpreters (or per-interpreter GIL). + support for multiple interpreters (or per-interpreter GIL). .. warning:: Using this function to disable the check can lead to diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 93ca46811f1c0a..d5afaa1c4c9557 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1547,7 +1547,7 @@ Cursor objects :raises ProgrammingError: If *sql* contains more than one SQL statement, - or is not a DML statment. + or is not a DML statement. Example: diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index 483ebea67f0c6d..6e6ca7cef3391f 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -1086,7 +1086,7 @@ parameter, ``h``, representing the variance of the kernel function. import math def kde_normal(sample, h): - "Create a continous probability density function from a sample." + "Create a continuous probability density function from a sample." # Smooth the sample with a normal distribution of variance h. kernel_h = NormalDist(0.0, math.sqrt(h)).pdf n = len(sample) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 2aa34422703872..246abf374b0219 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -352,7 +352,7 @@ Understanding How Tkinter Wraps Tcl/Tk When your application uses Tkinter's classes and methods, internally Tkinter is assembling strings representing Tcl/Tk commands, and executing those -commands in the Tcl interpreter attached to your applicaton's :class:`Tk` +commands in the Tcl interpreter attached to your application's :class:`Tk` instance. Whether it's trying to navigate reference documentation, trying to find diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index f4adea82a87c38..791d3ad7f4071a 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -221,7 +221,7 @@ Install Options Install architecture-independent files in PREFIX. On Unix, it defaults to :file:`/usr/local`. - This value can be retrived at runtime using :data:`sys.prefix`. + This value can be retrieved at runtime using :data:`sys.prefix`. As an example, one can use ``--prefix="$HOME/.local/"`` to install a Python in its home directory. @@ -230,7 +230,7 @@ Install Options Install architecture-dependent files in EPREFIX, defaults to :option:`--prefix`. - This value can be retrived at runtime using :data:`sys.exec_prefix`. + This value can be retrieved at runtime using :data:`sys.exec_prefix`. .. cmdoption:: --disable-test-modules From c942faead250c0e28d20400a5b4734f96e3e21ae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Aug 2023 03:40:05 -0700 Subject: [PATCH 0655/1206] [3.12] GH-106176, GH-104702: Fix reference leak when importing across multiple threads (GH-108497) (#108612) GH-106176, GH-104702: Fix reference leak when importing across multiple threads (GH-108497) (cherry picked from commit 5f85b443f7119e1c68a15fc9a342655e544d2852) Co-authored-by: Brett Cannon --- Lib/importlib/_bootstrap.py | 115 ++++++++++++++++-- ...-08-25-14-51-06.gh-issue-106176.D1EA2a.rst | 4 + 2 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index c48fd506a0e4eb..ec2e56f6ea9ca1 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -51,18 +51,106 @@ def _new_module(name): # Module-level locking ######################################################## -# A dict mapping module names to weakrefs of _ModuleLock instances -# Dictionary protected by the global import lock +# For a list that can have a weakref to it. +class _List(list): + pass + + +# Copied from weakref.py with some simplifications and modifications unique to +# bootstrapping importlib. Many methods were simply deleting for simplicity, so if they +# are needed in the future they may work if simply copied back in. +class _WeakValueDictionary: + + def __init__(self): + self_weakref = _weakref.ref(self) + + # Inlined to avoid issues with inheriting from _weakref.ref before _weakref is + # set by _setup(). Since there's only one instance of this class, this is + # not expensive. + class KeyedRef(_weakref.ref): + + __slots__ = "key", + + def __new__(type, ob, key): + self = super().__new__(type, ob, type.remove) + self.key = key + return self + + def __init__(self, ob, key): + super().__init__(ob, self.remove) + + @staticmethod + def remove(wr): + nonlocal self_weakref + + self = self_weakref() + if self is not None: + if self._iterating: + self._pending_removals.append(wr.key) + else: + _weakref._remove_dead_weakref(self.data, wr.key) + + self._KeyedRef = KeyedRef + self.clear() + + def clear(self): + self._pending_removals = [] + self._iterating = set() + self.data = {} + + def _commit_removals(self): + pop = self._pending_removals.pop + d = self.data + while True: + try: + key = pop() + except IndexError: + return + _weakref._remove_dead_weakref(d, key) + + def get(self, key, default=None): + if self._pending_removals: + self._commit_removals() + try: + wr = self.data[key] + except KeyError: + return default + else: + if (o := wr()) is None: + return default + else: + return o + + def setdefault(self, key, default=None): + try: + o = self.data[key]() + except KeyError: + o = None + if o is None: + if self._pending_removals: + self._commit_removals() + self.data[key] = self._KeyedRef(default, key) + return default + else: + return o + + +# A dict mapping module names to weakrefs of _ModuleLock instances. +# Dictionary protected by the global import lock. _module_locks = {} -# A dict mapping thread IDs to lists of _ModuleLock instances. This maps a -# thread to the module locks it is blocking on acquiring. The values are -# lists because a single thread could perform a re-entrant import and be "in -# the process" of blocking on locks for more than one module. A thread can -# be "in the process" because a thread cannot actually block on acquiring -# more than one lock but it can have set up bookkeeping that reflects that -# it intends to block on acquiring more than one lock. -_blocking_on = {} +# A dict mapping thread IDs to weakref'ed lists of _ModuleLock instances. +# This maps a thread to the module locks it is blocking on acquiring. The +# values are lists because a single thread could perform a re-entrant import +# and be "in the process" of blocking on locks for more than one module. A +# thread can be "in the process" because a thread cannot actually block on +# acquiring more than one lock but it can have set up bookkeeping that reflects +# that it intends to block on acquiring more than one lock. +# +# The dictionary uses a WeakValueDictionary to avoid keeping unnecessary +# lists around, regardless of GC runs. This way there's no memory leak if +# the list is no longer needed (GH-106176). +_blocking_on = None class _BlockingOnManager: @@ -79,7 +167,7 @@ def __enter__(self): # re-entrant (i.e., a single thread may take it more than once) so it # wouldn't help us be correct in the face of re-entrancy either. - self.blocked_on = _blocking_on.setdefault(self.thread_id, []) + self.blocked_on = _blocking_on.setdefault(self.thread_id, _List()) self.blocked_on.append(self.lock) def __exit__(self, *args, **kwargs): @@ -1409,7 +1497,7 @@ def _setup(sys_module, _imp_module): modules, those two modules must be explicitly passed in. """ - global _imp, sys + global _imp, sys, _blocking_on _imp = _imp_module sys = sys_module @@ -1437,6 +1525,9 @@ def _setup(sys_module, _imp_module): builtin_module = sys.modules[builtin_name] setattr(self_module, builtin_name, builtin_module) + # Instantiation requires _weakref to have been set. + _blocking_on = _WeakValueDictionary() + def _install(sys_module, _imp_module): """Install importers for builtin and frozen modules""" diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst new file mode 100644 index 00000000000000..7f63d1086ea39e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst @@ -0,0 +1,4 @@ +Use a ``WeakValueDictionary`` to track the lists containing the modules each +thread is currently importing. This helps avoid a reference leak from +keeping the list around longer than necessary. Weakrefs are used as GC can't +interrupt the cleanup. From cdca4af6c2cbd8b19d98dad7cc380f0a2d8a4de8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Aug 2023 03:54:35 -0700 Subject: [PATCH 0656/1206] [3.12] gh-108550: Fix sqlite3 CLI regression from gh-108551 (GH-108618) (#108621) gh-108550: Fix sqlite3 CLI regression from gh-108551 (GH-108618) (cherry picked from commit c8847841cc5629cbceead0c09dc6f537d7b92612) Co-authored-by: Erlend E. Aasland --- Lib/sqlite3/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 10a2e9e0a202a4..3b59763375c147 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -124,4 +124,4 @@ def main(*args): if __name__ == "__main__": - main(sys.argv) + main(sys.argv[1:]) From 1478a386e6540a7db46a20a45dd6b137bd30b585 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Aug 2023 11:29:52 -0700 Subject: [PATCH 0657/1206] [3.12] gh-108558: Improve sqlite3 row factory tests (GH-108578) (#108615) * gh-108558: Improve sqlite3 row factory tests (GH-108578) Add test_sqlite_row_keys() to explicitly test sqlite3.Row.keys(). Cleanups: - Reduce test noise by converting docstrings to regular comments - Reduce boilerplate code by adding a setUp() method to RowFactoryTests (cherry picked from commit 6eaddc10e972273c1aed8b88c538e65e4773496e) Co-authored-by: Edward Schauman-Haigh <142528725+EddInSverige@users.noreply.github.com> Co-authored-by: Erlend E. Aasland * Fix backport --------- Co-authored-by: Edward Schauman-Haigh <142528725+EddInSverige@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- Lib/test/test_sqlite3/test_factory.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py index 7c36135ecadccd..62909842388e04 100644 --- a/Lib/test/test_sqlite3/test_factory.py +++ b/Lib/test/test_sqlite3/test_factory.py @@ -111,6 +111,7 @@ def tearDown(self): class RowFactoryTests(unittest.TestCase): def setUp(self): self.con = sqlite.connect(":memory:") + self.con.row_factory = sqlite.Row def test_custom_factory(self): self.con.row_factory = lambda cur, row: list(row) @@ -118,7 +119,6 @@ def test_custom_factory(self): self.assertIsInstance(row, list) def test_sqlite_row_index(self): - self.con.row_factory = sqlite.Row row = self.con.execute("select 1 as a_1, 2 as b").fetchone() self.assertIsInstance(row, sqlite.Row) @@ -149,7 +149,6 @@ def test_sqlite_row_index(self): row[complex()] # index must be int or string def test_sqlite_row_index_unicode(self): - self.con.row_factory = sqlite.Row row = self.con.execute("select 1 as \xff").fetchone() self.assertEqual(row["\xff"], 1) with self.assertRaises(IndexError): @@ -159,7 +158,6 @@ def test_sqlite_row_index_unicode(self): def test_sqlite_row_slice(self): # A sqlite.Row can be sliced like a list. - self.con.row_factory = sqlite.Row row = self.con.execute("select 1, 2, 3, 4").fetchone() self.assertEqual(row[0:0], ()) self.assertEqual(row[0:1], (1,)) @@ -176,8 +174,7 @@ def test_sqlite_row_slice(self): self.assertEqual(row[3:0:-2], (4, 2)) def test_sqlite_row_iter(self): - """Checks if the row object is iterable""" - self.con.row_factory = sqlite.Row + # Checks if the row object is iterable. row = self.con.execute("select 1 as a, 2 as b").fetchone() # Is iterable in correct order and produces valid results: @@ -189,23 +186,20 @@ def test_sqlite_row_iter(self): self.assertEqual(items, [1, 2]) def test_sqlite_row_as_tuple(self): - """Checks if the row object can be converted to a tuple""" - self.con.row_factory = sqlite.Row + # Checks if the row object can be converted to a tuple. row = self.con.execute("select 1 as a, 2 as b").fetchone() t = tuple(row) self.assertEqual(t, (row['a'], row['b'])) def test_sqlite_row_as_dict(self): - """Checks if the row object can be correctly converted to a dictionary""" - self.con.row_factory = sqlite.Row + # Checks if the row object can be correctly converted to a dictionary. row = self.con.execute("select 1 as a, 2 as b").fetchone() d = dict(row) self.assertEqual(d["a"], row["a"]) self.assertEqual(d["b"], row["b"]) def test_sqlite_row_hash_cmp(self): - """Checks if the row object compares and hashes correctly""" - self.con.row_factory = sqlite.Row + # Checks if the row object compares and hashes correctly. row_1 = self.con.execute("select 1 as a, 2 as b").fetchone() row_2 = self.con.execute("select 1 as a, 2 as b").fetchone() row_3 = self.con.execute("select 1 as a, 3 as b").fetchone() @@ -238,21 +232,24 @@ def test_sqlite_row_hash_cmp(self): self.assertEqual(hash(row_1), hash(row_2)) def test_sqlite_row_as_sequence(self): - """ Checks if the row object can act like a sequence """ - self.con.row_factory = sqlite.Row + # Checks if the row object can act like a sequence. row = self.con.execute("select 1 as a, 2 as b").fetchone() as_tuple = tuple(row) self.assertEqual(list(reversed(row)), list(reversed(as_tuple))) self.assertIsInstance(row, Sequence) + def test_sqlite_row_keys(self): + # Checks if the row object can return a list of columns as strings. + row = self.con.execute("select 1 as a, 2 as b").fetchone() + self.assertEqual(row.keys(), ['a', 'b']) + def test_fake_cursor_class(self): # Issue #24257: Incorrect use of PyObject_IsInstance() caused # segmentation fault. # Issue #27861: Also applies for cursor factory. class FakeCursor(str): __class__ = sqlite.Cursor - self.con.row_factory = sqlite.Row self.assertRaises(TypeError, self.con.cursor, FakeCursor) self.assertRaises(TypeError, sqlite.Row, FakeCursor(), ()) From 4afc5d87161c7f079600380b3ef4579d9102ba97 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 29 Aug 2023 11:30:23 -0700 Subject: [PATCH 0658/1206] [3.12] gh-108617: Extend interactive session tests for sqlite3 (GH-108556) (#108626) gh-108617: Extend interactive session tests for sqlite3 (GH-108556) (cherry picked from commit ecb2bf02a4a564b638f756ce6e644ec17b6edf16) Co-authored-by: Serhiy Storchaka --- Lib/test/test_sqlite3/test_cli.py | 38 ++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_sqlite3/test_cli.py b/Lib/test/test_sqlite3/test_cli.py index e681f5c976b7b4..303f9e03b5383f 100644 --- a/Lib/test/test_sqlite3/test_cli.py +++ b/Lib/test/test_sqlite3/test_cli.py @@ -87,42 +87,68 @@ def run_cli(self, *args, commands=()): def test_interact(self): out, err = self.run_cli() self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn(self.PS1, out) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertTrue(out.endswith(self.PS1)) + self.assertEqual(out.count(self.PS1), 1) + self.assertEqual(out.count(self.PS2), 0) def test_interact_quit(self): out, err = self.run_cli(commands=(".quit",)) - self.assertIn(self.PS1, out) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertTrue(out.endswith(self.PS1)) + self.assertEqual(out.count(self.PS1), 1) + self.assertEqual(out.count(self.PS2), 0) def test_interact_version(self): out, err = self.run_cli(commands=(".version",)) self.assertIn(self.MEMORY_DB_MSG, err) + self.assertIn(sqlite3.sqlite_version + "\n", out) + self.assertTrue(out.endswith(self.PS1)) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) self.assertIn(sqlite3.sqlite_version, out) def test_interact_valid_sql(self): out, err = self.run_cli(commands=("SELECT 1;",)) self.assertIn(self.MEMORY_DB_MSG, err) - self.assertIn("(1,)", out) + self.assertIn("(1,)\n", out) + self.assertTrue(out.endswith(self.PS1)) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) + + def test_interact_incomplete_multiline_sql(self): + out, err = self.run_cli(commands=("SELECT 1",)) + self.assertIn(self.MEMORY_DB_MSG, err) + self.assertTrue(out.endswith(self.PS2)) + self.assertEqual(out.count(self.PS1), 1) + self.assertEqual(out.count(self.PS2), 1) def test_interact_valid_multiline_sql(self): out, err = self.run_cli(commands=("SELECT 1\n;",)) self.assertIn(self.MEMORY_DB_MSG, err) self.assertIn(self.PS2, out) - self.assertIn("(1,)", out) + self.assertIn("(1,)\n", out) + self.assertTrue(out.endswith(self.PS1)) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 1) def test_interact_invalid_sql(self): out, err = self.run_cli(commands=("sel;",)) self.assertIn(self.MEMORY_DB_MSG, err) self.assertIn("OperationalError (SQLITE_ERROR)", err) + self.assertTrue(out.endswith(self.PS1)) + self.assertEqual(out.count(self.PS1), 2) + self.assertEqual(out.count(self.PS2), 0) def test_interact_on_disk_file(self): self.addCleanup(unlink, TESTFN) out, err = self.run_cli(TESTFN, commands=("CREATE TABLE t(t);",)) self.assertIn(TESTFN, err) - self.assertIn(self.PS1, out) + self.assertTrue(out.endswith(self.PS1)) out, _ = self.run_cli(TESTFN, commands=("SELECT count(t) FROM t;",)) - self.assertIn("(0,)", out) + self.assertIn("(0,)\n", out) if __name__ == "__main__": From 036dd6958a14014947904914065119123430df95 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 29 Aug 2023 22:19:08 +0200 Subject: [PATCH 0659/1206] [3.12] gh-107801: Improve the accuracy of io.IOBase.seek docs (#108268) (#108655) (cherry picked from commit 8178a88bd81edae87d6974483e4de9b32e808797) - Add param docstrings - Link to os.SEEK_* constants - Mention the return value in the initial paragraph Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/io.rst | 26 ++++++++++++++------------ Modules/_io/clinic/iobase.c.h | 7 ++++++- Modules/_io/iobase.c | 4 +++- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 25f4d0d5841333..01088879218cb4 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -403,20 +403,19 @@ I/O Base Classes Note that it's already possible to iterate on file objects using ``for line in file: ...`` without calling :meth:`!file.readlines`. - .. method:: seek(offset, whence=SEEK_SET, /) + .. method:: seek(offset, whence=os.SEEK_SET, /) - Change the stream position to the given byte *offset*. *offset* is - interpreted relative to the position indicated by *whence*. The default - value for *whence* is :data:`!SEEK_SET`. Values for *whence* are: + Change the stream position to the given byte *offset*, + interpreted relative to the position indicated by *whence*, + and return the new absolute position. + Values for *whence* are: - * :data:`!SEEK_SET` or ``0`` -- start of the stream (the default); + * :data:`os.SEEK_SET` or ``0`` -- start of the stream (the default); *offset* should be zero or positive - * :data:`!SEEK_CUR` or ``1`` -- current stream position; *offset* may - be negative - * :data:`!SEEK_END` or ``2`` -- end of the stream; *offset* is usually - negative - - Return the new absolute position. + * :data:`os.SEEK_CUR` or ``1`` -- current stream position; + *offset* may be negative + * :data:`os.SEEK_END` or ``2`` -- end of the stream; + *offset* is usually negative .. versionadded:: 3.1 The :data:`!SEEK_*` constants. @@ -1061,6 +1060,10 @@ Text I/O Any other argument combinations are invalid, and may raise exceptions. + .. seealso:: + + :data:`os.SEEK_SET`, :data:`os.SEEK_CUR`, and :data:`os.SEEK_END`. + .. method:: tell() Return the stream position as an opaque number. @@ -1068,7 +1071,6 @@ Text I/O to restore a previous stream position. - .. class:: StringIO(initial_value='', newline='\n') A text stream using an in-memory text buffer. It inherits diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 773e0010477053..e29a4f182dc03e 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -14,6 +14,11 @@ PyDoc_STRVAR(_io__IOBase_seek__doc__, "\n" "Change the stream position to the given byte offset.\n" "\n" +" offset\n" +" The stream position, relative to \'whence\'.\n" +" whence\n" +" The relative position to seek from.\n" +"\n" "The offset is interpreted relative to the position indicated by whence.\n" "Values for whence are:\n" "\n" @@ -436,4 +441,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=301b22f8f75ce3dc input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7c2df7a330be8b5b input=a9049054013a1b77]*/ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index bcb498d9c5b5de..bc2c9afa016547 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -83,7 +83,9 @@ iobase_unsupported(_PyIO_State *state, const char *message) _io._IOBase.seek cls: defining_class offset: int(unused=True) + The stream position, relative to 'whence'. whence: int(unused=True, c_default='0') = os.SEEK_SET + The relative position to seek from. / Change the stream position to the given byte offset. @@ -101,7 +103,7 @@ Return the new absolute position. static PyObject * _io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, int Py_UNUSED(offset), int Py_UNUSED(whence)) -/*[clinic end generated code: output=8bd74ea6538ded53 input=8d4e6adcd08292f2]*/ +/*[clinic end generated code: output=8bd74ea6538ded53 input=74211232b363363e]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "seek"); From 1d6d05aa8283a4ad3376ac62189471869bd43826 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 30 Aug 2023 06:20:45 -0700 Subject: [PATCH 0660/1206] [3.12] Mention Ellipsis pickling in the docs (GH-103660) (#108661) Mention Ellipsis pickling in the docs (GH-103660) (cherry picked from commit 14ec0bb7c363def917f768b76f334146a3cddd84) Co-authored-by: sterliakov <50529348+sterliakov@users.noreply.github.com> --- Doc/library/pickle.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index 79476b04cd914d..d6be4ba33fa80b 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -494,7 +494,8 @@ What can be pickled and unpickled? The following types can be pickled: -* ``None``, ``True``, and ``False``; +* built-in constants (``None``, ``True``, ``False``, ``Ellipsis``, and + ``NotImplemented``); * integers, floating-point numbers, complex numbers; From ecabf1e19fb52c2ee27c4ad85dfb49bb6b021fc1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 30 Aug 2023 06:21:05 -0700 Subject: [PATCH 0661/1206] [3.12] gh-108669: unittest: Fix documentation for TestResult.collectedDurations (GH-108670) (#108672) gh-108669: unittest: Fix documentation for TestResult.collectedDurations (GH-108670) (cherry picked from commit 6c484c39beeb66d40ef0a73cc4f1e900ea498cfa) Co-authored-by: Sebastian Rittau --- Doc/library/unittest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 518bf6b13bad54..4c28e8fae8b088 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -2017,7 +2017,7 @@ Loading and running tests .. attribute:: collectedDurations - A list containing 2-tuples of :class:`TestCase` instances and floats + A list containing 2-tuples of test case names and floats representing the elapsed time of each test which was run. .. versionadded:: 3.12 From 2e60d58fff9f7d2212adf9a435d334a85ca74806 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 30 Aug 2023 06:21:32 -0700 Subject: [PATCH 0662/1206] [3.12] Fix typo in multiprocessing docs (GH-108666) (#108677) Fix typo in multiprocessing docs (GH-108666) (cherry picked from commit 38ab0dba801884b0963ef0daa95e94e120a2b524) Co-authored-by: kato8966 <66937409+kato8966@users.noreply.github.com> --- Doc/library/multiprocessing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 2efc08f130af32..38d24a86072970 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2988,7 +2988,7 @@ Global variables Safe importing of main module Make sure that the main module can be safely imported by a new Python - interpreter without causing unintended side effects (such a starting a new + interpreter without causing unintended side effects (such as starting a new process). For example, using the *spawn* or *forkserver* start method From 420db1027b7f8f1ff13bb62cc0579596e7116fd5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 30 Aug 2023 06:21:58 -0700 Subject: [PATCH 0663/1206] [3.12] gh-101100: Fix Sphinx warnings in the Logging Cookbook (GH-108678) (#108680) gh-101100: Fix Sphinx warnings in the Logging Cookbook (GH-108678) (cherry picked from commit c7cef546319c51defa01236469b636b6978b99ab) Co-authored-by: Hugo van Kemenade --- Doc/howto/logging-cookbook.rst | 15 +++++++++++---- Doc/tools/.nitignore | 1 - 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 6ef252d709e735..772973edadd9d8 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -761,7 +761,7 @@ printed on the console; on the server side, you should see something like: Note that there are some security issues with pickle in some scenarios. If these affect you, you can use an alternative serialization scheme by overriding -the :meth:`~handlers.SocketHandler.makePickle` method and implementing your +the :meth:`~SocketHandler.makePickle` method and implementing your alternative there, as well as adapting the above script to use your alternative serialization. @@ -835,6 +835,8 @@ To test these files, do the following in a POSIX environment: You may need to tweak the configuration files in the unlikely event that the configured ports clash with something else in your test environment. +.. currentmodule:: logging + .. _context-info: Adding contextual information to your logging output @@ -1546,7 +1548,7 @@ Sometimes you want to let a log file grow to a certain size, then open a new file and log to that. You may want to keep a certain number of these files, and when that many files have been created, rotate the files so that the number of files and the size of the files both remain bounded. For this usage pattern, the -logging package provides a :class:`~handlers.RotatingFileHandler`:: +logging package provides a :class:`RotatingFileHandler`:: import glob import logging @@ -1594,6 +1596,8 @@ and each time it reaches the size limit it is renamed with the suffix Obviously this example sets the log length much too small as an extreme example. You would want to set *maxBytes* to an appropriate value. +.. currentmodule:: logging + .. _format-styles: Use of alternative formatting styles @@ -1840,6 +1844,7 @@ However, it should be borne in mind that each link in the chain adds run-time overhead to all logging operations, and the technique should only be used when the use of a :class:`Filter` does not provide the desired result. +.. currentmodule:: logging.handlers .. _zeromq-handlers: @@ -1917,6 +1922,8 @@ of queues, for example a ZeroMQ 'subscribe' socket. Here's an example:: :ref:`A more advanced logging tutorial ` +.. currentmodule:: logging + An example dictionary-based configuration ----------------------------------------- @@ -3918,8 +3925,8 @@ that in other languages such as Java and C#, loggers are often static class attributes. However, this pattern doesn't make sense in Python, where the module (and not the class) is the unit of software decomposition. -Adding handlers other than :class:`NullHandler` to a logger in a library -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Adding handlers other than :class:`~logging.NullHandler` to a logger in a library +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Configuring logging by adding handlers, formatters and filters is the responsibility of the application developer, not the library developer. If you diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 13fc06983dac46..1ae878dbd6f790 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -28,7 +28,6 @@ Doc/glossary.rst Doc/howto/descriptor.rst Doc/howto/enum.rst Doc/howto/isolating-extensions.rst -Doc/howto/logging-cookbook.rst Doc/howto/logging.rst Doc/howto/urllib2.rst Doc/library/2to3.rst From 320d398262349d4928031142339ad895a052e83c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 30 Aug 2023 14:18:49 -0700 Subject: [PATCH 0664/1206] [3.12] gh-108520: Fix bad fork detection in nested multiprocessing use case (GH-108568) (#108691) gh-108520: Fix bad fork detection in nested multiprocessing use case (GH-108568) gh-107275 introduced a regression where a SemLock would fail being passed along nested child processes, as the `is_fork_ctx` attribute would be left missing after the first deserialization. --------- (cherry picked from commit add8d45cbe46581b9748909fbbf60fdc8ee8f71e) Co-authored-by: albanD Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Antoine Pitrou --- Lib/multiprocessing/synchronize.py | 8 +++--- Lib/test/_test_multiprocessing.py | 26 +++++++++++++++++++ ...-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst | 3 +++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py index 2328d332123082..3ccbfe311c71f3 100644 --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -50,8 +50,8 @@ class SemLock(object): def __init__(self, kind, value, maxvalue, *, ctx): if ctx is None: ctx = context._default_context.get_context() - self.is_fork_ctx = ctx.get_start_method() == 'fork' - unlink_now = sys.platform == 'win32' or self.is_fork_ctx + self._is_fork_ctx = ctx.get_start_method() == 'fork' + unlink_now = sys.platform == 'win32' or self._is_fork_ctx for i in range(100): try: sl = self._semlock = _multiprocessing.SemLock( @@ -103,7 +103,7 @@ def __getstate__(self): if sys.platform == 'win32': h = context.get_spawning_popen().duplicate_for_child(sl.handle) else: - if self.is_fork_ctx: + if self._is_fork_ctx: raise RuntimeError('A SemLock created in a fork context is being ' 'shared with a process in a spawn context. This is ' 'not supported. Please use the same context to create ' @@ -115,6 +115,8 @@ def __setstate__(self, state): self._semlock = _multiprocessing.SemLock._rebuild(*state) util.debug('recreated blocker with handle %r' % state[0]) self._make_methods() + # Ensure that deserialized SemLock can be serialized again (gh-108520). + self._is_fork_ctx = False @staticmethod def _make_name(): diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 19e1086639bfed..c1e18dd69294b1 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5405,6 +5405,32 @@ def test_mixed_startmethod(self): p.start() p.join() + @classmethod + def _put_one_in_queue(cls, queue): + queue.put(1) + + @classmethod + def _put_two_and_nest_once(cls, queue): + queue.put(2) + process = multiprocessing.Process(target=cls._put_one_in_queue, args=(queue,)) + process.start() + process.join() + + def test_nested_startmethod(self): + # gh-108520: Regression test to ensure that child process can send its + # arguments to another process + queue = multiprocessing.Queue() + + process = multiprocessing.Process(target=self._put_two_and_nest_once, args=(queue,)) + process.start() + process.join() + + results = [] + while not queue.empty(): + results.append(queue.get()) + + self.assertEqual(results, [2, 1]) + @unittest.skipIf(sys.platform == "win32", "test semantics don't make sense on Windows") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst new file mode 100644 index 00000000000000..44131fb11f068c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst @@ -0,0 +1,3 @@ +Fix :meth:`multiprocessing.synchronize.SemLock.__setstate__` to properly initialize :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx`. This fixes a regression when passing a SemLock accross nested processes. + +Rename :attr:`multiprocessing.synchronize.SemLock.is_fork_ctx` to :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx` to avoid exposing it as public API. From 1a15d20b75a1f3ee477c9c49c82bda47aa6a9cd1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 31 Aug 2023 06:32:17 -0700 Subject: [PATCH 0665/1206] [3.12] gh-108654: restore comprehension locals before handling exception (GH-108659) (#108700) gh-108654: restore comprehension locals before handling exception (GH-108659) (cherry picked from commit d52c4482a82f3f98f1a78efa948144a1fe3c52b2) Co-authored-by: Carl Meyer Co-authored-by: Dong-hee Na --- Lib/test/test_listcomps.py | 35 ++++++++++ ...-08-29-17-53-12.gh-issue-108654.jbkDVo.rst | 2 + Python/compile.c | 67 +++++++++++++++---- 3 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 9f28ced32bd26c..bedd99b4a44fcb 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -561,6 +561,41 @@ def test_iter_var_available_in_locals(self): } ) + def test_comp_in_try_except(self): + template = """ + value = ["a"] + try: + [{func}(value) for value in value] + except: + pass + """ + for func in ["str", "int"]: + code = template.format(func=func) + raises = func != "str" + with self.subTest(raises=raises): + self._check_in_scopes(code, {"value": ["a"]}) + + def test_comp_in_try_finally(self): + code = """ + def f(value): + try: + [{func}(value) for value in value] + finally: + return value + ret = f(["a"]) + """ + self._check_in_scopes(code, {"ret": ["a"]}) + + def test_exception_in_post_comp_call(self): + code = """ + value = [1, None] + try: + [v for v in value].sort() + except: + pass + """ + self._check_in_scopes(code, {"value": [1, None]}) + __test__ = {'doctests' : doctests} diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst new file mode 100644 index 00000000000000..032e0331b20e75 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst @@ -0,0 +1,2 @@ +Restore locals shadowed by an inlined comprehension if the comprehension +raises an exception. diff --git a/Python/compile.c b/Python/compile.c index a8d0016a10786a..9395f5229cf866 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5438,6 +5438,8 @@ typedef struct { PyObject *pushed_locals; PyObject *temp_symbols; PyObject *fast_hidden; + jump_target_label cleanup; + jump_target_label end; } inlined_comprehension_state; static int @@ -5543,11 +5545,45 @@ push_inlined_comprehension_state(struct compiler *c, location loc, // `pushed_locals` on the stack, but this will be reversed when we swap // out the comprehension result in pop_inlined_comprehension_state ADDOP_I(c, loc, SWAP, PyList_GET_SIZE(state->pushed_locals) + 1); + + // Add our own cleanup handler to restore comprehension locals in case + // of exception, so they have the correct values inside an exception + // handler or finally block. + NEW_JUMP_TARGET_LABEL(c, cleanup); + state->cleanup = cleanup; + NEW_JUMP_TARGET_LABEL(c, end); + state->end = end; + + // no need to push an fblock for this "virtual" try/finally; there can't + // be return/continue/break inside a comprehension + ADDOP_JUMP(c, loc, SETUP_FINALLY, cleanup); } return SUCCESS; } +static int +restore_inlined_comprehension_locals(struct compiler *c, location loc, + inlined_comprehension_state state) +{ + PyObject *k; + // pop names we pushed to stack earlier + Py_ssize_t npops = PyList_GET_SIZE(state.pushed_locals); + // Preserve the comprehension result (or exception) as TOS. This + // reverses the SWAP we did in push_inlined_comprehension_state to get + // the outermost iterable to TOS, so we can still just iterate + // pushed_locals in simple reverse order + ADDOP_I(c, loc, SWAP, npops + 1); + for (Py_ssize_t i = npops - 1; i >= 0; --i) { + k = PyList_GetItem(state.pushed_locals, i); + if (k == NULL) { + return ERROR; + } + ADDOP_NAME(c, loc, STORE_FAST_MAYBE_NULL, k, varnames); + } + return SUCCESS; +} + static int pop_inlined_comprehension_state(struct compiler *c, location loc, inlined_comprehension_state state) @@ -5564,19 +5600,22 @@ pop_inlined_comprehension_state(struct compiler *c, location loc, Py_CLEAR(state.temp_symbols); } if (state.pushed_locals) { - // pop names we pushed to stack earlier - Py_ssize_t npops = PyList_GET_SIZE(state.pushed_locals); - // Preserve the list/dict/set result of the comprehension as TOS. This - // reverses the SWAP we did in push_inlined_comprehension_state to get - // the outermost iterable to TOS, so we can still just iterate - // pushed_locals in simple reverse order - ADDOP_I(c, loc, SWAP, npops + 1); - for (Py_ssize_t i = npops - 1; i >= 0; --i) { - k = PyList_GetItem(state.pushed_locals, i); - if (k == NULL) { - return ERROR; - } - ADDOP_NAME(c, loc, STORE_FAST_MAYBE_NULL, k, varnames); + ADDOP(c, NO_LOCATION, POP_BLOCK); + ADDOP_JUMP(c, NO_LOCATION, JUMP, state.end); + + // cleanup from an exception inside the comprehension + USE_LABEL(c, state.cleanup); + // discard incomplete comprehension result (beneath exc on stack) + ADDOP_I(c, NO_LOCATION, SWAP, 2); + ADDOP(c, NO_LOCATION, POP_TOP); + if (restore_inlined_comprehension_locals(c, loc, state) < 0) { + return ERROR; + } + ADDOP_I(c, NO_LOCATION, RERAISE, 0); + + USE_LABEL(c, state.end); + if (restore_inlined_comprehension_locals(c, loc, state) < 0) { + return ERROR; } Py_CLEAR(state.pushed_locals); } @@ -5619,7 +5658,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, expr_ty val) { PyCodeObject *co = NULL; - inlined_comprehension_state inline_state = {NULL, NULL}; + inlined_comprehension_state inline_state = {NULL, NULL, NULL, NO_LABEL, NO_LABEL}; comprehension_ty outermost; int scope_type = c->u->u_scope_type; int is_top_level_await = IS_TOP_LEVEL_AWAIT(c); From bc42d6c6042d33a165b92ba61326a3e6aa389cb9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 31 Aug 2023 06:32:39 -0700 Subject: [PATCH 0666/1206] [3.12] gh-101100: Fix sphinx warnings in `threading.rst` (GH-108684) (#108707) gh-101100: Fix sphinx warnings in `threading.rst` (GH-108684) (cherry picked from commit 991e4e76b54b69f227242e73c2ec9d62f903da53) Co-authored-by: Nikita Sobolev Co-authored-by: Hugo van Kemenade --- Doc/library/threading.rst | 16 ++++++++-------- Doc/tools/.nitignore | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index 83ed48052704fb..23d8cd158abd5d 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -272,7 +272,7 @@ The instance's values will be different for separate threads. A class that represents thread-local data. For more details and extensive examples, see the documentation string of the - :mod:`_threading_local` module: :source:`Lib/_threading_local.py`. + :mod:`!_threading_local` module: :source:`Lib/_threading_local.py`. .. _thread-objects: @@ -285,7 +285,7 @@ thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the :meth:`~Thread.run` method in a subclass. No other methods (except for the constructor) should be overridden in a subclass. In other words, *only* override the -:meth:`~Thread.__init__` and :meth:`~Thread.run` methods of this class. +``__init__()`` and :meth:`~Thread.run` methods of this class. Once a thread object is created, its activity must be started by calling the thread's :meth:`~Thread.start` method. This invokes the :meth:`~Thread.run` @@ -337,7 +337,7 @@ since it is impossible to detect the termination of alien threads. are: *group* should be ``None``; reserved for future extension when a - :class:`ThreadGroup` class is implemented. + :class:`!ThreadGroup` class is implemented. *target* is the callable object to be invoked by the :meth:`run` method. Defaults to ``None``, meaning nothing is called. @@ -1009,7 +1009,7 @@ This class represents an action that should be run only after a certain amount of time has passed --- a timer. :class:`Timer` is a subclass of :class:`Thread` and as such also functions as an example of creating custom threads. -Timers are started, as with threads, by calling their :meth:`~Timer.start` +Timers are started, as with threads, by calling their :meth:`Timer.start ` method. The timer can be stopped (before its action has begun) by calling the :meth:`~Timer.cancel` method. The interval the timer will wait before executing its action may not be exactly the same as the interval specified by @@ -1147,10 +1147,10 @@ As an example, here is a simple way to synchronize a client and server thread:: Using locks, conditions, and semaphores in the :keyword:`!with` statement ------------------------------------------------------------------------- -All of the objects provided by this module that have :meth:`acquire` and -:meth:`release` methods can be used as context managers for a :keyword:`with` -statement. The :meth:`acquire` method will be called when the block is -entered, and :meth:`release` will be called when the block is exited. Hence, +All of the objects provided by this module that have ``acquire`` and +``release`` methods can be used as context managers for a :keyword:`with` +statement. The ``acquire`` method will be called when the block is +entered, and ``release`` will be called when the block is exited. Hence, the following snippet:: with some_lock: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 1ae878dbd6f790..765fbe2ca9e240 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -137,7 +137,6 @@ Doc/library/telnetlib.rst Doc/library/tempfile.rst Doc/library/termios.rst Doc/library/test.rst -Doc/library/threading.rst Doc/library/time.rst Doc/library/tkinter.rst Doc/library/tkinter.scrolledtext.rst From a92c60c99bab716d1d08bccb92dcc0fe6ee93abe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:03:02 -0700 Subject: [PATCH 0667/1206] [3.12] gh-97850: Note in py312 whatsnew that `importlib.util.set_loader` and `importlib.util.module_for_loader` have been removed (GH-108719) (#108723) gh-97850: Note in py312 whatsnew that `importlib.util.set_loader` and `importlib.util.module_for_loader` have been removed (GH-108719) Note in py312 whatsnew that `importlib.util.set_loader` and `importlib.util.module_for_loader` have been removed (cherry picked from commit 013a99a47b3299f48cf7f95aa451a116441b029c) Co-authored-by: Alex Waygood --- Doc/whatsnew/3.12.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d0326e05f78ea9..f76f9c465b9121 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1312,8 +1312,9 @@ Removed * References to, and support for :meth:`!module_repr()` has been removed. (Contributed by Barry Warsaw in :gh:`97850`.) - * ``importlib.util.set_package`` has been removed. (Contributed by Brett - Cannon in :gh:`65961`.) + * ``importlib.util.set_package``, ``importlib.util.set_loader`` and + ``importlib.util.module_for_loader`` have all been removed. (Contributed by + Brett Cannon and Nikita Sobolev in :gh:`65961` and :gh:`97850`.) * Support for ``find_loader()`` and ``find_module()`` APIs have been removed. (Contributed by Barry Warsaw in :gh:`98040`.) From 8c3793a539ce950e552da390b7b24485dd655237 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:04:55 -0700 Subject: [PATCH 0668/1206] [3.12] gh-108682: [Enum] raise TypeError if super().__new__ called in custom __new__ (GH-108704) (#108733) gh-108682: [Enum] raise TypeError if super().__new__ called in custom __new__ (GH-108704) When overriding the `__new__` method of an enum, the underlying data type should be created directly; i.e. . member = object.__new__(cls) member = int.__new__(cls, value) member = str.__new__(cls, value) Calling `super().__new__()` finds the lookup version of `Enum.__new__`, and will now raise an exception when detected. (cherry picked from commit d48760b2f1e28dd3c1a35721939f400a8ab619b8) Co-authored-by: Ethan Furman --- Doc/howto/enum.rst | 23 +- Lib/enum.py | 7 + Lib/test/test_enum.py | 284 ++++++++++++++---- ...-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst | 2 + 4 files changed, 260 insertions(+), 56 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 4312b4c8140f5c..28749754a54dba 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -426,10 +426,17 @@ enumeration, with the exception of special methods (:meth:`__str__`, :meth:`__add__`, etc.), descriptors (methods are also descriptors), and variable names listed in :attr:`_ignore_`. -Note: if your enumeration defines :meth:`__new__` and/or :meth:`__init__` then +Note: if your enumeration defines :meth:`__new__` and/or :meth:`__init__`, any value(s) given to the enum member will be passed into those methods. See `Planet`_ for an example. +.. note:: + + The :meth:`__new__` method, if defined, is used during creation of the Enum + members; it is then replaced by Enum's :meth:`__new__` which is used after + class creation for lookup of existing members. See :ref:`new-vs-init` for + more details. + Restricted Enum subclassing --------------------------- @@ -895,6 +902,8 @@ Some rules: :meth:`__str__` method has been reset to their data types' :meth:`__str__` method. +.. _new-vs-init: + When to use :meth:`__new__` vs. :meth:`__init__` ------------------------------------------------ @@ -927,6 +936,11 @@ want one of them to be the value:: >>> print(Coordinate(3)) Coordinate.VY +.. warning:: + + *Do not* call ``super().__new__()``, as the lookup-only ``__new__`` is the one + that is found; instead, use the data type directly. + Finer Points ^^^^^^^^^^^^ @@ -1353,6 +1367,13 @@ to handle any extra arguments:: members; it is then replaced by Enum's :meth:`__new__` which is used after class creation for lookup of existing members. +.. warning:: + + *Do not* call ``super().__new__()``, as the lookup-only ``__new__`` is the one + that is found; instead, use the data type directly -- e.g.:: + + obj = int.__new__(cls, value) + OrderedEnum ^^^^^^^^^^^ diff --git a/Lib/enum.py b/Lib/enum.py index 9114c5ccaaa95c..9c0af9e56d8ee5 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -865,6 +865,8 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s value = first_enum._generate_next_value_(name, start, count, last_values[:]) last_values.append(value) names.append((name, value)) + if names is None: + names = () # Here, names is either an iterable of (name, value) or a mapping. for item in names: @@ -1121,6 +1123,11 @@ def __new__(cls, value): for member in cls._member_map_.values(): if member._value_ == value: return member + # still not found -- verify that members exist, in-case somebody got here mistakenly + # (such as via super when trying to override __new__) + if not cls._member_map_: + raise TypeError("%r has no members defined" % cls) + # # still not found -- try _missing_ hook try: exc = None diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index dbdc639d62ec1f..dc60caccaa435c 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -236,11 +236,82 @@ class _EnumTests: values = None def setUp(self): - class BaseEnum(self.enum_type): + if self.__class__.__name__[-5:] == 'Class': + class BaseEnum(self.enum_type): + @enum.property + def first(self): + return '%s is first!' % self.name + class MainEnum(BaseEnum): + first = auto() + second = auto() + third = auto() + if issubclass(self.enum_type, Flag): + dupe = 3 + else: + dupe = third + self.MainEnum = MainEnum + # + class NewStrEnum(self.enum_type): + def __str__(self): + return self.name.upper() + first = auto() + self.NewStrEnum = NewStrEnum + # + class NewFormatEnum(self.enum_type): + def __format__(self, spec): + return self.name.upper() + first = auto() + self.NewFormatEnum = NewFormatEnum + # + class NewStrFormatEnum(self.enum_type): + def __str__(self): + return self.name.title() + def __format__(self, spec): + return ''.join(reversed(self.name)) + first = auto() + self.NewStrFormatEnum = NewStrFormatEnum + # + class NewBaseEnum(self.enum_type): + def __str__(self): + return self.name.title() + def __format__(self, spec): + return ''.join(reversed(self.name)) + class NewSubEnum(NewBaseEnum): + first = auto() + self.NewSubEnum = NewSubEnum + # + class LazyGNV(self.enum_type): + def _generate_next_value_(name, start, last, values): + pass + self.LazyGNV = LazyGNV + # + class BusyGNV(self.enum_type): + @staticmethod + def _generate_next_value_(name, start, last, values): + pass + self.BusyGNV = BusyGNV + # + self.is_flag = False + self.names = ['first', 'second', 'third'] + if issubclass(MainEnum, StrEnum): + self.values = self.names + elif MainEnum._member_type_ is str: + self.values = ['1', '2', '3'] + elif issubclass(self.enum_type, Flag): + self.values = [1, 2, 4] + self.is_flag = True + self.dupe2 = MainEnum(5) + else: + self.values = self.values or [1, 2, 3] + # + if not getattr(self, 'source_values', False): + self.source_values = self.values + elif self.__class__.__name__[-8:] == 'Function': @enum.property def first(self): return '%s is first!' % self.name - class MainEnum(BaseEnum): + BaseEnum = self.enum_type('BaseEnum', {'first':first}) + # first = auto() second = auto() third = auto() @@ -248,63 +319,60 @@ class MainEnum(BaseEnum): dupe = 3 else: dupe = third - self.MainEnum = MainEnum - # - class NewStrEnum(self.enum_type): + self.MainEnum = MainEnum = BaseEnum('MainEnum', dict(first=first, second=second, third=third, dupe=dupe)) + # def __str__(self): return self.name.upper() first = auto() - self.NewStrEnum = NewStrEnum - # - class NewFormatEnum(self.enum_type): + self.NewStrEnum = self.enum_type('NewStrEnum', (('first',first),('__str__',__str__))) + # def __format__(self, spec): return self.name.upper() first = auto() - self.NewFormatEnum = NewFormatEnum - # - class NewStrFormatEnum(self.enum_type): + self.NewFormatEnum = self.enum_type('NewFormatEnum', [('first',first),('__format__',__format__)]) + # def __str__(self): return self.name.title() def __format__(self, spec): return ''.join(reversed(self.name)) first = auto() - self.NewStrFormatEnum = NewStrFormatEnum - # - class NewBaseEnum(self.enum_type): + self.NewStrFormatEnum = self.enum_type('NewStrFormatEnum', dict(first=first, __format__=__format__, __str__=__str__)) + # def __str__(self): return self.name.title() def __format__(self, spec): return ''.join(reversed(self.name)) - class NewSubEnum(NewBaseEnum): - first = auto() - self.NewSubEnum = NewSubEnum - # - class LazyGNV(self.enum_type): + NewBaseEnum = self.enum_type('NewBaseEnum', dict(__format__=__format__, __str__=__str__)) + class NewSubEnum(NewBaseEnum): + first = auto() + self.NewSubEnum = NewBaseEnum('NewSubEnum', 'first') + # def _generate_next_value_(name, start, last, values): pass - self.LazyGNV = LazyGNV - # - class BusyGNV(self.enum_type): + self.LazyGNV = self.enum_type('LazyGNV', {'_generate_next_value_':_generate_next_value_}) + # @staticmethod def _generate_next_value_(name, start, last, values): pass - self.BusyGNV = BusyGNV - # - self.is_flag = False - self.names = ['first', 'second', 'third'] - if issubclass(MainEnum, StrEnum): - self.values = self.names - elif MainEnum._member_type_ is str: - self.values = ['1', '2', '3'] - elif issubclass(self.enum_type, Flag): - self.values = [1, 2, 4] - self.is_flag = True - self.dupe2 = MainEnum(5) + self.BusyGNV = self.enum_type('BusyGNV', {'_generate_next_value_':_generate_next_value_}) + # + self.is_flag = False + self.names = ['first', 'second', 'third'] + if issubclass(MainEnum, StrEnum): + self.values = self.names + elif MainEnum._member_type_ is str: + self.values = ['1', '2', '3'] + elif issubclass(self.enum_type, Flag): + self.values = [1, 2, 4] + self.is_flag = True + self.dupe2 = MainEnum(5) + else: + self.values = self.values or [1, 2, 3] + # + if not getattr(self, 'source_values', False): + self.source_values = self.values else: - self.values = self.values or [1, 2, 3] - # - if not getattr(self, 'source_values', False): - self.source_values = self.values + raise ValueError('unknown enum style: %r' % self.__class__.__name__) def assertFormatIsValue(self, spec, member): self.assertEqual(spec.format(member), spec.format(member.value)) @@ -332,6 +400,17 @@ def spam(cls): with self.assertRaises(AttributeError): del Season.SPRING.name + def test_bad_new_super(self): + with self.assertRaisesRegex( + TypeError, + 'has no members defined', + ): + class BadSuper(self.enum_type): + def __new__(cls, value): + obj = super().__new__(cls, value) + return obj + failed = 1 + def test_basics(self): TE = self.MainEnum if self.is_flag: @@ -387,7 +466,7 @@ def test_contains_tf(self): MainEnum = self.MainEnum self.assertIn(MainEnum.first, MainEnum) self.assertTrue(self.values[0] in MainEnum) - if type(self) is not TestStrEnum: + if type(self) not in (TestStrEnumClass, TestStrEnumFunction): self.assertFalse('first' in MainEnum) val = MainEnum.dupe self.assertIn(val, MainEnum) @@ -909,15 +988,23 @@ class OpenXYZ(self.enum_type): self.assertTrue(~OpenXYZ(0), (X|Y|Z)) -class TestPlainEnum(_EnumTests, _PlainOutputTests, unittest.TestCase): +class TestPlainEnumClass(_EnumTests, _PlainOutputTests, unittest.TestCase): + enum_type = Enum + + +class TestPlainEnumFunction(_EnumTests, _PlainOutputTests, unittest.TestCase): enum_type = Enum -class TestPlainFlag(_EnumTests, _PlainOutputTests, _FlagTests, unittest.TestCase): +class TestPlainFlagClass(_EnumTests, _PlainOutputTests, _FlagTests, unittest.TestCase): enum_type = Flag -class TestIntEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase): +class TestPlainFlagFunction(_EnumTests, _PlainOutputTests, _FlagTests, unittest.TestCase): + enum_type = Flag + + +class TestIntEnumClass(_EnumTests, _MinimalOutputTests, unittest.TestCase): enum_type = IntEnum # def test_shadowed_attr(self): @@ -929,7 +1016,17 @@ class Number(IntEnum): self.assertIs(Number.numerator.divisor, Number.divisor) -class TestStrEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase): +class TestIntEnumFunction(_EnumTests, _MinimalOutputTests, unittest.TestCase): + enum_type = IntEnum + # + def test_shadowed_attr(self): + Number = IntEnum('Number', ('divisor', 'numerator')) + # + self.assertEqual(Number.divisor.numerator, 1) + self.assertIs(Number.numerator.divisor, Number.divisor) + + +class TestStrEnumClass(_EnumTests, _MinimalOutputTests, unittest.TestCase): enum_type = StrEnum # def test_shadowed_attr(self): @@ -942,64 +1039,141 @@ class Book(StrEnum): self.assertIs(Book.title.author, Book.author) -class TestIntFlag(_EnumTests, _MinimalOutputTests, _FlagTests, unittest.TestCase): +class TestStrEnumFunction(_EnumTests, _MinimalOutputTests, unittest.TestCase): + enum_type = StrEnum + # + def test_shadowed_attr(self): + Book = StrEnum('Book', ('author', 'title')) + # + self.assertEqual(Book.author.title(), 'Author') + self.assertEqual(Book.title.title(), 'Title') + self.assertIs(Book.title.author, Book.author) + + +class TestIntFlagClass(_EnumTests, _MinimalOutputTests, _FlagTests, unittest.TestCase): + enum_type = IntFlag + + +class TestIntFlagFunction(_EnumTests, _MinimalOutputTests, _FlagTests, unittest.TestCase): enum_type = IntFlag -class TestMixedInt(_EnumTests, _MixedOutputTests, unittest.TestCase): +class TestMixedIntClass(_EnumTests, _MixedOutputTests, unittest.TestCase): class enum_type(int, Enum): pass -class TestMixedStr(_EnumTests, _MixedOutputTests, unittest.TestCase): +class TestMixedIntFunction(_EnumTests, _MixedOutputTests, unittest.TestCase): + enum_type = Enum('enum_type', type=int) + + +class TestMixedStrClass(_EnumTests, _MixedOutputTests, unittest.TestCase): class enum_type(str, Enum): pass -class TestMixedIntFlag(_EnumTests, _MixedOutputTests, _FlagTests, unittest.TestCase): +class TestMixedStrFunction(_EnumTests, _MixedOutputTests, unittest.TestCase): + enum_type = Enum('enum_type', type=str) + + +class TestMixedIntFlagClass(_EnumTests, _MixedOutputTests, _FlagTests, unittest.TestCase): class enum_type(int, Flag): pass -class TestMixedDate(_EnumTests, _MixedOutputTests, unittest.TestCase): +class TestMixedIntFlagFunction(_EnumTests, _MixedOutputTests, _FlagTests, unittest.TestCase): + enum_type = Flag('enum_type', type=int) + +class TestMixedDateClass(_EnumTests, _MixedOutputTests, unittest.TestCase): + # values = [date(2021, 12, 25), date(2020, 3, 15), date(2019, 11, 27)] source_values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)] - + # class enum_type(date, Enum): + @staticmethod def _generate_next_value_(name, start, count, last_values): values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)] return values[count] -class TestMinimalDate(_EnumTests, _MinimalOutputTests, unittest.TestCase): +class TestMixedDateFunction(_EnumTests, _MixedOutputTests, unittest.TestCase): + # + values = [date(2021, 12, 25), date(2020, 3, 15), date(2019, 11, 27)] + source_values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)] + # + # staticmethod decorator will be added by EnumType if not present + def _generate_next_value_(name, start, count, last_values): + values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)] + return values[count] + # + enum_type = Enum('enum_type', {'_generate_next_value_':_generate_next_value_}, type=date) + +class TestMinimalDateClass(_EnumTests, _MinimalOutputTests, unittest.TestCase): + # values = [date(2023, 12, 1), date(2016, 2, 29), date(2009, 1, 1)] source_values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)] - + # class enum_type(date, ReprEnum): + # staticmethod decorator will be added by EnumType if absent def _generate_next_value_(name, start, count, last_values): values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)] return values[count] -class TestMixedFloat(_EnumTests, _MixedOutputTests, unittest.TestCase): +class TestMinimalDateFunction(_EnumTests, _MinimalOutputTests, unittest.TestCase): + # + values = [date(2023, 12, 1), date(2016, 2, 29), date(2009, 1, 1)] + source_values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)] + # + @staticmethod + def _generate_next_value_(name, start, count, last_values): + values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)] + return values[count] + # + enum_type = ReprEnum('enum_type', {'_generate_next_value_':_generate_next_value_}, type=date) - values = [1.1, 2.2, 3.3] +class TestMixedFloatClass(_EnumTests, _MixedOutputTests, unittest.TestCase): + # + values = [1.1, 2.2, 3.3] + # class enum_type(float, Enum): def _generate_next_value_(name, start, count, last_values): values = [1.1, 2.2, 3.3] return values[count] -class TestMinimalFloat(_EnumTests, _MinimalOutputTests, unittest.TestCase): +class TestMixedFloatFunction(_EnumTests, _MixedOutputTests, unittest.TestCase): + # + values = [1.1, 2.2, 3.3] + # + def _generate_next_value_(name, start, count, last_values): + values = [1.1, 2.2, 3.3] + return values[count] + # + enum_type = Enum('enum_type', {'_generate_next_value_':_generate_next_value_}, type=float) - values = [4.4, 5.5, 6.6] +class TestMinimalFloatClass(_EnumTests, _MinimalOutputTests, unittest.TestCase): + # + values = [4.4, 5.5, 6.6] + # class enum_type(float, ReprEnum): def _generate_next_value_(name, start, count, last_values): values = [4.4, 5.5, 6.6] return values[count] +class TestMinimalFloatFunction(_EnumTests, _MinimalOutputTests, unittest.TestCase): + # + values = [4.4, 5.5, 6.6] + # + def _generate_next_value_(name, start, count, last_values): + values = [4.4, 5.5, 6.6] + return values[count] + # + enum_type = ReprEnum('enum_type', {'_generate_next_value_':_generate_next_value_}, type=float) + + class TestSpecial(unittest.TestCase): """ various operations that are not attributable to every possible enum diff --git a/Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst b/Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst new file mode 100644 index 00000000000000..148d4329142740 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst @@ -0,0 +1,2 @@ +Enum: raise :exc:`TypeError` if ``super().__new__()`` is called from a +custom ``__new__``. From 1e15c1501c51f03123ec0da3fa430f2286bac40c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 1 Sep 2023 06:32:13 -0700 Subject: [PATCH 0669/1206] [3.12] `ast` docs: Fix incorrect link on `keyword` (GH-108728) (#108737) `ast` docs: Fix incorrect link on `keyword` (GH-108728) In two places, Sphinx was erroneously adding links to the `keyword` module instead of the `ast.keyword` class (cherry picked from commit c1e2f3b2f70b8a72ea7e1bf792addf62a94ae65d) Co-authored-by: Alex Povel --- Doc/library/ast.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 530cf30643687f..9c76443983b155 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -585,7 +585,7 @@ Expressions :class:`Name` or :class:`Attribute` object. Of the arguments: * ``args`` holds a list of the arguments passed by position. - * ``keywords`` holds a list of :class:`keyword` objects representing + * ``keywords`` holds a list of :class:`.keyword` objects representing arguments passed by keyword. When creating a ``Call`` node, ``args`` and ``keywords`` are required, but @@ -2024,7 +2024,7 @@ Function and class definitions * ``name`` is a raw string for the class name * ``bases`` is a list of nodes for explicitly specified base classes. - * ``keywords`` is a list of :class:`keyword` nodes, principally for 'metaclass'. + * ``keywords`` is a list of :class:`.keyword` nodes, principally for 'metaclass'. Other keywords will be passed to the metaclass, as per `PEP-3115 `_. * ``body`` is a list of nodes representing the code within the class From 56683097f4092933545758f020acf173c5cb3926 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 1 Sep 2023 06:32:35 -0700 Subject: [PATCH 0670/1206] [3.12] gh-107805: Fix signatures of module-level generated functions in `turtle` (GH-107807) (#108749) gh-107805: Fix signatures of module-level generated functions in `turtle` (GH-107807) (cherry picked from commit 044b8b3b6a65e6651b161e3badfa5d57c666db19) Co-authored-by: Nikita Sobolev Co-authored-by: Alex Waygood --- Lib/test/test_turtle.py | 20 +++++++++ Lib/turtle.py | 43 +++++++++++-------- ...-08-09-13-49-37.gh-issue-107805.ezem0k.rst | 1 + 3 files changed, 45 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst diff --git a/Lib/test/test_turtle.py b/Lib/test/test_turtle.py index 3f9f129a3dd200..14121a590a5026 100644 --- a/Lib/test/test_turtle.py +++ b/Lib/test/test_turtle.py @@ -461,5 +461,25 @@ def test_teleport(self): self.assertTrue(tpen.isdown()) +class TestModuleLevel(unittest.TestCase): + def test_all_signatures(self): + import inspect + + known_signatures = { + 'teleport': + '(x=None, y=None, *, fill_gap: bool = False) -> None', + 'undo': '()', + 'goto': '(x, y=None)', + 'bgcolor': '(*args)', + 'pen': '(pen=None, **pendict)', + } + + for name in known_signatures: + with self.subTest(name=name): + obj = getattr(turtle, name) + sig = inspect.signature(obj) + self.assertEqual(str(sig), known_signatures[name]) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/turtle.py b/Lib/turtle.py index cf111158b7c149..811c5dfa492a72 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -3951,28 +3951,33 @@ def getmethparlist(ob): function definition and the second is suitable for use in function call. The "self" parameter is not included. """ - defText = callText = "" + orig_sig = inspect.signature(ob) # bit of a hack for methods - turn it into a function # but we drop the "self" param. # Try and build one for Python defined functions - args, varargs, varkw = inspect.getargs(ob.__code__) - items2 = args[1:] - realArgs = args[1:] - defaults = ob.__defaults__ or [] - defaults = ["=%r" % (value,) for value in defaults] - defaults = [""] * (len(realArgs)-len(defaults)) + defaults - items1 = [arg + dflt for arg, dflt in zip(realArgs, defaults)] - if varargs is not None: - items1.append("*" + varargs) - items2.append("*" + varargs) - if varkw is not None: - items1.append("**" + varkw) - items2.append("**" + varkw) - defText = ", ".join(items1) - defText = "(%s)" % defText - callText = ", ".join(items2) - callText = "(%s)" % callText - return defText, callText + func_sig = orig_sig.replace( + parameters=list(orig_sig.parameters.values())[1:], + ) + + call_args = [] + for param in func_sig.parameters.values(): + match param.kind: + case ( + inspect.Parameter.POSITIONAL_ONLY + | inspect.Parameter.POSITIONAL_OR_KEYWORD + ): + call_args.append(param.name) + case inspect.Parameter.VAR_POSITIONAL: + call_args.append(f'*{param.name}') + case inspect.Parameter.KEYWORD_ONLY: + call_args.append(f'{param.name}={param.name}') + case inspect.Parameter.VAR_KEYWORD: + call_args.append(f'**{param.name}') + case _: + raise RuntimeError('Unsupported parameter kind', param.kind) + call_text = f'({', '.join(call_args)})' + + return str(func_sig), call_text def _turtle_docrevise(docstr): """To reduce docstrings from RawTurtle class for functions diff --git a/Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst b/Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst new file mode 100644 index 00000000000000..263df68f8e5c80 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst @@ -0,0 +1 @@ +Fix signatures of module-level generated functions in :mod:`turtle`. From 712994e1ab37bc1fdb0b9fcb8cf215d923c0341c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 1 Sep 2023 06:33:36 -0700 Subject: [PATCH 0671/1206] [3.12] gh-101100: Fix sphinx warnings in `tutorial/classes.rst` (GH-108746) (#108756) gh-101100: Fix sphinx warnings in `tutorial/classes.rst` (GH-108746) (cherry picked from commit e775601ef1ada83a80e1539d0bcd5509deadee14) Co-authored-by: Nikita Sobolev --- Doc/tools/.nitignore | 1 - Doc/tutorial/classes.rst | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 765fbe2ca9e240..4fc681984bb8f7 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -172,7 +172,6 @@ Doc/reference/expressions.rst Doc/reference/import.rst Doc/reference/simple_stmts.rst Doc/tutorial/appendix.rst -Doc/tutorial/classes.rst Doc/tutorial/controlflow.rst Doc/tutorial/datastructures.rst Doc/tutorial/introduction.rst diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index 91a3b73d2b55aa..7b92e1a51b6e67 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -276,7 +276,7 @@ definition looked like this:: then ``MyClass.i`` and ``MyClass.f`` are valid attribute references, returning an integer and a function object, respectively. Class attributes can also be assigned to, so you can change the value of ``MyClass.i`` by assignment. -:attr:`__doc__` is also a valid attribute, returning the docstring belonging to +:attr:`!__doc__` is also a valid attribute, returning the docstring belonging to the class: ``"A simple example class"``. Class *instantiation* uses function notation. Just pretend that the class From 4dc07d2bde2e219f3b6995891b8cda3e8094804a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 1 Sep 2023 06:36:52 -0700 Subject: [PATCH 0672/1206] [3.12] Make test_fcntl quiet (GH-108758) (#108760) Make test_fcntl quiet (GH-108758) Running test_fcntl logs two "struct.pack: ..." lines because multiprocessing imports test_fcntl twice with test.support.verbose=1. Move get_lockdata() inside TestFcntl test case and only call it where it's needed, to stop logging these lines. (cherry picked from commit 23f54c120067c96973619b9501fe4dff1b055188) Co-authored-by: Victor Stinner --- Lib/test/test_fcntl.py | 63 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py index 5da75615b41d79..203dd6fe57dcd9 100644 --- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -16,37 +16,6 @@ -def get_lockdata(): - try: - os.O_LARGEFILE - except AttributeError: - start_len = "ll" - else: - start_len = "qq" - - if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd')) - or sys.platform == 'darwin'): - if struct.calcsize('l') == 8: - off_t = 'l' - pid_t = 'i' - else: - off_t = 'lxxxx' - pid_t = 'l' - lockdata = struct.pack(off_t + off_t + pid_t + 'hh', 0, 0, 0, - fcntl.F_WRLCK, 0) - elif sys.platform.startswith('gnukfreebsd'): - lockdata = struct.pack('qqihhi', 0, 0, 0, fcntl.F_WRLCK, 0, 0) - elif sys.platform in ['hp-uxB', 'unixware7']: - lockdata = struct.pack('hhlllii', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0) - else: - lockdata = struct.pack('hh'+start_len+'hh', fcntl.F_WRLCK, 0, 0, 0, 0, 0) - if lockdata: - if verbose: - print('struct.pack: ', repr(lockdata)) - return lockdata - -lockdata = get_lockdata() - class BadFile: def __init__(self, fn): self.fn = fn @@ -78,12 +47,43 @@ def tearDown(self): self.f.close() unlink(TESTFN) + @staticmethod + def get_lockdata(): + try: + os.O_LARGEFILE + except AttributeError: + start_len = "ll" + else: + start_len = "qq" + + if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd')) + or sys.platform == 'darwin'): + if struct.calcsize('l') == 8: + off_t = 'l' + pid_t = 'i' + else: + off_t = 'lxxxx' + pid_t = 'l' + lockdata = struct.pack(off_t + off_t + pid_t + 'hh', 0, 0, 0, + fcntl.F_WRLCK, 0) + elif sys.platform.startswith('gnukfreebsd'): + lockdata = struct.pack('qqihhi', 0, 0, 0, fcntl.F_WRLCK, 0, 0) + elif sys.platform in ['hp-uxB', 'unixware7']: + lockdata = struct.pack('hhlllii', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0) + else: + lockdata = struct.pack('hh'+start_len+'hh', fcntl.F_WRLCK, 0, 0, 0, 0, 0) + if lockdata: + if verbose: + print('struct.pack: ', repr(lockdata)) + return lockdata + def test_fcntl_fileno(self): # the example from the library docs self.f = open(TESTFN, 'wb') rv = fcntl.fcntl(self.f.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) if verbose: print('Status from fcntl with O_NONBLOCK: ', rv) + lockdata = self.get_lockdata() rv = fcntl.fcntl(self.f.fileno(), fcntl.F_SETLKW, lockdata) if verbose: print('String from fcntl with F_SETLKW: ', repr(rv)) @@ -95,6 +95,7 @@ def test_fcntl_file_descriptor(self): rv = fcntl.fcntl(self.f, fcntl.F_SETFL, os.O_NONBLOCK) if verbose: print('Status from fcntl with O_NONBLOCK: ', rv) + lockdata = self.get_lockdata() rv = fcntl.fcntl(self.f, fcntl.F_SETLKW, lockdata) if verbose: print('String from fcntl with F_SETLKW: ', repr(rv)) From f58617a3bc4ff64e4663ae1a719f03bf3f2475f1 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 2 Sep 2023 15:42:40 -0600 Subject: [PATCH 0673/1206] [3.12] gh-101100: Fix sphinx warnings in `tutorial/appendix.rst` (GH-108750) (#108759) (cherry picked from commit 3047f09490ae63f25d57efe1d14a9a65d9b5f6db) Co-authored-by: Nikita Sobolev --- Doc/tools/.nitignore | 1 - Doc/tutorial/appendix.rst | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 4fc681984bb8f7..75c6a8f8652131 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -171,7 +171,6 @@ Doc/reference/datamodel.rst Doc/reference/expressions.rst Doc/reference/import.rst Doc/reference/simple_stmts.rst -Doc/tutorial/appendix.rst Doc/tutorial/controlflow.rst Doc/tutorial/datastructures.rst Doc/tutorial/introduction.rst diff --git a/Doc/tutorial/appendix.rst b/Doc/tutorial/appendix.rst index 241a812037469e..588591fcdb726f 100644 --- a/Doc/tutorial/appendix.rst +++ b/Doc/tutorial/appendix.rst @@ -101,8 +101,8 @@ in the script:: The Customization Modules ------------------------- -Python provides two hooks to let you customize it: :mod:`sitecustomize` and -:mod:`usercustomize`. To see how it works, you need first to find the location +Python provides two hooks to let you customize it: :index:`sitecustomize` and +:index:`usercustomize`. To see how it works, you need first to find the location of your user site-packages directory. Start Python and run this code:: >>> import site @@ -113,9 +113,9 @@ Now you can create a file named :file:`usercustomize.py` in that directory and put anything you want in it. It will affect every invocation of Python, unless it is started with the :option:`-s` option to disable the automatic import. -:mod:`sitecustomize` works in the same way, but is typically created by an +:index:`sitecustomize` works in the same way, but is typically created by an administrator of the computer in the global site-packages directory, and is -imported before :mod:`usercustomize`. See the documentation of the :mod:`site` +imported before :index:`usercustomize`. See the documentation of the :mod:`site` module for more details. From ba7e06bb631a85b0e74b6de4c5005d4b4447519f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:43:14 -0700 Subject: [PATCH 0674/1206] [3.12] Add Modules/_testcapi/util.h header (GH-108774) (#108780) Add Modules/_testcapi/util.h header (GH-108774) It contains common macros used in C API tests. (cherry picked from commit 0e01fac315dfa705ac8a6954485546f28cf4c87d) Co-authored-by: Serhiy Storchaka --- Makefile.pre.in | 2 +- Modules/_testcapi/abstract.c | 19 +---------- Modules/_testcapi/dict.c | 19 +---------- Modules/_testcapi/exceptions.c | 2 +- Modules/_testcapi/unicode.c | 58 +++++++++++----------------------- Modules/_testcapi/util.h | 25 +++++++++++++++ Modules/_testcapimodule.c | 18 ++--------- 7 files changed, 49 insertions(+), 94 deletions(-) create mode 100644 Modules/_testcapi/util.h diff --git a/Makefile.pre.in b/Makefile.pre.in index ae6a12c2a2c430..0372c1a49ca244 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2792,7 +2792,7 @@ MODULE__SHA2_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA2_HEADERS) $(LIBHACL_ MODULE__SHA3_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HEADERS) Modules/_hacl/Hacl_Hash_SHA3.h Modules/_hacl/Hacl_Hash_SHA3.c MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo.h $(srcdir)/Modules/getaddrinfo.c $(srcdir)/Modules/getnameinfo.c MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c $(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c $(srcdir)/Modules/_ssl_data.h $(srcdir)/Modules/_ssl_data_111.h $(srcdir)/Modules/_ssl_data_300.h $(srcdir)/Modules/socketmodule.h -MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/_testcapi/testcapi_long.h $(srcdir)/Modules/_testcapi/parts.h +MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/_testcapi/testcapi_long.h $(srcdir)/Modules/_testcapi/parts.h $(srcdir)/Modules/_testcapi/util.h MODULE__SQLITE3_DEPS=$(srcdir)/Modules/_sqlite/connection.h $(srcdir)/Modules/_sqlite/cursor.h $(srcdir)/Modules/_sqlite/microprotocols.h $(srcdir)/Modules/_sqlite/module.h $(srcdir)/Modules/_sqlite/prepare_protocol.h $(srcdir)/Modules/_sqlite/row.h $(srcdir)/Modules/_sqlite/util.h CODECS_COMMON_HEADERS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h diff --git a/Modules/_testcapi/abstract.c b/Modules/_testcapi/abstract.c index 9715efb821740b..38236aaf4f4353 100644 --- a/Modules/_testcapi/abstract.c +++ b/Modules/_testcapi/abstract.c @@ -2,24 +2,7 @@ #define PY_SSIZE_T_CLEAN #include "parts.h" - -#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); - -#define RETURN_INT(value) do { \ - int _ret = (value); \ - if (_ret == -1) { \ - return NULL; \ - } \ - return PyLong_FromLong(_ret); \ - } while (0) - -#define RETURN_SIZE(value) do { \ - Py_ssize_t _ret = (value); \ - if (_ret == -1) { \ - return NULL; \ - } \ - return PyLong_FromSsize_t(_ret); \ - } while (0) +#include "util.h" static PyObject * diff --git a/Modules/_testcapi/dict.c b/Modules/_testcapi/dict.c index c0f26e799b5f19..bcc86c9a84cd2e 100644 --- a/Modules/_testcapi/dict.c +++ b/Modules/_testcapi/dict.c @@ -2,24 +2,7 @@ #define PY_SSIZE_T_CLEAN #include "parts.h" - -#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); - -#define RETURN_INT(value) do { \ - int _ret = (value); \ - if (_ret == -1) { \ - return NULL; \ - } \ - return PyLong_FromLong(_ret); \ - } while (0) - -#define RETURN_SIZE(value) do { \ - Py_ssize_t _ret = (value); \ - if (_ret == -1) { \ - return NULL; \ - } \ - return PyLong_FromSsize_t(_ret); \ - } while (0) +#include "util.h" static PyObject * diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index 4ae9ba4044df84..9756c3778ca524 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -1,8 +1,8 @@ #define PY_SSIZE_T_CLEAN #include "parts.h" +#include "util.h" #include "clinic/exceptions.c.h" -#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); /*[clinic input] module _testcapi diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index b4d7bf82d73c83..de899b679ca8f8 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -2,6 +2,7 @@ #define PY_SSIZE_T_CLEAN #include "parts.h" +#include "util.h" static struct PyModuleDef *_testcapimodule = NULL; // set at initialization @@ -102,7 +103,6 @@ test_widechar(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } -#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); static PyObject * unicode_copy(PyObject *unicode) @@ -348,13 +348,8 @@ unicode_substring(PyObject *self, PyObject *args) static PyObject * unicode_getlength(PyObject *self, PyObject *arg) { - Py_ssize_t result; - NULLABLE(arg); - result = PyUnicode_GetLength(arg); - if (result == -1) - return NULL; - return PyLong_FromSsize_t(result); + RETURN_SIZE(PyUnicode_GetLength(arg)); } /* Test PyUnicode_ReadChar() */ @@ -483,16 +478,12 @@ static PyObject * unicode_aswidechar_null(PyObject *self, PyObject *args) { PyObject *unicode; - Py_ssize_t buflen, size; + Py_ssize_t buflen; if (!PyArg_ParseTuple(args, "On", &unicode, &buflen)) return NULL; NULLABLE(unicode); - size = PyUnicode_AsWideChar(unicode, NULL, buflen); - if (size == -1) { - return NULL; - } - return PyLong_FromSsize_t(size); + RETURN_SIZE(PyUnicode_AsWideChar(unicode, NULL, buflen)); } /* Test PyUnicode_AsWideCharString() */ @@ -1302,17 +1293,13 @@ unicode_count(PyObject *self, PyObject *args) PyObject *substr; Py_ssize_t start; Py_ssize_t end; - Py_ssize_t result; if (!PyArg_ParseTuple(args, "OOnn", &str, &substr, &start, &end)) return NULL; NULLABLE(str); NULLABLE(substr); - result = PyUnicode_Count(str, substr, start, end); - if (result == -1) - return NULL; - return PyLong_FromSsize_t(result); + RETURN_SIZE(PyUnicode_Count(str, substr, start, end)); } /* Test PyUnicode_Find() */ @@ -1332,8 +1319,11 @@ unicode_find(PyObject *self, PyObject *args) NULLABLE(str); NULLABLE(substr); result = PyUnicode_Find(str, substr, start, end, direction); - if (result == -2) + if (result == -2) { + assert(PyErr_Occurred()); return NULL; + } + assert(!PyErr_Occurred()); return PyLong_FromSsize_t(result); } @@ -1346,17 +1336,13 @@ unicode_tailmatch(PyObject *self, PyObject *args) Py_ssize_t start; Py_ssize_t end; int direction; - Py_ssize_t result; if (!PyArg_ParseTuple(args, "OOnni", &str, &substr, &start, &end, &direction)) return NULL; NULLABLE(str); NULLABLE(substr); - result = PyUnicode_Tailmatch(str, substr, start, end, direction); - if (result == -1) - return NULL; - return PyLong_FromSsize_t(result); + RETURN_SIZE(PyUnicode_Tailmatch(str, substr, start, end, direction)); } /* Test PyUnicode_FindChar() */ @@ -1375,10 +1361,12 @@ unicode_findchar(PyObject *self, PyObject *args) } NULLABLE(str); result = PyUnicode_FindChar(str, (Py_UCS4)ch, start, end, direction); - if (result == -2) + if (result == -2) { + assert(PyErr_Occurred()); return NULL; - else - return PyLong_FromSsize_t(result); + } + assert(!PyErr_Occurred()); + return PyLong_FromSsize_t(result); } /* Test PyUnicode_Replace() */ @@ -1416,6 +1404,7 @@ unicode_compare(PyObject *self, PyObject *args) if (result == -1 && PyErr_Occurred()) { return NULL; } + assert(!PyErr_Occurred()); return PyLong_FromLong(result); } @@ -1476,32 +1465,21 @@ unicode_contains(PyObject *self, PyObject *args) { PyObject *container; PyObject *element; - int result; if (!PyArg_ParseTuple(args, "OO", &container, &element)) return NULL; NULLABLE(container); NULLABLE(element); - result = PyUnicode_Contains(container, element); - if (result == -1 && PyErr_Occurred()) { - return NULL; - } - return PyLong_FromLong(result); + RETURN_INT(PyUnicode_Contains(container, element)); } /* Test PyUnicode_IsIdentifier() */ static PyObject * unicode_isidentifier(PyObject *self, PyObject *arg) { - int result; - NULLABLE(arg); - result = PyUnicode_IsIdentifier(arg); - if (result == -1 && PyErr_Occurred()) { - return NULL; - } - return PyLong_FromLong(result); + RETURN_INT(PyUnicode_IsIdentifier(arg)); } /* Test PyUnicode_CopyCharacters() */ diff --git a/Modules/_testcapi/util.h b/Modules/_testcapi/util.h new file mode 100644 index 00000000000000..05ccb12a4444f8 --- /dev/null +++ b/Modules/_testcapi/util.h @@ -0,0 +1,25 @@ +#define NULLABLE(x) do { \ + if (x == Py_None) { \ + x = NULL; \ + } \ + } while (0); + +#define RETURN_INT(value) do { \ + int _ret = (value); \ + if (_ret == -1) { \ + assert(PyErr_Occurred()); \ + return NULL; \ + } \ + assert(!PyErr_Occurred()); \ + return PyLong_FromLong(_ret); \ + } while (0) + +#define RETURN_SIZE(value) do { \ + Py_ssize_t _ret = (value); \ + if (_ret == -1) { \ + assert(PyErr_Occurred()); \ + return NULL; \ + } \ + assert(!PyErr_Occurred()); \ + return PyLong_FromSsize_t(_ret); \ + } while (0) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ee6f02dd8ab48b..dec64af7a59cb4 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -44,16 +44,8 @@ // Several parts of this module are broken out into files in _testcapi/. // Include definitions from there. #include "_testcapi/parts.h" +#include "_testcapi/util.h" -#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); - -#define RETURN_INT(value) do { \ - int _ret = (value); \ - if (_ret == -1) { \ - return NULL; \ - } \ - return PyLong_FromLong(_ret); \ - } while (0) // Forward declarations static struct PyModuleDef _testcapimodule; @@ -1348,19 +1340,13 @@ static PyObject * test_PyBuffer_SizeFromFormat(PyObject *self, PyObject *args) { const char *format; - Py_ssize_t result; if (!PyArg_ParseTuple(args, "s:test_PyBuffer_SizeFromFormat", &format)) { return NULL; } - result = PyBuffer_SizeFromFormat(format); - if (result == -1) { - return NULL; - } - - return PyLong_FromSsize_t(result); + RETURN_SIZE(PyBuffer_SizeFromFormat(format)); } /* Test that the fatal error from not having a current thread doesn't From 246cb64984de988a5e53781f912ae7ba73365aca Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 3 Sep 2023 00:43:41 +0300 Subject: [PATCH 0675/1206] [3.12] Improve some C API documentation (GH-108768) (#108785) * Express functions which take argument as a C string in terms of functions which take Python object. * Use "note" directive for PyMapping_HasKey() and PyMapping_HasKeyString() notes.. (cherry picked from commit 6f97eeec222f81bd7ae836c149872a40b079e2a6) --- Doc/c-api/dict.rst | 16 ++++++---------- Doc/c-api/mapping.rst | 43 +++++++++++++++++++++++-------------------- Doc/c-api/object.rst | 28 ++++++++++++++-------------- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index f668f845de610e..5ccbfe64647854 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -70,12 +70,9 @@ Dictionary Objects .. c:function:: int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val) - .. index:: single: PyUnicode_FromString() - - Insert *val* into the dictionary *p* using *key* as a key. *key* should - be a :c:expr:`const char*` UTF-8 encoded bytes string. The key object is created using - ``PyUnicode_FromString(key)``. Return ``0`` on success or ``-1`` on - failure. This function *does not* steal a reference to *val*. + This is the same as :c:func:`PyDict_SetItem`, but *key* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. c:function:: int PyDict_DelItem(PyObject *p, PyObject *key) @@ -88,10 +85,9 @@ Dictionary Objects .. c:function:: int PyDict_DelItemString(PyObject *p, const char *key) - Remove the entry in dictionary *p* which has a key specified by the UTF-8 - encoded bytes string *key*. - If *key* is not in the dictionary, :exc:`KeyError` is raised. - Return ``0`` on success or ``-1`` on failure. + This is the same as :c:func:`PyDict_DelItem`, but *key* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. c:function:: PyObject* PyDict_GetItem(PyObject *p, PyObject *key) diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst index d94a9dc45b5ebe..0c42b9177bb56d 100644 --- a/Doc/c-api/mapping.rst +++ b/Doc/c-api/mapping.rst @@ -28,30 +28,28 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and .. c:function:: PyObject* PyMapping_GetItemString(PyObject *o, const char *key) - Return element of *o* corresponding to the string *key* or ``NULL`` on failure. - This is the equivalent of the Python expression ``o[key]``. - See also :c:func:`PyObject_GetItem`. + This is the same as :c:func:`PyObject_GetItem`, but *key* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. c:function:: int PyMapping_SetItemString(PyObject *o, const char *key, PyObject *v) - Map the string *key* to the value *v* in object *o*. Returns ``-1`` on - failure. This is the equivalent of the Python statement ``o[key] = v``. - See also :c:func:`PyObject_SetItem`. This function *does not* steal a - reference to *v*. + This is the same as :c:func:`PyObject_SetItem`, but *key* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. c:function:: int PyMapping_DelItem(PyObject *o, PyObject *key) - Remove the mapping for the object *key* from the object *o*. Return ``-1`` - on failure. This is equivalent to the Python statement ``del o[key]``. This is an alias of :c:func:`PyObject_DelItem`. .. c:function:: int PyMapping_DelItemString(PyObject *o, const char *key) - Remove the mapping for the string *key* from the object *o*. Return ``-1`` - on failure. This is equivalent to the Python statement ``del o[key]``. + This is the same as :c:func:`PyObject_DelItem`, but *key* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. c:function:: int PyMapping_HasKey(PyObject *o, PyObject *key) @@ -60,20 +58,25 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and This is equivalent to the Python expression ``key in o``. This function always succeeds. - Note that exceptions which occur while calling the :meth:`~object.__getitem__` - method will get suppressed. - To get error reporting use :c:func:`PyObject_GetItem()` instead. + .. note:: + + Exceptions which occur when this calls :meth:`~object.__getitem__` + method are silently ignored. + For proper error handling, use :c:func:`PyObject_GetItem()` instead. .. c:function:: int PyMapping_HasKeyString(PyObject *o, const char *key) - Return ``1`` if the mapping object has the key *key* and ``0`` otherwise. - This is equivalent to the Python expression ``key in o``. - This function always succeeds. + This is the same as :c:func:`PyMapping_HasKey`, but *key* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. + + .. note:: - Note that exceptions which occur while calling the :meth:`~object.__getitem__` - method and creating a temporary string object will get suppressed. - To get error reporting use :c:func:`PyMapping_GetItemString()` instead. + Exceptions that occur when this calls :meth:`~object.__getitem__` + method or while creating the temporary :class:`str` + object are silently ignored. + For proper error handling, use :c:func:`PyMapping_GetItemString` instead. .. c:function:: PyObject* PyMapping_Keys(PyObject *o) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 4a3fed1a6087a1..d88de7944859b7 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -42,15 +42,15 @@ Object Protocol .. c:function:: int PyObject_HasAttrString(PyObject *o, const char *attr_name) - Returns ``1`` if *o* has the attribute *attr_name*, and ``0`` otherwise. This - is equivalent to the Python expression ``hasattr(o, attr_name)``. This function - always succeeds. + This is the same as :c:func:`PyObject_HasAttr`, but *attr_name* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. note:: Exceptions that occur when this calls :meth:`~object.__getattr__` and - :meth:`~object.__getattribute__` methods or while creating the temporary :class:`str` - object are silently ignored. + :meth:`~object.__getattribute__` methods or while creating the temporary + :class:`str` object are silently ignored. For proper error handling, use :c:func:`PyObject_GetAttrString` instead. @@ -63,9 +63,9 @@ Object Protocol .. c:function:: PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name) - Retrieve an attribute named *attr_name* from object *o*. Returns the attribute - value on success, or ``NULL`` on failure. This is the equivalent of the Python - expression ``o.attr_name``. + This is the same as :c:func:`PyObject_GetAttr`, but *attr_name* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. c:function:: PyObject* PyObject_GenericGetAttr(PyObject *o, PyObject *name) @@ -92,10 +92,9 @@ Object Protocol .. c:function:: int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v) - Set the value of the attribute named *attr_name*, for object *o*, to the value - *v*. Raise an exception and return ``-1`` on failure; - return ``0`` on success. This is the equivalent of the Python statement - ``o.attr_name = v``. + This is the same as :c:func:`PyObject_SetAttr`, but *attr_name* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. If *v* is ``NULL``, the attribute is deleted, but this feature is deprecated in favour of using :c:func:`PyObject_DelAttrString`. @@ -121,8 +120,9 @@ Object Protocol .. c:function:: int PyObject_DelAttrString(PyObject *o, const char *attr_name) - Delete attribute named *attr_name*, for object *o*. Returns ``-1`` on failure. - This is the equivalent of the Python statement ``del o.attr_name``. + This is the same as :c:func:`PyObject_DelAttr`, but *attr_name* is + specified as a :c:expr:`const char*` UTF-8 encoded bytes string, + rather than a :c:expr:`PyObject*`. .. c:function:: PyObject* PyObject_GenericGetDict(PyObject *o, void *context) From 70a378c88871b1cfac56cfdecde31a4adaac929a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:44:06 -0700 Subject: [PATCH 0676/1206] [3.12] gh-105563: reference DateType in datetime's documentation (GH-105946) (#108789) gh-105563: reference DateType in datetime's documentation (GH-105946) (cherry picked from commit 8f9ea43ee805f98391f857397daac9df7ffa71cd) Co-authored-by: TATHAGATA ROY --- Doc/library/datetime.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 400c369a9bb736..04cc75562937e0 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -37,6 +37,10 @@ on efficient attribute extraction for output formatting and manipulation. Package `dateutil `_ Third-party library with expanded time zone and parsing support. + Package `DateType `_ + Third-party library that introduces distinct static types to e.g. allow static type checkers + to differentiate between naive and aware datetimes. + .. _datetime-naive-aware: Aware and Naive Objects From b862c25922764eb7bb3cd93dc91fd15c8e92d4f2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:44:28 -0700 Subject: [PATCH 0677/1206] [3.12] gh-106392: Fix inconsistency in deprecation warnings (GH-106436) (#108792) gh-106392: Fix inconsistency in deprecation warnings (GH-106436) They used "datetime" to refer to both the object and the module. (cherry picked from commit d5c5d4bfd3260219397326795d3b2ff62a9ab8cb) Co-authored-by: William Andrea --- Lib/_pydatetime.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index f4fc2c58e5e293..549fcda19dccf2 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -1812,7 +1812,7 @@ def utcfromtimestamp(cls, t): warnings.warn("datetime.utcfromtimestamp() is deprecated and scheduled " "for removal in a future version. Use timezone-aware " "objects to represent datetimes in UTC: " - "datetime.fromtimestamp(t, datetime.UTC).", + "datetime.datetime.fromtimestamp(t, datetime.UTC).", DeprecationWarning, stacklevel=2) return cls._fromtimestamp(t, True, None) @@ -1830,7 +1830,7 @@ def utcnow(cls): warnings.warn("datetime.utcnow() is deprecated and scheduled for " "removal in a future version. Instead, Use timezone-aware " "objects to represent datetimes in UTC: " - "datetime.now(datetime.UTC).", + "datetime.datetime.now(datetime.UTC).", DeprecationWarning, stacklevel=2) t = _time.time() From 54e8dd757cb3e41fc479be23db925fc3a475f185 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:45:40 -0700 Subject: [PATCH 0678/1206] [3.12] gh-101100: Fix sphinx warnings in `uuid.rst` (GH-108805) (#108807) * gh-101100: Fix sphinx warnings in `uuid.rst` (GH-108805) * gh-101100: Fix sphinx warnings in `uuid.rst` * Use anchors (cherry picked from commit 21da4980f5916e8fd648f04367a9e60d141af366) Co-authored-by: Nikita Sobolev * Fix typo * another typo --------- Co-authored-by: Nikita Sobolev Co-authored-by: Hugo van Kemenade Co-authored-by: Alex Waygood --- Doc/library/uuid.rst | 51 ++++++++++++++++++++++++++------------------ Doc/tools/.nitignore | 1 - 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 94b9a432372195..adf01770656754 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -22,7 +22,7 @@ random UUID. Depending on support from the underlying platform, :func:`uuid1` may or may not return a "safe" UUID. A safe UUID is one which is generated using synchronization methods that ensure no two processes can obtain the same -UUID. All instances of :class:`UUID` have an :attr:`is_safe` attribute +UUID. All instances of :class:`UUID` have an :attr:`~UUID.is_safe` attribute which relays any information about the UUID's safety, using this enumeration: .. class:: SafeUUID @@ -95,25 +95,34 @@ which relays any information about the UUID's safety, using this enumeration: A tuple of the six integer fields of the UUID, which are also available as six individual attributes and two derived attributes: - +------------------------------+-------------------------------+ - | Field | Meaning | - +==============================+===============================+ - | :attr:`time_low` | the first 32 bits of the UUID | - +------------------------------+-------------------------------+ - | :attr:`time_mid` | the next 16 bits of the UUID | - +------------------------------+-------------------------------+ - | :attr:`time_hi_version` | the next 16 bits of the UUID | - +------------------------------+-------------------------------+ - | :attr:`clock_seq_hi_variant` | the next 8 bits of the UUID | - +------------------------------+-------------------------------+ - | :attr:`clock_seq_low` | the next 8 bits of the UUID | - +------------------------------+-------------------------------+ - | :attr:`node` | the last 48 bits of the UUID | - +------------------------------+-------------------------------+ - | :attr:`time` | the 60-bit timestamp | - +------------------------------+-------------------------------+ - | :attr:`clock_seq` | the 14-bit sequence number | - +------------------------------+-------------------------------+ +.. list-table:: + + * - Field + - Meaning + + * - .. attribute:: UUID.time_low + - The first 32 bits of the UUID. + + * - .. attribute:: UUID.time_mid + - The next 16 bits of the UUID. + + * - .. attribute:: UUID.time_hi_version + - The next 16 bits of the UUID. + + * - .. attribute:: UUID.clock_seq_hi_variant + - The next 8 bits of the UUID. + + * - .. attribute:: UUID.clock_seq_low + - The next 8 bits of the UUID. + + * - .. attribute:: UUID.node + - The last 48 bits of the UUID. + + * - .. attribute:: UUID.time + - The 60-bit timestamp. + + * - .. attribute:: UUID.clock_seq + - The 14-bit sequence number. .. attribute:: UUID.hex @@ -233,7 +242,7 @@ The :mod:`uuid` module defines the following namespace identifiers for use with text output format. The :mod:`uuid` module defines the following constants for the possible values -of the :attr:`variant` attribute: +of the :attr:`~UUID.variant` attribute: .. data:: RESERVED_NCS diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 75c6a8f8652131..5a824a43820361 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -150,7 +150,6 @@ Doc/library/unittest.mock.rst Doc/library/unittest.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst -Doc/library/uuid.rst Doc/library/weakref.rst Doc/library/webbrowser.rst Doc/library/wsgiref.rst From c5ce34f9b4963a672ce5993d165384e96b6eefe9 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sun, 3 Sep 2023 00:46:03 +0300 Subject: [PATCH 0679/1206] [3.12] gh-101100: Fix sphinx warnings in `unittest.mock-examples.rst` (GH-108810) (#108813) * [3.12] gh-101100: Fix sphinx warnings in `unittest.mock-examples.rst` (GH-108810). (cherry picked from commit 5141b1ebe07ad54279e0770b4704eaf76f24951d) Co-authored-by: Nikita Sobolev * Make the requested changes --------- Co-authored-by: AlexWaygood --- Doc/library/unittest.mock-examples.rst | 13 +++++++------ Doc/tools/.nitignore | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 895b9f9f07671b..744fc9de63cd16 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -579,14 +579,14 @@ Partial mocking In some tests I wanted to mock out a call to :meth:`datetime.date.today` to return a known date, but I didn't want to prevent the code under test from creating new date objects. Unfortunately :class:`datetime.date` is written in C, and -so I couldn't just monkey-patch out the static :meth:`date.today` method. +so I couldn't just monkey-patch out the static :meth:`datetime.date.today` method. I found a simple way of doing this that involved effectively wrapping the date class with a mock, but passing through calls to the constructor to the real class (and returning real instances). The :func:`patch decorator ` is used here to -mock out the ``date`` class in the module under test. The :attr:`side_effect` +mock out the ``date`` class in the module under test. The :attr:`~Mock.side_effect` attribute on the mock date class is then set to a lambda function that returns a real date. When the mock date class is called a real date will be constructed and returned by ``side_effect``. :: @@ -766,8 +766,8 @@ mock has a nice API for making assertions about how your mock objects are used. >>> mock.foo_bar.assert_called_with('baz', spam='eggs') If your mock is only being called once you can use the -:meth:`assert_called_once_with` method that also asserts that the -:attr:`call_count` is one. +:meth:`~Mock.assert_called_once_with` method that also asserts that the +:attr:`~Mock.call_count` is one. >>> mock.foo_bar.assert_called_once_with('baz', spam='eggs') >>> mock.foo_bar() @@ -835,7 +835,7 @@ One possibility would be for mock to copy the arguments you pass in. This could then cause problems if you do assertions that rely on object identity for equality. -Here's one solution that uses the :attr:`side_effect` +Here's one solution that uses the :attr:`~Mock.side_effect` functionality. If you provide a ``side_effect`` function for a mock then ``side_effect`` will be called with the same args as the mock. This gives us an opportunity to copy the arguments and store them for later assertions. In this @@ -971,7 +971,8 @@ We can do this with :class:`MagicMock`, which will behave like a dictionary, and using :data:`~Mock.side_effect` to delegate dictionary access to a real underlying dictionary that is under our control. -When the :meth:`__getitem__` and :meth:`__setitem__` methods of our ``MagicMock`` are called +When the :meth:`~object.__getitem__` and :meth:`~object.__setitem__` methods +of our ``MagicMock`` are called (normal dictionary access) then ``side_effect`` is called with the key (and in the case of ``__setitem__`` the value too). We can also control what is returned. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 5a824a43820361..3d79b480946686 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -145,7 +145,6 @@ Doc/library/tkinter.ttk.rst Doc/library/traceback.rst Doc/library/tty.rst Doc/library/turtle.rst -Doc/library/unittest.mock-examples.rst Doc/library/unittest.mock.rst Doc/library/unittest.rst Doc/library/urllib.parse.rst From 7269916cd7b89b5e6f20bfe83ebe1038bda56b4b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 2 Sep 2023 23:47:25 +0200 Subject: [PATCH 0680/1206] [3.12] gh-63760: Don't declare gethostname() on Solaris (#108817) (#108824) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-63760: Don't declare gethostname() on Solaris (#108817) Since 2005, Solaris defines gethostname(). socketmodule.c no longer has to define gethostname() for Solaris. Oracle Solaris and OpenSolaris have patches to remove the gethostname() definition in Python: * https://github.com/oracle/solaris-userland/blob/master/components/python/python37/patches/15-gethostname.patch * https://github.com/OpenIndiana/oi-userland/blob/oi/hipster/components/python/python37/patches/15-gethostname.patch * https://github.com/omniosorg/omnios-build/blob/master/build/python27/patches/24-gethostname.patch Co-authored-by: Jakub Kulík (cherry picked from commit 0e6d582b3b73a88e71cae04327b31a1ee203722c) --- Include/pyport.h | 5 ----- .../next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst diff --git a/Include/pyport.h b/Include/pyport.h index d7c6ae64f2bf2f..35eca7234ca094 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -429,11 +429,6 @@ Please be conservative with adding new ones, document them and enclose them in platform-specific #ifdefs. **************************************************************************/ -#ifdef SOLARIS -/* Unchecked */ -extern int gethostname(char *, int); -#endif - #ifdef HAVE__GETPTY #include /* we need to import mode_t */ extern char * _getpty(int *, int, mode_t, int); diff --git a/Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst b/Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst new file mode 100644 index 00000000000000..9a7249e923e0c7 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst @@ -0,0 +1,3 @@ +Fix Solaris build: no longer redefine the ``gethostname()`` function. Solaris +defines the function since 2005. Patch by Victor Stinner, original patch by +Jakub Kulík. From dcaacd906638edbc66cc84fa651163dc7a743070 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:22:33 -0700 Subject: [PATCH 0681/1206] [3.12] gh-108416: Mark slow test methods with @requires_resource('cpu') (GH-108421) (#108798) gh-108416: Mark slow test methods with @requires_resource('cpu') (GH-108421) Only mark tests which spend significant system or user time, by itself or in subprocesses. (cherry picked from commit f3ba0a74cd50274acdcd592d4ce8395b92492b7c) Co-authored-by: Serhiy Storchaka --- Lib/test/_test_multiprocessing.py | 2 ++ Lib/test/pickletester.py | 1 + Lib/test/test_ast.py | 1 + Lib/test/test_buffer.py | 2 ++ Lib/test/test_builtin.py | 1 + Lib/test/test_compile.py | 1 + Lib/test/test_compileall.py | 2 ++ Lib/test/test_concurrent_futures/test_thread_pool.py | 2 ++ Lib/test/test_context.py | 2 ++ Lib/test/test_cppext/__init__.py | 2 ++ Lib/test/test_descr.py | 1 + Lib/test/test_email/test_email.py | 2 ++ Lib/test/test_exceptions.py | 1 + Lib/test/test_gdb.py | 7 +++++++ Lib/test/test_interpreters.py | 2 ++ Lib/test/test_itertools.py | 1 + Lib/test/test_largefile.py | 4 +++- Lib/test/test_multibytecodec.py | 1 + Lib/test/test_peepholer.py | 2 ++ Lib/test/test_runpy.py | 3 ++- Lib/test/test_selectors.py | 1 + Lib/test/test_source_encoding.py | 3 ++- Lib/test/test_statistics.py | 2 ++ Lib/test/test_subprocess.py | 1 + Lib/test/test_support.py | 1 + Lib/test/test_sys_settrace.py | 1 + Lib/test/test_tools/test_freeze.py | 1 + Lib/test/test_trace.py | 3 ++- Lib/test/test_traceback.py | 1 + Lib/test/test_unicodedata.py | 2 ++ Lib/test/test_venv.py | 4 +++- Lib/test/test_weakref.py | 2 ++ 32 files changed, 57 insertions(+), 5 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index c1e18dd69294b1..2e656538e99f3e 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -329,6 +329,7 @@ def test_set_executable(self): p.join() self.assertEqual(p.exitcode, 0) + @support.requires_resource('cpu') def test_args_argument(self): # bpo-45735: Using list or tuple as *args* in constructor could # achieve the same effect. @@ -4466,6 +4467,7 @@ def test_finalize(self): result = [obj for obj in iter(conn.recv, 'STOP')] self.assertEqual(result, ['a', 'b', 'd10', 'd03', 'd02', 'd01', 'e']) + @support.requires_resource('cpu') def test_thread_safety(self): # bpo-24484: _run_finalizers() should be thread-safe def cb(): diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 6e87370c2065ba..a687fe0629080a 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2576,6 +2576,7 @@ def check_frame_opcodes(self, pickled): self.assertLess(pos - frameless_start, self.FRAME_SIZE_MIN) @support.skip_if_pgo_task + @support.requires_resource('cpu') def test_framing_many_objects(self): obj = list(range(10**5)) for proto in range(4, pickle.HIGHEST_PROTOCOL + 1): diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 5346b39043f0f5..3ba7cf7b04266f 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1999,6 +1999,7 @@ def test_nameconstant(self): 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', ]) + @support.requires_resource('cpu') def test_stdlib_validates(self): stdlib = os.path.dirname(ast.__file__) tests = [fn for fn in os.listdir(stdlib) if fn.endswith(".py")] diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 9f00bd5e76195f..aafbb8a993def5 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -1028,6 +1028,7 @@ def match(req, flag): ndim=ndim, shape=shape, strides=strides, lst=lst, sliced=sliced) + @support.requires_resource('cpu') def test_ndarray_getbuf(self): requests = ( # distinct flags @@ -2759,6 +2760,7 @@ def iter_roundtrip(ex, m, items, fmt): m = memoryview(ex) iter_roundtrip(ex, m, items, fmt) + @support.requires_resource('cpu') def test_memoryview_cast_1D_ND(self): # Cast between C-contiguous buffers. At least one buffer must # be 1D, at least one format must be 'c', 'b' or 'B'. diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 1257b529038afb..daac1008829b4c 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -927,6 +927,7 @@ def test_filter_pickle(self): f2 = filter(filter_char, "abcdeabcde") self.check_iter_pickle(f1, list(f2), proto) + @support.requires_resource('cpu') def test_filter_dealloc(self): # Tests recursive deallocation of nested filter objects using the # thrashcan mechanism. See gh-102356 for more details. diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 55e55c7d2884d0..19b5aebdd38198 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -784,6 +784,7 @@ def test_path_like_objects(self): # An implicit test for PyUnicode_FSDecoder(). compile("42", FakePath("test_compile_pathlike"), "single") + @support.requires_resource('cpu') def test_stack_overflow(self): # bpo-31113: Stack overflow when compile a long sequence of # complex statements. diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index 05154c8f1c6057..df7c5122b3b1f5 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -551,6 +551,7 @@ def test_no_args_compiles_path(self): self.assertNotCompiled(self.barfn) @without_source_date_epoch # timestamp invalidation test + @support.requires_resource('cpu') def test_no_args_respects_force_flag(self): bazfn = script_helper.make_script(self.directory, 'baz', '') with self.temporary_pycache_prefix() as env: @@ -568,6 +569,7 @@ def test_no_args_respects_force_flag(self): mtime2 = os.stat(pycpath).st_mtime self.assertNotEqual(mtime, mtime2) + @support.requires_resource('cpu') def test_no_args_respects_quiet_flag(self): script_helper.make_script(self.directory, 'baz', '') with self.temporary_pycache_prefix() as env: diff --git a/Lib/test/test_concurrent_futures/test_thread_pool.py b/Lib/test/test_concurrent_futures/test_thread_pool.py index daef7b5a836825..812f989d8f3ad2 100644 --- a/Lib/test/test_concurrent_futures/test_thread_pool.py +++ b/Lib/test/test_concurrent_futures/test_thread_pool.py @@ -6,6 +6,7 @@ import threading import unittest from concurrent import futures +from test import support from .executor import ExecutorTest, mul from .util import BaseTestCase, ThreadPoolMixin, setup_module @@ -49,6 +50,7 @@ def test_idle_thread_reuse(self): executor.shutdown(wait=True) @unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork') + @support.requires_resource('cpu') def test_hang_global_shutdown_lock(self): # bpo-45021: _global_shutdown_lock should be reinitialized in the child # process, otherwise it will never exit diff --git a/Lib/test/test_context.py b/Lib/test/test_context.py index b1aece4f5c9c49..dc6856509a40a0 100644 --- a/Lib/test/test_context.py +++ b/Lib/test/test_context.py @@ -6,6 +6,7 @@ import time import unittest import weakref +from test import support from test.support import threading_helper try: @@ -570,6 +571,7 @@ def test_hamt_collision_3(self): self.assertEqual({k.name for k in h.keys()}, {'C', 'D', 'E'}) + @support.requires_resource('cpu') def test_hamt_stress(self): COLLECTION_SIZE = 7000 TEST_ITERS_EVERY = 647 diff --git a/Lib/test/test_cppext/__init__.py b/Lib/test/test_cppext/__init__.py index f3d32a3c7612c9..a322f417a774f0 100644 --- a/Lib/test/test_cppext/__init__.py +++ b/Lib/test/test_cppext/__init__.py @@ -17,9 +17,11 @@ @support.requires_subprocess() class TestCPPExt(unittest.TestCase): + @support.requires_resource('cpu') def test_build_cpp11(self): self.check_build(False, '_testcpp11ext') + @support.requires_resource('cpu') def test_build_cpp03(self): self.check_build(True, '_testcpp03ext') diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index ad3eefba365856..9d8b1497330f0a 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4457,6 +4457,7 @@ class Oops(object): o.whatever = Provoker(o) del o + @support.requires_resource('cpu') def test_wrapper_segfault(self): # SF 927248: deeply nested wrappers could cause stack overflow f = lambda:None diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index cdb6ef1275e520..2a237095b9080c 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -38,6 +38,7 @@ from email import quoprimime from email import utils +from test import support from test.support import threading_helper from test.support.os_helper import unlink from test.test_email import openfile, TestEmailBase @@ -3358,6 +3359,7 @@ def test_getaddresses_header_obj(self): self.assertEqual(addrs[0][1], 'aperson@dom.ain') @threading_helper.requires_working_threading() + @support.requires_resource('cpu') def test_make_msgid_collisions(self): # Test make_msgid uniqueness, even with multiple threads class MsgidsThread(Thread): diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index f3554f1c4bb3f3..72afb3b0fb03f8 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1350,6 +1350,7 @@ def g(): @cpython_only + @support.requires_resource('cpu') def test_trashcan_recursion(self): # See bpo-33930 diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 311a864a52387d..78d602873fd86f 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -317,6 +317,7 @@ def assertGdbRepr(self, val, exp_repr=None): ('%r did not equal expected %r; full output was:\n%s' % (gdb_repr, exp_repr, gdb_output))) + @support.requires_resource('cpu') def test_int(self): 'Verify the pretty-printing of various int values' self.assertGdbRepr(42) @@ -343,6 +344,7 @@ def test_lists(self): self.assertGdbRepr([]) self.assertGdbRepr(list(range(5))) + @support.requires_resource('cpu') def test_bytes(self): 'Verify the pretty-printing of bytes' self.assertGdbRepr(b'') @@ -357,6 +359,7 @@ def test_bytes(self): self.assertGdbRepr(bytes([b for b in range(255)])) + @support.requires_resource('cpu') def test_strings(self): 'Verify the pretty-printing of unicode strings' # We cannot simply call locale.getpreferredencoding() here, @@ -407,6 +410,7 @@ def test_tuples(self): self.assertGdbRepr((1,), '(1,)') self.assertGdbRepr(('foo', 'bar', 'baz')) + @support.requires_resource('cpu') def test_sets(self): 'Verify the pretty-printing of sets' if (gdb_major_version, gdb_minor_version) < (7, 3): @@ -425,6 +429,7 @@ def test_sets(self): id(s)''') self.assertEqual(gdb_repr, "{'b'}") + @support.requires_resource('cpu') def test_frozensets(self): 'Verify the pretty-printing of frozensets' if (gdb_major_version, gdb_minor_version) < (7, 3): @@ -828,6 +833,7 @@ def test_bt_full(self): @unittest.skipIf(python_is_optimized(), "Python was compiled with optimizations") + @support.requires_resource('cpu') def test_threads(self): 'Verify that "py-bt" indicates threads that are waiting for the GIL' cmd = ''' @@ -889,6 +895,7 @@ def test_gc(self): @unittest.skipIf(python_is_optimized(), "Python was compiled with optimizations") + @support.requires_resource('cpu') # Some older versions of gdb will fail with # "Cannot find new threads: generic error" # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround diff --git a/Lib/test/test_interpreters.py b/Lib/test/test_interpreters.py index 662eafa3b7a104..27a143c7f5f38d 100644 --- a/Lib/test/test_interpreters.py +++ b/Lib/test/test_interpreters.py @@ -470,12 +470,14 @@ class StressTests(TestBase): # In these tests we generally want a lot of interpreters, # but not so many that any test takes too long. + @support.requires_resource('cpu') def test_create_many_sequential(self): alive = [] for _ in range(100): interp = interpreters.create() alive.append(interp) + @support.requires_resource('cpu') def test_create_many_threaded(self): alive = [] def task(): diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 4d6ea780e15373..512745e45350d1 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -2401,6 +2401,7 @@ def gen2(x): self.assertEqual(hist, [0,1]) @support.skip_if_pgo_task + @support.requires_resource('cpu') def test_long_chain_of_empty_iterables(self): # Make sure itertools.chain doesn't run into recursion limits when # dealing with long chains of empty iterables. Even with a high diff --git a/Lib/test/test_largefile.py b/Lib/test/test_largefile.py index 3c11c59baef6e5..3b0930fe69e30e 100644 --- a/Lib/test/test_largefile.py +++ b/Lib/test/test_largefile.py @@ -8,7 +8,7 @@ import socket import shutil import threading -from test.support import requires, bigmemtest +from test.support import requires, bigmemtest, requires_resource from test.support import SHORT_TIMEOUT from test.support import socket_helper from test.support.os_helper import TESTFN, unlink @@ -173,6 +173,7 @@ class TestCopyfile(LargeFileTest, unittest.TestCase): # Exact required disk space would be (size * 2), but let's give it a # bit more tolerance. @skip_no_disk_space(TESTFN, size * 2.5) + @requires_resource('cpu') def test_it(self): # Internally shutil.copyfile() can use "fast copy" methods like # os.sendfile(). @@ -222,6 +223,7 @@ def run(sock): # Exact required disk space would be (size * 2), but let's give it a # bit more tolerance. @skip_no_disk_space(TESTFN, size * 2.5) + @requires_resource('cpu') def test_it(self): port = socket_helper.find_unused_port() with socket.create_server(("", port)) as sock: diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py index cf8bb5e3a0520d..6451df14696933 100644 --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -363,6 +363,7 @@ def test_iso2022_jp_g0(self): e = '\u3406'.encode(encoding) self.assertFalse(any(x > 0x80 for x in e)) + @support.requires_resource('cpu') def test_bug1572832(self): for x in range(0x10000, 0x110000): # Any ISO 2022 codec will cause the segfault diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 255e9280421423..0aabce880053d6 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -4,6 +4,7 @@ import textwrap import unittest +from test import support from test.support.bytecode_helper import BytecodeTestCase, CfgOptimizationTestCase @@ -522,6 +523,7 @@ def genexpr(): return (y for x in a for y in [f(x)]) self.assertEqual(count_instr_recursively(genexpr, 'FOR_ITER'), 1) + @support.requires_resource('cpu') def test_format_combinations(self): flags = '-+ #0' testcases = [ diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index 6aaa288c14e1d7..628c8cae38a751 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -12,7 +12,7 @@ import textwrap import unittest import warnings -from test.support import no_tracing, verbose, requires_subprocess +from test.support import no_tracing, verbose, requires_subprocess, requires_resource from test.support.import_helper import forget, make_legacy_pyc, unload from test.support.os_helper import create_empty_file, temp_dir from test.support.script_helper import make_script, make_zip_script @@ -733,6 +733,7 @@ def test_zipfile_error(self): self._check_import_error(zip_name, msg) @no_tracing + @requires_resource('cpu') def test_main_recursion_error(self): with temp_dir() as script_dir, temp_dir() as dummy_dir: mod_name = '__main__' diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py index c2db88c203920a..12ecc50d550c4f 100644 --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -449,6 +449,7 @@ class ScalableSelectorMixIn: # see issue #18963 for why it's skipped on older OS X versions @support.requires_mac_ver(10, 5) @unittest.skipUnless(resource, "Test needs resource module") + @support.requires_resource('cpu') def test_above_fd_setsize(self): # A scalable implementation should have no problem with more than # FD_SETSIZE file descriptors. Since we don't know the value, we just diff --git a/Lib/test/test_source_encoding.py b/Lib/test/test_source_encoding.py index b05173ad00d442..72c2b47779e005 100644 --- a/Lib/test/test_source_encoding.py +++ b/Lib/test/test_source_encoding.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import unittest -from test.support import script_helper, captured_stdout, requires_subprocess +from test.support import script_helper, captured_stdout, requires_subprocess, requires_resource from test.support.os_helper import TESTFN, unlink, rmtree from test.support.import_helper import unload import importlib @@ -250,6 +250,7 @@ def test_crcrcrlf2(self): class UTF8ValidatorTest(unittest.TestCase): @unittest.skipIf(not sys.platform.startswith("linux"), "Too slow to run on non-Linux platforms") + @requires_resource('cpu') def test_invalid_utf8(self): # This is a port of test_utf8_decode_invalid_sequences in # test_unicode.py to exercise the separate utf8 validator in diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index f0fa6454b1f91a..0080d9960409a8 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -2139,6 +2139,7 @@ def test_integer_sqrt_of_frac_rto(self): self.assertTrue(m * (r - 1)**2 < n < m * (r + 1)**2) @requires_IEEE_754 + @support.requires_resource('cpu') def test_float_sqrt_of_frac(self): def is_root_correctly_rounded(x: Fraction, root: float) -> bool: @@ -2770,6 +2771,7 @@ def test_cdf(self): self.assertTrue(math.isnan(X.cdf(float('NaN')))) @support.skip_if_pgo_task + @support.requires_resource('cpu') def test_inv_cdf(self): NormalDist = self.module.NormalDist diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 817eab0c8a7e19..0b9e9e16f55d7e 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1292,6 +1292,7 @@ def test_bufsize_equal_one_binary_mode(self): with self.assertWarnsRegex(RuntimeWarning, 'line buffering'): self._test_bufsize_equal_one(line, b'', universal_newlines=False) + @support.requires_resource('cpu') def test_leaking_fds_on_error(self): # see bug #5179: Popen leaks file descriptors to PIPEs if # the child fails to execute; this will eventually exhaust diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 85d692f3097494..23c6bd226b5bf6 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -500,6 +500,7 @@ def check_options(self, args, func, expected=None): self.assertEqual(proc.stdout.rstrip(), repr(expected)) self.assertEqual(proc.returncode, 0) + @support.requires_resource('cpu') def test_args_from_interpreter_flags(self): # Test test.support.args_from_interpreter_flags() for opts in ( diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 5603c3cdbf3c5e..59dd23348c866d 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -2812,6 +2812,7 @@ def test_jump_extended_args_unpack_ex_tricky(output): ) = output.append(4) or "Spam" output.append(5) + @support.requires_resource('cpu') def test_jump_extended_args_for_iter(self): # In addition to failing when extended arg handling is broken, this can # also hang for a *very* long time: diff --git a/Lib/test/test_tools/test_freeze.py b/Lib/test/test_tools/test_freeze.py index 2ba36ca208f967..922e74b441457a 100644 --- a/Lib/test/test_tools/test_freeze.py +++ b/Lib/test/test_tools/test_freeze.py @@ -17,6 +17,7 @@ @support.skip_if_buildbot('not all buildbots have enough space') class TestFreeze(unittest.TestCase): + @support.requires_resource('cpu') # Building Python is slow def test_freeze_simple_script(self): script = textwrap.dedent(""" import sys diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index 73339ebdb7c4e9..d1ef005a4314ed 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -1,7 +1,7 @@ import os from pickle import dump import sys -from test.support import captured_stdout +from test.support import captured_stdout, requires_resource from test.support.os_helper import (TESTFN, rmtree, unlink) from test.support.script_helper import assert_python_ok, assert_python_failure import textwrap @@ -367,6 +367,7 @@ def _coverage(self, tracer, r = tracer.results() r.write_results(show_missing=True, summary=True, coverdir=TESTFN) + @requires_resource('cpu') def test_coverage(self): tracer = trace.Trace(trace=0, count=1) with captured_stdout() as stdout: diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 9476e2c89def49..7bfeda8dc95b04 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -3525,6 +3525,7 @@ def CHECK(a, b, expected): CHECK("AttributeError", "AttributeErrorTests", 10) CHECK("ABA", "AAB", 4) + @support.requires_resource('cpu') def test_levenshtein_distance_short_circuit(self): if not LEVENSHTEIN_DATA_FILE.is_file(): self.fail( diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 3dc0790ca15b41..515c3840cb3647 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -313,6 +313,7 @@ def test_ucd_510(self): self.assertTrue("\u1d79".upper()=='\ua77d') self.assertTrue(".".upper()=='.') + @requires_resource('cpu') def test_bug_5828(self): self.assertEqual("\u1d79".lower(), "\u1d79") # Only U+0000 should have U+0000 as its upper/lower/titlecase variant @@ -353,6 +354,7 @@ def unistr(data): return "".join([chr(x) for x in data]) @requires_resource('network') + @requires_resource('cpu') def test_normalization(self): TESTDATAFILE = "NormalizationTest.txt" TESTDATAURL = f"http://www.pythontest.net/unicode/{unicodedata.unidata_version}/{TESTDATAFILE}" diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 5205604c2c7185..aa6a8fbf8cfd17 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -20,7 +20,8 @@ from test.support import (captured_stdout, captured_stderr, skip_if_broken_multiprocessing_synchronize, verbose, requires_subprocess, is_emscripten, is_wasi, - requires_venv_with_pip, TEST_HOME_DIR) + requires_venv_with_pip, TEST_HOME_DIR, + requires_resource) from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv @@ -775,6 +776,7 @@ def nicer_error(self): ) @requires_venv_with_pip() + @requires_resource('cpu') def test_with_pip(self): self.do_test_with_pip(False) self.do_test_with_pip(True) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 1bc1d05f7daba9..4cdd66d3769e0c 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1933,6 +1933,7 @@ def test_threaded_weak_key_dict_copy(self): self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, False) @threading_helper.requires_working_threading() + @support.requires_resource('cpu') def test_threaded_weak_key_dict_deepcopy(self): # Issue #35615: Weakref keys or values getting GC'ed during dict # copying should not result in a crash. @@ -1945,6 +1946,7 @@ def test_threaded_weak_value_dict_copy(self): self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False) @threading_helper.requires_working_threading() + @support.requires_resource('cpu') def test_threaded_weak_value_dict_deepcopy(self): # Issue #35615: Weakref keys or values getting GC'ed during dict # copying should not result in a crash. From c8cf6be213826c8d0e3e2acbcf31b8c1069df3ed Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 Sep 2023 13:45:50 +0200 Subject: [PATCH 0682/1206] [3.12] gh-108822: regrtest computes statistics (#108793) (#108833) gh-108822: regrtest computes statistics (#108793) test_netrc, test_pep646_syntax and test_xml_etree now return results in the test_main() function. Changes: * Rewrite TestResult as a dataclass with a new State class. * Add test.support.TestStats class and Regrtest.stats_dict attribute. * libregrtest.runtest functions now modify a TestResult instance in-place. * libregrtest summary lists the number of run tests and skipped tests, and denied resources. * Add TestResult.has_meaningful_duration() method. * Compute TestResult duration in the upper function. * Use time.perf_counter() instead of time.monotonic(). * Regrtest: rename 'resource_denieds' attribute to 'resource_denied'. * Rename CHILD_ERROR to MULTIPROCESSING_ERROR. * Use match/case syntadx to have different code depending on the test state. Notes on the backport: doctest.TestResults.skipped is a new feature in Python 3.13, so don't use it in the backport. Co-authored-by: Alex Waygood (cherry picked from commit d4e534cbb35678c82b3a1276826af55d7bfc23b6) --- Lib/test/libregrtest/main.py | 126 +++++++---- Lib/test/libregrtest/refleak.py | 5 +- Lib/test/libregrtest/runtest.py | 324 ++++++++++++++++------------- Lib/test/libregrtest/runtest_mp.py | 84 ++++---- Lib/test/libregrtest/save_env.py | 8 +- Lib/test/support/__init__.py | 60 ++++-- Lib/test/test_netrc.py | 2 +- Lib/test/test_pep646_syntax.py | 2 +- Lib/test/test_regrtest.py | 206 +++++++++++++----- Lib/test/test_xml_etree.py | 2 +- 10 files changed, 511 insertions(+), 308 deletions(-) diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 3df95db3eb6e1d..a357bd9c386c3b 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -11,15 +11,14 @@ import unittest from test.libregrtest.cmdline import _parse_args from test.libregrtest.runtest import ( - findtests, split_test_packages, runtest, get_abs_module, is_failed, - PROGRESS_MIN_TIME, - Passed, Failed, EnvChanged, Skipped, ResourceDenied, Interrupted, - ChildError, DidNotRun) + findtests, split_test_packages, runtest, get_abs_module, + PROGRESS_MIN_TIME, State) from test.libregrtest.setup import setup_tests from test.libregrtest.pgo import setup_pgo_tests from test.libregrtest.utils import (removepy, count, format_duration, printlist, get_build_info) from test import support +from test.support import TestStats from test.support import os_helper from test.support import threading_helper @@ -78,13 +77,14 @@ def __init__(self): self.good = [] self.bad = [] self.skipped = [] - self.resource_denieds = [] + self.resource_denied = [] self.environment_changed = [] self.run_no_tests = [] self.need_rerun = [] self.rerun = [] self.first_result = None self.interrupted = False + self.stats_dict: dict[str, TestStats] = {} # used by --slow self.test_times = [] @@ -93,7 +93,7 @@ def __init__(self): self.tracer = None # used to display the progress bar "[ 3/100]" - self.start_time = time.monotonic() + self.start_time = time.perf_counter() self.test_count = '' self.test_count_width = 1 @@ -111,36 +111,41 @@ def __init__(self): def get_executed(self): return (set(self.good) | set(self.bad) | set(self.skipped) - | set(self.resource_denieds) | set(self.environment_changed) + | set(self.resource_denied) | set(self.environment_changed) | set(self.run_no_tests)) def accumulate_result(self, result, rerun=False): - test_name = result.name - - if not isinstance(result, (ChildError, Interrupted)) and not rerun: - self.test_times.append((result.duration_sec, test_name)) - - if isinstance(result, Passed): - self.good.append(test_name) - elif isinstance(result, ResourceDenied): - self.skipped.append(test_name) - self.resource_denieds.append(test_name) - elif isinstance(result, Skipped): - self.skipped.append(test_name) - elif isinstance(result, EnvChanged): - self.environment_changed.append(test_name) - elif isinstance(result, Failed): - if not rerun: - self.bad.append(test_name) - self.need_rerun.append(result) - elif isinstance(result, DidNotRun): - self.run_no_tests.append(test_name) - elif isinstance(result, Interrupted): - self.interrupted = True - else: - raise ValueError("invalid test result: %r" % result) + test_name = result.test_name + + if result.has_meaningful_duration() and not rerun: + self.test_times.append((result.duration, test_name)) - if rerun and not isinstance(result, (Failed, Interrupted)): + match result.state: + case State.PASSED: + self.good.append(test_name) + case State.ENV_CHANGED: + self.environment_changed.append(test_name) + case State.SKIPPED: + self.skipped.append(test_name) + case State.RESOURCE_DENIED: + self.skipped.append(test_name) + self.resource_denied.append(test_name) + case State.INTERRUPTED: + self.interrupted = True + case State.DID_NOT_RUN: + self.run_no_tests.append(test_name) + case _: + if result.is_failed(self.ns.fail_env_changed): + if not rerun: + self.bad.append(test_name) + self.need_rerun.append(result) + else: + raise ValueError(f"invalid test state: {state!r}") + + if result.stats is not None: + self.stats_dict[result.test_name] = result.stats + + if rerun and not(result.is_failed(False) or result.state == State.INTERRUPTED): self.bad.remove(test_name) xml_data = result.xml_data @@ -162,7 +167,7 @@ def log(self, line=''): line = f"load avg: {load_avg:.2f} {line}" # add the timestamp prefix: "0:01:05 " - test_time = time.monotonic() - self.start_time + test_time = time.perf_counter() - self.start_time mins, secs = divmod(int(test_time), 60) hours, mins = divmod(mins, 60) @@ -337,7 +342,7 @@ def rerun_failed_tests(self): rerun_list = list(self.need_rerun) self.need_rerun.clear() for result in rerun_list: - test_name = result.name + test_name = result.test_name self.rerun.append(test_name) errors = result.errors or [] @@ -364,7 +369,7 @@ def rerun_failed_tests(self): self.accumulate_result(result, rerun=True) - if isinstance(result, Interrupted): + if result.state == State.INTERRUPTED: break if self.bad: @@ -461,7 +466,7 @@ def run_tests_sequential(self): previous_test = None for test_index, test_name in enumerate(self.tests, 1): - start_time = time.monotonic() + start_time = time.perf_counter() text = test_name if previous_test: @@ -480,14 +485,14 @@ def run_tests_sequential(self): result = runtest(self.ns, test_name) self.accumulate_result(result) - if isinstance(result, Interrupted): + if result.state == State.INTERRUPTED: break previous_test = str(result) - test_time = time.monotonic() - start_time + test_time = time.perf_counter() - start_time if test_time >= PROGRESS_MIN_TIME: previous_test = "%s in %s" % (previous_test, format_duration(test_time)) - elif isinstance(result, Passed): + elif result.state == State.PASSED: # be quiet: say nothing if the test passed shortly previous_test = None @@ -496,7 +501,7 @@ def run_tests_sequential(self): if module not in save_modules and module.startswith("test."): support.unload(module) - if self.ns.failfast and is_failed(result, self.ns): + if self.ns.failfast and result.is_failed(self.ns.fail_env_changed): break if previous_test: @@ -631,13 +636,48 @@ def finalize(self): coverdir=self.ns.coverdir) print() - duration = time.monotonic() - self.start_time - print("Total duration: %s" % format_duration(duration)) - print("Tests result: %s" % self.get_tests_result()) + self.display_summary() if self.ns.runleaks: os.system("leaks %d" % os.getpid()) + def display_summary(self): + duration = time.perf_counter() - self.start_time + + # Total duration + print("Total duration: %s" % format_duration(duration)) + + # Total tests + total = TestStats() + for stats in self.stats_dict.values(): + total.accumulate(stats) + stats = [f'run={total.tests_run:,}'] + if total.failures: + stats.append(f'failures={total.failures:,}') + if total.skipped: + stats.append(f'skipped={total.skipped:,}') + print(f"Total tests: {' '.join(stats)}") + + # Total test files + report = [f'success={len(self.good)}'] + if self.bad: + report.append(f'failed={len(self.bad)}') + if self.environment_changed: + report.append(f'env_changed={len(self.environment_changed)}') + if self.skipped: + report.append(f'skipped={len(self.skipped)}') + if self.resource_denied: + report.append(f'resource_denied={len(self.resource_denied)}') + if self.rerun: + report.append(f'rerun={len(self.rerun)}') + if self.run_no_tests: + report.append(f'run_no_tests={len(self.run_no_tests)}') + print(f"Total test files: {' '.join(report)}") + + # Result + result = self.get_tests_result() + print(f"Result: {result}") + def save_xml_result(self): if not self.ns.xmlpath and not self.testsuite_xml: return diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index cd11d385591f80..206802b60ddcd0 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -83,11 +83,12 @@ def get_pooled_int(value): print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr, flush=True) + results = None dash_R_cleanup(fs, ps, pic, zdc, abcs) support.gc_collect() for i in rep_range: - test_func() + results = test_func() dash_R_cleanup(fs, ps, pic, zdc, abcs) support.gc_collect() @@ -151,7 +152,7 @@ def check_fd_deltas(deltas): print(msg, file=refrep) refrep.flush() failed = True - return failed + return (failed, results) def dash_R_cleanup(fs, ps, pic, zdc, abcs): diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index fd49927679bdea..6fa60697371b72 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -1,3 +1,5 @@ +import dataclasses +import doctest import faulthandler import functools import gc @@ -10,6 +12,7 @@ import unittest from test import support +from test.support import TestStats from test.support import os_helper from test.support import threading_helper from test.libregrtest.cmdline import Namespace @@ -17,108 +20,114 @@ from test.libregrtest.utils import clear_caches, format_duration, print_warning -class TestResult: - def __init__( - self, - name: str, - duration_sec: float = 0.0, - xml_data: list[str] | None = None, - ) -> None: - self.name = name - self.duration_sec = duration_sec - self.xml_data = xml_data - - def __str__(self) -> str: - return f"{self.name} finished" - +# Avoid enum.Enum to reduce the number of imports when tests are run +class State: + PASSED = "PASSED" + FAILED = "FAILED" + SKIPPED = "SKIPPED" + UNCAUGHT_EXC = "UNCAUGHT_EXC" + REFLEAK = "REFLEAK" + ENV_CHANGED = "ENV_CHANGED" + RESOURCE_DENIED = "RESOURCE_DENIED" + INTERRUPTED = "INTERRUPTED" + MULTIPROCESSING_ERROR = "MULTIPROCESSING_ERROR" + DID_NOT_RUN = "DID_NOT_RUN" + TIMEOUT = "TIMEOUT" -class Passed(TestResult): - def __str__(self) -> str: - return f"{self.name} passed" - - -class Failed(TestResult): - def __init__( - self, - name: str, - duration_sec: float = 0.0, - xml_data: list[str] | None = None, - errors: list[tuple[str, str]] | None = None, - failures: list[tuple[str, str]] | None = None, - ) -> None: - super().__init__(name, duration_sec=duration_sec, xml_data=xml_data) - self.errors = errors - self.failures = failures + @staticmethod + def is_failed(state): + return state in { + State.FAILED, + State.UNCAUGHT_EXC, + State.REFLEAK, + State.MULTIPROCESSING_ERROR, + State.TIMEOUT} - def __str__(self) -> str: + @staticmethod + def has_meaningful_duration(state): + # Consider that the duration is meaningless for these cases. + # For example, if a whole test file is skipped, its duration + # is unlikely to be the duration of executing its tests, + # but just the duration to execute code which skips the test. + return state not in { + State.SKIPPED, + State.RESOURCE_DENIED, + State.INTERRUPTED, + State.MULTIPROCESSING_ERROR, + State.DID_NOT_RUN} + + +@dataclasses.dataclass(slots=True) +class TestResult: + test_name: str + state: str | None = None + # Test duration in seconds + duration: float | None = None + xml_data: list[str] | None = None + stats: TestStats | None = None + + # errors and failures copied from support.TestFailedWithDetails + errors: list[tuple[str, str]] | None = None + failures: list[tuple[str, str]] | None = None + + def is_failed(self, fail_env_changed: bool) -> bool: + if self.state == State.ENV_CHANGED: + return fail_env_changed + return State.is_failed(self.state) + + def _format_failed(self): if self.errors and self.failures: le = len(self.errors) lf = len(self.failures) error_s = "error" + ("s" if le > 1 else "") failure_s = "failure" + ("s" if lf > 1 else "") - return f"{self.name} failed ({le} {error_s}, {lf} {failure_s})" + return f"{self.test_name} failed ({le} {error_s}, {lf} {failure_s})" if self.errors: le = len(self.errors) error_s = "error" + ("s" if le > 1 else "") - return f"{self.name} failed ({le} {error_s})" + return f"{self.test_name} failed ({le} {error_s})" if self.failures: lf = len(self.failures) failure_s = "failure" + ("s" if lf > 1 else "") - return f"{self.name} failed ({lf} {failure_s})" - - return f"{self.name} failed" + return f"{self.test_name} failed ({lf} {failure_s})" + return f"{self.test_name} failed" -class UncaughtException(Failed): def __str__(self) -> str: - return f"{self.name} failed (uncaught exception)" - - -class EnvChanged(Failed): - def __str__(self) -> str: - return f"{self.name} failed (env changed)" - - # Convert Passed to EnvChanged - @staticmethod - def from_passed(other): - return EnvChanged(other.name, other.duration_sec, other.xml_data) - - -class RefLeak(Failed): - def __str__(self) -> str: - return f"{self.name} failed (reference leak)" - - -class Skipped(TestResult): - def __str__(self) -> str: - return f"{self.name} skipped" - - -class ResourceDenied(Skipped): - def __str__(self) -> str: - return f"{self.name} skipped (resource denied)" - - -class Interrupted(TestResult): - def __str__(self) -> str: - return f"{self.name} interrupted" - - -class ChildError(Failed): - def __str__(self) -> str: - return f"{self.name} crashed" - - -class DidNotRun(TestResult): - def __str__(self) -> str: - return f"{self.name} ran no tests" - - -class Timeout(Failed): - def __str__(self) -> str: - return f"{self.name} timed out ({format_duration(self.duration_sec)})" + match self.state: + case State.PASSED: + return f"{self.test_name} passed" + case State.FAILED: + return self._format_failed() + case State.SKIPPED: + return f"{self.test_name} skipped" + case State.UNCAUGHT_EXC: + return f"{self.test_name} failed (uncaught exception)" + case State.REFLEAK: + return f"{self.test_name} failed (reference leak)" + case State.ENV_CHANGED: + return f"{self.test_name} failed (env changed)" + case State.RESOURCE_DENIED: + return f"{self.test_name} skipped (resource denied)" + case State.INTERRUPTED: + return f"{self.test_name} interrupted" + case State.MULTIPROCESSING_ERROR: + return f"{self.test_name} process crashed" + case State.DID_NOT_RUN: + return f"{self.test_name} ran no tests" + case State.TIMEOUT: + return f"{self.test_name} timed out ({format_duration(self.duration)})" + case _: + raise ValueError("unknown result state: {state!r}") + + def has_meaningful_duration(self): + return State.has_meaningful_duration(self.state) + + def set_env_changed(self): + if self.state is None or self.state == State.PASSED: + self.state = State.ENV_CHANGED # Minimum duration of a test to display its duration or to mention that @@ -142,12 +151,6 @@ def __str__(self) -> str: FOUND_GARBAGE = [] -def is_failed(result: TestResult, ns: Namespace) -> bool: - if isinstance(result, EnvChanged): - return ns.fail_env_changed - return isinstance(result, Failed) - - def findtestdir(path=None): return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir @@ -194,9 +197,9 @@ def get_abs_module(ns: Namespace, test_name: str) -> str: return 'test.' + test_name -def _runtest(ns: Namespace, test_name: str) -> TestResult: - # Handle faulthandler timeout, capture stdout+stderr, XML serialization - # and measure time. +def _runtest_capture_output_timeout_junit(result: TestResult, ns: Namespace) -> None: + # Capture stdout and stderr, set faulthandler timeout, + # and create JUnit XML report. output_on_failure = ns.verbose3 @@ -206,7 +209,6 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult: if use_timeout: faulthandler.dump_traceback_later(ns.timeout, exit=True) - start_time = time.perf_counter() try: support.set_match_tests(ns.match_tests, ns.ignore_tests) support.junit_xml_list = xml_list = [] if ns.xmlpath else None @@ -231,9 +233,9 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult: # warnings will be written to sys.stderr below. print_warning.orig_stderr = stream - result = _runtest_inner(ns, test_name, - display_failure=False) - if not isinstance(result, Passed): + _runtest_env_changed_exc(result, ns, display_failure=False) + # Ignore output if the test passed successfully + if result.state != State.PASSED: output = stream.getvalue() finally: sys.stdout = orig_stdout @@ -247,18 +249,13 @@ def _runtest(ns: Namespace, test_name: str) -> TestResult: # Tell tests to be moderately quiet support.verbose = ns.verbose - result = _runtest_inner(ns, test_name, - display_failure=not ns.verbose) + _runtest_env_changed_exc(result, ns, + display_failure=not ns.verbose) if xml_list: import xml.etree.ElementTree as ET - result.xml_data = [ - ET.tostring(x).decode('us-ascii') - for x in xml_list - ] - - result.duration_sec = time.perf_counter() - start_time - return result + result.xml_data = [ET.tostring(x).decode('us-ascii') + for x in xml_list] finally: if use_timeout: faulthandler.cancel_dump_traceback_later() @@ -271,19 +268,23 @@ def runtest(ns: Namespace, test_name: str) -> TestResult: ns -- regrtest namespace of options test_name -- the name of the test - Returns a TestResult sub-class depending on the kind of result received. + Returns a TestResult. If ns.xmlpath is not None, xml_data is a list containing each generated testsuite element. """ + start_time = time.perf_counter() + result = TestResult(test_name) try: - return _runtest(ns, test_name) + _runtest_capture_output_timeout_junit(result, ns) except: if not ns.pgo: msg = traceback.format_exc() print(f"test {test_name} crashed -- {msg}", file=sys.stderr, flush=True) - return Failed(test_name) + result.state = State.UNCAUGHT_EXC + result.duration = time.perf_counter() - start_time + return result def _test_module(the_module): @@ -293,18 +294,48 @@ def _test_module(the_module): print(error, file=sys.stderr) if loader.errors: raise Exception("errors while loading tests") - support.run_unittest(tests) + return support.run_unittest(tests) def save_env(ns: Namespace, test_name: str): return saved_test_environment(test_name, ns.verbose, ns.quiet, pgo=ns.pgo) -def _runtest_inner2(ns: Namespace, test_name: str) -> bool: - # Load the test function, run the test function, handle huntrleaks - # to detect leaks. +def regrtest_runner(result, test_func, ns) -> None: + # Run test_func(), collect statistics, and detect reference and memory + # leaks. + + if ns.huntrleaks: + from test.libregrtest.refleak import dash_R + refleak, test_result = dash_R(ns, result.test_name, test_func) + else: + test_result = test_func() + refleak = False + + if refleak: + result.state = State.REFLEAK + + match test_result: + case TestStats(): + stats = test_result + case unittest.TestResult(): + stats = TestStats.from_unittest(test_result) + case doctest.TestResults(): + stats = TestStats.from_doctest(test_result) + case None: + print_warning(f"{result.test_name} test runner returned None: {test_func}") + stats = None + case _: + print_warning(f"Unknown test result type: {type(test_result)}") + stats = None + + result.stats = stats + - abstest = get_abs_module(ns, test_name) +def _load_run_test(result: TestResult, ns: Namespace) -> None: + # Load the test function, run the test function. + + abstest = get_abs_module(ns, result.test_name) # remove the module from sys.module to reload it if it was already imported try: @@ -314,23 +345,15 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool: the_module = importlib.import_module(abstest) - if ns.huntrleaks: - from test.libregrtest.refleak import dash_R - # If the test has a test_main, that will run the appropriate # tests. If not, use normal unittest test loading. - test_runner = getattr(the_module, "test_main", None) - if test_runner is None: - test_runner = functools.partial(_test_module, the_module) + test_func = getattr(the_module, "test_main", None) + if test_func is None: + test_func = functools.partial(_test_module, the_module) try: - with save_env(ns, test_name): - if ns.huntrleaks: - # Return True if the test leaked references - refleak = dash_R(ns, test_name, test_runner) - else: - test_runner() - refleak = False + with save_env(ns, result.test_name): + regrtest_runner(result, test_func, ns) finally: # First kill any dangling references to open files etc. # This can also issue some ResourceWarnings which would otherwise get @@ -338,11 +361,11 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool: # failures. support.gc_collect() - cleanup_test_droppings(test_name, ns.verbose) + cleanup_test_droppings(result.test_name, ns.verbose) if gc.garbage: support.environment_altered = True - print_warning(f"{test_name} created {len(gc.garbage)} " + print_warning(f"{result.test_name} created {len(gc.garbage)} " f"uncollectable object(s).") # move the uncollectable objects somewhere, @@ -352,12 +375,9 @@ def _runtest_inner2(ns: Namespace, test_name: str) -> bool: support.reap_children() - return refleak - -def _runtest_inner( - ns: Namespace, test_name: str, display_failure: bool = True -) -> TestResult: +def _runtest_env_changed_exc(result: TestResult, ns: Namespace, + display_failure: bool = True) -> None: # Detect environment changes, handle exceptions. # Reset the environment_altered flag to detect if a test altered @@ -367,49 +387,61 @@ def _runtest_inner( if ns.pgo: display_failure = False + test_name = result.test_name try: clear_caches() support.gc_collect() with save_env(ns, test_name): - refleak = _runtest_inner2(ns, test_name) + _load_run_test(result, ns) except support.ResourceDenied as msg: if not ns.quiet and not ns.pgo: print(f"{test_name} skipped -- {msg}", flush=True) - return ResourceDenied(test_name) + result.state = State.RESOURCE_DENIED + return except unittest.SkipTest as msg: if not ns.quiet and not ns.pgo: print(f"{test_name} skipped -- {msg}", flush=True) - return Skipped(test_name) + result.state = State.SKIPPED + return except support.TestFailedWithDetails as exc: msg = f"test {test_name} failed" if display_failure: msg = f"{msg} -- {exc}" print(msg, file=sys.stderr, flush=True) - return Failed(test_name, errors=exc.errors, failures=exc.failures) + result.state = State.FAILED + result.errors = exc.errors + result.failures = exc.failures + result.stats = exc.stats + return except support.TestFailed as exc: msg = f"test {test_name} failed" if display_failure: msg = f"{msg} -- {exc}" print(msg, file=sys.stderr, flush=True) - return Failed(test_name) + result.state = State.FAILED + result.stats = exc.stats + return except support.TestDidNotRun: - return DidNotRun(test_name) + result.state = State.DID_NOT_RUN + return except KeyboardInterrupt: print() - return Interrupted(test_name) + result.state = State.INTERRUPTED + return except: if not ns.pgo: msg = traceback.format_exc() print(f"test {test_name} crashed -- {msg}", file=sys.stderr, flush=True) - return UncaughtException(test_name) + result.state = State.UNCAUGHT_EXC + return - if refleak: - return RefLeak(test_name) if support.environment_altered: - return EnvChanged(test_name) - return Passed(test_name) + result.set_env_changed() + # Don't override the state if it was already set (REFLEAK or ENV_CHANGED) + if result.state is None: + result.state = State.PASSED def cleanup_test_droppings(test_name: str, verbose: int) -> None: diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index 62e6c6df36518c..fb1f80b0c054e3 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -1,3 +1,4 @@ +import dataclasses import faulthandler import json import os.path @@ -13,12 +14,13 @@ from test import support from test.support import os_helper +from test.support import TestStats from test.libregrtest.cmdline import Namespace from test.libregrtest.main import Regrtest from test.libregrtest.runtest import ( - runtest, is_failed, TestResult, Interrupted, Timeout, ChildError, - PROGRESS_MIN_TIME, Passed, EnvChanged) + runtest, TestResult, State, + PROGRESS_MIN_TIME) from test.libregrtest.setup import setup_tests from test.libregrtest.utils import format_duration, print_warning @@ -43,9 +45,9 @@ def must_stop(result: TestResult, ns: Namespace) -> bool: - if isinstance(result, Interrupted): + if result.state == State.INTERRUPTED: return True - if ns.failfast and is_failed(result, ns): + if ns.failfast and result.is_failed(ns.fail_env_changed): return True return False @@ -130,8 +132,8 @@ def stop(self): class MultiprocessResult(NamedTuple): result: TestResult # bpo-45410: stderr is written into stdout to keep messages order - stdout: str - error_msg: str + worker_stdout: str | None = None + err_msg: str | None = None ExcStr = str @@ -209,15 +211,12 @@ def stop(self) -> None: def mp_result_error( self, test_result: TestResult, - stdout: str = '', + stdout: str | None = None, err_msg=None ) -> MultiprocessResult: - test_result.duration_sec = time.monotonic() - self.start_time return MultiprocessResult(test_result, stdout, err_msg) def _run_process(self, test_name: str, tmp_dir: str, stdout_fh: TextIO) -> int: - self.start_time = time.monotonic() - self.current_test_name = test_name try: popen = run_test_in_subprocess(test_name, self.ns, tmp_dir, stdout_fh) @@ -306,38 +305,41 @@ def _runtest(self, test_name: str) -> MultiprocessResult: # gh-101634: Catch UnicodeDecodeError if stdout cannot be # decoded from encoding err_msg = f"Cannot read process stdout: {exc}" - return self.mp_result_error(ChildError(test_name), '', err_msg) + result = TestResult(test_name, state=State.MULTIPROCESSING_ERROR) + return self.mp_result_error(result, err_msg=err_msg) if retcode is None: - return self.mp_result_error(Timeout(test_name), stdout) + result = TestResult(test_name, state=State.TIMEOUT) + return self.mp_result_error(result, stdout) err_msg = None if retcode != 0: err_msg = "Exit code %s" % retcode else: - stdout, _, result = stdout.rpartition("\n") + stdout, _, worker_json = stdout.rpartition("\n") stdout = stdout.rstrip() - if not result: + if not worker_json: err_msg = "Failed to parse worker stdout" else: try: # deserialize run_tests_worker() output - result = json.loads(result, object_hook=decode_test_result) + result = json.loads(worker_json, + object_hook=decode_test_result) except Exception as exc: err_msg = "Failed to parse worker JSON: %s" % exc - if err_msg is not None: - return self.mp_result_error(ChildError(test_name), stdout, err_msg) + if err_msg: + result = TestResult(test_name, state=State.MULTIPROCESSING_ERROR) + return self.mp_result_error(result, stdout, err_msg) if tmp_files: msg = (f'\n\n' f'Warning -- {test_name} leaked temporary files ' f'({len(tmp_files)}): {", ".join(sorted(tmp_files))}') stdout += msg - if isinstance(result, Passed): - result = EnvChanged.from_passed(result) + result.set_env_changed() - return MultiprocessResult(result, stdout, err_msg) + return MultiprocessResult(result, stdout) def run(self) -> None: while not self._stopped: @@ -347,7 +349,9 @@ def run(self) -> None: except StopIteration: break + self.start_time = time.monotonic() mp_result = self._runtest(test_name) + mp_result.result.duration = time.monotonic() - self.start_time self.output.put((False, mp_result)) if must_stop(mp_result.result, self.ns): @@ -473,11 +477,11 @@ def display_result(self, mp_result: MultiprocessResult) -> None: result = mp_result.result text = str(result) - if mp_result.error_msg is not None: - # CHILD_ERROR - text += ' (%s)' % mp_result.error_msg - elif (result.duration_sec >= PROGRESS_MIN_TIME and not self.ns.pgo): - text += ' (%s)' % format_duration(result.duration_sec) + if mp_result.err_msg: + # MULTIPROCESSING_ERROR + text += ' (%s)' % mp_result.err_msg + elif (result.duration >= PROGRESS_MIN_TIME and not self.ns.pgo): + text += ' (%s)' % format_duration(result.duration) running = get_running(self.workers) if running and not self.ns.pgo: text += ' -- running: %s' % ', '.join(running) @@ -489,7 +493,7 @@ def _process_result(self, item: QueueOutput) -> bool: # Thread got an exception format_exc = item[1] print_warning(f"regrtest worker thread failed: {format_exc}") - result = ChildError("") + result = TestResult("", state=State.MULTIPROCESSING_ERROR) self.regrtest.accumulate_result(result) return True @@ -498,8 +502,8 @@ def _process_result(self, item: QueueOutput) -> bool: self.regrtest.accumulate_result(mp_result.result) self.display_result(mp_result) - if mp_result.stdout: - print(mp_result.stdout, flush=True) + if mp_result.worker_stdout: + print(mp_result.worker_stdout, flush=True) if must_stop(mp_result.result, self.ns): return True @@ -541,32 +545,20 @@ class EncodeTestResult(json.JSONEncoder): def default(self, o: Any) -> dict[str, Any]: if isinstance(o, TestResult): - result = vars(o) + result = dataclasses.asdict(o) result["__test_result__"] = o.__class__.__name__ return result return super().default(o) -def decode_test_result(d: dict[str, Any]) -> TestResult | dict[str, Any]: +def decode_test_result(d: dict[str, Any]) -> TestResult | TestStats | dict[str, Any]: """Decode a TestResult (sub)class object from a JSON dict.""" if "__test_result__" not in d: return d - cls_name = d.pop("__test_result__") - for cls in get_all_test_result_classes(): - if cls.__name__ == cls_name: - return cls(**d) - - -def get_all_test_result_classes() -> set[type[TestResult]]: - prev_count = 0 - classes = {TestResult} - while len(classes) > prev_count: - prev_count = len(classes) - to_add = [] - for cls in classes: - to_add.extend(cls.__subclasses__()) - classes.update(to_add) - return classes + d.pop('__test_result__') + if d['stats'] is not None: + d['stats'] = TestStats(**d['stats']) + return TestResult(**d) diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py index c7801b767c590c..164fe9806b5f0d 100644 --- a/Lib/test/libregrtest/save_env.py +++ b/Lib/test/libregrtest/save_env.py @@ -23,7 +23,7 @@ class SkipTestEnvironment(Exception): class saved_test_environment: """Save bits of the test environment and restore them at block exit. - with saved_test_environment(testname, verbose, quiet): + with saved_test_environment(test_name, verbose, quiet): #stuff Unless quiet is True, a warning is printed to stderr if any of @@ -34,8 +34,8 @@ class saved_test_environment: items is also printed. """ - def __init__(self, testname, verbose=0, quiet=False, *, pgo=False): - self.testname = testname + def __init__(self, test_name, verbose=0, quiet=False, *, pgo=False): + self.test_name = test_name self.verbose = verbose self.quiet = quiet self.pgo = pgo @@ -323,7 +323,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): restore(original) if not self.quiet and not self.pgo: print_warning( - f"{name} was modified by {self.testname}\n" + f"{name} was modified by {self.test_name}\n" f" Before: {original}\n" f" After: {current} ") return False diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ef7b5c814d5d47..37d0fdee5511f8 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -4,6 +4,7 @@ raise ImportError('support must be imported from the test package') import contextlib +import dataclasses import functools import getpass import opcode @@ -118,17 +119,20 @@ class Error(Exception): class TestFailed(Error): """Test failed.""" + def __init__(self, msg, *args, stats=None): + self.msg = msg + self.stats = stats + super().__init__(msg, *args) + + def __str__(self): + return self.msg class TestFailedWithDetails(TestFailed): """Test failed.""" - def __init__(self, msg, errors, failures): - self.msg = msg + def __init__(self, msg, errors, failures, stats): self.errors = errors self.failures = failures - super().__init__(msg, errors, failures) - - def __str__(self): - return self.msg + super().__init__(msg, errors, failures, stats=stats) class TestDidNotRun(Error): """Test did not run any subtests.""" @@ -1108,6 +1112,29 @@ def _filter_suite(suite, pred): newtests.append(test) suite._tests = newtests +@dataclasses.dataclass(slots=True) +class TestStats: + tests_run: int = 0 + failures: int = 0 + skipped: int = 0 + + @staticmethod + def from_unittest(result): + return TestStats(result.testsRun, + len(result.failures), + len(result.skipped)) + + @staticmethod + def from_doctest(results): + return TestStats(results.attempted, + results.failed) + + def accumulate(self, stats): + self.tests_run += stats.tests_run + self.failures += stats.failures + self.skipped += stats.skipped + + def _run_suite(suite): """Run tests from a unittest.TestSuite-derived class.""" runner = get_test_runner(sys.stdout, @@ -1122,6 +1149,7 @@ def _run_suite(suite): if not result.testsRun and not result.skipped and not result.errors: raise TestDidNotRun if not result.wasSuccessful(): + stats = TestStats.from_unittest(result) if len(result.errors) == 1 and not result.failures: err = result.errors[0][1] elif len(result.failures) == 1 and not result.errors: @@ -1131,7 +1159,8 @@ def _run_suite(suite): if not verbose: err += "; run in verbose mode for details" errors = [(str(tc), exc_str) for tc, exc_str in result.errors] failures = [(str(tc), exc_str) for tc, exc_str in result.failures] - raise TestFailedWithDetails(err, errors, failures) + raise TestFailedWithDetails(err, errors, failures, stats=stats) + return result # By default, don't filter tests @@ -1240,7 +1269,7 @@ def run_unittest(*classes): else: suite.addTest(loader.loadTestsFromTestCase(cls)) _filter_suite(suite, match_test) - _run_suite(suite) + return _run_suite(suite) #======================================================================= # Check for the presence of docstrings. @@ -1280,13 +1309,18 @@ def run_doctest(module, verbosity=None, optionflags=0): else: verbosity = None - f, t = doctest.testmod(module, verbose=verbosity, optionflags=optionflags) - if f: - raise TestFailed("%d of %d doctests failed" % (f, t)) + results = doctest.testmod(module, + verbose=verbosity, + optionflags=optionflags) + if results.failed: + stats = TestStats.from_doctest(results) + raise TestFailed(f"{results.failed} of {results.attempted} " + f"doctests failed", + stats=stats) if verbose: print('doctest (%s) ... %d tests with zero failures' % - (module.__name__, t)) - return f, t + (module.__name__, results.attempted)) + return results #======================================================================= diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py index 573d636de956d1..b38cb327f68ecc 100644 --- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -309,7 +309,7 @@ def test_security(self): ('anonymous', '', 'pass')) def test_main(): - run_unittest(NetrcTestCase) + return run_unittest(NetrcTestCase) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_pep646_syntax.py b/Lib/test/test_pep646_syntax.py index 3ffa82dc55fa23..12a4227e4dc959 100644 --- a/Lib/test/test_pep646_syntax.py +++ b/Lib/test/test_pep646_syntax.py @@ -320,7 +320,7 @@ def test_main(verbose=False): from test import support from test import test_pep646_syntax - support.run_doctest(test_pep646_syntax, verbose) + return support.run_doctest(test_pep646_syntax, verbose) if __name__ == "__main__": test_main(verbose=True) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 806b932a164df8..14f5a962356aa3 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -19,7 +19,7 @@ import unittest from test import libregrtest from test import support -from test.support import os_helper +from test.support import os_helper, TestStats from test.libregrtest import utils, setup if not support.has_subprocess_support: @@ -409,7 +409,9 @@ def regex_search(self, regex, output): self.fail("%r not found in %r" % (regex, output)) return match - def check_line(self, output, regex): + def check_line(self, output, regex, full=False): + if full: + regex += '\n' regex = re.compile(r'^' + regex, re.MULTILINE) self.assertRegex(output, regex) @@ -421,21 +423,27 @@ def parse_executed_tests(self, output): def check_executed_tests(self, output, tests, skipped=(), failed=(), env_changed=(), omitted=(), - rerun={}, no_test_ran=(), + rerun={}, run_no_tests=(), + resource_denied=(), randomize=False, interrupted=False, - fail_env_changed=False): + fail_env_changed=False, + *, stats): if isinstance(tests, str): tests = [tests] if isinstance(skipped, str): skipped = [skipped] + if isinstance(resource_denied, str): + resource_denied = [resource_denied] if isinstance(failed, str): failed = [failed] if isinstance(env_changed, str): env_changed = [env_changed] if isinstance(omitted, str): omitted = [omitted] - if isinstance(no_test_ran, str): - no_test_ran = [no_test_ran] + if isinstance(run_no_tests, str): + run_no_tests = [run_no_tests] + if isinstance(stats, int): + stats = TestStats(stats) executed = self.parse_executed_tests(output) if randomize: @@ -479,12 +487,12 @@ def list_regex(line_format, tests): regex = LOG_PREFIX + f"Re-running {name} in verbose mode \\(matching: {match}\\)" self.check_line(output, regex) - if no_test_ran: - regex = list_regex('%s test%s run no tests', no_test_ran) + if run_no_tests: + regex = list_regex('%s test%s run no tests', run_no_tests) self.check_line(output, regex) good = (len(tests) - len(skipped) - len(failed) - - len(omitted) - len(env_changed) - len(no_test_ran)) + - len(omitted) - len(env_changed) - len(run_no_tests)) if good: regex = r'%s test%s OK\.$' % (good, plural(good)) if not skipped and not failed and good > 1: @@ -494,6 +502,33 @@ def list_regex(line_format, tests): if interrupted: self.check_line(output, 'Test suite interrupted by signal SIGINT.') + # Total tests + parts = [f'run={stats.tests_run:,}'] + if stats.failures: + parts.append(f'failures={stats.failures:,}') + if stats.skipped: + parts.append(f'skipped={stats.skipped:,}') + line = fr'Total tests: {" ".join(parts)}' + self.check_line(output, line, full=True) + + # Total test files + report = [f'success={good}'] + if failed: + report.append(f'failed={len(failed)}') + if env_changed: + report.append(f'env_changed={len(env_changed)}') + if skipped: + report.append(f'skipped={len(skipped)}') + if resource_denied: + report.append(f'resource_denied={len(resource_denied)}') + if rerun: + report.append(f'rerun={len(rerun)}') + if run_no_tests: + report.append(f'run_no_tests={len(run_no_tests)}') + line = fr'Total test files: {" ".join(report)}' + self.check_line(output, line, full=True) + + # Result result = [] if failed: result.append('FAILURE') @@ -508,10 +543,8 @@ def list_regex(line_format, tests): result.append('SUCCESS') result = ', '.join(result) if rerun: - self.check_line(output, 'Tests result: FAILURE') result = 'FAILURE then %s' % result - - self.check_line(output, 'Tests result: %s' % result) + self.check_line(output, f'Result: {result}', full=True) def parse_random_seed(self, output): match = self.regex_search(r'Using random seed ([0-9]+)', output) @@ -600,7 +633,8 @@ def setUp(self): def check_output(self, output): self.parse_random_seed(output) - self.check_executed_tests(output, self.tests, randomize=True) + self.check_executed_tests(output, self.tests, + randomize=True, stats=len(self.tests)) def run_tests(self, args): output = self.run_python(args) @@ -714,7 +748,8 @@ def test_failing(self): tests = [test_ok, test_failing] output = self.run_tests(*tests, exitcode=EXITCODE_BAD_TEST) - self.check_executed_tests(output, tests, failed=test_failing) + self.check_executed_tests(output, tests, failed=test_failing, + stats=TestStats(2, 1)) def test_resources(self): # test -u command line option @@ -733,17 +768,21 @@ def test_pass(self): # -u all: 2 resources enabled output = self.run_tests('-u', 'all', *test_names) - self.check_executed_tests(output, test_names) + self.check_executed_tests(output, test_names, stats=2) # -u audio: 1 resource enabled output = self.run_tests('-uaudio', *test_names) self.check_executed_tests(output, test_names, - skipped=tests['network']) + skipped=tests['network'], + resource_denied=tests['network'], + stats=1) # no option: 0 resources enabled output = self.run_tests(*test_names) self.check_executed_tests(output, test_names, - skipped=test_names) + skipped=test_names, + resource_denied=test_names, + stats=0) def test_random(self): # test -r and --randseed command line option @@ -791,7 +830,8 @@ def test_fromfile(self): previous = name output = self.run_tests('--fromfile', filename) - self.check_executed_tests(output, tests) + stats = len(tests) + self.check_executed_tests(output, tests, stats=stats) # test format '[2/7] test_opcodes' with open(filename, "w") as fp: @@ -799,7 +839,7 @@ def test_fromfile(self): print("[%s/%s] %s" % (index, len(tests), name), file=fp) output = self.run_tests('--fromfile', filename) - self.check_executed_tests(output, tests) + self.check_executed_tests(output, tests, stats=stats) # test format 'test_opcodes' with open(filename, "w") as fp: @@ -807,7 +847,7 @@ def test_fromfile(self): print(name, file=fp) output = self.run_tests('--fromfile', filename) - self.check_executed_tests(output, tests) + self.check_executed_tests(output, tests, stats=stats) # test format 'Lib/test/test_opcodes.py' with open(filename, "w") as fp: @@ -815,20 +855,20 @@ def test_fromfile(self): print('Lib/test/%s.py' % name, file=fp) output = self.run_tests('--fromfile', filename) - self.check_executed_tests(output, tests) + self.check_executed_tests(output, tests, stats=stats) def test_interrupted(self): code = TEST_INTERRUPTED test = self.create_test('sigint', code=code) output = self.run_tests(test, exitcode=EXITCODE_INTERRUPTED) self.check_executed_tests(output, test, omitted=test, - interrupted=True) + interrupted=True, stats=0) def test_slowest(self): # test --slowest tests = [self.create_test() for index in range(3)] output = self.run_tests("--slowest", *tests) - self.check_executed_tests(output, tests) + self.check_executed_tests(output, tests, stats=len(tests)) regex = ('10 slowest tests:\n' '(?:- %s: .*\n){%s}' % (self.TESTNAME_REGEX, len(tests))) @@ -847,7 +887,8 @@ def test_slowest_interrupted(self): args = ("--slowest", test) output = self.run_tests(*args, exitcode=EXITCODE_INTERRUPTED) self.check_executed_tests(output, test, - omitted=test, interrupted=True) + omitted=test, interrupted=True, + stats=0) regex = ('10 slowest tests:\n') self.check_line(output, regex) @@ -856,7 +897,7 @@ def test_coverage(self): # test --coverage test = self.create_test('coverage') output = self.run_tests("--coverage", test) - self.check_executed_tests(output, [test]) + self.check_executed_tests(output, [test], stats=1) regex = (r'lines +cov% +module +\(path\)\n' r'(?: *[0-9]+ *[0-9]{1,2}% *[^ ]+ +\([^)]+\)+)+') self.check_line(output, regex) @@ -886,7 +927,8 @@ def test_run(self): """) test = self.create_test('forever', code=code) output = self.run_tests('--forever', test, exitcode=EXITCODE_BAD_TEST) - self.check_executed_tests(output, [test]*3, failed=test) + self.check_executed_tests(output, [test]*3, failed=test, + stats=TestStats(1, 1)) def check_leak(self, code, what): test = self.create_test('huntrleaks', code=code) @@ -896,7 +938,7 @@ def check_leak(self, code, what): output = self.run_tests('--huntrleaks', '3:3:', test, exitcode=EXITCODE_BAD_TEST, stderr=subprocess.STDOUT) - self.check_executed_tests(output, [test], failed=test) + self.check_executed_tests(output, [test], failed=test, stats=1) line = 'beginning 6 repetitions\n123456\n......\n' self.check_line(output, re.escape(line)) @@ -978,7 +1020,7 @@ def test_crashed(self): tests = [crash_test] output = self.run_tests("-j2", *tests, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, tests, failed=crash_test, - randomize=True) + randomize=True, stats=0) def parse_methods(self, output): regex = re.compile("^(test[^ ]+).*ok$", flags=re.MULTILINE) @@ -1073,13 +1115,14 @@ def test_env_changed(self): # don't fail by default output = self.run_tests(testname) - self.check_executed_tests(output, [testname], env_changed=testname) + self.check_executed_tests(output, [testname], + env_changed=testname, stats=1) # fail with --fail-env-changed output = self.run_tests("--fail-env-changed", testname, exitcode=EXITCODE_ENV_CHANGED) self.check_executed_tests(output, [testname], env_changed=testname, - fail_env_changed=True) + fail_env_changed=True, stats=1) def test_rerun_fail(self): # FAILURE then FAILURE @@ -1098,7 +1141,9 @@ def test_fail_always(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, [testname], - failed=testname, rerun={testname: "test_fail_always"}) + failed=testname, + rerun={testname: "test_fail_always"}, + stats=TestStats(1, 1)) def test_rerun_success(self): # FAILURE then SUCCESS @@ -1119,7 +1164,8 @@ def test_fail_once(self): output = self.run_tests("-w", testname, exitcode=0) self.check_executed_tests(output, [testname], - rerun={testname: "test_fail_once"}) + rerun={testname: "test_fail_once"}, + stats=1) def test_rerun_setup_class_hook_failure(self): # FAILURE then FAILURE @@ -1139,7 +1185,8 @@ def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "ExampleTests"}) + rerun={testname: "ExampleTests"}, + stats=0) def test_rerun_teardown_class_hook_failure(self): # FAILURE then FAILURE @@ -1159,7 +1206,8 @@ def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "ExampleTests"}) + rerun={testname: "ExampleTests"}, + stats=1) def test_rerun_setup_module_hook_failure(self): # FAILURE then FAILURE @@ -1178,7 +1226,8 @@ def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: testname}) + rerun={testname: testname}, + stats=0) def test_rerun_teardown_module_hook_failure(self): # FAILURE then FAILURE @@ -1197,7 +1246,8 @@ def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: testname}) + rerun={testname: testname}, + stats=1) def test_rerun_setup_hook_failure(self): # FAILURE then FAILURE @@ -1216,7 +1266,8 @@ def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "test_success"}) + rerun={testname: "test_success"}, + stats=1) def test_rerun_teardown_hook_failure(self): # FAILURE then FAILURE @@ -1235,7 +1286,8 @@ def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "test_success"}) + rerun={testname: "test_success"}, + stats=1) def test_rerun_async_setup_hook_failure(self): # FAILURE then FAILURE @@ -1254,7 +1306,8 @@ async def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "test_success"}) + rerun={testname: "test_success"}, + stats=1) def test_rerun_async_teardown_hook_failure(self): # FAILURE then FAILURE @@ -1273,7 +1326,8 @@ async def test_success(self): output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "test_success"}) + rerun={testname: "test_success"}, + stats=1) def test_no_tests_ran(self): code = textwrap.dedent(""" @@ -1287,7 +1341,9 @@ def test_bug(self): output = self.run_tests(testname, "-m", "nosuchtest", exitcode=EXITCODE_NO_TESTS_RAN) - self.check_executed_tests(output, [testname], no_test_ran=testname) + self.check_executed_tests(output, [testname], + run_no_tests=testname, + stats=0) def test_no_tests_ran_skip(self): code = textwrap.dedent(""" @@ -1300,7 +1356,8 @@ def test_skipped(self): testname = self.create_test(code=code) output = self.run_tests(testname) - self.check_executed_tests(output, [testname]) + self.check_executed_tests(output, [testname], + stats=TestStats(1, skipped=1)) def test_no_tests_ran_multiple_tests_nonexistent(self): code = textwrap.dedent(""" @@ -1316,7 +1373,8 @@ def test_bug(self): output = self.run_tests(testname, testname2, "-m", "nosuchtest", exitcode=EXITCODE_NO_TESTS_RAN) self.check_executed_tests(output, [testname, testname2], - no_test_ran=[testname, testname2]) + run_no_tests=[testname, testname2], + stats=0) def test_no_test_ran_some_test_exist_some_not(self): code = textwrap.dedent(""" @@ -1339,7 +1397,8 @@ def test_other_bug(self): output = self.run_tests(testname, testname2, "-m", "nosuchtest", "-m", "test_other_bug", exitcode=0) self.check_executed_tests(output, [testname, testname2], - no_test_ran=[testname]) + run_no_tests=[testname], + stats=1) @support.cpython_only def test_uncollectable(self): @@ -1366,7 +1425,8 @@ def test_garbage(self): exitcode=EXITCODE_ENV_CHANGED) self.check_executed_tests(output, [testname], env_changed=[testname], - fail_env_changed=True) + fail_env_changed=True, + stats=1) def test_multiprocessing_timeout(self): code = textwrap.dedent(r""" @@ -1392,7 +1452,7 @@ def test_sleep(self): output = self.run_tests("-j2", "--timeout=1.0", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, [testname], - failed=testname) + failed=testname, stats=0) self.assertRegex(output, re.compile('%s timed out' % testname, re.MULTILINE)) @@ -1426,7 +1486,8 @@ def test_unraisable_exc(self): exitcode=EXITCODE_ENV_CHANGED) self.check_executed_tests(output, [testname], env_changed=[testname], - fail_env_changed=True) + fail_env_changed=True, + stats=1) self.assertIn("Warning -- Unraisable exception", output) self.assertIn("Exception: weakref callback bug", output) @@ -1458,7 +1519,8 @@ def test_threading_excepthook(self): exitcode=EXITCODE_ENV_CHANGED) self.check_executed_tests(output, [testname], env_changed=[testname], - fail_env_changed=True) + fail_env_changed=True, + stats=1) self.assertIn("Warning -- Uncaught thread exception", output) self.assertIn("Exception: bug in thread", output) @@ -1499,7 +1561,8 @@ def test_print_warning(self): output = self.run_tests(*cmd, exitcode=EXITCODE_ENV_CHANGED) self.check_executed_tests(output, [testname], env_changed=[testname], - fail_env_changed=True) + fail_env_changed=True, + stats=1) self.assertRegex(output, regex) def test_unicode_guard_env(self): @@ -1546,7 +1609,8 @@ def test_leak_tmp_file(self): self.check_executed_tests(output, testnames, env_changed=testnames, fail_env_changed=True, - randomize=True) + randomize=True, + stats=len(testnames)) for testname in testnames: self.assertIn(f"Warning -- {testname} leaked temporary " f"files (1): mytmpfile", @@ -1585,7 +1649,47 @@ def test_mp_decode_error(self): exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, [testname], failed=[testname], - randomize=True) + randomize=True, + stats=0) + + def test_doctest(self): + code = textwrap.dedent(fr''' + import doctest + import sys + from test import support + + def my_function(): + """ + Pass: + + >>> 1 + 1 + 2 + + Failure: + + >>> 2 + 3 + 23 + >>> 1 + 1 + 11 + + Skipped test (ignored): + + >>> id(1.0) # doctest: +SKIP + 7948648 + """ + + def test_main(): + testmod = sys.modules[__name__] + return support.run_doctest(testmod) + ''') + testname = self.create_test(code=code) + + output = self.run_tests("--fail-env-changed", "-v", "-j1", testname, + exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, [testname], + failed=[testname], + randomize=True, + stats=TestStats(3, 2, 0)) class TestUtils(unittest.TestCase): diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 11efee00582e01..fe3ac04f00116c 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -4250,7 +4250,7 @@ def test_main(module=None): old_factories = None try: - support.run_unittest(*test_classes) + return support.run_unittest(*test_classes) finally: from xml.etree import ElementPath # Restore mapping and path cache From 183bb673a8ce65d6bef6c8da44f34ba70f25340b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Sep 2023 04:46:35 -0700 Subject: [PATCH 0683/1206] [3.12] gh-107208: Fix iter_index() recipe to not swallow exceptions (gh-108835) (#108837) gh-107208: Fix iter_index() recipe to not swallow exceptions (gh-108835) (cherry picked from commit f373c6b9483e12d7f6e03a631601149ed60ab883) gh-107208: iter_index now supports "stop" and no longer swallows ValueError Co-authored-by: Raymond Hettinger --- Doc/library/itertools.rst | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 730736bbb59ed9..72c68519b456e2 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -865,26 +865,22 @@ which incur interpreter overhead. # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x return next(filter(pred, iterable), default) - def iter_index(iterable, value, start=0): + def iter_index(iterable, value, start=0, stop=None): "Return indices where a value occurs in a sequence or iterable." # iter_index('AABCADEAF', 'A') --> 0 1 4 7 - try: - seq_index = iterable.index - except AttributeError: + seq_index = getattr(iterable, 'index', None) + if seq_index is None: # Slow path for general iterables - it = islice(iterable, start, None) - i = start - 1 - try: - while True: - yield (i := i + operator.indexOf(it, value) + 1) - except ValueError: - pass + it = islice(iterable, start, stop) + for i, element in enumerate(it, start): + if element is value or element == value: + yield i else: # Fast path for sequences i = start - 1 try: while True: - yield (i := seq_index(value, i+1)) + yield (i := seq_index(value, i+1, stop)) except ValueError: pass @@ -1333,6 +1329,21 @@ The following recipes have a more mathematical flavor: [] >>> list(iter_index(iter('AABCADEAF'), 'A', 10)) [] + >>> list(iter_index('AABCADEAF', 'A', 1, 7)) + [1, 4] + >>> list(iter_index(iter('AABCADEAF'), 'A', 1, 7)) + [1, 4] + >>> # Verify that ValueErrors not swallowed (gh-107208) + >>> def assert_no_value(iterable, forbidden_value): + ... for item in iterable: + ... if item == forbidden_value: + ... raise ValueError + ... yield item + ... + >>> list(iter_index(assert_no_value('AABCADEAF', 'B'), 'A')) + Traceback (most recent call last): + ... + ValueError >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] From 7b936ac12e412e749b7b8bb918d9ea8111174ed7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Sep 2023 04:47:07 -0700 Subject: [PATCH 0684/1206] [3.12] Reorder some test's decorators (GH-108804) (#108844) Reorder some test's decorators (GH-108804) For example, do not demand the 'cpu' resource if the test cannot be run due to non-working threads. (cherry picked from commit 509bb61977cc8a4487efd3f9cdd63d9f7b86be62) Co-authored-by: Serhiy Storchaka --- Lib/test/test_io.py | 4 ++-- Lib/test/test_site.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index cc16804fe21829..fc56c1d5111351 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1548,8 +1548,8 @@ def test_read_all(self): self.assertEqual(b"abcdefg", bufio.read()) - @support.requires_resource('cpu') @threading_helper.requires_working_threading() + @support.requires_resource('cpu') def test_threads(self): try: # Write out many bytes with exactly the same number of 0's, @@ -1937,8 +1937,8 @@ def test_truncate_after_write(self): f.truncate() self.assertEqual(f.tell(), buffer_size + 2) - @support.requires_resource('cpu') @threading_helper.requires_working_threading() + @support.requires_resource('cpu') def test_threads(self): try: # Write out many bytes from many threads and test they were diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 9e701fd847acdf..20a96169e8be4e 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -465,10 +465,10 @@ def test_sitecustomize_executed(self): else: self.fail("sitecustomize not imported automatically") - @test.support.requires_resource('network') - @test.support.system_must_validate_cert @unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"), 'need SSL support to download license') + @test.support.requires_resource('network') + @test.support.system_must_validate_cert def test_license_exists_at_url(self): # This test is a bit fragile since it depends on the format of the # string displayed by license in the absence of a LICENSE file. From e0f6080819f00d456215646e3117ae77b9af40d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 4 Sep 2023 16:24:16 +0200 Subject: [PATCH 0685/1206] [3.12] gh-46376: Revert "Return existing pointer when possible in ctypes (GH-107131) (GH-107487)" (#108864) This reverts commit 54aaaadef8a44324f6be674707c67a3516470ff6. Co-authored-by: T. Wouters --- Lib/test/test_ctypes/test_keeprefs.py | 27 ------------------------- Modules/_ctypes/_ctypes.c | 29 --------------------------- 2 files changed, 56 deletions(-) diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index 61650ad1704753..e20adc7696f501 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -93,33 +93,6 @@ def test_p_cint(self): x = pointer(i) self.assertEqual(x._objects, {'1': i}) - def test_pp_ownership(self): - d = c_int(123) - n = c_int(456) - - p = pointer(d) - pp = pointer(p) - - self.assertIs(pp._objects['1'], p) - self.assertIs(pp._objects['0']['1'], d) - - pp.contents.contents = n - - self.assertIs(pp._objects['1'], p) - self.assertIs(pp._objects['0']['1'], n) - - self.assertIs(p._objects['1'], n) - self.assertEqual(len(p._objects), 1) - - del d - del p - - self.assertIs(pp._objects['0']['1'], n) - self.assertEqual(len(pp._objects), 2) - - del n - - self.assertEqual(len(pp._objects), 2) class PointerToStructure(unittest.TestCase): def test(self): diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 8496077322a662..534ef8c1d6cf8f 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5122,8 +5122,6 @@ static PyObject * Pointer_get_contents(CDataObject *self, void *closure) { StgDictObject *stgdict; - PyObject *keep, *ptr_probe; - CDataObject *ptr2ptr; if (*(void **)self->b_ptr == NULL) { PyErr_SetString(PyExc_ValueError, @@ -5133,33 +5131,6 @@ Pointer_get_contents(CDataObject *self, void *closure) stgdict = PyObject_stgdict((PyObject *)self); assert(stgdict); /* Cannot be NULL for pointer instances */ - - keep = GetKeepedObjects(self); - if (keep != NULL) { - // check if it's a pointer to a pointer: - // pointers will have '0' key in the _objects - ptr_probe = PyDict_GetItemString(keep, "0"); - - if (ptr_probe != NULL) { - ptr2ptr = (CDataObject*) PyDict_GetItemString(keep, "1"); - if (ptr2ptr == NULL) { - PyErr_SetString(PyExc_ValueError, - "Unexpected NULL pointer in _objects"); - return NULL; - } - // don't construct a new object, - // return existing one instead to preserve refcount - assert( - *(void**) self->b_ptr == ptr2ptr->b_ptr || - *(void**) self->b_value.c == ptr2ptr->b_ptr || - *(void**) self->b_ptr == ptr2ptr->b_value.c || - *(void**) self->b_value.c == ptr2ptr->b_value.c - ); // double-check that we are returning the same thing - Py_INCREF(ptr2ptr); - return (PyObject *) ptr2ptr; - } - } - return PyCData_FromBaseObj(stgdict->proto, (PyObject *)self, 0, *(void **)self->b_ptr); From 331b0267e2b39a394797091b9b16138c26fcb0f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Sep 2023 09:40:59 -0700 Subject: [PATCH 0686/1206] [3.12] Resolve reference warnings in faq/gui.rst (GH-108147) (#108193) * Resolve reference warnings in faq/gui.rst (GH-108147) (cherry picked from commit 8f3d09bf5d16b508fece5420a22abe6f0c1f00b7) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade * Resolve reference warnings in faq/gui.rst --------- Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/faq/gui.rst | 11 ++++++----- Doc/tools/.nitignore | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/faq/gui.rst b/Doc/faq/gui.rst index 023ffdf0db510a..886833cee72b08 100644 --- a/Doc/faq/gui.rst +++ b/Doc/faq/gui.rst @@ -43,7 +43,7 @@ applications, the applications will not be truly stand-alone, as the application will still need the Tcl and Tk libraries. One solution is to ship the application with the Tcl and Tk libraries, and point -to them at run-time using the :envvar:`TCL_LIBRARY` and :envvar:`TK_LIBRARY` +to them at run-time using the :envvar:`!TCL_LIBRARY` and :envvar:`!TK_LIBRARY` environment variables. To get truly stand-alone applications, the Tcl scripts that form the library @@ -52,7 +52,7 @@ SAM (stand-alone modules), which is part of the Tix distribution (https://tix.sourceforge.net/). Build Tix with SAM enabled, perform the appropriate call to -:c:func:`Tclsam_init`, etc. inside Python's +:c:func:`!Tclsam_init`, etc. inside Python's :file:`Modules/tkappinit.c`, and link with libtclsam and libtksam (you might include the Tix libraries as well). @@ -62,7 +62,7 @@ Can I have Tk events handled while waiting for I/O? On platforms other than Windows, yes, and you don't even need threads! But you'll have to restructure your I/O -code a bit. Tk has the equivalent of Xt's :c:func:`XtAddInput()` call, which allows you +code a bit. Tk has the equivalent of Xt's :c:func:`!XtAddInput` call, which allows you to register a callback function which will be called from the Tk mainloop when I/O is possible on a file descriptor. See :ref:`tkinter-file-handlers`. @@ -70,8 +70,9 @@ I/O is possible on a file descriptor. See :ref:`tkinter-file-handlers`. I can't get key bindings to work in Tkinter: why? ------------------------------------------------- -An often-heard complaint is that event handlers bound to events with the -:meth:`bind` method don't get handled even when the appropriate key is pressed. +An often-heard complaint is that event handlers :ref:`bound ` +to events with the :meth:`!bind` method +don't get handled even when the appropriate key is pressed. The most common cause is that the widget to which the binding applies doesn't have "keyboard focus". Check out the Tk documentation for the focus command. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 3d79b480946686..3f00fef966c01c 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -23,7 +23,6 @@ Doc/c-api/type.rst Doc/c-api/typeobj.rst Doc/extending/extending.rst Doc/extending/newtypes.rst -Doc/faq/gui.rst Doc/glossary.rst Doc/howto/descriptor.rst Doc/howto/enum.rst From d5c2d453fd264547f5f8be7c80fdb93e920d0093 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Sep 2023 19:41:42 +0300 Subject: [PATCH 0687/1206] [3.12] gh-89392: Make test_pep646_syntax discoverable (GH-108861) (#108871) * [3.12] gh-89392: Make test_pep646_syntax discoverable (GH-108861). (cherry picked from commit d0b22f6bd84239e50b43709f98f2bb950222cfe5) Co-authored-by: Serhiy Storchaka * Add "import unittest". --- Lib/test/test_pep646_syntax.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_pep646_syntax.py b/Lib/test/test_pep646_syntax.py index 12a4227e4dc959..aac089b190bc11 100644 --- a/Lib/test/test_pep646_syntax.py +++ b/Lib/test/test_pep646_syntax.py @@ -1,3 +1,6 @@ +import doctest +import unittest + doctests = """ Setup @@ -317,10 +320,10 @@ __test__ = {'doctests' : doctests} -def test_main(verbose=False): - from test import support - from test import test_pep646_syntax - return support.run_doctest(test_pep646_syntax, verbose) +def load_tests(loader, tests, pattern): + tests.addTest(doctest.DocTestSuite()) + return tests + if __name__ == "__main__": - test_main(verbose=True) + unittest.main() From bce77915b68e4da2d313d17391a009bc113a023c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 4 Sep 2023 12:11:16 -0700 Subject: [PATCH 0688/1206] [3.12] Disable `differing_test_runners` health check (GH-108886) (#108887) Disable `differing_test_runners` health check (GH-108886) (cherry picked from commit 6ead5bd6ae20b902e6c11a3c0acede22632dc0d5) Co-authored-by: Nikita Sobolev --- .github/workflows/build.yml | 2 +- Lib/test/support/hypothesis_helper.py | 5 ++++- Tools/requirements-hypothesis.txt | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 Tools/requirements-hypothesis.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ea6d43947449f1..994694f57a6a32 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -474,7 +474,7 @@ jobs: VENV_PYTHON=$VENV_LOC/bin/python echo "HYPOVENV=${VENV_LOC}" >> $GITHUB_ENV echo "VENV_PYTHON=${VENV_PYTHON}" >> $GITHUB_ENV - ./python -m venv $VENV_LOC && $VENV_PYTHON -m pip install -U hypothesis + ./python -m venv $VENV_LOC && $VENV_PYTHON -m pip install -r ${GITHUB_WORKSPACE}/Tools/requirements-hypothesis.txt - name: 'Restore Hypothesis database' id: cache-hypothesis-database uses: actions/cache@v3 diff --git a/Lib/test/support/hypothesis_helper.py b/Lib/test/support/hypothesis_helper.py index da16eb50c25958..db93eea5e912e0 100644 --- a/Lib/test/support/hypothesis_helper.py +++ b/Lib/test/support/hypothesis_helper.py @@ -10,7 +10,10 @@ hypothesis.settings.register_profile( "slow-is-ok", deadline=None, - suppress_health_check=[hypothesis.HealthCheck.too_slow], + suppress_health_check=[ + hypothesis.HealthCheck.too_slow, + hypothesis.HealthCheck.differing_executors, + ], ) hypothesis.settings.load_profile("slow-is-ok") diff --git a/Tools/requirements-hypothesis.txt b/Tools/requirements-hypothesis.txt new file mode 100644 index 00000000000000..9db2b74c87cfb0 --- /dev/null +++ b/Tools/requirements-hypothesis.txt @@ -0,0 +1,4 @@ +# Requirements file for hypothesis that +# we use to run our property-based tests in CI. + +hypothesis==6.84.0 From 88ff02e3c5054fd4d356526a5b1f15f5bc4d65b3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Sep 2023 22:13:02 +0300 Subject: [PATCH 0689/1206] [3.12] gh-89392: Remove test_main() in test_netrc (GH-108860) (#108872) [3.12] gh-89392: Remove test_main() in test_netrc (GH-108860). (cherry picked from commit 76f3c043b6c5971d5a13fc6decf87a80ddf7ef95) Co-authored-by: T. Wouters --- Lib/test/test_netrc.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py index b38cb327f68ecc..81e11a293cc4c8 100644 --- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -1,5 +1,5 @@ import netrc, os, unittest, sys, textwrap -from test.support import os_helper, run_unittest +from test.support import os_helper try: import pwd @@ -308,8 +308,6 @@ def test_security(self): self.assertEqual(nrc.hosts['foo.domain.com'], ('anonymous', '', 'pass')) -def test_main(): - return run_unittest(NetrcTestCase) if __name__ == "__main__": - test_main() + unittest.main() From 9c1428c7cca3dde8055267487d4350b4ea18fc88 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Sep 2023 03:50:44 -0700 Subject: [PATCH 0690/1206] [3.12] CI: Bump GitHub Actions (GH-108879) (#108889) CI: Bump GitHub Actions (GH-108879) (cherry picked from commit 572678e1f864cb042df6962848a436d84ef7a8a4) Co-authored-by: Hugo van Kemenade --- .github/workflows/build.yml | 20 +++++++++---------- .github/workflows/build_msi.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/mypy.yml | 2 +- .github/workflows/reusable-docs.yml | 6 +++--- .github/workflows/verify-ensurepip-wheels.yml | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 994694f57a6a32..3061c8f59fc006 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: run_hypothesis: ${{ steps.check.outputs.run_hypothesis }} config_hash: ${{ steps.config_hash.outputs.hash }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Check for source changes id: check run: | @@ -154,13 +154,13 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Add ccache to PATH @@ -217,7 +217,7 @@ jobs: env: IncludeUwp: 'true' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build CPython run: .\PCbuild\build.bat -e -d -p Win32 - name: Display build info @@ -234,7 +234,7 @@ jobs: env: IncludeUwp: 'true' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Register MSVC problem matcher run: echo "::add-matcher::.github/problem-matchers/msvc.json" - name: Build CPython @@ -256,7 +256,7 @@ jobs: HOMEBREW_NO_INSTALL_CLEANUP: 1 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: @@ -290,7 +290,7 @@ jobs: OPENSSL_VER: 1.1.1v PYTHONSTRICTEXTENSIONBUILD: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies @@ -363,7 +363,7 @@ jobs: OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }} LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: @@ -411,7 +411,7 @@ jobs: OPENSSL_VER: 1.1.1v PYTHONSTRICTEXTENSIONBUILD: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies @@ -521,7 +521,7 @@ jobs: PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Restore config.cache uses: actions/cache@v3 with: diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 22f613a88aa11e..29282dffa37ec0 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -33,6 +33,6 @@ jobs: matrix: type: [x86, x64, arm64] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build CPython installer run: .\Tools\msi\build.bat --doc -${{ matrix.type }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4481ea80bfd936..27b04ba1d412e3 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.x" diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 1315bb5a966f01..f089a0b247aeb4 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.x" diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 6150b1a7d416a3..51efa54e8d1b3d 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -23,7 +23,7 @@ jobs: refspec_pr: '+${{ github.event.pull_request.head.sha }}:remotes/origin/${{ github.event.pull_request.head.ref }}' steps: - name: 'Check out latest PR branch commit' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} # Adapted from https://github.com/actions/checkout/issues/520#issuecomment-1167205721 @@ -70,7 +70,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: 'Set up Python' uses: actions/setup-python@v4 with: @@ -88,7 +88,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/cache@v3 with: path: ~/.cache/pip diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index 17d841f1f1c54a..4a545037bf6e2b 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3' From e76b0b778312591c9616617655c79d42d189340a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Sep 2023 13:51:37 +0300 Subject: [PATCH 0691/1206] [3.12] bpo-45229: Make ElementTree tests discoverable (GH-108859) (#108873) [3.12] bpo-45229: Make ElementTree tests discoverable (GH-108859). (cherry picked from commit 074ac1f72e392a576516639f650bac0519d1cb52) --- Lib/test/test_xml_etree.py | 66 ++++++++++-------------------------- Lib/test/test_xml_etree_c.py | 31 ++++++++++------- 2 files changed, 35 insertions(+), 62 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index fe3ac04f00116c..3cde6ef5fa7c62 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -365,6 +365,7 @@ def test_path_cache(self): from xml.etree import ElementPath elem = ET.XML(SAMPLE_XML) + ElementPath._cache.clear() for i in range(10): ET.ElementTree(elem).find('./'+str(i)) cache_len_10 = len(ElementPath._cache) for i in range(10): ET.ElementTree(elem).find('./'+str(i)) @@ -3926,8 +3927,9 @@ def test_issue14818(self): # -------------------------------------------------------------------- class NoAcceleratorTest(unittest.TestCase): - def setUp(self): - if not pyET: + @classmethod + def setUpClass(cls): + if ET is not pyET: raise unittest.SkipTest('only for the Python version') # Test that the C accelerator was not imported for pyET @@ -4192,8 +4194,7 @@ def get_option(config, option_name, default=None): # -------------------------------------------------------------------- - -def test_main(module=None): +def setUpModule(module=None): # When invoked without a module, runs the Python ET tests by loading pyET. # Otherwise, uses the given module as the ET. global pyET @@ -4205,63 +4206,30 @@ def test_main(module=None): global ET ET = module - test_classes = [ - ModuleTest, - ElementSlicingTest, - BasicElementTest, - BadElementTest, - BadElementPathTest, - ElementTreeTest, - IOTest, - ParseErrorTest, - XIncludeTest, - ElementTreeTypeTest, - ElementFindTest, - ElementIterTest, - TreeBuilderTest, - XMLParserTest, - XMLPullParserTest, - BugsTest, - KeywordArgsTest, - BoolTest, - C14NTest, - ] - - # These tests will only run for the pure-Python version that doesn't import - # _elementtree. We can't use skipUnless here, because pyET is filled in only - # after the module is loaded. - if pyET is not ET: - test_classes.extend([ - NoAcceleratorTest, - ]) + # don't interfere with subsequent tests + def cleanup(): + global ET, pyET + ET = pyET = None + unittest.addModuleCleanup(cleanup) # Provide default namespace mapping and path cache. from xml.etree import ElementPath nsmap = ET.register_namespace._namespace_map # Copy the default namespace mapping nsmap_copy = nsmap.copy() + unittest.addModuleCleanup(nsmap.update, nsmap_copy) + unittest.addModuleCleanup(nsmap.clear) + # Copy the path cache (should be empty) path_cache = ElementPath._cache + unittest.addModuleCleanup(setattr, ElementPath, "_cache", path_cache) ElementPath._cache = path_cache.copy() + # Align the Comment/PI factories. if hasattr(ET, '_set_factories'): old_factories = ET._set_factories(ET.Comment, ET.PI) - else: - old_factories = None - - try: - return support.run_unittest(*test_classes) - finally: - from xml.etree import ElementPath - # Restore mapping and path cache - nsmap.clear() - nsmap.update(nsmap_copy) - ElementPath._cache = path_cache - if old_factories is not None: - ET._set_factories(*old_factories) - # don't interfere with subsequent tests - ET = pyET = None + unittest.addModuleCleanup(ET._set_factories, *old_factories) if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py index fd27b575ec8dc9..3a0fc572f457ff 100644 --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -254,20 +254,25 @@ def test_element_with_children(self): self.check_sizeof(e, self.elementsize + self.extra + struct.calcsize('8P')) -def test_main(): - from test import test_xml_etree - - # Run the tests specific to the C implementation - support.run_unittest( - MiscTests, - TestAliasWorking, - TestAcceleratorImported, - SizeofTest, - ) - # Run the same test suite as the Python module - test_xml_etree.test_main(module=cET) +def install_tests(): + # Test classes should have __module__ referring to this module. + from test import test_xml_etree + for name, base in vars(test_xml_etree).items(): + if isinstance(base, type) and issubclass(base, unittest.TestCase): + class Temp(base): + pass + Temp.__name__ = Temp.__qualname__ = name + Temp.__module__ = __name__ + assert name not in globals() + globals()[name] = Temp + +install_tests() + +def setUpModule(): + from test import test_xml_etree + test_xml_etree.setUpModule(module=cET) if __name__ == '__main__': - test_main() + unittest.main() From 8c551a7f2a7e9b8e3c811f669b915419851c2c8e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Sep 2023 03:52:36 -0700 Subject: [PATCH 0692/1206] [3.12] Link to PEP sections in What's New in 3.12 (GH-108878) (#108890) Link to PEP sections in What's New in 3.12 (GH-108878) (cherry picked from commit 7855d325e638a4b7f7b40f2c35dc80de82d8fe70) Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f76f9c465b9121..f58c2d94e431bc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -68,7 +68,7 @@ Summary -- Release highlights New grammar features: -* :pep:`701`: Syntactic formalization of f-strings +* :ref:`whatsnew312-pep701` Interpreter improvements: @@ -76,13 +76,13 @@ Interpreter improvements: New typing features: -* :pep:`688`: Making the buffer protocol accessible in Python +* :ref:`whatsnew312-pep688` * :ref:`whatsnew312-pep692` * :ref:`whatsnew312-pep695` -* :pep:`698`: Override Decorator for Static Typing +* :ref:`whatsnew312-pep698` Important deprecations, removals or restrictions: @@ -268,6 +268,8 @@ Inlining does result in a few visible behavior changes: Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`. +.. _whatsnew312-pep688: + PEP 688: Making the buffer protocol accessible in Python -------------------------------------------------------- @@ -341,6 +343,8 @@ See :pep:`692` for more details. (Contributed by Franek Magiera in :gh:`103629`.) +.. _whatsnew312-pep698: + PEP 698: Override Decorator for Static Typing --------------------------------------------- From 5121faabd1b3733a1198a18fa5df540eeb2475f6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Sep 2023 14:18:41 +0300 Subject: [PATCH 0693/1206] [3.12] gh-89392: Remove support of test_main() in libregrtest (GH-108876) (#108897) [3.12] gh-89392: Remove support of test_main() in libregrtest (GH-108876). (cherry picked from commit 04a0830b00879efe057e3dfe75e9aa9c0caf1a26) Co-authored-by: Alex Waygood --- Lib/test/libregrtest/runtest.py | 9 ++++----- Lib/test/test_regrtest.py | 8 ++++---- .../Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst | 2 ++ 3 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index 6fa60697371b72..2c30269fc9fd6d 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -345,11 +345,10 @@ def _load_run_test(result: TestResult, ns: Namespace) -> None: the_module = importlib.import_module(abstest) - # If the test has a test_main, that will run the appropriate - # tests. If not, use normal unittest test loading. - test_func = getattr(the_module, "test_main", None) - if test_func is None: - test_func = functools.partial(_test_module, the_module) + if hasattr(the_module, "test_main"): + # https://github.com/python/cpython/issues/89392 + raise Exception(f"Module {result.test_name} defines test_main() which is no longer supported by regrtest") + test_func = functools.partial(_test_module, the_module) try: with save_env(ns, result.test_name): diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 14f5a962356aa3..68f71360d6914c 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -1678,9 +1678,9 @@ def my_function(): 7948648 """ - def test_main(): - testmod = sys.modules[__name__] - return support.run_doctest(testmod) + def load_tests(loader, tests, pattern): + tests.addTest(doctest.DocTestSuite()) + return tests ''') testname = self.create_test(code=code) @@ -1689,7 +1689,7 @@ def test_main(): self.check_executed_tests(output, [testname], failed=[testname], randomize=True, - stats=TestStats(3, 2, 0)) + stats=TestStats(1, 1, 0)) class TestUtils(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst b/Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst new file mode 100644 index 00000000000000..e1dea8e78cdd4e --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst @@ -0,0 +1,2 @@ +Removed support of ``test_main()`` function in tests. They now always use +normal unittest test runner. From 7ee021f99998690ee724d08a95dceadd2ec8a051 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 5 Sep 2023 12:29:38 +0100 Subject: [PATCH 0694/1206] [3.12] GH-108390: Prevent non-local events being set with `sys.monitoring.set_local_events()` (GH-108420) (#108899) * GH-108390: Prevent non-local events being set with `sys.monitoring.set_local_events()` (GH-108420) * Restore generated objects * Restore size of monitoring arrays in code object for 3.12 ABI compatibility. * Update ABI file --- Doc/data/python3.12.abi | 5796 +++++++++-------- Include/cpython/code.h | 19 +- Include/internal/pycore_instruments.h | 2 +- Include/internal/pycore_interp.h | 2 +- Lib/test/test_monitoring.py | 30 +- ...-08-13-17-18-22.gh-issue-108390.TkBccC.rst | 4 + Python/ceval.c | 32 +- Python/instrumentation.c | 147 +- 8 files changed, 3066 insertions(+), 2966 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi index cdefda782b9c6f..f4138bee406a27 100644 --- a/Doc/data/python3.12.abi +++ b/Doc/data/python3.12.abi @@ -2067,7 +2067,7 @@ - + @@ -2522,6 +2522,12 @@ + + + + + + @@ -4032,7 +4038,7 @@ - + @@ -5719,32 +5725,32 @@ - + - + - + - + - + - + - + - + - + - + @@ -5801,7 +5807,7 @@ - + @@ -6264,12 +6270,12 @@ - + - + @@ -8195,14 +8201,14 @@ - + - + @@ -8286,122 +8292,122 @@ - - - - - + - + - + - - - + + + + + + + - - - - + + + + - - + + - - - - + + + + - + - - + + - - + + - - - + + + - - - - + + + + - - - - + + + + - - - + + + - - + + - - - - - + + + + + - - + + - - + + - - + + - - + + - - + + - - - + + + - - + + - - + + - - + + @@ -8813,19 +8819,19 @@ - + - + - + - + @@ -10818,7 +10824,7 @@ - + @@ -10889,10 +10895,10 @@ - + - + @@ -11104,175 +11110,181 @@ - + - + - - + + + + + + + + - + - + - + - + - + - - + + - + - + - + - + - - + + - + - + - - + + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - + + + + @@ -11284,7 +11296,7 @@ - + @@ -11316,7 +11328,7 @@ - + @@ -11325,10 +11337,10 @@ - - - - + + + + @@ -11336,8 +11348,8 @@ - - + + @@ -11390,8 +11402,8 @@ - - + + @@ -11399,9 +11411,9 @@ - - - + + + @@ -11409,7 +11421,7 @@ - + @@ -11417,8 +11429,8 @@ - - + + @@ -11450,8 +11462,8 @@ - - + + @@ -11513,16 +11525,16 @@ - + - + - + - + @@ -11600,7 +11612,7 @@ - + @@ -11645,8 +11657,8 @@ - - + + @@ -11657,26 +11669,26 @@ - + - + - + - - + + - + - + @@ -11684,7 +11696,7 @@ - + @@ -11708,20 +11720,20 @@ - - + + - + - + - - + + @@ -11747,48 +11759,48 @@ - - - + + + - + - + - + - + - - - + + + - + - - + + - + - - + + - + @@ -11800,8 +11812,8 @@ - - + + @@ -11809,7 +11821,7 @@ - + @@ -11820,7 +11832,7 @@ - + @@ -11841,13 +11853,13 @@ - + - + - + @@ -11877,10 +11889,10 @@ - + - + @@ -11904,7 +11916,7 @@ - + @@ -11916,10 +11928,10 @@ - + - + @@ -11945,11 +11957,11 @@ - - - - - + + + + + @@ -11960,24 +11972,24 @@ - + - + - - + + - + - - - + + + @@ -11985,8 +11997,8 @@ - - + + @@ -11997,10 +12009,10 @@ - + - + @@ -12014,10 +12026,10 @@ - - + + - + @@ -12026,8 +12038,8 @@ - - + + @@ -12765,9 +12777,9 @@ - + - + @@ -12776,7 +12788,7 @@ - + @@ -12784,11 +12796,11 @@ - + - - + + @@ -12799,16 +12811,16 @@ - - + + - + - + - + @@ -12817,19 +12829,19 @@ - - - - - + + + + + - + - + @@ -12846,85 +12858,85 @@ - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -12938,29 +12950,29 @@ - + - - + + - + - + - + - + @@ -12969,7 +12981,7 @@ - + @@ -12993,7 +13005,7 @@ - + @@ -13013,7 +13025,7 @@ - + @@ -13027,12 +13039,12 @@ - + - + @@ -13041,8 +13053,8 @@ - - + + @@ -13059,21 +13071,21 @@ - + - + - + - + - + @@ -13082,7 +13094,7 @@ - + @@ -13099,7 +13111,7 @@ - + @@ -13125,18 +13137,18 @@ - + - + - + - + @@ -13148,30 +13160,30 @@ - - + + - + - + - + - + - + - + @@ -13223,13 +13235,13 @@ - + - + @@ -13238,23 +13250,23 @@ - + - + - + - + - + - + @@ -13274,7 +13286,7 @@ - + @@ -13291,7 +13303,7 @@ - + @@ -13315,7 +13327,7 @@ - + @@ -13329,38 +13341,38 @@ - + - + - + - + - + - + - + - + - + - + @@ -13371,22 +13383,22 @@ - + - + - + - + - + - + @@ -13397,7 +13409,7 @@ - + @@ -13432,2438 +13444,2438 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + @@ -15872,8 +15884,8 @@ - - + + @@ -15884,25 +15896,25 @@ - - + + - + - - + + - + - - + + - + - + @@ -15911,22 +15923,22 @@ - - - - - - - + + + + + + + - + - + - - + + @@ -15934,50 +15946,50 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -16000,15 +16012,15 @@ - + - + - + - + @@ -16017,23 +16029,23 @@ - + - + - + - + @@ -16047,7 +16059,7 @@ - + @@ -16062,16 +16074,16 @@ - + - + - + - + @@ -16080,13 +16092,13 @@ - + - + - + @@ -16116,7 +16128,7 @@ - + @@ -16140,13 +16152,13 @@ - + - + - + @@ -16161,58 +16173,58 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -16236,16 +16248,16 @@ - + - + - + - + @@ -16259,21 +16271,21 @@ - + - + - + - + - + @@ -16281,68 +16293,68 @@ - + - + - + - - - + + + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + @@ -16351,17 +16363,17 @@ - + - + - + @@ -16385,34 +16397,34 @@ - + - + - + - - + + - + - + - - + + - + @@ -16421,7 +16433,7 @@ - + @@ -16429,42 +16441,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -16472,22 +16484,22 @@ - - + + - + - + - + - + @@ -16498,42 +16510,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -16541,9 +16553,9 @@ - + - + @@ -16552,8 +16564,8 @@ - - + + @@ -16570,34 +16582,34 @@ - + - + - + - + - + - + - + - + - + @@ -16606,37 +16618,37 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -16645,30 +16657,30 @@ - + - + - + - + - + - + - + - + - + @@ -16680,31 +16692,31 @@ - + - + - + - + - + - + - + - + - + @@ -16716,23 +16728,23 @@ - + - + - + - + - + - + @@ -16740,9 +16752,9 @@ - + - + @@ -16751,7 +16763,7 @@ - + @@ -16765,29 +16777,29 @@ - + - + - + - + - + - + - + - + @@ -16796,28 +16808,28 @@ - + - + - + - + - + - + - + @@ -16828,7 +16840,7 @@ - + @@ -16836,7 +16848,7 @@ - + @@ -16852,12 +16864,12 @@ - + - + @@ -16877,13 +16889,13 @@ - - + + - + @@ -16892,30 +16904,30 @@ - - + + - + - + - - + + - + - + - + - + @@ -16929,7 +16941,7 @@ - + @@ -16937,18 +16949,18 @@ - + - + - + - + - + @@ -16962,15 +16974,15 @@ - - - - - - - - - + + + + + + + + + @@ -16984,18 +16996,18 @@ - - - - + + + + - + - + @@ -17003,8 +17015,8 @@ - - + + @@ -17012,11 +17024,11 @@ - - - + + + - + @@ -17025,10 +17037,10 @@ - - + + - + @@ -17037,10 +17049,10 @@ - - + + - + @@ -17052,21 +17064,21 @@ - + - + - + - - - - - - - + + + + + + + @@ -17089,24 +17101,24 @@ - + - + - + - + - - + + - + - + @@ -17124,25 +17136,25 @@ - - - - - - + + + + + + - - + + - - + + @@ -17150,9 +17162,9 @@ - - - + + + @@ -17166,36 +17178,36 @@ - + - + - + - + - + - + - + - + - + - + @@ -17203,7 +17215,7 @@ - + @@ -17211,10 +17223,10 @@ - + - + @@ -17222,10 +17234,10 @@ - + - + @@ -17242,7 +17254,7 @@ - + @@ -17250,18 +17262,18 @@ - + - + - + - + - + @@ -17269,7 +17281,7 @@ - + @@ -17277,7 +17289,7 @@ - + @@ -17288,8 +17300,8 @@ - - + + @@ -17300,106 +17312,106 @@ - - - + + + - + - - - + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + - + - - - - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + - - + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + @@ -17422,7 +17434,7 @@ - + @@ -17430,17 +17442,17 @@ - + - + - + - + @@ -17475,163 +17487,163 @@ - + - + - - + + - - + + - + - + - + - + - + - + - + - + - + - - + + - - + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -17639,8 +17651,8 @@ - - + + @@ -17653,17 +17665,17 @@ - - + + - + - - + + @@ -17671,8 +17683,8 @@ - - + + @@ -17680,8 +17692,8 @@ - - + + @@ -17689,35 +17701,35 @@ - - + + - + - - + + - + - - + + - - + + @@ -17725,8 +17737,8 @@ - - + + @@ -17734,29 +17746,29 @@ - - + + - - - - + + - - + + - - - + + + + - + + @@ -17794,7 +17806,7 @@ - + @@ -17824,22 +17836,22 @@ - + - + - + - + - + @@ -17890,13 +17902,13 @@ - + - + @@ -18186,7 +18198,7 @@ - + @@ -18217,7 +18229,7 @@ - + @@ -18268,7 +18280,7 @@ - + @@ -18278,7 +18290,7 @@ - + @@ -18289,7 +18301,7 @@ - + @@ -18299,7 +18311,7 @@ - + @@ -18362,7 +18374,7 @@ - + @@ -18383,7 +18395,7 @@ - + @@ -18526,27 +18538,27 @@ - + - + - + - + @@ -18586,72 +18598,76 @@ - + + + + + - + - + - + - - + + - - + + - + - + - + - + - + - - + + - + - + - + - + - - + + - + - - + + - + @@ -18660,104 +18676,104 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - - + + - + - + - - + + @@ -18766,43 +18782,43 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -18810,22 +18826,22 @@ - + - + - + - + @@ -18835,39 +18851,39 @@ - + - + - + - - - + + + - + - + - + - + - + @@ -18876,60 +18892,60 @@ - + - + - + - - + + - + - + - + - + - + - + - + - + - + @@ -18937,15 +18953,15 @@ - - + + - + @@ -18957,7 +18973,7 @@ - + @@ -18967,22 +18983,22 @@ - + - + - + - - - - + + + + @@ -18996,32 +19012,32 @@ - - + + - + - - + + - + - + - + - - - + + + - + @@ -19029,7 +19045,7 @@ - + @@ -19037,189 +19053,189 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - - + + - + - + - + - - - + + + - + - + - + - + - - + + - + - - + + @@ -19239,43 +19255,43 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -19290,16 +19306,16 @@ - + - + - + @@ -19317,22 +19333,22 @@ - + - + - + - + - + @@ -19371,17 +19387,17 @@ - - - + + + - + - + @@ -19390,7 +19406,7 @@ - + @@ -19410,7 +19426,7 @@ - + @@ -19418,25 +19434,25 @@ - + - - - + + + - - + + - - + + @@ -19452,20 +19468,20 @@ - - + + - - - - - - + + + + + + @@ -19473,11 +19489,11 @@ - + - - + + @@ -19485,11 +19501,11 @@ - + - - + + @@ -19497,11 +19513,11 @@ - + - - + + @@ -19509,11 +19525,11 @@ - + - - + + @@ -19543,12 +19559,12 @@ - + - + - + @@ -19563,42 +19579,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -19610,51 +19626,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -19662,7 +19678,7 @@ - + @@ -19673,15 +19689,15 @@ - + - + - + @@ -19689,7 +19705,7 @@ - + @@ -19700,7 +19716,7 @@ - + @@ -19708,20 +19724,20 @@ - + - + - + - + @@ -19729,7 +19745,7 @@ - + @@ -19737,7 +19753,7 @@ - + @@ -19748,7 +19764,7 @@ - + @@ -19759,7 +19775,7 @@ - + @@ -19770,12 +19786,12 @@ - + - + @@ -19783,7 +19799,7 @@ - + @@ -19794,7 +19810,7 @@ - + @@ -19805,7 +19821,7 @@ - + @@ -19813,7 +19829,7 @@ - + @@ -19821,7 +19837,7 @@ - + @@ -19829,7 +19845,7 @@ - + @@ -19840,7 +19856,7 @@ - + @@ -19854,7 +19870,7 @@ - + @@ -19877,7 +19893,7 @@ - + @@ -19900,7 +19916,7 @@ - + @@ -19920,9 +19936,9 @@ - - - + + + @@ -19936,23 +19952,23 @@ - + - + - + - + - + @@ -19960,43 +19976,43 @@ - - - - + + + + - - - - - + + + + + - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + @@ -20031,24 +20047,24 @@ - - - + + + - - - - - - - - + + + + + + + + - - - + + + @@ -20086,10 +20102,10 @@ - + - + @@ -20098,31 +20114,31 @@ - + - + - + - + - + - + @@ -20134,11 +20150,11 @@ - + - + @@ -20149,11 +20165,11 @@ - + - - + + @@ -20176,14 +20192,14 @@ - + - - + + @@ -20191,10 +20207,10 @@ - - + + - + @@ -20203,7 +20219,7 @@ - + @@ -20211,13 +20227,13 @@ - - + + - + - + @@ -20232,7 +20248,7 @@ - + @@ -20268,7 +20284,7 @@ - + @@ -20283,19 +20299,19 @@ - - + + - + - + @@ -20321,14 +20337,14 @@ - + - + - + @@ -20373,8 +20389,8 @@ - - + + @@ -20412,7 +20428,7 @@ - + @@ -20442,22 +20458,22 @@ - + - + - + - + - + @@ -20508,13 +20524,13 @@ - + - + @@ -20529,82 +20545,82 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - + + - - - - + + + + @@ -20828,7 +20844,7 @@ - + @@ -20836,143 +20852,143 @@ - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -21003,6 +21019,11 @@ + + + + + @@ -21072,11 +21093,6 @@ - - - - - @@ -21102,14 +21118,14 @@ - - + + - + - + @@ -21127,9 +21143,9 @@ - - - + + + @@ -21224,7 +21240,7 @@ - + @@ -21298,7 +21314,7 @@ - + @@ -21406,7 +21422,7 @@ - + @@ -21488,7 +21504,7 @@ - + @@ -21564,13 +21580,13 @@ - + - + @@ -21632,44 +21648,44 @@ - + - + - + - + - + - + - + @@ -21677,7 +21693,7 @@ - + @@ -21685,25 +21701,25 @@ - + - + - + - + @@ -21725,7 +21741,7 @@ - + @@ -21763,35 +21779,35 @@ - + - - + + - + - - - + + + - + @@ -21799,7 +21815,7 @@ - + @@ -21808,7 +21824,7 @@ - + @@ -21896,66 +21912,66 @@ - - + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - + - - + + - + - - + + - - + + - - + + - - + + - + - + @@ -21963,30 +21979,30 @@ - - + + - + - + - - - - - + + + + + - - - + - + + + - + @@ -22019,42 +22035,42 @@ - + - - + + - + - + - + - + - + - + - + @@ -22095,13 +22111,13 @@ - + - + @@ -22113,7 +22129,7 @@ - + @@ -22214,16 +22230,16 @@ - + - + - + - + @@ -22237,17 +22253,17 @@ - - + + - + - - + + @@ -22261,8 +22277,8 @@ - - + + @@ -22273,8 +22289,8 @@ - - + + @@ -22282,16 +22298,16 @@ - + - + - - + + - + @@ -22309,8 +22325,8 @@ - - + + @@ -22348,8 +22364,8 @@ - - + + @@ -22357,46 +22373,46 @@ - + - + - + - - + + - - + + - + - - + + - + - + - + - + - + @@ -22432,23 +22448,23 @@ - - + + - + - + - + - + - - + + @@ -22458,8 +22474,8 @@ - - + + @@ -22467,16 +22483,16 @@ - - + + - + - + @@ -22494,7 +22510,7 @@ - + @@ -22503,7 +22519,7 @@ - + @@ -22526,7 +22542,7 @@ - + @@ -22544,7 +22560,7 @@ - + @@ -22595,23 +22611,23 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -22627,38 +22643,38 @@ - - + + - + - + - - + + - + - + - + - + - + @@ -22668,56 +22684,56 @@ - + - + - + - + - + - - - + + + - + - + - + - + - + @@ -22726,7 +22742,7 @@ - + @@ -22735,35 +22751,35 @@ - - - - - - + + + + + + - - - - + + + + - - + + - - - - + + + + - - - - - + + + + + @@ -22785,44 +22801,44 @@ - + - + - + - + - + - + - - + + - + - + - + - + @@ -22911,136 +22927,136 @@ - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - + + - + - - - + + + - - - - + + + + - - - - + + + + - - + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - + - - - - + + + + - - - - - + + + + + - - - + + + - - - - - - + + + + + + - - - - + + + + - - - + + + - + - + - + @@ -23048,11 +23064,11 @@ - - - - - + + + + + @@ -23097,7 +23113,7 @@ - + @@ -23149,23 +23165,23 @@ - - - + + + - - + + - - - + + + - - - + + + @@ -23180,7 +23196,7 @@ - + @@ -23254,15 +23270,15 @@ - + - + - + @@ -23280,7 +23296,7 @@ - + @@ -23297,7 +23313,7 @@ - + @@ -23305,15 +23321,15 @@ - - - + - - - - - + + + + + + + @@ -23385,9 +23401,9 @@ - + - + @@ -23399,7 +23415,7 @@ - + @@ -23572,8 +23588,8 @@ - - + + @@ -23585,18 +23601,18 @@ - - - - - + + + + + - + @@ -23604,54 +23620,54 @@ - + - + - + - + - - + + - - - - - - + + + + + + - - - + + + - + - + - - + + @@ -23659,7 +23675,7 @@ - + @@ -23667,8 +23683,8 @@ - - + + @@ -23678,12 +23694,12 @@ - - - + + + - + @@ -23773,7 +23789,7 @@ - + @@ -23851,7 +23867,7 @@ - + @@ -23862,16 +23878,16 @@ - + - - + + - + - + @@ -23886,24 +23902,24 @@ - - - - - - - - - - - + + + + + + + + + + + - - + + - - + + @@ -23945,13 +23961,13 @@ - + - - + + @@ -23976,30 +23992,30 @@ - + - + - + - - + + - + - + @@ -24013,7 +24029,7 @@ - + @@ -24022,7 +24038,7 @@ - + @@ -24064,12 +24080,12 @@ - + - + @@ -24097,27 +24113,27 @@ - + - + - + - + - + @@ -24138,7 +24154,7 @@ - + @@ -24173,12 +24189,12 @@ - + - + @@ -24196,24 +24212,24 @@ - + - + - + - + - - - - - - + + + + + + @@ -24230,8 +24246,8 @@ - - + + @@ -24258,12 +24274,12 @@ - + - + @@ -24271,7 +24287,7 @@ - + @@ -24280,7 +24296,7 @@ - + @@ -24290,18 +24306,18 @@ - + - + - + - + @@ -24319,34 +24335,34 @@ - + - + - + - + - + - + - + - + - - - - + + + + @@ -24520,7 +24536,7 @@ - + @@ -24552,55 +24568,55 @@ - + - + - + - + - + - - - - + + + + - + - + - + - + - + - + - + - + - + @@ -24608,7 +24624,7 @@ - + @@ -24616,26 +24632,26 @@ - + - + - + - + - - + + - + @@ -24647,22 +24663,22 @@ - - - - - + + + + + - + - + - + @@ -24685,20 +24701,20 @@ - - + + - + - + - + - - + + @@ -24712,23 +24728,23 @@ - - - - + + + + - - - - - - + + + + - + - - + + + + @@ -24763,7 +24779,7 @@ - + @@ -24873,17 +24889,17 @@ - + - - + + - + @@ -24902,7 +24918,7 @@ - + @@ -25106,7 +25122,7 @@ - + @@ -25146,7 +25162,7 @@ - + @@ -25254,7 +25270,7 @@ - + @@ -25263,8 +25279,8 @@ - + @@ -25300,24 +25316,24 @@ - - + + - + - + - + @@ -25333,71 +25349,71 @@ - - - + + + - + - - + + - - - + + + - - + + - - - + + + - - + + - - + + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - + + + - + - + @@ -25405,7 +25421,7 @@ - + @@ -25416,6 +25432,10 @@ + + + + @@ -25460,142 +25480,142 @@ - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - - + + + - - - + + + - + - + - + - + - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + - - + + - - - + + + - - + + - - + + - - - + + + - - + + - - - + + + - - - + + + - - - + + + - - + + @@ -25863,7 +25883,7 @@ - + @@ -25877,16 +25897,16 @@ - - + + - + - + @@ -25924,25 +25944,25 @@ - - - - - - - + + + + + + + - + - + - - + + - - + + @@ -25956,15 +25976,15 @@ - - - + + + - - - - + + + + @@ -25977,127 +25997,127 @@ - + - - + + - - + + - + - - + + - - + + - + - + - - + + - + - + - + - + - + - + - - + + - - - + + + - - - + + + - - - + + + - + - + - + - + - + - - + + - + - - + + - - + + @@ -26111,12 +26131,12 @@ - - + + - - + + @@ -26166,55 +26186,55 @@ - + - - + + - + - + - + - + - - + + - + - - - - - - - - - - - - + + + + + + + + + + - + + + - - - + + + @@ -26230,81 +26250,81 @@ - + - + - + - + - - + + - + - + - - + + - + - + - + - + - + - + - + - + - + @@ -26341,15 +26361,15 @@ - + - + - + @@ -26374,7 +26394,7 @@ - + @@ -26414,18 +26434,18 @@ - + - + - + diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 565b3942ad2d45..03834b20c3e83e 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -8,16 +8,23 @@ extern "C" { #endif - +/* Count of all local monitoring events */ +#define _PY_MONITORING_LOCAL_EVENTS 10 /* Count of all "real" monitoring events (not derived from other events) */ #define _PY_MONITORING_UNGROUPED_EVENTS 15 /* Count of all monitoring events */ #define _PY_MONITORING_EVENTS 17 -/* Table of which tools are active for each monitored event. */ -typedef struct _Py_Monitors { +/* Tables of which tools are active for each monitored event. */ +/* For 3.12 ABI compatibility this is over sized */ +typedef struct _Py_LocalMonitors { + /* Only _PY_MONITORING_LOCAL_EVENTS of these are used */ + uint8_t tools[_PY_MONITORING_UNGROUPED_EVENTS]; +} _Py_LocalMonitors; + +typedef struct _Py_GlobalMonitors { uint8_t tools[_PY_MONITORING_UNGROUPED_EVENTS]; -} _Py_Monitors; +} _Py_GlobalMonitors; /* Each instruction in a code object is a fixed-width value, * currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG @@ -81,9 +88,9 @@ typedef struct { */ typedef struct { /* Monitoring specific to this code object */ - _Py_Monitors local_monitors; + _Py_LocalMonitors local_monitors; /* Monitoring that is active on this code object */ - _Py_Monitors active_monitors; + _Py_LocalMonitors active_monitors; /* The tools that are to be notified for events for the matching code unit */ uint8_t *tools; /* Information to support line events */ diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index 56de9f87171484..87f70d2dc0d9ac 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -29,7 +29,7 @@ extern "C" { #define PY_MONITORING_EVENT_STOP_ITERATION 9 #define PY_MONITORING_IS_INSTRUMENTED_EVENT(ev) \ - ((ev) <= PY_MONITORING_EVENT_STOP_ITERATION) + ((ev) < _PY_MONITORING_LOCAL_EVENTS) /* Other events, mainly exceptions */ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 6109e934098989..1db23145a539cb 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -182,7 +182,7 @@ struct _is { struct callable_cache callable_cache; PyCodeObject *interpreter_trampoline; - _Py_Monitors monitors; + _Py_GlobalMonitors monitors; bool f_opcode_trace_set; bool sys_profile_initialized; bool sys_trace_initialized; diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 4c7438992f88e5..8665c355e7fdd5 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1218,9 +1218,11 @@ def test_instruction_then_line(self): self.check_events(self.func2, recorders = recorders, must_include = self.MUST_INCLUDE_CI) +LOCAL_RECORDERS = CallRecorder, LineRecorder, CReturnRecorder, CRaiseRecorder + class TestLocalEvents(MonitoringTestBase, unittest.TestCase): - def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): + def check_events(self, func, expected, tool=TEST_TOOL, recorders=()): try: self.assertEqual(sys.monitoring._all_events(), {}) event_list = [] @@ -1248,7 +1250,7 @@ def func1(): line2 = 2 line3 = 3 - self.check_events(func1, recorders = MANY_RECORDERS, expected = [ + self.check_events(func1, recorders = LOCAL_RECORDERS, expected = [ ('line', 'func1', 1), ('line', 'func1', 2), ('line', 'func1', 3)]) @@ -1260,7 +1262,7 @@ def func2(): [].append(2) line3 = 3 - self.check_events(func2, recorders = MANY_RECORDERS, expected = [ + self.check_events(func2, recorders = LOCAL_RECORDERS, expected = [ ('line', 'func2', 1), ('line', 'func2', 2), ('call', 'append', [2]), @@ -1277,15 +1279,17 @@ def func3(): line = 5 line = 6 - self.check_events(func3, recorders = MANY_RECORDERS, expected = [ + self.check_events(func3, recorders = LOCAL_RECORDERS, expected = [ ('line', 'func3', 1), ('line', 'func3', 2), ('line', 'func3', 3), - ('raise', KeyError), ('line', 'func3', 4), ('line', 'func3', 5), ('line', 'func3', 6)]) + def test_set_non_local_event(self): + with self.assertRaises(ValueError): + sys.monitoring.set_local_events(TEST_TOOL, just_call.__code__, E.RAISE) def line_from_offset(code, offset): for start, end, line in code.co_lines(): @@ -1698,3 +1702,19 @@ def run(): self.assertEqual(caught, "inner") finally: sys.monitoring.set_events(TEST_TOOL, 0) + + def test_108390(self): + + class Foo: + def __init__(self, set_event): + if set_event: + sys.monitoring.set_events(TEST_TOOL, E.PY_RESUME) + + def make_foo_optimized_then_set_event(): + for i in range(100): + Foo(i == 99) + + try: + make_foo_optimized_then_set_event() + finally: + sys.monitoring.set_events(TEST_TOOL, 0) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst new file mode 100644 index 00000000000000..3ed596007b56f7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst @@ -0,0 +1,4 @@ +Raise an exception when setting a non-local event (``RAISE``, ``EXCEPTION_HANDLED``, +etc.) in ``sys.monitoring.set_local_events``. + +Fixes crash when tracing in recursive calls to Python classes. diff --git a/Python/ceval.c b/Python/ceval.c index c6f54dd24052e8..fdb5b72e6c0f7b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2021,28 +2021,30 @@ do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame, return err; } -static inline int -no_tools_for_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event) +static inline bool +no_tools_for_global_event(PyThreadState *tstate, int event) { + return tstate->interp->monitors.tools[event] == 0; +} + +static inline bool +no_tools_for_local_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event) +{ + assert(event < _PY_MONITORING_LOCAL_EVENTS); _PyCoMonitoringData *data = frame->f_code->_co_monitoring; if (data) { - if (data->active_monitors.tools[event] == 0) { - return 1; - } + return data->active_monitors.tools[event] == 0; } else { - if (tstate->interp->monitors.tools[event] == 0) { - return 1; - } + return no_tools_for_global_event(tstate, event); } - return 0; } static void monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { - if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_RAISE)) { + if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_RAISE)) { return; } do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RAISE); @@ -2052,7 +2054,7 @@ static void monitor_reraise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { - if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_RERAISE)) { + if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_RERAISE)) { return; } do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RERAISE); @@ -2062,7 +2064,7 @@ static int monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { - if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_STOP_ITERATION)) { + if (no_tools_for_local_event(tstate, frame, PY_MONITORING_EVENT_STOP_ITERATION)) { return 0; } return do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_STOP_ITERATION); @@ -2073,7 +2075,7 @@ monitor_unwind(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { - if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_UNWIND)) { + if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_UNWIND)) { return; } do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_UNWIND); @@ -2085,7 +2087,7 @@ monitor_handled(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *exc) { - if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) { + if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) { return 0; } return _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc); @@ -2096,7 +2098,7 @@ monitor_throw(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { - if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_THROW)) { + if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_THROW)) { return; } do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_THROW); diff --git a/Python/instrumentation.c b/Python/instrumentation.c index a5b10ae63e2e6a..f612d78c913f80 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1,5 +1,6 @@ + #include "Python.h" #include "pycore_call.h" #include "pycore_frame.h" @@ -136,9 +137,9 @@ is_instrumented(int opcode) #ifndef NDEBUG static inline bool -monitors_equals(_Py_Monitors a, _Py_Monitors b) +monitors_equals(_Py_LocalMonitors a, _Py_LocalMonitors b) { - for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { if (a.tools[i] != b.tools[i]) { return false; } @@ -147,42 +148,47 @@ monitors_equals(_Py_Monitors a, _Py_Monitors b) } #endif -static inline _Py_Monitors -monitors_sub(_Py_Monitors a, _Py_Monitors b) +static inline _Py_LocalMonitors +monitors_sub(_Py_LocalMonitors a, _Py_LocalMonitors b) { - _Py_Monitors res; - for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { + _Py_LocalMonitors res; + for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { res.tools[i] = a.tools[i] & ~b.tools[i]; } return res; } #ifndef NDEBUG -static inline _Py_Monitors -monitors_and(_Py_Monitors a, _Py_Monitors b) +static inline _Py_LocalMonitors +monitors_and(_Py_LocalMonitors a, _Py_LocalMonitors b) { - _Py_Monitors res; - for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { + _Py_LocalMonitors res; + for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { res.tools[i] = a.tools[i] & b.tools[i]; } return res; } #endif -static inline _Py_Monitors -monitors_or(_Py_Monitors a, _Py_Monitors b) +/* The union of the *local* events in a and b. + * Global events like RAISE are ignored. + * Used for instrumentation, as only local + * events get instrumented. + */ +static inline _Py_LocalMonitors +local_union(_Py_GlobalMonitors a, _Py_LocalMonitors b) { - _Py_Monitors res; - for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { + _Py_LocalMonitors res; + for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { res.tools[i] = a.tools[i] | b.tools[i]; } return res; } static inline bool -monitors_are_empty(_Py_Monitors m) +monitors_are_empty(_Py_LocalMonitors m) { - for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { if (m.tools[i]) { return false; } @@ -191,9 +197,9 @@ monitors_are_empty(_Py_Monitors m) } static inline bool -multiple_tools(_Py_Monitors *m) +multiple_tools(_Py_LocalMonitors *m) { - for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { + for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { if (_Py_popcount32(m->tools[i]) > 1) { return true; } @@ -202,7 +208,19 @@ multiple_tools(_Py_Monitors *m) } static inline _PyMonitoringEventSet -get_events(_Py_Monitors *m, int tool_id) +get_local_events(_Py_LocalMonitors *m, int tool_id) +{ + _PyMonitoringEventSet result = 0; + for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) { + if ((m->tools[e] >> tool_id) & 1) { + result |= (1 << e); + } + } + return result; +} + +static inline _PyMonitoringEventSet +get_events(_Py_GlobalMonitors *m, int tool_id) { _PyMonitoringEventSet result = 0; for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { @@ -449,10 +467,10 @@ sanity_check_instrumentation(PyCodeObject *code) if (data == NULL) { return; } - _Py_Monitors active_monitors = PyInterpreterState_Get()->monitors; + _Py_GlobalMonitors active_monitors = _PyInterpreterState_GET()->monitors; if (code->_co_monitoring) { _Py_Monitors local_monitors = code->_co_monitoring->local_monitors; - active_monitors = monitors_or(active_monitors, local_monitors); + active_monitors = local_union(active_monitors, local_monitors); } assert(monitors_equals( code->_co_monitoring->active_monitors, @@ -879,7 +897,7 @@ is_version_up_to_date(PyCodeObject *code, PyInterpreterState *interp) static bool instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code) { - _Py_Monitors expected = monitors_or( + _Py_LocalMonitors expected = local_union( interp->monitors, code->_co_monitoring->local_monitors); return monitors_equals(code->_co_monitoring->active_monitors, expected); @@ -887,26 +905,29 @@ instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code) #endif static inline uint8_t -get_tools_for_instruction(PyCodeObject * code, int i, int event) +get_tools_for_instruction(PyCodeObject *code, PyInterpreterState *interp, int i, int event) { uint8_t tools; assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); - assert(instrumentation_cross_checks(PyThreadState_GET()->interp, code)); - _PyCoMonitoringData *monitoring = code->_co_monitoring; if (event >= _PY_MONITORING_UNGROUPED_EVENTS) { assert(event == PY_MONITORING_EVENT_C_RAISE || event == PY_MONITORING_EVENT_C_RETURN); event = PY_MONITORING_EVENT_CALL; } - if (PY_MONITORING_IS_INSTRUMENTED_EVENT(event) && monitoring->tools) { - tools = monitoring->tools[i]; + if (PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) { + CHECK(is_version_up_to_date(code, interp)); + CHECK(instrumentation_cross_checks(interp, code)); + if (code->_co_monitoring->tools) { + tools = code->_co_monitoring->tools[i]; + } + else { + tools = code->_co_monitoring->active_monitors.tools[event]; + } } else { - tools = code->_co_monitoring->active_monitors.tools[event]; + tools = interp->monitors.tools[event]; } - CHECK(tools_is_subset_for_event(code, event, tools)); - CHECK((tools & code->_co_monitoring->active_monitors.tools[event]) == tools); return tools; } @@ -956,11 +977,11 @@ call_instrumentation_vector( } assert(args[2] == NULL); args[2] = offset_obj; - uint8_t tools = get_tools_for_instruction(code, offset, event); + PyInterpreterState *interp = tstate->interp; + uint8_t tools = get_tools_for_instruction(code, interp, offset, event); Py_ssize_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; PyObject **callargs = &args[1]; int err = 0; - PyInterpreterState *interp = tstate->interp; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); @@ -1397,7 +1418,7 @@ initialize_lines(PyCodeObject *code) } static void -initialize_line_tools(PyCodeObject *code, _Py_Monitors *all_events) +initialize_line_tools(PyCodeObject *code, _Py_LocalMonitors *all_events) { uint8_t *line_tools = code->_co_monitoring->line_tools; assert(line_tools != NULL); @@ -1417,8 +1438,8 @@ allocate_instrumentation_data(PyCodeObject *code) PyErr_NoMemory(); return -1; } - code->_co_monitoring->local_monitors = (_Py_Monitors){ 0 }; - code->_co_monitoring->active_monitors = (_Py_Monitors){ 0 }; + code->_co_monitoring->local_monitors = (_Py_LocalMonitors){ 0 }; + code->_co_monitoring->active_monitors = (_Py_LocalMonitors){ 0 }; code->_co_monitoring->tools = NULL; code->_co_monitoring->lines = NULL; code->_co_monitoring->line_tools = NULL; @@ -1435,7 +1456,7 @@ update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp) if (allocate_instrumentation_data(code)) { return -1; } - _Py_Monitors all_events = monitors_or( + _Py_LocalMonitors all_events = local_union( interp->monitors, code->_co_monitoring->local_monitors); bool multitools = multiple_tools(&all_events); @@ -1518,14 +1539,23 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) return 0; } int code_len = (int)Py_SIZE(code); + /* code->_co_firsttraceable >= code_len indicates + * that no instrumentation can be inserted. + * Exit early to avoid creating instrumentation + * data for potential statically allocated code + * objects. + * See https://github.com/python/cpython/issues/108390 */ + if (code->_co_firsttraceable >= code_len) { + return 0; + } if (update_instrumentation_data(code, interp)) { return -1; } - _Py_Monitors active_events = monitors_or( + _Py_LocalMonitors active_events = local_union( interp->monitors, code->_co_monitoring->local_monitors); - _Py_Monitors new_events; - _Py_Monitors removed_events; + _Py_LocalMonitors new_events; + _Py_LocalMonitors removed_events; bool restarted = interp->last_restart_version > code->_co_instrumentation_version; if (restarted) { @@ -1669,10 +1699,22 @@ instrument_all_executing_code_objects(PyInterpreterState *interp) { } static void -set_events(_Py_Monitors *m, int tool_id, _PyMonitoringEventSet events) +set_events(_Py_GlobalMonitors *m, int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { + uint8_t *tools = &m->tools[e]; + int active = (events >> e) & 1; + *tools &= ~(1 << tool_id); + *tools |= (active << tool_id); + } +} + +static void +set_local_events(_Py_LocalMonitors *m, int tool_id, _PyMonitoringEventSet events) +{ + assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); + for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) { uint8_t *tools = &m->tools[e]; int val = (events >> e) & 1; *tools &= ~(1 << tool_id); @@ -1715,19 +1757,23 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_Get(); - assert(events < (1 << _PY_MONITORING_UNGROUPED_EVENTS)); + assert(events < (1 << _PY_MONITORING_LOCAL_EVENTS)); + if (code->_co_firsttraceable >= Py_SIZE(code)) { + PyErr_Format(PyExc_SystemError, "cannot instrument shim code object '%U'", code->co_name); + return -1; + } if (check_tool(interp, tool_id)) { return -1; } if (allocate_instrumentation_data(code)) { return -1; } - _Py_Monitors *local = &code->_co_monitoring->local_monitors; - uint32_t existing_events = get_events(local, tool_id); + _Py_LocalMonitors *local = &code->_co_monitoring->local_monitors; + uint32_t existing_events = get_local_events(local, tool_id); if (existing_events == events) { return 0; } - set_events(local, tool_id, events); + set_local_events(local, tool_id, events); if (is_version_up_to_date(code, interp)) { /* Force instrumentation update */ code->_co_instrumentation_version = UINT64_MAX; @@ -1886,7 +1932,7 @@ monitoring_get_events_impl(PyObject *module, int tool_id) if (check_valid_tool(tool_id)) { return -1; } - _Py_Monitors *m = &_PyInterpreterState_Get()->monitors; + _Py_GlobalMonitors *m = &_PyInterpreterState_GET()->monitors; _PyMonitoringEventSet event_set = get_events(m, tool_id); return event_set; } @@ -1949,7 +1995,7 @@ monitoring_get_local_events_impl(PyObject *module, int tool_id, _PyMonitoringEventSet event_set = 0; _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring; if (data != NULL) { - for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { + for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) { if ((data->local_monitors.tools[e] >> tool_id) & 1) { event_set |= (1 << e); } @@ -1983,15 +2029,16 @@ monitoring_set_local_events_impl(PyObject *module, int tool_id, if (check_valid_tool(tool_id)) { return NULL; } - if (event_set < 0 || event_set >= (1 << _PY_MONITORING_EVENTS)) { - PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); - return NULL; - } if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); return NULL; } event_set &= ~C_RETURN_EVENTS; + if (event_set < 0 || event_set >= (1 << _PY_MONITORING_LOCAL_EVENTS)) { + PyErr_Format(PyExc_ValueError, "invalid local event set 0x%x", event_set); + return NULL; + } + if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) { return NULL; } From 578b3ea0e9816cecaef246a50d20257de8e0d642 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Sep 2023 06:07:11 -0700 Subject: [PATCH 0695/1206] [3.12] GH-103082: Document PEP-669: Low Impact Monitoring for CPython (GH-107772) (#108909) GH-103082: Document PEP-669: Low Impact Monitoring for CPython (GH-107772) (cherry picked from commit 8b515f60ee1dec65cb3d64f1cc1d4b32aa2f4184) Co-authored-by: Mark Shannon --- Doc/library/python.rst | 1 + Doc/library/sys.monitoring.rst | 300 +++++++++++++++++++++++++++++++++ Doc/library/sys.rst | 7 + Doc/whatsnew/3.12.rst | 15 ++ 4 files changed, 323 insertions(+) create mode 100644 Doc/library/sys.monitoring.rst diff --git a/Doc/library/python.rst b/Doc/library/python.rst index f39613f572884f..610435999d9f48 100644 --- a/Doc/library/python.rst +++ b/Doc/library/python.rst @@ -12,6 +12,7 @@ overview: .. toctree:: sys.rst + sys.monitoring.rst sysconfig.rst builtins.rst __main__.rst diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst new file mode 100644 index 00000000000000..7b02b95fd766a7 --- /dev/null +++ b/Doc/library/sys.monitoring.rst @@ -0,0 +1,300 @@ +:mod:`sys.monitoring` --- Execution event monitoring +==================================================== + +.. module:: sys.monitoring + :synopsis: Access and control event monitoring + +----------------- + +.. note:: + + ``sys.monitoring`` is a namespace within the ``sys`` module, + not an independent module, so there is no need to + ``import sys.monitoring``, simply ``import sys`` and then use + ``sys.monitoring``. + + +This namespace provides access to the functions and constants necessary to +activate and control event monitoring. + +As programs execute, events occur that might be of interest to tools that +monitor execution. The :mod:`!sys.monitoring` namespace provides means to +receive callbacks when events of interest occur. + +The monitoring API consists of three components: + +* Tool identifiers +* Events +* Callbacks + +Tool identifiers +---------------- + +A tool identifier is an integer and associated name. +Tool identifiers are used to discourage tools from interfering with each +other and to allow multiple tools to operate at the same time. +Currently tools are completely independent and cannot be used to +monitor each other. This restriction may be lifted in the future. + +Before registering or activating events, a tool should choose an identifier. +Identifiers are integers in the range 0 to 5. + +Registering and using tools +''''''''''''''''''''''''''' + +.. function:: use_tool_id(id: int, name: str) -> None + + Must be called before ``id`` can be used. + ``id`` must be in the range 0 to 5 inclusive. + Raises a ``ValueError`` if ``id`` is in use. + +.. function:: free_tool_id(id: int) -> None + + Should be called once a tool no longer requires ``id``. + +.. function:: get_tool(id: int) -> str | None + + Returns the name of the tool if ``id`` is in use, + otherwise it returns ``None``. + ``id`` must be in the range 0 to 5 inclusive. + +All IDs are treated the same by the VM with regard to events, but the +following IDs are pre-defined to make co-operation of tools easier:: + + sys.monitoring.DEBUGGER_ID = 0 + sys.monitoring.COVERAGE_ID = 1 + sys.monitoring.PROFILER_ID = 2 + sys.monitoring.OPTIMIZER_ID = 5 + +There is no obligation to set an ID, nor is there anything preventing a tool +from using an ID even it is already in use. +However, tools are encouraged to use a unique ID and respect other tools. + +Events +------ + +The following events are supported: + +BRANCH + A conditional branch is taken (or not). +CALL + A call in Python code (event occurs before the call). +C_RAISE + Exception raised from any callable, except Python functions (event occurs after the exit). +C_RETURN + Return from any callable, except Python functions (event occurs after the return). +EXCEPTION_HANDLED + An exception is handled. +INSTRUCTION + A VM instruction is about to be executed. +JUMP + An unconditional jump in the control flow graph is made. +LINE + An instruction is about to be executed that has a different line number from the preceding instruction. +PY_RESUME + Resumption of a Python function (for generator and coroutine functions), except for throw() calls. +PY_RETURN + Return from a Python function (occurs immediately before the return, the callee's frame will be on the stack). +PY_START + Start of a Python function (occurs immediately after the call, the callee's frame will be on the stack) +PY_THROW + A Python function is resumed by a throw() call. +PY_UNWIND + Exit from a Python function during exception unwinding. +PY_YIELD + Yield from a Python function (occurs immediately before the yield, the callee's frame will be on the stack). +RAISE + An exception is raised, except those that cause a ``STOP_ITERATION`` event. +RERAISE + An exception is re-raised, for example at the end of a ``finally`` block. +STOP_ITERATION + An artificial ``StopIteration`` is raised; see `the STOP_ITERATION event`_. + +More events may be added in the future. + +These events are attributes of the :mod:`!sys.monitoring.events` namespace. +Each event is represented as a power-of-2 integer constant. +To define a set of events, simply bitwise or the individual events together. +For example, to specify both ``PY_RETURN`` and ``PY_START`` events, use the +expression ``PY_RETURN | PY_START``. + +Events are divided into three groups: + +Local events +'''''''''''' + +Local events are associated with normal execution of the program and happen +at clearly defined locations. All local events can be disabled. +The local events are: + +* PY_START +* PY_RESUME +* PY_RETURN +* PY_YIELD +* CALL +* LINE +* INSTRUCTION +* JUMP +* BRANCH +* STOP_ITERATION + +Ancillary events +'''''''''''''''' + +Ancillary events can be monitored like other events, but are controlled +by another event: + +* C_RAISE +* C_RETURN + +The ``C_RETURN`` and ``C_RAISE`` events are are controlled by the ``CALL`` +event. ``C_RETURN`` and ``C_RAISE`` events will only be seen if the +corresponding ``CALL`` event is being monitored. + +Other events +'''''''''''' + +Other events are not necessarily tied to a specific location in the +program and cannot be individually disabled. + +The other events that can be monitored are: + +* PY_THROW +* PY_UNWIND +* RAISE +* EXCEPTION_HANDLED + + +The STOP_ITERATION event +'''''''''''''''''''''''' + +:pep:`PEP 380 <380#use-of-stopiteration-to-return-values>` +specifies that a ``StopIteration`` exception is raised when returning a value +from a generator or coroutine. However, this is a very inefficient way to +return a value, so some Python implementations, notably CPython 3.12+, do not +raise an exception unless it would be visible to other code. + +To allow tools to monitor for real exceptions without slowing down generators +and coroutines, the ``STOP_ITERATION`` event is provided. +``STOP_ITERATION`` can be locally disabled, unlike ``RAISE``. + + +Turning events on and off +------------------------- + +In order to monitor an event, it must be turned on and a callback registered. +Events can be turned on or off by setting the events either globally or +for a particular code object. + + +Setting events globally +''''''''''''''''''''''' + +Events can be controlled globally by modifying the set of events being monitored. + +.. function:: get_events(tool_id: int) -> int + + Returns the ``int`` representing all the active events. + +.. function:: set_events(tool_id: int, event_set: int) + + Activates all events which are set in ``event_set``. + Raises a ``ValueError`` if ``tool_id`` is not in use. + +No events are active by default. + +Per code object events +'''''''''''''''''''''' + +Events can also be controlled on a per code object basis. + +.. function:: get_local_events(tool_id: int, code: CodeType) -> int + + Returns all the local events for ``code`` + +.. function:: set_local_events(tool_id: int, code: CodeType, event_set: int) + + Activates all the local events for ``code`` which are set in ``event_set``. + Raises a ``ValueError`` if ``tool_id`` is not in use. + +Local events add to global events, but do not mask them. +In other words, all global events will trigger for a code object, +regardless of the local events. + + +Disabling events +'''''''''''''''' + +Local events can be disabled for a specific code location by returning +``sys.monitoring.DISABLE`` from a callback function. This does not change +which events are set, or any other code locations for the same event. + +Disabling events for specific locations is very important for high +performance monitoring. For example, a program can be run under a +debugger with no overhead if the debugger disables all monitoring +except for a few breakpoints. + + +Registering callback functions +------------------------------ + +To register a callable for events call + +.. function:: register_callback(tool_id: int, event: int, func: Callable | None) -> Callable | None + + Registers the callable ``func`` for the ``event`` with the given ``tool_id`` + + If another callback was registered for the given ``tool_id`` and ``event``, + it is unregistered and returned. + Otherwise ``register_callback`` returns ``None``. + + +Functions can be unregistered by calling +``sys.monitoring.register_callback(tool_id, event, None)``. + +Callback functions can be registered and unregistered at any time. + +Registering or unregistering a callback function will generate a ``sys.audit`` event. + + +Callback function arguments +''''''''''''''''''''''''''' + +When an active event occurs, the registered callback function is called. +Different events will provide the callback function with different arguments, as follows: + +* ``PY_START`` and ``PY_RESUME``:: + + func(code: CodeType, instruction_offset: int) -> DISABLE | Any + +* ``PY_RETURN`` and ``PY_YIELD``: + + ``func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any`` + +* ``CALL``, ``C_RAISE`` and ``C_RETURN``: + + ``func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any`` + + If there are no arguments, ``arg0`` is set to ``MISSING``. + +* ``RAISE``, ``RERAISE``, ``EXCEPTION_HANDLED``, ``PY_UNWIND``, ``PY_THROW`` and ``STOP_ITERATION``: + + ``func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any`` + +* ``LINE``: + + ``func(code: CodeType, line_number: int) -> DISABLE | Any`` + +* ``BRANCH`` and ``JUMP``: + + ``func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any`` + + Note that the ``destination_offset`` is where the code will next execute. + For an untaken branch this will be the offset of the instruction following + the branch. + +* ``INSTRUCTION``: + + ``func(code: CodeType, instruction_offset: int) -> DISABLE | Any`` + + diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index e7b34a83ebe9a7..20a337bdf0f595 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1953,6 +1953,13 @@ always available. .. availability:: Windows. +.. data:: monitoring + :noindex: + + Namespace containing functions and constants for register callbacks + and controlling monitoring events. + See :mod:`sys.monitoring` for details. + .. data:: _xoptions A dictionary of the various implementation-specific flags passed through diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f58c2d94e431bc..8bd642245d4fe3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -74,6 +74,8 @@ Interpreter improvements: * :ref:`whatsnew312-pep684` +* :ref:`whatsnew312-pep669` + New typing features: * :ref:`whatsnew312-pep688` @@ -313,6 +315,19 @@ A Python API is anticipated for 3.13. (See :pep:`554`.) (Contributed by Eric Snow in :gh:`104210`, etc.) +.. _whatsnew312-pep669: + +PEP 669: Low impact monitoring for CPython +------------------------------------------ + +CPython 3.12 now supports the ability to monitor calls, +returns, lines, exceptions and other events using instrumentation. +This means that you only pay for what you use, providing support +for near-zero overhead debuggers and coverage tools. + +See :mod:`sys.monitoring` for details. + + New Features Related to Type Hints ================================== From 3d0827e397f6d75d33e578ce4eec459458a34080 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Sep 2023 11:19:06 -0700 Subject: [PATCH 0696/1206] [3.12] gh-107565: Update Windows build to use OpenSSL 3.0.10 (GH-108928) (#108930) gh-107565: Update Windows build to use OpenSSL 3.0.10 (GH-108928) (cherry picked from commit deea7c82682848b2a0db971a4dcc3a32c73a9f8c) Co-authored-by: Zachary Ware --- .../Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst | 1 + PCbuild/get_externals.bat | 4 ++-- PCbuild/python.props | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst diff --git a/Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst b/Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst new file mode 100644 index 00000000000000..024a58299caed9 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst @@ -0,0 +1 @@ +Update Windows build to use OpenSSL 3.0.10. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 77b9594799ea79..99c2e20a267b2b 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.9 +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.10 set libraries=%libraries% sqlite-3.42.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 @@ -77,7 +77,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.9 +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.10 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.13.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/python.props b/PCbuild/python.props index d3586235c82652..94faa8221eac5a 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -74,8 +74,8 @@ $(ExternalsDir)libffi-3.4.4\ $(libffiDir)$(ArchName)\ $(libffiOutDir)include - $(ExternalsDir)openssl-3.0.9\ - $(ExternalsDir)openssl-bin-3.0.9\$(ArchName)\ + $(ExternalsDir)openssl-3.0.10\ + $(ExternalsDir)openssl-bin-3.0.10\$(ArchName)\ $(opensslOutDir)include $(ExternalsDir)\nasm-2.11.06\ $(ExternalsDir)\zlib-1.2.13\ From 460043b5548c736ac784e8a09030799322777af0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Sep 2023 13:43:47 -0700 Subject: [PATCH 0697/1206] [3.12] gh-108927: Fix test_import + test_importlib + test_unittest problem (GH-108929) (#108954) gh-108927: Fix test_import + test_importlib + test_unittest problem (GH-108929) (cherry picked from commit 3f89b257639dd817a32079da2ae2c4436b8e82eb) Co-authored-by: Nikita Sobolev --- Lib/test/test_unittest/test_discovery.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_unittest/test_discovery.py b/Lib/test/test_unittest/test_discovery.py index 946fa1258ea25e..004898ed431834 100644 --- a/Lib/test/test_unittest/test_discovery.py +++ b/Lib/test/test_unittest/test_discovery.py @@ -6,7 +6,6 @@ import pickle from test import support from test.support import import_helper -import test.test_importlib.util import unittest import unittest.mock @@ -826,6 +825,8 @@ def restore(): 'as dotted module names') def test_discovery_failed_discovery(self): + from test.test_importlib import util + loader = unittest.TestLoader() package = types.ModuleType('package') @@ -837,7 +838,7 @@ def _import(packagename, *args, **kwargs): # Since loader.discover() can modify sys.path, restore it when done. with import_helper.DirsOnSysPath(): # Make sure to remove 'package' from sys.modules when done. - with test.test_importlib.util.uncache('package'): + with util.uncache('package'): with self.assertRaises(TypeError) as cm: loader.discover('package') self.assertEqual(str(cm.exception), From 495ba70356fc4824aabb7c245b441051dded14e0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Sep 2023 13:49:55 -0700 Subject: [PATCH 0698/1206] [3.12] gh-108469: Update ast.unparse for unescaped quote support from PEP701 [3.12] (GH-108553) (#108960) Co-authored-by: Anthony Shaw Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> --- Lib/ast.py | 31 ++++++------------- Lib/test/test_tokenize.py | 2 +- Lib/test/test_unparse.py | 23 ++++++++++---- ...-09-03-04-37-52.gh-issue-108469.kusj40.rst | 3 ++ 4 files changed, 31 insertions(+), 28 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst diff --git a/Lib/ast.py b/Lib/ast.py index a307f3ecd06175..f4e542cdf253c6 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1223,17 +1223,7 @@ def _write_str_avoiding_backslashes(self, string, *, quote_types=_ALL_QUOTES): def visit_JoinedStr(self, node): self.write("f") - if self._avoid_backslashes: - with self.buffered() as buffer: - self._write_fstring_inner(node) - return self._write_str_avoiding_backslashes("".join(buffer)) - - # If we don't need to avoid backslashes globally (i.e., we only need - # to avoid them inside FormattedValues), it's cosmetically preferred - # to use escaped whitespace. That is, it's preferred to use backslashes - # for cases like: f"{x}\n". To accomplish this, we keep track of what - # in our buffer corresponds to FormattedValues and what corresponds to - # Constant parts of the f-string, and allow escapes accordingly. + fstring_parts = [] for value in node.values: with self.buffered() as buffer: @@ -1245,11 +1235,14 @@ def visit_JoinedStr(self, node): new_fstring_parts = [] quote_types = list(_ALL_QUOTES) for value, is_constant in fstring_parts: - value, quote_types = self._str_literal_helper( - value, - quote_types=quote_types, - escape_special_whitespace=is_constant, - ) + if is_constant: + value, quote_types = self._str_literal_helper( + value, + quote_types=quote_types, + escape_special_whitespace=True, + ) + elif "\n" in value: + quote_types = [q for q in quote_types if q in _MULTI_QUOTES] new_fstring_parts.append(value) value = "".join(new_fstring_parts) @@ -1271,16 +1264,12 @@ def _write_fstring_inner(self, node): def visit_FormattedValue(self, node): def unparse_inner(inner): - unparser = type(self)(_avoid_backslashes=True) + unparser = type(self)() unparser.set_precedence(_Precedence.TEST.next(), inner) return unparser.visit(inner) with self.delimit("{", "}"): expr = unparse_inner(node.value) - if "\\" in expr: - raise ValueError( - "Unable to avoid backslash in f-string expression part" - ) if expr.startswith("{"): # Separate pair of opening brackets as "{ {" self.write(" ") diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 5ad278499c9df9..c320478cf3a7bf 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1857,7 +1857,7 @@ def test_random_files(self): testfiles.remove(os.path.join(tempdir, "test_unicode_identifiers.py")) - # TODO: Remove this once we can unparse PEP 701 syntax + # TODO: Remove this once we can untokenize PEP 701 syntax testfiles.remove(os.path.join(tempdir, "test_fstring.py")) for f in ('buffer', 'builtin', 'fileio', 'inspect', 'os', 'platform', 'sys'): diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index b3efb61e83049e..38c59e6d430b58 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -197,6 +197,10 @@ def test_fstrings_complicated(self): self.check_ast_roundtrip('''f"a\\r\\nb"''') self.check_ast_roundtrip('''f"\\u2028{'x'}"''') + def test_fstrings_pep701(self): + self.check_ast_roundtrip('f" something { my_dict["key"] } something else "') + self.check_ast_roundtrip('f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"') + def test_strings(self): self.check_ast_roundtrip("u'foo'") self.check_ast_roundtrip("r'foo'") @@ -378,8 +382,15 @@ def test_invalid_fstring_value(self): ) ) - def test_invalid_fstring_backslash(self): - self.check_invalid(ast.FormattedValue(value=ast.Constant(value="\\\\"))) + def test_fstring_backslash(self): + # valid since Python 3.12 + self.assertEqual(ast.unparse( + ast.FormattedValue( + value=ast.Constant(value="\\\\"), + conversion=-1, + format_spec=None, + ) + ), "{'\\\\\\\\'}") def test_invalid_yield_from(self): self.check_invalid(ast.YieldFrom(value=None)) @@ -502,11 +513,11 @@ def test_class_bases_and_keywords(self): self.check_src_roundtrip("class X(*args, **kwargs):\n pass") def test_fstrings(self): - self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''') - self.check_src_roundtrip('''f"\\u2028{'x'}"''') + self.check_src_roundtrip("f'-{f'*{f'+{f'.{x}.'}+'}*'}-'") + self.check_src_roundtrip("f'\\u2028{'x'}'") self.check_src_roundtrip(r"f'{x}\n'") - self.check_src_roundtrip('''f''\'{"""\n"""}\\n''\'''') - self.check_src_roundtrip('''f''\'{f"""{x}\n"""}\\n''\'''') + self.check_src_roundtrip("f'{'\\n'}\\n'") + self.check_src_roundtrip("f'{f'{x}\\n'}\\n'") def test_docstrings(self): docstrings = ( diff --git a/Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst b/Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst new file mode 100644 index 00000000000000..ac0f682963daec --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst @@ -0,0 +1,3 @@ +:func:`ast.unparse` now supports new :term:`f-string` syntax introduced in +Python 3.12. Note that the :term:`f-string` quotes are reselected for simplicity +under the new syntax. (Patch by Steven Sun) From 40913a56eda152e72c4b80aee8e86542c3019084 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 5 Sep 2023 23:55:58 +0200 Subject: [PATCH 0699/1206] Python 3.12.0rc2 --- Include/patchlevel.h | 4 +- Lib/pydoc_data/topics.py | 1947 +++++++++-------- Misc/NEWS.d/3.12.0rc2.rst | 510 +++++ ...-08-09-17-05-33.gh-issue-107814.c0Oapq.rst | 1 - ...3-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst | 3 - ...-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst | 1 - ...-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst | 4 - ...-08-14-10-59-03.gh-issue-107916.KH4Muo.rst | 4 - ...3-07-25-22-35-35.gh-issue-77377.EHAbXx.rst | 1 - ...-08-02-12-24-51.gh-issue-107080.PNolFU.rst | 4 - ...-08-04-21-25-26.gh-issue-107724.EbBXMr.rst | 3 - ...3-08-10-17-36-27.gh-issue-91051.LfaeNW.rst | 2 - ...-08-13-17-18-22.gh-issue-108390.TkBccC.rst | 4 - ...-08-21-21-13-30.gh-issue-107901.hszvdk.rst | 1 - ...-08-25-14-51-06.gh-issue-106176.D1EA2a.rst | 4 - ...-08-26-04-33-18.gh-issue-108487.aUFxqf.rst | 1 - ...-08-29-17-53-12.gh-issue-108654.jbkDVo.rst | 2 - ...-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst | 3 - ...-05-29-14-10-24.gh-issue-105052.MGFwbm.rst | 1 - ...2-11-26-22-05-22.gh-issue-99203.j0DUae.rst | 5 - ...-03-14-01-19-57.gh-issue-100061.CiXJYn.rst | 2 - ...-07-07-14-52-31.gh-issue-106052.ak8nbs.rst | 2 - ...-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst | 1 - ...-08-05-05-10-41.gh-issue-106684.P9zRXb.rst | 1 - ...-08-06-15-29-00.gh-issue-100814.h195gW.rst | 2 - ...-08-07-14-12-07.gh-issue-107715.238r2f.rst | 1 - ...-08-09-13-49-37.gh-issue-107805.ezem0k.rst | 1 - ...-08-10-17-36-22.gh-issue-107845.dABiMJ.rst | 3 - ...-08-14-11-18-13.gh-issue-107913.4ooY6i.rst | 3 - ...-08-14-23-11-11.gh-issue-106242.71HMym.rst | 1 - ...-08-15-18-20-00.gh-issue-107963.20g5BG.rst | 2 - ...-08-17-12-59-35.gh-issue-108083.9J7UcT.rst | 3 - ...-08-17-14-45-25.gh-issue-105736.NJsH7r.rst | 3 - ...-08-22-17-27-12.gh-issue-108111.N7a4u_.rst | 2 - ...3-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst | 2 - ...-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst | 1 - ...-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst | 2 - ...-09-03-04-37-52.gh-issue-108469.kusj40.rst | 3 - ...-08-05-03-51-05.gh-issue-107774.VPjaTR.rst | 3 - ...-08-22-17-39-12.gh-issue-108310.fVM3sg.rst | 7 - ...-07-24-16-56-59.gh-issue-107178.Gq1usE.rst | 2 - ...-08-23-04-08-18.gh-issue-105776.oE6wp_.rst | 2 - ...-08-24-04-23-35.gh-issue-108388.mr0MeE.rst | 4 - ...-08-24-06-10-36.gh-issue-108388.YCVB0D.rst | 2 - ...3-09-04-15-18-14.gh-issue-89392.8A4T5p.rst | 2 - ...3-08-07-16-30-48.gh-issue-95065.-im4R5.rst | 2 - ...-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst | 2 - ...-07-18-13-01-26.gh-issue-106844.mci4xO.rst | 1 - ...-08-22-00-36-57.gh-issue-106242.q24ITw.rst | 4 - ...-09-05-10-08-47.gh-issue-107565.CIMftz.rst | 1 - ...-08-12-13-33-57.gh-issue-107565.SJwqf4.rst | 1 - README.rst | 2 +- 52 files changed, 1499 insertions(+), 1076 deletions(-) create mode 100644 Misc/NEWS.d/3.12.0rc2.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst delete mode 100644 Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst delete mode 100644 Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst delete mode 100644 Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst delete mode 100644 Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst delete mode 100644 Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 29a87c5a3f5ef6..5fd803e587f4dc 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.12.0rc1+" +#define PY_VERSION "3.12.0rc2" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 8d19a85963fe43..3436f03b47e4ec 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sat Aug 5 14:10:40 2023 +# Autogenerated by Sphinx on Tue Sep 5 23:56:33 2023 # as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' @@ -1006,9 +1006,7 @@ 'for each\n' ' instance.\n' '\n' - '\n' - 'Notes on using *__slots__*\n' - '--------------------------\n' + 'Notes on using *__slots__*:\n' '\n' '* When inheriting from a class without *__slots__*, the ' '"__dict__" and\n' @@ -10581,9 +10579,7 @@ 'each\n' ' instance.\n' '\n' - '\n' - 'Notes on using *__slots__*\n' - '~~~~~~~~~~~~~~~~~~~~~~~~~~\n' + 'Notes on using *__slots__*:\n' '\n' '* When inheriting from a class without *__slots__*, the ' '"__dict__" and\n' @@ -13544,1156 +13540,1185 @@ 'definition\n' 'may change in the future.\n' '\n' + '\n' 'None\n' - ' This type has a single value. There is a single object with ' - 'this\n' - ' value. This object is accessed through the built-in name "None". ' - 'It\n' - ' is used to signify the absence of a value in many situations, ' - 'e.g.,\n' - ' it is returned from functions that don’t explicitly return\n' - ' anything. Its truth value is false.\n' + '====\n' + '\n' + 'This type has a single value. There is a single object with this\n' + 'value. This object is accessed through the built-in name "None". It ' + 'is\n' + 'used to signify the absence of a value in many situations, e.g., it ' + 'is\n' + 'returned from functions that don’t explicitly return anything. Its\n' + 'truth value is false.\n' + '\n' '\n' 'NotImplemented\n' - ' This type has a single value. There is a single object with ' - 'this\n' - ' value. This object is accessed through the built-in name\n' - ' "NotImplemented". Numeric methods and rich comparison methods\n' - ' should return this value if they do not implement the operation ' - 'for\n' - ' the operands provided. (The interpreter will then try the\n' - ' reflected operation, or some other fallback, depending on the\n' - ' operator.) It should not be evaluated in a boolean context.\n' + '==============\n' '\n' - ' See Implementing the arithmetic operations for more details.\n' + 'This type has a single value. There is a single object with this\n' + 'value. This object is accessed through the built-in name\n' + '"NotImplemented". Numeric methods and rich comparison methods ' + 'should\n' + 'return this value if they do not implement the operation for the\n' + 'operands provided. (The interpreter will then try the reflected\n' + 'operation, or some other fallback, depending on the operator.) It\n' + 'should not be evaluated in a boolean context.\n' + '\n' + 'See Implementing the arithmetic operations for more details.\n' + '\n' + 'Changed in version 3.9: Evaluating "NotImplemented" in a boolean\n' + 'context is deprecated. While it currently evaluates as true, it ' + 'will\n' + 'emit a "DeprecationWarning". It will raise a "TypeError" in a ' + 'future\n' + 'version of Python.\n' '\n' - ' Changed in version 3.9: Evaluating "NotImplemented" in a ' - 'boolean\n' - ' context is deprecated. While it currently evaluates as true, it\n' - ' will emit a "DeprecationWarning". It will raise a "TypeError" in ' - 'a\n' - ' future version of Python.\n' '\n' 'Ellipsis\n' - ' This type has a single value. There is a single object with ' - 'this\n' - ' value. This object is accessed through the literal "..." or the\n' - ' built-in name "Ellipsis". Its truth value is true.\n' + '========\n' + '\n' + 'This type has a single value. There is a single object with this\n' + 'value. This object is accessed through the literal "..." or the ' + 'built-\n' + 'in name "Ellipsis". Its truth value is true.\n' + '\n' '\n' '"numbers.Number"\n' - ' These are created by numeric literals and returned as results ' - 'by\n' - ' arithmetic operators and arithmetic built-in functions. ' - 'Numeric\n' - ' objects are immutable; once created their value never changes.\n' - ' Python numbers are of course strongly related to mathematical\n' - ' numbers, but subject to the limitations of numerical ' - 'representation\n' - ' in computers.\n' - '\n' - ' The string representations of the numeric classes, computed by\n' - ' "__repr__()" and "__str__()", have the following properties:\n' - '\n' - ' * They are valid numeric literals which, when passed to their ' + '================\n' + '\n' + 'These are created by numeric literals and returned as results by\n' + 'arithmetic operators and arithmetic built-in functions. Numeric\n' + 'objects are immutable; once created their value never changes. ' + 'Python\n' + 'numbers are of course strongly related to mathematical numbers, ' + 'but\n' + 'subject to the limitations of numerical representation in ' + 'computers.\n' + '\n' + 'The string representations of the numeric classes, computed by\n' + '"__repr__()" and "__str__()", have the following properties:\n' + '\n' + '* They are valid numeric literals which, when passed to their ' 'class\n' - ' constructor, produce an object having the value of the ' - 'original\n' - ' numeric.\n' + ' constructor, produce an object having the value of the original\n' + ' numeric.\n' '\n' - ' * The representation is in base 10, when possible.\n' + '* The representation is in base 10, when possible.\n' '\n' - ' * Leading zeros, possibly excepting a single zero before a ' - 'decimal\n' - ' point, are not shown.\n' + '* Leading zeros, possibly excepting a single zero before a decimal\n' + ' point, are not shown.\n' '\n' - ' * Trailing zeros, possibly excepting a single zero after a ' - 'decimal\n' - ' point, are not shown.\n' + '* Trailing zeros, possibly excepting a single zero after a decimal\n' + ' point, are not shown.\n' '\n' - ' * A sign is shown only when the number is negative.\n' + '* A sign is shown only when the number is negative.\n' '\n' - ' Python distinguishes between integers, floating point numbers, ' - 'and\n' - ' complex numbers:\n' + 'Python distinguishes between integers, floating point numbers, and\n' + 'complex numbers:\n' '\n' - ' "numbers.Integral"\n' - ' These represent elements from the mathematical set of ' - 'integers\n' - ' (positive and negative).\n' '\n' - ' There are two types of integers:\n' + '"numbers.Integral"\n' + '------------------\n' '\n' - ' Integers ("int")\n' - ' These represent numbers in an unlimited range, subject to\n' - ' available (virtual) memory only. For the purpose of ' - 'shift\n' - ' and mask operations, a binary representation is assumed, ' - 'and\n' - ' negative numbers are represented in a variant of 2’s\n' - ' complement which gives the illusion of an infinite string ' - 'of\n' - ' sign bits extending to the left.\n' + 'These represent elements from the mathematical set of integers\n' + '(positive and negative).\n' '\n' - ' Booleans ("bool")\n' - ' These represent the truth values False and True. The two\n' - ' objects representing the values "False" and "True" are ' - 'the\n' - ' only Boolean objects. The Boolean type is a subtype of ' + 'Note:\n' + '\n' + ' The rules for integer representation are intended to give the ' + 'most\n' + ' meaningful interpretation of shift and mask operations involving\n' + ' negative integers.\n' + '\n' + 'There are two types of integers:\n' + '\n' + 'Integers ("int")\n' + ' These represent numbers in an unlimited range, subject to ' + 'available\n' + ' (virtual) memory only. For the purpose of shift and mask\n' + ' operations, a binary representation is assumed, and negative\n' + ' numbers are represented in a variant of 2’s complement which ' + 'gives\n' + ' the illusion of an infinite string of sign bits extending to ' 'the\n' - ' integer type, and Boolean values behave like the values 0 ' - 'and\n' - ' 1, respectively, in almost all contexts, the exception ' - 'being\n' - ' that when converted to a string, the strings ""False"" or\n' - ' ""True"" are returned, respectively.\n' + ' left.\n' + '\n' + 'Booleans ("bool")\n' + ' These represent the truth values False and True. The two ' + 'objects\n' + ' representing the values "False" and "True" are the only Boolean\n' + ' objects. The Boolean type is a subtype of the integer type, and\n' + ' Boolean values behave like the values 0 and 1, respectively, in\n' + ' almost all contexts, the exception being that when converted to ' + 'a\n' + ' string, the strings ""False"" or ""True"" are returned,\n' + ' respectively.\n' '\n' - ' The rules for integer representation are intended to give ' + '\n' + '"numbers.Real" ("float")\n' + '------------------------\n' + '\n' + 'These represent machine-level double precision floating point ' + 'numbers.\n' + 'You are at the mercy of the underlying machine architecture (and C ' + 'or\n' + 'Java implementation) for the accepted range and handling of ' + 'overflow.\n' + 'Python does not support single-precision floating point numbers; ' 'the\n' - ' most meaningful interpretation of shift and mask operations\n' - ' involving negative integers.\n' - '\n' - ' "numbers.Real" ("float")\n' - ' These represent machine-level double precision floating ' - 'point\n' - ' numbers. You are at the mercy of the underlying machine\n' - ' architecture (and C or Java implementation) for the accepted\n' - ' range and handling of overflow. Python does not support ' - 'single-\n' - ' precision floating point numbers; the savings in processor ' - 'and\n' - ' memory usage that are usually the reason for using these are\n' - ' dwarfed by the overhead of using objects in Python, so there ' - 'is\n' - ' no reason to complicate the language with two kinds of ' - 'floating\n' - ' point numbers.\n' - '\n' - ' "numbers.Complex" ("complex")\n' - ' These represent complex numbers as a pair of machine-level\n' - ' double precision floating point numbers. The same caveats ' - 'apply\n' - ' as for floating point numbers. The real and imaginary parts ' - 'of a\n' - ' complex number "z" can be retrieved through the read-only\n' - ' attributes "z.real" and "z.imag".\n' + 'savings in processor and memory usage that are usually the reason ' + 'for\n' + 'using these are dwarfed by the overhead of using objects in Python, ' + 'so\n' + 'there is no reason to complicate the language with two kinds of\n' + 'floating point numbers.\n' + '\n' + '\n' + '"numbers.Complex" ("complex")\n' + '-----------------------------\n' + '\n' + 'These represent complex numbers as a pair of machine-level double\n' + 'precision floating point numbers. The same caveats apply as for\n' + 'floating point numbers. The real and imaginary parts of a complex\n' + 'number "z" can be retrieved through the read-only attributes ' + '"z.real"\n' + 'and "z.imag".\n' + '\n' '\n' 'Sequences\n' - ' These represent finite ordered sets indexed by non-negative\n' - ' numbers. The built-in function "len()" returns the number of ' - 'items\n' - ' of a sequence. When the length of a sequence is *n*, the index ' + '=========\n' + '\n' + 'These represent finite ordered sets indexed by non-negative ' + 'numbers.\n' + 'The built-in function "len()" returns the number of items of a\n' + 'sequence. When the length of a sequence is *n*, the index set ' + 'contains\n' + 'the numbers 0, 1, …, *n*-1. Item *i* of sequence *a* is selected ' + 'by\n' + '"a[i]".\n' + '\n' + 'Sequences also support slicing: "a[i:j]" selects all items with ' + 'index\n' + '*k* such that *i* "<=" *k* "<" *j*. When used as an expression, a\n' + 'slice is a sequence of the same type. This implies that the index ' 'set\n' - ' contains the numbers 0, 1, …, *n*-1. Item *i* of sequence *a* ' - 'is\n' - ' selected by "a[i]".\n' + 'is renumbered so that it starts at 0.\n' '\n' - ' Sequences also support slicing: "a[i:j]" selects all items with\n' - ' index *k* such that *i* "<=" *k* "<" *j*. When used as an\n' - ' expression, a slice is a sequence of the same type. This ' - 'implies\n' - ' that the index set is renumbered so that it starts at 0.\n' + 'Some sequences also support “extended slicing†with a third “stepâ€\n' + 'parameter: "a[i:j:k]" selects all items of *a* with index *x* where ' + '"x\n' + '= i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n' '\n' - ' Some sequences also support “extended slicing†with a third ' - '“stepâ€\n' - ' parameter: "a[i:j:k]" selects all items of *a* with index *x* ' - 'where\n' - ' "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n' + 'Sequences are distinguished according to their mutability:\n' '\n' - ' Sequences are distinguished according to their mutability:\n' '\n' - ' Immutable sequences\n' - ' An object of an immutable sequence type cannot change once it ' - 'is\n' - ' created. (If the object contains references to other ' - 'objects,\n' - ' these other objects may be mutable and may be changed; ' - 'however,\n' - ' the collection of objects directly referenced by an ' - 'immutable\n' - ' object cannot change.)\n' + 'Immutable sequences\n' + '-------------------\n' '\n' - ' The following types are immutable sequences:\n' + 'An object of an immutable sequence type cannot change once it is\n' + 'created. (If the object contains references to other objects, ' + 'these\n' + 'other objects may be mutable and may be changed; however, the\n' + 'collection of objects directly referenced by an immutable object\n' + 'cannot change.)\n' '\n' - ' Strings\n' - ' A string is a sequence of values that represent Unicode ' - 'code\n' - ' points. All the code points in the range "U+0000 - ' - 'U+10FFFF"\n' - ' can be represented in a string. Python doesn’t have a ' - 'char\n' - ' type; instead, every code point in the string is ' - 'represented\n' - ' as a string object with length "1". The built-in ' - 'function\n' - ' "ord()" converts a code point from its string form to an\n' - ' integer in the range "0 - 10FFFF"; "chr()" converts an\n' - ' integer in the range "0 - 10FFFF" to the corresponding ' - 'length\n' - ' "1" string object. "str.encode()" can be used to convert ' - 'a\n' - ' "str" to "bytes" using the given text encoding, and\n' - ' "bytes.decode()" can be used to achieve the opposite.\n' + 'The following types are immutable sequences:\n' '\n' - ' Tuples\n' - ' The items of a tuple are arbitrary Python objects. Tuples ' - 'of\n' - ' two or more items are formed by comma-separated lists of\n' - ' expressions. A tuple of one item (a ‘singleton’) can be\n' - ' formed by affixing a comma to an expression (an expression ' - 'by\n' - ' itself does not create a tuple, since parentheses must be\n' - ' usable for grouping of expressions). An empty tuple can ' + 'Strings\n' + ' A string is a sequence of values that represent Unicode code\n' + ' points. All the code points in the range "U+0000 - U+10FFFF" can ' 'be\n' - ' formed by an empty pair of parentheses.\n' - '\n' - ' Bytes\n' - ' A bytes object is an immutable array. The items are ' - '8-bit\n' - ' bytes, represented by integers in the range 0 <= x < 256.\n' - ' Bytes literals (like "b\'abc\'") and the built-in ' - '"bytes()"\n' - ' constructor can be used to create bytes objects. Also, ' - 'bytes\n' - ' objects can be decoded to strings via the "decode()" ' - 'method.\n' + ' represented in a string. Python doesn’t have a char type; ' + 'instead,\n' + ' every code point in the string is represented as a string ' + 'object\n' + ' with length "1". The built-in function "ord()" converts a code\n' + ' point from its string form to an integer in the range "0 - ' + '10FFFF";\n' + ' "chr()" converts an integer in the range "0 - 10FFFF" to the\n' + ' corresponding length "1" string object. "str.encode()" can be ' + 'used\n' + ' to convert a "str" to "bytes" using the given text encoding, ' + 'and\n' + ' "bytes.decode()" can be used to achieve the opposite.\n' '\n' - ' Mutable sequences\n' - ' Mutable sequences can be changed after they are created. ' - 'The\n' - ' subscription and slicing notations can be used as the target ' + 'Tuples\n' + ' The items of a tuple are arbitrary Python objects. Tuples of two ' + 'or\n' + ' more items are formed by comma-separated lists of expressions. ' + 'A\n' + ' tuple of one item (a ‘singleton’) can be formed by affixing a ' + 'comma\n' + ' to an expression (an expression by itself does not create a ' + 'tuple,\n' + ' since parentheses must be usable for grouping of expressions). ' + 'An\n' + ' empty tuple can be formed by an empty pair of parentheses.\n' + '\n' + 'Bytes\n' + ' A bytes object is an immutable array. The items are 8-bit ' + 'bytes,\n' + ' represented by integers in the range 0 <= x < 256. Bytes ' + 'literals\n' + ' (like "b\'abc\'") and the built-in "bytes()" constructor can be ' + 'used\n' + ' to create bytes objects. Also, bytes objects can be decoded to\n' + ' strings via the "decode()" method.\n' + '\n' + '\n' + 'Mutable sequences\n' + '-----------------\n' + '\n' + 'Mutable sequences can be changed after they are created. The\n' + 'subscription and slicing notations can be used as the target of\n' + 'assignment and "del" (delete) statements.\n' + '\n' + 'Note:\n' + '\n' + ' The "collections" and "array" module provide additional examples ' 'of\n' - ' assignment and "del" (delete) statements.\n' + ' mutable sequence types.\n' '\n' - ' There are currently two intrinsic mutable sequence types:\n' + 'There are currently two intrinsic mutable sequence types:\n' '\n' - ' Lists\n' - ' The items of a list are arbitrary Python objects. Lists ' - 'are\n' - ' formed by placing a comma-separated list of expressions ' - 'in\n' - ' square brackets. (Note that there are no special cases ' - 'needed\n' - ' to form lists of length 0 or 1.)\n' + 'Lists\n' + ' The items of a list are arbitrary Python objects. Lists are ' + 'formed\n' + ' by placing a comma-separated list of expressions in square\n' + ' brackets. (Note that there are no special cases needed to form\n' + ' lists of length 0 or 1.)\n' '\n' - ' Byte Arrays\n' - ' A bytearray object is a mutable array. They are created ' - 'by\n' - ' the built-in "bytearray()" constructor. Aside from being\n' - ' mutable (and hence unhashable), byte arrays otherwise ' - 'provide\n' - ' the same interface and functionality as immutable "bytes"\n' - ' objects.\n' + 'Byte Arrays\n' + ' A bytearray object is a mutable array. They are created by the\n' + ' built-in "bytearray()" constructor. Aside from being mutable ' + '(and\n' + ' hence unhashable), byte arrays otherwise provide the same ' + 'interface\n' + ' and functionality as immutable "bytes" objects.\n' '\n' - ' The extension module "array" provides an additional example ' - 'of a\n' - ' mutable sequence type, as does the "collections" module.\n' '\n' 'Set types\n' - ' These represent unordered, finite sets of unique, immutable\n' - ' objects. As such, they cannot be indexed by any subscript. ' - 'However,\n' - ' they can be iterated over, and the built-in function "len()"\n' - ' returns the number of items in a set. Common uses for sets are ' - 'fast\n' - ' membership testing, removing duplicates from a sequence, and\n' - ' computing mathematical operations such as intersection, union,\n' - ' difference, and symmetric difference.\n' - '\n' - ' For set elements, the same immutability rules apply as for\n' - ' dictionary keys. Note that numeric types obey the normal rules ' - 'for\n' - ' numeric comparison: if two numbers compare equal (e.g., "1" and\n' - ' "1.0"), only one of them can be contained in a set.\n' + '=========\n' + '\n' + 'These represent unordered, finite sets of unique, immutable ' + 'objects.\n' + 'As such, they cannot be indexed by any subscript. However, they can ' + 'be\n' + 'iterated over, and the built-in function "len()" returns the number ' + 'of\n' + 'items in a set. Common uses for sets are fast membership testing,\n' + 'removing duplicates from a sequence, and computing mathematical\n' + 'operations such as intersection, union, difference, and symmetric\n' + 'difference.\n' + '\n' + 'For set elements, the same immutability rules apply as for ' + 'dictionary\n' + 'keys. Note that numeric types obey the normal rules for numeric\n' + 'comparison: if two numbers compare equal (e.g., "1" and "1.0"), ' + 'only\n' + 'one of them can be contained in a set.\n' '\n' - ' There are currently two intrinsic set types:\n' + 'There are currently two intrinsic set types:\n' '\n' - ' Sets\n' - ' These represent a mutable set. They are created by the ' + 'Sets\n' + ' These represent a mutable set. They are created by the built-in\n' + ' "set()" constructor and can be modified afterwards by several\n' + ' methods, such as "add()".\n' + '\n' + 'Frozen sets\n' + ' These represent an immutable set. They are created by the ' 'built-in\n' - ' "set()" constructor and can be modified afterwards by ' - 'several\n' - ' methods, such as "add()".\n' - '\n' - ' Frozen sets\n' - ' These represent an immutable set. They are created by the\n' - ' built-in "frozenset()" constructor. As a frozenset is ' - 'immutable\n' - ' and *hashable*, it can be used again as an element of ' - 'another\n' - ' set, or as a dictionary key.\n' + ' "frozenset()" constructor. As a frozenset is immutable and\n' + ' *hashable*, it can be used again as an element of another set, ' + 'or\n' + ' as a dictionary key.\n' + '\n' '\n' 'Mappings\n' - ' These represent finite sets of objects indexed by arbitrary ' - 'index\n' - ' sets. The subscript notation "a[k]" selects the item indexed by ' + '========\n' + '\n' + 'These represent finite sets of objects indexed by arbitrary index\n' + 'sets. The subscript notation "a[k]" selects the item indexed by ' '"k"\n' - ' from the mapping "a"; this can be used in expressions and as ' - 'the\n' - ' target of assignments or "del" statements. The built-in ' - 'function\n' - ' "len()" returns the number of items in a mapping.\n' + 'from the mapping "a"; this can be used in expressions and as the\n' + 'target of assignments or "del" statements. The built-in function\n' + '"len()" returns the number of items in a mapping.\n' '\n' - ' There is currently a single intrinsic mapping type:\n' + 'There is currently a single intrinsic mapping type:\n' '\n' - ' Dictionaries\n' - ' These represent finite sets of objects indexed by nearly\n' - ' arbitrary values. The only types of values not acceptable ' - 'as\n' - ' keys are values containing lists or dictionaries or other\n' - ' mutable types that are compared by value rather than by ' - 'object\n' - ' identity, the reason being that the efficient implementation ' - 'of\n' - ' dictionaries requires a key’s hash value to remain constant.\n' - ' Numeric types used for keys obey the normal rules for ' - 'numeric\n' - ' comparison: if two numbers compare equal (e.g., "1" and ' - '"1.0")\n' - ' then they can be used interchangeably to index the same\n' - ' dictionary entry.\n' - '\n' - ' Dictionaries preserve insertion order, meaning that keys will ' - 'be\n' - ' produced in the same order they were added sequentially over ' - 'the\n' - ' dictionary. Replacing an existing key does not change the ' - 'order,\n' - ' however removing a key and re-inserting it will add it to ' + '\n' + 'Dictionaries\n' + '------------\n' + '\n' + 'These represent finite sets of objects indexed by nearly arbitrary\n' + 'values. The only types of values not acceptable as keys are ' + 'values\n' + 'containing lists or dictionaries or other mutable types that are\n' + 'compared by value rather than by object identity, the reason being\n' + 'that the efficient implementation of dictionaries requires a key’s\n' + 'hash value to remain constant. Numeric types used for keys obey ' 'the\n' - ' end instead of keeping its old place.\n' + 'normal rules for numeric comparison: if two numbers compare equal\n' + '(e.g., "1" and "1.0") then they can be used interchangeably to ' + 'index\n' + 'the same dictionary entry.\n' '\n' - ' Dictionaries are mutable; they can be created by the "{...}"\n' - ' notation (see section Dictionary displays).\n' + 'Dictionaries preserve insertion order, meaning that keys will be\n' + 'produced in the same order they were added sequentially over the\n' + 'dictionary. Replacing an existing key does not change the order,\n' + 'however removing a key and re-inserting it will add it to the end\n' + 'instead of keeping its old place.\n' '\n' - ' The extension modules "dbm.ndbm" and "dbm.gnu" provide\n' - ' additional examples of mapping types, as does the ' - '"collections"\n' - ' module.\n' + 'Dictionaries are mutable; they can be created by the "{...}" ' + 'notation\n' + '(see section Dictionary displays).\n' + '\n' + 'The extension modules "dbm.ndbm" and "dbm.gnu" provide additional\n' + 'examples of mapping types, as does the "collections" module.\n' + '\n' + 'Changed in version 3.7: Dictionaries did not preserve insertion ' + 'order\n' + 'in versions of Python before 3.6. In CPython 3.6, insertion order ' + 'was\n' + 'preserved, but it was considered an implementation detail at that ' + 'time\n' + 'rather than a language guarantee.\n' '\n' - ' Changed in version 3.7: Dictionaries did not preserve ' - 'insertion\n' - ' order in versions of Python before 3.6. In CPython 3.6,\n' - ' insertion order was preserved, but it was considered an\n' - ' implementation detail at that time rather than a language\n' - ' guarantee.\n' '\n' 'Callable types\n' - ' These are the types to which the function call operation (see\n' - ' section Calls) can be applied:\n' + '==============\n' + '\n' + 'These are the types to which the function call operation (see ' + 'section\n' + 'Calls) can be applied:\n' '\n' - ' User-defined functions\n' - ' A user-defined function object is created by a function\n' - ' definition (see section Function definitions). It should be\n' - ' called with an argument list containing the same number of ' - 'items\n' - ' as the function’s formal parameter list.\n' '\n' - ' Special attributes:\n' + 'User-defined functions\n' + '----------------------\n' + '\n' + 'A user-defined function object is created by a function definition\n' + '(see section Function definitions). It should be called with an\n' + 'argument list containing the same number of items as the ' + 'function’s\n' + 'formal parameter list.\n' + '\n' + 'Special attributes:\n' '\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | Attribute | Meaning ' + '| Attribute | Meaning ' '| |\n' - ' ' '|===========================|=================================|=============|\n' - ' | "__doc__" | The function’s documentation ' - '| Writable |\n' - ' | | string, or "None" if ' + '| "__doc__" | The function’s documentation | ' + 'Writable |\n' + '| | string, or "None" if ' '| |\n' - ' | | unavailable; not inherited by ' + '| | unavailable; not inherited by ' '| |\n' - ' | | subclasses. ' + '| | subclasses. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__name__" | The function’s name. ' - '| Writable |\n' - ' ' + '| "__name__" | The function’s name. | ' + 'Writable |\n' '+---------------------------+---------------------------------+-------------+\n' - ' | "__qualname__" | The function’s *qualified ' - '| Writable |\n' - ' | | name*. New in version 3.3. ' + '| "__qualname__" | The function’s *qualified | ' + 'Writable |\n' + '| | name*. New in version 3.3. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__module__" | The name of the module the ' - '| Writable |\n' - ' | | function was defined in, or ' + '| "__module__" | The name of the module the | ' + 'Writable |\n' + '| | function was defined in, or ' '| |\n' - ' | | "None" if unavailable. ' + '| | "None" if unavailable. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__defaults__" | A tuple containing default ' - '| Writable |\n' - ' | | argument values for those ' + '| "__defaults__" | A tuple containing default | ' + 'Writable |\n' + '| | argument values for those ' '| |\n' - ' | | arguments that have defaults, ' + '| | arguments that have defaults, ' '| |\n' - ' | | or "None" if no arguments have ' + '| | or "None" if no arguments have ' '| |\n' - ' | | a default value. ' + '| | a default value. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__code__" | The code object representing ' - '| Writable |\n' - ' | | the compiled function body. ' + '| "__code__" | The code object representing | ' + 'Writable |\n' + '| | the compiled function body. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__globals__" | A reference to the dictionary ' - '| Read-only |\n' - ' | | that holds the function’s ' + '| "__globals__" | A reference to the dictionary | ' + 'Read-only |\n' + '| | that holds the function’s ' '| |\n' - ' | | global variables — the global ' + '| | global variables — the global ' '| |\n' - ' | | namespace of the module in ' + '| | namespace of the module in ' '| |\n' - ' | | which the function was defined. ' + '| | which the function was defined. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__dict__" | The namespace supporting ' - '| Writable |\n' - ' | | arbitrary function attributes. ' + '| "__dict__" | The namespace supporting | ' + 'Writable |\n' + '| | arbitrary function attributes. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__closure__" | "None" or a tuple of cells that ' - '| Read-only |\n' - ' | | contain bindings for the ' + '| "__closure__" | "None" or a tuple of cells that | ' + 'Read-only |\n' + '| | contain bindings for the ' '| |\n' - ' | | function’s free variables. See ' + '| | function’s free variables. See ' '| |\n' - ' | | below for information on the ' + '| | below for information on the ' '| |\n' - ' | | "cell_contents" attribute. ' + '| | "cell_contents" attribute. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__annotations__" | A dict containing annotations ' - '| Writable |\n' - ' | | of parameters. The keys of the ' + '| "__annotations__" | A dict containing annotations | ' + 'Writable |\n' + '| | of parameters. The keys of the ' + '| |\n' + '| | dict are the parameter names, ' '| |\n' - ' | | dict are the parameter names, ' + '| | and "\'return\'" for the return ' '| |\n' - ' | | and "\'return\'" for the ' - 'return | |\n' - ' | | annotation, if provided. For ' + '| | annotation, if provided. For ' '| |\n' - ' | | more information on working ' + '| | more information on working ' '| |\n' - ' | | with this attribute, see ' + '| | with this attribute, see ' '| |\n' - ' | | Annotations Best Practices. ' + '| | Annotations Best Practices. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__kwdefaults__" | A dict containing defaults for ' - '| Writable |\n' - ' | | keyword-only parameters. ' + '| "__kwdefaults__" | A dict containing defaults for | ' + 'Writable |\n' + '| | keyword-only parameters. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' - ' | "__type_params__" | A tuple containing the type ' - '| Writable |\n' - ' | | parameters of a generic ' + '| "__type_params__" | A tuple containing the type | ' + 'Writable |\n' + '| | parameters of a generic ' '| |\n' - ' | | function. ' + '| | function. ' '| |\n' - ' ' '+---------------------------+---------------------------------+-------------+\n' '\n' - ' Most of the attributes labelled “Writable†check the type of ' - 'the\n' - ' assigned value.\n' + 'Most of the attributes labelled “Writable†check the type of the\n' + 'assigned value.\n' '\n' - ' Function objects also support getting and setting arbitrary\n' - ' attributes, which can be used, for example, to attach ' - 'metadata\n' - ' to functions. Regular attribute dot-notation is used to get ' - 'and\n' - ' set such attributes. *Note that the current implementation ' - 'only\n' - ' supports function attributes on user-defined functions. ' - 'Function\n' - ' attributes on built-in functions may be supported in the\n' - ' future.*\n' - '\n' - ' A cell object has the attribute "cell_contents". This can be\n' - ' used to get the value of the cell, as well as set the value.\n' - '\n' - ' Additional information about a function’s definition can be\n' - ' retrieved from its code object; see the description of ' - 'internal\n' - ' types below. The "cell" type can be accessed in the "types"\n' - ' module.\n' - '\n' - ' Instance methods\n' - ' An instance method object combines a class, a class instance ' - 'and\n' - ' any callable object (normally a user-defined function).\n' - '\n' - ' Special read-only attributes: "__self__" is the class ' - 'instance\n' - ' object, "__func__" is the function object; "__doc__" is the\n' - ' method’s documentation (same as "__func__.__doc__"); ' - '"__name__"\n' - ' is the method name (same as "__func__.__name__"); ' - '"__module__"\n' - ' is the name of the module the method was defined in, or ' - '"None"\n' - ' if unavailable.\n' + 'Function objects also support getting and setting arbitrary\n' + 'attributes, which can be used, for example, to attach metadata to\n' + 'functions. Regular attribute dot-notation is used to get and set ' + 'such\n' + 'attributes. *Note that the current implementation only supports\n' + 'function attributes on user-defined functions. Function attributes ' + 'on\n' + 'built-in functions may be supported in the future.*\n' '\n' - ' Methods also support accessing (but not setting) the ' - 'arbitrary\n' - ' function attributes on the underlying function object.\n' + 'A cell object has the attribute "cell_contents". This can be used ' + 'to\n' + 'get the value of the cell, as well as set the value.\n' '\n' - ' User-defined method objects may be created when getting an\n' - ' attribute of a class (perhaps via an instance of that class), ' - 'if\n' - ' that attribute is a user-defined function object or a class\n' - ' method object.\n' - '\n' - ' When an instance method object is created by retrieving a ' - 'user-\n' - ' defined function object from a class via one of its ' - 'instances,\n' - ' its "__self__" attribute is the instance, and the method ' - 'object\n' - ' is said to be bound. The new method’s "__func__" attribute ' - 'is\n' - ' the original function object.\n' + 'Additional information about a function’s definition can be ' + 'retrieved\n' + 'from its code object; see the description of internal types below. ' + 'The\n' + '"cell" type can be accessed in the "types" module.\n' '\n' - ' When an instance method object is created by retrieving a ' - 'class\n' - ' method object from a class or instance, its "__self__" ' - 'attribute\n' - ' is the class itself, and its "__func__" attribute is the\n' - ' function object underlying the class method.\n' '\n' - ' When an instance method object is called, the underlying\n' - ' function ("__func__") is called, inserting the class ' - 'instance\n' - ' ("__self__") in front of the argument list. For instance, ' - 'when\n' - ' "C" is a class which contains a definition for a function ' - '"f()",\n' - ' and "x" is an instance of "C", calling "x.f(1)" is equivalent ' - 'to\n' - ' calling "C.f(x, 1)".\n' + 'Instance methods\n' + '----------------\n' '\n' - ' When an instance method object is derived from a class ' + 'An instance method object combines a class, a class instance and ' + 'any\n' + 'callable object (normally a user-defined function).\n' + '\n' + 'Special read-only attributes: "__self__" is the class instance ' + 'object,\n' + '"__func__" is the function object; "__doc__" is the method’s\n' + 'documentation (same as "__func__.__doc__"); "__name__" is the ' 'method\n' - ' object, the “class instance†stored in "__self__" will ' - 'actually\n' - ' be the class itself, so that calling either "x.f(1)" or ' - '"C.f(1)"\n' - ' is equivalent to calling "f(C,1)" where "f" is the ' - 'underlying\n' - ' function.\n' - '\n' - ' Note that the transformation from function object to ' - 'instance\n' - ' method object happens each time the attribute is retrieved ' - 'from\n' - ' the instance. In some cases, a fruitful optimization is to\n' - ' assign the attribute to a local variable and call that local\n' - ' variable. Also notice that this transformation only happens ' - 'for\n' - ' user-defined functions; other callable objects (and all non-\n' - ' callable objects) are retrieved without transformation. It ' - 'is\n' - ' also important to note that user-defined functions which are\n' - ' attributes of a class instance are not converted to bound\n' - ' methods; this *only* happens when the function is an ' + 'name (same as "__func__.__name__"); "__module__" is the name of ' + 'the\n' + 'module the method was defined in, or "None" if unavailable.\n' + '\n' + 'Methods also support accessing (but not setting) the arbitrary\n' + 'function attributes on the underlying function object.\n' + '\n' + 'User-defined method objects may be created when getting an ' + 'attribute\n' + 'of a class (perhaps via an instance of that class), if that ' 'attribute\n' - ' of the class.\n' + 'is a user-defined function object or a class method object.\n' '\n' - ' Generator functions\n' - ' A function or method which uses the "yield" statement (see\n' - ' section The yield statement) is called a *generator ' - 'function*.\n' - ' Such a function, when called, always returns an *iterator*\n' - ' object which can be used to execute the body of the ' - 'function:\n' - ' calling the iterator’s "iterator.__next__()" method will ' - 'cause\n' - ' the function to execute until it provides a value using the\n' - ' "yield" statement. When the function executes a "return"\n' - ' statement or falls off the end, a "StopIteration" exception ' - 'is\n' - ' raised and the iterator will have reached the end of the set ' + 'When an instance method object is created by retrieving a ' + 'user-defined\n' + 'function object from a class via one of its instances, its ' + '"__self__"\n' + 'attribute is the instance, and the method object is said to be ' + 'bound.\n' + 'The new method’s "__func__" attribute is the original function ' + 'object.\n' + '\n' + 'When an instance method object is created by retrieving a class ' + 'method\n' + 'object from a class or instance, its "__self__" attribute is the ' + 'class\n' + 'itself, and its "__func__" attribute is the function object ' + 'underlying\n' + 'the class method.\n' + '\n' + 'When an instance method object is called, the underlying function\n' + '("__func__") is called, inserting the class instance ("__self__") ' + 'in\n' + 'front of the argument list. For instance, when "C" is a class ' + 'which\n' + 'contains a definition for a function "f()", and "x" is an instance ' 'of\n' - ' values to be returned.\n' - '\n' - ' Coroutine functions\n' - ' A function or method which is defined using "async def" is\n' - ' called a *coroutine function*. Such a function, when ' - 'called,\n' - ' returns a *coroutine* object. It may contain "await"\n' - ' expressions, as well as "async with" and "async for" ' - 'statements.\n' - ' See also the Coroutine Objects section.\n' - '\n' - ' Asynchronous generator functions\n' - ' A function or method which is defined using "async def" and\n' - ' which uses the "yield" statement is called a *asynchronous\n' - ' generator function*. Such a function, when called, returns ' - 'an\n' - ' *asynchronous iterator* object which can be used in an ' - '"async\n' - ' for" statement to execute the body of the function.\n' + '"C", calling "x.f(1)" is equivalent to calling "C.f(x, 1)".\n' '\n' - ' Calling the asynchronous iterator’s "aiterator.__anext__" ' + 'When an instance method object is derived from a class method ' + 'object,\n' + 'the “class instance†stored in "__self__" will actually be the ' + 'class\n' + 'itself, so that calling either "x.f(1)" or "C.f(1)" is equivalent ' + 'to\n' + 'calling "f(C,1)" where "f" is the underlying function.\n' + '\n' + 'Note that the transformation from function object to instance ' 'method\n' - ' will return an *awaitable* which when awaited will execute ' + 'object happens each time the attribute is retrieved from the ' + 'instance.\n' + 'In some cases, a fruitful optimization is to assign the attribute ' + 'to a\n' + 'local variable and call that local variable. Also notice that this\n' + 'transformation only happens for user-defined functions; other ' + 'callable\n' + 'objects (and all non-callable objects) are retrieved without\n' + 'transformation. It is also important to note that user-defined\n' + 'functions which are attributes of a class instance are not ' + 'converted\n' + 'to bound methods; this *only* happens when the function is an\n' + 'attribute of the class.\n' + '\n' + '\n' + 'Generator functions\n' + '-------------------\n' + '\n' + 'A function or method which uses the "yield" statement (see section ' + 'The\n' + 'yield statement) is called a *generator function*. Such a ' + 'function,\n' + 'when called, always returns an *iterator* object which can be used ' + 'to\n' + 'execute the body of the function: calling the iterator’s\n' + '"iterator.__next__()" method will cause the function to execute ' 'until\n' - ' it provides a value using the "yield" expression. When the\n' - ' function executes an empty "return" statement or falls off ' + 'it provides a value using the "yield" statement. When the ' + 'function\n' + 'executes a "return" statement or falls off the end, a ' + '"StopIteration"\n' + 'exception is raised and the iterator will have reached the end of ' 'the\n' - ' end, a "StopAsyncIteration" exception is raised and the\n' - ' asynchronous iterator will have reached the end of the set ' - 'of\n' - ' values to be yielded.\n' + 'set of values to be returned.\n' '\n' - ' Built-in functions\n' - ' A built-in function object is a wrapper around a C function.\n' - ' Examples of built-in functions are "len()" and "math.sin()"\n' - ' ("math" is a standard built-in module). The number and type ' - 'of\n' - ' the arguments are determined by the C function. Special ' - 'read-\n' - ' only attributes: "__doc__" is the function’s documentation\n' - ' string, or "None" if unavailable; "__name__" is the ' - 'function’s\n' - ' name; "__self__" is set to "None" (but see the next item);\n' - ' "__module__" is the name of the module the function was ' - 'defined\n' - ' in or "None" if unavailable.\n' '\n' - ' Built-in methods\n' - ' This is really a different disguise of a built-in function, ' - 'this\n' - ' time containing an object passed to the C function as an\n' - ' implicit extra argument. An example of a built-in method is\n' - ' "alist.append()", assuming *alist* is a list object. In this\n' - ' case, the special read-only attribute "__self__" is set to ' + 'Coroutine functions\n' + '-------------------\n' + '\n' + 'A function or method which is defined using "async def" is called ' + 'a\n' + '*coroutine function*. Such a function, when called, returns a\n' + '*coroutine* object. It may contain "await" expressions, as well ' + 'as\n' + '"async with" and "async for" statements. See also the Coroutine\n' + 'Objects section.\n' + '\n' + '\n' + 'Asynchronous generator functions\n' + '--------------------------------\n' + '\n' + 'A function or method which is defined using "async def" and which ' + 'uses\n' + 'the "yield" statement is called a *asynchronous generator ' + 'function*.\n' + 'Such a function, when called, returns an *asynchronous iterator*\n' + 'object which can be used in an "async for" statement to execute ' 'the\n' - ' object denoted by *alist*.\n' + 'body of the function.\n' '\n' - ' Classes\n' - ' Classes are callable. These objects normally act as ' - 'factories\n' - ' for new instances of themselves, but variations are possible ' - 'for\n' - ' class types that override "__new__()". The arguments of the\n' - ' call are passed to "__new__()" and, in the typical case, to\n' - ' "__init__()" to initialize the new instance.\n' + 'Calling the asynchronous iterator’s "aiterator.__anext__" method ' + 'will\n' + 'return an *awaitable* which when awaited will execute until it\n' + 'provides a value using the "yield" expression. When the function\n' + 'executes an empty "return" statement or falls off the end, a\n' + '"StopAsyncIteration" exception is raised and the asynchronous ' + 'iterator\n' + 'will have reached the end of the set of values to be yielded.\n' + '\n' + '\n' + 'Built-in functions\n' + '------------------\n' + '\n' + 'A built-in function object is a wrapper around a C function. ' + 'Examples\n' + 'of built-in functions are "len()" and "math.sin()" ("math" is a\n' + 'standard built-in module). The number and type of the arguments ' + 'are\n' + 'determined by the C function. Special read-only attributes: ' + '"__doc__"\n' + 'is the function’s documentation string, or "None" if unavailable;\n' + '"__name__" is the function’s name; "__self__" is set to "None" ' + '(but\n' + 'see the next item); "__module__" is the name of the module the\n' + 'function was defined in or "None" if unavailable.\n' + '\n' + '\n' + 'Built-in methods\n' + '----------------\n' + '\n' + 'This is really a different disguise of a built-in function, this ' + 'time\n' + 'containing an object passed to the C function as an implicit extra\n' + 'argument. An example of a built-in method is "alist.append()",\n' + 'assuming *alist* is a list object. In this case, the special ' + 'read-only\n' + 'attribute "__self__" is set to the object denoted by *alist*.\n' + '\n' + '\n' + 'Classes\n' + '-------\n' + '\n' + 'Classes are callable. These objects normally act as factories for ' + 'new\n' + 'instances of themselves, but variations are possible for class ' + 'types\n' + 'that override "__new__()". The arguments of the call are passed ' + 'to\n' + '"__new__()" and, in the typical case, to "__init__()" to ' + 'initialize\n' + 'the new instance.\n' + '\n' + '\n' + 'Class Instances\n' + '---------------\n' + '\n' + 'Instances of arbitrary classes can be made callable by defining a\n' + '"__call__()" method in their class.\n' '\n' - ' Class Instances\n' - ' Instances of arbitrary classes can be made callable by ' - 'defining\n' - ' a "__call__()" method in their class.\n' '\n' 'Modules\n' - ' Modules are a basic organizational unit of Python code, and are\n' - ' created by the import system as invoked either by the "import"\n' - ' statement, or by calling functions such as\n' - ' "importlib.import_module()" and built-in "__import__()". A ' - 'module\n' - ' object has a namespace implemented by a dictionary object (this ' - 'is\n' - ' the dictionary referenced by the "__globals__" attribute of\n' - ' functions defined in the module). Attribute references are\n' - ' translated to lookups in this dictionary, e.g., "m.x" is ' - 'equivalent\n' - ' to "m.__dict__["x"]". A module object does not contain the code\n' - ' object used to initialize the module (since it isn’t needed ' - 'once\n' - ' the initialization is done).\n' + '=======\n' + '\n' + 'Modules are a basic organizational unit of Python code, and are\n' + 'created by the import system as invoked either by the "import"\n' + 'statement, or by calling functions such as ' + '"importlib.import_module()"\n' + 'and built-in "__import__()". A module object has a namespace\n' + 'implemented by a dictionary object (this is the dictionary ' + 'referenced\n' + 'by the "__globals__" attribute of functions defined in the ' + 'module).\n' + 'Attribute references are translated to lookups in this dictionary,\n' + 'e.g., "m.x" is equivalent to "m.__dict__["x"]". A module object ' + 'does\n' + 'not contain the code object used to initialize the module (since ' + 'it\n' + 'isn’t needed once the initialization is done).\n' + '\n' + 'Attribute assignment updates the module’s namespace dictionary, ' + 'e.g.,\n' + '"m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n' '\n' - ' Attribute assignment updates the module’s namespace dictionary,\n' - ' e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n' + 'Predefined (writable) attributes:\n' '\n' - ' Predefined (writable) attributes:\n' + ' "__name__"\n' + ' The module’s name.\n' '\n' - ' "__name__"\n' - ' The module’s name.\n' + ' "__doc__"\n' + ' The module’s documentation string, or "None" if unavailable.\n' '\n' - ' "__doc__"\n' - ' The module’s documentation string, or "None" if ' - 'unavailable.\n' + ' "__file__"\n' + ' The pathname of the file from which the module was loaded, if ' + 'it\n' + ' was loaded from a file. The "__file__" attribute may be ' + 'missing\n' + ' for certain types of modules, such as C modules that are\n' + ' statically linked into the interpreter. For extension ' + 'modules\n' + ' loaded dynamically from a shared library, it’s the pathname ' + 'of\n' + ' the shared library file.\n' '\n' - ' "__file__"\n' - ' The pathname of the file from which the module was loaded, ' - 'if\n' - ' it was loaded from a file. The "__file__" attribute may ' - 'be\n' - ' missing for certain types of modules, such as C modules ' - 'that\n' - ' are statically linked into the interpreter. For ' - 'extension\n' - ' modules loaded dynamically from a shared library, it’s ' - 'the\n' - ' pathname of the shared library file.\n' - '\n' - ' "__annotations__"\n' - ' A dictionary containing *variable annotations* collected\n' - ' during module body execution. For best practices on ' - 'working\n' - ' with "__annotations__", please see Annotations Best\n' - ' Practices.\n' - '\n' - ' Special read-only attribute: "__dict__" is the module’s ' - 'namespace\n' - ' as a dictionary object.\n' - '\n' - ' **CPython implementation detail:** Because of the way CPython\n' - ' clears module dictionaries, the module dictionary will be ' - 'cleared\n' - ' when the module falls out of scope even if the dictionary still ' - 'has\n' - ' live references. To avoid this, copy the dictionary or keep ' + ' "__annotations__"\n' + ' A dictionary containing *variable annotations* collected ' + 'during\n' + ' module body execution. For best practices on working with\n' + ' "__annotations__", please see Annotations Best Practices.\n' + '\n' + 'Special read-only attribute: "__dict__" is the module’s namespace ' + 'as a\n' + 'dictionary object.\n' + '\n' + '**CPython implementation detail:** Because of the way CPython ' + 'clears\n' + 'module dictionaries, the module dictionary will be cleared when ' 'the\n' - ' module around while using its dictionary directly.\n' + 'module falls out of scope even if the dictionary still has live\n' + 'references. To avoid this, copy the dictionary or keep the module\n' + 'around while using its dictionary directly.\n' + '\n' '\n' 'Custom classes\n' - ' Custom class types are typically created by class definitions ' - '(see\n' - ' section Class definitions). A class has a namespace implemented ' - 'by\n' - ' a dictionary object. Class attribute references are translated ' - 'to\n' - ' lookups in this dictionary, e.g., "C.x" is translated to\n' - ' "C.__dict__["x"]" (although there are a number of hooks which ' + '==============\n' + '\n' + 'Custom class types are typically created by class definitions (see\n' + 'section Class definitions). A class has a namespace implemented by ' + 'a\n' + 'dictionary object. Class attribute references are translated to\n' + 'lookups in this dictionary, e.g., "C.x" is translated to\n' + '"C.__dict__["x"]" (although there are a number of hooks which ' 'allow\n' - ' for other means of locating attributes). When the attribute name ' + 'for other means of locating attributes). When the attribute name ' 'is\n' - ' not found there, the attribute search continues in the base\n' - ' classes. This search of the base classes uses the C3 method\n' - ' resolution order which behaves correctly even in the presence ' - 'of\n' - ' ‘diamond’ inheritance structures where there are multiple\n' - ' inheritance paths leading back to a common ancestor. Additional\n' - ' details on the C3 MRO used by Python can be found in the\n' - ' documentation accompanying the 2.3 release at\n' - ' https://www.python.org/download/releases/2.3/mro/.\n' - '\n' - ' When a class attribute reference (for class "C", say) would ' - 'yield a\n' - ' class method object, it is transformed into an instance method\n' - ' object whose "__self__" attribute is "C". When it would yield ' + 'not found there, the attribute search continues in the base ' + 'classes.\n' + 'This search of the base classes uses the C3 method resolution ' + 'order\n' + 'which behaves correctly even in the presence of ‘diamond’ ' + 'inheritance\n' + 'structures where there are multiple inheritance paths leading back ' + 'to\n' + 'a common ancestor. Additional details on the C3 MRO used by Python ' + 'can\n' + 'be found in the documentation accompanying the 2.3 release at\n' + 'https://www.python.org/download/releases/2.3/mro/.\n' + '\n' + 'When a class attribute reference (for class "C", say) would yield ' 'a\n' - ' static method object, it is transformed into the object wrapped ' - 'by\n' - ' the static method object. See section Implementing Descriptors ' - 'for\n' - ' another way in which attributes retrieved from a class may ' - 'differ\n' - ' from those actually contained in its "__dict__".\n' + 'class method object, it is transformed into an instance method ' + 'object\n' + 'whose "__self__" attribute is "C". When it would yield a static\n' + 'method object, it is transformed into the object wrapped by the ' + 'static\n' + 'method object. See section Implementing Descriptors for another way ' + 'in\n' + 'which attributes retrieved from a class may differ from those ' + 'actually\n' + 'contained in its "__dict__".\n' '\n' - ' Class attribute assignments update the class’s dictionary, ' - 'never\n' - ' the dictionary of a base class.\n' + 'Class attribute assignments update the class’s dictionary, never ' + 'the\n' + 'dictionary of a base class.\n' '\n' - ' A class object can be called (see above) to yield a class ' - 'instance\n' - ' (see below).\n' + 'A class object can be called (see above) to yield a class instance\n' + '(see below).\n' '\n' - ' Special attributes:\n' + 'Special attributes:\n' '\n' - ' "__name__"\n' - ' The class name.\n' + ' "__name__"\n' + ' The class name.\n' '\n' - ' "__module__"\n' - ' The name of the module in which the class was defined.\n' + ' "__module__"\n' + ' The name of the module in which the class was defined.\n' '\n' - ' "__dict__"\n' - ' The dictionary containing the class’s namespace.\n' + ' "__dict__"\n' + ' The dictionary containing the class’s namespace.\n' '\n' - ' "__bases__"\n' - ' A tuple containing the base classes, in the order of ' - 'their\n' - ' occurrence in the base class list.\n' + ' "__bases__"\n' + ' A tuple containing the base classes, in the order of their\n' + ' occurrence in the base class list.\n' '\n' - ' "__doc__"\n' - ' The class’s documentation string, or "None" if undefined.\n' + ' "__doc__"\n' + ' The class’s documentation string, or "None" if undefined.\n' '\n' - ' "__annotations__"\n' - ' A dictionary containing *variable annotations* collected\n' - ' during class body execution. For best practices on ' - 'working\n' - ' with "__annotations__", please see Annotations Best\n' - ' Practices.\n' + ' "__annotations__"\n' + ' A dictionary containing *variable annotations* collected ' + 'during\n' + ' class body execution. For best practices on working with\n' + ' "__annotations__", please see Annotations Best Practices.\n' + '\n' + ' "__type_params__"\n' + ' A tuple containing the type parameters of a generic class.\n' '\n' - ' "__type_params__"\n' - ' A tuple containing the type parameters of a generic ' - 'class.\n' '\n' 'Class instances\n' - ' A class instance is created by calling a class object (see ' - 'above).\n' - ' A class instance has a namespace implemented as a dictionary ' - 'which\n' - ' is the first place in which attribute references are searched.\n' - ' When an attribute is not found there, and the instance’s class ' - 'has\n' - ' an attribute by that name, the search continues with the class\n' - ' attributes. If a class attribute is found that is a ' - 'user-defined\n' - ' function object, it is transformed into an instance method ' - 'object\n' - ' whose "__self__" attribute is the instance. Static method and\n' - ' class method objects are also transformed; see above under\n' - ' “Classesâ€. See section Implementing Descriptors for another way ' - 'in\n' - ' which attributes of a class retrieved via its instances may ' - 'differ\n' - ' from the objects actually stored in the class’s "__dict__". If ' - 'no\n' - ' class attribute is found, and the object’s class has a\n' - ' "__getattr__()" method, that is called to satisfy the lookup.\n' + '===============\n' '\n' - ' Attribute assignments and deletions update the instance’s\n' - ' dictionary, never a class’s dictionary. If the class has a\n' - ' "__setattr__()" or "__delattr__()" method, this is called ' - 'instead\n' - ' of updating the instance dictionary directly.\n' + 'A class instance is created by calling a class object (see above). ' + 'A\n' + 'class instance has a namespace implemented as a dictionary which ' + 'is\n' + 'the first place in which attribute references are searched. When ' + 'an\n' + 'attribute is not found there, and the instance’s class has an\n' + 'attribute by that name, the search continues with the class\n' + 'attributes. If a class attribute is found that is a user-defined\n' + 'function object, it is transformed into an instance method object\n' + 'whose "__self__" attribute is the instance. Static method and ' + 'class\n' + 'method objects are also transformed; see above under “Classesâ€. ' + 'See\n' + 'section Implementing Descriptors for another way in which ' + 'attributes\n' + 'of a class retrieved via its instances may differ from the objects\n' + 'actually stored in the class’s "__dict__". If no class attribute ' + 'is\n' + 'found, and the object’s class has a "__getattr__()" method, that ' + 'is\n' + 'called to satisfy the lookup.\n' '\n' - ' Class instances can pretend to be numbers, sequences, or ' - 'mappings\n' - ' if they have methods with certain special names. See section\n' - ' Special method names.\n' + 'Attribute assignments and deletions update the instance’s ' + 'dictionary,\n' + 'never a class’s dictionary. If the class has a "__setattr__()" or\n' + '"__delattr__()" method, this is called instead of updating the\n' + 'instance dictionary directly.\n' + '\n' + 'Class instances can pretend to be numbers, sequences, or mappings ' + 'if\n' + 'they have methods with certain special names. See section Special\n' + 'method names.\n' + '\n' + 'Special attributes: "__dict__" is the attribute dictionary;\n' + '"__class__" is the instance’s class.\n' '\n' - ' Special attributes: "__dict__" is the attribute dictionary;\n' - ' "__class__" is the instance’s class.\n' '\n' 'I/O objects (also known as file objects)\n' - ' A *file object* represents an open file. Various shortcuts are\n' - ' available to create file objects: the "open()" built-in ' - 'function,\n' - ' and also "os.popen()", "os.fdopen()", and the "makefile()" ' - 'method\n' - ' of socket objects (and perhaps by other functions or methods\n' - ' provided by extension modules).\n' + '========================================\n' + '\n' + 'A *file object* represents an open file. Various shortcuts are\n' + 'available to create file objects: the "open()" built-in function, ' + 'and\n' + 'also "os.popen()", "os.fdopen()", and the "makefile()" method of\n' + 'socket objects (and perhaps by other functions or methods provided ' + 'by\n' + 'extension modules).\n' + '\n' + 'The objects "sys.stdin", "sys.stdout" and "sys.stderr" are ' + 'initialized\n' + 'to file objects corresponding to the interpreter’s standard input,\n' + 'output and error streams; they are all open in text mode and ' + 'therefore\n' + 'follow the interface defined by the "io.TextIOBase" abstract ' + 'class.\n' '\n' - ' The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n' - ' initialized to file objects corresponding to the interpreter’s\n' - ' standard input, output and error streams; they are all open in ' - 'text\n' - ' mode and therefore follow the interface defined by the\n' - ' "io.TextIOBase" abstract class.\n' '\n' 'Internal types\n' - ' A few types used internally by the interpreter are exposed to ' - 'the\n' - ' user. Their definitions may change with future versions of the\n' - ' interpreter, but they are mentioned here for completeness.\n' - '\n' - ' Code objects\n' - ' Code objects represent *byte-compiled* executable Python ' - 'code,\n' - ' or *bytecode*. The difference between a code object and a\n' - ' function object is that the function object contains an ' - 'explicit\n' - ' reference to the function’s globals (the module in which it ' - 'was\n' - ' defined), while a code object contains no context; also the\n' - ' default argument values are stored in the function object, ' - 'not\n' - ' in the code object (because they represent values calculated ' - 'at\n' - ' run-time). Unlike function objects, code objects are ' - 'immutable\n' - ' and contain no references (directly or indirectly) to ' - 'mutable\n' - ' objects.\n' - '\n' - ' Special read-only attributes: "co_name" gives the function ' - 'name;\n' - ' "co_qualname" gives the fully qualified function name;\n' - ' "co_argcount" is the total number of positional arguments\n' - ' (including positional-only arguments and arguments with ' - 'default\n' - ' values); "co_posonlyargcount" is the number of ' - 'positional-only\n' - ' arguments (including arguments with default values);\n' - ' "co_kwonlyargcount" is the number of keyword-only arguments\n' - ' (including arguments with default values); "co_nlocals" is ' - 'the\n' - ' number of local variables used by the function (including\n' - ' arguments); "co_varnames" is a tuple containing the names of ' - 'the\n' - ' local variables (starting with the argument names);\n' - ' "co_cellvars" is a tuple containing the names of local ' - 'variables\n' - ' that are referenced by nested functions; "co_freevars" is a\n' - ' tuple containing the names of free variables; "co_code" is a\n' - ' string representing the sequence of bytecode instructions;\n' - ' "co_consts" is a tuple containing the literals used by the\n' - ' bytecode; "co_names" is a tuple containing the names used by ' - 'the\n' - ' bytecode; "co_filename" is the filename from which the code ' - 'was\n' - ' compiled; "co_firstlineno" is the first line number of the\n' - ' function; "co_lnotab" is a string encoding the mapping from\n' - ' bytecode offsets to line numbers (for details see the source\n' - ' code of the interpreter, is deprecated since 3.12 and may be\n' - ' removed in 3.14); "co_stacksize" is the required stack size;\n' - ' "co_flags" is an integer encoding a number of flags for the\n' - ' interpreter.\n' - '\n' - ' The following flag bits are defined for "co_flags": bit ' - '"0x04"\n' - ' is set if the function uses the "*arguments" syntax to accept ' - 'an\n' - ' arbitrary number of positional arguments; bit "0x08" is set ' - 'if\n' - ' the function uses the "**keywords" syntax to accept ' - 'arbitrary\n' - ' keyword arguments; bit "0x20" is set if the function is a\n' - ' generator.\n' + '==============\n' '\n' - ' Future feature declarations ("from __future__ import ' - 'division")\n' - ' also use bits in "co_flags" to indicate whether a code ' + 'A few types used internally by the interpreter are exposed to the\n' + 'user. Their definitions may change with future versions of the\n' + 'interpreter, but they are mentioned here for completeness.\n' + '\n' + '\n' + 'Code objects\n' + '------------\n' + '\n' + 'Code objects represent *byte-compiled* executable Python code, or\n' + '*bytecode*. The difference between a code object and a function ' 'object\n' - ' was compiled with a particular feature enabled: bit "0x2000" ' + 'is that the function object contains an explicit reference to the\n' + 'function’s globals (the module in which it was defined), while a ' + 'code\n' + 'object contains no context; also the default argument values are\n' + 'stored in the function object, not in the code object (because ' + 'they\n' + 'represent values calculated at run-time). Unlike function ' + 'objects,\n' + 'code objects are immutable and contain no references (directly or\n' + 'indirectly) to mutable objects.\n' + '\n' + 'Special read-only attributes: "co_name" gives the function name;\n' + '"co_qualname" gives the fully qualified function name; ' + '"co_argcount"\n' + 'is the total number of positional arguments (including ' + 'positional-only\n' + 'arguments and arguments with default values); "co_posonlyargcount" ' + 'is\n' + 'the number of positional-only arguments (including arguments with\n' + 'default values); "co_kwonlyargcount" is the number of keyword-only\n' + 'arguments (including arguments with default values); "co_nlocals" ' 'is\n' - ' set if the function was compiled with future division ' - 'enabled;\n' - ' bits "0x10" and "0x1000" were used in earlier versions of\n' - ' Python.\n' + 'the number of local variables used by the function (including\n' + 'arguments); "co_varnames" is a tuple containing the names of the ' + 'local\n' + 'variables (starting with the argument names); "co_cellvars" is a ' + 'tuple\n' + 'containing the names of local variables that are referenced by ' + 'nested\n' + 'functions; "co_freevars" is a tuple containing the names of free\n' + 'variables; "co_code" is a string representing the sequence of ' + 'bytecode\n' + 'instructions; "co_consts" is a tuple containing the literals used ' + 'by\n' + 'the bytecode; "co_names" is a tuple containing the names used by ' + 'the\n' + 'bytecode; "co_filename" is the filename from which the code was\n' + 'compiled; "co_firstlineno" is the first line number of the ' + 'function;\n' + '"co_lnotab" is a string encoding the mapping from bytecode offsets ' + 'to\n' + 'line numbers (for details see the source code of the interpreter, ' + 'is\n' + 'deprecated since 3.12 and may be removed in 3.14); "co_stacksize" ' + 'is\n' + 'the required stack size; "co_flags" is an integer encoding a number ' + 'of\n' + 'flags for the interpreter.\n' '\n' - ' Other bits in "co_flags" are reserved for internal use.\n' + 'The following flag bits are defined for "co_flags": bit "0x04" is ' + 'set\n' + 'if the function uses the "*arguments" syntax to accept an ' + 'arbitrary\n' + 'number of positional arguments; bit "0x08" is set if the function ' + 'uses\n' + 'the "**keywords" syntax to accept arbitrary keyword arguments; bit\n' + '"0x20" is set if the function is a generator.\n' + '\n' + 'Future feature declarations ("from __future__ import division") ' + 'also\n' + 'use bits in "co_flags" to indicate whether a code object was ' + 'compiled\n' + 'with a particular feature enabled: bit "0x2000" is set if the ' + 'function\n' + 'was compiled with future division enabled; bits "0x10" and ' + '"0x1000"\n' + 'were used in earlier versions of Python.\n' '\n' - ' If a code object represents a function, the first item in\n' - ' "co_consts" is the documentation string of the function, or\n' - ' "None" if undefined.\n' + 'Other bits in "co_flags" are reserved for internal use.\n' '\n' - ' codeobject.co_positions()\n' + 'If a code object represents a function, the first item in ' + '"co_consts"\n' + 'is the documentation string of the function, or "None" if ' + 'undefined.\n' '\n' - ' Returns an iterable over the source code positions of ' - 'each\n' - ' bytecode instruction in the code object.\n' + 'codeobject.co_positions()\n' '\n' - ' The iterator returns tuples containing the "(start_line,\n' - ' end_line, start_column, end_column)". The *i-th* tuple\n' - ' corresponds to the position of the source code that ' - 'compiled\n' - ' to the *i-th* instruction. Column information is ' - '0-indexed\n' - ' utf-8 byte offsets on the given source line.\n' + ' Returns an iterable over the source code positions of each ' + 'bytecode\n' + ' instruction in the code object.\n' '\n' - ' This positional information can be missing. A ' - 'non-exhaustive\n' - ' lists of cases where this may happen:\n' + ' The iterator returns tuples containing the "(start_line, ' + 'end_line,\n' + ' start_column, end_column)". The *i-th* tuple corresponds to the\n' + ' position of the source code that compiled to the *i-th*\n' + ' instruction. Column information is 0-indexed utf-8 byte offsets ' + 'on\n' + ' the given source line.\n' '\n' - ' * Running the interpreter with "-X" "no_debug_ranges".\n' + ' This positional information can be missing. A non-exhaustive ' + 'lists\n' + ' of cases where this may happen:\n' '\n' - ' * Loading a pyc file compiled while using "-X"\n' - ' "no_debug_ranges".\n' + ' * Running the interpreter with "-X" "no_debug_ranges".\n' '\n' - ' * Position tuples corresponding to artificial ' - 'instructions.\n' + ' * Loading a pyc file compiled while using "-X" ' + '"no_debug_ranges".\n' '\n' - ' * Line and column numbers that can’t be represented due ' - 'to\n' - ' implementation specific limitations.\n' + ' * Position tuples corresponding to artificial instructions.\n' '\n' - ' When this occurs, some or all of the tuple elements can ' - 'be\n' - ' "None".\n' + ' * Line and column numbers that can’t be represented due to\n' + ' implementation specific limitations.\n' '\n' - ' New in version 3.11.\n' + ' When this occurs, some or all of the tuple elements can be ' + '"None".\n' '\n' - ' Note:\n' + ' New in version 3.11.\n' '\n' - ' This feature requires storing column positions in code\n' - ' objects which may result in a small increase of disk ' - 'usage\n' - ' of compiled Python files or interpreter memory usage. ' - 'To\n' - ' avoid storing the extra information and/or deactivate\n' - ' printing the extra traceback information, the "-X"\n' - ' "no_debug_ranges" command line flag or the\n' - ' "PYTHONNODEBUGRANGES" environment variable can be used.\n' + ' Note:\n' '\n' - ' Frame objects\n' - ' Frame objects represent execution frames. They may occur in\n' - ' traceback objects (see below), and are also passed to ' - 'registered\n' - ' trace functions.\n' + ' This feature requires storing column positions in code ' + 'objects\n' + ' which may result in a small increase of disk usage of ' + 'compiled\n' + ' Python files or interpreter memory usage. To avoid storing ' + 'the\n' + ' extra information and/or deactivate printing the extra ' + 'traceback\n' + ' information, the "-X" "no_debug_ranges" command line flag or ' + 'the\n' + ' "PYTHONNODEBUGRANGES" environment variable can be used.\n' + '\n' + '\n' + 'Frame objects\n' + '-------------\n' + '\n' + 'Frame objects represent execution frames. They may occur in ' + 'traceback\n' + 'objects (see below), and are also passed to registered trace\n' + 'functions.\n' + '\n' + 'Special read-only attributes: "f_back" is to the previous stack ' + 'frame\n' + '(towards the caller), or "None" if this is the bottom stack frame;\n' + '"f_code" is the code object being executed in this frame; ' + '"f_locals"\n' + 'is the dictionary used to look up local variables; "f_globals" is ' + 'used\n' + 'for global variables; "f_builtins" is used for built-in ' + '(intrinsic)\n' + 'names; "f_lasti" gives the precise instruction (this is an index ' + 'into\n' + 'the bytecode string of the code object).\n' + '\n' + 'Accessing "f_code" raises an auditing event "object.__getattr__" ' + 'with\n' + 'arguments "obj" and ""f_code"".\n' + '\n' + 'Special writable attributes: "f_trace", if not "None", is a ' + 'function\n' + 'called for various events during code execution (this is used by ' + 'the\n' + 'debugger). Normally an event is triggered for each new source line ' + '-\n' + 'this can be disabled by setting "f_trace_lines" to "False".\n' '\n' - ' Special read-only attributes: "f_back" is to the previous ' - 'stack\n' - ' frame (towards the caller), or "None" if this is the bottom\n' - ' stack frame; "f_code" is the code object being executed in ' + 'Implementations *may* allow per-opcode events to be requested by\n' + 'setting "f_trace_opcodes" to "True". Note that this may lead to\n' + 'undefined interpreter behaviour if exceptions raised by the trace\n' + 'function escape to the function being traced.\n' + '\n' + '"f_lineno" is the current line number of the frame — writing to ' 'this\n' - ' frame; "f_locals" is the dictionary used to look up local\n' - ' variables; "f_globals" is used for global variables;\n' - ' "f_builtins" is used for built-in (intrinsic) names; ' - '"f_lasti"\n' - ' gives the precise instruction (this is an index into the\n' - ' bytecode string of the code object).\n' - '\n' - ' Accessing "f_code" raises an auditing event ' - '"object.__getattr__"\n' - ' with arguments "obj" and ""f_code"".\n' - '\n' - ' Special writable attributes: "f_trace", if not "None", is a\n' - ' function called for various events during code execution ' - '(this\n' - ' is used by the debugger). Normally an event is triggered for\n' - ' each new source line - this can be disabled by setting\n' - ' "f_trace_lines" to "False".\n' - '\n' - ' Implementations *may* allow per-opcode events to be requested ' - 'by\n' - ' setting "f_trace_opcodes" to "True". Note that this may lead ' - 'to\n' - ' undefined interpreter behaviour if exceptions raised by the\n' - ' trace function escape to the function being traced.\n' + 'from within a trace function jumps to the given line (only for the\n' + 'bottom-most frame). A debugger can implement a Jump command (aka ' + 'Set\n' + 'Next Statement) by writing to f_lineno.\n' '\n' - ' "f_lineno" is the current line number of the frame — writing ' - 'to\n' - ' this from within a trace function jumps to the given line ' - '(only\n' - ' for the bottom-most frame). A debugger can implement a Jump\n' - ' command (aka Set Next Statement) by writing to f_lineno.\n' + 'Frame objects support one method:\n' '\n' - ' Frame objects support one method:\n' + 'frame.clear()\n' '\n' - ' frame.clear()\n' + ' This method clears all references to local variables held by ' + 'the\n' + ' frame. Also, if the frame belonged to a generator, the ' + 'generator\n' + ' is finalized. This helps break reference cycles involving ' + 'frame\n' + ' objects (for example when catching an exception and storing its\n' + ' traceback for later use).\n' '\n' - ' This method clears all references to local variables held ' - 'by\n' - ' the frame. Also, if the frame belonged to a generator, ' + ' "RuntimeError" is raised if the frame is currently executing.\n' + '\n' + ' New in version 3.4.\n' + '\n' + '\n' + 'Traceback objects\n' + '-----------------\n' + '\n' + 'Traceback objects represent a stack trace of an exception. A\n' + 'traceback object is implicitly created when an exception occurs, ' + 'and\n' + 'may also be explicitly created by calling "types.TracebackType".\n' + '\n' + 'For implicitly created tracebacks, when the search for an ' + 'exception\n' + 'handler unwinds the execution stack, at each unwound level a ' + 'traceback\n' + 'object is inserted in front of the current traceback. When an\n' + 'exception handler is entered, the stack trace is made available to ' 'the\n' - ' generator is finalized. This helps break reference ' - 'cycles\n' - ' involving frame objects (for example when catching an\n' - ' exception and storing its traceback for later use).\n' + 'program. (See section The try statement.) It is accessible as the\n' + 'third item of the tuple returned by "sys.exc_info()", and as the\n' + '"__traceback__" attribute of the caught exception.\n' '\n' - ' "RuntimeError" is raised if the frame is currently ' - 'executing.\n' + 'When the program contains no suitable handler, the stack trace is\n' + 'written (nicely formatted) to the standard error stream; if the\n' + 'interpreter is interactive, it is also made available to the user ' + 'as\n' + '"sys.last_traceback".\n' '\n' - ' New in version 3.4.\n' + 'For explicitly created tracebacks, it is up to the creator of the\n' + 'traceback to determine how the "tb_next" attributes should be ' + 'linked\n' + 'to form a full stack trace.\n' '\n' - ' Traceback objects\n' - ' Traceback objects represent a stack trace of an exception. ' - 'A\n' - ' traceback object is implicitly created when an exception ' - 'occurs,\n' - ' and may also be explicitly created by calling\n' - ' "types.TracebackType".\n' - '\n' - ' For implicitly created tracebacks, when the search for an\n' - ' exception handler unwinds the execution stack, at each ' - 'unwound\n' - ' level a traceback object is inserted in front of the current\n' - ' traceback. When an exception handler is entered, the stack\n' - ' trace is made available to the program. (See section The try\n' - ' statement.) It is accessible as the third item of the tuple\n' - ' returned by "sys.exc_info()", and as the "__traceback__"\n' - ' attribute of the caught exception.\n' - '\n' - ' When the program contains no suitable handler, the stack ' - 'trace\n' - ' is written (nicely formatted) to the standard error stream; ' - 'if\n' - ' the interpreter is interactive, it is also made available to ' + 'Special read-only attributes: "tb_frame" points to the execution ' + 'frame\n' + 'of the current level; "tb_lineno" gives the line number where the\n' + 'exception occurred; "tb_lasti" indicates the precise instruction. ' + 'The\n' + 'line number and last instruction in the traceback may differ from ' 'the\n' - ' user as "sys.last_traceback".\n' + 'line number of its frame object if the exception occurred in a ' + '"try"\n' + 'statement with no matching except clause or with a finally clause.\n' '\n' - ' For explicitly created tracebacks, it is up to the creator ' - 'of\n' - ' the traceback to determine how the "tb_next" attributes ' - 'should\n' - ' be linked to form a full stack trace.\n' - '\n' - ' Special read-only attributes: "tb_frame" points to the ' - 'execution\n' - ' frame of the current level; "tb_lineno" gives the line ' - 'number\n' - ' where the exception occurred; "tb_lasti" indicates the ' - 'precise\n' - ' instruction. The line number and last instruction in the\n' - ' traceback may differ from the line number of its frame object ' + 'Accessing "tb_frame" raises an auditing event "object.__getattr__"\n' + 'with arguments "obj" and ""tb_frame"".\n' + '\n' + 'Special writable attribute: "tb_next" is the next level in the ' + 'stack\n' + 'trace (towards the frame where the exception occurred), or "None" ' 'if\n' - ' the exception occurred in a "try" statement with no matching\n' - ' except clause or with a finally clause.\n' + 'there is no next level.\n' '\n' - ' Accessing "tb_frame" raises an auditing event\n' - ' "object.__getattr__" with arguments "obj" and ""tb_frame"".\n' + 'Changed in version 3.7: Traceback objects can now be explicitly\n' + 'instantiated from Python code, and the "tb_next" attribute of ' + 'existing\n' + 'instances can be updated.\n' '\n' - ' Special writable attribute: "tb_next" is the next level in ' - 'the\n' - ' stack trace (towards the frame where the exception occurred), ' - 'or\n' - ' "None" if there is no next level.\n' '\n' - ' Changed in version 3.7: Traceback objects can now be ' - 'explicitly\n' - ' instantiated from Python code, and the "tb_next" attribute ' - 'of\n' - ' existing instances can be updated.\n' + 'Slice objects\n' + '-------------\n' '\n' - ' Slice objects\n' - ' Slice objects are used to represent slices for ' - '"__getitem__()"\n' - ' methods. They are also created by the built-in "slice()"\n' - ' function.\n' + 'Slice objects are used to represent slices for "__getitem__()"\n' + 'methods. They are also created by the built-in "slice()" ' + 'function.\n' '\n' - ' Special read-only attributes: "start" is the lower bound; ' - '"stop"\n' - ' is the upper bound; "step" is the step value; each is "None" ' - 'if\n' - ' omitted. These attributes can have any type.\n' + 'Special read-only attributes: "start" is the lower bound; "stop" ' + 'is\n' + 'the upper bound; "step" is the step value; each is "None" if ' + 'omitted.\n' + 'These attributes can have any type.\n' '\n' - ' Slice objects support one method:\n' + 'Slice objects support one method:\n' '\n' - ' slice.indices(self, length)\n' + 'slice.indices(self, length)\n' '\n' - ' This method takes a single integer argument *length* and\n' - ' computes information about the slice that the slice ' - 'object\n' - ' would describe if applied to a sequence of *length* ' - 'items.\n' - ' It returns a tuple of three integers; respectively these ' - 'are\n' - ' the *start* and *stop* indices and the *step* or stride\n' - ' length of the slice. Missing or out-of-bounds indices are\n' - ' handled in a manner consistent with regular slices.\n' - '\n' - ' Static method objects\n' - ' Static method objects provide a way of defeating the\n' - ' transformation of function objects to method objects ' - 'described\n' - ' above. A static method object is a wrapper around any other\n' - ' object, usually a user-defined method object. When a static\n' - ' method object is retrieved from a class or a class instance, ' - 'the\n' - ' object actually returned is the wrapped object, which is not\n' - ' subject to any further transformation. Static method objects ' - 'are\n' - ' also callable. Static method objects are created by the ' - 'built-in\n' - ' "staticmethod()" constructor.\n' + ' This method takes a single integer argument *length* and ' + 'computes\n' + ' information about the slice that the slice object would describe ' + 'if\n' + ' applied to a sequence of *length* items. It returns a tuple of\n' + ' three integers; respectively these are the *start* and *stop*\n' + ' indices and the *step* or stride length of the slice. Missing ' + 'or\n' + ' out-of-bounds indices are handled in a manner consistent with\n' + ' regular slices.\n' '\n' - ' Class method objects\n' - ' A class method object, like a static method object, is a ' - 'wrapper\n' - ' around another object that alters the way in which that ' - 'object\n' - ' is retrieved from classes and class instances. The behaviour ' + '\n' + 'Static method objects\n' + '---------------------\n' + '\n' + 'Static method objects provide a way of defeating the transformation ' 'of\n' - ' class method objects upon such retrieval is described above,\n' - ' under “User-defined methodsâ€. Class method objects are ' - 'created\n' - ' by the built-in "classmethod()" constructor.\n', + 'function objects to method objects described above. A static ' + 'method\n' + 'object is a wrapper around any other object, usually a ' + 'user-defined\n' + 'method object. When a static method object is retrieved from a ' + 'class\n' + 'or a class instance, the object actually returned is the wrapped\n' + 'object, which is not subject to any further transformation. Static\n' + 'method objects are also callable. Static method objects are created ' + 'by\n' + 'the built-in "staticmethod()" constructor.\n' + '\n' + '\n' + 'Class method objects\n' + '--------------------\n' + '\n' + 'A class method object, like a static method object, is a wrapper\n' + 'around another object that alters the way in which that object is\n' + 'retrieved from classes and class instances. The behaviour of class\n' + 'method objects upon such retrieval is described above, under ' + '“User-\n' + 'defined methodsâ€. Class method objects are created by the built-in\n' + '"classmethod()" constructor.\n', 'typesfunctions': 'Functions\n' '*********\n' '\n' diff --git a/Misc/NEWS.d/3.12.0rc2.rst b/Misc/NEWS.d/3.12.0rc2.rst new file mode 100644 index 00000000000000..3741da94798e50 --- /dev/null +++ b/Misc/NEWS.d/3.12.0rc2.rst @@ -0,0 +1,510 @@ +.. date: 2023-08-22-17-39-12 +.. gh-issue: 108310 +.. nonce: fVM3sg +.. release date: 2023-09-05 +.. section: Security + +Fixed an issue where instances of :class:`ssl.SSLSocket` were vulnerable to +a bypass of the TLS handshake and included protections (like certificate +verification) and treating sent unencrypted data as if it were +post-handshake TLS encrypted data. Security issue reported as +`CVE-2023-40217 +`_ by Aapo +Oksman. Patch by Gregory P. Smith. + +.. + +.. date: 2023-08-05-03-51-05 +.. gh-issue: 107774 +.. nonce: VPjaTR +.. section: Security + +PEP 669 specifies that ``sys.monitoring.register_callback`` will generate an +audit event. Pre-releases of Python 3.12 did not generate the audit event. +This is now fixed. + +.. + +.. date: 2023-08-30-15-41-47 +.. gh-issue: 108520 +.. nonce: u0ZGP_ +.. section: Core and Builtins + +Fix :meth:`multiprocessing.synchronize.SemLock.__setstate__` to properly +initialize :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx`. This +fixes a regression when passing a SemLock accross nested processes. + +Rename :attr:`multiprocessing.synchronize.SemLock.is_fork_ctx` to +:attr:`multiprocessing.synchronize.SemLock._is_fork_ctx` to avoid exposing +it as public API. + +.. + +.. date: 2023-08-29-17-53-12 +.. gh-issue: 108654 +.. nonce: jbkDVo +.. section: Core and Builtins + +Restore locals shadowed by an inlined comprehension if the comprehension +raises an exception. + +.. + +.. date: 2023-08-26-04-33-18 +.. gh-issue: 108487 +.. nonce: aUFxqf +.. section: Core and Builtins + +Change an assert that would cause a spurious crash in a devious case that +should only trigger deoptimization. + +.. + +.. date: 2023-08-25-14-51-06 +.. gh-issue: 106176 +.. nonce: D1EA2a +.. section: Core and Builtins + +Use a ``WeakValueDictionary`` to track the lists containing the modules each +thread is currently importing. This helps avoid a reference leak from +keeping the list around longer than necessary. Weakrefs are used as GC can't +interrupt the cleanup. + +.. + +.. date: 2023-08-21-21-13-30 +.. gh-issue: 107901 +.. nonce: hszvdk +.. section: Core and Builtins + +Fix missing line number on :opcode:`JUMP_BACKWARD` at the end of a for loop. + +.. + +.. date: 2023-08-13-17-18-22 +.. gh-issue: 108390 +.. nonce: TkBccC +.. section: Core and Builtins + +Raise an exception when setting a non-local event (``RAISE``, +``EXCEPTION_HANDLED``, etc.) in ``sys.monitoring.set_local_events``. + +Fixes crash when tracing in recursive calls to Python classes. + +.. + +.. date: 2023-08-10-17-36-27 +.. gh-issue: 91051 +.. nonce: LfaeNW +.. section: Core and Builtins + +Fix abort / segfault when using all eight type watcher slots, on platforms +where ``char`` is signed by default. + +.. + +.. date: 2023-08-04-21-25-26 +.. gh-issue: 107724 +.. nonce: EbBXMr +.. section: Core and Builtins + +In pre-release versions of 3.12, up to rc1, the sys.monitoring callback +function for the ``PY_THROW`` event was missing the third, exception +argument. That is now fixed. + +.. + +.. date: 2023-08-02-12-24-51 +.. gh-issue: 107080 +.. nonce: PNolFU +.. section: Core and Builtins + +Trace refs builds (``--with-trace-refs``) were crashing when used with +isolated subinterpreters. The problematic global state has been isolated to +each interpreter. Other fixing the crashes, this change does not affect +users. + +.. + +.. date: 2023-07-25-22-35-35 +.. gh-issue: 77377 +.. nonce: EHAbXx +.. section: Core and Builtins + +Ensure that multiprocessing synchronization objects created in a fork +context are not sent to a different process created in a spawn context. This +changes a segfault into an actionable RuntimeError in the parent process. + +.. + +.. date: 2023-09-03-04-37-52 +.. gh-issue: 108469 +.. nonce: kusj40 +.. section: Library + +:func:`ast.unparse` now supports new :term:`f-string` syntax introduced in +Python 3.12. Note that the :term:`f-string` quotes are reselected for +simplicity under the new syntax. (Patch by Steven Sun) + +.. + +.. date: 2023-08-30-20-10-28 +.. gh-issue: 108682 +.. nonce: c2gzLQ +.. section: Library + +Enum: raise :exc:`TypeError` if ``super().__new__()`` is called from a +custom ``__new__``. + +.. + +.. date: 2023-08-26-08-38-57 +.. gh-issue: 108295 +.. nonce: Pn0QRM +.. section: Library + +Fix crashes related to use of weakrefs on :data:`typing.TypeVar`. + +.. + +.. date: 2023-08-22-22-29-42 +.. gh-issue: 64662 +.. nonce: jHl_Bt +.. section: Library + +Fix support for virtual tables in :meth:`sqlite3.Connection.iterdump`. Patch +by Aviv Palivoda. + +.. + +.. date: 2023-08-22-17-27-12 +.. gh-issue: 108111 +.. nonce: N7a4u_ +.. section: Library + +Fix a regression introduced in GH-101251 for 3.12, resulting in an incorrect +offset calculation in :meth:`gzip.GzipFile.seek`. + +.. + +.. date: 2023-08-17-14-45-25 +.. gh-issue: 105736 +.. nonce: NJsH7r +.. section: Library + +Harmonized the pure Python version of :class:`~collections.OrderedDict` with +the C version. Now, both versions set up their internal state in +``__new__``. Formerly, the pure Python version did the set up in +``__init__``. + +.. + +.. date: 2023-08-17-12-59-35 +.. gh-issue: 108083 +.. nonce: 9J7UcT +.. section: Library + +Fix bugs in the constructor of :mod:`sqlite3.Connection` and +:meth:`sqlite3.Connection.close` where exceptions could be leaked. Patch by +Erlend E. Aasland. + +.. + +.. date: 2023-08-15-18-20-00 +.. gh-issue: 107963 +.. nonce: 20g5BG +.. section: Library + +Fix :func:`multiprocessing.set_forkserver_preload` to check the given list +of modules names. Patch by Dong-hee Na. + +.. + +.. date: 2023-08-14-23-11-11 +.. gh-issue: 106242 +.. nonce: 71HMym +.. section: Library + +Fixes :func:`os.path.normpath` to handle embedded null characters without +truncating the path. + +.. + +.. date: 2023-08-14-11-18-13 +.. gh-issue: 107913 +.. nonce: 4ooY6i +.. section: Library + +Fix possible losses of ``errno`` and ``winerror`` values in :exc:`OSError` +exceptions if they were cleared or modified by the cleanup code before +creating the exception object. + +.. + +.. date: 2023-08-10-17-36-22 +.. gh-issue: 107845 +.. nonce: dABiMJ +.. section: Library + +:func:`tarfile.data_filter` now takes the location of symlinks into account +when determining their target, so it will no longer reject some valid +tarballs with ``LinkOutsideDestinationError``. + +.. + +.. date: 2023-08-09-13-49-37 +.. gh-issue: 107805 +.. nonce: ezem0k +.. section: Library + +Fix signatures of module-level generated functions in :mod:`turtle`. + +.. + +.. date: 2023-08-07-14-12-07 +.. gh-issue: 107715 +.. nonce: 238r2f +.. section: Library + +Fix :meth:`doctest.DocTestFinder.find` in presence of class names with +special characters. Patch by Gertjan van Zwieten. + +.. + +.. date: 2023-08-06-15-29-00 +.. gh-issue: 100814 +.. nonce: h195gW +.. section: Library + +Passing a callable object as an option value to a Tkinter image now raises +the expected TclError instead of an AttributeError. + +.. + +.. date: 2023-08-05-05-10-41 +.. gh-issue: 106684 +.. nonce: P9zRXb +.. section: Library + +Close :class:`asyncio.StreamWriter` when it is not closed by application +leading to memory leaks. Patch by Kumar Aditya. + +.. + +.. date: 2023-07-31-07-36-24 +.. gh-issue: 107396 +.. nonce: 3_Kh6D +.. section: Library + +tarfiles; Fixed use before assignment of self.exception for gzip +decompression + +.. + +.. date: 2023-07-07-14-52-31 +.. gh-issue: 106052 +.. nonce: ak8nbs +.. section: Library + +:mod:`re` module: fix the matching of possessive quantifiers in the case of +a subpattern containing backtracking. + +.. + +.. date: 2023-03-14-01-19-57 +.. gh-issue: 100061 +.. nonce: CiXJYn +.. section: Library + +Fix a bug that causes wrong matches for regular expressions with possessive +qualifier. + +.. + +.. date: 2022-11-26-22-05-22 +.. gh-issue: 99203 +.. nonce: j0DUae +.. section: Library + +Restore following CPython <= 3.10.5 behavior of :func:`shutil.make_archive`: +do not create an empty archive if ``root_dir`` is not a directory, and, in +that case, raise :class:`FileNotFoundError` or :class:`NotADirectoryError` +regardless of ``format`` choice. Beyond the brought-back behavior, the +function may now also raise these exceptions in ``dry_run`` mode. + +.. + +.. date: 2023-05-29-14-10-24 +.. gh-issue: 105052 +.. nonce: MGFwbm +.. section: Documentation + +Update ``timeit`` doc to specify that time in seconds is just the default. + +.. + +.. date: 2023-09-04-15-18-14 +.. gh-issue: 89392 +.. nonce: 8A4T5p +.. section: Tests + +Removed support of ``test_main()`` function in tests. They now always use +normal unittest test runner. + +.. + +.. date: 2023-08-24-06-10-36 +.. gh-issue: 108388 +.. nonce: YCVB0D +.. section: Tests + +Convert test_concurrent_futures to a package of 7 sub-tests. Patch by Victor +Stinner. + +.. + +.. date: 2023-08-24-04-23-35 +.. gh-issue: 108388 +.. nonce: mr0MeE +.. section: Tests + +Split test_multiprocessing_fork, test_multiprocessing_forkserver and +test_multiprocessing_spawn into test packages. Each package is made of 4 +sub-tests: processes, threads, manager and misc. It allows running more +tests in parallel and so reduce the total test duration. Patch by Victor +Stinner. + +.. + +.. date: 2023-08-23-04-08-18 +.. gh-issue: 105776 +.. nonce: oE6wp_ +.. section: Tests + +Fix test_cppext when the C compiler command ``-std=c11`` option: remove +``-std=`` options from the compiler command. Patch by Victor Stinner. + +.. + +.. date: 2023-07-24-16-56-59 +.. gh-issue: 107178 +.. nonce: Gq1usE +.. section: Tests + +Add the C API test for functions in the Mapping Protocol, the Sequence +Protocol and some functions in the Object Protocol. + +.. + +.. date: 2023-09-02-18-04-15 +.. gh-issue: 63760 +.. nonce: r8hJ6q +.. section: Build + +Fix Solaris build: no longer redefine the ``gethostname()`` function. +Solaris defines the function since 2005. Patch by Victor Stinner, original +patch by Jakub Kulík. + +.. + +.. date: 2023-08-09-17-05-33 +.. gh-issue: 107814 +.. nonce: c0Oapq +.. section: Build + +When calling ``find_python.bat`` with ``-q`` it did not properly silence the +output of nuget. That is now fixed. + +.. + +.. date: 2023-09-05-10-08-47 +.. gh-issue: 107565 +.. nonce: CIMftz +.. section: Windows + +Update Windows build to use OpenSSL 3.0.10. + +.. + +.. date: 2023-08-22-00-36-57 +.. gh-issue: 106242 +.. nonce: q24ITw +.. section: Windows + +Fixes :func:`~os.path.realpath` to behave consistently when passed a path +containing an embedded null character on Windows. In strict mode, it now +raises :exc:`OSError` instead of the unexpected :exc:`ValueError`, and in +non-strict mode will make the path absolute. + +.. + +.. date: 2023-07-18-13-01-26 +.. gh-issue: 106844 +.. nonce: mci4xO +.. section: Windows + +Fix integer overflow and truncating by the null character in +:func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`. + +.. + +.. date: 2023-08-12-13-33-57 +.. gh-issue: 107565 +.. nonce: SJwqf4 +.. section: macOS + +Update macOS installer to use OpenSSL 3.0.10. + +.. + +.. date: 2023-08-12-13-18-15 +.. gh-issue: 107565 +.. nonce: Tv22Ne +.. section: Tools/Demos + +Update multissltests and GitHub CI workflows to use OpenSSL 1.1.1v, 3.0.10, +and 3.1.2. + +.. + +.. date: 2023-08-07-16-30-48 +.. gh-issue: 95065 +.. nonce: -im4R5 +.. section: Tools/Demos + +Argument Clinic now supports overriding automatically generated signature by +using directive ``@text_signature``. + +.. + +.. date: 2023-08-14-10-59-03 +.. gh-issue: 107916 +.. nonce: KH4Muo +.. section: C API + +C API functions :c:func:`PyErr_SetFromErrnoWithFilename`, +:c:func:`PyErr_SetExcFromWindowsErrWithFilename` and +:c:func:`PyErr_SetFromWindowsErrWithFilename` save now the error code before +calling :c:func:`PyUnicode_DecodeFSDefault`. + +.. + +.. date: 2023-08-13-12-33-00 +.. gh-issue: 107915 +.. nonce: jQ0wOi +.. section: C API + +Such C API functions as ``PyErr_SetString()``, ``PyErr_Format()``, +``PyErr_SetFromErrnoWithFilename()`` and many others no longer crash or +ignore errors if it failed to format the error message or decode the +filename. Instead, they keep a corresponding error. + +.. + +.. date: 2023-08-10-11-12-25 +.. gh-issue: 107810 +.. nonce: oJ40Qx +.. section: C API + +Improve :exc:`DeprecationWarning` for uses of :c:type:`PyType_Spec` with +metaclasses that have custom ``tp_new``. diff --git a/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst b/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst deleted file mode 100644 index d3723353470ce2..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-08-09-17-05-33.gh-issue-107814.c0Oapq.rst +++ /dev/null @@ -1 +0,0 @@ -When calling ``find_python.bat`` with ``-q`` it did not properly silence the output of nuget. That is now fixed. diff --git a/Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst b/Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst deleted file mode 100644 index 9a7249e923e0c7..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-09-02-18-04-15.gh-issue-63760.r8hJ6q.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix Solaris build: no longer redefine the ``gethostname()`` function. Solaris -defines the function since 2005. Patch by Victor Stinner, original patch by -Jakub Kulík. diff --git a/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst b/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst deleted file mode 100644 index c8a1f6d122b61b..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-08-10-11-12-25.gh-issue-107810.oJ40Qx.rst +++ /dev/null @@ -1 +0,0 @@ -Improve :exc:`DeprecationWarning` for uses of :c:type:`PyType_Spec` with metaclasses that have custom ``tp_new``. diff --git a/Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst b/Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst deleted file mode 100644 index 58ee3f169a28cc..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-08-13-12-33-00.gh-issue-107915.jQ0wOi.rst +++ /dev/null @@ -1,4 +0,0 @@ -Such C API functions as ``PyErr_SetString()``, ``PyErr_Format()``, -``PyErr_SetFromErrnoWithFilename()`` and many others no longer crash or -ignore errors if it failed to format the error message or decode the -filename. Instead, they keep a corresponding error. diff --git a/Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst b/Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst deleted file mode 100644 index f1f16609b118ba..00000000000000 --- a/Misc/NEWS.d/next/C API/2023-08-14-10-59-03.gh-issue-107916.KH4Muo.rst +++ /dev/null @@ -1,4 +0,0 @@ -C API functions :c:func:`PyErr_SetFromErrnoWithFilename`, -:c:func:`PyErr_SetExcFromWindowsErrWithFilename` and -:c:func:`PyErr_SetFromWindowsErrWithFilename` save now the error code before -calling :c:func:`PyUnicode_DecodeFSDefault`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst deleted file mode 100644 index 194851dea13352..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-07-25-22-35-35.gh-issue-77377.EHAbXx.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure that multiprocessing synchronization objects created in a fork context are not sent to a different process created in a spawn context. This changes a segfault into an actionable RuntimeError in the parent process. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst deleted file mode 100644 index 5084c854360e35..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-12-24-51.gh-issue-107080.PNolFU.rst +++ /dev/null @@ -1,4 +0,0 @@ -Trace refs builds (``--with-trace-refs``) were crashing when used with -isolated subinterpreters. The problematic global state has been isolated to -each interpreter. Other fixing the crashes, this change does not affect -users. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst deleted file mode 100644 index 6e853cf72a3348..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-04-21-25-26.gh-issue-107724.EbBXMr.rst +++ /dev/null @@ -1,3 +0,0 @@ -In pre-release versions of 3.12, up to rc1, the sys.monitoring callback -function for the ``PY_THROW`` event was missing the third, exception -argument. That is now fixed. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst deleted file mode 100644 index b4b90ad4ea0ecc..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-10-17-36-27.gh-issue-91051.LfaeNW.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix abort / segfault when using all eight type watcher slots, on platforms -where ``char`` is signed by default. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst deleted file mode 100644 index 3ed596007b56f7..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-13-17-18-22.gh-issue-108390.TkBccC.rst +++ /dev/null @@ -1,4 +0,0 @@ -Raise an exception when setting a non-local event (``RAISE``, ``EXCEPTION_HANDLED``, -etc.) in ``sys.monitoring.set_local_events``. - -Fixes crash when tracing in recursive calls to Python classes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst deleted file mode 100644 index 112e093736dd5d..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-21-21-13-30.gh-issue-107901.hszvdk.rst +++ /dev/null @@ -1 +0,0 @@ -Fix missing line number on :opcode:`JUMP_BACKWARD` at the end of a for loop. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst deleted file mode 100644 index 7f63d1086ea39e..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-25-14-51-06.gh-issue-106176.D1EA2a.rst +++ /dev/null @@ -1,4 +0,0 @@ -Use a ``WeakValueDictionary`` to track the lists containing the modules each -thread is currently importing. This helps avoid a reference leak from -keeping the list around longer than necessary. Weakrefs are used as GC can't -interrupt the cleanup. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst deleted file mode 100644 index 1117bcd7e9852b..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-26-04-33-18.gh-issue-108487.aUFxqf.rst +++ /dev/null @@ -1 +0,0 @@ -Change an assert that would cause a spurious crash in a devious case that should only trigger deoptimization. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst deleted file mode 100644 index 032e0331b20e75..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-29-17-53-12.gh-issue-108654.jbkDVo.rst +++ /dev/null @@ -1,2 +0,0 @@ -Restore locals shadowed by an inlined comprehension if the comprehension -raises an exception. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst deleted file mode 100644 index 44131fb11f068c..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-08-30-15-41-47.gh-issue-108520.u0ZGP_.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix :meth:`multiprocessing.synchronize.SemLock.__setstate__` to properly initialize :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx`. This fixes a regression when passing a SemLock accross nested processes. - -Rename :attr:`multiprocessing.synchronize.SemLock.is_fork_ctx` to :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx` to avoid exposing it as public API. diff --git a/Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst b/Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst deleted file mode 100644 index 8fdc38d439f54f..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-05-29-14-10-24.gh-issue-105052.MGFwbm.rst +++ /dev/null @@ -1 +0,0 @@ -Update ``timeit`` doc to specify that time in seconds is just the default. diff --git a/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst b/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst deleted file mode 100644 index fcfb044d476acc..00000000000000 --- a/Misc/NEWS.d/next/Library/2022-11-26-22-05-22.gh-issue-99203.j0DUae.rst +++ /dev/null @@ -1,5 +0,0 @@ -Restore following CPython <= 3.10.5 behavior of :func:`shutil.make_archive`: -do not create an empty archive if ``root_dir`` is not a directory, and, in that -case, raise :class:`FileNotFoundError` or :class:`NotADirectoryError` -regardless of ``format`` choice. Beyond the brought-back behavior, the function -may now also raise these exceptions in ``dry_run`` mode. diff --git a/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst b/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst deleted file mode 100644 index dfed34f6ae9768..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-14-01-19-57.gh-issue-100061.CiXJYn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug that causes wrong matches for regular expressions with possessive -qualifier. diff --git a/Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst b/Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst deleted file mode 100644 index f2d4c2f7b18ec7..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-07-14-52-31.gh-issue-106052.ak8nbs.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`re` module: fix the matching of possessive quantifiers in the case of -a subpattern containing backtracking. diff --git a/Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst b/Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst deleted file mode 100644 index 73bff4bdbe024d..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-07-31-07-36-24.gh-issue-107396.3_Kh6D.rst +++ /dev/null @@ -1 +0,0 @@ -tarfiles; Fixed use before assignment of self.exception for gzip decompression diff --git a/Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst b/Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst deleted file mode 100644 index 85bce76229853f..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-05-05-10-41.gh-issue-106684.P9zRXb.rst +++ /dev/null @@ -1 +0,0 @@ -Close :class:`asyncio.StreamWriter` when it is not closed by application leading to memory leaks. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst b/Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst deleted file mode 100644 index 86cb7bf79f3078..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-06-15-29-00.gh-issue-100814.h195gW.rst +++ /dev/null @@ -1,2 +0,0 @@ -Passing a callable object as an option value to a Tkinter image now raises -the expected TclError instead of an AttributeError. diff --git a/Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst b/Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst deleted file mode 100644 index 4bf08c071df2f9..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-07-14-12-07.gh-issue-107715.238r2f.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :meth:`doctest.DocTestFinder.find` in presence of class names with special characters. Patch by Gertjan van Zwieten. diff --git a/Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst b/Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst deleted file mode 100644 index 263df68f8e5c80..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-09-13-49-37.gh-issue-107805.ezem0k.rst +++ /dev/null @@ -1 +0,0 @@ -Fix signatures of module-level generated functions in :mod:`turtle`. diff --git a/Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst b/Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst deleted file mode 100644 index 32c1fb93f4ab2c..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-10-17-36-22.gh-issue-107845.dABiMJ.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`tarfile.data_filter` now takes the location of symlinks into account -when determining their target, so it will no longer reject some valid -tarballs with ``LinkOutsideDestinationError``. diff --git a/Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst b/Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst deleted file mode 100644 index de5e21abfc3ae7..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-14-11-18-13.gh-issue-107913.4ooY6i.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix possible losses of ``errno`` and ``winerror`` values in :exc:`OSError` -exceptions if they were cleared or modified by the cleanup code before -creating the exception object. diff --git a/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst b/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst deleted file mode 100644 index 44237a9f15708c..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-14-23-11-11.gh-issue-106242.71HMym.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes :func:`os.path.normpath` to handle embedded null characters without truncating the path. diff --git a/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst b/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst deleted file mode 100644 index 3a73b2da0c4334..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-15-18-20-00.gh-issue-107963.20g5BG.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`multiprocessing.set_forkserver_preload` to check the given list -of modules names. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst b/Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst deleted file mode 100644 index ff499ced73a309..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-17-12-59-35.gh-issue-108083.9J7UcT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix bugs in the constructor of :mod:`sqlite3.Connection` and -:meth:`sqlite3.Connection.close` where exceptions could be leaked. Patch by -Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst b/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst deleted file mode 100644 index 1d959a3b22284c..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-17-14-45-25.gh-issue-105736.NJsH7r.rst +++ /dev/null @@ -1,3 +0,0 @@ -Harmonized the pure Python version of :class:`~collections.OrderedDict` with the C version. Now, -both versions set up their internal state in ``__new__``. Formerly, the pure -Python version did the set up in ``__init__``. diff --git a/Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst b/Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst deleted file mode 100644 index 8eafa6cfbbf8cf..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-22-17-27-12.gh-issue-108111.N7a4u_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a regression introduced in GH-101251 for 3.12, resulting in an incorrect -offset calculation in :meth:`gzip.GzipFile.seek`. diff --git a/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst b/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst deleted file mode 100644 index 1b4c33a82b0b86..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-22-22-29-42.gh-issue-64662.jHl_Bt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix support for virtual tables in :meth:`sqlite3.Connection.iterdump`. Patch -by Aviv Palivoda. diff --git a/Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst b/Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst deleted file mode 100644 index 7e61ed4de75ce6..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-26-08-38-57.gh-issue-108295.Pn0QRM.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crashes related to use of weakrefs on :data:`typing.TypeVar`. diff --git a/Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst b/Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst deleted file mode 100644 index 148d4329142740..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-08-30-20-10-28.gh-issue-108682.c2gzLQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Enum: raise :exc:`TypeError` if ``super().__new__()`` is called from a -custom ``__new__``. diff --git a/Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst b/Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst deleted file mode 100644 index ac0f682963daec..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-09-03-04-37-52.gh-issue-108469.kusj40.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`ast.unparse` now supports new :term:`f-string` syntax introduced in -Python 3.12. Note that the :term:`f-string` quotes are reselected for simplicity -under the new syntax. (Patch by Steven Sun) diff --git a/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst b/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst deleted file mode 100644 index b89b50c79f7e2a..00000000000000 --- a/Misc/NEWS.d/next/Security/2023-08-05-03-51-05.gh-issue-107774.VPjaTR.rst +++ /dev/null @@ -1,3 +0,0 @@ -PEP 669 specifies that ``sys.monitoring.register_callback`` will generate an -audit event. Pre-releases of Python 3.12 did not generate the audit event. -This is now fixed. diff --git a/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst b/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst deleted file mode 100644 index 403c77a9d480ee..00000000000000 --- a/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst +++ /dev/null @@ -1,7 +0,0 @@ -Fixed an issue where instances of :class:`ssl.SSLSocket` were vulnerable to -a bypass of the TLS handshake and included protections (like certificate -verification) and treating sent unencrypted data as if it were -post-handshake TLS encrypted data. Security issue reported as -`CVE-2023-40217 -`_ by -Aapo Oksman. Patch by Gregory P. Smith. diff --git a/Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst b/Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst deleted file mode 100644 index dd6becf6b00130..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-07-24-16-56-59.gh-issue-107178.Gq1usE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add the C API test for functions in the Mapping Protocol, the Sequence -Protocol and some functions in the Object Protocol. diff --git a/Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst b/Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst deleted file mode 100644 index 0e0a3aa9b11e68..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-08-23-04-08-18.gh-issue-105776.oE6wp_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix test_cppext when the C compiler command ``-std=c11`` option: remove -``-std=`` options from the compiler command. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst b/Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst deleted file mode 100644 index 8cf77b1cc187f1..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-08-24-04-23-35.gh-issue-108388.mr0MeE.rst +++ /dev/null @@ -1,4 +0,0 @@ -Split test_multiprocessing_fork, test_multiprocessing_forkserver and -test_multiprocessing_spawn into test packages. Each package is made of 4 -sub-tests: processes, threads, manager and misc. It allows running more tests -in parallel and so reduce the total test duration. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst b/Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst deleted file mode 100644 index ddff07be024d47..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-08-24-06-10-36.gh-issue-108388.YCVB0D.rst +++ /dev/null @@ -1,2 +0,0 @@ -Convert test_concurrent_futures to a package of 7 sub-tests. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst b/Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst deleted file mode 100644 index e1dea8e78cdd4e..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-04-15-18-14.gh-issue-89392.8A4T5p.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed support of ``test_main()`` function in tests. They now always use -normal unittest test runner. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst b/Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst deleted file mode 100644 index 4768e6767574d8..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-08-07-16-30-48.gh-issue-95065.-im4R5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Argument Clinic now supports overriding automatically generated signature by -using directive ``@text_signature``. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst b/Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst deleted file mode 100644 index c43ee680e8158e..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-08-12-13-18-15.gh-issue-107565.Tv22Ne.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update multissltests and GitHub CI workflows to use OpenSSL 1.1.1v, 3.0.10, -and 3.1.2. diff --git a/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst b/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst deleted file mode 100644 index 1fdf162ef4ecdd..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst +++ /dev/null @@ -1 +0,0 @@ -Fix integer overflow and truncating by the null character in :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`. diff --git a/Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst b/Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst deleted file mode 100644 index ffe42ec5dc3faf..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-08-22-00-36-57.gh-issue-106242.q24ITw.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixes :func:`~os.path.realpath` to behave consistently when passed a path -containing an embedded null character on Windows. In strict mode, it now -raises :exc:`OSError` instead of the unexpected :exc:`ValueError`, and in -non-strict mode will make the path absolute. diff --git a/Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst b/Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst deleted file mode 100644 index 024a58299caed9..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-09-05-10-08-47.gh-issue-107565.CIMftz.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows build to use OpenSSL 3.0.10. diff --git a/Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst b/Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst deleted file mode 100644 index c238c4760239e1..00000000000000 --- a/Misc/NEWS.d/next/macOS/2023-08-12-13-33-57.gh-issue-107565.SJwqf4.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use OpenSSL 3.0.10. diff --git a/README.rst b/README.rst index b97bd3c8bd667d..1d0aee57123731 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 release candidate 1 +This is Python version 3.12.0 release candidate 2 ================================================= .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From d7869ec22a1d2ba1a59126ba09b4735b1c810467 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 5 Sep 2023 17:39:21 -0700 Subject: [PATCH 0700/1206] [3.12] gh-108857: improve markup in inspect.Signature.replace() docs (GH-108862) (#108971) gh-108857: improve markup in inspect.Signature.replace() docs (GH-108862) (cherry picked from commit 6f8411cfd68134ccae01b0b4cb332578008a69e3) Co-authored-by: nabin2004 <107109731+nabin2004@users.noreply.github.com> --- Doc/library/inspect.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 7884308a333020..603ac3263bb9ec 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -730,7 +730,7 @@ function. .. method:: Signature.replace(*[, parameters][, return_annotation]) - Create a new Signature instance based on the instance replace was invoked + Create a new Signature instance based on the instance :meth:`replace` was invoked on. It is possible to pass different ``parameters`` and/or ``return_annotation`` to override the corresponding properties of the base signature. To remove return_annotation from the copied Signature, pass in From 8c7655554cad5d9062f9edf0a78c5fadaede0497 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Wed, 6 Sep 2023 12:27:54 +0200 Subject: [PATCH 0701/1206] Post 3.12.0rc2 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 5fd803e587f4dc..edb59b7968b219 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.12.0rc2" +#define PY_VERSION "3.12.0rc2+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From db55cfcbabfe257f5d3aeaffc1c5fe0166030c03 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 6 Sep 2023 11:01:36 -0700 Subject: [PATCH 0702/1206] [3.12] gh-109002: Ensure only one wheel for each vendored package (GH-109003) (#109005) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Output with one wheel: ``` ⯠GITHUB_ACTIONS=true ./Tools/build/verify_ensurepip_wheels.py Verifying checksum for /Volumes/RAMDisk/cpython/Lib/ensurepip/_bundled/pip-23.2.1-py3-none-any.whl. Expected digest: 7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be Actual digest: 7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be ::notice file=/Volumes/RAMDisk/cpython/Lib/ensurepip/_bundled/pip-23.2.1-py3-none-any.whl::Successfully verified the checksum of the pip wheel. ``` Output with two wheels: ``` ⯠GITHUB_ACTIONS=true ./Tools/build/verify_ensurepip_wheels.py ::error file=/Volumes/RAMDisk/cpython/Lib/ensurepip/_bundled/pip-22.0.4-py3-none-any.whl::Found more than one wheel for package pip. ::error file=/Volumes/RAMDisk/cpython/Lib/ensurepip/_bundled/pip-23.2.1-py3-none-any.whl::Found more than one wheel for package pip. ``` Output without wheels: ``` ⯠GITHUB_ACTIONS=true ./Tools/build/verify_ensurepip_wheels.py ::error file=::Could not find a pip wheel on disk. ``` (cherry picked from commit f8a047941f2e4a1848700c21d58a08c9ec6a9c68) Co-authored-by: Åukasz Langa --- Tools/build/verify_ensurepip_wheels.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Tools/build/verify_ensurepip_wheels.py b/Tools/build/verify_ensurepip_wheels.py index 09fd5d9e3103ac..29897425da6c03 100755 --- a/Tools/build/verify_ensurepip_wheels.py +++ b/Tools/build/verify_ensurepip_wheels.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 """ Compare checksums for wheels in :mod:`ensurepip` against the Cheeseshop. @@ -35,11 +35,17 @@ def print_error(file_path: str, message: str) -> None: def verify_wheel(package_name: str) -> bool: # Find the package on disk - package_path = next(WHEEL_DIR.glob(f"{package_name}*.whl"), None) - if not package_path: - print_error("", f"Could not find a {package_name} wheel on disk.") + package_paths = list(WHEEL_DIR.glob(f"{package_name}*.whl")) + if len(package_paths) != 1: + if package_paths: + for p in package_paths: + print_error(p, f"Found more than one wheel for package {package_name}.") + else: + print_error("", f"Could not find a {package_name} wheel on disk.") return False + package_path = package_paths[0] + print(f"Verifying checksum for {package_path}.") # Find the version of the package used by ensurepip From e65401d24512503f50baab1543928102def53b5a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 8 Sep 2023 16:09:49 +0300 Subject: [PATCH 0703/1206] [3.12] C API tests: use special markers to test that output parameters were set (GH-109014) (#109023) [3.12] C API tests: use special markers to test that output parameters were set (GH-109014). (cherry picked from commit bf414b7fcb7c8ba780a5e1d9f320ecef0c7f9488) --- Modules/_testcapi/code.c | 4 +++- Modules/_testcapi/dict.c | 4 +++- Modules/_testcapi/exceptions.c | 11 ++++++---- Modules/_testcapi/unicode.c | 38 +++++++++++++++++++++------------- Modules/_testcapi/util.h | 7 +++++++ Modules/_testcapimodule.c | 6 ++++++ 6 files changed, 50 insertions(+), 20 deletions(-) diff --git a/Modules/_testcapi/code.c b/Modules/_testcapi/code.c index cadaf5eb94692e..8287268b6128ca 100644 --- a/Modules/_testcapi/code.c +++ b/Modules/_testcapi/code.c @@ -1,4 +1,5 @@ #include "parts.h" +#include "util.h" static Py_ssize_t get_code_extra_index(PyInterpreterState* interp) { @@ -74,7 +75,7 @@ test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) } // Check the value is initially NULL - void *extra; + void *extra = UNINITIALIZED_PTR; int res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra); if (res < 0) { goto finally; @@ -87,6 +88,7 @@ test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) goto finally; } // Assert it was set correctly + extra = UNINITIALIZED_PTR; res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra); if (res < 0) { goto finally; diff --git a/Modules/_testcapi/dict.c b/Modules/_testcapi/dict.c index bcc86c9a84cd2e..374464c40d582f 100644 --- a/Modules/_testcapi/dict.c +++ b/Modules/_testcapi/dict.c @@ -212,7 +212,7 @@ dict_items(PyObject *self, PyObject *obj) static PyObject * dict_next(PyObject *self, PyObject *args) { - PyObject *mapping, *key, *value; + PyObject *mapping, *key = UNINITIALIZED_PTR, *value = UNINITIALIZED_PTR; Py_ssize_t pos; if (!PyArg_ParseTuple(args, "On", &mapping, &pos)) { return NULL; @@ -222,6 +222,8 @@ dict_next(PyObject *self, PyObject *args) if (rc != 0) { return Py_BuildValue("inOO", rc, pos, key, value); } + assert(key == UNINITIALIZED_PTR); + assert(value == UNINITIALIZED_PTR); if (PyErr_Occurred()) { return NULL; } diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index 9756c3778ca524..c511c6d071b6f1 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -121,12 +121,15 @@ _testcapi_exc_set_object_fetch_impl(PyObject *module, PyObject *exc, PyObject *obj) /*[clinic end generated code: output=7a5ff5f6d3cf687f input=77ec686f1f95fa38]*/ { - PyObject *type; - PyObject *value; - PyObject *tb; + PyObject *type = UNINITIALIZED_PTR; + PyObject *value = UNINITIALIZED_PTR; + PyObject *tb = UNINITIALIZED_PTR; PyErr_SetObject(exc, obj); PyErr_Fetch(&type, &value, &tb); + assert(type != UNINITIALIZED_PTR); + assert(value != UNINITIALIZED_PTR); + assert(tb != UNINITIALIZED_PTR); Py_XDECREF(type); Py_XDECREF(tb); return value; @@ -245,7 +248,7 @@ _testcapi_set_exc_info_impl(PyObject *module, PyObject *new_type, PyObject *new_value, PyObject *new_tb) /*[clinic end generated code: output=b55fa35dec31300e input=ea9f19e0f55fe5b3]*/ { - PyObject *type, *value, *tb; + PyObject *type = UNINITIALIZED_PTR, *value = UNINITIALIZED_PTR, *tb = UNINITIALIZED_PTR; PyErr_GetExcInfo(&type, &value, &tb); Py_INCREF(new_type); diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index de899b679ca8f8..3f2964e4c7bf85 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -491,7 +491,7 @@ static PyObject * unicode_aswidecharstring(PyObject *self, PyObject *args) { PyObject *unicode, *result; - Py_ssize_t size = 100; + Py_ssize_t size = UNINITIALIZED_SIZE; wchar_t *buffer; if (!PyArg_ParseTuple(args, "O", &unicode)) @@ -499,8 +499,10 @@ unicode_aswidecharstring(PyObject *self, PyObject *args) NULLABLE(unicode); buffer = PyUnicode_AsWideCharString(unicode, &size); - if (buffer == NULL) + if (buffer == NULL) { + assert(size == UNINITIALIZED_SIZE); return NULL; + } result = PyUnicode_FromWideChar(buffer, size + 1); PyMem_Free(buffer); @@ -625,15 +627,17 @@ unicode_asutf8andsize(PyObject *self, PyObject *args) PyObject *unicode; Py_ssize_t buflen; const char *s; - Py_ssize_t size = -100; + Py_ssize_t size = UNINITIALIZED_SIZE; if (!PyArg_ParseTuple(args, "On", &unicode, &buflen)) return NULL; NULLABLE(unicode); s = PyUnicode_AsUTF8AndSize(unicode, &size); - if (s == NULL) + if (s == NULL) { + assert(size == UNINITIALIZED_SIZE); return NULL; + } return Py_BuildValue("(y#n)", s, buflen, size); } @@ -735,7 +739,7 @@ unicode_decodeutf7stateful(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - Py_ssize_t consumed; + Py_ssize_t consumed = UNINITIALIZED_SIZE; PyObject *result; if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) @@ -743,6 +747,7 @@ unicode_decodeutf7stateful(PyObject *self, PyObject *args) result = PyUnicode_DecodeUTF7Stateful(data, size, errors, &consumed); if (!result) { + assert(consumed == UNINITIALIZED_SIZE); return NULL; } return Py_BuildValue("(Nn)", result, consumed); @@ -769,7 +774,7 @@ unicode_decodeutf8stateful(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - Py_ssize_t consumed = 123456789; + Py_ssize_t consumed = UNINITIALIZED_SIZE; PyObject *result; if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) @@ -777,6 +782,7 @@ unicode_decodeutf8stateful(PyObject *self, PyObject *args) result = PyUnicode_DecodeUTF8Stateful(data, size, errors, &consumed); if (!result) { + assert(consumed == UNINITIALIZED_SIZE); return NULL; } return Py_BuildValue("(Nn)", result, consumed); @@ -797,7 +803,7 @@ unicode_decodeutf32(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - int byteorder; + int byteorder = UNINITIALIZED_INT; PyObject *result; if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) @@ -817,8 +823,8 @@ unicode_decodeutf32stateful(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - int byteorder; - Py_ssize_t consumed; + int byteorder = UNINITIALIZED_INT; + Py_ssize_t consumed = UNINITIALIZED_SIZE; PyObject *result; if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) @@ -826,6 +832,7 @@ unicode_decodeutf32stateful(PyObject *self, PyObject *args) result = PyUnicode_DecodeUTF32Stateful(data, size, errors, &byteorder, &consumed); if (!result) { + assert(consumed == UNINITIALIZED_SIZE); return NULL; } return Py_BuildValue("(iNn)", byteorder, result, consumed); @@ -846,7 +853,7 @@ unicode_decodeutf16(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - int byteorder = 0; + int byteorder = UNINITIALIZED_INT; PyObject *result; if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) @@ -866,8 +873,8 @@ unicode_decodeutf16stateful(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - int byteorder; - Py_ssize_t consumed; + int byteorder = UNINITIALIZED_INT; + Py_ssize_t consumed = UNINITIALIZED_SIZE; PyObject *result; if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) @@ -875,6 +882,7 @@ unicode_decodeutf16stateful(PyObject *self, PyObject *args) result = PyUnicode_DecodeUTF16Stateful(data, size, errors, &byteorder, &consumed); if (!result) { + assert(consumed == UNINITIALIZED_SIZE); return NULL; } return Py_BuildValue("(iNn)", byteorder, result, consumed); @@ -1028,7 +1036,7 @@ unicode_decodembcsstateful(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - Py_ssize_t consumed; + Py_ssize_t consumed = UNINITIALIZED_SIZE; PyObject *result; if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) @@ -1036,6 +1044,7 @@ unicode_decodembcsstateful(PyObject *self, PyObject *args) result = PyUnicode_DecodeMBCSStateful(data, size, errors, &consumed); if (!result) { + assert(consumed == UNINITIALIZED_SIZE); return NULL; } return Py_BuildValue("(Nn)", result, consumed); @@ -1049,7 +1058,7 @@ unicode_decodecodepagestateful(PyObject *self, PyObject *args) const char *data; Py_ssize_t size; const char *errors = NULL; - Py_ssize_t consumed; + Py_ssize_t consumed = UNINITIALIZED_SIZE; PyObject *result; if (!PyArg_ParseTuple(args, "iy#|z", &code_page, &data, &size, &errors)) @@ -1057,6 +1066,7 @@ unicode_decodecodepagestateful(PyObject *self, PyObject *args) result = PyUnicode_DecodeCodePageStateful(code_page, data, size, errors, &consumed); if (!result) { + assert(consumed == UNINITIALIZED_SIZE); return NULL; } return Py_BuildValue("(Nn)", result, consumed); diff --git a/Modules/_testcapi/util.h b/Modules/_testcapi/util.h index 05ccb12a4444f8..4cf7e226382bfc 100644 --- a/Modules/_testcapi/util.h +++ b/Modules/_testcapi/util.h @@ -23,3 +23,10 @@ assert(!PyErr_Occurred()); \ return PyLong_FromSsize_t(_ret); \ } while (0) + +/* Marker to check that pointer value was set. */ +#define UNINITIALIZED_PTR ((void *)"uninitialized") +/* Marker to check that Py_ssize_t value was set. */ +#define UNINITIALIZED_SIZE ((Py_ssize_t)236892191) +/* Marker to check that integer value was set. */ +#define UNINITIALIZED_INT (63256717) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index dec64af7a59cb4..4904e8ae33fa1a 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -221,10 +221,13 @@ test_dict_inner(int count) Py_DECREF(v); } + k = v = UNINITIALIZED_PTR; while (PyDict_Next(dict, &pos, &k, &v)) { PyObject *o; iterations++; + assert(k != UNINITIALIZED_PTR); + assert(v != UNINITIALIZED_PTR); i = PyLong_AS_LONG(v) + 1; o = PyLong_FromLong(i); if (o == NULL) @@ -234,7 +237,10 @@ test_dict_inner(int count) return -1; } Py_DECREF(o); + k = v = UNINITIALIZED_PTR; } + assert(k == UNINITIALIZED_PTR); + assert(v == UNINITIALIZED_PTR); Py_DECREF(dict); From 19d822681bf18f111191ea8f3fe5127ea0b2e6e0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:10:18 -0700 Subject: [PATCH 0704/1206] [3.12] GH-90690: Mention removal of ``PRECALL`` in What's New (GH-103910) (#109027) GH-90690: Mention removal of ``PRECALL`` in What's New (GH-103910) (cherry picked from commit f9bd6e49ae58e0ba2934f29dd0f3299ba844cc8d) Co-authored-by: Anthony Shaw Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8bd642245d4fe3..249303f1e8877f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -998,6 +998,9 @@ CPython bytecode changes * Remove the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` instructions. (Contributed by Irit Katriel in :gh:`102859`.) +* Removed the :opcode:`!PRECALL` instruction. (Contributed by Mark Shannon in + :gh:`92925`.) + * Add the :opcode:`LOAD_FAST_AND_CLEAR` instruction as part of the implementation of :pep:`709`. (Contributed by Carl Meyer in :gh:`101441`.) From ef0dbfb5a83ba2ccfa138faab0a4e920e8c0c44f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:11:16 -0700 Subject: [PATCH 0705/1206] [3.12] GH-108202: Document ``calendar``'s command-line interface (GH-109020) (#109030) GH-108202: Document ``calendar``'s command-line interface (GH-109020) (cherry picked from commit f0f96a9f40762499811681d405b6f922b6ed7a55) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/library/calendar.rst | 143 +++++++++++++++++++++++++++++++++++++++ Lib/calendar.py | 2 +- 2 files changed, 144 insertions(+), 1 deletion(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 1868eb1cd359c4..157a7537f97dc6 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -489,3 +489,146 @@ The :mod:`calendar` module defines the following exceptions: Module :mod:`time` Low-level time related functions. + + +.. _calendar-cli: + +Command-Line Usage +------------------ + +.. versionadded:: 2.5 + +The :mod:`calendar` module can be executed as a script from the command line +to interactively print a calendar. + +.. code-block:: shell + + python -m calendar [-h] [-L LOCALE] [-e ENCODING] [-t {text,html}] + [-w WIDTH] [-l LINES] [-s SPACING] [-m MONTHS] [-c CSS] + [year] [month] + + +For example, to print a calendar for the year 2000: + +.. code-block:: console + + $ python -m calendar 2000 + 2000 + + January February March + Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su + 1 2 1 2 3 4 5 6 1 2 3 4 5 + 3 4 5 6 7 8 9 7 8 9 10 11 12 13 6 7 8 9 10 11 12 + 10 11 12 13 14 15 16 14 15 16 17 18 19 20 13 14 15 16 17 18 19 + 17 18 19 20 21 22 23 21 22 23 24 25 26 27 20 21 22 23 24 25 26 + 24 25 26 27 28 29 30 28 29 27 28 29 30 31 + 31 + + April May June + Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su + 1 2 1 2 3 4 5 6 7 1 2 3 4 + 3 4 5 6 7 8 9 8 9 10 11 12 13 14 5 6 7 8 9 10 11 + 10 11 12 13 14 15 16 15 16 17 18 19 20 21 12 13 14 15 16 17 18 + 17 18 19 20 21 22 23 22 23 24 25 26 27 28 19 20 21 22 23 24 25 + 24 25 26 27 28 29 30 29 30 31 26 27 28 29 30 + + July August September + Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su + 1 2 1 2 3 4 5 6 1 2 3 + 3 4 5 6 7 8 9 7 8 9 10 11 12 13 4 5 6 7 8 9 10 + 10 11 12 13 14 15 16 14 15 16 17 18 19 20 11 12 13 14 15 16 17 + 17 18 19 20 21 22 23 21 22 23 24 25 26 27 18 19 20 21 22 23 24 + 24 25 26 27 28 29 30 28 29 30 31 25 26 27 28 29 30 + 31 + + October November December + Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su + 1 1 2 3 4 5 1 2 3 + 2 3 4 5 6 7 8 6 7 8 9 10 11 12 4 5 6 7 8 9 10 + 9 10 11 12 13 14 15 13 14 15 16 17 18 19 11 12 13 14 15 16 17 + 16 17 18 19 20 21 22 20 21 22 23 24 25 26 18 19 20 21 22 23 24 + 23 24 25 26 27 28 29 27 28 29 30 25 26 27 28 29 30 31 + 30 31 + + +The following options are accepted: + +.. program:: calendar + + +.. option:: --help, -h + + Show the help message and exit. + + +.. option:: --locale LOCALE, -L LOCALE + + The locale to use for month and weekday names. + Defaults to English. + + +.. option:: --encoding ENCODING, -e ENCODING + + The encoding to use for output. + :option:`--encoding` is required if :option:`--locale` is set. + + +.. option:: --type {text,html}, -t {text,html} + + Print the calendar to the terminal as text, + or as an HTML document. + + +.. option:: year + + The year to print the calendar for. + Must be a number between 1 and 9999. + Defaults to the current year. + + +.. option:: month + + The month of the specified :option:`year` to print the calendar for. + Must be a number between 1 and 12, + and may only be used in text mode. + Defaults to printing a calendar for the full year. + + +*Text-mode options:* + +.. option:: --width WIDTH, -w WIDTH + + The width of the date column in terminal columns. + The date is printed centred in the column. + Any value lower than 2 is ignored. + Defaults to 2. + + +.. option:: --lines LINES, -l LINES + + The number of lines for each week in terminal rows. + The date is printed top-aligned. + Any value lower than 1 is ignored. + Defaults to 1. + + +.. option:: --spacing SPACING, -s SPACING + + The space between months in columns. + Any value lower than 2 is ignored. + Defaults to 6. + + +.. option:: --months MONTHS, -m MONTHS + + The number of months printed per row. + Defaults to 3. + + +*HTML-mode options:* + +.. option:: --css CSS, -c CSS + + The path of a CSS stylesheet to use for the calendar. + This must either be relative to the generated HTML, + or an absolute HTTP or ``file:///`` URL. diff --git a/Lib/calendar.py b/Lib/calendar.py index ea56f12ccc41d0..baab52a1578929 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -723,7 +723,7 @@ def main(args): parser.add_argument( "-L", "--locale", default=None, - help="locale to be used from month and weekday names" + help="locale to use for month and weekday names" ) parser.add_argument( "-e", "--encoding", From 579d78227627abf7edca0637de167e27946dc276 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:11:32 -0700 Subject: [PATCH 0706/1206] [3.12] Docs: Fix typo in datetime.tzinfo docstring (GH-107257) (#109032) Docs: Fix typo in datetime.tzinfo docstring (GH-107257) (cherry picked from commit 60a9eea3f56c002356998f5532b3ad870a1ffa8e) Co-authored-by: Mikhail Samylov Co-authored-by: Paul Ganssle <1377457+pganssle@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Lib/_pydatetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index 549fcda19dccf2..a6d43399f9e703 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -1236,7 +1236,7 @@ def __reduce__(self): class tzinfo: """Abstract base class for time zone info classes. - Subclasses must override the name(), utcoffset() and dst() methods. + Subclasses must override the tzname(), utcoffset() and dst() methods. """ __slots__ = () From c9dc2bc0de367308fbac1ab01a3e9ccb8cd6f5ba Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:12:29 -0700 Subject: [PATCH 0707/1206] [3.12] gh-109015: Add test.support.socket_helper.tcp_blackhole() (GH-109016) (#109041) gh-109015: Add test.support.socket_helper.tcp_blackhole() (GH-109016) Skip test_asyncio, test_imaplib and test_socket tests if FreeBSD TCP blackhole is enabled (net.inet.tcp.blackhole=2). (cherry picked from commit a52a3509770f29f940cda9307704908949912276) Co-authored-by: Victor Stinner --- Lib/test/support/socket_helper.py | 60 +++++++++++++++++++ Lib/test/test_asyncio/test_events.py | 3 + Lib/test/test_asyncio/test_sock_lowlevel.py | 4 ++ Lib/test/test_asyncio/test_sslproto.py | 3 + Lib/test/test_imaplib.py | 1 + Lib/test/test_socket.py | 2 + ...-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst | 6 ++ 7 files changed, 79 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst diff --git a/Lib/test/support/socket_helper.py b/Lib/test/support/socket_helper.py index 78409238db8954..e85d912c778dea 100644 --- a/Lib/test/support/socket_helper.py +++ b/Lib/test/support/socket_helper.py @@ -3,6 +3,7 @@ import os.path import socket import sys +import subprocess import tempfile import unittest @@ -283,3 +284,62 @@ def create_unix_domain_name(): """ return tempfile.mktemp(prefix="test_python_", suffix='.sock', dir=os.path.curdir) + + +# consider that sysctl values should not change while tests are running +_sysctl_cache = {} + +def _get_sysctl(name): + """Get a sysctl value as an integer.""" + try: + return _sysctl_cache[name] + except KeyError: + pass + + # At least Linux and FreeBSD support the "-n" option + cmd = ['sysctl', '-n', name] + proc = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True) + if proc.returncode: + support.print_warning(f'{' '.join(cmd)!r} command failed with ' + f'exit code {proc.returncode}') + # cache the error to only log the warning once + _sysctl_cache[name] = None + return None + output = proc.stdout + + # Parse '0\n' to get '0' + try: + value = int(output.strip()) + except Exception as exc: + support.print_warning(f'Failed to parse {' '.join(cmd)!r} ' + f'command output {output!r}: {exc!r}') + # cache the error to only log the warning once + _sysctl_cache[name] = None + return None + + _sysctl_cache[name] = value + return value + + +def tcp_blackhole(): + if not sys.platform.startswith('freebsd'): + return False + + # gh-109015: test if FreeBSD TCP blackhole is enabled + value = _get_sysctl('net.inet.tcp.blackhole') + if value is None: + # don't skip if we fail to get the sysctl value + return False + return (value != 0) + + +def skip_if_tcp_blackhole(test): + """Decorator skipping test if TCP blackhole is enabled.""" + skip_if = unittest.skipIf( + tcp_blackhole(), + "TCP blackhole is enabled (sysctl net.inet.tcp.blackhole)" + ) + return skip_if(test) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index b9069056c3a436..30cc8fd80bfe94 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -671,6 +671,7 @@ def test_create_connection_local_addr(self): self.assertEqual(port, expected) tr.close() + @socket_helper.skip_if_tcp_blackhole def test_create_connection_local_addr_skip_different_family(self): # See https://github.com/python/cpython/issues/86508 port1 = socket_helper.find_unused_port() @@ -692,6 +693,7 @@ async def getaddrinfo(host, port, *args, **kwargs): with self.assertRaises(OSError): self.loop.run_until_complete(f) + @socket_helper.skip_if_tcp_blackhole def test_create_connection_local_addr_nomatch_family(self): # See https://github.com/python/cpython/issues/86508 port1 = socket_helper.find_unused_port() @@ -1271,6 +1273,7 @@ def connection_made(self, transport): server.close() + @socket_helper.skip_if_tcp_blackhole def test_server_close(self): f = self.loop.create_server(MyProto, '0.0.0.0', 0) server = self.loop.run_until_complete(f) diff --git a/Lib/test/test_asyncio/test_sock_lowlevel.py b/Lib/test/test_asyncio/test_sock_lowlevel.py index b829fd4cc69fff..075113cbe8e4a6 100644 --- a/Lib/test/test_asyncio/test_sock_lowlevel.py +++ b/Lib/test/test_asyncio/test_sock_lowlevel.py @@ -10,6 +10,10 @@ from test import support from test.support import socket_helper +if socket_helper.tcp_blackhole(): + raise unittest.SkipTest('Not relevant to ProactorEventLoop') + + def tearDownModule(): asyncio.set_event_loop_policy(None) diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py index 52a45f1c7c6e96..37d015339761c6 100644 --- a/Lib/test/test_asyncio/test_sslproto.py +++ b/Lib/test/test_asyncio/test_sslproto.py @@ -5,6 +5,7 @@ import unittest import weakref from test import support +from test.support import socket_helper from unittest import mock try: import ssl @@ -350,6 +351,7 @@ async def client(addr): support.gc_collect() self.assertIsNone(client_context()) + @socket_helper.skip_if_tcp_blackhole def test_start_tls_client_buf_proto_1(self): HELLO_MSG = b'1' * self.PAYLOAD_SIZE @@ -502,6 +504,7 @@ async def client(addr): asyncio.wait_for(client(srv.addr), timeout=support.SHORT_TIMEOUT)) + @socket_helper.skip_if_tcp_blackhole def test_start_tls_server_1(self): HELLO_MSG = b'1' * self.PAYLOAD_SIZE ANSWER = b'answer' diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 60f5b671b1da48..cfa1c107a4b01d 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -74,6 +74,7 @@ def test_that_Time2Internaldate_returns_a_result(self): for t in self.timevalues(): imaplib.Time2Internaldate(t) + @socket_helper.skip_if_tcp_blackhole def test_imap4_host_default_value(self): # Check whether the IMAP4_PORT is truly unavailable. with socket.socket() as s: diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 0eaf64257c3b81..f35618e0281e70 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5288,6 +5288,7 @@ def mocked_socket_module(self): finally: socket.socket = old_socket + @socket_helper.skip_if_tcp_blackhole def test_connect(self): port = socket_helper.find_unused_port() cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -5296,6 +5297,7 @@ def test_connect(self): cli.connect((HOST, port)) self.assertEqual(cm.exception.errno, errno.ECONNREFUSED) + @socket_helper.skip_if_tcp_blackhole def test_create_connection(self): # Issue #9792: errors raised by create_connection() should have # a proper errno attribute. diff --git a/Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst b/Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst new file mode 100644 index 00000000000000..cb641be9312e1a --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst @@ -0,0 +1,6 @@ +Fix test_asyncio, test_imaplib and test_socket tests on FreeBSD if the TCP +blackhole is enabled (``sysctl net.inet.tcp.blackhole``). Skip the few tests +which failed with ``ETIMEDOUT`` which such non standard configuration. +Currently, the `FreeBSD GCP image enables TCP and UDP blackhole +`_ (``sysctl net.inet.tcp.blackhole=2`` +and ``sysctl net.inet.udp.blackhole=1``). Patch by Victor Stinner. From 5ca2a68bbe385ccd3eb2e3291a1d849b1a852c5b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 8 Sep 2023 07:12:48 -0600 Subject: [PATCH 0708/1206] [3.12] gh-107732: Mention dir support in importlib.resources docs (GH-107734) (#109058) gh-107732: Mention dir support in importlib.resources docs (#107734) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade (cherry picked from commit 9f0c0a46f00d687e921990ee83894b2f4ce8a6e7) Co-authored-by: Shahriar Heidrich --- Doc/library/importlib.resources.rst | 13 ++++++++----- Doc/whatsnew/3.12.rst | 6 ++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/library/importlib.resources.rst b/Doc/library/importlib.resources.rst index 755693840fecd8..fecb7ef2a8a71c 100644 --- a/Doc/library/importlib.resources.rst +++ b/Doc/library/importlib.resources.rst @@ -82,19 +82,22 @@ for example, a package and its resources can be imported from a zip file using .. function:: as_file(traversable) Given a :class:`~importlib.resources.abc.Traversable` object representing - a file, typically from :func:`importlib.resources.files`, return - a context manager for use in a :keyword:`with` statement. + a file or directory, typically from :func:`importlib.resources.files`, + return a context manager for use in a :keyword:`with` statement. The context manager provides a :class:`pathlib.Path` object. - Exiting the context manager cleans up any temporary file created when the - resource was extracted from e.g. a zip file. + Exiting the context manager cleans up any temporary file or directory + created when the resource was extracted from e.g. a zip file. Use ``as_file`` when the Traversable methods - (``read_text``, etc) are insufficient and an actual file on + (``read_text``, etc) are insufficient and an actual file or directory on the file system is required. .. versionadded:: 3.9 + .. versionchanged:: 3.12 + Added support for ``traversable`` representing a directory. + Deprecated functions ^^^^^^^^^^^^^^^^^^^^ diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 249303f1e8877f..57f33e639de69e 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -631,6 +631,12 @@ fractions * Objects of type :class:`fractions.Fraction` now support float-style formatting. (Contributed by Mark Dickinson in :gh:`100161`.) +importlib.resources +------------------- + +* :func:`importlib.resources.as_file` now supports resource directories. + (Contributed by Jason R. Coombs in :gh:`97930`.) + inspect ------- From eeaae92b496bf75e8c937af1d5fd277d71fb7334 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:13:31 -0700 Subject: [PATCH 0709/1206] [3.12] gh-107755: Document the correct default value of slice step (GH-107756) (#108955) gh-107755: Document the correct default value of slice step (GH-107756) Document the correct default value of slice step. (cherry picked from commit 9bf350b0662fcf1a8b43b9293e6c8ecf3c711561) Co-authored-by: wim glenn --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index b271067ae639c5..593591f6ceca17 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1631,7 +1631,7 @@ are always available. They are listed here in alphabetical order. .. class:: slice(stop) - slice(start, stop, step=1) + slice(start, stop, step=None) Return a :term:`slice` object representing the set of indices specified by ``range(start, stop, step)``. The *start* and *step* arguments default to From 0855b2c8b69f02f86f837875acda148479e6a061 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 8 Sep 2023 15:14:17 +0200 Subject: [PATCH 0710/1206] [3.12] gh-108834: Sync libregrtest with the main branch (#108966) * gh-108834: regrtest reruns failed tests in subprocesses (#108839) When using --rerun option, regrtest now re-runs failed tests in verbose mode in fresh worker processes to have more deterministic behavior. So it can write its final report even if a test killed a worker progress. Add --fail-rerun option to regrtest: exit with non-zero exit code if a test failed pass passed when re-run in verbose mode (in a fresh process). That's now more useful since tests can pass when re-run in a fresh worker progress, whereas they failed when run after other tests when tests are run sequentially. Rename --verbose2 option (-w) to --rerun. Keep --verbose2 as a deprecated alias. Changes: * Fix and enhance statistics in regrtest summary. Add "(filtered)" when --match and/or --ignore options are used. * Add RunTests class. * Add TestResult.get_rerun_match_tests() method * Rewrite code to serialize/deserialize worker arguments as JSON using a new WorkerJob class. * Fix stats when a test is run with --forever --rerun. * If failed test names cannot be parsed, log a warning and don't filter tests. * test_regrtest.test_rerun_success() now uses a marker file, since the test is re-run in a separated process. * Add tests on normalize_test_name() function. * Add test_success() and test_skip() tests to test_regrtest. (cherry picked from commit 31c2945f143c6b80c837fcf09a5cfb85fea9ea4c) * gh-108834: regrtest --fail-rerun exits with code 5 (#108896) When the --fail-rerun option is used and a test fails and then pass, regrtest now uses exit code 5 ("rerun) instead of 2 ("bad test"). (cherry picked from commit 1170d5a292b46f754cd29c245a040f1602f70301) * gh-108416: Mark slow but not CPU bound test methods with requires_resource('walltime') (GH-108480) (cherry picked from commit 1e0d62793a84001e92f1c80b511d3a212b435acc) * Manually sync Lib/test/libregrtest/ from main --------- Co-authored-by: Serhiy Storchaka --- Lib/test/_test_multiprocessing.py | 3 + Lib/test/bisect_cmd.py | 7 +- Lib/test/libregrtest/cmdline.py | 15 +- Lib/test/libregrtest/main.py | 592 +++++++++--------- Lib/test/libregrtest/runtest.py | 228 +++++-- Lib/test/libregrtest/runtest_mp.py | 179 ++++-- Lib/test/libregrtest/utils.py | 2 +- Lib/test/support/__init__.py | 1 - Lib/test/support/testresult.py | 3 + Lib/test/test_concurrent_futures/executor.py | 1 + Lib/test/test_concurrent_futures/test_wait.py | 3 + Lib/test/test_eintr.py | 1 + Lib/test/test_faulthandler.py | 1 + Lib/test/test_httplib.py | 1 + Lib/test/test_imaplib.py | 5 +- Lib/test/test_io.py | 6 + Lib/test/test_logging.py | 1 + Lib/test/test_poll.py | 3 +- Lib/test/test_regrtest.py | 306 ++++++--- Lib/test/test_signal.py | 1 + Lib/test/test_smtpnet.py | 1 + Lib/test/test_ssl.py | 2 + Lib/test/test_subprocess.py | 2 + Lib/test/test_urllib2net.py | 5 + Lib/test/test_urllibnet.py | 2 + Lib/test/test_xmlrpc.py | 9 + ...-09-03-02-01-55.gh-issue-108834.iAwXzj.rst | 6 + ...-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst | 2 + ...-09-03-20-15-49.gh-issue-108834.Osvmhf.rst | 3 + 29 files changed, 892 insertions(+), 499 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst create mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst create mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 2e656538e99f3e..044bfc97b8c666 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -675,6 +675,7 @@ def test_close(self): close_queue(q) + @support.requires_resource('walltime') def test_many_processes(self): if self.TYPE == 'threads': self.skipTest('test not appropriate for {}'.format(self.TYPE)) @@ -4953,6 +4954,7 @@ def test_wait_slow(self): def test_wait_socket_slow(self): self.test_wait_socket(True) + @support.requires_resource('walltime') def test_wait_timeout(self): from multiprocessing.connection import wait @@ -4981,6 +4983,7 @@ def signal_and_sleep(cls, sem, period): sem.release() time.sleep(period) + @support.requires_resource('walltime') def test_wait_integer(self): from multiprocessing.connection import wait diff --git a/Lib/test/bisect_cmd.py b/Lib/test/bisect_cmd.py index 0bdd7a43c03f7b..5cb804bd469dc3 100755 --- a/Lib/test/bisect_cmd.py +++ b/Lib/test/bisect_cmd.py @@ -109,9 +109,10 @@ def parse_args(): def main(): args = parse_args() - if '-w' in args.test_args or '--verbose2' in args.test_args: - print("WARNING: -w/--verbose2 option should not be used to bisect!") - print() + for opt in ('-w', '--rerun', '--verbose2'): + if opt in args.test_args: + print(f"WARNING: {opt} option should not be used to bisect!") + print() if args.input: with open(args.input) as fp: diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py index ebe57920d9185c..d1a590d8c1a5b3 100644 --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -107,6 +107,8 @@ cpu - Used for certain CPU-heavy tests. + walltime - Long running but not CPU-bound tests. + subprocess Run all tests for the subprocess module. urlfetch - It is okay to download files required on testing. @@ -129,7 +131,7 @@ ALL_RESOURCES = ('audio', 'curses', 'largefile', 'network', - 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui') + 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'walltime') # Other resources excluded from --use=all: # @@ -156,7 +158,7 @@ def __init__(self, **kwargs) -> None: self.coverdir = 'coverage' self.runleaks = False self.huntrleaks = False - self.verbose2 = False + self.rerun = False self.verbose3 = False self.print_slow = False self.random_seed = None @@ -213,8 +215,10 @@ def _create_parser(): group = parser.add_argument_group('Verbosity') group.add_argument('-v', '--verbose', action='count', help='run tests in verbose mode with output to stdout') - group.add_argument('-w', '--verbose2', action='store_true', + group.add_argument('-w', '--rerun', action='store_true', help='re-run failed tests in verbose mode') + group.add_argument('--verbose2', action='store_true', dest='rerun', + help='deprecated alias to --rerun') group.add_argument('-W', '--verbose3', action='store_true', help='display test output on failure') group.add_argument('-q', '--quiet', action='store_true', @@ -309,6 +313,9 @@ def _create_parser(): group.add_argument('--fail-env-changed', action='store_true', help='if a test file alters the environment, mark ' 'the test as failed') + group.add_argument('--fail-rerun', action='store_true', + help='if a test failed and then passed when re-run, ' + 'mark the tests as failed') group.add_argument('--junit-xml', dest='xmlpath', metavar='FILENAME', help='writes JUnit-style XML results to the specified ' @@ -380,7 +387,7 @@ def _parse_args(args, **kwargs): ns.python = shlex.split(ns.python) if ns.failfast and not (ns.verbose or ns.verbose3): parser.error("-G/--failfast needs either -v or -W") - if ns.pgo and (ns.verbose or ns.verbose2 or ns.verbose3): + if ns.pgo and (ns.verbose or ns.rerun or ns.verbose3): parser.error("--pgo/-v don't go together!") if ns.pgo_extended: ns.pgo = True # pgo_extended implies pgo diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index a357bd9c386c3b..ab03647ca5802f 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -11,11 +11,11 @@ import unittest from test.libregrtest.cmdline import _parse_args from test.libregrtest.runtest import ( - findtests, split_test_packages, runtest, get_abs_module, - PROGRESS_MIN_TIME, State) + findtests, split_test_packages, runtest, abs_module_name, + PROGRESS_MIN_TIME, State, MatchTestsDict, RunTests) from test.libregrtest.setup import setup_tests from test.libregrtest.pgo import setup_pgo_tests -from test.libregrtest.utils import (removepy, count, format_duration, +from test.libregrtest.utils import (strip_py_suffix, count, format_duration, printlist, get_build_info) from test import support from test.support import TestStats @@ -28,18 +28,11 @@ # Must be smaller than buildbot "1200 seconds without output" limit. EXIT_TIMEOUT = 120.0 -# gh-90681: When rerunning tests, we might need to rerun the whole -# class or module suite if some its life-cycle hooks fail. -# Test level hooks are not affected. -_TEST_LIFECYCLE_HOOKS = frozenset(( - 'setUpClass', 'tearDownClass', - 'setUpModule', 'tearDownModule', -)) - EXITCODE_BAD_TEST = 2 -EXITCODE_INTERRUPTED = 130 EXITCODE_ENV_CHANGED = 3 EXITCODE_NO_TESTS_RAN = 4 +EXITCODE_RERUN_FAIL = 5 +EXITCODE_INTERRUPTED = 130 class Regrtest: @@ -72,19 +65,22 @@ def __init__(self): # tests self.tests = [] self.selected = [] + self.all_runtests: list[RunTests] = [] # test results - self.good = [] - self.bad = [] - self.skipped = [] - self.resource_denied = [] - self.environment_changed = [] - self.run_no_tests = [] - self.need_rerun = [] - self.rerun = [] - self.first_result = None + self.good: list[str] = [] + self.bad: list[str] = [] + self.rerun_bad: list[str] = [] + self.skipped: list[str] = [] + self.resource_denied: list[str] = [] + self.environment_changed: list[str] = [] + self.run_no_tests: list[str] = [] + self.rerun: list[str] = [] + + self.need_rerun: list[TestResult] = [] + self.first_state: str | None = None self.interrupted = False - self.stats_dict: dict[str, TestStats] = {} + self.total_stats = TestStats() # used by --slow self.test_times = [] @@ -94,7 +90,7 @@ def __init__(self): # used to display the progress bar "[ 3/100]" self.start_time = time.perf_counter() - self.test_count = '' + self.test_count_text = '' self.test_count_width = 1 # used by --single @@ -107,7 +103,6 @@ def __init__(self): # misc self.win_load_tracker = None self.tmp_dir = None - self.worker_test_name = None def get_executed(self): return (set(self.good) | set(self.bad) | set(self.skipped) @@ -115,11 +110,9 @@ def get_executed(self): | set(self.run_no_tests)) def accumulate_result(self, result, rerun=False): + fail_env_changed = self.ns.fail_env_changed test_name = result.test_name - if result.has_meaningful_duration() and not rerun: - self.test_times.append((result.duration, test_name)) - match result.state: case State.PASSED: self.good.append(test_name) @@ -128,25 +121,24 @@ def accumulate_result(self, result, rerun=False): case State.SKIPPED: self.skipped.append(test_name) case State.RESOURCE_DENIED: - self.skipped.append(test_name) self.resource_denied.append(test_name) case State.INTERRUPTED: self.interrupted = True case State.DID_NOT_RUN: self.run_no_tests.append(test_name) case _: - if result.is_failed(self.ns.fail_env_changed): - if not rerun: - self.bad.append(test_name) - self.need_rerun.append(result) + if result.is_failed(fail_env_changed): + self.bad.append(test_name) + self.need_rerun.append(result) else: - raise ValueError(f"invalid test state: {state!r}") + raise ValueError(f"invalid test state: {result.state!r}") + if result.has_meaningful_duration() and not rerun: + self.test_times.append((result.duration, test_name)) if result.stats is not None: - self.stats_dict[result.test_name] = result.stats - - if rerun and not(result.is_failed(False) or result.state == State.INTERRUPTED): - self.bad.remove(test_name) + self.total_stats.accumulate(result.stats) + if rerun: + self.rerun.append(test_name) xml_data = result.xml_data if xml_data: @@ -180,13 +172,15 @@ def log(self, line=''): print(line, flush=True) def display_progress(self, test_index, text): - if self.ns.quiet: + quiet = self.ns.quiet + pgo = self.ns.pgo + if quiet: return # "[ 51/405/1] test_tcl passed" - line = f"{test_index:{self.test_count_width}}{self.test_count}" + line = f"{test_index:{self.test_count_width}}{self.test_count_text}" fails = len(self.bad) + len(self.environment_changed) - if fails and not self.ns.pgo: + if fails and not pgo: line = f"{line}/{fails}" self.log(f"[{line}] {text}") @@ -196,15 +190,7 @@ def parse_args(self, kwargs): if ns.xmlpath: support.junit_xml_list = self.testsuite_xml = [] - worker_args = ns.worker_args - if worker_args is not None: - from test.libregrtest.runtest_mp import parse_worker_args - ns, test_name = parse_worker_args(ns.worker_args) - ns.worker_args = worker_args - self.worker_test_name = test_name - - # Strip .py extensions. - removepy(ns.args) + strip_py_suffix(ns.args) if ns.huntrleaks: warmup, repetitions, _ = ns.huntrleaks @@ -221,9 +207,18 @@ def parse_args(self, kwargs): self.ns = ns def find_tests(self, tests): + ns = self.ns + single = ns.single + fromfile = ns.fromfile + pgo = ns.pgo + exclude = ns.exclude + test_dir = ns.testdir + starting_test = ns.start + randomize = ns.randomize + self.tests = tests - if self.ns.single: + if single: self.next_single_filename = os.path.join(self.tmp_dir, 'pynexttest') try: with open(self.next_single_filename, 'r') as fp: @@ -232,12 +227,12 @@ def find_tests(self, tests): except OSError: pass - if self.ns.fromfile: + if fromfile: self.tests = [] # regex to match 'test_builtin' in line: # '0:00:00 [ 4/400] test_builtin -- test_dict took 1 sec' regex = re.compile(r'\btest_[a-zA-Z0-9_]+\b') - with open(os.path.join(os_helper.SAVEDCWD, self.ns.fromfile)) as fp: + with open(os.path.join(os_helper.SAVEDCWD, fromfile)) as fp: for line in fp: line = line.split('#', 1)[0] line = line.strip() @@ -245,22 +240,22 @@ def find_tests(self, tests): if match is not None: self.tests.append(match.group()) - removepy(self.tests) + strip_py_suffix(self.tests) - if self.ns.pgo: + if pgo: # add default PGO tests if no tests are specified - setup_pgo_tests(self.ns) + setup_pgo_tests(ns) - exclude = set() - if self.ns.exclude: - for arg in self.ns.args: - exclude.add(arg) - self.ns.args = [] + exclude_tests = set() + if exclude: + for arg in ns.args: + exclude_tests.add(arg) + ns.args = [] - alltests = findtests(testdir=self.ns.testdir, exclude=exclude) + alltests = findtests(testdir=test_dir, exclude=exclude_tests) - if not self.ns.fromfile: - self.selected = self.tests or self.ns.args + if not fromfile: + self.selected = self.tests or ns.args if self.selected: self.selected = split_test_packages(self.selected) else: @@ -268,7 +263,7 @@ def find_tests(self, tests): else: self.selected = self.tests - if self.ns.single: + if single: self.selected = self.selected[:1] try: pos = alltests.index(self.selected[0]) @@ -277,17 +272,17 @@ def find_tests(self, tests): pass # Remove all the selected tests that precede start if it's set. - if self.ns.start: + if starting_test: try: - del self.selected[:self.selected.index(self.ns.start)] + del self.selected[:self.selected.index(starting_test)] except ValueError: - print("Couldn't find starting test (%s), using all tests" - % self.ns.start, file=sys.stderr) + print(f"Cannot find starting test: {starting_test}") + sys.exit(1) - if self.ns.randomize: - if self.ns.random_seed is None: - self.ns.random_seed = random.randrange(10000000) - random.seed(self.ns.random_seed) + if randomize: + if ns.random_seed is None: + ns.random_seed = random.randrange(10000000) + random.seed(ns.random_seed) random.shuffle(self.selected) def list_tests(self): @@ -305,25 +300,63 @@ def _list_cases(self, suite): print(test.id()) def list_cases(self): + ns = self.ns + test_dir = ns.testdir support.verbose = False - support.set_match_tests(self.ns.match_tests, self.ns.ignore_tests) + support.set_match_tests(ns.match_tests, ns.ignore_tests) + skipped = [] for test_name in self.selected: - abstest = get_abs_module(self.ns, test_name) + module_name = abs_module_name(test_name, test_dir) try: - suite = unittest.defaultTestLoader.loadTestsFromName(abstest) + suite = unittest.defaultTestLoader.loadTestsFromName(module_name) self._list_cases(suite) except unittest.SkipTest: - self.skipped.append(test_name) + skipped.append(test_name) - if self.skipped: - print(file=sys.stderr) - print(count(len(self.skipped), "test"), "skipped:", file=sys.stderr) - printlist(self.skipped, file=sys.stderr) + if skipped: + sys.stdout.flush() + stderr = sys.stderr + print(file=stderr) + print(count(len(skipped), "test"), "skipped:", file=stderr) + printlist(skipped, file=stderr) - def rerun_failed_tests(self): - self.log() + def get_rerun_match(self, rerun_list) -> MatchTestsDict: + rerun_match_tests = {} + for result in rerun_list: + match_tests = result.get_rerun_match_tests() + # ignore empty match list + if match_tests: + rerun_match_tests[result.test_name] = match_tests + return rerun_match_tests + + def _rerun_failed_tests(self, need_rerun): + # Configure the runner to re-run tests + ns = self.ns + ns.verbose = True + ns.failfast = False + ns.verbose3 = False + ns.forever = False + if ns.use_mp is None: + ns.use_mp = 1 + + # Get tests to re-run + tests = [result.test_name for result in need_rerun] + match_tests = self.get_rerun_match(need_rerun) + self.set_tests(tests) + + # Clear previously failed tests + self.rerun_bad.extend(self.bad) + self.bad.clear() + self.need_rerun.clear() + # Re-run failed tests + self.log(f"Re-running {len(tests)} failed tests in verbose mode in subprocesses") + runtests = RunTests(tests, match_tests=match_tests, rerun=True) + self.all_runtests.append(runtests) + self._run_tests_mp(runtests) + + def rerun_failed_tests(self, need_rerun): if self.ns.python: # Temp patch for https://github.com/python/cpython/issues/94052 self.log( @@ -332,45 +365,10 @@ def rerun_failed_tests(self): ) return - self.ns.verbose = True - self.ns.failfast = False - self.ns.verbose3 = False - - self.first_result = self.get_tests_result() - - self.log("Re-running failed tests in verbose mode") - rerun_list = list(self.need_rerun) - self.need_rerun.clear() - for result in rerun_list: - test_name = result.test_name - self.rerun.append(test_name) - - errors = result.errors or [] - failures = result.failures or [] - error_names = [ - self.normalize_test_name(test_full_name, is_error=True) - for (test_full_name, *_) in errors] - failure_names = [ - self.normalize_test_name(test_full_name) - for (test_full_name, *_) in failures] - self.ns.verbose = True - orig_match_tests = self.ns.match_tests - if errors or failures: - if self.ns.match_tests is None: - self.ns.match_tests = [] - self.ns.match_tests.extend(error_names) - self.ns.match_tests.extend(failure_names) - matching = "matching: " + ", ".join(self.ns.match_tests) - self.log(f"Re-running {test_name} in verbose mode ({matching})") - else: - self.log(f"Re-running {test_name} in verbose mode") - result = runtest(self.ns, test_name) - self.ns.match_tests = orig_match_tests + self.first_state = self.get_tests_state() - self.accumulate_result(result, rerun=True) - - if result.state == State.INTERRUPTED: - break + print() + self._rerun_failed_tests(need_rerun) if self.bad: print(count(len(self.bad), 'test'), "failed again:") @@ -378,28 +376,17 @@ def rerun_failed_tests(self): self.display_result() - def normalize_test_name(self, test_full_name, *, is_error=False): - short_name = test_full_name.split(" ")[0] - if is_error and short_name in _TEST_LIFECYCLE_HOOKS: - # This means that we have a failure in a life-cycle hook, - # we need to rerun the whole module or class suite. - # Basically the error looks like this: - # ERROR: setUpClass (test.test_reg_ex.RegTest) - # or - # ERROR: setUpModule (test.test_reg_ex) - # So, we need to parse the class / module name. - lpar = test_full_name.index('(') - rpar = test_full_name.index(')') - return test_full_name[lpar + 1: rpar].split('.')[-1] - return short_name - def display_result(self): + pgo = self.ns.pgo + quiet = self.ns.quiet + print_slow = self.ns.print_slow + # If running the test suite for PGO then no one cares about results. - if self.ns.pgo: + if pgo: return print() - print("== Tests result: %s ==" % self.get_tests_result()) + print("== Tests result: %s ==" % self.get_tests_state()) if self.interrupted: print("Test suite interrupted by signal SIGINT.") @@ -410,7 +397,7 @@ def display_result(self): print(count(len(omitted), "test"), "omitted:") printlist(omitted) - if self.good and not self.ns.quiet: + if self.good and not quiet: print() if (not self.bad and not self.skipped @@ -419,7 +406,7 @@ def display_result(self): print("All", end=' ') print(count(len(self.good), "test"), "OK.") - if self.ns.print_slow: + if print_slow: self.test_times.sort(reverse=True) print() print("10 slowest tests:") @@ -437,11 +424,16 @@ def display_result(self): count(len(self.environment_changed), "test"))) printlist(self.environment_changed) - if self.skipped and not self.ns.quiet: + if self.skipped and not quiet: print() print(count(len(self.skipped), "test"), "skipped:") printlist(self.skipped) + if self.resource_denied and not quiet: + print() + print(count(len(self.resource_denied), "test"), "skipped (resource denied):") + printlist(self.resource_denied) + if self.rerun: print() print("%s:" % count(len(self.rerun), "re-run test")) @@ -452,40 +444,58 @@ def display_result(self): print(count(len(self.run_no_tests), "test"), "run no tests:") printlist(self.run_no_tests) - def run_tests_sequential(self): - if self.ns.trace: + def run_test(self, test_index, test_name, previous_test, save_modules): + text = test_name + if previous_test: + text = '%s -- %s' % (text, previous_test) + self.display_progress(test_index, text) + + if self.tracer: + # If we're tracing code coverage, then we don't exit with status + # if on a false return value from main. + cmd = ('result = runtest(self.ns, test_name); ' + 'self.accumulate_result(result)') + ns = dict(locals()) + self.tracer.runctx(cmd, globals=globals(), locals=ns) + result = ns['result'] + else: + result = runtest(self.ns, test_name) + self.accumulate_result(result) + + # Unload the newly imported modules (best effort finalization) + for module in sys.modules.keys(): + if module not in save_modules and module.startswith("test."): + support.unload(module) + + return result + + def run_tests_sequentially(self, runtests): + ns = self.ns + coverage = ns.trace + fail_fast = ns.failfast + fail_env_changed = ns.fail_env_changed + timeout = ns.timeout + + if coverage: import trace self.tracer = trace.Trace(trace=False, count=True) save_modules = sys.modules.keys() msg = "Run tests sequentially" - if self.ns.timeout: - msg += " (timeout: %s)" % format_duration(self.ns.timeout) + if timeout: + msg += " (timeout: %s)" % format_duration(timeout) self.log(msg) previous_test = None - for test_index, test_name in enumerate(self.tests, 1): + tests_iter = runtests.iter_tests() + for test_index, test_name in enumerate(tests_iter, 1): start_time = time.perf_counter() - text = test_name - if previous_test: - text = '%s -- %s' % (text, previous_test) - self.display_progress(test_index, text) - - if self.tracer: - # If we're tracing code coverage, then we don't exit with status - # if on a false return value from main. - cmd = ('result = runtest(self.ns, test_name); ' - 'self.accumulate_result(result)') - ns = dict(locals()) - self.tracer.runctx(cmd, globals=globals(), locals=ns) - result = ns['result'] - else: - result = runtest(self.ns, test_name) - self.accumulate_result(result) + result = self.run_test(test_index, test_name, + previous_test, save_modules) - if result.state == State.INTERRUPTED: + if result.must_stop(fail_fast, fail_env_changed): break previous_test = str(result) @@ -496,26 +506,9 @@ def run_tests_sequential(self): # be quiet: say nothing if the test passed shortly previous_test = None - # Unload the newly imported modules (best effort finalization) - for module in sys.modules.keys(): - if module not in save_modules and module.startswith("test."): - support.unload(module) - - if self.ns.failfast and result.is_failed(self.ns.fail_env_changed): - break - if previous_test: print(previous_test) - def _test_forever(self, tests): - while True: - for test_name in tests: - yield test_name - if self.bad: - return - if self.ns.fail_env_changed and self.environment_changed: - return - def display_header(self): # Print basic platform information print("==", platform.python_implementation(), *sys.version.split()) @@ -528,36 +521,45 @@ def display_header(self): print("== CPU count:", cpu_count) print("== encodings: locale=%s, FS=%s" % (locale.getencoding(), sys.getfilesystemencoding())) + self.display_sanitizers() + + def display_sanitizers(self): + # This makes it easier to remember what to set in your local + # environment when trying to reproduce a sanitizer failure. asan = support.check_sanitizer(address=True) msan = support.check_sanitizer(memory=True) ubsan = support.check_sanitizer(ub=True) - # This makes it easier to remember what to set in your local - # environment when trying to reproduce a sanitizer failure. - if asan or msan or ubsan: - names = [n for n in (asan and "address", - msan and "memory", - ubsan and "undefined behavior") - if n] - print(f"== sanitizers: {', '.join(names)}") - a_opts = os.environ.get("ASAN_OPTIONS") - if asan and a_opts is not None: - print(f"== ASAN_OPTIONS={a_opts}") - m_opts = os.environ.get("ASAN_OPTIONS") - if msan and m_opts is not None: - print(f"== MSAN_OPTIONS={m_opts}") - ub_opts = os.environ.get("UBSAN_OPTIONS") - if ubsan and ub_opts is not None: - print(f"== UBSAN_OPTIONS={ub_opts}") + sanitizers = [] + if asan: + sanitizers.append("address") + if msan: + sanitizers.append("memory") + if ubsan: + sanitizers.append("undefined behavior") + if not sanitizers: + return + + print(f"== sanitizers: {', '.join(sanitizers)}") + for sanitizer, env_var in ( + (asan, "ASAN_OPTIONS"), + (msan, "MSAN_OPTIONS"), + (ubsan, "UBSAN_OPTIONS"), + ): + options= os.environ.get(env_var) + if sanitizer and options is not None: + print(f"== {env_var}={options!r}") def no_tests_run(self): return not any((self.good, self.bad, self.skipped, self.interrupted, self.environment_changed)) - def get_tests_result(self): + def get_tests_state(self): + fail_env_changed = self.ns.fail_env_changed + result = [] if self.bad: result.append("FAILURE") - elif self.ns.fail_env_changed and self.environment_changed: + elif fail_env_changed and self.environment_changed: result.append("ENV CHANGED") elif self.no_tests_run(): result.append("NO TESTS RAN") @@ -569,10 +571,40 @@ def get_tests_result(self): result.append("SUCCESS") result = ', '.join(result) - if self.first_result: - result = '%s then %s' % (self.first_result, result) + if self.first_state: + result = '%s then %s' % (self.first_state, result) return result + def _run_tests_mp(self, runtests: RunTests) -> None: + from test.libregrtest.runtest_mp import run_tests_multiprocess + # If we're on windows and this is the parent runner (not a worker), + # track the load average. + if sys.platform == 'win32': + from test.libregrtest.win_utils import WindowsLoadTracker + + try: + self.win_load_tracker = WindowsLoadTracker() + except PermissionError as error: + # Standard accounts may not have access to the performance + # counters. + print(f'Failed to create WindowsLoadTracker: {error}') + + try: + run_tests_multiprocess(self, runtests) + finally: + if self.win_load_tracker is not None: + self.win_load_tracker.close() + self.win_load_tracker = None + + def set_tests(self, tests): + self.tests = tests + if self.ns.forever: + self.test_count_text = '' + self.test_count_width = 3 + else: + self.test_count_text = '/{}'.format(len(self.tests)) + self.test_count_width = len(self.test_count_text) - 1 + def run_tests(self): # For a partial run, we do not need to clutter the output. if (self.ns.header @@ -590,37 +622,14 @@ def run_tests(self): if self.ns.randomize: print("Using random seed", self.ns.random_seed) - if self.ns.forever: - self.tests = self._test_forever(list(self.selected)) - self.test_count = '' - self.test_count_width = 3 - else: - self.tests = iter(self.selected) - self.test_count = '/{}'.format(len(self.selected)) - self.test_count_width = len(self.test_count) - 1 - + tests = self.selected + self.set_tests(tests) + runtests = RunTests(tests, forever=self.ns.forever) + self.all_runtests.append(runtests) if self.ns.use_mp: - from test.libregrtest.runtest_mp import run_tests_multiprocess - # If we're on windows and this is the parent runner (not a worker), - # track the load average. - if sys.platform == 'win32' and self.worker_test_name is None: - from test.libregrtest.win_utils import WindowsLoadTracker - - try: - self.win_load_tracker = WindowsLoadTracker() - except PermissionError as error: - # Standard accounts may not have access to the performance - # counters. - print(f'Failed to create WindowsLoadTracker: {error}') - - try: - run_tests_multiprocess(self) - finally: - if self.win_load_tracker is not None: - self.win_load_tracker.close() - self.win_load_tracker = None + self._run_tests_mp(runtests) else: - self.run_tests_sequential() + self.run_tests_sequentially(runtests) def finalize(self): if self.next_single_filename: @@ -635,23 +644,29 @@ def finalize(self): r.write_results(show_missing=True, summary=True, coverdir=self.ns.coverdir) - print() - self.display_summary() - if self.ns.runleaks: os.system("leaks %d" % os.getpid()) + self.save_xml_result() + def display_summary(self): duration = time.perf_counter() - self.start_time + first_runtests = self.all_runtests[0] + # the second runtests (re-run failed tests) disables forever, + # use the first runtests + forever = first_runtests.forever + filtered = bool(self.ns.match_tests) or bool(self.ns.ignore_tests) # Total duration + print() print("Total duration: %s" % format_duration(duration)) # Total tests - total = TestStats() - for stats in self.stats_dict.values(): - total.accumulate(stats) - stats = [f'run={total.tests_run:,}'] + total = self.total_stats + text = f'run={total.tests_run:,}' + if filtered: + text = f"{text} (filtered)" + stats = [text] if total.failures: stats.append(f'failures={total.failures:,}') if total.skipped: @@ -659,23 +674,31 @@ def display_summary(self): print(f"Total tests: {' '.join(stats)}") # Total test files - report = [f'success={len(self.good)}'] - if self.bad: - report.append(f'failed={len(self.bad)}') - if self.environment_changed: - report.append(f'env_changed={len(self.environment_changed)}') - if self.skipped: - report.append(f'skipped={len(self.skipped)}') - if self.resource_denied: - report.append(f'resource_denied={len(self.resource_denied)}') - if self.rerun: - report.append(f'rerun={len(self.rerun)}') - if self.run_no_tests: - report.append(f'run_no_tests={len(self.run_no_tests)}') + all_tests = [self.good, self.bad, self.rerun, + self.skipped, + self.environment_changed, self.run_no_tests] + run = sum(map(len, all_tests)) + text = f'run={run}' + if not forever: + ntest = len(first_runtests.tests) + text = f"{text}/{ntest}" + if filtered: + text = f"{text} (filtered)" + report = [text] + for name, tests in ( + ('failed', self.bad), + ('env_changed', self.environment_changed), + ('skipped', self.skipped), + ('resource_denied', self.resource_denied), + ('rerun', self.rerun), + ('run_no_tests', self.run_no_tests), + ): + if tests: + report.append(f'{name}={len(tests)}') print(f"Total test files: {' '.join(report)}") # Result - result = self.get_tests_result() + result = self.get_tests_state() print(f"Result: {result}") def save_xml_result(self): @@ -735,6 +758,9 @@ def set_temp_dir(self): self.tmp_dir = os.path.abspath(self.tmp_dir) + def is_worker(self): + return (self.ns.worker_args is not None) + def create_temp_dir(self): os.makedirs(self.tmp_dir, exist_ok=True) @@ -747,7 +773,8 @@ def create_temp_dir(self): nounce = random.randint(0, 1_000_000) else: nounce = os.getpid() - if self.worker_test_name is not None: + + if self.is_worker(): test_cwd = 'test_python_worker_{}'.format(nounce) else: test_cwd = 'test_python_{}'.format(nounce) @@ -810,48 +837,53 @@ def getloadavg(self): return None + def get_exitcode(self): + exitcode = 0 + if self.bad: + exitcode = EXITCODE_BAD_TEST + elif self.interrupted: + exitcode = EXITCODE_INTERRUPTED + elif self.ns.fail_env_changed and self.environment_changed: + exitcode = EXITCODE_ENV_CHANGED + elif self.no_tests_run(): + exitcode = EXITCODE_NO_TESTS_RAN + elif self.rerun and self.ns.fail_rerun: + exitcode = EXITCODE_RERUN_FAIL + return exitcode + + def action_run_tests(self): + self.run_tests() + self.display_result() + + need_rerun = self.need_rerun + if self.ns.rerun and need_rerun: + self.rerun_failed_tests(need_rerun) + + self.display_summary() + self.finalize() + def _main(self, tests, kwargs): - if self.worker_test_name is not None: + if self.is_worker(): from test.libregrtest.runtest_mp import run_tests_worker - run_tests_worker(self.ns, self.worker_test_name) + run_tests_worker(self.ns.worker_args) + return if self.ns.wait: input("Press any key to continue...") - support.PGO = self.ns.pgo - support.PGO_EXTENDED = self.ns.pgo_extended - setup_tests(self.ns) - self.find_tests(tests) + exitcode = 0 if self.ns.list_tests: self.list_tests() - sys.exit(0) - - if self.ns.list_cases: + elif self.ns.list_cases: self.list_cases() - sys.exit(0) - - self.run_tests() - self.display_result() - - if self.ns.verbose2 and self.bad: - self.rerun_failed_tests() - - self.finalize() - - self.save_xml_result() + else: + self.action_run_tests() + exitcode = self.get_exitcode() - if self.bad: - sys.exit(EXITCODE_BAD_TEST) - if self.interrupted: - sys.exit(EXITCODE_INTERRUPTED) - if self.ns.fail_env_changed and self.environment_changed: - sys.exit(EXITCODE_ENV_CHANGED) - if self.no_tests_run(): - sys.exit(EXITCODE_NO_TESTS_RAN) - sys.exit(0) + sys.exit(exitcode) def main(tests=None, **kwargs): diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index 2c30269fc9fd6d..16ae04191da768 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -1,7 +1,6 @@ import dataclasses import doctest import faulthandler -import functools import gc import importlib import io @@ -20,6 +19,10 @@ from test.libregrtest.utils import clear_caches, format_duration, print_warning +MatchTests = list[str] +MatchTestsDict = dict[str, MatchTests] + + # Avoid enum.Enum to reduce the number of imports when tests are run class State: PASSED = "PASSED" @@ -56,6 +59,41 @@ def has_meaningful_duration(state): State.MULTIPROCESSING_ERROR, State.DID_NOT_RUN} + @staticmethod + def must_stop(state): + return state in { + State.INTERRUPTED, + State.MULTIPROCESSING_ERROR} + + +# gh-90681: When rerunning tests, we might need to rerun the whole +# class or module suite if some its life-cycle hooks fail. +# Test level hooks are not affected. +_TEST_LIFECYCLE_HOOKS = frozenset(( + 'setUpClass', 'tearDownClass', + 'setUpModule', 'tearDownModule', +)) + +def normalize_test_name(test_full_name, *, is_error=False): + short_name = test_full_name.split(" ")[0] + if is_error and short_name in _TEST_LIFECYCLE_HOOKS: + if test_full_name.startswith(('setUpModule (', 'tearDownModule (')): + # if setUpModule() or tearDownModule() failed, don't filter + # tests with the test file name, don't use use filters. + return None + + # This means that we have a failure in a life-cycle hook, + # we need to rerun the whole module or class suite. + # Basically the error looks like this: + # ERROR: setUpClass (test.test_reg_ex.RegTest) + # or + # ERROR: setUpModule (test.test_reg_ex) + # So, we need to parse the class / module name. + lpar = test_full_name.index('(') + rpar = test_full_name.index(')') + return test_full_name[lpar + 1: rpar].split('.')[-1] + return short_name + @dataclasses.dataclass(slots=True) class TestResult: @@ -129,6 +167,58 @@ def set_env_changed(self): if self.state is None or self.state == State.PASSED: self.state = State.ENV_CHANGED + def must_stop(self, fail_fast: bool, fail_env_changed: bool) -> bool: + if State.must_stop(self.state): + return True + if fail_fast and self.is_failed(fail_env_changed): + return True + return False + + def get_rerun_match_tests(self): + match_tests = [] + + errors = self.errors or [] + failures = self.failures or [] + for error_list, is_error in ( + (errors, True), + (failures, False), + ): + for full_name, *_ in error_list: + match_name = normalize_test_name(full_name, is_error=is_error) + if match_name is None: + # 'setUpModule (test.test_sys)': don't filter tests + return None + if not match_name: + error_type = "ERROR" if is_error else "FAIL" + print_warning(f"rerun failed to parse {error_type} test name: " + f"{full_name!r}: don't filter tests") + return None + match_tests.append(match_name) + + return match_tests + + +@dataclasses.dataclass(slots=True, frozen=True) +class RunTests: + tests: list[str] + match_tests: MatchTestsDict | None = None + rerun: bool = False + forever: bool = False + + def get_match_tests(self, test_name) -> MatchTests | None: + if self.match_tests is not None: + return self.match_tests.get(test_name, None) + else: + return None + + def iter_tests(self): + tests = tuple(self.tests) + if self.forever: + while True: + yield from tests + else: + yield from tests + # Minimum duration of a test to display its duration or to mention that # the test is running in background @@ -147,9 +237,6 @@ def set_env_changed(self): "test_multiprocessing_spawn", } -# Storage of uncollectable objects -FOUND_GARBAGE = [] - def findtestdir(path=None): return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir @@ -189,31 +276,41 @@ def split_test_packages(tests, *, testdir=None, exclude=(), return splitted -def get_abs_module(ns: Namespace, test_name: str) -> str: - if test_name.startswith('test.') or ns.testdir: +def abs_module_name(test_name: str, test_dir: str | None) -> str: + if test_name.startswith('test.') or test_dir: return test_name else: # Import it from the test package return 'test.' + test_name -def _runtest_capture_output_timeout_junit(result: TestResult, ns: Namespace) -> None: +def setup_support(ns: Namespace): + support.PGO = ns.pgo + support.PGO_EXTENDED = ns.pgo_extended + support.set_match_tests(ns.match_tests, ns.ignore_tests) + support.failfast = ns.failfast + support.verbose = ns.verbose + if ns.xmlpath: + support.junit_xml_list = [] + else: + support.junit_xml_list = None + + +def _runtest(result: TestResult, ns: Namespace) -> None: # Capture stdout and stderr, set faulthandler timeout, # and create JUnit XML report. - + verbose = ns.verbose output_on_failure = ns.verbose3 + timeout = ns.timeout use_timeout = ( - ns.timeout is not None and threading_helper.can_start_thread + timeout is not None and threading_helper.can_start_thread ) if use_timeout: - faulthandler.dump_traceback_later(ns.timeout, exit=True) + faulthandler.dump_traceback_later(timeout, exit=True) try: - support.set_match_tests(ns.match_tests, ns.ignore_tests) - support.junit_xml_list = xml_list = [] if ns.xmlpath else None - if ns.failfast: - support.failfast = True + setup_support(ns) if output_on_failure: support.verbose = True @@ -247,11 +344,10 @@ def _runtest_capture_output_timeout_junit(result: TestResult, ns: Namespace) -> sys.stderr.flush() else: # Tell tests to be moderately quiet - support.verbose = ns.verbose - - _runtest_env_changed_exc(result, ns, - display_failure=not ns.verbose) + support.verbose = verbose + _runtest_env_changed_exc(result, ns, display_failure=not verbose) + xml_list = support.junit_xml_list if xml_list: import xml.etree.ElementTree as ET result.xml_data = [ET.tostring(x).decode('us-ascii') @@ -276,7 +372,7 @@ def runtest(ns: Namespace, test_name: str) -> TestResult: start_time = time.perf_counter() result = TestResult(test_name) try: - _runtest_capture_output_timeout_junit(result, ns) + _runtest(result, ns) except: if not ns.pgo: msg = traceback.format_exc() @@ -287,9 +383,9 @@ def runtest(ns: Namespace, test_name: str) -> TestResult: return result -def _test_module(the_module): +def run_unittest(test_mod): loader = unittest.TestLoader() - tests = loader.loadTestsFromModule(the_module) + tests = loader.loadTestsFromModule(test_mod) for error in loader.errors: print(error, file=sys.stderr) if loader.errors: @@ -304,7 +400,6 @@ def save_env(ns: Namespace, test_name: str): def regrtest_runner(result, test_func, ns) -> None: # Run test_func(), collect statistics, and detect reference and memory # leaks. - if ns.huntrleaks: from test.libregrtest.refleak import dash_R refleak, test_result = dash_R(ns, result.test_name, test_func) @@ -332,23 +427,24 @@ def regrtest_runner(result, test_func, ns) -> None: result.stats = stats +# Storage of uncollectable objects +FOUND_GARBAGE = [] + + def _load_run_test(result: TestResult, ns: Namespace) -> None: # Load the test function, run the test function. + module_name = abs_module_name(result.test_name, ns.testdir) - abstest = get_abs_module(ns, result.test_name) - - # remove the module from sys.module to reload it if it was already imported - try: - del sys.modules[abstest] - except KeyError: - pass + # Remove the module from sys.module to reload it if it was already imported + sys.modules.pop(module_name, None) - the_module = importlib.import_module(abstest) + test_mod = importlib.import_module(module_name) - if hasattr(the_module, "test_main"): + if hasattr(test_mod, "test_main"): # https://github.com/python/cpython/issues/89392 raise Exception(f"Module {result.test_name} defines test_main() which is no longer supported by regrtest") - test_func = functools.partial(_test_module, the_module) + def test_func(): + return run_unittest(test_mod) try: with save_env(ns, result.test_name): @@ -360,12 +456,12 @@ def _load_run_test(result: TestResult, ns: Namespace) -> None: # failures. support.gc_collect() - cleanup_test_droppings(result.test_name, ns.verbose) + remove_testfn(result.test_name, ns.verbose) if gc.garbage: support.environment_altered = True print_warning(f"{result.test_name} created {len(gc.garbage)} " - f"uncollectable object(s).") + f"uncollectable object(s)") # move the uncollectable objects somewhere, # so we don't see them again @@ -443,35 +539,37 @@ def _runtest_env_changed_exc(result: TestResult, ns: Namespace, result.state = State.PASSED -def cleanup_test_droppings(test_name: str, verbose: int) -> None: - # Try to clean up junk commonly left behind. While tests shouldn't leave - # any files or directories behind, when a test fails that can be tedious - # for it to arrange. The consequences can be especially nasty on Windows, - # since if a test leaves a file open, it cannot be deleted by name (while - # there's nothing we can do about that here either, we can display the - # name of the offending test, which is a real help). - for name in (os_helper.TESTFN,): - if not os.path.exists(name): - continue +def remove_testfn(test_name: str, verbose: int) -> None: + # Try to clean up os_helper.TESTFN if left behind. + # + # While tests shouldn't leave any files or directories behind, when a test + # fails that can be tedious for it to arrange. The consequences can be + # especially nasty on Windows, since if a test leaves a file open, it + # cannot be deleted by name (while there's nothing we can do about that + # here either, we can display the name of the offending test, which is a + # real help). + name = os_helper.TESTFN + if not os.path.exists(name): + return - if os.path.isdir(name): - import shutil - kind, nuker = "directory", shutil.rmtree - elif os.path.isfile(name): - kind, nuker = "file", os.unlink - else: - raise RuntimeError(f"os.path says {name!r} exists but is neither " - f"directory nor file") - - if verbose: - print_warning(f"{test_name} left behind {kind} {name!r}") - support.environment_altered = True - - try: - import stat - # fix possible permissions problems that might prevent cleanup - os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) - nuker(name) - except Exception as exc: - print_warning(f"{test_name} left behind {kind} {name!r} " - f"and it couldn't be removed: {exc}") + if os.path.isdir(name): + import shutil + kind, nuker = "directory", shutil.rmtree + elif os.path.isfile(name): + kind, nuker = "file", os.unlink + else: + raise RuntimeError(f"os.path says {name!r} exists but is neither " + f"directory nor file") + + if verbose: + print_warning(f"{test_name} left behind {kind} {name!r}") + support.environment_altered = True + + try: + import stat + # fix possible permissions problems that might prevent cleanup + os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + nuker(name) + except Exception as exc: + print_warning(f"{test_name} left behind {kind} {name!r} " + f"and it couldn't be removed: {exc}") diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index fb1f80b0c054e3..60089554cab5dd 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -19,8 +19,8 @@ from test.libregrtest.cmdline import Namespace from test.libregrtest.main import Regrtest from test.libregrtest.runtest import ( - runtest, TestResult, State, - PROGRESS_MIN_TIME) + runtest, TestResult, State, PROGRESS_MIN_TIME, + MatchTests, RunTests) from test.libregrtest.setup import setup_tests from test.libregrtest.utils import format_duration, print_warning @@ -44,26 +44,54 @@ USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg")) -def must_stop(result: TestResult, ns: Namespace) -> bool: - if result.state == State.INTERRUPTED: - return True - if ns.failfast and result.is_failed(ns.fail_env_changed): - return True - return False +@dataclasses.dataclass(slots=True) +class WorkerJob: + test_name: str + namespace: Namespace + rerun: bool = False + match_tests: MatchTests | None = None -def parse_worker_args(worker_args) -> tuple[Namespace, str]: - ns_dict, test_name = json.loads(worker_args) - ns = Namespace(**ns_dict) - return (ns, test_name) +class _EncodeWorkerJob(json.JSONEncoder): + def default(self, o: Any) -> dict[str, Any]: + match o: + case WorkerJob(): + result = dataclasses.asdict(o) + result["__worker_job__"] = True + return result + case Namespace(): + result = vars(o) + result["__namespace__"] = True + return result + case _: + return super().default(o) + + +def _decode_worker_job(d: dict[str, Any]) -> WorkerJob | dict[str, Any]: + if "__worker_job__" in d: + d.pop('__worker_job__') + return WorkerJob(**d) + if "__namespace__" in d: + d.pop('__namespace__') + return Namespace(**d) + else: + return d + + +def _parse_worker_args(worker_json: str) -> tuple[Namespace, str]: + return json.loads(worker_json, + object_hook=_decode_worker_job) -def run_test_in_subprocess(testname: str, ns: Namespace, tmp_dir: str, stdout_fh: TextIO) -> subprocess.Popen: - ns_dict = vars(ns) - worker_args = (ns_dict, testname) - worker_args = json.dumps(worker_args) - if ns.python is not None: - executable = ns.python +def run_test_in_subprocess(worker_job: WorkerJob, + output_file: TextIO, + tmp_dir: str | None = None) -> subprocess.Popen: + ns = worker_job.namespace + python = ns.python + worker_args = json.dumps(worker_job, cls=_EncodeWorkerJob) + + if python is not None: + executable = python else: executable = [sys.executable] cmd = [*executable, *support.args_from_interpreter_flags(), @@ -82,9 +110,9 @@ def run_test_in_subprocess(testname: str, ns: Namespace, tmp_dir: str, stdout_fh # sysconfig.is_python_build() is true. See issue 15300. kw = dict( env=env, - stdout=stdout_fh, + stdout=output_file, # bpo-45410: Write stderr into stdout to keep messages order - stderr=stdout_fh, + stderr=output_file, text=True, close_fds=(os.name != 'nt'), cwd=os_helper.SAVEDCWD, @@ -94,11 +122,27 @@ def run_test_in_subprocess(testname: str, ns: Namespace, tmp_dir: str, stdout_fh return subprocess.Popen(cmd, **kw) -def run_tests_worker(ns: Namespace, test_name: str) -> NoReturn: +def run_tests_worker(worker_json: str) -> NoReturn: + worker_job = _parse_worker_args(worker_json) + ns = worker_job.namespace + test_name = worker_job.test_name + rerun = worker_job.rerun + match_tests = worker_job.match_tests + setup_tests(ns) - result = runtest(ns, test_name) + if rerun: + if match_tests: + matching = "matching: " + ", ".join(match_tests) + print(f"Re-running {test_name} in verbose mode ({matching})", flush=True) + else: + print(f"Re-running {test_name} in verbose mode", flush=True) + ns.verbose = True + if match_tests is not None: + ns.match_tests = match_tests + + result = runtest(ns, test_name) print() # Force a newline (just in case) # Serialize TestResult as dict in JSON @@ -148,11 +192,13 @@ class TestWorkerProcess(threading.Thread): def __init__(self, worker_id: int, runner: "MultiprocessTestRunner") -> None: super().__init__() self.worker_id = worker_id + self.runtests = runner.runtests self.pending = runner.pending self.output = runner.output self.ns = runner.ns self.timeout = runner.worker_timeout self.regrtest = runner.regrtest + self.rerun = runner.rerun self.current_test_name = None self.start_time = None self._popen = None @@ -216,10 +262,11 @@ def mp_result_error( ) -> MultiprocessResult: return MultiprocessResult(test_result, stdout, err_msg) - def _run_process(self, test_name: str, tmp_dir: str, stdout_fh: TextIO) -> int: - self.current_test_name = test_name + def _run_process(self, worker_job, output_file: TextIO, + tmp_dir: str | None = None) -> int: + self.current_test_name = worker_job.test_name try: - popen = run_test_in_subprocess(test_name, self.ns, tmp_dir, stdout_fh) + popen = run_test_in_subprocess(worker_job, output_file, tmp_dir) self._killed = False self._popen = popen @@ -277,9 +324,15 @@ def _runtest(self, test_name: str) -> MultiprocessResult: else: encoding = sys.stdout.encoding + match_tests = self.runtests.get_match_tests(test_name) + # gh-94026: Write stdout+stderr to a tempfile as workaround for # non-blocking pipes on Emscripten with NodeJS. - with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh: + with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_file: + worker_job = WorkerJob(test_name, + namespace=self.ns, + rerun=self.rerun, + match_tests=match_tests) # gh-93353: Check for leaked temporary files in the parent process, # since the deletion of temporary files can happen late during # Python finalization: too late for libregrtest. @@ -290,17 +343,17 @@ def _runtest(self, test_name: str) -> MultiprocessResult: tmp_dir = tempfile.mkdtemp(prefix="test_python_") tmp_dir = os.path.abspath(tmp_dir) try: - retcode = self._run_process(test_name, tmp_dir, stdout_fh) + retcode = self._run_process(worker_job, stdout_file, tmp_dir) finally: tmp_files = os.listdir(tmp_dir) os_helper.rmtree(tmp_dir) else: - retcode = self._run_process(test_name, None, stdout_fh) + retcode = self._run_process(worker_job, stdout_file) tmp_files = () - stdout_fh.seek(0) + stdout_file.seek(0) try: - stdout = stdout_fh.read().strip() + stdout = stdout_file.read().strip() except Exception as exc: # gh-101634: Catch UnicodeDecodeError if stdout cannot be # decoded from encoding @@ -342,6 +395,8 @@ def _runtest(self, test_name: str) -> MultiprocessResult: return MultiprocessResult(result, stdout) def run(self) -> None: + fail_fast = self.ns.failfast + fail_env_changed = self.ns.fail_env_changed while not self._stopped: try: try: @@ -354,7 +409,7 @@ def run(self) -> None: mp_result.result.duration = time.monotonic() - self.start_time self.output.put((False, mp_result)) - if must_stop(mp_result.result, self.ns): + if mp_result.result.must_stop(fail_fast, fail_env_changed): break except ExitThread: break @@ -410,29 +465,36 @@ def get_running(workers: list[TestWorkerProcess]) -> list[TestWorkerProcess]: class MultiprocessTestRunner: - def __init__(self, regrtest: Regrtest) -> None: + def __init__(self, regrtest: Regrtest, runtests: RunTests) -> None: + ns = regrtest.ns + timeout = ns.timeout + self.regrtest = regrtest + self.runtests = runtests + self.rerun = runtests.rerun self.log = self.regrtest.log - self.ns = regrtest.ns + self.ns = ns self.output: queue.Queue[QueueOutput] = queue.Queue() - self.pending = MultiprocessIterator(self.regrtest.tests) - if self.ns.timeout is not None: + tests_iter = runtests.iter_tests() + self.pending = MultiprocessIterator(tests_iter) + if timeout is not None: # Rely on faulthandler to kill a worker process. This timouet is # when faulthandler fails to kill a worker process. Give a maximum # of 5 minutes to faulthandler to kill the worker. - self.worker_timeout = min(self.ns.timeout * 1.5, - self.ns.timeout + 5 * 60) + self.worker_timeout = min(timeout * 1.5, timeout + 5 * 60) else: self.worker_timeout = None self.workers = None def start_workers(self) -> None: + use_mp = self.ns.use_mp + timeout = self.ns.timeout self.workers = [TestWorkerProcess(index, self) - for index in range(1, self.ns.use_mp + 1)] + for index in range(1, use_mp + 1)] msg = f"Run tests in parallel using {len(self.workers)} child processes" - if self.ns.timeout: + if timeout: msg += (" (timeout: %s, worker timeout: %s)" - % (format_duration(self.ns.timeout), + % (format_duration(timeout), format_duration(self.worker_timeout))) self.log(msg) for worker in self.workers: @@ -446,6 +508,7 @@ def stop_workers(self) -> None: worker.wait_stopped(start_time) def _get_result(self) -> QueueOutput | None: + pgo = self.ns.pgo use_faulthandler = (self.ns.timeout is not None) timeout = PROGRESS_UPDATE @@ -464,7 +527,7 @@ def _get_result(self) -> QueueOutput | None: # display progress running = get_running(self.workers) - if running and not self.ns.pgo: + if running and not pgo: self.log('running: %s' % ', '.join(running)) # all worker threads are done: consume pending results @@ -475,42 +538,46 @@ def _get_result(self) -> QueueOutput | None: def display_result(self, mp_result: MultiprocessResult) -> None: result = mp_result.result + pgo = self.ns.pgo text = str(result) if mp_result.err_msg: # MULTIPROCESSING_ERROR text += ' (%s)' % mp_result.err_msg - elif (result.duration >= PROGRESS_MIN_TIME and not self.ns.pgo): + elif (result.duration >= PROGRESS_MIN_TIME and not pgo): text += ' (%s)' % format_duration(result.duration) running = get_running(self.workers) - if running and not self.ns.pgo: + if running and not pgo: text += ' -- running: %s' % ', '.join(running) self.regrtest.display_progress(self.test_index, text) def _process_result(self, item: QueueOutput) -> bool: """Returns True if test runner must stop.""" + rerun = self.runtests.rerun if item[0]: # Thread got an exception format_exc = item[1] print_warning(f"regrtest worker thread failed: {format_exc}") result = TestResult("", state=State.MULTIPROCESSING_ERROR) - self.regrtest.accumulate_result(result) - return True + self.regrtest.accumulate_result(result, rerun=rerun) + return result self.test_index += 1 mp_result = item[1] - self.regrtest.accumulate_result(mp_result.result) + result = mp_result.result + self.regrtest.accumulate_result(result, rerun=rerun) self.display_result(mp_result) if mp_result.worker_stdout: print(mp_result.worker_stdout, flush=True) - if must_stop(mp_result.result, self.ns): - return True - - return False + return result def run_tests(self) -> None: + fail_fast = self.ns.failfast + fail_env_changed = self.ns.fail_env_changed + timeout = self.ns.timeout + self.start_workers() self.test_index = 0 @@ -520,14 +587,14 @@ def run_tests(self) -> None: if item is None: break - stop = self._process_result(item) - if stop: + result = self._process_result(item) + if result.must_stop(fail_fast, fail_env_changed): break except KeyboardInterrupt: print() self.regrtest.interrupted = True finally: - if self.ns.timeout is not None: + if timeout is not None: faulthandler.cancel_dump_traceback_later() # Always ensure that all worker processes are no longer @@ -536,8 +603,8 @@ def run_tests(self) -> None: self.stop_workers() -def run_tests_multiprocess(regrtest: Regrtest) -> None: - MultiprocessTestRunner(regrtest).run_tests() +def run_tests_multiprocess(regrtest: Regrtest, runtests: RunTests) -> None: + MultiprocessTestRunner(regrtest, runtests).run_tests() class EncodeTestResult(json.JSONEncoder): @@ -552,7 +619,7 @@ def default(self, o: Any) -> dict[str, Any]: return super().default(o) -def decode_test_result(d: dict[str, Any]) -> TestResult | TestStats | dict[str, Any]: +def decode_test_result(d: dict[str, Any]) -> TestResult | dict[str, Any]: """Decode a TestResult (sub)class object from a JSON dict.""" if "__test_result__" not in d: diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index fd46819fd903fe..5e16b1ae054a26 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -31,7 +31,7 @@ def format_duration(seconds): return ' '.join(parts) -def removepy(names): +def strip_py_suffix(names: list[str]): if not names: return for idx, name in enumerate(names): diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 37d0fdee5511f8..878b6fc13a9da4 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1191,7 +1191,6 @@ def _is_full_match_test(pattern): def set_match_tests(accept_patterns=None, ignore_patterns=None): global _match_test_func, _accept_test_patterns, _ignore_test_patterns - if accept_patterns is None: accept_patterns = () if ignore_patterns is None: diff --git a/Lib/test/support/testresult.py b/Lib/test/support/testresult.py index 14474be222dc4b..de23fdd59ded95 100644 --- a/Lib/test/support/testresult.py +++ b/Lib/test/support/testresult.py @@ -8,6 +8,7 @@ import time import traceback import unittest +from test import support class RegressionTestResult(unittest.TextTestResult): USE_XML = False @@ -112,6 +113,8 @@ def addExpectedFailure(self, test, err): def addFailure(self, test, err): self._add_result(test, True, failure=self.__makeErrorDict(*err)) super().addFailure(test, err) + if support.failfast: + self.stop() def addSkip(self, test, reason): self._add_result(test, skipped=reason) diff --git a/Lib/test/test_concurrent_futures/executor.py b/Lib/test/test_concurrent_futures/executor.py index 36278bdd501971..1e7d4344740943 100644 --- a/Lib/test/test_concurrent_futures/executor.py +++ b/Lib/test/test_concurrent_futures/executor.py @@ -53,6 +53,7 @@ def test_map_exception(self): self.assertEqual(i.__next__(), (0, 1)) self.assertRaises(ZeroDivisionError, i.__next__) + @support.requires_resource('walltime') def test_map_timeout(self): results = [] try: diff --git a/Lib/test/test_concurrent_futures/test_wait.py b/Lib/test/test_concurrent_futures/test_wait.py index e4bea8b05aced6..3f64ca173c02f6 100644 --- a/Lib/test/test_concurrent_futures/test_wait.py +++ b/Lib/test/test_concurrent_futures/test_wait.py @@ -3,6 +3,7 @@ import time import unittest from concurrent import futures +from test import support from .util import ( CANCELLED_FUTURE, CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, @@ -53,6 +54,7 @@ def test_first_completed_some_already_completed(self): finished) self.assertEqual(set([future1]), pending) + @support.requires_resource('walltime') def test_first_exception(self): future1 = self.executor.submit(mul, 2, 21) future2 = self.executor.submit(sleep_and_raise, 1.5) @@ -110,6 +112,7 @@ def test_all_completed(self): future2]), finished) self.assertEqual(set(), pending) + @support.requires_resource('walltime') def test_timeout(self): future1 = self.executor.submit(mul, 6, 7) future2 = self.executor.submit(time.sleep, 6) diff --git a/Lib/test/test_eintr.py b/Lib/test/test_eintr.py index 528147802ba47e..49b15f1a2dba92 100644 --- a/Lib/test/test_eintr.py +++ b/Lib/test/test_eintr.py @@ -9,6 +9,7 @@ class EINTRTests(unittest.TestCase): @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") + @support.requires_resource('walltime') def test_all(self): # Run the tester in a sub-process, to make sure there is only one # thread (for reliable signal delivery). diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 2e97de592712c0..cfc7ce5a86bab8 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -676,6 +676,7 @@ def test_dump_traceback_later_fd(self): with tempfile.TemporaryFile('wb+') as fp: self.check_dump_traceback_later(fd=fp.fileno()) + @support.requires_resource('walltime') def test_dump_traceback_later_twice(self): self.check_dump_traceback_later(loops=2) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index fe8105ee2bb3fa..676725c46ec694 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1954,6 +1954,7 @@ def test_networked_good_cert(self): h.close() self.assertIn('nginx', server_string) + @support.requires_resource('walltime') def test_networked_bad_cert(self): # We feed a "CA" cert that is unrelated to the server's cert import ssl diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index cfa1c107a4b01d..4b38355c37b329 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -10,7 +10,7 @@ import threading import socket -from test.support import verbose, run_with_tz, run_with_locale, cpython_only +from test.support import verbose, run_with_tz, run_with_locale, cpython_only, requires_resource from test.support import hashlib_helper from test.support import threading_helper import unittest @@ -457,6 +457,7 @@ def test_simple_with_statement(self): with self.imap_class(*server.server_address): pass + @requires_resource('walltime') def test_imaplib_timeout_test(self): _, server = self._setup(SimpleIMAPHandler) addr = server.server_address[1] @@ -550,6 +551,7 @@ class NewIMAPSSLTests(NewIMAPTestsMixin, unittest.TestCase): imap_class = IMAP4_SSL server_class = SecureTCPServer + @requires_resource('walltime') def test_ssl_raises(self): ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) self.assertEqual(ssl_context.verify_mode, ssl.CERT_REQUIRED) @@ -564,6 +566,7 @@ def test_ssl_raises(self): ssl_context=ssl_context) client.shutdown() + @requires_resource('walltime') def test_ssl_verified(self): ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ssl_context.load_verify_locations(CAFILE) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index fc56c1d5111351..e032325fbe2578 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4478,10 +4478,12 @@ def run(): self.assertFalse(err.strip('.!')) @threading_helper.requires_working_threading() + @support.requires_resource('walltime') def test_daemon_threads_shutdown_stdout_deadlock(self): self.check_daemon_threads_shutdown_deadlock('stdout') @threading_helper.requires_working_threading() + @support.requires_resource('walltime') def test_daemon_threads_shutdown_stderr_deadlock(self): self.check_daemon_threads_shutdown_deadlock('stderr') @@ -4655,11 +4657,13 @@ def alarm_handler(sig, frame): os.close(r) @requires_alarm + @support.requires_resource('walltime') def test_interrupted_read_retry_buffered(self): self.check_interrupted_read_retry(lambda x: x.decode('latin1'), mode="rb") @requires_alarm + @support.requires_resource('walltime') def test_interrupted_read_retry_text(self): self.check_interrupted_read_retry(lambda x: x, mode="r", encoding="latin1") @@ -4733,10 +4737,12 @@ def alarm2(sig, frame): raise @requires_alarm + @support.requires_resource('walltime') def test_interrupted_write_retry_buffered(self): self.check_interrupted_write_retry(b"x", mode="wb") @requires_alarm + @support.requires_resource('walltime') def test_interrupted_write_retry_text(self): self.check_interrupted_write_retry("x", mode="w", encoding="latin1") diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index def976fbe96ba3..b7f4c6edf10614 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -680,6 +680,7 @@ def test_path_objects(self): support.is_emscripten, "Emscripten cannot fstat unlinked files." ) @threading_helper.requires_working_threading() + @support.requires_resource('walltime') def test_race(self): # Issue #14632 refers. def remove_loop(fname, tries): diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py index 02165a0244ddf4..1847ae95db9292 100644 --- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py @@ -8,7 +8,7 @@ import time import unittest from test.support import ( - cpython_only, requires_subprocess, requires_working_socket + cpython_only, requires_subprocess, requires_working_socket, requires_resource ) from test.support import threading_helper from test.support.os_helper import TESTFN @@ -124,6 +124,7 @@ def fileno(self): # select(), modified to use poll() instead. @requires_subprocess() + @requires_resource('walltime') def test_poll2(self): cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done' proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 68f71360d6914c..a72c052cb83e0d 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -5,6 +5,7 @@ """ import contextlib +import dataclasses import glob import io import locale @@ -21,6 +22,7 @@ from test import support from test.support import os_helper, TestStats from test.libregrtest import utils, setup +from test.libregrtest.runtest import normalize_test_name if not support.has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") @@ -32,6 +34,7 @@ EXITCODE_BAD_TEST = 2 EXITCODE_ENV_CHANGED = 3 EXITCODE_NO_TESTS_RAN = 4 +EXITCODE_RERUN_FAIL = 5 EXITCODE_INTERRUPTED = 130 TEST_INTERRUPTED = textwrap.dedent(""" @@ -96,11 +99,11 @@ def test_verbose(self): ns = libregrtest._parse_args([]) self.assertEqual(ns.verbose, 0) - def test_verbose2(self): - for opt in '-w', '--verbose2': + def test_rerun(self): + for opt in '-w', '--rerun', '--verbose2': with self.subTest(opt=opt): ns = libregrtest._parse_args([opt]) - self.assertTrue(ns.verbose2) + self.assertTrue(ns.rerun) def test_verbose3(self): for opt in '-W', '--verbose3': @@ -362,6 +365,13 @@ def test_unknown_option(self): 'unrecognized arguments: --unknown-option') +@dataclasses.dataclass(slots=True) +class Rerun: + name: str + match: str | None + success: bool + + class BaseTestCase(unittest.TestCase): TEST_UNIQUE_ID = 1 TESTNAME_PREFIX = 'test_regrtest_' @@ -423,11 +433,11 @@ def parse_executed_tests(self, output): def check_executed_tests(self, output, tests, skipped=(), failed=(), env_changed=(), omitted=(), - rerun={}, run_no_tests=(), + rerun=None, run_no_tests=(), resource_denied=(), randomize=False, interrupted=False, fail_env_changed=False, - *, stats): + *, stats, forever=False, filtered=False): if isinstance(tests, str): tests = [tests] if isinstance(skipped, str): @@ -445,11 +455,20 @@ def check_executed_tests(self, output, tests, skipped=(), failed=(), if isinstance(stats, int): stats = TestStats(stats) + rerun_failed = [] + if rerun is not None: + failed = [rerun.name] + if not rerun.success: + rerun_failed.append(rerun.name) + executed = self.parse_executed_tests(output) + total_tests = list(tests) + if rerun is not None: + total_tests.append(rerun.name) if randomize: - self.assertEqual(set(executed), set(tests), output) + self.assertEqual(set(executed), set(total_tests), output) else: - self.assertEqual(executed, tests, output) + self.assertEqual(executed, total_tests, output) def plural(count): return 's' if count != 1 else '' @@ -465,6 +484,10 @@ def list_regex(line_format, tests): regex = list_regex('%s test%s skipped', skipped) self.check_line(output, regex) + if resource_denied: + regex = list_regex(r'%s test%s skipped \(resource denied\)', resource_denied) + self.check_line(output, regex) + if failed: regex = list_regex('%s test%s failed', failed) self.check_line(output, regex) @@ -478,32 +501,36 @@ def list_regex(line_format, tests): regex = list_regex('%s test%s omitted', omitted) self.check_line(output, regex) - if rerun: - regex = list_regex('%s re-run test%s', rerun.keys()) + if rerun is not None: + regex = list_regex('%s re-run test%s', [rerun.name]) self.check_line(output, regex) - regex = LOG_PREFIX + r"Re-running failed tests in verbose mode" + regex = LOG_PREFIX + fr"Re-running 1 failed tests in verbose mode" + self.check_line(output, regex) + regex = fr"Re-running {rerun.name} in verbose mode" + if rerun.match: + regex = fr"{regex} \(matching: {rerun.match}\)" self.check_line(output, regex) - for name, match in rerun.items(): - regex = LOG_PREFIX + f"Re-running {name} in verbose mode \\(matching: {match}\\)" - self.check_line(output, regex) if run_no_tests: regex = list_regex('%s test%s run no tests', run_no_tests) self.check_line(output, regex) - good = (len(tests) - len(skipped) - len(failed) + good = (len(tests) - len(skipped) - len(resource_denied) - len(failed) - len(omitted) - len(env_changed) - len(run_no_tests)) if good: - regex = r'%s test%s OK\.$' % (good, plural(good)) - if not skipped and not failed and good > 1: + regex = r'%s test%s OK\.' % (good, plural(good)) + if not skipped and not failed and (rerun is None or rerun.success) and good > 1: regex = 'All %s' % regex - self.check_line(output, regex) + self.check_line(output, regex, full=True) if interrupted: self.check_line(output, 'Test suite interrupted by signal SIGINT.') # Total tests - parts = [f'run={stats.tests_run:,}'] + text = f'run={stats.tests_run:,}' + if filtered: + text = fr'{text} \(filtered\)' + parts = [text] if stats.failures: parts.append(f'failures={stats.failures:,}') if stats.skipped: @@ -512,39 +539,52 @@ def list_regex(line_format, tests): self.check_line(output, line, full=True) # Total test files - report = [f'success={good}'] - if failed: - report.append(f'failed={len(failed)}') - if env_changed: - report.append(f'env_changed={len(env_changed)}') - if skipped: - report.append(f'skipped={len(skipped)}') - if resource_denied: - report.append(f'resource_denied={len(resource_denied)}') - if rerun: - report.append(f'rerun={len(rerun)}') - if run_no_tests: - report.append(f'run_no_tests={len(run_no_tests)}') + run = len(total_tests) - len(resource_denied) + if rerun is not None: + total_failed = len(rerun_failed) + total_rerun = 1 + else: + total_failed = len(failed) + total_rerun = 0 + if interrupted: + run = 0 + text = f'run={run}' + if not forever: + text = f'{text}/{len(tests)}' + if filtered: + text = fr'{text} \(filtered\)' + report = [text] + for name, ntest in ( + ('failed', total_failed), + ('env_changed', len(env_changed)), + ('skipped', len(skipped)), + ('resource_denied', len(resource_denied)), + ('rerun', total_rerun), + ('run_no_tests', len(run_no_tests)), + ): + if ntest: + report.append(f'{name}={ntest}') line = fr'Total test files: {" ".join(report)}' self.check_line(output, line, full=True) # Result - result = [] + state = [] if failed: - result.append('FAILURE') + state.append('FAILURE') elif fail_env_changed and env_changed: - result.append('ENV CHANGED') + state.append('ENV CHANGED') if interrupted: - result.append('INTERRUPTED') - if not any((good, result, failed, interrupted, skipped, + state.append('INTERRUPTED') + if not any((good, failed, interrupted, skipped, env_changed, fail_env_changed)): - result.append("NO TESTS RAN") - elif not result: - result.append('SUCCESS') - result = ', '.join(result) - if rerun: - result = 'FAILURE then %s' % result - self.check_line(output, f'Result: {result}', full=True) + state.append("NO TESTS RAN") + elif not state: + state.append('SUCCESS') + state = ', '.join(state) + if rerun is not None: + new_state = 'SUCCESS' if rerun.success else 'FAILURE' + state = 'FAILURE then ' + new_state + self.check_line(output, f'Result: {state}', full=True) def parse_random_seed(self, output): match = self.regex_search(r'Using random seed ([0-9]+)', output) @@ -563,13 +603,13 @@ def run_command(self, args, input=None, exitcode=0, **kw): stdout=subprocess.PIPE, **kw) if proc.returncode != exitcode: - msg = ("Command %s failed with exit code %s\n" + msg = ("Command %s failed with exit code %s, but exit code %s expected!\n" "\n" "stdout:\n" "---\n" "%s\n" "---\n" - % (str(args), proc.returncode, proc.stdout)) + % (str(args), proc.returncode, exitcode, proc.stdout)) if proc.stderr: msg += ("\n" "stderr:\n" @@ -734,6 +774,40 @@ def run_tests(self, *testargs, **kw): cmdargs = ['-m', 'test', '--testdir=%s' % self.tmptestdir, *testargs] return self.run_python(cmdargs, **kw) + def test_success(self): + code = textwrap.dedent(""" + import unittest + + class PassingTests(unittest.TestCase): + def test_test1(self): + pass + + def test_test2(self): + pass + + def test_test3(self): + pass + """) + tests = [self.create_test(f'ok{i}', code=code) for i in range(1, 6)] + + output = self.run_tests(*tests) + self.check_executed_tests(output, tests, + stats=3 * len(tests)) + + def test_skip(self): + code = textwrap.dedent(""" + import unittest + raise unittest.SkipTest("nope") + """) + test_ok = self.create_test('ok') + test_skip = self.create_test('skip', code=code) + tests = [test_ok, test_skip] + + output = self.run_tests(*tests) + self.check_executed_tests(output, tests, + skipped=[test_skip], + stats=1) + def test_failing_test(self): # test a failing test code = textwrap.dedent(""" @@ -773,14 +847,12 @@ def test_pass(self): # -u audio: 1 resource enabled output = self.run_tests('-uaudio', *test_names) self.check_executed_tests(output, test_names, - skipped=tests['network'], resource_denied=tests['network'], stats=1) # no option: 0 resources enabled - output = self.run_tests(*test_names) + output = self.run_tests(*test_names, exitcode=EXITCODE_NO_TESTS_RAN) self.check_executed_tests(output, test_names, - skipped=test_names, resource_denied=test_names, stats=0) @@ -926,9 +998,21 @@ def test_run(self): builtins.__dict__['RUN'] = 1 """) test = self.create_test('forever', code=code) + + # --forever output = self.run_tests('--forever', test, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, [test]*3, failed=test, - stats=TestStats(1, 1)) + stats=TestStats(3, 1), + forever=True) + + # --forever --rerun + output = self.run_tests('--forever', '--rerun', test, exitcode=0) + self.check_executed_tests(output, [test]*3, + rerun=Rerun(test, + match='test_run', + success=True), + stats=TestStats(4, 1), + forever=True) def check_leak(self, code, what): test = self.create_test('huntrleaks', code=code) @@ -1139,33 +1223,55 @@ def test_fail_always(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, [testname], - failed=testname, - rerun={testname: "test_fail_always"}, - stats=TestStats(1, 1)) + rerun=Rerun(testname, + "test_fail_always", + success=False), + stats=TestStats(3, 2)) def test_rerun_success(self): # FAILURE then SUCCESS - code = textwrap.dedent(""" - import builtins + marker_filename = os.path.abspath("regrtest_marker_filename") + self.addCleanup(os_helper.unlink, marker_filename) + self.assertFalse(os.path.exists(marker_filename)) + + code = textwrap.dedent(f""" + import os.path import unittest + marker_filename = {marker_filename!r} + class Tests(unittest.TestCase): def test_succeed(self): return def test_fail_once(self): - if not hasattr(builtins, '_test_failed'): - builtins._test_failed = True + if not os.path.exists(marker_filename): + open(marker_filename, "w").close() self.fail("bug") """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=0) + # FAILURE then SUCCESS => exit code 0 + output = self.run_tests("--rerun", testname, exitcode=0) self.check_executed_tests(output, [testname], - rerun={testname: "test_fail_once"}, - stats=1) + rerun=Rerun(testname, + match="test_fail_once", + success=True), + stats=TestStats(3, 1)) + os_helper.unlink(marker_filename) + + # with --fail-rerun, exit code EXITCODE_RERUN_FAIL + # on "FAILURE then SUCCESS" state. + output = self.run_tests("--rerun", "--fail-rerun", testname, + exitcode=EXITCODE_RERUN_FAIL) + self.check_executed_tests(output, [testname], + rerun=Rerun(testname, + match="test_fail_once", + success=True), + stats=TestStats(3, 1)) + os_helper.unlink(marker_filename) def test_rerun_setup_class_hook_failure(self): # FAILURE then FAILURE @@ -1182,10 +1288,12 @@ def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "ExampleTests"}, + rerun=Rerun(testname, + match="ExampleTests", + success=False), stats=0) def test_rerun_teardown_class_hook_failure(self): @@ -1203,11 +1311,13 @@ def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "ExampleTests"}, - stats=1) + rerun=Rerun(testname, + match="ExampleTests", + success=False), + stats=2) def test_rerun_setup_module_hook_failure(self): # FAILURE then FAILURE @@ -1223,10 +1333,12 @@ def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: testname}, + rerun=Rerun(testname, + match=None, + success=False), stats=0) def test_rerun_teardown_module_hook_failure(self): @@ -1243,11 +1355,13 @@ def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) - self.check_executed_tests(output, testname, + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, [testname], failed=[testname], - rerun={testname: testname}, - stats=1) + rerun=Rerun(testname, + match=None, + success=False), + stats=2) def test_rerun_setup_hook_failure(self): # FAILURE then FAILURE @@ -1263,11 +1377,13 @@ def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "test_success"}, - stats=1) + rerun=Rerun(testname, + match="test_success", + success=False), + stats=2) def test_rerun_teardown_hook_failure(self): # FAILURE then FAILURE @@ -1283,11 +1399,13 @@ def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "test_success"}, - stats=1) + rerun=Rerun(testname, + match="test_success", + success=False), + stats=2) def test_rerun_async_setup_hook_failure(self): # FAILURE then FAILURE @@ -1303,11 +1421,12 @@ async def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, - failed=[testname], - rerun={testname: "test_success"}, - stats=1) + rerun=Rerun(testname, + match="test_success", + success=False), + stats=2) def test_rerun_async_teardown_hook_failure(self): # FAILURE then FAILURE @@ -1323,11 +1442,13 @@ async def test_success(self): """) testname = self.create_test(code=code) - output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--rerun", testname, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, testname, failed=[testname], - rerun={testname: "test_success"}, - stats=1) + rerun=Rerun(testname, + match="test_success", + success=False), + stats=2) def test_no_tests_ran(self): code = textwrap.dedent(""" @@ -1343,7 +1464,7 @@ def test_bug(self): exitcode=EXITCODE_NO_TESTS_RAN) self.check_executed_tests(output, [testname], run_no_tests=testname, - stats=0) + stats=0, filtered=True) def test_no_tests_ran_skip(self): code = textwrap.dedent(""" @@ -1374,7 +1495,7 @@ def test_bug(self): exitcode=EXITCODE_NO_TESTS_RAN) self.check_executed_tests(output, [testname, testname2], run_no_tests=[testname, testname2], - stats=0) + stats=0, filtered=True) def test_no_test_ran_some_test_exist_some_not(self): code = textwrap.dedent(""" @@ -1398,7 +1519,7 @@ def test_other_bug(self): "-m", "test_other_bug", exitcode=0) self.check_executed_tests(output, [testname, testname2], run_no_tests=[testname], - stats=1) + stats=1, filtered=True) @support.cpython_only def test_uncollectable(self): @@ -1715,6 +1836,17 @@ def test_format_duration(self): self.assertEqual(utils.format_duration(3 * 3600 + 1), '3 hour 1 sec') + def test_normalize_test_name(self): + normalize = normalize_test_name + self.assertEqual(normalize('test_access (test.test_os.FileTests.test_access)'), + 'test_access') + self.assertEqual(normalize('setUpClass (test.test_os.ChownFileTests)', is_error=True), + 'ChownFileTests') + self.assertEqual(normalize('test_success (test.test_bug.ExampleTests.test_success)', is_error=True), + 'test_success') + self.assertIsNone(normalize('setUpModule (test.test_x)', is_error=True)) + self.assertIsNone(normalize('tearDownModule (test.test_module)', is_error=True)) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 25afd6aabe0751..2a1a1ee22f43da 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -745,6 +745,7 @@ def test_siginterrupt_on(self): interrupted = self.readpipe_interrupted(True) self.assertTrue(interrupted) + @support.requires_resource('walltime') def test_siginterrupt_off(self): # If a signal handler is installed and siginterrupt is called with # a false value for the second argument, when that signal arrives, it diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py index 72f51cd8d81f59..2e0dc1aa276f35 100644 --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -61,6 +61,7 @@ def test_connect_default_port(self): server.ehlo() server.quit() + @support.requires_resource('walltime') def test_connect_using_sslcontext(self): context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) context.check_hostname = False diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 4e49dc5640d3f5..2c32fec5104c23 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2182,6 +2182,7 @@ def test_timeout_connect_ex(self): self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK)) @unittest.skipUnless(socket_helper.IPV6_ENABLED, 'Needs IPv6') + @support.requires_resource('walltime') def test_get_server_certificate_ipv6(self): with socket_helper.transient_internet('ipv6.google.com'): _test_get_server_certificate(self, 'ipv6.google.com', 443) @@ -2740,6 +2741,7 @@ def try_protocol_combo(server_protocol, client_protocol, expect_success, class ThreadedTests(unittest.TestCase): + @support.requires_resource('walltime') def test_echo(self): """Basic test of an SSL client connecting to a server""" if support.verbose: diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 0b9e9e16f55d7e..d95ef72b0da47a 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -269,6 +269,7 @@ def test_check_output_stdin_with_input_arg(self): self.assertIn('stdin', c.exception.args[0]) self.assertIn('input', c.exception.args[0]) + @support.requires_resource('walltime') def test_check_output_timeout(self): # check_output() function with timeout arg with self.assertRaises(subprocess.TimeoutExpired) as c: @@ -1643,6 +1644,7 @@ def test_check_output_stdin_with_input_arg(self): self.assertIn('stdin', c.exception.args[0]) self.assertIn('input', c.exception.args[0]) + @support.requires_resource('walltime') def test_check_output_timeout(self): with self.assertRaises(subprocess.TimeoutExpired) as c: cp = self.run_python(( diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py index d8d882b2d33589..f0874d8d3ce463 100644 --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -133,6 +133,7 @@ def setUp(self): # XXX The rest of these tests aren't very good -- they don't check much. # They do sometimes catch some major disasters, though. + @support.requires_resource('walltime') def test_ftp(self): # Testing the same URL twice exercises the caching in CacheFTPHandler urls = [ @@ -196,6 +197,7 @@ def test_urlwithfrag(self): self.assertEqual(res.geturl(), "http://www.pythontest.net/index.html#frag") + @support.requires_resource('walltime') def test_redirect_url_withfrag(self): redirect_url_with_frag = "http://www.pythontest.net/redir/with_frag/" with socket_helper.transient_internet(redirect_url_with_frag): @@ -334,6 +336,7 @@ def test_http_timeout(self): FTP_HOST = 'ftp://www.pythontest.net/' + @support.requires_resource('walltime') def test_ftp_basic(self): self.assertIsNone(socket.getdefaulttimeout()) with socket_helper.transient_internet(self.FTP_HOST, timeout=None): @@ -352,6 +355,7 @@ def test_ftp_default_timeout(self): socket.setdefaulttimeout(None) self.assertEqual(u.fp.fp.raw._sock.gettimeout(), 60) + @support.requires_resource('walltime') def test_ftp_no_timeout(self): self.assertIsNone(socket.getdefaulttimeout()) with socket_helper.transient_internet(self.FTP_HOST): @@ -363,6 +367,7 @@ def test_ftp_no_timeout(self): socket.setdefaulttimeout(None) self.assertIsNone(u.fp.fp.raw._sock.gettimeout()) + @support.requires_resource('walltime') def test_ftp_timeout(self): with socket_helper.transient_internet(self.FTP_HOST): u = _urlopen_with_retry(self.FTP_HOST, timeout=60) diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py index 773101ce41f602..49a3b5afdebb2f 100644 --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -109,6 +109,7 @@ def test_getcode(self): open_url.close() self.assertEqual(code, 404) + @support.requires_resource('walltime') def test_bad_address(self): # Make sure proper exception is raised when connecting to a bogus # address. @@ -191,6 +192,7 @@ def test_header(self): logo = "http://www.pythontest.net/" + @support.requires_resource('walltime') def test_data_header(self): with self.urlretrieve(self.logo) as (file_location, fileheaders): datevalue = fileheaders.get('Date') diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 9ff5545f786a32..7f517dc7c13564 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -1031,38 +1031,47 @@ def test_path2(self): self.assertEqual(p.add(6,8), 6+8) self.assertRaises(xmlrpclib.Fault, p.pow, 6, 8) + @support.requires_resource('walltime') def test_path3(self): p = xmlrpclib.ServerProxy(URL+"/is/broken") self.assertRaises(xmlrpclib.Fault, p.add, 6, 8) + @support.requires_resource('walltime') def test_invalid_path(self): p = xmlrpclib.ServerProxy(URL+"/invalid") self.assertRaises(xmlrpclib.Fault, p.add, 6, 8) + @support.requires_resource('walltime') def test_path_query_fragment(self): p = xmlrpclib.ServerProxy(URL+"/foo?k=v#frag") self.assertEqual(p.test(), "/foo?k=v#frag") + @support.requires_resource('walltime') def test_path_fragment(self): p = xmlrpclib.ServerProxy(URL+"/foo#frag") self.assertEqual(p.test(), "/foo#frag") + @support.requires_resource('walltime') def test_path_query(self): p = xmlrpclib.ServerProxy(URL+"/foo?k=v") self.assertEqual(p.test(), "/foo?k=v") + @support.requires_resource('walltime') def test_empty_path(self): p = xmlrpclib.ServerProxy(URL) self.assertEqual(p.test(), "/RPC2") + @support.requires_resource('walltime') def test_root_path(self): p = xmlrpclib.ServerProxy(URL + "/") self.assertEqual(p.test(), "/") + @support.requires_resource('walltime') def test_empty_path_query(self): p = xmlrpclib.ServerProxy(URL + "?k=v") self.assertEqual(p.test(), "?k=v") + @support.requires_resource('walltime') def test_empty_path_fragment(self): p = xmlrpclib.ServerProxy(URL + "#frag") self.assertEqual(p.test(), "#frag") diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst b/Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst new file mode 100644 index 00000000000000..43b9948db0075c --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst @@ -0,0 +1,6 @@ +When regrtest reruns failed tests in verbose mode (``./python -m test +--rerun``), tests are now rerun in fresh worker processes rather than being +executed in the main process. If a test does crash or is killed by a timeout, +the main process can detect and handle the killed worker process. Tests are +rerun in parallel if the ``-jN`` option is used to run tests in parallel. +Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst b/Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst new file mode 100644 index 00000000000000..734cc66aebee15 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst @@ -0,0 +1,2 @@ +Rename regrtest ``--verbose2`` option (``-w``) to ``--rerun``. Keep +``--verbose2`` as a deprecated alias. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst b/Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst new file mode 100644 index 00000000000000..098861ffa30374 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst @@ -0,0 +1,3 @@ +Add ``--fail-rerun option`` option to regrtest: if a test failed when then +passed when rerun in verbose mode, exit the process with exit code 2 +(error), instead of exit code 0 (success). Patch by Victor Stinner. From b9dfe60e8d58518794bcb7895c19f1d328cfe4de Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:14:57 -0700 Subject: [PATCH 0711/1206] [3.12] gh-108962: Skip test_tempfile.test_flags() if not supported (GH-108964) (#108967) gh-108962: Skip test_tempfile.test_flags() if not supported (GH-108964) Skip test_tempfile.test_flags() if chflags() fails with "OSError: [Errno 45] Operation not supported" (ex: on FreeBSD 13). (cherry picked from commit cd2ef21b076b494224985e266c5f5f8b37c66618) Co-authored-by: Victor Stinner --- Lib/test/test_tempfile.py | 18 +++++++++++++++++- ...3-09-05-23-00-09.gh-issue-108962.R4NwuU.rst | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index db08fb1c7f2a42..1673507e2f7c91 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1834,9 +1834,25 @@ def test_modes(self): d.cleanup() self.assertFalse(os.path.exists(d.name)) - @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.lchflags') + @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags') def test_flags(self): flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK + + # skip the test if these flags are not supported (ex: FreeBSD 13) + filename = os_helper.TESTFN + try: + open(filename, "w").close() + try: + os.chflags(filename, flags) + except OSError as exc: + # "OSError: [Errno 45] Operation not supported" + self.skipTest(f"chflags() doesn't support " + f"UF_IMMUTABLE|UF_NOUNLINK: {exc}") + else: + os.chflags(filename, 0) + finally: + os_helper.unlink(filename) + d = self.do_create(recurse=3, dirs=2, files=2) with d: # Change files and directories flags recursively. diff --git a/Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst b/Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst new file mode 100644 index 00000000000000..380fb20b8881b2 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst @@ -0,0 +1,3 @@ +Skip ``test_tempfile.test_flags()`` if ``chflags()`` fails with "OSError: +[Errno 45] Operation not supported" (ex: on FreeBSD 13). Patch by Victor +Stinner. From 9441005bcf47baa15b3e4544cb37435f088cd4e9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:16:02 -0700 Subject: [PATCH 0712/1206] [3.12] gh-108983: Add more PEP 526 tests to `test_grammar` (GH-108984) (#109000) gh-108983: Add more PEP 526 tests to `test_grammar` (GH-108984) (cherry picked from commit 1fb20d42c58924e2e941622b3539645c7b843e0e) Co-authored-by: Nikita Sobolev --- Lib/test/test_grammar.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index ee105a3de17f8a..b2415d579145f5 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -350,6 +350,11 @@ def test_var_annot_syntax_errors(self): check_syntax_error(self, "x: int: str") check_syntax_error(self, "def f():\n" " nonlocal x: int\n") + check_syntax_error(self, "def f():\n" + " global x: int\n") + check_syntax_error(self, "x: int = y = 1") + check_syntax_error(self, "z = w: int = 1") + check_syntax_error(self, "x: int = y: int = 1") # AST pass check_syntax_error(self, "[x, 0]: int\n") check_syntax_error(self, "f(): int\n") @@ -363,6 +368,12 @@ def test_var_annot_syntax_errors(self): check_syntax_error(self, "def f():\n" " global x\n" " x: int\n") + check_syntax_error(self, "def f():\n" + " x: int\n" + " nonlocal x\n") + check_syntax_error(self, "def f():\n" + " nonlocal x\n" + " x: int\n") def test_var_annot_basic_semantics(self): # execution order From 4b749ba4702926fae1b89e9f215f5444b30e0e7f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:16:16 -0700 Subject: [PATCH 0713/1206] [3.12] gh-91960: Skip test_gdb if gdb cannot retrive Python frames (GH-108999) (#109010) gh-91960: Skip test_gdb if gdb cannot retrive Python frames (GH-108999) Skip test_gdb if gdb is unable to retrieve Python frame objects: if a frame is "". When Python is built with "clang -Og", gdb can fail to retrive the 'frame' parameter of _PyEval_EvalFrameDefault(). In this case, tests like py_bt() are likely to fail. Without getting access to Python frames, python-gdb.py is mostly clueless on retrieving the Python traceback. Moreover, test_gdb is no longer skipped on macOS if Python is built with Clang. (cherry picked from commit fbce43a251488f666be9794c908a6613bf8ae260) Co-authored-by: Victor Stinner --- Lib/test/test_gdb.py | 7 +++---- .../Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst | 7 +++++++ 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 78d602873fd86f..fa56761043f8af 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -55,10 +55,6 @@ def get_gdb_version(): if not sysconfig.is_python_build(): raise unittest.SkipTest("test_gdb only works on source builds at the moment.") -if 'Clang' in platform.python_compiler() and sys.platform == 'darwin': - raise unittest.SkipTest("test_gdb doesn't work correctly when python is" - " built with LLVM clang") - if ((sysconfig.get_config_var('PGO_PROF_USE_FLAG') or 'xxx') in (sysconfig.get_config_var('PY_CORE_CFLAGS') or '')): raise unittest.SkipTest("test_gdb is not reliable on PGO builds") @@ -247,6 +243,9 @@ def get_stack_trace(self, source=None, script=None, for pattern in ( '(frame information optimized out)', 'Unable to read information on python frame', + # gh-91960: On Python built with "clang -Og", gdb gets + # "frame=" for _PyEval_EvalFrameDefault() parameter + '(unable to read python frame information)', ): if pattern in out: raise unittest.SkipTest(f"{pattern!r} found in gdb output") diff --git a/Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst b/Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst new file mode 100644 index 00000000000000..46472abf9802bc --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst @@ -0,0 +1,7 @@ +Skip ``test_gdb`` if gdb is unable to retrieve Python frame objects: if a +frame is ````. When Python is built with "clang -Og", gdb can +fail to retrive the *frame* parameter of ``_PyEval_EvalFrameDefault()``. In +this case, tests like ``py_bt()`` are likely to fail. Without getting access +to Python frames, ``python-gdb.py`` is mostly clueless on retrieving the +Python traceback. Moreover, ``test_gdb`` is no longer skipped on macOS if +Python is built with Clang. Patch by Victor Stinner. From da02508a0e25cb2505950d960f105a3523c60530 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:16:55 -0700 Subject: [PATCH 0714/1206] [3.12] gh-89392: Use normal unittest runner in test_type_cache (GH-108911) (#108913) gh-89392: Use normal unittest runner in test_type_cache (GH-108911) (cherry picked from commit eaabaac7c099884f92428a7bb04ffa1f1d6080dd) Co-authored-by: Serhiy Storchaka --- Lib/test/test_type_cache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 24f83cd3e172c7..72587ecc11b6f3 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -58,4 +58,4 @@ class C: if __name__ == "__main__": - support.run_unittest(TypeCacheTests) + unittest.main() From 038b0a9cb0e5fee6f8e7cd2f503b5f02971fc660 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:17:14 -0700 Subject: [PATCH 0715/1206] [3.12] gh-89392: Use unittest test runner for doctests in test_getopt (GH-108916) (#108919) gh-89392: Use unittest test runner for doctests in test_getopt (GH-108916) (cherry picked from commit f980cc19b9cafc09ef21e906871f810a1c89e62f) Co-authored-by: Serhiy Storchaka --- Lib/test/test_getopt.py | 71 +++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_getopt.py b/Lib/test/test_getopt.py index c96a33b77fe272..c8b3442de4aa77 100644 --- a/Lib/test/test_getopt.py +++ b/Lib/test/test_getopt.py @@ -1,8 +1,8 @@ # test_getopt.py # David Goodger 2000-08-19 -from test.support import verbose, run_doctest from test.support.os_helper import EnvironmentVarGuard +import doctest import unittest import getopt @@ -134,48 +134,49 @@ def test_gnu_getopt(self): self.assertEqual(opts, [('-a', '')]) self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2']) - def test_libref_examples(self): - s = """ - Examples from the Library Reference: Doc/lib/libgetopt.tex + def test_issue4629(self): + longopts, shortopts = getopt.getopt(['--help='], '', ['help=']) + self.assertEqual(longopts, [('--help', '')]) + longopts, shortopts = getopt.getopt(['--help=x'], '', ['help=']) + self.assertEqual(longopts, [('--help', 'x')]) + self.assertRaises(getopt.GetoptError, getopt.getopt, ['--help='], '', ['help']) - An example using only Unix style options: +def test_libref_examples(): + """ + Examples from the Library Reference: Doc/lib/libgetopt.tex + An example using only Unix style options: - >>> import getopt - >>> args = '-a -b -cfoo -d bar a1 a2'.split() - >>> args - ['-a', '-b', '-cfoo', '-d', 'bar', 'a1', 'a2'] - >>> optlist, args = getopt.getopt(args, 'abc:d:') - >>> optlist - [('-a', ''), ('-b', ''), ('-c', 'foo'), ('-d', 'bar')] - >>> args - ['a1', 'a2'] - Using long option names is equally easy: + >>> import getopt + >>> args = '-a -b -cfoo -d bar a1 a2'.split() + >>> args + ['-a', '-b', '-cfoo', '-d', 'bar', 'a1', 'a2'] + >>> optlist, args = getopt.getopt(args, 'abc:d:') + >>> optlist + [('-a', ''), ('-b', ''), ('-c', 'foo'), ('-d', 'bar')] + >>> args + ['a1', 'a2'] + Using long option names is equally easy: - >>> s = '--condition=foo --testing --output-file abc.def -x a1 a2' - >>> args = s.split() - >>> args - ['--condition=foo', '--testing', '--output-file', 'abc.def', '-x', 'a1', 'a2'] - >>> optlist, args = getopt.getopt(args, 'x', [ - ... 'condition=', 'output-file=', 'testing']) - >>> optlist - [('--condition', 'foo'), ('--testing', ''), ('--output-file', 'abc.def'), ('-x', '')] - >>> args - ['a1', 'a2'] - """ - import types - m = types.ModuleType("libreftest", s) - run_doctest(m, verbose) + >>> s = '--condition=foo --testing --output-file abc.def -x a1 a2' + >>> args = s.split() + >>> args + ['--condition=foo', '--testing', '--output-file', 'abc.def', '-x', 'a1', 'a2'] + >>> optlist, args = getopt.getopt(args, 'x', [ + ... 'condition=', 'output-file=', 'testing']) + >>> optlist + [('--condition', 'foo'), ('--testing', ''), ('--output-file', 'abc.def'), ('-x', '')] + >>> args + ['a1', 'a2'] + """ + +def load_tests(loader, tests, pattern): + tests.addTest(doctest.DocTestSuite()) + return tests - def test_issue4629(self): - longopts, shortopts = getopt.getopt(['--help='], '', ['help=']) - self.assertEqual(longopts, [('--help', '')]) - longopts, shortopts = getopt.getopt(['--help=x'], '', ['help=']) - self.assertEqual(longopts, [('--help', 'x')]) - self.assertRaises(getopt.GetoptError, getopt.getopt, ['--help='], '', ['help']) if __name__ == "__main__": unittest.main() From 55d7e8fef135a0ce69b0ed19c8b06a4fb04934d1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:18:02 -0700 Subject: [PATCH 0716/1206] [3.12] gh-108851: Fix tomllib recursion tests (GH-108853) (#109012) gh-108851: Fix tomllib recursion tests (GH-108853) * Add get_recursion_available() and get_recursion_depth() functions to the test.support module. * Change infinite_recursion() default max_depth from 75 to 100. * Fix test_tomllib recursion tests for WASI buildbots: reduce the recursion limit and compute the maximum nested array/dict depending on the current available recursion limit. * test.pythoninfo logs sys.getrecursionlimit(). * Enhance test_sys tests on sys.getrecursionlimit() and sys.setrecursionlimit(). (cherry picked from commit 8ff11425783806f8cb78e99f667546b1f7f3428e) Co-authored-by: Victor Stinner --- Lib/test/pythoninfo.py | 1 + Lib/test/support/__init__.py | 43 ++++++++++- Lib/test/test_support.py | 77 +++++++++++++++++++ Lib/test/test_sys.py | 65 ++++++++-------- Lib/test/test_tomllib/test_misc.py | 27 +++++-- ...-09-03-21-18-35.gh-issue-108851.CCuHyI.rst | 2 + ...-09-03-21-41-10.gh-issue-108851.xFTYOE.rst | 3 + 7 files changed, 177 insertions(+), 41 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst create mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index adc211b3e2169c..1f75f669636d05 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -112,6 +112,7 @@ def collect_sys(info_add): call_func(info_add, 'sys.androidapilevel', sys, 'getandroidapilevel') call_func(info_add, 'sys.windowsversion', sys, 'getwindowsversion') + call_func(info_add, 'sys.getrecursionlimit', sys, 'getrecursionlimit') encoding = sys.getfilesystemencoding() if hasattr(sys, 'getfilesystemencodeerrors'): diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 878b6fc13a9da4..b6350e4e5292fe 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2243,6 +2243,39 @@ def check_disallow_instantiation(testcase, tp, *args, **kwds): msg = f"cannot create '{re.escape(qualname)}' instances" testcase.assertRaisesRegex(TypeError, msg, tp, *args, **kwds) +def get_recursion_depth(): + """Get the recursion depth of the caller function. + + In the __main__ module, at the module level, it should be 1. + """ + try: + import _testinternalcapi + depth = _testinternalcapi.get_recursion_depth() + except (ImportError, RecursionError) as exc: + # sys._getframe() + frame.f_back implementation. + try: + depth = 0 + frame = sys._getframe() + while frame is not None: + depth += 1 + frame = frame.f_back + finally: + # Break any reference cycles. + frame = None + + # Ignore get_recursion_depth() frame. + return max(depth - 1, 1) + +def get_recursion_available(): + """Get the number of available frames before RecursionError. + + It depends on the current recursion depth of the caller function and + sys.getrecursionlimit(). + """ + limit = sys.getrecursionlimit() + depth = get_recursion_depth() + return limit - depth + @contextlib.contextmanager def set_recursion_limit(limit): """Temporarily change the recursion limit.""" @@ -2253,14 +2286,18 @@ def set_recursion_limit(limit): finally: sys.setrecursionlimit(original_limit) -def infinite_recursion(max_depth=75): +def infinite_recursion(max_depth=100): """Set a lower limit for tests that interact with infinite recursions (e.g test_ast.ASTHelpers_Test.test_recursion_direct) since on some debug windows builds, due to not enough functions being inlined the stack size might not handle the default recursion limit (1000). See bpo-11105 for details.""" - return set_recursion_limit(max_depth) - + if max_depth < 3: + raise ValueError("max_depth must be at least 3, got {max_depth}") + depth = get_recursion_depth() + depth = max(depth - 1, 1) # Ignore infinite_recursion() frame. + limit = depth + max_depth + return set_recursion_limit(limit) def ignore_deprecations_from(module: str, *, like: str) -> object: token = object() diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 23c6bd226b5bf6..4047e0bd0164a5 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -688,6 +688,83 @@ def test_has_strftime_extensions(self): else: self.assertTrue(support.has_strftime_extensions) + def test_get_recursion_depth(self): + # test support.get_recursion_depth() + code = textwrap.dedent(""" + from test import support + import sys + + def check(cond): + if not cond: + raise AssertionError("test failed") + + # depth 1 + check(support.get_recursion_depth() == 1) + + # depth 2 + def test_func(): + check(support.get_recursion_depth() == 2) + test_func() + + def test_recursive(depth, limit): + if depth >= limit: + # cannot call get_recursion_depth() at this depth, + # it can raise RecursionError + return + get_depth = support.get_recursion_depth() + print(f"test_recursive: {depth}/{limit}: " + f"get_recursion_depth() says {get_depth}") + check(get_depth == depth) + test_recursive(depth + 1, limit) + + # depth up to 25 + with support.infinite_recursion(max_depth=25): + limit = sys.getrecursionlimit() + print(f"test with sys.getrecursionlimit()={limit}") + test_recursive(2, limit) + + # depth up to 500 + with support.infinite_recursion(max_depth=500): + limit = sys.getrecursionlimit() + print(f"test with sys.getrecursionlimit()={limit}") + test_recursive(2, limit) + """) + script_helper.assert_python_ok("-c", code) + + def test_recursion(self): + # Test infinite_recursion() and get_recursion_available() functions. + def recursive_function(depth): + if depth: + recursive_function(depth - 1) + + for max_depth in (5, 25, 250): + with support.infinite_recursion(max_depth): + available = support.get_recursion_available() + + # Recursion up to 'available' additional frames should be OK. + recursive_function(available) + + # Recursion up to 'available+1' additional frames must raise + # RecursionError. Avoid self.assertRaises(RecursionError) which + # can consume more than 3 frames and so raises RecursionError. + try: + recursive_function(available + 1) + except RecursionError: + pass + else: + self.fail("RecursionError was not raised") + + # Test the bare minimumum: max_depth=3 + with support.infinite_recursion(3): + try: + recursive_function(3) + except RecursionError: + pass + else: + self.fail("RecursionError was not raised") + + #self.assertEqual(available, 2) + # XXX -follows a list of untested API # make_legacy_pyc # is_resource_enabled diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index d81501f6f1df6a..c3e9f9c406815f 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -269,20 +269,29 @@ def test_switchinterval(self): finally: sys.setswitchinterval(orig) - def test_recursionlimit(self): + def test_getrecursionlimit(self): + limit = sys.getrecursionlimit() + self.assertIsInstance(limit, int) + self.assertGreater(limit, 1) + self.assertRaises(TypeError, sys.getrecursionlimit, 42) - oldlimit = sys.getrecursionlimit() - self.assertRaises(TypeError, sys.setrecursionlimit) - self.assertRaises(ValueError, sys.setrecursionlimit, -42) - sys.setrecursionlimit(10000) - self.assertEqual(sys.getrecursionlimit(), 10000) - sys.setrecursionlimit(oldlimit) + + def test_setrecursionlimit(self): + old_limit = sys.getrecursionlimit() + try: + sys.setrecursionlimit(10_005) + self.assertEqual(sys.getrecursionlimit(), 10_005) + + self.assertRaises(TypeError, sys.setrecursionlimit) + self.assertRaises(ValueError, sys.setrecursionlimit, -42) + finally: + sys.setrecursionlimit(old_limit) def test_recursionlimit_recovery(self): if hasattr(sys, 'gettrace') and sys.gettrace(): self.skipTest('fatal error if run with a trace function') - oldlimit = sys.getrecursionlimit() + old_limit = sys.getrecursionlimit() def f(): f() try: @@ -301,35 +310,31 @@ def f(): with self.assertRaises(RecursionError): f() finally: - sys.setrecursionlimit(oldlimit) + sys.setrecursionlimit(old_limit) @test.support.cpython_only - def test_setrecursionlimit_recursion_depth(self): + def test_setrecursionlimit_to_depth(self): # Issue #25274: Setting a low recursion limit must be blocked if the # current recursion depth is already higher than limit. - from _testinternalcapi import get_recursion_depth - - def set_recursion_limit_at_depth(depth, limit): - recursion_depth = get_recursion_depth() - if recursion_depth >= depth: - with self.assertRaises(RecursionError) as cm: - sys.setrecursionlimit(limit) - self.assertRegex(str(cm.exception), - "cannot set the recursion limit to [0-9]+ " - "at the recursion depth [0-9]+: " - "the limit is too low") - else: - set_recursion_limit_at_depth(depth, limit) - - oldlimit = sys.getrecursionlimit() + old_limit = sys.getrecursionlimit() try: - sys.setrecursionlimit(1000) - - for limit in (10, 25, 50, 75, 100, 150, 200): - set_recursion_limit_at_depth(limit, limit) + depth = support.get_recursion_depth() + with self.subTest(limit=sys.getrecursionlimit(), depth=depth): + # depth + 1 is OK + sys.setrecursionlimit(depth + 1) + + # reset the limit to be able to call self.assertRaises() + # context manager + sys.setrecursionlimit(old_limit) + with self.assertRaises(RecursionError) as cm: + sys.setrecursionlimit(depth) + self.assertRegex(str(cm.exception), + "cannot set the recursion limit to [0-9]+ " + "at the recursion depth [0-9]+: " + "the limit is too low") finally: - sys.setrecursionlimit(oldlimit) + sys.setrecursionlimit(old_limit) def test_getwindowsversion(self): # Raise SkipTest if sys doesn't have getwindowsversion attribute diff --git a/Lib/test/test_tomllib/test_misc.py b/Lib/test/test_tomllib/test_misc.py index a477a219fd9ebd..9e677a337a2835 100644 --- a/Lib/test/test_tomllib/test_misc.py +++ b/Lib/test/test_tomllib/test_misc.py @@ -9,6 +9,7 @@ import sys import tempfile import unittest +from test import support from . import tomllib @@ -92,13 +93,23 @@ def test_deepcopy(self): self.assertEqual(obj_copy, expected_obj) def test_inline_array_recursion_limit(self): - # 465 with default recursion limit - nest_count = int(sys.getrecursionlimit() * 0.465) - recursive_array_toml = "arr = " + nest_count * "[" + nest_count * "]" - tomllib.loads(recursive_array_toml) + with support.infinite_recursion(max_depth=100): + available = support.get_recursion_available() + nest_count = (available // 2) - 2 + # Add details if the test fails + with self.subTest(limit=sys.getrecursionlimit(), + available=available, + nest_count=nest_count): + recursive_array_toml = "arr = " + nest_count * "[" + nest_count * "]" + tomllib.loads(recursive_array_toml) def test_inline_table_recursion_limit(self): - # 310 with default recursion limit - nest_count = int(sys.getrecursionlimit() * 0.31) - recursive_table_toml = nest_count * "key = {" + nest_count * "}" - tomllib.loads(recursive_table_toml) + with support.infinite_recursion(max_depth=100): + available = support.get_recursion_available() + nest_count = (available // 3) - 1 + # Add details if the test fails + with self.subTest(limit=sys.getrecursionlimit(), + available=available, + nest_count=nest_count): + recursive_table_toml = nest_count * "key = {" + nest_count * "}" + tomllib.loads(recursive_table_toml) diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst b/Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst new file mode 100644 index 00000000000000..7a5b3052af22f2 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst @@ -0,0 +1,2 @@ +Add ``get_recursion_available()`` and ``get_recursion_depth()`` functions to +the :mod:`test.support` module. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst b/Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst new file mode 100644 index 00000000000000..b35aaebb410afb --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst @@ -0,0 +1,3 @@ +Fix ``test_tomllib`` recursion tests for WASI buildbots: reduce the recursion +limit and compute the maximum nested array/dict depending on the current +available recursion limit. Patch by Victor Stinner. From de0202e937ead659d97f0b243fda3db48720c79f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 8 Sep 2023 15:19:20 +0200 Subject: [PATCH 0717/1206] [3.12] gh-108740: Fix "make regen-all" race condition (#108741) (#109019) gh-108740: Fix "make regen-all" race condition (#108741) Fix a race condition in "make regen-all". The deepfreeze.c source and files generated by Argument Clinic are now generated or updated before generating "global objects". Previously, some identifiers may miss depending on the order in which these files were generated. * "make regen-global-objects": Make sure that deepfreeze.c is generated and up to date, and always run "make clinic". * "make clinic" no longer runs generate_global_objects.py script. * "make regen-deepfreeze" now only updates deepfreeze.c (C file). It doesn't build deepfreeze.o (object) anymore. * Remove misleading messages in "make regen-global-objects" and "make clinic". They are now outdated, these commands are now safe to use. * Document generates files in Doc/using/configure.rst. Co-authored-by: Erlend E. Aasland (cherry picked from commit db1ee6a19ab62191c16ecb732cb4dcaede98a902) --- Doc/using/configure.rst | 23 +++++++++++++++++++ Makefile.pre.in | 19 +++++++-------- ...-09-01-01-39-26.gh-issue-108740.JHExAQ.rst | 4 ++++ Tools/build/freeze_modules.py | 2 +- 4 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 791d3ad7f4071a..00520000b871cd 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -43,6 +43,29 @@ See also :pep:`7` "Style Guide for C Code" and :pep:`11` "CPython platform support". +Generated files +=============== + +To reduce build dependencies, Python source code contains multiple generated +files. Commands to regenerate all generated files:: + + make regen-all + make regen-stdlib-module-names + make regen-limited-abi + make regen-configure + +The ``Makefile.pre.in`` file documents generated files, their inputs, and tools used +to regenerate them. Search for ``regen-*`` make targets. + +The ``make regen-configure`` command runs `tiran/cpython_autoconf +`_ container for reproducible build; +see container ``entry.sh`` script. The container is optional, the following +command can be run locally, the generated files depend on autoconf and aclocal +versions:: + + autoreconf -ivf -Werror + + .. _configure-options: Configure Options diff --git a/Makefile.pre.in b/Makefile.pre.in index 0372c1a49ca244..09ceccda1dcde5 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -487,6 +487,7 @@ OBJECT_OBJS= \ Objects/weakrefobject.o \ @PERF_TRAMPOLINE_OBJ@ +DEEPFREEZE_C = Python/deepfreeze/deepfreeze.c DEEPFREEZE_OBJS = Python/deepfreeze/deepfreeze.o ########################################################################## @@ -774,7 +775,6 @@ coverage-report: regen-token regen-frozen .PHONY: clinic clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c $(PYTHON_FOR_REGEN) $(srcdir)/Tools/clinic/clinic.py --make --srcdir $(srcdir) - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_global_objects.py # Build the interpreter $(BUILDPYTHON): Programs/python.o $(LINK_PYTHON_DEPS) @@ -1245,12 +1245,12 @@ regen-frozen: Tools/build/freeze_modules.py $(FROZEN_FILES_IN) # Deepfreeze targets .PHONY: regen-deepfreeze -regen-deepfreeze: $(DEEPFREEZE_OBJS) +regen-deepfreeze: $(DEEPFREEZE_C) DEEPFREEZE_DEPS=$(srcdir)/Tools/build/deepfreeze.py $(FREEZE_MODULE_DEPS) $(FROZEN_FILES_OUT) # BEGIN: deepfreeze modules -Python/deepfreeze/deepfreeze.c: $(DEEPFREEZE_DEPS) +$(DEEPFREEZE_C): $(DEEPFREEZE_DEPS) $(PYTHON_FOR_FREEZE) $(srcdir)/Tools/build/deepfreeze.py \ Python/frozen_modules/importlib._bootstrap.h:importlib._bootstrap \ Python/frozen_modules/importlib._bootstrap_external.h:importlib._bootstrap_external \ @@ -1277,8 +1277,6 @@ Python/deepfreeze/deepfreeze.c: $(DEEPFREEZE_DEPS) Python/frozen_modules/frozen_only.h:frozen_only \ -o Python/deepfreeze/deepfreeze.c # END: deepfreeze modules - @echo "Note: Deepfreeze may have added some global objects," - @echo " so run 'make regen-global-objects' if necessary." # We keep this renamed target around for folks with muscle memory. .PHONY: regen-importlib @@ -1287,11 +1285,12 @@ regen-importlib: regen-frozen ############################################################################ # Global objects +# Dependencies which can add and/or remove _Py_ID() identifiers: +# - deepfreeze.c +# - "make clinic" .PHONY: regen-global-objects -regen-global-objects: $(srcdir)/Tools/build/generate_global_objects.py +regen-global-objects: $(srcdir)/Tools/build/generate_global_objects.py $(DEEPFREEZE_C) clinic $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_global_objects.py - @echo "Note: Global objects can be added or removed by other tools (e.g. deepfreeze), " - @echo " so be sure to re-run regen-global-objects after those tools." ############################################################################ # ABI @@ -1313,9 +1312,10 @@ regen-limited-abi: all ############################################################################ # Regenerate all generated files +# "clinic" is regenerated implicitly via "regen-global-objects". .PHONY: regen-all regen-all: regen-cases regen-opcode regen-opcode-targets regen-typeslots \ - regen-token regen-ast regen-keyword regen-sre regen-frozen clinic \ + regen-token regen-ast regen-keyword regen-sre regen-frozen \ regen-pegen-metaparser regen-pegen regen-test-frozenmain \ regen-test-levenshtein regen-global-objects @echo @@ -2586,6 +2586,7 @@ recheck: autoconf: (cd $(srcdir); autoreconf -ivf -Werror) +# See https://github.com/tiran/cpython_autoconf container .PHONY: regen-configure regen-configure: @if command -v podman >/dev/null; then RUNTIME="podman"; else RUNTIME="docker"; fi; \ diff --git a/Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst b/Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst new file mode 100644 index 00000000000000..190d50387f339e --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst @@ -0,0 +1,4 @@ +Fix a race condition in ``make regen-all``. The ``deepfreeze.c`` source and +files generated by Argument Clinic are now generated or updated before +generating "global objects". Previously, some identifiers may miss depending +on the order in which these files were generated. Patch by Victor Stinner. diff --git a/Tools/build/freeze_modules.py b/Tools/build/freeze_modules.py index ee4dd2f8682ba4..12200979fa4bc7 100644 --- a/Tools/build/freeze_modules.py +++ b/Tools/build/freeze_modules.py @@ -585,7 +585,7 @@ def regen_makefile(modules): pyfiles = [] frozenfiles = [] rules = [''] - deepfreezerules = ["Python/deepfreeze/deepfreeze.c: $(DEEPFREEZE_DEPS)", + deepfreezerules = ["$(DEEPFREEZE_C): $(DEEPFREEZE_DEPS)", "\t$(PYTHON_FOR_FREEZE) $(srcdir)/Tools/build/deepfreeze.py \\"] for src in _iter_sources(modules): frozen_header = relpath_for_posix_display(src.frozenfile, ROOT_DIR) From 2979cee1af755eac6eab02acbe7d90048ba011f4 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:19:38 -0700 Subject: [PATCH 0718/1206] [3.12] gh-108915: Removes extra backslashes in str.split docstring (GH-109044). (#109061) * [3.12] gh-108915: Removes extra backslashes in str.split docstring (GH-109044). (cherry picked from commit e7d5433f944a5725aa82595f9251abfc8a63d333) Co-authored-by: Daniel Weiss <134341009+justdan6@users.noreply.github.com> * re-clinic --------- Co-authored-by: Daniel Weiss <134341009+justdan6@users.noreply.github.com> --- Objects/clinic/unicodeobject.c.h | 6 +++--- Objects/unicodeobject.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index f640c997577363..d3769eb079f0a2 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -934,7 +934,7 @@ PyDoc_STRVAR(unicode_split__doc__, " The separator used to split the string.\n" "\n" " When set to None (the default value), will split on any whitespace\n" -" character (including \\\\n \\\\r \\\\t \\\\f and spaces) and will discard\n" +" character (including \\n \\r \\t \\f and spaces) and will discard\n" " empty strings from the result.\n" " maxsplit\n" " Maximum number of splits (starting from the left).\n" @@ -1058,7 +1058,7 @@ PyDoc_STRVAR(unicode_rsplit__doc__, " The separator used to split the string.\n" "\n" " When set to None (the default value), will split on any whitespace\n" -" character (including \\\\n \\\\r \\\\t \\\\f and spaces) and will discard\n" +" character (including \\n \\r \\t \\f and spaces) and will discard\n" " empty strings from the result.\n" " maxsplit\n" " Maximum number of splits (starting from the left).\n" @@ -1497,4 +1497,4 @@ unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=05d942840635dadf input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32edbbf75dc8a03b input=a9049054013a1b77]*/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 3fbc2d297cdd56..26aa13913d98a0 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -12361,7 +12361,7 @@ str.split as unicode_split The separator used to split the string. When set to None (the default value), will split on any whitespace - character (including \\n \\r \\t \\f and spaces) and will discard + character (including \n \r \t \f and spaces) and will discard empty strings from the result. maxsplit: Py_ssize_t = -1 Maximum number of splits (starting from the left). @@ -12377,7 +12377,7 @@ the regular expression module. static PyObject * unicode_split_impl(PyObject *self, PyObject *sep, Py_ssize_t maxsplit) -/*[clinic end generated code: output=3a65b1db356948dc input=906d953b44efc43b]*/ +/*[clinic end generated code: output=3a65b1db356948dc input=07b9040d98c5fe8d]*/ { if (sep == Py_None) return split(self, NULL, maxsplit); From 8c9f5f714e1126a3610194196fdd03d156b73dbd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:20:05 -0700 Subject: [PATCH 0719/1206] [3.12] test.pythoninfo logs freedesktop_os_release() (GH-109057) (#109064) test.pythoninfo logs freedesktop_os_release() (GH-109057) (cherry picked from commit babdced23fc299b7607ac76abfdd7a81050f8359) Co-authored-by: Victor Stinner --- Lib/test/pythoninfo.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 1f75f669636d05..8d7fb9f4f2103b 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -164,6 +164,26 @@ def collect_platform(info_add): if libc_ver: info_add('platform.libc_ver', libc_ver) + try: + os_release = platform.freedesktop_os_release() + except OSError: + pass + else: + for key in ( + 'ID', + 'NAME', + 'PRETTY_NAME' + 'VARIANT', + 'VARIANT_ID', + 'VERSION', + 'VERSION_CODENAME', + 'VERSION_ID', + ): + if key not in os_release: + continue + info_add(f'platform.freedesktop_os_release[{key}]', + os_release[key]) + def collect_locale(info_add): import locale @@ -913,7 +933,6 @@ def dump_info(info, file=None): for key, value in infos: value = value.replace("\n", " ") print("%s: %s" % (key, value)) - print() def main(): @@ -922,6 +941,7 @@ def main(): dump_info(info) if error: + print() print("Collection failed: exit with error", file=sys.stderr) sys.exit(1) From 29404b6d255b41989b0e490539781db824b368b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:21:38 -0700 Subject: [PATCH 0720/1206] [3.12] gh-103186: Suppress and assert expected RuntimeWarnings in test_sys_settrace (GH-103244) (#109066) gh-103186: Suppress and assert expected RuntimeWarnings in test_sys_settrace (GH-103244) Caused as a result of frame manipulation where locals are never assigned / initialised. (cherry picked from commit 3e53ac99038920550358c1ea0212c3907a8cb385) Co-authored-by: Ijtaba Hussain --- Lib/test/test_sys_settrace.py | 74 +++++++++++-------- ...-04-05-06-45-20.gh-issue-103186.640Eg-.rst | 1 + 2 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 59dd23348c866d..568c16044afe06 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -8,6 +8,7 @@ from functools import wraps import asyncio from test.support import import_helper +import contextlib support.requires_working_socket(module=True) @@ -1900,6 +1901,8 @@ def no_jump_without_trace_function(): class JumpTestCase(unittest.TestCase): + unbound_locals = r"assigning None to [0-9]+ unbound local" + def setUp(self): self.addCleanup(sys.settrace, sys.gettrace()) sys.settrace(None) @@ -1911,33 +1914,39 @@ def compare_jump_output(self, expected, received): "Received: " + repr(received)) def run_test(self, func, jumpFrom, jumpTo, expected, error=None, - event='line', decorated=False): + event='line', decorated=False, warning=None): tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) sys.settrace(tracer.trace) output = [] - if error is None: + + with contextlib.ExitStack() as stack: + if error is not None: + stack.enter_context(self.assertRaisesRegex(*error)) + if warning is not None: + stack.enter_context(self.assertWarnsRegex(*warning)) func(output) - else: - with self.assertRaisesRegex(*error): - func(output) + sys.settrace(None) self.compare_jump_output(expected, output) def run_async_test(self, func, jumpFrom, jumpTo, expected, error=None, - event='line', decorated=False): + event='line', decorated=False, warning=None): tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) sys.settrace(tracer.trace) output = [] - if error is None: + + with contextlib.ExitStack() as stack: + if error is not None: + stack.enter_context(self.assertRaisesRegex(*error)) + if warning is not None: + stack.enter_context(self.assertWarnsRegex(*warning)) asyncio.run(func(output)) - else: - with self.assertRaisesRegex(*error): - asyncio.run(func(output)) + sys.settrace(None) asyncio.set_event_loop_policy(None) self.compare_jump_output(expected, output) - def jump_test(jumpFrom, jumpTo, expected, error=None, event='line'): + def jump_test(jumpFrom, jumpTo, expected, error=None, event='line', warning=None): """Decorator that creates a test that makes a jump from one place to another in the following code. """ @@ -1945,11 +1954,11 @@ def decorator(func): @wraps(func) def test(self): self.run_test(func, jumpFrom, jumpTo, expected, - error=error, event=event, decorated=True) + error=error, event=event, decorated=True, warning=warning) return test return decorator - def async_jump_test(jumpFrom, jumpTo, expected, error=None, event='line'): + def async_jump_test(jumpFrom, jumpTo, expected, error=None, event='line', warning=None): """Decorator that creates a test that makes a jump from one place to another in the following asynchronous code. """ @@ -1957,7 +1966,7 @@ def decorator(func): @wraps(func) def test(self): self.run_async_test(func, jumpFrom, jumpTo, expected, - error=error, event=event, decorated=True) + error=error, event=event, decorated=True, warning=warning) return test return decorator @@ -1974,7 +1983,7 @@ def test_jump_simple_backwards(output): output.append(1) output.append(2) - @jump_test(3, 5, [2, 5]) + @jump_test(3, 5, [2, 5], warning=(RuntimeWarning, unbound_locals)) def test_jump_out_of_block_forwards(output): for i in 1, 2: output.append(2) @@ -2188,7 +2197,7 @@ def test_jump_within_except_block(output): output.append(6) output.append(7) - @jump_test(6, 1, [1, 5, 1, 5]) + @jump_test(6, 1, [1, 5, 1, 5], warning=(RuntimeWarning, unbound_locals)) def test_jump_over_try_except(output): output.append(1) try: @@ -2284,7 +2293,7 @@ def test_jump_out_of_complex_nested_blocks(output): output.append(11) output.append(12) - @jump_test(3, 5, [1, 2, 5]) + @jump_test(3, 5, [1, 2, 5], warning=(RuntimeWarning, unbound_locals)) def test_jump_out_of_with_assignment(output): output.append(1) with tracecontext(output, 2) \ @@ -2292,7 +2301,7 @@ def test_jump_out_of_with_assignment(output): output.append(4) output.append(5) - @async_jump_test(3, 5, [1, 2, 5]) + @async_jump_test(3, 5, [1, 2, 5], warning=(RuntimeWarning, unbound_locals)) async def test_jump_out_of_async_with_assignment(output): output.append(1) async with asynctracecontext(output, 2) \ @@ -2328,7 +2337,7 @@ def test_jump_over_break_in_try_finally_block(output): break output.append(13) - @jump_test(1, 7, [7, 8]) + @jump_test(1, 7, [7, 8], warning=(RuntimeWarning, unbound_locals)) def test_jump_over_for_block_before_else(output): output.append(1) if not output: # always false @@ -2339,7 +2348,7 @@ def test_jump_over_for_block_before_else(output): output.append(7) output.append(8) - @async_jump_test(1, 7, [7, 8]) + @async_jump_test(1, 7, [7, 8], warning=(RuntimeWarning, unbound_locals)) async def test_jump_over_async_for_block_before_else(output): output.append(1) if not output: # always false @@ -2414,6 +2423,7 @@ def test_no_jump_backwards_into_for_block(output): output.append(2) output.append(3) + @async_jump_test(3, 2, [2, 2], (ValueError, "can't jump into the body of a for loop")) async def test_no_jump_backwards_into_async_for_block(output): async for i in asynciter([1, 2]): @@ -2479,7 +2489,7 @@ def test_jump_backwards_into_try_except_block(output): output.append(6) # 'except' with a variable creates an implicit finally block - @jump_test(5, 7, [4, 7, 8]) + @jump_test(5, 7, [4, 7, 8], warning=(RuntimeWarning, unbound_locals)) def test_jump_between_except_blocks_2(output): try: 1/0 @@ -2642,7 +2652,7 @@ def test_large_function(self): output.append(x) # line 1007 return""" % ('\n' * 1000,), d) f = d['f'] - self.run_test(f, 2, 1007, [0]) + self.run_test(f, 2, 1007, [0], warning=(RuntimeWarning, self.unbound_locals)) def test_jump_to_firstlineno(self): # This tests that PDB can jump back to the first line in a @@ -2692,7 +2702,7 @@ def gen(): next(gen()) output.append(5) - @jump_test(2, 3, [1, 3]) + @jump_test(2, 3, [1, 3], warning=(RuntimeWarning, unbound_locals)) def test_jump_forward_over_listcomp(output): output.append(1) x = [i for i in range(10)] @@ -2700,13 +2710,13 @@ def test_jump_forward_over_listcomp(output): # checking for segfaults. # See https://github.com/python/cpython/issues/92311 - @jump_test(3, 1, []) + @jump_test(3, 1, [], warning=(RuntimeWarning, unbound_locals)) def test_jump_backward_over_listcomp(output): a = 1 x = [i for i in range(10)] c = 3 - @jump_test(8, 2, [2, 7, 2]) + @jump_test(8, 2, [2, 7, 2], warning=(RuntimeWarning, unbound_locals)) def test_jump_backward_over_listcomp_v2(output): flag = False output.append(2) @@ -2717,19 +2727,19 @@ def test_jump_backward_over_listcomp_v2(output): output.append(7) output.append(8) - @async_jump_test(2, 3, [1, 3]) + @async_jump_test(2, 3, [1, 3], warning=(RuntimeWarning, unbound_locals)) async def test_jump_forward_over_async_listcomp(output): output.append(1) x = [i async for i in asynciter(range(10))] output.append(3) - @async_jump_test(3, 1, []) + @async_jump_test(3, 1, [], warning=(RuntimeWarning, unbound_locals)) async def test_jump_backward_over_async_listcomp(output): a = 1 x = [i async for i in asynciter(range(10))] c = 3 - @async_jump_test(8, 2, [2, 7, 2]) + @async_jump_test(8, 2, [2, 7, 2], warning=(RuntimeWarning, unbound_locals)) async def test_jump_backward_over_async_listcomp_v2(output): flag = False output.append(2) @@ -2798,13 +2808,13 @@ def test_jump_with_null_on_stack_load_attr(output): ) output.append(15) - @jump_test(2, 3, [1, 3]) + @jump_test(2, 3, [1, 3], warning=(RuntimeWarning, unbound_locals)) def test_jump_extended_args_unpack_ex_simple(output): output.append(1) _, *_, _ = output.append(2) or "Spam" output.append(3) - @jump_test(3, 4, [1, 4, 4, 5]) + @jump_test(3, 4, [1, 4, 4, 5], warning=(RuntimeWarning, unbound_locals)) def test_jump_extended_args_unpack_ex_tricky(output): output.append(1) ( @@ -2826,9 +2836,9 @@ def test_jump_extended_args_for_iter(self): namespace = {} exec("\n".join(source), namespace) f = namespace["f"] - self.run_test(f, 2, 100_000, [1, 100_000]) + self.run_test(f, 2, 100_000, [1, 100_000], warning=(RuntimeWarning, self.unbound_locals)) - @jump_test(2, 3, [1, 3]) + @jump_test(2, 3, [1, 3], warning=(RuntimeWarning, unbound_locals)) def test_jump_or_pop(output): output.append(1) _ = output.append(2) and "Spam" diff --git a/Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst b/Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst new file mode 100644 index 00000000000000..2f596aa5f47bda --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst @@ -0,0 +1 @@ +Suppress and assert expected RuntimeWarnings in test_sys_settrace.py From 736c413977730fa590a759d2eca3d2ac611fd5ec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:21:51 -0700 Subject: [PATCH 0721/1206] [3.12] bpo-38157: Add example about per file output for mock_open. (GH-16090) (#109071) bpo-38157: Add example about per file output for mock_open. (GH-16090) (cherry picked from commit e183a71eef1ec3ac86bb4d81a158c21d6f1a783b) Co-authored-by: Karthikeyan Singaravelan Co-authored-by: Stanley <46876382+slateny@users.noreply.github.com> Co-authored-by: Jelle Zijlstra Co-authored-by: Hugo van Kemenade --- Doc/library/unittest.mock-examples.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 744fc9de63cd16..34f343ebacdbb7 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -360,6 +360,30 @@ of arbitrary attributes as well as the getting of them then you can use *spec_set* instead of *spec*. +Using side_effect to return per file content +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:func:`mock_open` is used to patch :func:`open` method. :attr:`~Mock.side_effect` +can be used to return a new Mock object per call. This can be used to return different +contents per file stored in a dictionary:: + + DEFAULT = "default" + data_dict = {"file1": "data1", + "file2": "data2"} + + def open_side_effect(name): + return mock_open(read_data=data_dict.get(name, DEFAULT))() + + with patch("builtins.open", side_effect=open_side_effect): + with open("file1") as file1: + assert file1.read() == "data1" + + with open("file2") as file2: + assert file2.read() == "data2" + + with open("file3") as file2: + assert file2.read() == "default" + Patch Decorators ---------------- From 26f42b34f1e67b286655f79d73fd249935d46d12 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:22:08 -0700 Subject: [PATCH 0722/1206] [3.12] GH-90915: Document that SystemExit doesn't trigger sys.excepthook (GH-31357) (#109082) GH-90915: Document that SystemExit doesn't trigger sys.excepthook (GH-31357) (cherry picked from commit 1294fcede09af6c781553b7a3a6ff612c7dfa431) Co-authored-by: Colin Watson Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/library/sys.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 20a337bdf0f595..26bee990cf5d7f 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -378,7 +378,7 @@ always available. This function prints out a given traceback and exception to ``sys.stderr``. - When an exception is raised and uncaught, the interpreter calls + When an exception other than :exc:`SystemExit` is raised and uncaught, the interpreter calls ``sys.excepthook`` with three arguments, the exception class, exception instance, and a traceback object. In an interactive session this happens just before control is returned to the prompt; in a Python program this happens just From 02e51f86d8fcb283e47f67cfd613cc923571c2db Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:22:19 -0700 Subject: [PATCH 0723/1206] [3.12] gh-103186: Remove debug print in test_sys_settrace (GH-109077) (#109084) gh-103186: Remove debug print in test_sys_settrace (GH-109077) (cherry picked from commit e4bb0026b9a21d066e7a5c4716ea4d755b95d2d5) Co-authored-by: Serhiy Storchaka --- Lib/test/test_sys_settrace.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 568c16044afe06..6fb9099bd36f62 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1632,7 +1632,6 @@ def error_once(frame, event, arg): except Exception as ex: count = 0 tb = ex.__traceback__ - print(tb) while tb: if tb.tb_frame.f_code.co_name == "test_settrace_error": count += 1 From 82f5291a1d4bac8a072ecdd0796116d98fee5791 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:22:33 -0700 Subject: [PATCH 0724/1206] [3.12] gh-71770: Add more details on behavior of configparser's default_section (GH-31562) (#109088) gh-71770: Add more details on behavior of configparser's default_section (GH-31562) (cherry picked from commit 891236f48263e2d4c650b7a127fc9bffb8327807) Co-authored-by: Stanley <46876382+slateny@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/library/configparser.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index a7f75fd6e84f4c..bb282428c5fffc 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -935,8 +935,10 @@ ConfigParser Objects When *default_section* is given, it specifies the name for the special section holding default values for other sections and interpolation purposes - (normally named ``"DEFAULT"``). This value can be retrieved and changed on - runtime using the ``default_section`` instance attribute. + (normally named ``"DEFAULT"``). This value can be retrieved and changed at + runtime using the ``default_section`` instance attribute. This won't + re-evaluate an already parsed config file, but will be used when writing + parsed settings to a new config file. Interpolation behaviour may be customized by providing a custom handler through the *interpolation* argument. ``None`` can be used to turn off From 2ce26121b1b7f19867988c6bd98d1761e57770b7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:23:12 -0700 Subject: [PATCH 0725/1206] [3.12] socket documentation fix - rename triple to 3-tuple (GH-24722) (#109073) socket documentation fix - rename triple to 3-tuple (GH-24722) (cherry picked from commit 6b15ff52351787644115a4dd9d5d6717d66b9806) Co-authored-by: Ori Hoch Co-authored-by: Hugo van Kemenade --- Doc/library/socket.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 4f220e8a098979..83957c87990440 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -979,7 +979,7 @@ The :mod:`socket` module also offers various network-related services: .. function:: gethostbyname_ex(hostname) Translate a host name to IPv4 address format, extended interface. Return a - triple ``(hostname, aliaslist, ipaddrlist)`` where *hostname* is the host's + 3-tuple ``(hostname, aliaslist, ipaddrlist)`` where *hostname* is the host's primary host name, *aliaslist* is a (possibly empty) list of alternative host names for the same address, and *ipaddrlist* is a list of IPv4 addresses for the same interface on the same host (often but not @@ -1007,7 +1007,7 @@ The :mod:`socket` module also offers various network-related services: .. function:: gethostbyaddr(ip_address) - Return a triple ``(hostname, aliaslist, ipaddrlist)`` where *hostname* is the + Return a 3-tuple ``(hostname, aliaslist, ipaddrlist)`` where *hostname* is the primary host name responding to the given *ip_address*, *aliaslist* is a (possibly empty) list of alternative host names for the same address, and *ipaddrlist* is a list of IPv4/v6 addresses for the same interface on the same From 4cb29bb6832760bc021adc8b8e973e3f3e4d044e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:23:41 -0700 Subject: [PATCH 0726/1206] [3.12] gh-102823: Document return type of floor division on floats (GH-102824) (#109092) gh-102823: Document return type of floor division on floats (GH-102824) (cherry picked from commit b72251de930c8ec6893f1b3f6fdf1640cc17dfed) Co-authored-by: Mark Dickinson Co-authored-by: Hugo van Kemenade --- Doc/library/stdtypes.rst | 8 +++++--- .../2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 804342386abd7f..50f56603911182 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -282,7 +282,7 @@ the operations, see :ref:`operator-summary`): +---------------------+---------------------------------+---------+--------------------+ | ``x / y`` | quotient of *x* and *y* | | | +---------------------+---------------------------------+---------+--------------------+ -| ``x // y`` | floored quotient of *x* and | \(1) | | +| ``x // y`` | floored quotient of *x* and | \(1)\(2)| | | | *y* | | | +---------------------+---------------------------------+---------+--------------------+ | ``x % y`` | remainder of ``x / y`` | \(2) | | @@ -319,8 +319,10 @@ the operations, see :ref:`operator-summary`): Notes: (1) - Also referred to as integer division. The resultant value is a whole - integer, though the result's type is not necessarily int. The result is + Also referred to as integer division. For operands of type :class:`int`, + the result has type :class:`int`. For operands of type :class:`float`, + the result has type :class:`float`. In general, the result is a whole + integer, though the result's type is not necessarily :class:`int`. The result is always rounded towards minus infinity: ``1//2`` is ``0``, ``(-1)//2`` is ``-1``, ``1//(-2)`` is ``-1``, and ``(-1)//(-2)`` is ``0``. diff --git a/Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst b/Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst new file mode 100644 index 00000000000000..1e32f3c89231c8 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst @@ -0,0 +1,2 @@ +Document the return type of ``x // y`` when ``x`` and ``y`` have type +:class:`float`. From b27ca96a0f6de9a1f53c0accffc5aa6e6ab81b60 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:24:18 -0700 Subject: [PATCH 0727/1206] [3.12] gh-107924: re-order os.sendfile() flag documentation (GH-107926) (#109099) gh-107924: re-order os.sendfile() flag documentation (GH-107926) (cherry picked from commit 403ab1306a6e9860197bce57eadcb83418966f21) Co-authored-by: Christoph Anton Mitterer Co-authored-by: Hugo van Kemenade --- Doc/library/os.rst | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 4f4d8c99023529..c67b966f777db8 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1618,25 +1618,6 @@ or `the MSDN `_ on Windo Parameters *out* and *in* was renamed to *out_fd* and *in_fd*. -.. function:: set_blocking(fd, blocking, /) - - Set the blocking mode of the specified file descriptor. Set the - :data:`O_NONBLOCK` flag if blocking is ``False``, clear the flag otherwise. - - See also :func:`get_blocking` and :meth:`socket.socket.setblocking`. - - .. availability:: Unix, Windows. - - The function is limited on Emscripten and WASI, see - :ref:`wasm-availability` for more information. - - On Windows, this function is limited to pipes. - - .. versionadded:: 3.5 - - .. versionchanged:: 3.12 - Added support for pipes on Windows. - .. data:: SF_NODISKIO SF_MNOWAIT SF_SYNC @@ -1658,6 +1639,26 @@ or `the MSDN `_ on Windo .. versionadded:: 3.11 +.. function:: set_blocking(fd, blocking, /) + + Set the blocking mode of the specified file descriptor. Set the + :data:`O_NONBLOCK` flag if blocking is ``False``, clear the flag otherwise. + + See also :func:`get_blocking` and :meth:`socket.socket.setblocking`. + + .. availability:: Unix, Windows. + + The function is limited on Emscripten and WASI, see + :ref:`wasm-availability` for more information. + + On Windows, this function is limited to pipes. + + .. versionadded:: 3.5 + + .. versionchanged:: 3.12 + Added support for pipes on Windows. + + .. function:: splice(src, dst, count, offset_src=None, offset_dst=None) Transfer *count* bytes from file descriptor *src*, starting from offset From 41ff5b0674fce5a6c5c6841634ff90ffe19694a8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:24:55 -0700 Subject: [PATCH 0728/1206] [3.12] gh-75743: Restore test_timeout.testConnectTimeout() (GH-109087) (#109103) gh-75743: Restore test_timeout.testConnectTimeout() (GH-109087) This un-skips this test now that pythontest.net implements appropriate firewall rules for it. (cherry picked from commit 1829a3c9a3712b6a68a3a449e4a08787c73da51d) Co-authored-by: Ee Durbin --- Lib/test/test_timeout.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_timeout.py b/Lib/test/test_timeout.py index 30e843a423a777..35ff56f1a5ee09 100644 --- a/Lib/test/test_timeout.py +++ b/Lib/test/test_timeout.py @@ -148,13 +148,12 @@ def setUp(self): def tearDown(self): self.sock.close() - @unittest.skipIf(True, 'need to replace these hosts; see bpo-35518') def testConnectTimeout(self): # Testing connect timeout is tricky: we need to have IP connectivity # to a host that silently drops our packets. We can't simulate this # from Python because it's a function of the underlying TCP/IP stack. - # So, the following Snakebite host has been defined: - blackhole = resolve_address('blackhole.snakebite.net', 56666) + # So, the following port on the pythontest.net host has been defined: + blackhole = resolve_address('pythontest.net', 56666) # Blackhole has been configured to silently drop any incoming packets. # No RSTs (for TCP) or ICMP UNREACH (for UDP/ICMP) will be sent back @@ -166,7 +165,7 @@ def testConnectTimeout(self): # to firewalling or general network configuration. In order to improve # our confidence in testing the blackhole, a corresponding 'whitehole' # has also been set up using one port higher: - whitehole = resolve_address('whitehole.snakebite.net', 56667) + whitehole = resolve_address('pythontest.net', 56667) # This address has been configured to immediately drop any incoming # packets as well, but it does it respectfully with regards to the @@ -180,20 +179,15 @@ def testConnectTimeout(self): # timeframe). # For the records, the whitehole/blackhole configuration has been set - # up using the 'pf' firewall (available on BSDs), using the following: + # up using the 'iptables' firewall, using the following rules: # - # ext_if="bge0" - # - # blackhole_ip="35.8.247.6" - # whitehole_ip="35.8.247.6" - # blackhole_port="56666" - # whitehole_port="56667" - # - # block return in log quick on $ext_if proto { tcp udp } \ - # from any to $whitehole_ip port $whitehole_port - # block drop in log quick on $ext_if proto { tcp udp } \ - # from any to $blackhole_ip port $blackhole_port + # -A INPUT -p tcp --destination-port 56666 -j DROP + # -A INPUT -p udp --destination-port 56666 -j DROP + # -A INPUT -p tcp --destination-port 56667 -j REJECT + # -A INPUT -p udp --destination-port 56667 -j REJECT # + # See https://github.com/python/psf-salt/blob/main/pillar/base/firewall/snakebite.sls + # for the current configuration. skip = True sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) From 68ba35eecbb493d3f24a82eda5ba3cb89bcda4e5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:25:18 -0700 Subject: [PATCH 0729/1206] [3.12] gh-68403: Fix test_coverage in test_trace (GH-108910) (#109104) gh-68403: Fix test_coverage in test_trace (GH-108910) Its behavior no longer affected by test running options such as -m. (cherry picked from commit 7e1a7abb9831965cdec477e62dbe4f8415b8a582) Co-authored-by: Serhiy Storchaka --- Lib/test/test_trace.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index d1ef005a4314ed..c1e289bcaff9e5 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -360,9 +360,14 @@ def tearDown(self): rmtree(TESTFN) unlink(TESTFN) - def _coverage(self, tracer, - cmd='import test.support, test.test_pprint;' - 'test.support.run_unittest(test.test_pprint.QueryTestCase)'): + DEFAULT_SCRIPT = '''if True: + import unittest + from test.test_pprint import QueryTestCase + loader = unittest.TestLoader() + tests = loader.loadTestsFromTestCase(QueryTestCase) + tests(unittest.TestResult()) + ''' + def _coverage(self, tracer, cmd=DEFAULT_SCRIPT): tracer.run(cmd) r = tracer.results() r.write_results(show_missing=True, summary=True, coverdir=TESTFN) From fff524ede8ed9530b03042cb46d42393b51bb6c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 06:25:55 -0700 Subject: [PATCH 0730/1206] [3.12] Add version directives to ast docs (GH-108788) (#109106) Add version directives to ast docs (GH-108788) (cherry picked from commit 74fc96bc60f5c02bde50ff2f3516add99483e402) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Doc/library/ast.rst | 46 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 9c76443983b155..a7fa8074493dec 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -650,10 +650,10 @@ Expressions .. class:: NamedExpr(target, value) - A named expression. This AST node is produced by the assignment expressions - operator (also known as the walrus operator). As opposed to the :class:`Assign` - node in which the first argument can be multiple nodes, in this case both - ``target`` and ``value`` must be single nodes. + A named expression. This AST node is produced by the assignment expressions + operator (also known as the walrus operator). As opposed to the :class:`Assign` + node in which the first argument can be multiple nodes, in this case both + ``target`` and ``value`` must be single nodes. .. doctest:: @@ -663,6 +663,7 @@ Expressions target=Name(id='x', ctx=Store()), value=Constant(value=4))) + .. versionadded:: 3.8 Subscripting ~~~~~~~~~~~~ @@ -1036,6 +1037,7 @@ Statements value=Name(id='int', ctx=Load()))], type_ignores=[]) + .. versionadded:: 3.12 Other statements which are only applicable inside functions or loops are described in other sections. @@ -1318,6 +1320,7 @@ Control flow finalbody=[])], type_ignores=[]) + .. versionadded:: 3.11 .. class:: ExceptHandler(type, name, body) @@ -1407,6 +1410,8 @@ Pattern matching that is being matched against the cases) and ``cases`` contains an iterable of :class:`match_case` nodes with the different cases. + .. versionadded:: 3.10 + .. class:: match_case(pattern, guard, body) A single case pattern in a ``match`` statement. ``pattern`` contains the @@ -1458,6 +1463,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchValue(value) A match literal or value pattern that compares by equality. ``value`` is @@ -1485,6 +1492,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchSingleton(value) A match literal pattern that compares by identity. ``value`` is the @@ -1510,6 +1519,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchSequence(patterns) A match sequence pattern. ``patterns`` contains the patterns to be matched @@ -1541,6 +1552,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchStar(name) Matches the rest of the sequence in a variable length match sequence pattern. @@ -1581,6 +1594,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchMapping(keys, patterns, rest) A match mapping pattern. ``keys`` is a sequence of expression nodes. @@ -1627,6 +1642,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchClass(cls, patterns, kwd_attrs, kwd_patterns) A match class pattern. ``cls`` is an expression giving the nominal class to @@ -1691,6 +1708,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchAs(pattern, name) A match "as-pattern", capture pattern or wildcard pattern. ``pattern`` @@ -1732,6 +1751,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. class:: MatchOr(patterns) A match "or-pattern". An or-pattern matches each of its subpatterns in turn @@ -1764,6 +1785,8 @@ Pattern matching value=Constant(value=Ellipsis))])])], type_ignores=[]) + .. versionadded:: 3.10 + .. _ast-type-params: Type parameters @@ -1795,6 +1818,8 @@ aliases. ctx=Load()))], type_ignores=[]) + .. versionadded:: 3.12 + .. class:: ParamSpec(name) A :class:`typing.ParamSpec`. ``name`` is the name of the parameter specification. @@ -1818,6 +1843,8 @@ aliases. ctx=Load()))], type_ignores=[]) + .. versionadded:: 3.12 + .. class:: TypeVarTuple(name) A :class:`typing.TypeVarTuple`. ``name`` is the name of the type variable tuple. @@ -1842,6 +1869,8 @@ aliases. ctx=Load()))], type_ignores=[]) + .. versionadded:: 3.12 + Function and class definitions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1861,6 +1890,9 @@ Function and class definitions ``type_comment`` is an optional string with the type annotation as a comment. + .. versionchanged:: 3.12 + Added ``type_params``. + .. class:: Lambda(args, body) @@ -2059,6 +2091,9 @@ Function and class definitions type_params=[])], type_ignores=[]) + .. versionchanged:: 3.12 + Added ``type_params``. + Async and await ^^^^^^^^^^^^^^^ @@ -2067,6 +2102,9 @@ Async and await An ``async def`` function definition. Has the same fields as :class:`FunctionDef`. + .. versionchanged:: 3.12 + Added ``type_params``. + .. class:: Await(value) From a1ba0e531cd42189d205b249bc6340a0b1027909 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 08:56:11 -0700 Subject: [PATCH 0731/1206] [3.12] gh-103186: Suppress RuntimeWarning about unclosed async iterator in test_sys_settrace (GH-109075) (#109138) gh-103186: Suppress RuntimeWarning about unclosed async iterator in test_sys_settrace (GH-109075) (cherry picked from commit d485551c9d1792ff3539eef1d6374bd4c01dcd5d) Co-authored-by: Serhiy Storchaka --- Lib/test/test_sys_settrace.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 6fb9099bd36f62..eef43e8c0e56ee 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -41,6 +41,20 @@ async def asynciter(iterable): for x in iterable: yield x +def clean_asynciter(test): + @wraps(test) + async def wrapper(*args, **kwargs): + cleanups = [] + def wrapped_asynciter(iterable): + it = asynciter(iterable) + cleanups.append(it.aclose) + return it + try: + return await test(*args, **kwargs, asynciter=wrapped_asynciter) + finally: + while cleanups: + await cleanups.pop()() + return wrapper # A very basic example. If this fails, we're in deep trouble. def basic(): @@ -1914,7 +1928,11 @@ def compare_jump_output(self, expected, received): def run_test(self, func, jumpFrom, jumpTo, expected, error=None, event='line', decorated=False, warning=None): - tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) + wrapped = func + while hasattr(wrapped, '__wrapped__'): + wrapped = wrapped.__wrapped__ + + tracer = JumpTracer(wrapped, jumpFrom, jumpTo, event, decorated) sys.settrace(tracer.trace) output = [] @@ -1930,7 +1948,11 @@ def run_test(self, func, jumpFrom, jumpTo, expected, error=None, def run_async_test(self, func, jumpFrom, jumpTo, expected, error=None, event='line', decorated=False, warning=None): - tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) + wrapped = func + while hasattr(wrapped, '__wrapped__'): + wrapped = wrapped.__wrapped__ + + tracer = JumpTracer(wrapped, jumpFrom, jumpTo, event, decorated) sys.settrace(tracer.trace) output = [] @@ -2001,7 +2023,8 @@ def test_jump_out_of_block_backwards(output): output.append(7) @async_jump_test(4, 5, [3, 5]) - async def test_jump_out_of_async_for_block_forwards(output): + @clean_asynciter + async def test_jump_out_of_async_for_block_forwards(output, asynciter): for i in [1]: async for i in asynciter([1, 2]): output.append(3) @@ -2009,7 +2032,8 @@ async def test_jump_out_of_async_for_block_forwards(output): output.append(5) @async_jump_test(5, 2, [2, 4, 2, 4, 5, 6]) - async def test_jump_out_of_async_for_block_backwards(output): + @clean_asynciter + async def test_jump_out_of_async_for_block_backwards(output, asynciter): for i in [1]: output.append(2) async for i in asynciter([1]): From af83d1e8214efc806488226d206c24462686bd1d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 8 Sep 2023 10:04:28 -0700 Subject: [PATCH 0732/1206] [3.12] gh-106922: Fix error location for constructs with spaces and parentheses (GH-108959) (#109147) Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_traceback.py | 36 +++++++++++++++++++ Lib/traceback.py | 16 +++++++-- ...-09-05-20-52-17.gh-issue-108959.6z45Sy.rst | 2 ++ Python/traceback.c | 17 +++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7bfeda8dc95b04..e84e8fecdf1b50 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -596,6 +596,24 @@ def f_with_binary_operator(): result_lines = self.get_exception(f_with_binary_operator) self.assertEqual(result_lines, expected_error.splitlines()) + def test_caret_for_binary_operators_with_spaces_and_parenthesis(self): + def f_with_binary_operator(): + a = 1 + b = "" + return ( a ) + b + + lineno_f = f_with_binary_operator.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n' + ' return ( a ) + b\n' + ' ~~~~~~~~~~^~~\n' + ) + result_lines = self.get_exception(f_with_binary_operator) + self.assertEqual(result_lines, expected_error.splitlines()) + def test_caret_for_subscript(self): def f_with_subscript(): some_dict = {'x': {'y': None}} @@ -630,6 +648,24 @@ def f_with_subscript(): result_lines = self.get_exception(f_with_subscript) self.assertEqual(result_lines, expected_error.splitlines()) + def test_caret_for_subscript_with_spaces_and_parenthesis(self): + def f_with_binary_operator(): + a = [] + b = c = 1 + return b [ a ] + c + + lineno_f = f_with_binary_operator.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n' + ' return b [ a ] + c\n' + ' ~~~~~~^^^^^^^^^\n' + ) + result_lines = self.get_exception(f_with_binary_operator) + self.assertEqual(result_lines, expected_error.splitlines()) + def test_traceback_specialization_with_syntax_error(self): bytecode = compile("1 / 0 / 1 / 2\n", TESTFN, "exec") diff --git a/Lib/traceback.py b/Lib/traceback.py index 21e32040ee9872..813e13e1e0cc2b 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -608,11 +608,21 @@ def _extract_caret_anchors_from_line_segment(segment): and not operator_str[operator_offset + 1].isspace() ): right_anchor += 1 + + while left_anchor < len(segment) and ((ch := segment[left_anchor]).isspace() or ch in ")#"): + left_anchor += 1 + right_anchor += 1 return _Anchors(normalize(left_anchor), normalize(right_anchor)) case ast.Subscript(): - subscript_start = normalize(expr.value.end_col_offset) - subscript_end = normalize(expr.slice.end_col_offset + 1) - return _Anchors(subscript_start, subscript_end) + left_anchor = normalize(expr.value.end_col_offset) + right_anchor = normalize(expr.slice.end_col_offset + 1) + while left_anchor < len(segment) and ((ch := segment[left_anchor]).isspace() or ch != "["): + left_anchor += 1 + while right_anchor < len(segment) and ((ch := segment[right_anchor]).isspace() or ch != "]"): + right_anchor += 1 + if right_anchor < len(segment): + right_anchor += 1 + return _Anchors(left_anchor, right_anchor) return None diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst new file mode 100644 index 00000000000000..792bbc454f2b27 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst @@ -0,0 +1,2 @@ +Fix caret placement for error locations for subscript and binary operations +that involve non-semantic parentheses and spaces. Patch by Pablo Galindo diff --git a/Python/traceback.c b/Python/traceback.c index b2479542047308..dc258703a8c49a 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -615,6 +615,11 @@ extract_anchors_from_expr(const char *segment_str, expr_ty expr, Py_ssize_t *lef ++*right_anchor; } + // Keep going if the current char is not ')' + if (i+1 < right->col_offset && (segment_str[i] == ')')) { + continue; + } + // Set the error characters *primary_error_char = "~"; *secondary_error_char = "^"; @@ -625,6 +630,18 @@ extract_anchors_from_expr(const char *segment_str, expr_ty expr, Py_ssize_t *lef case Subscript_kind: { *left_anchor = expr->v.Subscript.value->end_col_offset; *right_anchor = expr->v.Subscript.slice->end_col_offset + 1; + Py_ssize_t str_len = strlen(segment_str); + + // Move right_anchor and left_anchor forward to the first non-whitespace character that is not ']' and '[' + while (*left_anchor < str_len && (IS_WHITESPACE(segment_str[*left_anchor]) || segment_str[*left_anchor] != '[')) { + ++*left_anchor; + } + while (*right_anchor < str_len && (IS_WHITESPACE(segment_str[*right_anchor]) || segment_str[*right_anchor] != ']')) { + ++*right_anchor; + } + if (*right_anchor < str_len){ + *right_anchor += 1; + } // Set the error characters *primary_error_char = "~"; From d533ab17ec37b457a5cc286f30c7559e358492bf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 06:50:29 -0700 Subject: [PATCH 0733/1206] [3.12] gh-108732: include comprehension locals in frame.f_locals (GH-109026) (#109097) gh-108732: include comprehension locals in frame.f_locals (GH-109026) (cherry picked from commit f2584eade378910b9ea18072bb1dab3dd58e23bb) Co-authored-by: Carl Meyer Co-authored-by: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> Co-authored-by: Jelle Zijlstra --- Lib/test/test_listcomps.py | 7 +++++++ .../2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst | 2 ++ Objects/frameobject.c | 14 ++++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index bedd99b4a44fcb..c1089574d71b02 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -596,6 +596,13 @@ def test_exception_in_post_comp_call(self): """ self._check_in_scopes(code, {"value": [1, None]}) + def test_frame_locals(self): + code = """ + val = [sys._getframe().f_locals for a in [0]][0]["a"] + """ + import sys + self._check_in_scopes(code, {"val": 0}, ns={"sys": sys}) + __test__ = {'doctests' : doctests} diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst new file mode 100644 index 00000000000000..94a143b86b6708 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst @@ -0,0 +1,2 @@ +Make iteration variables of module- and class-scoped comprehensions visible +to pdb and other tools that use ``frame.f_locals`` again. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index ba365750bd4d2b..30c8d3c5270cad 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -24,10 +24,16 @@ static PyMemberDef frame_memberlist[] = { static PyObject * frame_getlocals(PyFrameObject *f, void *closure) { - if (PyFrame_FastToLocalsWithError(f) < 0) + if (f == NULL) { + PyErr_BadInternalCall(); return NULL; - PyObject *locals = f->f_frame->f_locals; - return Py_NewRef(locals); + } + assert(!_PyFrame_IsIncomplete(f->f_frame)); + PyObject *locals = _PyFrame_GetLocals(f->f_frame, 1); + if (locals) { + f->f_fast_as_locals = 1; + } + return locals; } int @@ -1351,11 +1357,11 @@ PyFrame_GetVarString(PyFrameObject *frame, const char *name) int PyFrame_FastToLocalsWithError(PyFrameObject *f) { - assert(!_PyFrame_IsIncomplete(f->f_frame)); if (f == NULL) { PyErr_BadInternalCall(); return -1; } + assert(!_PyFrame_IsIncomplete(f->f_frame)); int err = _PyFrame_FastToLocalsWithError(f->f_frame); if (err == 0) { f->f_fast_as_locals = 1; From ca848bbf78cf82447cc5c2fe6822c82f6f9e59c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 06:53:16 -0700 Subject: [PATCH 0734/1206] [3.12] gh-109022: [Enum] require `names=()` to create empty enum type (GH-109048) (#109122) gh-109022: [Enum] require `names=()` to create empty enum type (GH-109048) add guard so that ``Enum('bar')`` raises a TypeError instead of creating a new enum class called `bar`. To create the new but empty class, use: huh = Enum('bar', names=()) (cherry picked from commit c74e440168fab9bf91346471087a394af13fa2db) Co-authored-by: Ethan Furman --- Lib/enum.py | 5 +++++ Lib/test/test_enum.py | 11 +++++++---- .../2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst diff --git a/Lib/enum.py b/Lib/enum.py index 9c0af9e56d8ee5..c207dc234c0da2 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -739,6 +739,11 @@ def __call__(cls, value, names=None, *values, module=None, qualname=None, type=N value = (value, names) + values return cls.__new__(cls, value) # otherwise, functional API: we're creating a new Enum type + if names is None and type is None: + # no body? no data-type? possibly wrong usage + raise TypeError( + f"{cls} has no members; specify `names=()` if you meant to create a new, empty, enum" + ) return cls._create_( class_name=value, names=names, diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index dc60caccaa435c..14f16f7f26efc3 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -276,6 +276,7 @@ def __str__(self): return self.name.title() def __format__(self, spec): return ''.join(reversed(self.name)) + self.NewBaseEnum = NewBaseEnum class NewSubEnum(NewBaseEnum): first = auto() self.NewSubEnum = NewSubEnum @@ -342,10 +343,8 @@ def __str__(self): return self.name.title() def __format__(self, spec): return ''.join(reversed(self.name)) - NewBaseEnum = self.enum_type('NewBaseEnum', dict(__format__=__format__, __str__=__str__)) - class NewSubEnum(NewBaseEnum): - first = auto() - self.NewSubEnum = NewBaseEnum('NewSubEnum', 'first') + self.NewBaseEnum = self.enum_type('NewBaseEnum', dict(__format__=__format__, __str__=__str__)) + self.NewSubEnum = self.NewBaseEnum('NewSubEnum', 'first') # def _generate_next_value_(name, start, last, values): pass @@ -561,6 +560,10 @@ class SubEnum(SuperEnum): self.assertTrue('description' not in dir(SubEnum)) self.assertTrue('description' in dir(SubEnum.sample), dir(SubEnum.sample)) + def test_empty_enum_has_no_values(self): + with self.assertRaisesRegex(TypeError, "<.... 'NewBaseEnum'> has no members"): + self.NewBaseEnum(7) + def test_enum_in_enum_out(self): Main = self.MainEnum self.assertIs(Main(Main.first), Main.first) diff --git a/Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst b/Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst new file mode 100644 index 00000000000000..8c13d43ee9744b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst @@ -0,0 +1,2 @@ +Enum: require ``names=()`` or ``type=...`` to create an empty enum using +the functional syntax. From c76f4b97dcede6790a0e43d7d36179a298bbf0a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 06:56:02 -0700 Subject: [PATCH 0735/1206] [3.12] GH-109067: fix randomly failing `test_async_gen_asyncio_gc_aclose_09` test (GH-109142) (#109149) GH-109067: fix randomly failing `test_async_gen_asyncio_gc_aclose_09` test (GH-109142) Use `asyncio.sleep(0)` instead of short sleeps. (cherry picked from commit ccd48623d4860e730a16f3f252d67bfea8c1e905) Co-authored-by: Kumar Aditya --- Lib/test/test_asyncgen.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 09e4010b0e53d6..9a9343781cd40c 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -1057,8 +1057,7 @@ async def gen(): while True: yield 1 finally: - await asyncio.sleep(0.01) - await asyncio.sleep(0.01) + await asyncio.sleep(0) DONE = 1 async def run(): @@ -1068,7 +1067,10 @@ async def run(): del g gc_collect() # For PyPy or other GCs. - await asyncio.sleep(0.1) + # Starts running the aclose task + await asyncio.sleep(0) + # For asyncio.sleep(0) in finally block + await asyncio.sleep(0) self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) From acde502e8a692a322ea43c69059c01cc8f6d5bad Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 12 Sep 2023 06:59:09 -0700 Subject: [PATCH 0736/1206] [3.12] gh-109118: Fix runtime crash when NameError happens in PEP 695 function (GH-109123) (#109173) * gh-109118: Fix runtime crash when NameError happens in PEP 695 function (#109123) (cherry picked from commit 17f994174de9211b2baaff217eeb1033343230fc) * [3.12] gh-109118: Fix runtime crash when NameError happens in PEP 695 function (GH-109123). (cherry picked from commit 17f994174de9211b2baaff217eeb1033343230fc) Co-authored-by: Jelle Zijlstra --- Lib/test/test_type_params.py | 40 + ...-09-07-18-24-42.gh-issue-109118.yPXRAe.rst | 2 + Python/bytecodes.c | 74 +- Python/generated_cases.c.h | 803 +++++++++--------- Python/opcode_metadata.h | 12 +- 5 files changed, 501 insertions(+), 430 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 0045057f181e1c..f93d088ea758a9 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -956,3 +956,43 @@ class NewStyle[T]: for case in cases: with self.subTest(case=case): weakref.ref(case) + + +class TypeParamsRuntimeTest(unittest.TestCase): + def test_name_error(self): + # gh-109118: This crashed the interpreter due to a refcounting bug + code = """ + class name_2[name_5]: + class name_4[name_5](name_0): + pass + """ + with self.assertRaises(NameError): + run_code(code) + + # Crashed with a slightly different stack trace + code = """ + class name_2[name_5]: + class name_4[name_5: name_5](name_0): + pass + """ + with self.assertRaises(NameError): + run_code(code) + + def test_broken_class_namespace(self): + code = """ + class WeirdMapping(dict): + def __missing__(self, key): + if key == "T": + raise RuntimeError + raise KeyError(key) + + class Meta(type): + def __prepare__(name, bases): + return WeirdMapping() + + class MyClass[V](metaclass=Meta): + class Inner[U](T): + pass + """ + with self.assertRaises(RuntimeError): + run_code(code) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst new file mode 100644 index 00000000000000..f14fce4423896f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst @@ -0,0 +1,2 @@ +Fix interpreter crash when a NameError is raised inside the type parameters +of a generic class. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5e80e06205ae4e..dfebaaa300fc8a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1165,7 +1165,7 @@ dummy_func( } } - op(_LOAD_LOCALS, ( -- locals)) { + inst(LOAD_LOCALS, ( -- locals)) { locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1175,9 +1175,7 @@ dummy_func( Py_INCREF(locals); } - macro(LOAD_LOCALS) = _LOAD_LOCALS; - - op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) { + inst(LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1185,7 +1183,6 @@ dummy_func( Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { - Py_DECREF(mod_or_class_dict); goto error; } } @@ -1193,13 +1190,11 @@ dummy_func( v = PyObject_GetItem(mod_or_class_dict, name); if (v == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(mod_or_class_dict); goto error; } _PyErr_Clear(tstate); } } - Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { @@ -1234,11 +1229,70 @@ dummy_func( } } } + DECREF_INPUTS(); } - macro(LOAD_NAME) = _LOAD_LOCALS + _LOAD_FROM_DICT_OR_GLOBALS; - - macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS; + inst(LOAD_NAME, (-- v)) { + PyObject *mod_or_class_dict = LOCALS(); + if (mod_or_class_dict == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + ERROR_IF(true, error); + } + PyObject *name = GETITEM(frame->f_code->co_names, oparg); + if (PyDict_CheckExact(mod_or_class_dict)) { + v = PyDict_GetItemWithError(mod_or_class_dict, name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; + } + } + else { + v = PyObject_GetItem(mod_or_class_dict, name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + goto error; + } + _PyErr_Clear(tstate); + } + } + if (v == NULL) { + v = PyDict_GetItemWithError(GLOBALS(), name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; + } + else { + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + Py_INCREF(v); + } + else { + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + } + } + } + } family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { LOAD_GLOBAL, diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a3c049569268c1..e4cff7bdc3384b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1619,174 +1619,149 @@ } TARGET(LOAD_LOCALS) { - PyObject *_tmp_1; - { - PyObject *locals; - #line 1169 "Python/bytecodes.c" - locals = LOCALS(); - if (locals == NULL) { - _PyErr_SetString(tstate, PyExc_SystemError, - "no locals found"); - if (true) goto error; - } - Py_INCREF(locals); - #line 1634 "Python/generated_cases.c.h" - _tmp_1 = locals; + PyObject *locals; + #line 1169 "Python/bytecodes.c" + locals = LOCALS(); + if (locals == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + if (true) goto error; } + Py_INCREF(locals); + #line 1632 "Python/generated_cases.c.h" STACK_GROW(1); - stack_pointer[-1] = _tmp_1; + stack_pointer[-1] = locals; DISPATCH(); } - TARGET(LOAD_NAME) { - PyObject *_tmp_1; - { - PyObject *locals; - #line 1169 "Python/bytecodes.c" - locals = LOCALS(); - if (locals == NULL) { - _PyErr_SetString(tstate, PyExc_SystemError, - "no locals found"); - if (true) goto error; + TARGET(LOAD_FROM_DICT_OR_GLOBALS) { + PyObject *mod_or_class_dict = stack_pointer[-1]; + PyObject *v; + #line 1179 "Python/bytecodes.c" + PyObject *name = GETITEM(frame->f_code->co_names, oparg); + if (PyDict_CheckExact(mod_or_class_dict)) { + v = PyDict_GetItemWithError(mod_or_class_dict, name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; } - Py_INCREF(locals); - #line 1654 "Python/generated_cases.c.h" - _tmp_1 = locals; } - { - PyObject *mod_or_class_dict = _tmp_1; - PyObject *v; - #line 1181 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); - if (PyDict_CheckExact(mod_or_class_dict)) { - v = PyDict_GetItemWithError(mod_or_class_dict, name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(mod_or_class_dict); + else { + v = PyObject_GetItem(mod_or_class_dict, name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { goto error; } + _PyErr_Clear(tstate); + } + } + if (v == NULL) { + v = PyDict_GetItemWithError(GLOBALS(), name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; } else { - v = PyObject_GetItem(mod_or_class_dict, name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(mod_or_class_dict); + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } goto error; } - _PyErr_Clear(tstate); - } - } - Py_DECREF(mod_or_class_dict); - if (v == NULL) { - v = PyDict_GetItemWithError(GLOBALS(), name); - if (v != NULL) { Py_INCREF(v); } - else if (_PyErr_Occurred(tstate)) { - goto error; - } else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); - } - else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; } + goto error; } } } - #line 1717 "Python/generated_cases.c.h" - _tmp_1 = v; } - STACK_GROW(1); - stack_pointer[-1] = _tmp_1; + #line 1695 "Python/generated_cases.c.h" + Py_DECREF(mod_or_class_dict); + stack_pointer[-1] = v; DISPATCH(); } - TARGET(LOAD_FROM_DICT_OR_GLOBALS) { - PyObject *_tmp_1 = stack_pointer[-1]; - { - PyObject *mod_or_class_dict = _tmp_1; - PyObject *v; - #line 1181 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); - if (PyDict_CheckExact(mod_or_class_dict)) { - v = PyDict_GetItemWithError(mod_or_class_dict, name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(mod_or_class_dict); + TARGET(LOAD_NAME) { + PyObject *v; + #line 1236 "Python/bytecodes.c" + PyObject *mod_or_class_dict = LOCALS(); + if (mod_or_class_dict == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + if (true) goto error; + } + PyObject *name = GETITEM(frame->f_code->co_names, oparg); + if (PyDict_CheckExact(mod_or_class_dict)) { + v = PyDict_GetItemWithError(mod_or_class_dict, name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; + } + } + else { + v = PyObject_GetItem(mod_or_class_dict, name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { goto error; } + _PyErr_Clear(tstate); + } + } + if (v == NULL) { + v = PyDict_GetItemWithError(GLOBALS(), name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; } else { - v = PyObject_GetItem(mod_or_class_dict, name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(mod_or_class_dict); + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } goto error; } - _PyErr_Clear(tstate); - } - } - Py_DECREF(mod_or_class_dict); - if (v == NULL) { - v = PyDict_GetItemWithError(GLOBALS(), name); - if (v != NULL) { Py_INCREF(v); } - else if (_PyErr_Occurred(tstate)) { - goto error; - } else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); - } - else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; } + goto error; } } } - #line 1787 "Python/generated_cases.c.h" - _tmp_1 = v; } - stack_pointer[-1] = _tmp_1; + #line 1763 "Python/generated_cases.c.h" + STACK_GROW(1); + stack_pointer[-1] = v; DISPATCH(); } @@ -1795,7 +1770,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1250 "Python/bytecodes.c" + #line 1304 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1847,7 +1822,7 @@ } } null = NULL; - #line 1851 "Python/generated_cases.c.h" + #line 1826 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1861,7 +1836,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1304 "Python/bytecodes.c" + #line 1358 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1872,7 +1847,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1876 "Python/generated_cases.c.h" + #line 1851 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1887,7 +1862,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1317 "Python/bytecodes.c" + #line 1371 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1902,7 +1877,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1906 "Python/generated_cases.c.h" + #line 1881 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1912,16 +1887,16 @@ } TARGET(DELETE_FAST) { - #line 1334 "Python/bytecodes.c" + #line 1388 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1920 "Python/generated_cases.c.h" + #line 1895 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1340 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1930,12 +1905,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1934 "Python/generated_cases.c.h" + #line 1909 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1351 "Python/bytecodes.c" + #line 1405 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1946,14 +1921,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1950 "Python/generated_cases.c.h" + #line 1925 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1364 "Python/bytecodes.c" + #line 1418 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1988,14 +1963,14 @@ } Py_INCREF(value); } - #line 1992 "Python/generated_cases.c.h" + #line 1967 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1401 "Python/bytecodes.c" + #line 1455 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2003,7 +1978,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2007 "Python/generated_cases.c.h" + #line 1982 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2011,18 +1986,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1411 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2020 "Python/generated_cases.c.h" + #line 1995 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1418 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -2033,22 +2008,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2037 "Python/generated_cases.c.h" + #line 2012 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1431 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2046 "Python/generated_cases.c.h" + #line 2021 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1433 "Python/bytecodes.c" + #line 1487 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2052 "Python/generated_cases.c.h" + #line 2027 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2058,10 +2033,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1437 "Python/bytecodes.c" + #line 1491 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2065 "Python/generated_cases.c.h" + #line 2040 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2071,10 +2046,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1442 "Python/bytecodes.c" + #line 1496 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2078 "Python/generated_cases.c.h" + #line 2053 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2084,7 +2059,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1447 "Python/bytecodes.c" + #line 1501 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2095,13 +2070,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2099 "Python/generated_cases.c.h" + #line 2074 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1458 "Python/bytecodes.c" + #line 1512 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2105 "Python/generated_cases.c.h" + #line 2080 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2110,13 +2085,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1465 "Python/bytecodes.c" + #line 1519 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2116 "Python/generated_cases.c.h" + #line 2091 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1467 "Python/bytecodes.c" + #line 1521 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2120 "Python/generated_cases.c.h" + #line 2095 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2124,7 +2099,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1471 "Python/bytecodes.c" + #line 1525 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2139,7 +2114,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2143 "Python/generated_cases.c.h" + #line 2118 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2149,7 +2124,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1488 "Python/bytecodes.c" + #line 1542 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2157,13 +2132,13 @@ if (map == NULL) goto error; - #line 2161 "Python/generated_cases.c.h" + #line 2136 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1496 "Python/bytecodes.c" + #line 1550 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2167 "Python/generated_cases.c.h" + #line 2142 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2171,7 +2146,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1500 "Python/bytecodes.c" + #line 1554 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2211,7 +2186,7 @@ Py_DECREF(ann_dict); } } - #line 2215 "Python/generated_cases.c.h" + #line 2190 "Python/generated_cases.c.h" DISPATCH(); } @@ -2219,7 +2194,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1542 "Python/bytecodes.c" + #line 1596 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2229,14 +2204,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2233 "Python/generated_cases.c.h" + #line 2208 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1552 "Python/bytecodes.c" + #line 1606 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2240 "Python/generated_cases.c.h" + #line 2215 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2244,7 +2219,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1556 "Python/bytecodes.c" + #line 1610 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2252,12 +2227,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2256 "Python/generated_cases.c.h" + #line 2231 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1564 "Python/bytecodes.c" + #line 1618 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2261 "Python/generated_cases.c.h" + #line 2236 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2265,17 +2240,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1570 "Python/bytecodes.c" + #line 1624 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2274 "Python/generated_cases.c.h" + #line 2249 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1575 "Python/bytecodes.c" + #line 1629 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2279 "Python/generated_cases.c.h" + #line 2254 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2285,26 +2260,26 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1582 "Python/bytecodes.c" + #line 1636 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2295 "Python/generated_cases.c.h" + #line 2270 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1591 "Python/bytecodes.c" + #line 1645 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2308 "Python/generated_cases.c.h" + #line 2283 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2315,7 +2290,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1605 "Python/bytecodes.c" + #line 1659 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2357,16 +2332,16 @@ } } } - #line 2361 "Python/generated_cases.c.h" + #line 2336 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1647 "Python/bytecodes.c" + #line 1701 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2370 "Python/generated_cases.c.h" + #line 2345 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2381,20 +2356,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1654 "Python/bytecodes.c" + #line 1708 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2392 "Python/generated_cases.c.h" + #line 2367 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1661 "Python/bytecodes.c" + #line 1715 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2398 "Python/generated_cases.c.h" + #line 2373 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2409,7 +2384,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1665 "Python/bytecodes.c" + #line 1719 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2432,7 +2407,7 @@ res = res2; res2 = NULL; } - #line 2436 "Python/generated_cases.c.h" + #line 2411 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2446,7 +2421,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1704 "Python/bytecodes.c" + #line 1758 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2480,9 +2455,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2484 "Python/generated_cases.c.h" + #line 2459 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1738 "Python/bytecodes.c" + #line 1792 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2491,12 +2466,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2495 "Python/generated_cases.c.h" + #line 2470 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1747 "Python/bytecodes.c" + #line 1801 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2500 "Python/generated_cases.c.h" + #line 2475 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2510,7 +2485,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1752 "Python/bytecodes.c" + #line 1806 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2523,7 +2498,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2527 "Python/generated_cases.c.h" + #line 2502 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2538,7 +2513,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1768 "Python/bytecodes.c" + #line 1822 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2551,7 +2526,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2555 "Python/generated_cases.c.h" + #line 2530 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2566,7 +2541,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1784 "Python/bytecodes.c" + #line 1838 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2593,7 +2568,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2597 "Python/generated_cases.c.h" + #line 2572 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2608,7 +2583,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1814 "Python/bytecodes.c" + #line 1868 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2618,7 +2593,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2622 "Python/generated_cases.c.h" + #line 2597 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2633,7 +2608,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1827 "Python/bytecodes.c" + #line 1881 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2645,7 +2620,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2649 "Python/generated_cases.c.h" + #line 2624 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2659,7 +2634,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1842 "Python/bytecodes.c" + #line 1896 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2683,7 +2658,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2687 "Python/generated_cases.c.h" + #line 2662 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2691,7 +2666,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1868 "Python/bytecodes.c" + #line 1922 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2717,7 +2692,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2721 "Python/generated_cases.c.h" + #line 2696 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2725,7 +2700,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1896 "Python/bytecodes.c" + #line 1950 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2743,7 +2718,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2747 "Python/generated_cases.c.h" + #line 2722 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2754,7 +2729,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1916 "Python/bytecodes.c" + #line 1970 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2793,7 +2768,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2797 "Python/generated_cases.c.h" + #line 2772 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2804,7 +2779,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1957 "Python/bytecodes.c" + #line 2011 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2814,7 +2789,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2818 "Python/generated_cases.c.h" + #line 2793 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2826,7 +2801,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1976 "Python/bytecodes.c" + #line 2030 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2839,12 +2814,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2843 "Python/generated_cases.c.h" + #line 2818 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1989 "Python/bytecodes.c" + #line 2043 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2848 "Python/generated_cases.c.h" + #line 2823 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2855,7 +2830,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1993 "Python/bytecodes.c" + #line 2047 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2866,7 +2841,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2870 "Python/generated_cases.c.h" + #line 2845 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2877,7 +2852,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2007 "Python/bytecodes.c" + #line 2061 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2892,7 +2867,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2896 "Python/generated_cases.c.h" + #line 2871 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2903,7 +2878,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2025 "Python/bytecodes.c" + #line 2079 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2915,7 +2890,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2919 "Python/generated_cases.c.h" + #line 2894 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2926,14 +2901,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2039 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2932 "Python/generated_cases.c.h" + #line 2907 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2041 "Python/bytecodes.c" + #line 2095 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2937 "Python/generated_cases.c.h" + #line 2912 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2943,15 +2918,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2045 "Python/bytecodes.c" + #line 2099 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2949 "Python/generated_cases.c.h" + #line 2924 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2047 "Python/bytecodes.c" + #line 2101 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2955 "Python/generated_cases.c.h" + #line 2930 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2962,12 +2937,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2052 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2968 "Python/generated_cases.c.h" + #line 2943 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2054 "Python/bytecodes.c" + #line 2108 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2975,10 +2950,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2979 "Python/generated_cases.c.h" + #line 2954 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2062 "Python/bytecodes.c" + #line 2116 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2987,7 +2962,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2991 "Python/generated_cases.c.h" + #line 2966 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2997,21 +2972,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2073 "Python/bytecodes.c" + #line 2127 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3004 "Python/generated_cases.c.h" + #line 2979 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2076 "Python/bytecodes.c" + #line 2130 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3011 "Python/generated_cases.c.h" + #line 2986 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2081 "Python/bytecodes.c" + #line 2135 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3015 "Python/generated_cases.c.h" + #line 2990 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3020,15 +2995,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2085 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3027 "Python/generated_cases.c.h" + #line 3002 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2088 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3032 "Python/generated_cases.c.h" + #line 3007 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3037,29 +3012,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2092 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3045 "Python/generated_cases.c.h" + #line 3020 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2098 "Python/bytecodes.c" + #line 2152 "Python/bytecodes.c" JUMPBY(oparg); - #line 3054 "Python/generated_cases.c.h" + #line 3029 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2102 "Python/bytecodes.c" + #line 2156 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3063 "Python/generated_cases.c.h" + #line 3038 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3067,15 +3042,15 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2108 "Python/bytecodes.c" + #line 2162 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3077 "Python/generated_cases.c.h" + #line 3052 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2114 "Python/bytecodes.c" + #line 2168 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3083,22 +3058,22 @@ if (err < 0) goto pop_1_error; } } - #line 3087 "Python/generated_cases.c.h" + #line 3062 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2124 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3100 "Python/generated_cases.c.h" + #line 3075 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2130 "Python/bytecodes.c" + #line 2184 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3106,63 +3081,63 @@ if (err < 0) goto pop_1_error; } } - #line 3110 "Python/generated_cases.c.h" + #line 3085 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2140 "Python/bytecodes.c" + #line 2194 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3119 "Python/generated_cases.c.h" + #line 3094 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2142 "Python/bytecodes.c" + #line 2196 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3124 "Python/generated_cases.c.h" + #line 3099 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2147 "Python/bytecodes.c" + #line 2201 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3136 "Python/generated_cases.c.h" + #line 3111 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2152 "Python/bytecodes.c" + #line 2206 "Python/bytecodes.c" } - #line 3140 "Python/generated_cases.c.h" + #line 3115 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2156 "Python/bytecodes.c" + #line 2210 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3153 "Python/generated_cases.c.h" + #line 3128 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2165 "Python/bytecodes.c" + #line 2219 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3166 "Python/generated_cases.c.h" + #line 3141 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3173,16 +3148,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2173 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3182 "Python/generated_cases.c.h" + #line 3157 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2178 "Python/bytecodes.c" + #line 2232 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3190,7 +3165,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3194 "Python/generated_cases.c.h" + #line 3169 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3199,10 +3174,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2188 "Python/bytecodes.c" + #line 2242 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3206 "Python/generated_cases.c.h" + #line 3181 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3212,10 +3187,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2194 "Python/bytecodes.c" + #line 2248 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3219 "Python/generated_cases.c.h" + #line 3194 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3226,11 +3201,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2200 "Python/bytecodes.c" + #line 2254 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3234 "Python/generated_cases.c.h" + #line 3209 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3239,14 +3214,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2206 "Python/bytecodes.c" + #line 2260 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3246 "Python/generated_cases.c.h" + #line 3221 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2209 "Python/bytecodes.c" + #line 2263 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3250 "Python/generated_cases.c.h" + #line 3225 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3254,7 +3229,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2213 "Python/bytecodes.c" + #line 2267 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3277,11 +3252,11 @@ if (iter == NULL) { goto error; } - #line 3281 "Python/generated_cases.c.h" + #line 3256 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2236 "Python/bytecodes.c" + #line 2290 "Python/bytecodes.c" } - #line 3285 "Python/generated_cases.c.h" + #line 3260 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3292,7 +3267,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2255 "Python/bytecodes.c" + #line 2309 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3323,7 +3298,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3327 "Python/generated_cases.c.h" + #line 3302 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3331,7 +3306,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2288 "Python/bytecodes.c" + #line 2342 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3357,14 +3332,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3361 "Python/generated_cases.c.h" + #line 3336 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2316 "Python/bytecodes.c" + #line 2370 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3384,7 +3359,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3388 "Python/generated_cases.c.h" + #line 3363 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3394,7 +3369,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2338 "Python/bytecodes.c" + #line 2392 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3414,7 +3389,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3418 "Python/generated_cases.c.h" + #line 3393 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3424,7 +3399,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2360 "Python/bytecodes.c" + #line 2414 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3442,7 +3417,7 @@ if (next == NULL) { goto error; } - #line 3446 "Python/generated_cases.c.h" + #line 3421 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3451,7 +3426,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2380 "Python/bytecodes.c" + #line 2434 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3467,14 +3442,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3471 "Python/generated_cases.c.h" + #line 3446 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2398 "Python/bytecodes.c" + #line 2452 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3497,16 +3472,16 @@ Py_DECREF(enter); goto error; } - #line 3501 "Python/generated_cases.c.h" + #line 3476 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2421 "Python/bytecodes.c" + #line 2475 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3510 "Python/generated_cases.c.h" + #line 3485 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3518,7 +3493,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2431 "Python/bytecodes.c" + #line 2485 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3544,16 +3519,16 @@ Py_DECREF(enter); goto error; } - #line 3548 "Python/generated_cases.c.h" + #line 3523 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2457 "Python/bytecodes.c" + #line 2511 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3557 "Python/generated_cases.c.h" + #line 3532 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3565,7 +3540,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2466 "Python/bytecodes.c" + #line 2520 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3591,7 +3566,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3595 "Python/generated_cases.c.h" + #line 3570 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3600,7 +3575,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2494 "Python/bytecodes.c" + #line 2548 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3610,7 +3585,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3614 "Python/generated_cases.c.h" + #line 3589 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3624,7 +3599,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2506 "Python/bytecodes.c" + #line 2560 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3641,7 +3616,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3645 "Python/generated_cases.c.h" + #line 3620 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3655,7 +3630,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2525 "Python/bytecodes.c" + #line 2579 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3665,7 +3640,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3669 "Python/generated_cases.c.h" + #line 3644 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3679,7 +3654,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2537 "Python/bytecodes.c" + #line 2591 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3693,7 +3668,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3697 "Python/generated_cases.c.h" + #line 3672 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3702,16 +3677,16 @@ } TARGET(KW_NAMES) { - #line 2553 "Python/bytecodes.c" + #line 2607 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3710 "Python/generated_cases.c.h" + #line 3685 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2559 "Python/bytecodes.c" + #line 2613 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3724,7 +3699,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3728 "Python/generated_cases.c.h" + #line 3703 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3734,7 +3709,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2604 "Python/bytecodes.c" + #line 2658 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3816,7 +3791,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3820 "Python/generated_cases.c.h" + #line 3795 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3828,7 +3803,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2692 "Python/bytecodes.c" + #line 2746 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3838,7 +3813,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3842 "Python/generated_cases.c.h" + #line 3817 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3847,7 +3822,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2704 "Python/bytecodes.c" + #line 2758 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3873,7 +3848,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3877 "Python/generated_cases.c.h" + #line 3852 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3881,7 +3856,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2732 "Python/bytecodes.c" + #line 2786 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3917,7 +3892,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3921 "Python/generated_cases.c.h" + #line 3896 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3925,7 +3900,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2770 "Python/bytecodes.c" + #line 2824 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3935,7 +3910,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3939 "Python/generated_cases.c.h" + #line 3914 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3948,7 +3923,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2782 "Python/bytecodes.c" + #line 2836 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3959,7 +3934,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3963 "Python/generated_cases.c.h" + #line 3938 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3973,7 +3948,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2796 "Python/bytecodes.c" + #line 2850 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3984,7 +3959,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3988 "Python/generated_cases.c.h" + #line 3963 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3998,7 +3973,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2810 "Python/bytecodes.c" + #line 2864 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4020,7 +3995,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4024 "Python/generated_cases.c.h" + #line 3999 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4034,7 +4009,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2835 "Python/bytecodes.c" + #line 2889 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4062,7 +4037,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4066 "Python/generated_cases.c.h" + #line 4041 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4076,7 +4051,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2866 "Python/bytecodes.c" + #line 2920 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4108,7 +4083,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4112 "Python/generated_cases.c.h" + #line 4087 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4122,7 +4097,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2901 "Python/bytecodes.c" + #line 2955 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4154,7 +4129,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4158 "Python/generated_cases.c.h" + #line 4133 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4168,7 +4143,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2936 "Python/bytecodes.c" + #line 2990 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4193,7 +4168,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4197 "Python/generated_cases.c.h" + #line 4172 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4206,7 +4181,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2963 "Python/bytecodes.c" + #line 3017 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4233,7 +4208,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4237 "Python/generated_cases.c.h" + #line 4212 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4245,7 +4220,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2993 "Python/bytecodes.c" + #line 3047 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -4263,14 +4238,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4267 "Python/generated_cases.c.h" + #line 4242 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3013 "Python/bytecodes.c" + #line 3067 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4301,7 +4276,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4305 "Python/generated_cases.c.h" + #line 4280 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4314,7 +4289,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3047 "Python/bytecodes.c" + #line 3101 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4343,7 +4318,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4347 "Python/generated_cases.c.h" + #line 4322 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4356,7 +4331,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3079 "Python/bytecodes.c" + #line 3133 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4385,7 +4360,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4389 "Python/generated_cases.c.h" + #line 4364 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4398,7 +4373,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3111 "Python/bytecodes.c" + #line 3165 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4426,7 +4401,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4430 "Python/generated_cases.c.h" + #line 4405 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4436,9 +4411,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3142 "Python/bytecodes.c" + #line 3196 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4442 "Python/generated_cases.c.h" + #line 4417 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4447,7 +4422,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3146 "Python/bytecodes.c" + #line 3200 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4509,14 +4484,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4513 "Python/generated_cases.c.h" + #line 4488 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3208 "Python/bytecodes.c" + #line 3262 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4520 "Python/generated_cases.c.h" + #line 4495 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4531,7 +4506,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3218 "Python/bytecodes.c" + #line 3272 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4560,14 +4535,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4564 "Python/generated_cases.c.h" + #line 4539 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3249 "Python/bytecodes.c" + #line 3303 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4588,7 +4563,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4592 "Python/generated_cases.c.h" + #line 4567 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4596,15 +4571,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3272 "Python/bytecodes.c" + #line 3326 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4602 "Python/generated_cases.c.h" + #line 4577 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3274 "Python/bytecodes.c" + #line 3328 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4608 "Python/generated_cases.c.h" + #line 4583 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4615,7 +4590,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3278 "Python/bytecodes.c" + #line 3332 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4650,7 +4625,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4654 "Python/generated_cases.c.h" + #line 4629 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4659,10 +4634,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3315 "Python/bytecodes.c" + #line 3369 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4666 "Python/generated_cases.c.h" + #line 4641 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4674,7 +4649,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3320 "Python/bytecodes.c" + #line 3374 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4689,12 +4664,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4693 "Python/generated_cases.c.h" + #line 4668 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3335 "Python/bytecodes.c" + #line 3389 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4698 "Python/generated_cases.c.h" + #line 4673 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4704,16 +4679,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3340 "Python/bytecodes.c" + #line 3394 "Python/bytecodes.c" assert(oparg >= 2); - #line 4710 "Python/generated_cases.c.h" + #line 4685 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3344 "Python/bytecodes.c" + #line 3398 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4725,26 +4700,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4729 "Python/generated_cases.c.h" + #line 4704 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3358 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4735 "Python/generated_cases.c.h" + #line 4710 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3362 "Python/bytecodes.c" + #line 3416 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4742 "Python/generated_cases.c.h" + #line 4717 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3367 "Python/bytecodes.c" + #line 3421 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4753,12 +4728,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4757 "Python/generated_cases.c.h" + #line 4732 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3378 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4767,12 +4742,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4771 "Python/generated_cases.c.h" + #line 4746 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3389 "Python/bytecodes.c" + #line 3443 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4784,12 +4759,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4788 "Python/generated_cases.c.h" + #line 4763 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3403 "Python/bytecodes.c" + #line 3457 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4801,30 +4776,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4805 "Python/generated_cases.c.h" + #line 4780 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3417 "Python/bytecodes.c" + #line 3471 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4816 "Python/generated_cases.c.h" + #line 4791 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3425 "Python/bytecodes.c" + #line 3479 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4823 "Python/generated_cases.c.h" + #line 4798 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3430 "Python/bytecodes.c" + #line 3484 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4830 "Python/generated_cases.c.h" + #line 4805 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 53fbaa3e317e56..f9b1c928cd4845 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -163,10 +163,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case LOAD_LOCALS: return 0; - case LOAD_NAME: - return 0+1; case LOAD_FROM_DICT_OR_GLOBALS: return 1; + case LOAD_NAME: + return 0; case LOAD_GLOBAL: return 0; case LOAD_GLOBAL_MODULE: @@ -559,10 +559,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case LOAD_LOCALS: return 1; - case LOAD_NAME: - return 1+1; case LOAD_FROM_DICT_OR_GLOBALS: return 1; + case LOAD_NAME: + return 1; case LOAD_GLOBAL: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_GLOBAL_MODULE: @@ -881,9 +881,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [DELETE_ATTR] = { true, INSTR_FMT_IB }, [STORE_GLOBAL] = { true, INSTR_FMT_IB }, [DELETE_GLOBAL] = { true, INSTR_FMT_IB }, - [LOAD_LOCALS] = { true, INSTR_FMT_IB }, - [LOAD_NAME] = { true, INSTR_FMT_IB }, + [LOAD_LOCALS] = { true, INSTR_FMT_IX }, [LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB }, + [LOAD_NAME] = { true, INSTR_FMT_IB }, [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 }, [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 }, [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 }, From 888bcf49c08cd2a9e5a9b1dc4d7791c1525b3d69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:00:13 -0700 Subject: [PATCH 0737/1206] [3.12] Fix an ironic typo in a code comment. (gh-109186) (#109188) Fix an ironic typo in a code comment. (gh-109186) (cherry picked from commit 75cd86599bad05cb372aed9fccc3ff884cd38b70) Co-authored-by: Raymond Hettinger --- Lib/random.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/random.py b/Lib/random.py index 586c3f7f9da938..84bbfc5df1bf23 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -827,7 +827,7 @@ def binomialvariate(self, n=1, p=0.5): return k # Acceptance-rejection test. - # Note, the original paper errorneously omits the call to log(v) + # Note, the original paper erroneously omits the call to log(v) # when comparing to the log of the rescaled binomial distribution. if not setup_complete: alpha = (2.83 + 5.1 / b) * spq From aef019b04a249cf6c395e663f9e27a4d63cf2ae2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:00:33 -0700 Subject: [PATCH 0738/1206] [3.12] Improve the sieve() recipe in the itertools docs (gh-109199) (#109203) Improve the sieve() recipe in the itertools docs (gh-109199) Lazier sieve (cherry picked from commit d3ed9921cdd8ac291fbfe3adf42f7730d3a14dbc) Co-authored-by: Raymond Hettinger --- Doc/library/itertools.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 72c68519b456e2..5c4d1728234b33 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1030,13 +1030,16 @@ The following recipes have a more mathematical flavor: def sieve(n): "Primes less than n." # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 + if n > 2: + yield 2 + start = 3 data = bytearray((0, 1)) * (n // 2) - data[:3] = 0, 0, 0 limit = math.isqrt(n) + 1 - for p in compress(range(limit), data): + for p in iter_index(data, 1, start, limit): + yield from iter_index(data, 1, start, p*p) data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) - data[2] = 1 - return iter_index(data, 1) if n > 2 else iter([]) + start = p*p + yield from iter_index(data, 1, start) def factor(n): "Prime factors of n." From bcd59070d0ba2c0a6df08688e48578314cda92c1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:00:54 -0700 Subject: [PATCH 0739/1206] [3.12] Fix "FSTRING_MIDDLE" typo in py312 "What's New" (GH-109222) (#109223) Fix "FSTRING_MIDDLE" typo in py312 "What's New" (GH-109222) (cherry picked from commit 2dd6a86c4ee604b331ed739c2508b0d0114993c6) Co-authored-by: Delgan <4193924+Delgan@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 57f33e639de69e..b05107df661897 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1599,7 +1599,7 @@ Changes in the Python API functions is now changed due to the changes introduced in :pep:`701`. This means that ``STRING`` tokens are not emitted any more for f-strings and the tokens described in :pep:`701` are now produced instead: ``FSTRING_START``, - ``FSRING_MIDDLE`` and ``FSTRING_END`` are now emitted for f-string "string" + ``FSTRING_MIDDLE`` and ``FSTRING_END`` are now emitted for f-string "string" parts in addition to the appropriate tokens for the tokenization in the expression components. For example for the f-string ``f"start {1+1} end"`` the old version of the tokenizer emitted:: From b3613815d4550a611e67a9c97f616c97124b6495 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:03:18 -0700 Subject: [PATCH 0740/1206] [3.12] gh-109237: Fix test_site for non-ASCII working directory (GH-109238) (#109239) gh-109237: Fix test_site for non-ASCII working directory (GH-109238) Fix test_site.test_underpth_basic() when the working directory contains at least one non-ASCII character: encode the "._pth" file to UTF-8 and enable the UTF-8 Mode to use UTF-8 for the child process stdout. (cherry picked from commit cbb3a6f8ada3d133c3ab9f9465b65067fce5bb42) Co-authored-by: Victor Stinner --- Lib/test/test_site.py | 4 ++-- .../next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 20a96169e8be4e..e8ec3b35881fec 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -576,7 +576,7 @@ def _create_underpth_exe(self, lines, exe_pth=True): _pth_file = os.path.splitext(exe_file)[0] + '._pth' else: _pth_file = os.path.splitext(dll_file)[0] + '._pth' - with open(_pth_file, 'w') as f: + with open(_pth_file, 'w', encoding='utf8') as f: for line in lines: print(line, file=f) return exe_file @@ -613,7 +613,7 @@ def test_underpth_basic(self): os.path.dirname(exe_file), pth_lines) - output = subprocess.check_output([exe_file, '-c', + output = subprocess.check_output([exe_file, '-X', 'utf8', '-c', 'import sys; print("\\n".join(sys.path) if sys.flags.no_site else "")' ], encoding='utf-8', errors='surrogateescape') actual_sys_path = output.rstrip().split('\n') diff --git a/Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst b/Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst new file mode 100644 index 00000000000000..1d762bbe1d2592 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst @@ -0,0 +1,4 @@ +Fix ``test_site.test_underpth_basic()`` when the working directory contains +at least one non-ASCII character: encode the ``._pth`` file to UTF-8 and +enable the UTF-8 Mode to use UTF-8 for the child process stdout. Patch by +Victor Stinner. From df64210ad0d65e82449bbff2c5125764d49e5073 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:03:47 -0700 Subject: [PATCH 0741/1206] [3.12] gh-109230: test_pyexpat no longer depends on the current directory (GH-109233) (#109241) gh-109230: test_pyexpat no longer depends on the current directory (GH-109233) Fix test_pyexpat.test_exception(): it can now be run from a directory different than Python source code directory. Before, the test failed in this case. Skip the test if Modules/pyexpat.c source is not available. Skip also the test on Python implementations other than CPython. (cherry picked from commit e55aab95786e0e9fb36a9a1122d2d0fb3d2403cd) Co-authored-by: Victor Stinner --- Lib/test/test_pyexpat.py | 72 ++++++++++++------- ...-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst | 5 ++ 2 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py index 863c1194672c1c..95698c0b23cbcf 100644 --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -1,13 +1,15 @@ # XXX TypeErrors on calling handlers, or on bad return values from a # handler, are obscure and unhelpful. -from io import BytesIO import os import platform import sys import sysconfig import unittest import traceback +from io import BytesIO +from test import support +from test.support import os_helper from xml.parsers import expat from xml.parsers.expat import errors @@ -441,37 +443,59 @@ def test7(self): # Test handling of exception from callback: class HandlerExceptionTest(unittest.TestCase): def StartElementHandler(self, name, attrs): - raise RuntimeError(name) + raise RuntimeError(f'StartElementHandler: <{name}>') def check_traceback_entry(self, entry, filename, funcname): - self.assertEqual(os.path.basename(entry[0]), filename) - self.assertEqual(entry[2], funcname) + self.assertEqual(os.path.basename(entry.filename), filename) + self.assertEqual(entry.name, funcname) + @support.cpython_only def test_exception(self): + # gh-66652: test _PyTraceback_Add() used by pyexpat.c to inject frames + + # Change the current directory to the Python source code directory + # if it is available. + src_dir = sysconfig.get_config_var('abs_builddir') + if src_dir: + have_source = os.path.isdir(src_dir) + else: + have_source = False + if have_source: + with os_helper.change_cwd(src_dir): + self._test_exception(have_source) + else: + self._test_exception(have_source) + + def _test_exception(self, have_source): + # Use path relative to the current directory which should be the Python + # source code directory (if it is available). + PYEXPAT_C = os.path.join('Modules', 'pyexpat.c') + parser = expat.ParserCreate() parser.StartElementHandler = self.StartElementHandler try: parser.Parse(b"", True) - self.fail() - except RuntimeError as e: - self.assertEqual(e.args[0], 'a', - "Expected RuntimeError for element 'a', but" + \ - " found %r" % e.args[0]) - # Check that the traceback contains the relevant line in pyexpat.c - entries = traceback.extract_tb(e.__traceback__) - self.assertEqual(len(entries), 3) - self.check_traceback_entry(entries[0], - "test_pyexpat.py", "test_exception") - self.check_traceback_entry(entries[1], - "pyexpat.c", "StartElement") - self.check_traceback_entry(entries[2], - "test_pyexpat.py", "StartElementHandler") - if (sysconfig.is_python_build() - and not (sys.platform == 'win32' and platform.machine() == 'ARM') - and not is_emscripten - and not is_wasi - ): - self.assertIn('call_with_frame("StartElement"', entries[1][3]) + + self.fail("the parser did not raise RuntimeError") + except RuntimeError as exc: + self.assertEqual(exc.args[0], 'StartElementHandler: ', exc) + entries = traceback.extract_tb(exc.__traceback__) + + self.assertEqual(len(entries), 3, entries) + self.check_traceback_entry(entries[0], + "test_pyexpat.py", "_test_exception") + self.check_traceback_entry(entries[1], + os.path.basename(PYEXPAT_C), + "StartElement") + self.check_traceback_entry(entries[2], + "test_pyexpat.py", "StartElementHandler") + + # Check that the traceback contains the relevant line in + # Modules/pyexpat.c. Skip the test if Modules/pyexpat.c is not + # available. + if have_source and os.path.exists(PYEXPAT_C): + self.assertIn('call_with_frame("StartElement"', + entries[1].line) # Test Current* members: diff --git a/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst b/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst new file mode 100644 index 00000000000000..18e1e85242005a --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst @@ -0,0 +1,5 @@ +Fix ``test_pyexpat.test_exception()``: it can now be run from a directory +different than Python source code directory. Before, the test failed in this +case. Skip the test if Modules/pyexpat.c source is not available. Skip also +the test on Python implementations other than CPython. Patch by Victor +Stinner. From 5e917a0b09dbd86cff88b04501898e72ade574d5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:13:45 -0700 Subject: [PATCH 0742/1206] [3.12] Test DocTestFinder directly instead of calling support.run_doctest() (GH-108917) (#109259) Test DocTestFinder directly instead of calling support.run_doctest() (GH-108917) (cherry picked from commit 0abc935086931d4915ea3c45cffffecb31e7a45c) Co-authored-by: Serhiy Storchaka --- Lib/test/test_doctest.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 542fcdb5cf6f66..bca4915e0fa673 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -740,15 +740,13 @@ class TestDocTestFinder(unittest.TestCase): def test_issue35753(self): # This import of `call` should trigger issue35753 when - # `support.run_doctest` is called due to unwrap failing, + # DocTestFinder.find() is called due to inspect.unwrap() failing, # however with a patched doctest this should succeed. from unittest.mock import call dummy_module = types.ModuleType("dummy") dummy_module.__dict__['inject_call'] = call - try: - support.run_doctest(dummy_module, verbosity=True) - except ValueError as e: - raise support.TestFailed("Doctest unwrap failed") from e + finder = doctest.DocTestFinder() + self.assertEqual(finder.find(dummy_module), []) def test_empty_namespace_package(self): pkg_name = 'doctest_empty_pkg' From 3efe7bc65f45ea568e71b16458e2d956be30b6c7 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 12 Sep 2023 15:14:49 +0100 Subject: [PATCH 0743/1206] [3.12] GH-108976. Keep monitoring data structures valid during de-optimization during callback. (GH-109131) (#109268) GH-108976. Keep monitoring data structures valid during de-optimization during callback. (GH-109131) --- Lib/test/test_monitoring.py | 8 ++ Lib/test/test_pdb.py | 18 +++ ...-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst | 2 + Python/instrumentation.c | 104 +++++++++--------- 4 files changed, 77 insertions(+), 55 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 8665c355e7fdd5..2e4ec244ce6f17 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1718,3 +1718,11 @@ def make_foo_optimized_then_set_event(): make_foo_optimized_then_set_event() finally: sys.monitoring.set_events(TEST_TOOL, 0) + + def test_gh108976(self): + sys.monitoring.use_tool_id(0, "test") + sys.monitoring.set_events(0, 0) + sys.monitoring.register_callback(0, E.LINE, lambda *args: sys.monitoring.set_events(0, 0)) + sys.monitoring.register_callback(0, E.INSTRUCTION, lambda *args: 0) + sys.monitoring.set_events(0, E.LINE | E.INSTRUCTION) + sys.monitoring.set_events(0, 0) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 83c7cdff87fd34..5793dbfbfdf4d0 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1799,6 +1799,24 @@ def test_pdb_issue_gh_101517(): (Pdb) continue """ +def test_pdb_issue_gh_108976(): + """See GH-108976 + Make sure setting f_trace_opcodes = True won't crash pdb + >>> def test_function(): + ... import sys + ... sys._getframe().f_trace_opcodes = True + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... a = 1 + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'continue' + ... ]): + ... test_function() + bdb.Bdb.dispatch: unknown debugging event: 'opcode' + > (5)test_function() + -> a = 1 + (Pdb) continue + """ + def test_pdb_ambiguous_statements(): """See GH-104301 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst new file mode 100644 index 00000000000000..4b89375f0f57ef --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst @@ -0,0 +1,2 @@ +Fix crash that occurs after de-instrumenting a code object in a monitoring +callback. diff --git a/Python/instrumentation.c b/Python/instrumentation.c index f612d78c913f80..0a54eb67c31967 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1,6 +1,7 @@ + #include "Python.h" #include "pycore_call.h" #include "pycore_frame.h" @@ -355,7 +356,7 @@ dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringDat } static void -dump_monitors(const char *prefix, _Py_Monitors monitors, FILE*out) +dump_global_monitors(const char *prefix, _Py_GlobalMonitors monitors, FILE*out) { fprintf(out, "%s monitors:\n", prefix); for (int event = 0; event < _PY_MONITORING_UNGROUPED_EVENTS; event++) { @@ -363,37 +364,13 @@ dump_monitors(const char *prefix, _Py_Monitors monitors, FILE*out) } } -/* Like _Py_GetBaseOpcode but without asserts. - * Does its best to give the right answer, but won't abort - * if something is wrong */ -static int -get_base_opcode_best_attempt(PyCodeObject *code, int offset) +static void +dump_local_monitors(const char *prefix, _Py_LocalMonitors monitors, FILE*out) { - int opcode = _Py_OPCODE(_PyCode_CODE(code)[offset]); - if (INSTRUMENTED_OPCODES[opcode] != opcode) { - /* Not instrumented */ - return _PyOpcode_Deopt[opcode] == 0 ? opcode : _PyOpcode_Deopt[opcode]; - } - if (opcode == INSTRUMENTED_INSTRUCTION) { - if (code->_co_monitoring->per_instruction_opcodes[offset] == 0) { - return opcode; - } - opcode = code->_co_monitoring->per_instruction_opcodes[offset]; - } - if (opcode == INSTRUMENTED_LINE) { - if (code->_co_monitoring->lines[offset].original_opcode == 0) { - return opcode; - } - opcode = code->_co_monitoring->lines[offset].original_opcode; - } - int deinstrumented = DE_INSTRUMENT[opcode]; - if (deinstrumented) { - return deinstrumented; - } - if (_PyOpcode_Deopt[opcode] == 0) { - return opcode; + fprintf(out, "%s monitors:\n", prefix); + for (int event = 0; event < _PY_MONITORING_LOCAL_EVENTS; event++) { + fprintf(out, " Event %d: Tools %x\n", event, monitors.tools[event]); } - return _PyOpcode_Deopt[opcode]; } /* No error checking -- Don't use this for anything but experimental debugging */ @@ -408,9 +385,9 @@ dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) fprintf(out, "NULL\n"); return; } - dump_monitors("Global", PyInterpreterState_Get()->monitors, out); - dump_monitors("Code", data->local_monitors, out); - dump_monitors("Active", data->active_monitors, out); + dump_global_monitors("Global", _PyInterpreterState_GET()->monitors, out); + dump_local_monitors("Code", data->local_monitors, out); + dump_local_monitors("Active", data->active_monitors, out); int code_len = (int)Py_SIZE(code); bool starred = false; for (int i = 0; i < code_len; i += instruction_length(code, i)) { @@ -467,18 +444,23 @@ sanity_check_instrumentation(PyCodeObject *code) if (data == NULL) { return; } - _Py_GlobalMonitors active_monitors = _PyInterpreterState_GET()->monitors; + _Py_GlobalMonitors global_monitors = _PyInterpreterState_GET()->monitors; + _Py_LocalMonitors active_monitors; if (code->_co_monitoring) { - _Py_Monitors local_monitors = code->_co_monitoring->local_monitors; - active_monitors = local_union(active_monitors, local_monitors); + _Py_LocalMonitors local_monitors = code->_co_monitoring->local_monitors; + active_monitors = local_union(global_monitors, local_monitors); + } + else { + _Py_LocalMonitors empty = (_Py_LocalMonitors) { 0 }; + active_monitors = local_union(global_monitors, empty); } assert(monitors_equals( code->_co_monitoring->active_monitors, - active_monitors) - ); + active_monitors)); int code_len = (int)Py_SIZE(code); for (int i = 0; i < code_len;) { - int opcode = _PyCode_CODE(code)[i].op.code; + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + int opcode = instr->op.code; int base_opcode = _Py_GetBaseOpcode(code, i); CHECK(valid_opcode(opcode)); CHECK(valid_opcode(base_opcode)); @@ -498,23 +480,30 @@ sanity_check_instrumentation(PyCodeObject *code) opcode = data->lines[i].original_opcode; CHECK(opcode != END_FOR); CHECK(opcode != RESUME); + CHECK(opcode != RESUME_CHECK); CHECK(opcode != INSTRUMENTED_RESUME); if (!is_instrumented(opcode)) { CHECK(_PyOpcode_Deopt[opcode] == opcode); } CHECK(opcode != INSTRUMENTED_LINE); } - else if (data->lines && !is_instrumented(opcode)) { - CHECK(data->lines[i].original_opcode == 0 || - data->lines[i].original_opcode == base_opcode || - DE_INSTRUMENT[data->lines[i].original_opcode] == base_opcode); + else if (data->lines) { + /* If original_opcode is INSTRUMENTED_INSTRUCTION + * *and* we are executing a INSTRUMENTED_LINE instruction + * that has de-instrumented itself, then we will execute + * an invalid INSTRUMENTED_INSTRUCTION */ + CHECK(data->lines[i].original_opcode != INSTRUMENTED_INSTRUCTION); + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + CHECK(data->per_instruction_opcodes[i] != 0); + opcode = data->per_instruction_opcodes[i]; } if (is_instrumented(opcode)) { CHECK(DE_INSTRUMENT[opcode] == base_opcode); int event = EVENT_FOR_OPCODE[DE_INSTRUMENT[opcode]]; if (event < 0) { /* RESUME fixup */ - event = _PyCode_CODE(code)[i].op.arg; + event = instr->op.arg ? 1: 0; } CHECK(active_monitors.tools[event] != 0); } @@ -599,30 +588,30 @@ static void de_instrument_line(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; - uint8_t *opcode_ptr = &instr->op.code; - int opcode =*opcode_ptr; + int opcode = instr->op.code; if (opcode != INSTRUMENTED_LINE) { return; } _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; int original_opcode = lines->original_opcode; + if (original_opcode == INSTRUMENTED_INSTRUCTION) { + lines->original_opcode = code->_co_monitoring->per_instruction_opcodes[i]; + } CHECK(original_opcode != 0); CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); - *opcode_ptr = instr->op.code = original_opcode; + instr->op.code = original_opcode; if (_PyOpcode_Caches[original_opcode]) { instr[1].cache = adaptive_counter_warmup(); } - assert(*opcode_ptr != INSTRUMENTED_LINE); assert(instr->op.code != INSTRUMENTED_LINE); } - static void de_instrument_per_instruction(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; - int opcode =*opcode_ptr; + int opcode = *opcode_ptr; if (opcode == INSTRUMENTED_LINE) { opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; opcode = *opcode_ptr; @@ -633,10 +622,11 @@ de_instrument_per_instruction(PyCodeObject *code, int i) int original_opcode = code->_co_monitoring->per_instruction_opcodes[i]; CHECK(original_opcode != 0); CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); - instr->op.code = original_opcode; + *opcode_ptr = original_opcode; if (_PyOpcode_Caches[original_opcode]) { instr[1].cache = adaptive_counter_warmup(); } + assert(*opcode_ptr != INSTRUMENTED_INSTRUCTION); assert(instr->op.code != INSTRUMENTED_INSTRUCTION); /* Keep things clean for sanity check */ code->_co_monitoring->per_instruction_opcodes[i] = 0; @@ -676,7 +666,7 @@ static void instrument_line(PyCodeObject *code, int i) { uint8_t *opcode_ptr = &_PyCode_CODE(code)[i].op.code; - int opcode =*opcode_ptr; + int opcode = *opcode_ptr; if (opcode == INSTRUMENTED_LINE) { return; } @@ -691,13 +681,14 @@ instrument_per_instruction(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; - int opcode =*opcode_ptr; + int opcode = *opcode_ptr; if (opcode == INSTRUMENTED_LINE) { _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; opcode_ptr = &lines->original_opcode; opcode = *opcode_ptr; } if (opcode == INSTRUMENTED_INSTRUCTION) { + assert(code->_co_monitoring->per_instruction_opcodes[i] > 0); return; } CHECK(opcode != 0); @@ -1127,7 +1118,6 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _PyCoMonitoringData *monitoring = code->_co_monitoring; _PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; - uint8_t original_opcode = line_data->original_opcode; if (tstate->tracing) { goto done; } @@ -1178,7 +1168,9 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, } } Py_DECREF(line_obj); + uint8_t original_opcode; done: + original_opcode = line_data->original_opcode; assert(original_opcode != 0); assert(original_opcode < INSTRUMENTED_LINE); assert(_PyOpcode_Deopt[original_opcode] == original_opcode); @@ -1633,7 +1625,9 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) i += instruction_length(code, i); } } - +#ifdef INSTRUMENT_DEBUG + sanity_check_instrumentation(code); +#endif uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE]; uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; From 5305cdc39b1ec85de36aae6ea02ea2ae5b75d8ab Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:15:40 -0700 Subject: [PATCH 0744/1206] [3.12] gh-109182: Fix and improve tests for gh-108654 (GH-109189) (#109271) gh-109182: Fix and improve tests for gh-108654 (GH-109189) (cherry picked from commit c0f488b88f2a54d76256818e2841d868fecfd396) Co-authored-by: Serhiy Storchaka --- Lib/test/test_listcomps.py | 46 +++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index c1089574d71b02..12f7bbd123b30c 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -125,7 +125,7 @@ def get_output(moddict, name): self.assertIs(type(e), raises) else: for k, v in (outputs or {}).items(): - self.assertEqual(get_output(newns, k), v) + self.assertEqual(get_output(newns, k), v, k) def test_lambdas_with_iteration_var_as_default(self): code = """ @@ -563,28 +563,38 @@ def test_iter_var_available_in_locals(self): def test_comp_in_try_except(self): template = """ - value = ["a"] + value = ["ab"] + result = snapshot = None try: - [{func}(value) for value in value] + result = [{func}(value) for value in value] except: - pass + snapshot = value + raise """ - for func in ["str", "int"]: - code = template.format(func=func) - raises = func != "str" - with self.subTest(raises=raises): - self._check_in_scopes(code, {"value": ["a"]}) + # No exception. + code = template.format(func='len') + self._check_in_scopes(code, {"value": ["ab"], "result": [2], "snapshot": None}) + # Handles exception. + code = template.format(func='int') + self._check_in_scopes(code, {"value": ["ab"], "result": None, "snapshot": ["ab"]}, + raises=ValueError) def test_comp_in_try_finally(self): - code = """ - def f(value): - try: - [{func}(value) for value in value] - finally: - return value - ret = f(["a"]) - """ - self._check_in_scopes(code, {"ret": ["a"]}) + template = """ + value = ["ab"] + result = snapshot = None + try: + result = [{func}(value) for value in value] + finally: + snapshot = value + """ + # No exception. + code = template.format(func='len') + self._check_in_scopes(code, {"value": ["ab"], "result": [2], "snapshot": ["ab"]}) + # Handles exception. + code = template.format(func='int') + self._check_in_scopes(code, {"value": ["ab"], "result": None, "snapshot": ["ab"]}, + raises=ValueError) def test_exception_in_post_comp_call(self): code = """ From a8393dc27ef808755076463f7f209b06ec1a1aae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:16:35 -0700 Subject: [PATCH 0745/1206] [3.12] gh-109190: What's New in 3.12: Add subheadings to removals for easy linking (GH-109159) (#109273) gh-109190: What's New in 3.12: Add subheadings to removals for easy linking (GH-109159) (cherry picked from commit 57b6205523d934d61b6308d63ef72c494c7d2b7e) Co-authored-by: Hugo van Kemenade Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 159 ++++++++++++++++++++++++++++-------------- 1 file changed, 107 insertions(+), 52 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b05107df661897..494a4b096c1103 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1274,13 +1274,19 @@ although there is currently no date scheduled for their removal. Removed ======= -* ``asynchat`` and ``asyncore``: These two modules have been removed +asynchat and asyncore +--------------------- + +* These two modules have been removed according to the schedule in :pep:`594`, having been deprecated in Python 3.6. Use :mod:`asyncio` instead. (Contributed by Nikita Sobolev in :gh:`96580`.) -* :mod:`configparser`: Several names deprecated in the :mod:`configparser` way back in 3.2 have +configparser +------------ + +* Several names deprecated in the :mod:`configparser` way back in 3.2 have been removed per :gh:`89336`: * :class:`configparser.ParsingError` no longer has a ``filename`` attribute @@ -1290,13 +1296,19 @@ Removed * :class:`configparser.ConfigParser` no longer has a ``readfp`` method. Use :meth:`~configparser.ConfigParser.read_file` instead. -* ``distutils``: Remove the ``distutils`` package. It was deprecated in Python 3.10 by +distutils +--------- + +* Remove the :py:mod:`!distutils` package. It was deprecated in Python 3.10 by :pep:`632` "Deprecate distutils module". For projects still using ``distutils`` and cannot be updated to something else, the ``setuptools`` project can be installed: it still provides ``distutils``. (Contributed by Victor Stinner in :gh:`92584`.) -* :mod:`ensurepip`: Remove the bundled setuptools wheel from :mod:`ensurepip`, +ensurepip +--------- + +* Remove the bundled setuptools wheel from :mod:`ensurepip`, and stop installing setuptools in environments created by :mod:`venv`. ``pip (>= 22.1)`` does not require setuptools to be installed in the @@ -1314,27 +1326,42 @@ Removed (Contributed by Pradyun Gedam in :gh:`95299`.) -* :mod:`enum`: Remove ``EnumMeta.__getattr__``, which is no longer needed for +enum +---- + +* Remove :mod:`enum`'s ``EnumMeta.__getattr__``, which is no longer needed for enum attribute access. (Contributed by Ethan Furman in :gh:`95083`.) -* :mod:`ftplib`: Remove the ``FTP_TLS.ssl_version`` class attribute: use the +ftplib +------ + +* Remove :mod:`ftplib`'s ``FTP_TLS.ssl_version`` class attribute: use the *context* parameter instead. (Contributed by Victor Stinner in :gh:`94172`.) -* :mod:`gzip`: Remove the ``filename`` attribute of :class:`gzip.GzipFile`, +gzip +---- + +* Remove the ``filename`` attribute of :mod:`gzip`'s :class:`gzip.GzipFile`, deprecated since Python 2.6, use the :attr:`~gzip.GzipFile.name` attribute instead. In write mode, the ``filename`` attribute added ``'.gz'`` file extension if it was not present. (Contributed by Victor Stinner in :gh:`94196`.) -* :mod:`hashlib`: Remove the pure Python implementation of +hashlib +------- + +* Remove the pure Python implementation of :mod:`hashlib`'s :func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. (Contributed by Victor Stinner in :gh:`94199`.) -* :mod:`importlib`: Many previously deprecated cleanups in :mod:`importlib` have now been +importlib +--------- + +* Many previously deprecated cleanups in :mod:`importlib` have now been completed: * References to, and support for :meth:`!module_repr()` has been removed. @@ -1350,10 +1377,13 @@ Removed * ``importlib.abc.Finder``, ``pkgutil.ImpImporter``, and ``pkgutil.ImpLoader`` have been removed. (Contributed by Barry Warsaw in :gh:`98040`.) - * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in - :gh:`98040`.) +imp +--- - * Replace removed :mod:`!imp` functions with :mod:`importlib` functions: +* The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in + :gh:`98040`.) + +* Replace removed :mod:`!imp` functions with :mod:`importlib` functions: ================================= ======================================= imp importlib @@ -1370,7 +1400,7 @@ Removed ``imp.source_from_cache()`` :func:`importlib.util.source_from_cache` ================================= ======================================= - * Replace ``imp.load_source()`` with:: +* Replace ``imp.load_source()`` with:: import importlib.util import importlib.machinery @@ -1385,28 +1415,34 @@ Removed loader.exec_module(module) return module - * Removed :mod:`!imp` functions and attributes with no replacements: +* Removed :mod:`!imp` functions and attributes with no replacements: + + * undocumented functions: - * undocumented functions: + * ``imp.init_builtin()`` + * ``imp.load_compiled()`` + * ``imp.load_dynamic()`` + * ``imp.load_package()`` - * ``imp.init_builtin()`` - * ``imp.load_compiled()`` - * ``imp.load_dynamic()`` - * ``imp.load_package()`` + * ``imp.lock_held()``, ``imp.acquire_lock()``, ``imp.release_lock()``: + the locking scheme has changed in Python 3.3 to per-module locks. + * ``imp.find_module()`` constants: ``SEARCH_ERROR``, ``PY_SOURCE``, + ``PY_COMPILED``, ``C_EXTENSION``, ``PY_RESOURCE``, ``PKG_DIRECTORY``, + ``C_BUILTIN``, ``PY_FROZEN``, ``PY_CODERESOURCE``, ``IMP_HOOK``. - * ``imp.lock_held()``, ``imp.acquire_lock()``, ``imp.release_lock()``: - the locking scheme has changed in Python 3.3 to per-module locks. - * ``imp.find_module()`` constants: ``SEARCH_ERROR``, ``PY_SOURCE``, - ``PY_COMPILED``, ``C_EXTENSION``, ``PY_RESOURCE``, ``PKG_DIRECTORY``, - ``C_BUILTIN``, ``PY_FROZEN``, ``PY_CODERESOURCE``, ``IMP_HOOK``. +io +-- -* :mod:`io`: Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python +* Remove :mod:`io`'s ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python 3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) function is a built-in function. Since Python 3.10, :func:`!_pyio.open` is also a static method. (Contributed by Victor Stinner in :gh:`94169`.) -* :mod:`locale`: Remove the :func:`!locale.format` function, deprecated in Python 3.7: +locale +------ + +* Remove :mod:`locale`'s :func:`!locale.format` function, deprecated in Python 3.7: use :func:`locale.format_string` instead. (Contributed by Victor Stinner in :gh:`94226`.) @@ -1418,7 +1454,10 @@ Removed .. _aiosmtpd: https://pypi.org/project/aiosmtpd/ -* :mod:`sqlite3`: The following undocumented :mod:`sqlite3` features, deprecated in Python +sqlite3 +------- + +* The following undocumented :mod:`sqlite3` features, deprecated in Python 3.10, are now removed: * ``sqlite3.enable_shared_cache()`` @@ -1434,30 +1473,34 @@ Removed (Contributed by Erlend E. Aasland in :gh:`92548`.) -* :mod:`ssl`: +ssl +--- - * Remove the :func:`!ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: - use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. - (Contributed by Victor Stinner in :gh:`94199`.) +* Remove :mod:`ssl`'s :func:`!ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: + use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. + (Contributed by Victor Stinner in :gh:`94199`.) + +* Remove the :func:`!ssl.match_hostname` function. + It was deprecated in Python 3.7. OpenSSL performs + hostname matching since Python 3.7, Python no longer uses the + :func:`!ssl.match_hostname` function. + (Contributed by Victor Stinner in :gh:`94199`.) - * Remove the :func:`!ssl.match_hostname` function. - It was deprecated in Python 3.7. OpenSSL performs - hostname matching since Python 3.7, Python no longer uses the - :func:`!ssl.match_hostname` function. - (Contributed by Victor Stinner in :gh:`94199`.) +* Remove the :func:`!ssl.wrap_socket` function, deprecated in Python 3.7: + instead, create a :class:`ssl.SSLContext` object and call its + :class:`ssl.SSLContext.wrap_socket` method. Any package that still uses + :func:`!ssl.wrap_socket` is broken and insecure. The function neither sends a + SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 + `_: Improper Certificate + Validation. + (Contributed by Victor Stinner in :gh:`94199`.) - * Remove the :func:`!ssl.wrap_socket` function, deprecated in Python 3.7: - instead, create a :class:`ssl.SSLContext` object and call its - :class:`ssl.SSLContext.wrap_socket` method. Any package that still uses - :func:`!ssl.wrap_socket` is broken and insecure. The function neither sends a - SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 - `_: Improper Certificate - Validation. - (Contributed by Victor Stinner in :gh:`94199`.) +unittest +-------- -* :mod:`unittest`: Removed many old deprecated :mod:`unittest` features: +* Removed many old deprecated :mod:`unittest` features: - - A number of :class:`~unittest.TestCase` method aliases: + * A number of :class:`~unittest.TestCase` method aliases: ============================ =============================== =============== Deprecated alias Method Name Deprecated in @@ -1482,33 +1525,45 @@ Removed You can use https://github.com/isidentical/teyit to automatically modernise your unit tests. - - Undocumented and broken :class:`~unittest.TestCase` method + * Undocumented and broken :class:`~unittest.TestCase` method ``assertDictContainsSubset`` (deprecated in Python 3.2). - - Undocumented :meth:`TestLoader.loadTestsFromModule + * Undocumented :meth:`TestLoader.loadTestsFromModule ` parameter *use_load_tests* (deprecated and ignored since Python 3.2). - - An alias of the :class:`~unittest.TextTestResult` class: + * An alias of the :class:`~unittest.TextTestResult` class: ``_TextTestResult`` (deprecated in Python 3.2). (Contributed by Serhiy Storchaka in :issue:`45162`.) -* :mod:`webbrowser`: Remove support for obsolete browsers from :mod:`webbrowser`. +webbrowser +---------- + +* Remove support for obsolete browsers from :mod:`webbrowser`. Removed browsers include: Grail, Mosaic, Netscape, Galeon, Skipstone, Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). -* :mod:`xml.etree.ElementTree`: Remove the ``ElementTree.Element.copy()`` method of the +xml.etree.ElementTree +--------------------- + +* Remove the ``ElementTree.Element.copy()`` method of the pure Python implementation, deprecated in Python 3.10, use the :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree.ElementTree` has no ``copy()`` method, only a ``__copy__()`` method. (Contributed by Victor Stinner in :gh:`94383`.) -* :mod:`zipimport`: Remove ``find_loader()`` and ``find_module()`` methods, +zipimport +--------- + +* Remove :mod:`zipimport`'s ``find_loader()`` and ``find_module()`` methods, deprecated in Python 3.10: use the ``find_spec()`` method instead. See :pep:`451` for the rationale. (Contributed by Victor Stinner in :gh:`94379`.) +Others +------ + * Removed the ``suspicious`` rule from the documentation Makefile, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint `_. From 33ee98b217d06aed6f999b1be31be21e01655db8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:17:05 -0700 Subject: [PATCH 0746/1206] [3.12] gh-90805: Make sure test_functools works with and without _functoolsmodule (GH-108644) (#109275) gh-90805: Make sure test_functools works with and without _functoolsmodule (GH-108644) (cherry picked from commit baa6dc8e388e71b2a00347143ecefb2ad3a8e53b) Co-authored-by: Nikita Sobolev --- Lib/test/test_functools.py | 58 ++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index c4eca0f5b79511..ce2bdeb62a4da3 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -26,10 +26,16 @@ py_functools = import_helper.import_fresh_module('functools', blocked=['_functools']) -c_functools = import_helper.import_fresh_module('functools') +c_functools = import_helper.import_fresh_module('functools', + fresh=['_functools']) decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal']) +_partial_types = [py_functools.partial] +if c_functools: + _partial_types.append(c_functools.partial) + + @contextlib.contextmanager def replaced_module(name, replacement): original_module = sys.modules[name] @@ -201,7 +207,7 @@ def test_repr(self): kwargs = {'a': object(), 'b': object()} kwargs_reprs = ['a={a!r}, b={b!r}'.format_map(kwargs), 'b={b!r}, a={a!r}'.format_map(kwargs)] - if self.partial in (c_functools.partial, py_functools.partial): + if self.partial in _partial_types: name = 'functools.partial' else: name = self.partial.__name__ @@ -223,7 +229,7 @@ def test_repr(self): for kwargs_repr in kwargs_reprs]) def test_recursive_repr(self): - if self.partial in (c_functools.partial, py_functools.partial): + if self.partial in _partial_types: name = 'functools.partial' else: name = self.partial.__name__ @@ -250,7 +256,7 @@ def test_recursive_repr(self): f.__setstate__((capture, (), {}, {})) def test_pickle(self): - with self.AllowPickle(): + with replaced_module('functools', self.module): f = self.partial(signature, ['asdf'], bar=[True]) f.attr = [] for proto in range(pickle.HIGHEST_PROTOCOL + 1): @@ -333,7 +339,7 @@ def test_setstate_subclasses(self): self.assertIs(type(r[0]), tuple) def test_recursive_pickle(self): - with self.AllowPickle(): + with replaced_module('functools', self.module): f = self.partial(capture) f.__setstate__((f, (), {}, {})) try: @@ -387,14 +393,9 @@ def __getitem__(self, key): @unittest.skipUnless(c_functools, 'requires the C _functools module') class TestPartialC(TestPartial, unittest.TestCase): if c_functools: + module = c_functools partial = c_functools.partial - class AllowPickle: - def __enter__(self): - return self - def __exit__(self, type, value, tb): - return False - def test_attributes_unwritable(self): # attributes should not be writable p = self.partial(capture, 1, 2, a=10, b=20) @@ -437,15 +438,9 @@ def __str__(self): class TestPartialPy(TestPartial, unittest.TestCase): + module = py_functools partial = py_functools.partial - class AllowPickle: - def __init__(self): - self._cm = replaced_module("functools", py_functools) - def __enter__(self): - return self._cm.__enter__() - def __exit__(self, type, value, tb): - return self._cm.__exit__(type, value, tb) if c_functools: class CPartialSubclass(c_functools.partial): @@ -1872,9 +1867,10 @@ def orig(): ... def py_cached_func(x, y): return 3 * x + y -@c_functools.lru_cache() -def c_cached_func(x, y): - return 3 * x + y +if c_functools: + @c_functools.lru_cache() + def c_cached_func(x, y): + return 3 * x + y class TestLRUPy(TestLRU, unittest.TestCase): @@ -1891,18 +1887,20 @@ def cached_staticmeth(x, y): return 3 * x + y +@unittest.skipUnless(c_functools, 'requires the C _functools module') class TestLRUC(TestLRU, unittest.TestCase): - module = c_functools - cached_func = c_cached_func, + if c_functools: + module = c_functools + cached_func = c_cached_func, - @module.lru_cache() - def cached_meth(self, x, y): - return 3 * x + y + @module.lru_cache() + def cached_meth(self, x, y): + return 3 * x + y - @staticmethod - @module.lru_cache() - def cached_staticmeth(x, y): - return 3 * x + y + @staticmethod + @module.lru_cache() + def cached_staticmeth(x, y): + return 3 * x + y class TestSingleDispatch(unittest.TestCase): From 8e96b98282d8da7702a963aa751d9ecc29826dda Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:19:05 -0700 Subject: [PATCH 0747/1206] [3.12] gh-107322: zipapp: Remove the suggestion to remove .dist-info directories (GH-107296) (#109281) gh-107322: zipapp: Remove the suggestion to remove .dist-info directories (GH-107296) Removed zipapp suggestion to rm .dist-info subdirectories. This totally breaks importlib.metadata (cherry picked from commit 1ee50e2a78f644d81d341a08562073ad169d8cc7) Co-authored-by: wim glenn --- Doc/library/zipapp.rst | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index 8cee85b32d2a83..7c01fc102fca07 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -281,12 +281,7 @@ The steps to create a standalone archive are as follows: file - if not, you can just list the dependencies manually on the pip command line). -3. Optionally, delete the ``.dist-info`` directories created by pip in the - ``myapp`` directory. These hold metadata for pip to manage the packages, and - as you won't be making any further use of pip they aren't required - - although it won't do any harm if you leave them. - -4. Package the application using: +3. Package the application using: .. code-block:: shell-session From 2004e12d8d6268795425a57b4f5b4fb7e895d1ea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:20:41 -0700 Subject: [PATCH 0748/1206] [3.12] gh-109195: fix source location for super load before LOAD_SUPER_ATTR (GH-109289) (#109291) gh-109195: fix source location for super load before LOAD_SUPER_ATTR (GH-109289) (cherry picked from commit ceeb4173aee7b835f553a8286feaa48b98c16124) Co-authored-by: Carl Meyer --- Lib/test/test_compile.py | 7 +++++++ .../2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst | 4 ++++ Python/compile.c | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 19b5aebdd38198..16a59c106bbb67 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1742,6 +1742,13 @@ def test_column_offset_deduplication(self): list(code.co_consts[1].co_positions()), ) + def test_load_super_attr(self): + source = "class C:\n def __init__(self):\n super().__init__()" + code = compile(source, "", "exec").co_consts[0].co_consts[1] + self.assertOpcodeSourcePositionIs( + code, "LOAD_GLOBAL", line=3, end_line=3, column=4, end_column=9 + ) + class TestExpressionStackSize(unittest.TestCase): # These tests check that the computed stack size for a code object diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst new file mode 100644 index 00000000000000..5427232c2df9a0 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst @@ -0,0 +1,4 @@ +Fix source location for the ``LOAD_*`` instruction preceding a +``LOAD_SUPER_ATTR`` to load the ``super`` global (or shadowing variable) so +that it encompasses only the name ``super`` and not the following +parentheses. diff --git a/Python/compile.c b/Python/compile.c index 9395f5229cf866..b6e5adf1c76418 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4776,7 +4776,7 @@ load_args_for_super(struct compiler *c, expr_ty e) { // load super() global PyObject *super_name = e->v.Call.func->v.Name.id; - RETURN_IF_ERROR(compiler_nameop(c, loc, super_name, Load)); + RETURN_IF_ERROR(compiler_nameop(c, LOC(e->v.Call.func), super_name, Load)); if (asdl_seq_LEN(e->v.Call.args) == 2) { VISIT(c, expr, asdl_seq_GET(e->v.Call.args, 0)); From a6ed8106e2197e1be220a4419daf71c36766c69e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:21:08 -0700 Subject: [PATCH 0749/1206] [3.12] gh-109292: add symtable impact of PEP 709 to What's New (GH-109293) (#109296) gh-109292: add symtable impact of PEP 709 to What's New (GH-109293) (cherry picked from commit 2b1e2f1cd154e6df553eda7936715ea0622b4ecf) Co-authored-by: Carl Meyer --- Doc/whatsnew/3.12.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 494a4b096c1103..3bd9081c793b78 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -258,6 +258,9 @@ Inlining does result in a few visible behavior changes: * There is no longer a separate frame for the comprehension in tracebacks, and tracing/profiling no longer shows the comprehension as a function call. +* The :mod:`symtable` module will no longer produce child symbol tables for each + comprehension; instead, the comprehension's locals will be included in the + parent function's symbol table. * Calling :func:`locals` inside a comprehension now includes variables from outside the comprehension, and no longer includes the synthetic ``.0`` variable for the comprehension "argument". From 8acfb42ea313cc2b7b898180820d2997c3971873 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:22:43 -0700 Subject: [PATCH 0750/1206] [3.12] gh-109295: Clean up multiprocessing in test_asyncio and test_compileall (GH-109298) (#109301) gh-109295: Clean up multiprocessing in test_asyncio and test_compileall (GH-109298) test_asyncio and test_compileall now clean up multiprocessing by calling multiprocessing _cleanup_tests(): explicitly clean up resources and stop background processes like the resource tracker. (cherry picked from commit 09ea4b8706165fd9474165090a0ba86509abd6c8) Co-authored-by: Victor Stinner --- Lib/test/test_asyncio/test_events.py | 3 +++ Lib/test/test_compileall.py | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 30cc8fd80bfe94..1647d2308c4e35 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -31,6 +31,7 @@ from asyncio import coroutines from asyncio import events from asyncio import selector_events +from multiprocessing.util import _cleanup_tests as multiprocessing_cleanup_tests from test.test_asyncio import utils as test_utils from test import support from test.support import socket_helper @@ -2765,6 +2766,8 @@ def test_get_event_loop_new_process(self): # multiprocessing.synchronize module cannot be imported. support.skip_if_broken_multiprocessing_synchronize() + self.addCleanup(multiprocessing_cleanup_tests) + async def main(): if multiprocessing.get_start_method() == 'fork': # Avoid 'fork' DeprecationWarning. diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index df7c5122b3b1f5..9cd92ad365c5a9 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -18,6 +18,7 @@ try: # compileall relies on ProcessPoolExecutor if ProcessPoolExecutor exists # and it can function. + from multiprocessing.util import _cleanup_tests as multiprocessing_cleanup_tests from concurrent.futures import ProcessPoolExecutor from concurrent.futures.process import _check_system_limits _check_system_limits() @@ -54,6 +55,8 @@ class CompileallTestsBase: def setUp(self): self.directory = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, self.directory) + self.source_path = os.path.join(self.directory, '_test.py') self.bc_path = importlib.util.cache_from_source(self.source_path) with open(self.source_path, 'w', encoding="utf-8") as file: @@ -66,9 +69,6 @@ def setUp(self): self.source_path3 = os.path.join(self.subdirectory, '_test3.py') shutil.copyfile(self.source_path, self.source_path3) - def tearDown(self): - shutil.rmtree(self.directory) - def add_bad_source_file(self): self.bad_source_path = os.path.join(self.directory, '_test_bad.py') with open(self.bad_source_path, 'w', encoding="utf-8") as file: @@ -307,9 +307,13 @@ def _test_ddir_only(self, *, ddir, parallel=True): script_helper.make_script(path, "__init__", "") mods.append(script_helper.make_script(path, "mod", "def fn(): 1/0\nfn()\n")) + + if parallel: + self.addCleanup(multiprocessing_cleanup_tests) compileall.compile_dir( self.directory, quiet=True, ddir=ddir, workers=2 if parallel else 1) + self.assertTrue(mods) for mod in mods: self.assertTrue(mod.startswith(self.directory), mod) From 7479a7aca2c8b5799ae0a84e2bbd5f07c0daf1b1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:23:03 -0700 Subject: [PATCH 0751/1206] [3.12] gh-109295: Fix test_os.test_access_denied() for TEMP=cwd (GH-109299) (#109304) gh-109295: Fix test_os.test_access_denied() for TEMP=cwd (GH-109299) Fix test_os.test_access_denied() when the TEMP environment variable is equal to the current working directory. Run the test using a different filename, since self.fname already exists in this case. (cherry picked from commit 7dedfd36dc16d9e1e15d7d0b0a636dd401a5a543) Co-authored-by: Victor Stinner --- Lib/test/test_os.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 9453742132667d..3cc5a6aaafcf36 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -737,7 +737,7 @@ def test_access_denied(self): # denied. See issue 28075. # os.environ['TEMP'] should be located on a volume that # supports file ACLs. - fname = os.path.join(os.environ['TEMP'], self.fname) + fname = os.path.join(os.environ['TEMP'], self.fname + "_access") self.addCleanup(os_helper.unlink, fname) create_file(fname, b'ABC') # Deny the right to [S]YNCHRONIZE on the file to From 778d094126f8975a9823ed7da1a630e29bb75bf0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:23:20 -0700 Subject: [PATCH 0752/1206] [3.12] Fix iter_index() to work with lists which do not support stop=None. (gh-109306) (#109310) Fix iter_index() to work with lists which do not support stop=None. (gh-109306) (cherry picked from commit f2a55fecd063244a5fd09a38f673f0781f8802d1) Co-authored-by: Raymond Hettinger --- Doc/library/itertools.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 5c4d1728234b33..7fc1ae913cdba5 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -877,6 +877,7 @@ which incur interpreter overhead. yield i else: # Fast path for sequences + stop = len(iterable) if stop is None else stop i = start - 1 try: while True: @@ -1347,6 +1348,16 @@ The following recipes have a more mathematical flavor: Traceback (most recent call last): ... ValueError + >>> # Verify that both paths can find identical NaN values + >>> x = float('NaN') + >>> y = float('NaN') + >>> list(iter_index([0, x, x, y, 0], x)) + [1, 2] + >>> list(iter_index(iter([0, x, x, y, 0]), x)) + [1, 2] + >>> # Test list input. Lists do not support None for the stop argument + >>> list(iter_index(list('AABCADEAF'), 'A')) + [0, 1, 4, 7] >>> list(sieve(30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] From 8208657f3d6398817f7dd6e5160ea037840e562f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:31:26 -0700 Subject: [PATCH 0753/1206] [3.12] gh-109118: Disallow nested scopes within PEP 695 scopes within classes (GH-109196) (#109297) gh-109118: Disallow nested scopes within PEP 695 scopes within classes (GH-109196) Fixes GH-109118. Fixes GH-109194. (cherry picked from commit b88d9e75f68f102aca45fa62e2b0e2e2ff46d810) Co-authored-by: Jelle Zijlstra Co-authored-by: Carl Meyer --- Lib/test/test_type_params.py | 93 +++++++++++++++++++ ...-09-09-12-49-46.gh-issue-109118.gx0X4h.rst | 2 + Python/symtable.c | 23 +++++ 3 files changed, 118 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index f93d088ea758a9..b1848aee4753a1 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -412,6 +412,99 @@ def test_comprehension_02(self): func, = T.__bound__ self.assertEqual(func(), 1) + def test_gen_exp_in_nested_class(self): + code = """ + from test.test_type_params import make_base + + class C[T]: + T = "class" + class Inner(make_base(T for _ in (1,)), make_base(T)): + pass + """ + C = run_code(code)["C"] + T, = C.__type_params__ + base1, base2 = C.Inner.__bases__ + self.assertEqual(list(base1.__arg__), [T]) + self.assertEqual(base2.__arg__, "class") + + def test_gen_exp_in_nested_generic_class(self): + code = """ + from test.test_type_params import make_base + + class C[T]: + T = "class" + class Inner[U](make_base(T for _ in (1,)), make_base(T)): + pass + """ + with self.assertRaisesRegex(SyntaxError, + "Cannot use comprehension in annotation scope within class scope"): + run_code(code) + + def test_listcomp_in_nested_class(self): + code = """ + from test.test_type_params import make_base + + class C[T]: + T = "class" + class Inner(make_base([T for _ in (1,)]), make_base(T)): + pass + """ + C = run_code(code)["C"] + T, = C.__type_params__ + base1, base2 = C.Inner.__bases__ + self.assertEqual(base1.__arg__, [T]) + self.assertEqual(base2.__arg__, "class") + + def test_listcomp_in_nested_generic_class(self): + code = """ + from test.test_type_params import make_base + + class C[T]: + T = "class" + class Inner[U](make_base([T for _ in (1,)]), make_base(T)): + pass + """ + with self.assertRaisesRegex(SyntaxError, + "Cannot use comprehension in annotation scope within class scope"): + run_code(code) + + def test_gen_exp_in_generic_method(self): + code = """ + class C[T]: + T = "class" + def meth[U](x: (T for _ in (1,)), y: T): + pass + """ + with self.assertRaisesRegex(SyntaxError, + "Cannot use comprehension in annotation scope within class scope"): + run_code(code) + + def test_nested_scope_in_generic_alias(self): + code = """ + class C[T]: + T = "class" + {} + """ + error_cases = [ + "type Alias1[T] = lambda: T", + "type Alias2 = lambda: T", + "type Alias3[T] = (T for _ in (1,))", + "type Alias4 = (T for _ in (1,))", + "type Alias5[T] = [T for _ in (1,)]", + "type Alias6 = [T for _ in (1,)]", + ] + for case in error_cases: + with self.subTest(case=case): + with self.assertRaisesRegex(SyntaxError, + r"Cannot use [a-z]+ in annotation scope within class scope"): + run_code(code.format(case)) + + +def make_base(arg): + class Base: + __arg__ = arg + return Base + def global_generic_func[T](): pass diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst new file mode 100644 index 00000000000000..87069c85870410 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst @@ -0,0 +1,2 @@ +Disallow nested scopes (lambdas, generator expressions, and comprehensions) +within PEP 695 annotation scopes that are nested within classes. diff --git a/Python/symtable.c b/Python/symtable.c index 115882da09b75a..691698e00b4619 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1969,6 +1969,17 @@ symtable_visit_expr(struct symtable *st, expr_ty e) VISIT(st, expr, e->v.UnaryOp.operand); break; case Lambda_kind: { + if (st->st_cur->ste_can_see_class_scope) { + // gh-109118 + PyErr_Format(PyExc_SyntaxError, + "Cannot use lambda in annotation scope within class scope"); + PyErr_RangedSyntaxLocationObject(st->st_filename, + e->lineno, + e->col_offset + 1, + e->end_lineno, + e->end_col_offset + 1); + VISIT_QUIT(st, 0); + } if (e->v.Lambda.args->defaults) VISIT_SEQ(st, expr, e->v.Lambda.args->defaults); if (e->v.Lambda.args->kw_defaults) @@ -2418,6 +2429,18 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e, identifier scope_name, asdl_comprehension_seq *generators, expr_ty elt, expr_ty value) { + if (st->st_cur->ste_can_see_class_scope) { + // gh-109118 + PyErr_Format(PyExc_SyntaxError, + "Cannot use comprehension in annotation scope within class scope"); + PyErr_RangedSyntaxLocationObject(st->st_filename, + e->lineno, + e->col_offset + 1, + e->end_lineno, + e->end_col_offset + 1); + VISIT_QUIT(st, 0); + } + int is_generator = (e->kind == GeneratorExp_kind); comprehension_ty outermost = ((comprehension_ty) asdl_seq_GET(generators, 0)); From 21f4e6d6cb53b2edbc22dbd5ab92702dcce5b795 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 12 Sep 2023 16:52:25 +0100 Subject: [PATCH 0754/1206] [3.12] gh-109114: Relax the check for invalid lambdas inside f-strings to avoid false positives (GH-109121). (#109155) (cherry picked from commit 5bda2f637e1cfbca45a83aa6e22db25498064b27) Signed-off-by: Pablo Galindo --- Grammar/python.gram | 2 +- Lib/test/test_fstring.py | 4 + ...-09-08-01-50-41.gh-issue-109114.adqgtb.rst | 3 + Parser/parser.c | 2557 ++++++++--------- 4 files changed, 1257 insertions(+), 1309 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index c1863aec67cc2b..f88dc2bdd92327 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -1170,7 +1170,7 @@ invalid_expression: _PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL : RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") } | a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") } - | a='lambda' [lambda_params] b=':' &(FSTRING_MIDDLE | fstring_replacement_field) { + | a='lambda' [lambda_params] b=':' &FSTRING_MIDDLE { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "f-string: lambda expressions are not allowed without parentheses") } invalid_named_expression(memo): diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 16f01973f99f3e..4f05a149a901b2 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1027,6 +1027,10 @@ def test_lambda(self): "f'{lambda x:}'", "f'{lambda :}'", ]) + # Ensure the detection of invalid lambdas doesn't trigger detection + # for valid lambdas in the second error pass + with self.assertRaisesRegex(SyntaxError, "invalid syntax"): + compile("lambda name_3=f'{name_4}': {name_3}\n1 $ 1", "", "exec") # but don't emit the paren warning in general cases with self.assertRaisesRegex(SyntaxError, "f-string: expecting a valid expression after '{'"): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst new file mode 100644 index 00000000000000..3d95dd5d29450c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst @@ -0,0 +1,3 @@ +Relax the detection of the error message for invalid lambdas inside +f-strings to not search for arbitrary replacement fields to avoid false +positives. Patch by Pablo Galindo diff --git a/Parser/parser.c b/Parser/parser.c index 860bbea4431c08..5d2adf7417b2ec 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -481,65 +481,65 @@ static char *soft_keywords[] = { #define _tmp_157_type 1400 #define _tmp_158_type 1401 #define _tmp_159_type 1402 -#define _tmp_160_type 1403 +#define _loop0_160_type 1403 #define _loop0_161_type 1404 #define _loop0_162_type 1405 -#define _loop0_163_type 1406 +#define _tmp_163_type 1406 #define _tmp_164_type 1407 #define _tmp_165_type 1408 #define _tmp_166_type 1409 #define _tmp_167_type 1410 -#define _tmp_168_type 1411 +#define _loop0_168_type 1411 #define _loop0_169_type 1412 #define _loop0_170_type 1413 -#define _loop0_171_type 1414 -#define _loop1_172_type 1415 -#define _tmp_173_type 1416 -#define _loop0_174_type 1417 -#define _tmp_175_type 1418 -#define _loop0_176_type 1419 -#define _loop1_177_type 1420 +#define _loop1_171_type 1414 +#define _tmp_172_type 1415 +#define _loop0_173_type 1416 +#define _tmp_174_type 1417 +#define _loop0_175_type 1418 +#define _loop1_176_type 1419 +#define _tmp_177_type 1420 #define _tmp_178_type 1421 #define _tmp_179_type 1422 -#define _tmp_180_type 1423 -#define _loop0_181_type 1424 +#define _loop0_180_type 1423 +#define _tmp_181_type 1424 #define _tmp_182_type 1425 -#define _tmp_183_type 1426 -#define _loop1_184_type 1427 -#define _tmp_185_type 1428 +#define _loop1_183_type 1426 +#define _tmp_184_type 1427 +#define _loop0_185_type 1428 #define _loop0_186_type 1429 #define _loop0_187_type 1430 -#define _loop0_188_type 1431 -#define _loop0_190_type 1432 -#define _gather_189_type 1433 -#define _tmp_191_type 1434 -#define _loop0_192_type 1435 -#define _tmp_193_type 1436 -#define _loop0_194_type 1437 +#define _loop0_189_type 1431 +#define _gather_188_type 1432 +#define _tmp_190_type 1433 +#define _loop0_191_type 1434 +#define _tmp_192_type 1435 +#define _loop0_193_type 1436 +#define _loop1_194_type 1437 #define _loop1_195_type 1438 -#define _loop1_196_type 1439 +#define _tmp_196_type 1439 #define _tmp_197_type 1440 -#define _tmp_198_type 1441 -#define _loop0_199_type 1442 +#define _loop0_198_type 1441 +#define _tmp_199_type 1442 #define _tmp_200_type 1443 #define _tmp_201_type 1444 -#define _tmp_202_type 1445 -#define _loop0_204_type 1446 -#define _gather_203_type 1447 -#define _loop0_206_type 1448 -#define _gather_205_type 1449 -#define _loop0_208_type 1450 -#define _gather_207_type 1451 -#define _loop0_210_type 1452 -#define _gather_209_type 1453 -#define _loop0_212_type 1454 -#define _gather_211_type 1455 -#define _tmp_213_type 1456 -#define _loop0_214_type 1457 -#define _loop1_215_type 1458 -#define _tmp_216_type 1459 -#define _loop0_217_type 1460 -#define _loop1_218_type 1461 +#define _loop0_203_type 1445 +#define _gather_202_type 1446 +#define _loop0_205_type 1447 +#define _gather_204_type 1448 +#define _loop0_207_type 1449 +#define _gather_206_type 1450 +#define _loop0_209_type 1451 +#define _gather_208_type 1452 +#define _loop0_211_type 1453 +#define _gather_210_type 1454 +#define _tmp_212_type 1455 +#define _loop0_213_type 1456 +#define _loop1_214_type 1457 +#define _tmp_215_type 1458 +#define _loop0_216_type 1459 +#define _loop1_217_type 1460 +#define _tmp_218_type 1461 #define _tmp_219_type 1462 #define _tmp_220_type 1463 #define _tmp_221_type 1464 @@ -549,9 +549,9 @@ static char *soft_keywords[] = { #define _tmp_225_type 1468 #define _tmp_226_type 1469 #define _tmp_227_type 1470 -#define _tmp_228_type 1471 -#define _loop0_230_type 1472 -#define _gather_229_type 1473 +#define _loop0_229_type 1471 +#define _gather_228_type 1472 +#define _tmp_230_type 1473 #define _tmp_231_type 1474 #define _tmp_232_type 1475 #define _tmp_233_type 1476 @@ -564,8 +564,8 @@ static char *soft_keywords[] = { #define _tmp_240_type 1483 #define _tmp_241_type 1484 #define _tmp_242_type 1485 -#define _tmp_243_type 1486 -#define _loop0_244_type 1487 +#define _loop0_243_type 1486 +#define _tmp_244_type 1487 #define _tmp_245_type 1488 #define _tmp_246_type 1489 #define _tmp_247_type 1490 @@ -597,7 +597,6 @@ static char *soft_keywords[] = { #define _tmp_273_type 1516 #define _tmp_274_type 1517 #define _tmp_275_type 1518 -#define _tmp_276_type 1519 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -1002,65 +1001,65 @@ static void *_tmp_156_rule(Parser *p); static void *_tmp_157_rule(Parser *p); static void *_tmp_158_rule(Parser *p); static void *_tmp_159_rule(Parser *p); -static void *_tmp_160_rule(Parser *p); +static asdl_seq *_loop0_160_rule(Parser *p); static asdl_seq *_loop0_161_rule(Parser *p); static asdl_seq *_loop0_162_rule(Parser *p); -static asdl_seq *_loop0_163_rule(Parser *p); +static void *_tmp_163_rule(Parser *p); static void *_tmp_164_rule(Parser *p); static void *_tmp_165_rule(Parser *p); static void *_tmp_166_rule(Parser *p); static void *_tmp_167_rule(Parser *p); -static void *_tmp_168_rule(Parser *p); +static asdl_seq *_loop0_168_rule(Parser *p); static asdl_seq *_loop0_169_rule(Parser *p); static asdl_seq *_loop0_170_rule(Parser *p); -static asdl_seq *_loop0_171_rule(Parser *p); -static asdl_seq *_loop1_172_rule(Parser *p); -static void *_tmp_173_rule(Parser *p); -static asdl_seq *_loop0_174_rule(Parser *p); -static void *_tmp_175_rule(Parser *p); -static asdl_seq *_loop0_176_rule(Parser *p); -static asdl_seq *_loop1_177_rule(Parser *p); +static asdl_seq *_loop1_171_rule(Parser *p); +static void *_tmp_172_rule(Parser *p); +static asdl_seq *_loop0_173_rule(Parser *p); +static void *_tmp_174_rule(Parser *p); +static asdl_seq *_loop0_175_rule(Parser *p); +static asdl_seq *_loop1_176_rule(Parser *p); +static void *_tmp_177_rule(Parser *p); static void *_tmp_178_rule(Parser *p); static void *_tmp_179_rule(Parser *p); -static void *_tmp_180_rule(Parser *p); -static asdl_seq *_loop0_181_rule(Parser *p); +static asdl_seq *_loop0_180_rule(Parser *p); +static void *_tmp_181_rule(Parser *p); static void *_tmp_182_rule(Parser *p); -static void *_tmp_183_rule(Parser *p); -static asdl_seq *_loop1_184_rule(Parser *p); -static void *_tmp_185_rule(Parser *p); +static asdl_seq *_loop1_183_rule(Parser *p); +static void *_tmp_184_rule(Parser *p); +static asdl_seq *_loop0_185_rule(Parser *p); static asdl_seq *_loop0_186_rule(Parser *p); static asdl_seq *_loop0_187_rule(Parser *p); -static asdl_seq *_loop0_188_rule(Parser *p); -static asdl_seq *_loop0_190_rule(Parser *p); -static asdl_seq *_gather_189_rule(Parser *p); -static void *_tmp_191_rule(Parser *p); -static asdl_seq *_loop0_192_rule(Parser *p); -static void *_tmp_193_rule(Parser *p); -static asdl_seq *_loop0_194_rule(Parser *p); +static asdl_seq *_loop0_189_rule(Parser *p); +static asdl_seq *_gather_188_rule(Parser *p); +static void *_tmp_190_rule(Parser *p); +static asdl_seq *_loop0_191_rule(Parser *p); +static void *_tmp_192_rule(Parser *p); +static asdl_seq *_loop0_193_rule(Parser *p); +static asdl_seq *_loop1_194_rule(Parser *p); static asdl_seq *_loop1_195_rule(Parser *p); -static asdl_seq *_loop1_196_rule(Parser *p); +static void *_tmp_196_rule(Parser *p); static void *_tmp_197_rule(Parser *p); -static void *_tmp_198_rule(Parser *p); -static asdl_seq *_loop0_199_rule(Parser *p); +static asdl_seq *_loop0_198_rule(Parser *p); +static void *_tmp_199_rule(Parser *p); static void *_tmp_200_rule(Parser *p); static void *_tmp_201_rule(Parser *p); -static void *_tmp_202_rule(Parser *p); -static asdl_seq *_loop0_204_rule(Parser *p); -static asdl_seq *_gather_203_rule(Parser *p); -static asdl_seq *_loop0_206_rule(Parser *p); -static asdl_seq *_gather_205_rule(Parser *p); -static asdl_seq *_loop0_208_rule(Parser *p); -static asdl_seq *_gather_207_rule(Parser *p); -static asdl_seq *_loop0_210_rule(Parser *p); -static asdl_seq *_gather_209_rule(Parser *p); -static asdl_seq *_loop0_212_rule(Parser *p); -static asdl_seq *_gather_211_rule(Parser *p); -static void *_tmp_213_rule(Parser *p); -static asdl_seq *_loop0_214_rule(Parser *p); -static asdl_seq *_loop1_215_rule(Parser *p); -static void *_tmp_216_rule(Parser *p); -static asdl_seq *_loop0_217_rule(Parser *p); -static asdl_seq *_loop1_218_rule(Parser *p); +static asdl_seq *_loop0_203_rule(Parser *p); +static asdl_seq *_gather_202_rule(Parser *p); +static asdl_seq *_loop0_205_rule(Parser *p); +static asdl_seq *_gather_204_rule(Parser *p); +static asdl_seq *_loop0_207_rule(Parser *p); +static asdl_seq *_gather_206_rule(Parser *p); +static asdl_seq *_loop0_209_rule(Parser *p); +static asdl_seq *_gather_208_rule(Parser *p); +static asdl_seq *_loop0_211_rule(Parser *p); +static asdl_seq *_gather_210_rule(Parser *p); +static void *_tmp_212_rule(Parser *p); +static asdl_seq *_loop0_213_rule(Parser *p); +static asdl_seq *_loop1_214_rule(Parser *p); +static void *_tmp_215_rule(Parser *p); +static asdl_seq *_loop0_216_rule(Parser *p); +static asdl_seq *_loop1_217_rule(Parser *p); +static void *_tmp_218_rule(Parser *p); static void *_tmp_219_rule(Parser *p); static void *_tmp_220_rule(Parser *p); static void *_tmp_221_rule(Parser *p); @@ -1070,9 +1069,9 @@ static void *_tmp_224_rule(Parser *p); static void *_tmp_225_rule(Parser *p); static void *_tmp_226_rule(Parser *p); static void *_tmp_227_rule(Parser *p); -static void *_tmp_228_rule(Parser *p); -static asdl_seq *_loop0_230_rule(Parser *p); -static asdl_seq *_gather_229_rule(Parser *p); +static asdl_seq *_loop0_229_rule(Parser *p); +static asdl_seq *_gather_228_rule(Parser *p); +static void *_tmp_230_rule(Parser *p); static void *_tmp_231_rule(Parser *p); static void *_tmp_232_rule(Parser *p); static void *_tmp_233_rule(Parser *p); @@ -1085,8 +1084,8 @@ static void *_tmp_239_rule(Parser *p); static void *_tmp_240_rule(Parser *p); static void *_tmp_241_rule(Parser *p); static void *_tmp_242_rule(Parser *p); -static void *_tmp_243_rule(Parser *p); -static asdl_seq *_loop0_244_rule(Parser *p); +static asdl_seq *_loop0_243_rule(Parser *p); +static void *_tmp_244_rule(Parser *p); static void *_tmp_245_rule(Parser *p); static void *_tmp_246_rule(Parser *p); static void *_tmp_247_rule(Parser *p); @@ -1118,7 +1117,6 @@ static void *_tmp_272_rule(Parser *p); static void *_tmp_273_rule(Parser *p); static void *_tmp_274_rule(Parser *p); static void *_tmp_275_rule(Parser *p); -static void *_tmp_276_rule(Parser *p); // file: statements? $ @@ -20274,7 +20272,7 @@ invalid_legacy_expression_rule(Parser *p) // invalid_expression: // | !(NAME STRING | SOFT_KEYWORD) disjunction expression_without_invalid // | disjunction 'if' disjunction !('else' | ':') -// | 'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field) +// | 'lambda' lambda_params? ':' &FSTRING_MIDDLE static void * invalid_expression_rule(Parser *p) { @@ -20348,12 +20346,12 @@ invalid_expression_rule(Parser *p) D(fprintf(stderr, "%*c%s invalid_expression[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); } - { // 'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field) + { // 'lambda' lambda_params? ':' &FSTRING_MIDDLE if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)")); + D(fprintf(stderr, "%*c> invalid_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &FSTRING_MIDDLE")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -20365,10 +20363,10 @@ invalid_expression_rule(Parser *p) && (b = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_157_rule, p) + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, FSTRING_MIDDLE) // token=FSTRING_MIDDLE ) { - D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)")); + D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &FSTRING_MIDDLE")); _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "f-string: lambda expressions are not allowed without parentheses" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -20379,7 +20377,7 @@ invalid_expression_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_expression[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'lambda' lambda_params? ':' &FSTRING_MIDDLE")); } _res = NULL; done: @@ -20453,7 +20451,7 @@ invalid_named_expression_rule(Parser *p) && (b = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_158_rule, p) + _PyPegen_lookahead(0, _tmp_157_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | ':=')")); @@ -20479,7 +20477,7 @@ invalid_named_expression_rule(Parser *p) Token * b; expr_ty bitwise_or_var; if ( - _PyPegen_lookahead(0, _tmp_159_rule, p) + _PyPegen_lookahead(0, _tmp_158_rule, p) && (a = bitwise_or_rule(p)) // bitwise_or && @@ -20487,7 +20485,7 @@ invalid_named_expression_rule(Parser *p) && (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_160_rule, p) + _PyPegen_lookahead(0, _tmp_159_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')")); @@ -20567,7 +20565,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_161_var; + asdl_seq * _loop0_160_var; expr_ty a; expr_ty expression_var; if ( @@ -20575,7 +20573,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_161_var = _loop0_161_rule(p)) // star_named_expressions* + (_loop0_160_var = _loop0_160_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -20632,10 +20630,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_162_var; + asdl_seq * _loop0_161_var; expr_ty a; if ( - (_loop0_162_var = _loop0_162_rule(p)) // ((star_targets '='))* + (_loop0_161_var = _loop0_161_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -20662,10 +20660,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_163_var; + asdl_seq * _loop0_162_var; expr_ty a; if ( - (_loop0_163_var = _loop0_163_rule(p)) // ((star_targets '='))* + (_loop0_162_var = _loop0_162_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -20691,7 +20689,7 @@ invalid_assignment_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); - void *_tmp_164_var; + void *_tmp_163_var; expr_ty a; AugOperator* augassign_var; if ( @@ -20699,7 +20697,7 @@ invalid_assignment_rule(Parser *p) && (augassign_var = augassign_rule(p)) // augassign && - (_tmp_164_var = _tmp_164_rule(p)) // yield_expr | star_expressions + (_tmp_163_var = _tmp_163_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); @@ -20921,11 +20919,11 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_165_var; + void *_tmp_164_var; expr_ty a; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_165_var = _tmp_165_rule(p)) // '[' | '(' | '{' + (_tmp_164_var = _tmp_164_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -20952,12 +20950,12 @@ invalid_comprehension_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses")); Token * _literal; - void *_tmp_166_var; + void *_tmp_165_var; expr_ty a; asdl_expr_seq* b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_166_var = _tmp_166_rule(p)) // '[' | '{' + (_tmp_165_var = _tmp_165_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20987,12 +20985,12 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' for_if_clauses")); - void *_tmp_167_var; + void *_tmp_166_var; expr_ty a; Token * b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_167_var = _tmp_167_rule(p)) // '[' | '{' + (_tmp_166_var = _tmp_166_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -21127,13 +21125,13 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slash_no_default | slash_with_default) param_maybe_default* '/'")); - asdl_seq * _loop0_169_var; - void *_tmp_168_var; + asdl_seq * _loop0_168_var; + void *_tmp_167_var; Token * a; if ( - (_tmp_168_var = _tmp_168_rule(p)) // slash_no_default | slash_with_default + (_tmp_167_var = _tmp_167_rule(p)) // slash_no_default | slash_with_default && - (_loop0_169_var = _loop0_169_rule(p)) // param_maybe_default* + (_loop0_168_var = _loop0_168_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21157,7 +21155,7 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default? param_no_default* invalid_parameters_helper param_no_default")); - asdl_seq * _loop0_170_var; + asdl_seq * _loop0_169_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21165,7 +21163,7 @@ invalid_parameters_rule(Parser *p) if ( (_opt_var = slash_no_default_rule(p), !p->error_indicator) // slash_no_default? && - (_loop0_170_var = _loop0_170_rule(p)) // param_no_default* + (_loop0_169_var = _loop0_169_rule(p)) // param_no_default* && (invalid_parameters_helper_var = invalid_parameters_helper_rule(p)) // invalid_parameters_helper && @@ -21191,18 +21189,18 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* '(' param_no_default+ ','? ')'")); - asdl_seq * _loop0_171_var; - asdl_seq * _loop1_172_var; + asdl_seq * _loop0_170_var; + asdl_seq * _loop1_171_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_171_var = _loop0_171_rule(p)) // param_no_default* + (_loop0_170_var = _loop0_170_rule(p)) // param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_loop1_172_var = _loop1_172_rule(p)) // param_no_default+ + (_loop1_171_var = _loop1_171_rule(p)) // param_no_default+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21229,22 +21227,22 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(slash_no_default | slash_with_default)] param_maybe_default* '*' (',' | param_no_default) param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_174_var; - asdl_seq * _loop0_176_var; + asdl_seq * _loop0_173_var; + asdl_seq * _loop0_175_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_175_var; + void *_tmp_174_var; Token * a; if ( - (_opt_var = _tmp_173_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] + (_opt_var = _tmp_172_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] && - (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default* + (_loop0_173_var = _loop0_173_rule(p)) // param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_175_var = _tmp_175_rule(p)) // ',' | param_no_default + (_tmp_174_var = _tmp_174_rule(p)) // ',' | param_no_default && - (_loop0_176_var = _loop0_176_rule(p)) // param_maybe_default* + (_loop0_175_var = _loop0_175_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21269,10 +21267,10 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_177_var; + asdl_seq * _loop1_176_var; Token * a; if ( - (_loop1_177_var = _loop1_177_rule(p)) // param_maybe_default+ + (_loop1_176_var = _loop1_176_rule(p)) // param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21321,7 +21319,7 @@ invalid_default_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_178_rule, p) + _PyPegen_lookahead(1, _tmp_177_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')")); @@ -21366,12 +21364,12 @@ invalid_star_etc_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); - void *_tmp_179_var; + void *_tmp_178_var; Token * a; if ( (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_179_var = _tmp_179_rule(p)) // ')' | ',' (')' | '**') + (_tmp_178_var = _tmp_178_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -21454,20 +21452,20 @@ invalid_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_181_var; - void *_tmp_180_var; - void *_tmp_182_var; + asdl_seq * _loop0_180_var; + void *_tmp_179_var; + void *_tmp_181_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_180_var = _tmp_180_rule(p)) // param_no_default | ',' + (_tmp_179_var = _tmp_179_rule(p)) // param_no_default | ',' && - (_loop0_181_var = _loop0_181_rule(p)) // param_maybe_default* + (_loop0_180_var = _loop0_180_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_182_var = _tmp_182_rule(p)) // param_no_default | ',' + (_tmp_181_var = _tmp_181_rule(p)) // param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); @@ -21582,7 +21580,7 @@ invalid_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_183_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_182_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')")); @@ -21647,13 +21645,13 @@ invalid_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - asdl_seq * _loop1_184_var; + asdl_seq * _loop1_183_var; if ( - (_loop1_184_var = _loop1_184_rule(p)) // param_with_default+ + (_loop1_183_var = _loop1_183_rule(p)) // param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - _res = _loop1_184_var; + _res = _loop1_183_var; goto done; } p->mark = _mark; @@ -21718,13 +21716,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/'")); - asdl_seq * _loop0_186_var; - void *_tmp_185_var; + asdl_seq * _loop0_185_var; + void *_tmp_184_var; Token * a; if ( - (_tmp_185_var = _tmp_185_rule(p)) // lambda_slash_no_default | lambda_slash_with_default + (_tmp_184_var = _tmp_184_rule(p)) // lambda_slash_no_default | lambda_slash_with_default && - (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_maybe_default* + (_loop0_185_var = _loop0_185_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21748,7 +21746,7 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default")); - asdl_seq * _loop0_187_var; + asdl_seq * _loop0_186_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21756,7 +21754,7 @@ invalid_lambda_parameters_rule(Parser *p) if ( (_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default? && - (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_no_default* + (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_no_default* && (invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper && @@ -21782,18 +21780,18 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* '(' ','.lambda_param+ ','? ')'")); - asdl_seq * _gather_189_var; - asdl_seq * _loop0_188_var; + asdl_seq * _gather_188_var; + asdl_seq * _loop0_187_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_188_var = _loop0_188_rule(p)) // lambda_param_no_default* + (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_189_var = _gather_189_rule(p)) // ','.lambda_param+ + (_gather_188_var = _gather_188_rule(p)) // ','.lambda_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21820,22 +21818,22 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_192_var; - asdl_seq * _loop0_194_var; + asdl_seq * _loop0_191_var; + asdl_seq * _loop0_193_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_193_var; + void *_tmp_192_var; Token * a; if ( - (_opt_var = _tmp_191_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] + (_opt_var = _tmp_190_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] && - (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default* + (_loop0_191_var = _loop0_191_rule(p)) // lambda_param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_193_var = _tmp_193_rule(p)) // ',' | lambda_param_no_default + (_tmp_192_var = _tmp_192_rule(p)) // ',' | lambda_param_no_default && - (_loop0_194_var = _loop0_194_rule(p)) // lambda_param_maybe_default* + (_loop0_193_var = _loop0_193_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21860,10 +21858,10 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_195_var; + asdl_seq * _loop1_194_var; Token * a; if ( - (_loop1_195_var = _loop1_195_rule(p)) // lambda_param_maybe_default+ + (_loop1_194_var = _loop1_194_rule(p)) // lambda_param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21934,13 +21932,13 @@ invalid_lambda_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_196_var; + asdl_seq * _loop1_195_var; if ( - (_loop1_196_var = _loop1_196_rule(p)) // lambda_param_with_default+ + (_loop1_195_var = _loop1_195_rule(p)) // lambda_param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_lambda_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_196_var; + _res = _loop1_195_var; goto done; } p->mark = _mark; @@ -21976,11 +21974,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_197_var; + void *_tmp_196_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_197_var = _tmp_197_rule(p)) // ':' | ',' (':' | '**') + (_tmp_196_var = _tmp_196_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -22033,20 +22031,20 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_199_var; - void *_tmp_198_var; - void *_tmp_200_var; + asdl_seq * _loop0_198_var; + void *_tmp_197_var; + void *_tmp_199_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_198_var = _tmp_198_rule(p)) // lambda_param_no_default | ',' + (_tmp_197_var = _tmp_197_rule(p)) // lambda_param_no_default | ',' && - (_loop0_199_var = _loop0_199_rule(p)) // lambda_param_maybe_default* + (_loop0_198_var = _loop0_198_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_200_var = _tmp_200_rule(p)) // lambda_param_no_default | ',' + (_tmp_199_var = _tmp_199_rule(p)) // lambda_param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); @@ -22164,7 +22162,7 @@ invalid_lambda_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_201_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_200_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')")); @@ -22270,7 +22268,7 @@ invalid_with_item_rule(Parser *p) && (a = expression_rule(p)) // expression && - _PyPegen_lookahead(1, _tmp_202_rule, p) + _PyPegen_lookahead(1, _tmp_201_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' | ')' | ':')")); @@ -22443,14 +22441,14 @@ invalid_import_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); - asdl_seq * _gather_203_var; + asdl_seq * _gather_202_var; Token * _keyword; Token * a; expr_ty dotted_name_var; if ( (a = _PyPegen_expect_token(p, 607)) // token='import' && - (_gather_203_var = _gather_203_rule(p)) // ','.dotted_name+ + (_gather_202_var = _gather_202_rule(p)) // ','.dotted_name+ && (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && @@ -22546,7 +22544,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_205_var; + asdl_seq * _gather_204_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22556,7 +22554,7 @@ invalid_with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_205_var = _gather_205_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_204_var = _gather_204_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22580,7 +22578,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_207_var; + asdl_seq * _gather_206_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -22596,7 +22594,7 @@ invalid_with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_207_var = _gather_207_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_206_var = _gather_206_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22645,7 +22643,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_209_var; + asdl_seq * _gather_208_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22656,7 +22654,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (a = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_209_var = _gather_209_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_208_var = _gather_208_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22684,7 +22682,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_211_var; + asdl_seq * _gather_210_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -22701,7 +22699,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_211_var = _gather_211_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_210_var = _gather_210_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22798,7 +22796,7 @@ invalid_try_stmt_rule(Parser *p) && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_213_rule, p) + _PyPegen_lookahead(0, _tmp_212_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -22823,8 +22821,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_214_var; - asdl_seq * _loop1_215_var; + asdl_seq * _loop0_213_var; + asdl_seq * _loop1_214_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22835,9 +22833,9 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_214_var = _loop0_214_rule(p)) // block* + (_loop0_213_var = _loop0_213_rule(p)) // block* && - (_loop1_215_var = _loop1_215_rule(p)) // except_block+ + (_loop1_214_var = _loop1_214_rule(p)) // except_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && @@ -22845,7 +22843,7 @@ invalid_try_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_215_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22872,8 +22870,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_217_var; - asdl_seq * _loop1_218_var; + asdl_seq * _loop0_216_var; + asdl_seq * _loop1_217_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22882,13 +22880,13 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_217_var = _loop0_217_rule(p)) // block* + (_loop0_216_var = _loop0_216_rule(p)) // block* && - (_loop1_218_var = _loop1_218_rule(p)) // except_star_block+ + (_loop1_217_var = _loop1_217_rule(p)) // except_star_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && - (_opt_var = _tmp_219_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_218_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22955,7 +22953,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var_1 = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22993,7 +22991,7 @@ invalid_except_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var_1 = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23045,14 +23043,14 @@ invalid_except_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_222_var; + void *_tmp_221_var; Token * a; if ( (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_222_var = _tmp_222_rule(p)) // NEWLINE | ':' + (_tmp_221_var = _tmp_221_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -23157,7 +23155,7 @@ invalid_except_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_222_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23251,7 +23249,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23615,7 +23613,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_225_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_224_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -24103,7 +24101,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_226_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_2 = _tmp_225_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24162,7 +24160,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_226_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24197,7 +24195,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_228_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24247,11 +24245,11 @@ invalid_double_starred_kvpairs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_229_var; + asdl_seq * _gather_228_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_229_var = _gather_229_rule(p)) // ','.double_starred_kvpair+ + (_gather_228_var = _gather_228_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24259,7 +24257,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_229_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_228_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -24312,7 +24310,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_231_rule, p) + _PyPegen_lookahead(1, _tmp_230_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24422,7 +24420,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_232_rule, p) + _PyPegen_lookahead(1, _tmp_231_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24638,7 +24636,7 @@ invalid_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - _PyPegen_lookahead(0, _tmp_233_rule, p) + _PyPegen_lookahead(0, _tmp_232_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)")); @@ -24661,13 +24659,13 @@ invalid_replacement_field_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); Token * _literal; - void *_tmp_234_var; + void *_tmp_233_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions + (_tmp_233_var = _tmp_233_rule(p)) // yield_expr | star_expressions && - _PyPegen_lookahead(0, _tmp_235_rule, p) + _PyPegen_lookahead(0, _tmp_234_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); @@ -24691,15 +24689,15 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); Token * _literal; Token * _literal_1; - void *_tmp_236_var; + void *_tmp_235_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions + (_tmp_235_var = _tmp_235_rule(p)) // yield_expr | star_expressions && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_237_rule, p) + _PyPegen_lookahead(0, _tmp_236_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); @@ -24724,12 +24722,12 @@ invalid_replacement_field_rule(Parser *p) Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_238_var; + void *_tmp_237_var; void *invalid_conversion_character_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions + (_tmp_237_var = _tmp_237_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && @@ -24737,7 +24735,7 @@ invalid_replacement_field_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_238_var, _opt_var, invalid_conversion_character_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_237_var, _opt_var, invalid_conversion_character_var); goto done; } p->mark = _mark; @@ -24755,17 +24753,17 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_239_var; + void *_tmp_238_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_239_var = _tmp_239_rule(p)) // yield_expr | star_expressions + (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_240_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_239_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_241_rule, p) + _PyPegen_lookahead(0, _tmp_240_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); @@ -24789,24 +24787,24 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_244_var; + asdl_seq * _loop0_243_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_242_var; + void *_tmp_241_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_242_var = _tmp_242_rule(p)) // yield_expr | star_expressions + (_tmp_241_var = _tmp_241_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_243_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_242_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_244_var = _loop0_244_rule(p)) // fstring_format_spec* + (_loop0_243_var = _loop0_243_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24835,15 +24833,15 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_245_var; + void *_tmp_244_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_245_var = _tmp_245_rule(p)) // yield_expr | star_expressions + (_tmp_244_var = _tmp_244_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_246_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_245_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24890,7 +24888,7 @@ invalid_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_247_rule, p) + _PyPegen_lookahead(1, _tmp_246_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -25820,12 +25818,12 @@ _loop1_15_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_248_var; + void *_tmp_247_var; while ( - (_tmp_248_var = _tmp_248_rule(p)) // star_targets '=' + (_tmp_247_var = _tmp_247_rule(p)) // star_targets '=' ) { - _res = _tmp_248_var; + _res = _tmp_247_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26389,12 +26387,12 @@ _loop0_25_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_249_var; + void *_tmp_248_var; while ( - (_tmp_249_var = _tmp_249_rule(p)) // '.' | '...' + (_tmp_248_var = _tmp_248_rule(p)) // '.' | '...' ) { - _res = _tmp_249_var; + _res = _tmp_248_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26456,12 +26454,12 @@ _loop1_26_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_250_var; + void *_tmp_249_var; while ( - (_tmp_250_var = _tmp_250_rule(p)) // '.' | '...' + (_tmp_249_var = _tmp_249_rule(p)) // '.' | '...' ) { - _res = _tmp_250_var; + _res = _tmp_249_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26854,12 +26852,12 @@ _loop1_33_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_251_var; + void *_tmp_250_var; while ( - (_tmp_251_var = _tmp_251_rule(p)) // '@' named_expression NEWLINE + (_tmp_250_var = _tmp_250_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_251_var; + _res = _tmp_250_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29984,12 +29982,12 @@ _loop1_83_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_252_var; + void *_tmp_251_var; while ( - (_tmp_252_var = _tmp_252_rule(p)) // ',' expression + (_tmp_251_var = _tmp_251_rule(p)) // ',' expression ) { - _res = _tmp_252_var; + _res = _tmp_251_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30056,9 +30054,198 @@ _loop1_84_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); + void *_tmp_252_var; + while ( + (_tmp_252_var = _tmp_252_rule(p)) // ',' star_expression + ) + { + _res = _tmp_252_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop1_84[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)")); + } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop0_86: ',' star_named_expression +static asdl_seq * +_loop0_86_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ',' star_named_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); + Token * _literal; + expr_ty elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = star_named_expression_rule(p)) // star_named_expression + ) + { + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _gather_85: star_named_expression _loop0_86 +static asdl_seq * +_gather_85_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_seq * _res = NULL; + int _mark = p->mark; + { // star_named_expression _loop0_86 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); + expr_ty elem; + asdl_seq * seq; + if ( + (elem = star_named_expression_rule(p)) // star_named_expression + && + (seq = _loop0_86_rule(p)) // _loop0_86 + ) + { + D(fprintf(stderr, "%*c+ _gather_85[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_85[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_86")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop1_87: ('or' conjunction) +static asdl_seq * +_loop1_87_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ('or' conjunction) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); void *_tmp_253_var; while ( - (_tmp_253_var = _tmp_253_rule(p)) // ',' star_expression + (_tmp_253_var = _tmp_253_rule(p)) // 'or' conjunction ) { _res = _tmp_253_var; @@ -30078,195 +30265,6 @@ _loop1_84_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_84[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop0_86: ',' star_named_expression -static asdl_seq * -_loop0_86_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // ',' star_named_expression - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); - Token * _literal; - expr_ty elem; - while ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (elem = star_named_expression_rule(p)) // star_named_expression - ) - { - _res = elem; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - PyMem_Free(_children); - p->level--; - return NULL; - } - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _gather_85: star_named_expression _loop0_86 -static asdl_seq * -_gather_85_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - asdl_seq * _res = NULL; - int _mark = p->mark; - { // star_named_expression _loop0_86 - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _gather_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); - expr_ty elem; - asdl_seq * seq; - if ( - (elem = star_named_expression_rule(p)) // star_named_expression - && - (seq = _loop0_86_rule(p)) // _loop0_86 - ) - { - D(fprintf(stderr, "%*c+ _gather_85[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); - _res = _PyPegen_seq_insert_in_front(p, elem, seq); - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_85[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_86")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop1_87: ('or' conjunction) -static asdl_seq * -_loop1_87_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // ('or' conjunction) - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_254_var; - while ( - (_tmp_254_var = _tmp_254_rule(p)) // 'or' conjunction - ) - { - _res = _tmp_254_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)")); } @@ -30317,12 +30315,12 @@ _loop1_88_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_255_var; + void *_tmp_254_var; while ( - (_tmp_255_var = _tmp_255_rule(p)) // 'and' inversion + (_tmp_254_var = _tmp_254_rule(p)) // 'and' inversion ) { - _res = _tmp_255_var; + _res = _tmp_254_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30509,7 +30507,7 @@ _loop0_92_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_256_rule(p)) // slice | starred_expression + (elem = _tmp_255_rule(p)) // slice | starred_expression ) { _res = elem; @@ -30574,7 +30572,7 @@ _gather_91_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_256_rule(p)) // slice | starred_expression + (elem = _tmp_255_rule(p)) // slice | starred_expression && (seq = _loop0_92_rule(p)) // _loop0_92 ) @@ -32106,12 +32104,12 @@ _loop1_115_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_257_var; + void *_tmp_256_var; while ( - (_tmp_257_var = _tmp_257_rule(p)) // fstring | string + (_tmp_256_var = _tmp_256_rule(p)) // fstring | string ) { - _res = _tmp_257_var; + _res = _tmp_256_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32416,12 +32414,12 @@ _loop0_120_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_258_var; + void *_tmp_257_var; while ( - (_tmp_258_var = _tmp_258_rule(p)) // 'if' disjunction + (_tmp_257_var = _tmp_257_rule(p)) // 'if' disjunction ) { - _res = _tmp_258_var; + _res = _tmp_257_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32483,12 +32481,12 @@ _loop0_121_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_259_var; + void *_tmp_258_var; while ( - (_tmp_259_var = _tmp_259_rule(p)) // 'if' disjunction + (_tmp_258_var = _tmp_258_rule(p)) // 'if' disjunction ) { - _res = _tmp_259_var; + _res = _tmp_258_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32614,7 +32612,7 @@ _loop0_124_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_259_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -32680,7 +32678,7 @@ _gather_123_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_259_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && (seq = _loop0_124_rule(p)) // _loop0_124 ) @@ -33241,12 +33239,12 @@ _loop0_134_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_261_var; + void *_tmp_260_var; while ( - (_tmp_261_var = _tmp_261_rule(p)) // ',' star_target + (_tmp_260_var = _tmp_260_rule(p)) // ',' star_target ) { - _res = _tmp_261_var; + _res = _tmp_260_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33425,12 +33423,12 @@ _loop1_137_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_262_var; + void *_tmp_261_var; while ( - (_tmp_262_var = _tmp_262_rule(p)) // ',' star_target + (_tmp_261_var = _tmp_261_rule(p)) // ',' star_target ) { - _res = _tmp_262_var; + _res = _tmp_261_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34527,66 +34525,9 @@ _tmp_156_rule(Parser *p) return _res; } -// _tmp_157: FSTRING_MIDDLE | fstring_replacement_field +// _tmp_157: '=' | ':=' static void * _tmp_157_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // FSTRING_MIDDLE - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); - Token * fstring_middle_var; - if ( - (fstring_middle_var = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE' - ) - { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); - _res = fstring_middle_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE")); - } - { // fstring_replacement_field - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); - expr_ty fstring_replacement_field_var; - if ( - (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field - ) - { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); - _res = fstring_replacement_field_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_158: '=' | ':=' -static void * -_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34602,18 +34543,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34621,18 +34562,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34641,9 +34582,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _tmp_159: list | tuple | genexp | 'True' | 'None' | 'False' +// _tmp_158: list | tuple | genexp | 'True' | 'None' | 'False' static void * -_tmp_159_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34659,18 +34600,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // tuple @@ -34678,18 +34619,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // genexp @@ -34697,18 +34638,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } { // 'True' @@ -34716,18 +34657,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'None' @@ -34735,18 +34676,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } { // 'False' @@ -34754,18 +34695,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } _res = NULL; @@ -34774,9 +34715,9 @@ _tmp_159_rule(Parser *p) return _res; } -// _tmp_160: '=' | ':=' +// _tmp_159: '=' | ':=' static void * -_tmp_160_rule(Parser *p) +_tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34792,18 +34733,18 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34811,18 +34752,18 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34831,9 +34772,9 @@ _tmp_160_rule(Parser *p) return _res; } -// _loop0_161: star_named_expressions +// _loop0_160: star_named_expressions static asdl_seq * -_loop0_161_rule(Parser *p) +_loop0_160_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34858,7 +34799,7 @@ _loop0_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_expr_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -34881,7 +34822,7 @@ _loop0_161_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34898,9 +34839,9 @@ _loop0_161_rule(Parser *p) return _seq; } -// _loop0_162: (star_targets '=') +// _loop0_161: (star_targets '=') static asdl_seq * -_loop0_162_rule(Parser *p) +_loop0_161_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34925,13 +34866,13 @@ _loop0_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_263_var; + D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_262_var; while ( - (_tmp_263_var = _tmp_263_rule(p)) // star_targets '=' + (_tmp_262_var = _tmp_262_rule(p)) // star_targets '=' ) { - _res = _tmp_263_var; + _res = _tmp_262_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34948,7 +34889,7 @@ _loop0_162_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34965,9 +34906,9 @@ _loop0_162_rule(Parser *p) return _seq; } -// _loop0_163: (star_targets '=') +// _loop0_162: (star_targets '=') static asdl_seq * -_loop0_163_rule(Parser *p) +_loop0_162_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34992,13 +34933,13 @@ _loop0_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_264_var; + D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_263_var; while ( - (_tmp_264_var = _tmp_264_rule(p)) // star_targets '=' + (_tmp_263_var = _tmp_263_rule(p)) // star_targets '=' ) { - _res = _tmp_264_var; + _res = _tmp_263_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35015,7 +34956,7 @@ _loop0_163_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35032,9 +34973,9 @@ _loop0_163_rule(Parser *p) return _seq; } -// _tmp_164: yield_expr | star_expressions +// _tmp_163: yield_expr | star_expressions static void * -_tmp_164_rule(Parser *p) +_tmp_163_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35050,18 +34991,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -35069,18 +35010,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -35089,9 +35030,9 @@ _tmp_164_rule(Parser *p) return _res; } -// _tmp_165: '[' | '(' | '{' +// _tmp_164: '[' | '(' | '{' static void * -_tmp_165_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35107,18 +35048,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '(' @@ -35126,18 +35067,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '{' @@ -35145,18 +35086,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35165,9 +35106,9 @@ _tmp_165_rule(Parser *p) return _res; } -// _tmp_166: '[' | '{' +// _tmp_165: '[' | '{' static void * -_tmp_166_rule(Parser *p) +_tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35183,18 +35124,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -35202,18 +35143,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35222,9 +35163,9 @@ _tmp_166_rule(Parser *p) return _res; } -// _tmp_167: '[' | '{' +// _tmp_166: '[' | '{' static void * -_tmp_167_rule(Parser *p) +_tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35240,18 +35181,18 @@ _tmp_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -35259,18 +35200,18 @@ _tmp_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35279,9 +35220,9 @@ _tmp_167_rule(Parser *p) return _res; } -// _tmp_168: slash_no_default | slash_with_default +// _tmp_167: slash_no_default | slash_with_default static void * -_tmp_168_rule(Parser *p) +_tmp_167_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35297,18 +35238,18 @@ _tmp_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35316,18 +35257,18 @@ _tmp_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35336,9 +35277,9 @@ _tmp_168_rule(Parser *p) return _res; } -// _loop0_169: param_maybe_default +// _loop0_168: param_maybe_default static asdl_seq * -_loop0_169_rule(Parser *p) +_loop0_168_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35363,7 +35304,7 @@ _loop0_169_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35386,7 +35327,7 @@ _loop0_169_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35403,9 +35344,9 @@ _loop0_169_rule(Parser *p) return _seq; } -// _loop0_170: param_no_default +// _loop0_169: param_no_default static asdl_seq * -_loop0_170_rule(Parser *p) +_loop0_169_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35430,7 +35371,7 @@ _loop0_170_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35453,7 +35394,7 @@ _loop0_170_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_170[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35470,9 +35411,9 @@ _loop0_170_rule(Parser *p) return _seq; } -// _loop0_171: param_no_default +// _loop0_170: param_no_default static asdl_seq * -_loop0_171_rule(Parser *p) +_loop0_170_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35497,7 +35438,7 @@ _loop0_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35520,7 +35461,7 @@ _loop0_171_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_170[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35537,9 +35478,9 @@ _loop0_171_rule(Parser *p) return _seq; } -// _loop1_172: param_no_default +// _loop1_171: param_no_default static asdl_seq * -_loop1_172_rule(Parser *p) +_loop1_171_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35564,7 +35505,7 @@ _loop1_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35587,7 +35528,7 @@ _loop1_172_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_171[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -35609,9 +35550,9 @@ _loop1_172_rule(Parser *p) return _seq; } -// _tmp_173: slash_no_default | slash_with_default +// _tmp_172: slash_no_default | slash_with_default static void * -_tmp_173_rule(Parser *p) +_tmp_172_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35627,18 +35568,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35646,18 +35587,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35666,9 +35607,9 @@ _tmp_173_rule(Parser *p) return _res; } -// _loop0_174: param_maybe_default +// _loop0_173: param_maybe_default static asdl_seq * -_loop0_174_rule(Parser *p) +_loop0_173_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35693,7 +35634,7 @@ _loop0_174_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35716,7 +35657,7 @@ _loop0_174_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_174[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35733,9 +35674,9 @@ _loop0_174_rule(Parser *p) return _seq; } -// _tmp_175: ',' | param_no_default +// _tmp_174: ',' | param_no_default static void * -_tmp_175_rule(Parser *p) +_tmp_174_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35751,18 +35692,18 @@ _tmp_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // param_no_default @@ -35770,18 +35711,18 @@ _tmp_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } _res = NULL; @@ -35790,9 +35731,9 @@ _tmp_175_rule(Parser *p) return _res; } -// _loop0_176: param_maybe_default +// _loop0_175: param_maybe_default static asdl_seq * -_loop0_176_rule(Parser *p) +_loop0_175_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35817,7 +35758,7 @@ _loop0_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35840,7 +35781,7 @@ _loop0_176_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35857,9 +35798,9 @@ _loop0_176_rule(Parser *p) return _seq; } -// _loop1_177: param_maybe_default +// _loop1_176: param_maybe_default static asdl_seq * -_loop1_177_rule(Parser *p) +_loop1_176_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35884,7 +35825,7 @@ _loop1_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35907,7 +35848,7 @@ _loop1_177_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_176[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -35929,9 +35870,9 @@ _loop1_177_rule(Parser *p) return _seq; } -// _tmp_178: ')' | ',' +// _tmp_177: ')' | ',' static void * -_tmp_178_rule(Parser *p) +_tmp_177_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35947,18 +35888,18 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' @@ -35966,18 +35907,18 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -35986,9 +35927,9 @@ _tmp_178_rule(Parser *p) return _res; } -// _tmp_179: ')' | ',' (')' | '**') +// _tmp_178: ')' | ',' (')' | '**') static void * -_tmp_179_rule(Parser *p) +_tmp_178_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36004,18 +35945,18 @@ _tmp_179_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -36023,21 +35964,21 @@ _tmp_179_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_265_var; + void *_tmp_264_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_265_var = _tmp_265_rule(p)) // ')' | '**' + (_tmp_264_var = _tmp_264_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_265_var); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_264_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -36046,9 +35987,9 @@ _tmp_179_rule(Parser *p) return _res; } -// _tmp_180: param_no_default | ',' +// _tmp_179: param_no_default | ',' static void * -_tmp_180_rule(Parser *p) +_tmp_179_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36064,18 +36005,18 @@ _tmp_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -36083,18 +36024,18 @@ _tmp_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -36103,9 +36044,9 @@ _tmp_180_rule(Parser *p) return _res; } -// _loop0_181: param_maybe_default +// _loop0_180: param_maybe_default static asdl_seq * -_loop0_181_rule(Parser *p) +_loop0_180_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36130,7 +36071,7 @@ _loop0_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -36153,7 +36094,7 @@ _loop0_181_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_181[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_180[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36170,9 +36111,9 @@ _loop0_181_rule(Parser *p) return _seq; } -// _tmp_182: param_no_default | ',' +// _tmp_181: param_no_default | ',' static void * -_tmp_182_rule(Parser *p) +_tmp_181_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36188,18 +36129,18 @@ _tmp_182_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -36207,18 +36148,18 @@ _tmp_182_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -36227,9 +36168,9 @@ _tmp_182_rule(Parser *p) return _res; } -// _tmp_183: '*' | '**' | '/' +// _tmp_182: '*' | '**' | '/' static void * -_tmp_183_rule(Parser *p) +_tmp_182_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36245,18 +36186,18 @@ _tmp_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -36264,18 +36205,18 @@ _tmp_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -36283,18 +36224,18 @@ _tmp_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -36303,9 +36244,9 @@ _tmp_183_rule(Parser *p) return _res; } -// _loop1_184: param_with_default +// _loop1_183: param_with_default static asdl_seq * -_loop1_184_rule(Parser *p) +_loop1_183_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36330,7 +36271,7 @@ _loop1_184_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -36353,7 +36294,7 @@ _loop1_184_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_184[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_183[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -36375,9 +36316,9 @@ _loop1_184_rule(Parser *p) return _seq; } -// _tmp_185: lambda_slash_no_default | lambda_slash_with_default +// _tmp_184: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_185_rule(Parser *p) +_tmp_184_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36393,18 +36334,18 @@ _tmp_185_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_185[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -36412,18 +36353,18 @@ _tmp_185_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_185[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -36432,9 +36373,9 @@ _tmp_185_rule(Parser *p) return _res; } -// _loop0_186: lambda_param_maybe_default +// _loop0_185: lambda_param_maybe_default static asdl_seq * -_loop0_186_rule(Parser *p) +_loop0_185_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36459,7 +36400,7 @@ _loop0_186_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36482,7 +36423,7 @@ _loop0_186_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_185[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36499,9 +36440,9 @@ _loop0_186_rule(Parser *p) return _seq; } -// _loop0_187: lambda_param_no_default +// _loop0_186: lambda_param_no_default static asdl_seq * -_loop0_187_rule(Parser *p) +_loop0_186_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36526,7 +36467,7 @@ _loop0_187_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -36549,7 +36490,7 @@ _loop0_187_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36566,9 +36507,9 @@ _loop0_187_rule(Parser *p) return _seq; } -// _loop0_188: lambda_param_no_default +// _loop0_187: lambda_param_no_default static asdl_seq * -_loop0_188_rule(Parser *p) +_loop0_187_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36593,7 +36534,7 @@ _loop0_188_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -36616,7 +36557,7 @@ _loop0_188_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_188[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36633,9 +36574,9 @@ _loop0_188_rule(Parser *p) return _seq; } -// _loop0_190: ',' lambda_param +// _loop0_189: ',' lambda_param static asdl_seq * -_loop0_190_rule(Parser *p) +_loop0_189_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36660,7 +36601,7 @@ _loop0_190_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); + D(fprintf(stderr, "%*c> _loop0_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); Token * _literal; arg_ty elem; while ( @@ -36692,7 +36633,7 @@ _loop0_190_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_190[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_189[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' lambda_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36709,9 +36650,9 @@ _loop0_190_rule(Parser *p) return _seq; } -// _gather_189: lambda_param _loop0_190 +// _gather_188: lambda_param _loop0_189 static asdl_seq * -_gather_189_rule(Parser *p) +_gather_188_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36722,27 +36663,27 @@ _gather_189_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // lambda_param _loop0_190 + { // lambda_param _loop0_189 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190")); + D(fprintf(stderr, "%*c> _gather_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_189")); arg_ty elem; asdl_seq * seq; if ( (elem = lambda_param_rule(p)) // lambda_param && - (seq = _loop0_190_rule(p)) // _loop0_190 + (seq = _loop0_189_rule(p)) // _loop0_189 ) { - D(fprintf(stderr, "%*c+ _gather_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190")); + D(fprintf(stderr, "%*c+ _gather_188[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_189")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_189[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_190")); + D(fprintf(stderr, "%*c%s _gather_188[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_189")); } _res = NULL; done: @@ -36750,9 +36691,9 @@ _gather_189_rule(Parser *p) return _res; } -// _tmp_191: lambda_slash_no_default | lambda_slash_with_default +// _tmp_190: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_191_rule(Parser *p) +_tmp_190_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36768,18 +36709,18 @@ _tmp_191_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -36787,18 +36728,18 @@ _tmp_191_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -36807,9 +36748,9 @@ _tmp_191_rule(Parser *p) return _res; } -// _loop0_192: lambda_param_maybe_default +// _loop0_191: lambda_param_maybe_default static asdl_seq * -_loop0_192_rule(Parser *p) +_loop0_191_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36834,7 +36775,7 @@ _loop0_192_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36857,7 +36798,7 @@ _loop0_192_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_192[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_191[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36874,9 +36815,9 @@ _loop0_192_rule(Parser *p) return _seq; } -// _tmp_193: ',' | lambda_param_no_default +// _tmp_192: ',' | lambda_param_no_default static void * -_tmp_193_rule(Parser *p) +_tmp_192_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36892,18 +36833,18 @@ _tmp_193_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // lambda_param_no_default @@ -36911,18 +36852,18 @@ _tmp_193_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } _res = NULL; @@ -36931,9 +36872,9 @@ _tmp_193_rule(Parser *p) return _res; } -// _loop0_194: lambda_param_maybe_default +// _loop0_193: lambda_param_maybe_default static asdl_seq * -_loop0_194_rule(Parser *p) +_loop0_193_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36958,7 +36899,7 @@ _loop0_194_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36981,7 +36922,7 @@ _loop0_194_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_194[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_193[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36998,9 +36939,9 @@ _loop0_194_rule(Parser *p) return _seq; } -// _loop1_195: lambda_param_maybe_default +// _loop1_194: lambda_param_maybe_default static asdl_seq * -_loop1_195_rule(Parser *p) +_loop1_194_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37025,7 +36966,7 @@ _loop1_195_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -37048,7 +36989,7 @@ _loop1_195_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_195[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_194[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -37070,9 +37011,9 @@ _loop1_195_rule(Parser *p) return _seq; } -// _loop1_196: lambda_param_with_default +// _loop1_195: lambda_param_with_default static asdl_seq * -_loop1_196_rule(Parser *p) +_loop1_195_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37097,7 +37038,7 @@ _loop1_196_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -37120,7 +37061,7 @@ _loop1_196_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_196[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_195[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -37142,9 +37083,9 @@ _loop1_196_rule(Parser *p) return _seq; } -// _tmp_197: ':' | ',' (':' | '**') +// _tmp_196: ':' | ',' (':' | '**') static void * -_tmp_197_rule(Parser *p) +_tmp_196_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37160,18 +37101,18 @@ _tmp_197_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -37179,21 +37120,21 @@ _tmp_197_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_266_var; + void *_tmp_265_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_266_var = _tmp_266_rule(p)) // ':' | '**' + (_tmp_265_var = _tmp_265_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_266_var); + D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_265_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -37202,9 +37143,9 @@ _tmp_197_rule(Parser *p) return _res; } -// _tmp_198: lambda_param_no_default | ',' +// _tmp_197: lambda_param_no_default | ',' static void * -_tmp_198_rule(Parser *p) +_tmp_197_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37220,18 +37161,18 @@ _tmp_198_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -37239,18 +37180,18 @@ _tmp_198_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37259,9 +37200,9 @@ _tmp_198_rule(Parser *p) return _res; } -// _loop0_199: lambda_param_maybe_default +// _loop0_198: lambda_param_maybe_default static asdl_seq * -_loop0_199_rule(Parser *p) +_loop0_198_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37286,7 +37227,7 @@ _loop0_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -37309,7 +37250,7 @@ _loop0_199_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_198[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37326,9 +37267,9 @@ _loop0_199_rule(Parser *p) return _seq; } -// _tmp_200: lambda_param_no_default | ',' +// _tmp_199: lambda_param_no_default | ',' static void * -_tmp_200_rule(Parser *p) +_tmp_199_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37344,18 +37285,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -37363,18 +37304,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37383,9 +37324,9 @@ _tmp_200_rule(Parser *p) return _res; } -// _tmp_201: '*' | '**' | '/' +// _tmp_200: '*' | '**' | '/' static void * -_tmp_201_rule(Parser *p) +_tmp_200_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37401,18 +37342,18 @@ _tmp_201_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -37420,18 +37361,18 @@ _tmp_201_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -37439,18 +37380,18 @@ _tmp_201_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -37459,9 +37400,9 @@ _tmp_201_rule(Parser *p) return _res; } -// _tmp_202: ',' | ')' | ':' +// _tmp_201: ',' | ')' | ':' static void * -_tmp_202_rule(Parser *p) +_tmp_201_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37477,18 +37418,18 @@ _tmp_202_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -37496,18 +37437,18 @@ _tmp_202_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -37515,18 +37456,18 @@ _tmp_202_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -37535,9 +37476,9 @@ _tmp_202_rule(Parser *p) return _res; } -// _loop0_204: ',' dotted_name +// _loop0_203: ',' dotted_name static asdl_seq * -_loop0_204_rule(Parser *p) +_loop0_203_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37562,7 +37503,7 @@ _loop0_204_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); + D(fprintf(stderr, "%*c> _loop0_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); Token * _literal; expr_ty elem; while ( @@ -37594,7 +37535,7 @@ _loop0_204_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_204[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_203[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37611,9 +37552,9 @@ _loop0_204_rule(Parser *p) return _seq; } -// _gather_203: dotted_name _loop0_204 +// _gather_202: dotted_name _loop0_203 static asdl_seq * -_gather_203_rule(Parser *p) +_gather_202_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37624,27 +37565,27 @@ _gather_203_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // dotted_name _loop0_204 + { // dotted_name _loop0_203 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); + D(fprintf(stderr, "%*c> _gather_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_203")); expr_ty elem; asdl_seq * seq; if ( (elem = dotted_name_rule(p)) // dotted_name && - (seq = _loop0_204_rule(p)) // _loop0_204 + (seq = _loop0_203_rule(p)) // _loop0_203 ) { - D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); + D(fprintf(stderr, "%*c+ _gather_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_203")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_204")); + D(fprintf(stderr, "%*c%s _gather_202[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_203")); } _res = NULL; done: @@ -37652,9 +37593,9 @@ _gather_203_rule(Parser *p) return _res; } -// _loop0_206: ',' (expression ['as' star_target]) +// _loop0_205: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_206_rule(Parser *p) +_loop0_205_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37679,13 +37620,13 @@ _loop0_206_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_267_rule(p)) // expression ['as' star_target] + (elem = _tmp_266_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37711,7 +37652,7 @@ _loop0_206_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_206[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_205[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37728,9 +37669,9 @@ _loop0_206_rule(Parser *p) return _seq; } -// _gather_205: (expression ['as' star_target]) _loop0_206 +// _gather_204: (expression ['as' star_target]) _loop0_205 static asdl_seq * -_gather_205_rule(Parser *p) +_gather_204_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37741,27 +37682,27 @@ _gather_205_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_206 + { // (expression ['as' star_target]) _loop0_205 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c> _gather_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_205")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_267_rule(p)) // expression ['as' star_target] + (elem = _tmp_266_rule(p)) // expression ['as' star_target] && - (seq = _loop0_206_rule(p)) // _loop0_206 + (seq = _loop0_205_rule(p)) // _loop0_205 ) { - D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c+ _gather_204[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_205")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c%s _gather_204[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_205")); } _res = NULL; done: @@ -37769,9 +37710,9 @@ _gather_205_rule(Parser *p) return _res; } -// _loop0_208: ',' (expressions ['as' star_target]) +// _loop0_207: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_208_rule(Parser *p) +_loop0_207_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37796,13 +37737,13 @@ _loop0_208_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_268_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -37828,7 +37769,7 @@ _loop0_208_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_207[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37845,9 +37786,9 @@ _loop0_208_rule(Parser *p) return _seq; } -// _gather_207: (expressions ['as' star_target]) _loop0_208 +// _gather_206: (expressions ['as' star_target]) _loop0_207 static asdl_seq * -_gather_207_rule(Parser *p) +_gather_206_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37858,27 +37799,27 @@ _gather_207_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_208 + { // (expressions ['as' star_target]) _loop0_207 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c> _gather_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_207")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_268_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_208_rule(p)) // _loop0_208 + (seq = _loop0_207_rule(p)) // _loop0_207 ) { - D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c+ _gather_206[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_207")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c%s _gather_206[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_207")); } _res = NULL; done: @@ -37886,9 +37827,9 @@ _gather_207_rule(Parser *p) return _res; } -// _loop0_210: ',' (expression ['as' star_target]) +// _loop0_209: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_210_rule(Parser *p) +_loop0_209_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37913,13 +37854,13 @@ _loop0_210_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_269_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37945,7 +37886,7 @@ _loop0_210_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_209[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37962,9 +37903,9 @@ _loop0_210_rule(Parser *p) return _seq; } -// _gather_209: (expression ['as' star_target]) _loop0_210 +// _gather_208: (expression ['as' star_target]) _loop0_209 static asdl_seq * -_gather_209_rule(Parser *p) +_gather_208_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37975,27 +37916,27 @@ _gather_209_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_210 + { // (expression ['as' star_target]) _loop0_209 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); + D(fprintf(stderr, "%*c> _gather_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_209")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_269_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expression ['as' star_target] && - (seq = _loop0_210_rule(p)) // _loop0_210 + (seq = _loop0_209_rule(p)) // _loop0_209 ) { - D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); + D(fprintf(stderr, "%*c+ _gather_208[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_209")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_209[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); + D(fprintf(stderr, "%*c%s _gather_208[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_209")); } _res = NULL; done: @@ -38003,9 +37944,9 @@ _gather_209_rule(Parser *p) return _res; } -// _loop0_212: ',' (expressions ['as' star_target]) +// _loop0_211: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_212_rule(Parser *p) +_loop0_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38030,13 +37971,13 @@ _loop0_212_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_270_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -38062,7 +38003,7 @@ _loop0_212_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_212[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_211[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38079,9 +38020,9 @@ _loop0_212_rule(Parser *p) return _seq; } -// _gather_211: (expressions ['as' star_target]) _loop0_212 +// _gather_210: (expressions ['as' star_target]) _loop0_211 static asdl_seq * -_gather_211_rule(Parser *p) +_gather_210_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38092,27 +38033,27 @@ _gather_211_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_212 + { // (expressions ['as' star_target]) _loop0_211 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); + D(fprintf(stderr, "%*c> _gather_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_211")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_270_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_212_rule(p)) // _loop0_212 + (seq = _loop0_211_rule(p)) // _loop0_211 ) { - D(fprintf(stderr, "%*c+ _gather_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); + D(fprintf(stderr, "%*c+ _gather_210[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_211")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_211[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); + D(fprintf(stderr, "%*c%s _gather_210[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_211")); } _res = NULL; done: @@ -38120,9 +38061,9 @@ _gather_211_rule(Parser *p) return _res; } -// _tmp_213: 'except' | 'finally' +// _tmp_212: 'except' | 'finally' static void * -_tmp_213_rule(Parser *p) +_tmp_212_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38138,18 +38079,18 @@ _tmp_213_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 637)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); } { // 'finally' @@ -38157,18 +38098,18 @@ _tmp_213_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' ) { - D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; @@ -38177,9 +38118,9 @@ _tmp_213_rule(Parser *p) return _res; } -// _loop0_214: block +// _loop0_213: block static asdl_seq * -_loop0_214_rule(Parser *p) +_loop0_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38204,7 +38145,7 @@ _loop0_214_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38227,7 +38168,7 @@ _loop0_214_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_214[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_213[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38244,9 +38185,9 @@ _loop0_214_rule(Parser *p) return _seq; } -// _loop1_215: except_block +// _loop1_214: except_block static asdl_seq * -_loop1_215_rule(Parser *p) +_loop1_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38271,7 +38212,7 @@ _loop1_215_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); excepthandler_ty except_block_var; while ( (except_block_var = except_block_rule(p)) // except_block @@ -38294,7 +38235,7 @@ _loop1_215_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_215[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_214[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -38316,9 +38257,9 @@ _loop1_215_rule(Parser *p) return _seq; } -// _tmp_216: 'as' NAME +// _tmp_215: 'as' NAME static void * -_tmp_216_rule(Parser *p) +_tmp_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38334,7 +38275,7 @@ _tmp_216_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38343,12 +38284,12 @@ _tmp_216_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_215[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38357,9 +38298,9 @@ _tmp_216_rule(Parser *p) return _res; } -// _loop0_217: block +// _loop0_216: block static asdl_seq * -_loop0_217_rule(Parser *p) +_loop0_216_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38384,7 +38325,7 @@ _loop0_217_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38407,7 +38348,7 @@ _loop0_217_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_217[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_216[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38424,9 +38365,9 @@ _loop0_217_rule(Parser *p) return _seq; } -// _loop1_218: except_star_block +// _loop1_217: except_star_block static asdl_seq * -_loop1_218_rule(Parser *p) +_loop1_217_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38451,7 +38392,7 @@ _loop1_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); excepthandler_ty except_star_block_var; while ( (except_star_block_var = except_star_block_rule(p)) // except_star_block @@ -38474,7 +38415,7 @@ _loop1_218_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_218[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_217[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -38496,9 +38437,9 @@ _loop1_218_rule(Parser *p) return _seq; } -// _tmp_219: expression ['as' NAME] +// _tmp_218: expression ['as' NAME] static void * -_tmp_219_rule(Parser *p) +_tmp_218_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38514,22 +38455,22 @@ _tmp_219_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_270_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -38538,9 +38479,9 @@ _tmp_219_rule(Parser *p) return _res; } -// _tmp_220: 'as' NAME +// _tmp_219: 'as' NAME static void * -_tmp_220_rule(Parser *p) +_tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38556,7 +38497,7 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38565,12 +38506,12 @@ _tmp_220_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38579,9 +38520,9 @@ _tmp_220_rule(Parser *p) return _res; } -// _tmp_221: 'as' NAME +// _tmp_220: 'as' NAME static void * -_tmp_221_rule(Parser *p) +_tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38597,7 +38538,7 @@ _tmp_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38606,12 +38547,12 @@ _tmp_221_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38620,9 +38561,9 @@ _tmp_221_rule(Parser *p) return _res; } -// _tmp_222: NEWLINE | ':' +// _tmp_221: NEWLINE | ':' static void * -_tmp_222_rule(Parser *p) +_tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38638,18 +38579,18 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -38657,18 +38598,18 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -38677,9 +38618,9 @@ _tmp_222_rule(Parser *p) return _res; } -// _tmp_223: 'as' NAME +// _tmp_222: 'as' NAME static void * -_tmp_223_rule(Parser *p) +_tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38695,7 +38636,7 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38704,12 +38645,12 @@ _tmp_223_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38718,9 +38659,9 @@ _tmp_223_rule(Parser *p) return _res; } -// _tmp_224: 'as' NAME +// _tmp_223: 'as' NAME static void * -_tmp_224_rule(Parser *p) +_tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38736,7 +38677,7 @@ _tmp_224_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38745,12 +38686,12 @@ _tmp_224_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38759,9 +38700,9 @@ _tmp_224_rule(Parser *p) return _res; } -// _tmp_225: positional_patterns ',' +// _tmp_224: positional_patterns ',' static void * -_tmp_225_rule(Parser *p) +_tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38777,7 +38718,7 @@ _tmp_225_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -38786,12 +38727,12 @@ _tmp_225_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -38800,9 +38741,9 @@ _tmp_225_rule(Parser *p) return _res; } -// _tmp_226: '->' expression +// _tmp_225: '->' expression static void * -_tmp_226_rule(Parser *p) +_tmp_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38818,7 +38759,7 @@ _tmp_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty expression_var; if ( @@ -38827,12 +38768,12 @@ _tmp_226_rule(Parser *p) (expression_var = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = _PyPegen_dummy_name(p, _literal, expression_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -38841,9 +38782,9 @@ _tmp_226_rule(Parser *p) return _res; } -// _tmp_227: '(' arguments? ')' +// _tmp_226: '(' arguments? ')' static void * -_tmp_227_rule(Parser *p) +_tmp_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38859,7 +38800,7 @@ _tmp_227_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38872,12 +38813,12 @@ _tmp_227_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38886,9 +38827,9 @@ _tmp_227_rule(Parser *p) return _res; } -// _tmp_228: '(' arguments? ')' +// _tmp_227: '(' arguments? ')' static void * -_tmp_228_rule(Parser *p) +_tmp_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38904,7 +38845,7 @@ _tmp_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38917,12 +38858,12 @@ _tmp_228_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38931,9 +38872,9 @@ _tmp_228_rule(Parser *p) return _res; } -// _loop0_230: ',' double_starred_kvpair +// _loop0_229: ',' double_starred_kvpair static asdl_seq * -_loop0_230_rule(Parser *p) +_loop0_229_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38958,7 +38899,7 @@ _loop0_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -38990,7 +38931,7 @@ _loop0_230_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_229[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -39007,9 +38948,9 @@ _loop0_230_rule(Parser *p) return _seq; } -// _gather_229: double_starred_kvpair _loop0_230 +// _gather_228: double_starred_kvpair _loop0_229 static asdl_seq * -_gather_229_rule(Parser *p) +_gather_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39020,27 +38961,27 @@ _gather_229_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_230 + { // double_starred_kvpair _loop0_229 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); + D(fprintf(stderr, "%*c> _gather_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_229")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_230_rule(p)) // _loop0_230 + (seq = _loop0_229_rule(p)) // _loop0_229 ) { - D(fprintf(stderr, "%*c+ _gather_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); + D(fprintf(stderr, "%*c+ _gather_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_229")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_229[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_230")); + D(fprintf(stderr, "%*c%s _gather_228[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_229")); } _res = NULL; done: @@ -39048,9 +38989,9 @@ _gather_229_rule(Parser *p) return _res; } -// _tmp_231: '}' | ',' +// _tmp_230: '}' | ',' static void * -_tmp_231_rule(Parser *p) +_tmp_230_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39066,18 +39007,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -39085,18 +39026,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -39105,9 +39046,9 @@ _tmp_231_rule(Parser *p) return _res; } -// _tmp_232: '}' | ',' +// _tmp_231: '}' | ',' static void * -_tmp_232_rule(Parser *p) +_tmp_231_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39123,18 +39064,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -39142,18 +39083,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -39162,9 +39103,9 @@ _tmp_232_rule(Parser *p) return _res; } -// _tmp_233: yield_expr | star_expressions +// _tmp_232: yield_expr | star_expressions static void * -_tmp_233_rule(Parser *p) +_tmp_232_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39180,18 +39121,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39199,18 +39140,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39219,9 +39160,9 @@ _tmp_233_rule(Parser *p) return _res; } -// _tmp_234: yield_expr | star_expressions +// _tmp_233: yield_expr | star_expressions static void * -_tmp_234_rule(Parser *p) +_tmp_233_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39237,18 +39178,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39256,18 +39197,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39276,9 +39217,9 @@ _tmp_234_rule(Parser *p) return _res; } -// _tmp_235: '=' | '!' | ':' | '}' +// _tmp_234: '=' | '!' | ':' | '}' static void * -_tmp_235_rule(Parser *p) +_tmp_234_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39294,18 +39235,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // '!' @@ -39313,18 +39254,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39332,18 +39273,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39351,18 +39292,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39371,9 +39312,9 @@ _tmp_235_rule(Parser *p) return _res; } -// _tmp_236: yield_expr | star_expressions +// _tmp_235: yield_expr | star_expressions static void * -_tmp_236_rule(Parser *p) +_tmp_235_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39389,18 +39330,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39408,18 +39349,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39428,9 +39369,9 @@ _tmp_236_rule(Parser *p) return _res; } -// _tmp_237: '!' | ':' | '}' +// _tmp_236: '!' | ':' | '}' static void * -_tmp_237_rule(Parser *p) +_tmp_236_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39446,18 +39387,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39465,18 +39406,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39484,18 +39425,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39504,9 +39445,9 @@ _tmp_237_rule(Parser *p) return _res; } -// _tmp_238: yield_expr | star_expressions +// _tmp_237: yield_expr | star_expressions static void * -_tmp_238_rule(Parser *p) +_tmp_237_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39522,18 +39463,18 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39541,18 +39482,18 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39561,9 +39502,9 @@ _tmp_238_rule(Parser *p) return _res; } -// _tmp_239: yield_expr | star_expressions +// _tmp_238: yield_expr | star_expressions static void * -_tmp_239_rule(Parser *p) +_tmp_238_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39579,18 +39520,18 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39598,18 +39539,18 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39618,9 +39559,9 @@ _tmp_239_rule(Parser *p) return _res; } -// _tmp_240: '!' NAME +// _tmp_239: '!' NAME static void * -_tmp_240_rule(Parser *p) +_tmp_239_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39636,7 +39577,7 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39645,12 +39586,12 @@ _tmp_240_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39659,9 +39600,9 @@ _tmp_240_rule(Parser *p) return _res; } -// _tmp_241: ':' | '}' +// _tmp_240: ':' | '}' static void * -_tmp_241_rule(Parser *p) +_tmp_240_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39677,18 +39618,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39696,18 +39637,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39716,9 +39657,9 @@ _tmp_241_rule(Parser *p) return _res; } -// _tmp_242: yield_expr | star_expressions +// _tmp_241: yield_expr | star_expressions static void * -_tmp_242_rule(Parser *p) +_tmp_241_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39734,18 +39675,18 @@ _tmp_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39753,18 +39694,18 @@ _tmp_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39773,9 +39714,9 @@ _tmp_242_rule(Parser *p) return _res; } -// _tmp_243: '!' NAME +// _tmp_242: '!' NAME static void * -_tmp_243_rule(Parser *p) +_tmp_242_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39791,7 +39732,7 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39800,12 +39741,12 @@ _tmp_243_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39814,9 +39755,9 @@ _tmp_243_rule(Parser *p) return _res; } -// _loop0_244: fstring_format_spec +// _loop0_243: fstring_format_spec static asdl_seq * -_loop0_244_rule(Parser *p) +_loop0_243_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39841,7 +39782,7 @@ _loop0_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -39864,7 +39805,7 @@ _loop0_244_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_244[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_243[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -39881,9 +39822,9 @@ _loop0_244_rule(Parser *p) return _seq; } -// _tmp_245: yield_expr | star_expressions +// _tmp_244: yield_expr | star_expressions static void * -_tmp_245_rule(Parser *p) +_tmp_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39899,18 +39840,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39918,18 +39859,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39938,9 +39879,9 @@ _tmp_245_rule(Parser *p) return _res; } -// _tmp_246: '!' NAME +// _tmp_245: '!' NAME static void * -_tmp_246_rule(Parser *p) +_tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39956,7 +39897,7 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39965,12 +39906,12 @@ _tmp_246_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39979,9 +39920,9 @@ _tmp_246_rule(Parser *p) return _res; } -// _tmp_247: ':' | '}' +// _tmp_246: ':' | '}' static void * -_tmp_247_rule(Parser *p) +_tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39997,18 +39938,18 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -40016,18 +39957,18 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -40036,9 +39977,9 @@ _tmp_247_rule(Parser *p) return _res; } -// _tmp_248: star_targets '=' +// _tmp_247: star_targets '=' static void * -_tmp_248_rule(Parser *p) +_tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40054,7 +39995,7 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -40063,7 +40004,7 @@ _tmp_248_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40073,7 +40014,7 @@ _tmp_248_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40082,9 +40023,9 @@ _tmp_248_rule(Parser *p) return _res; } -// _tmp_249: '.' | '...' +// _tmp_248: '.' | '...' static void * -_tmp_249_rule(Parser *p) +_tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40100,18 +40041,18 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40119,18 +40060,18 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40139,9 +40080,9 @@ _tmp_249_rule(Parser *p) return _res; } -// _tmp_250: '.' | '...' +// _tmp_249: '.' | '...' static void * -_tmp_250_rule(Parser *p) +_tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40157,18 +40098,18 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40176,18 +40117,18 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40196,9 +40137,9 @@ _tmp_250_rule(Parser *p) return _res; } -// _tmp_251: '@' named_expression NEWLINE +// _tmp_250: '@' named_expression NEWLINE static void * -_tmp_251_rule(Parser *p) +_tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40214,7 +40155,7 @@ _tmp_251_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -40226,7 +40167,7 @@ _tmp_251_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40236,7 +40177,7 @@ _tmp_251_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -40245,9 +40186,9 @@ _tmp_251_rule(Parser *p) return _res; } -// _tmp_252: ',' expression +// _tmp_251: ',' expression static void * -_tmp_252_rule(Parser *p) +_tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40263,7 +40204,7 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -40272,7 +40213,7 @@ _tmp_252_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40282,7 +40223,7 @@ _tmp_252_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -40291,9 +40232,9 @@ _tmp_252_rule(Parser *p) return _res; } -// _tmp_253: ',' star_expression +// _tmp_252: ',' star_expression static void * -_tmp_253_rule(Parser *p) +_tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40309,7 +40250,7 @@ _tmp_253_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -40318,7 +40259,7 @@ _tmp_253_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40328,7 +40269,7 @@ _tmp_253_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -40337,9 +40278,9 @@ _tmp_253_rule(Parser *p) return _res; } -// _tmp_254: 'or' conjunction +// _tmp_253: 'or' conjunction static void * -_tmp_254_rule(Parser *p) +_tmp_253_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40355,7 +40296,7 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -40364,7 +40305,7 @@ _tmp_254_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40374,7 +40315,7 @@ _tmp_254_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -40383,9 +40324,9 @@ _tmp_254_rule(Parser *p) return _res; } -// _tmp_255: 'and' inversion +// _tmp_254: 'and' inversion static void * -_tmp_255_rule(Parser *p) +_tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40401,7 +40342,7 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -40410,7 +40351,7 @@ _tmp_255_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40420,7 +40361,7 @@ _tmp_255_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -40429,9 +40370,9 @@ _tmp_255_rule(Parser *p) return _res; } -// _tmp_256: slice | starred_expression +// _tmp_255: slice | starred_expression static void * -_tmp_256_rule(Parser *p) +_tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40447,18 +40388,18 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -40466,18 +40407,18 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -40486,9 +40427,9 @@ _tmp_256_rule(Parser *p) return _res; } -// _tmp_257: fstring | string +// _tmp_256: fstring | string static void * -_tmp_257_rule(Parser *p) +_tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40504,18 +40445,18 @@ _tmp_257_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -40523,18 +40464,18 @@ _tmp_257_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -40543,9 +40484,9 @@ _tmp_257_rule(Parser *p) return _res; } -// _tmp_258: 'if' disjunction +// _tmp_257: 'if' disjunction static void * -_tmp_258_rule(Parser *p) +_tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40561,7 +40502,7 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40570,7 +40511,7 @@ _tmp_258_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40580,7 +40521,7 @@ _tmp_258_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40589,9 +40530,9 @@ _tmp_258_rule(Parser *p) return _res; } -// _tmp_259: 'if' disjunction +// _tmp_258: 'if' disjunction static void * -_tmp_259_rule(Parser *p) +_tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40607,7 +40548,7 @@ _tmp_259_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40616,7 +40557,7 @@ _tmp_259_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40626,7 +40567,7 @@ _tmp_259_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40635,9 +40576,9 @@ _tmp_259_rule(Parser *p) return _res; } -// _tmp_260: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_259: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_260_rule(Parser *p) +_tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40653,18 +40594,18 @@ _tmp_260_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -40672,20 +40613,20 @@ _tmp_260_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_272_var; + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_271_var; if ( - (_tmp_272_var = _tmp_272_rule(p)) // assignment_expression | expression !':=' + (_tmp_271_var = _tmp_271_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_272_var; + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_271_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -40694,9 +40635,9 @@ _tmp_260_rule(Parser *p) return _res; } -// _tmp_261: ',' star_target +// _tmp_260: ',' star_target static void * -_tmp_261_rule(Parser *p) +_tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40712,7 +40653,7 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40721,7 +40662,7 @@ _tmp_261_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40731,7 +40672,7 @@ _tmp_261_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -40740,9 +40681,9 @@ _tmp_261_rule(Parser *p) return _res; } -// _tmp_262: ',' star_target +// _tmp_261: ',' star_target static void * -_tmp_262_rule(Parser *p) +_tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40758,7 +40699,7 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40767,7 +40708,7 @@ _tmp_262_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40777,7 +40718,7 @@ _tmp_262_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -40786,9 +40727,9 @@ _tmp_262_rule(Parser *p) return _res; } -// _tmp_263: star_targets '=' +// _tmp_262: star_targets '=' static void * -_tmp_263_rule(Parser *p) +_tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40804,7 +40745,7 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40813,12 +40754,12 @@ _tmp_263_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40827,9 +40768,9 @@ _tmp_263_rule(Parser *p) return _res; } -// _tmp_264: star_targets '=' +// _tmp_263: star_targets '=' static void * -_tmp_264_rule(Parser *p) +_tmp_263_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40845,7 +40786,7 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40854,12 +40795,12 @@ _tmp_264_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40868,9 +40809,9 @@ _tmp_264_rule(Parser *p) return _res; } -// _tmp_265: ')' | '**' +// _tmp_264: ')' | '**' static void * -_tmp_265_rule(Parser *p) +_tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40886,18 +40827,18 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -40905,18 +40846,18 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -40925,9 +40866,9 @@ _tmp_265_rule(Parser *p) return _res; } -// _tmp_266: ':' | '**' +// _tmp_265: ':' | '**' static void * -_tmp_266_rule(Parser *p) +_tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40943,18 +40884,18 @@ _tmp_266_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -40962,18 +40903,18 @@ _tmp_266_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -40982,9 +40923,9 @@ _tmp_266_rule(Parser *p) return _res; } -// _tmp_267: expression ['as' star_target] +// _tmp_266: expression ['as' star_target] static void * -_tmp_267_rule(Parser *p) +_tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41000,22 +40941,22 @@ _tmp_267_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -41024,9 +40965,9 @@ _tmp_267_rule(Parser *p) return _res; } -// _tmp_268: expressions ['as' star_target] +// _tmp_267: expressions ['as' star_target] static void * -_tmp_268_rule(Parser *p) +_tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41042,22 +40983,22 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41066,9 +41007,9 @@ _tmp_268_rule(Parser *p) return _res; } -// _tmp_269: expression ['as' star_target] +// _tmp_268: expression ['as' star_target] static void * -_tmp_269_rule(Parser *p) +_tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41084,22 +41025,22 @@ _tmp_269_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_275_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -41108,9 +41049,9 @@ _tmp_269_rule(Parser *p) return _res; } -// _tmp_270: expressions ['as' star_target] +// _tmp_269: expressions ['as' star_target] static void * -_tmp_270_rule(Parser *p) +_tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41126,22 +41067,22 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_276_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_275_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41150,9 +41091,9 @@ _tmp_270_rule(Parser *p) return _res; } -// _tmp_271: 'as' NAME +// _tmp_270: 'as' NAME static void * -_tmp_271_rule(Parser *p) +_tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41168,7 +41109,7 @@ _tmp_271_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -41177,12 +41118,12 @@ _tmp_271_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -41191,9 +41132,9 @@ _tmp_271_rule(Parser *p) return _res; } -// _tmp_272: assignment_expression | expression !':=' +// _tmp_271: assignment_expression | expression !':=' static void * -_tmp_272_rule(Parser *p) +_tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41209,18 +41150,18 @@ _tmp_272_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -41228,7 +41169,7 @@ _tmp_272_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -41236,12 +41177,12 @@ _tmp_272_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -41250,9 +41191,9 @@ _tmp_272_rule(Parser *p) return _res; } -// _tmp_273: 'as' star_target +// _tmp_272: 'as' star_target static void * -_tmp_273_rule(Parser *p) +_tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41268,7 +41209,7 @@ _tmp_273_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41277,12 +41218,12 @@ _tmp_273_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41291,9 +41232,9 @@ _tmp_273_rule(Parser *p) return _res; } -// _tmp_274: 'as' star_target +// _tmp_273: 'as' star_target static void * -_tmp_274_rule(Parser *p) +_tmp_273_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41309,7 +41250,7 @@ _tmp_274_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41318,12 +41259,12 @@ _tmp_274_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41332,9 +41273,9 @@ _tmp_274_rule(Parser *p) return _res; } -// _tmp_275: 'as' star_target +// _tmp_274: 'as' star_target static void * -_tmp_275_rule(Parser *p) +_tmp_274_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41350,7 +41291,7 @@ _tmp_275_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_275[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41359,12 +41300,12 @@ _tmp_275_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_275[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_275[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41373,9 +41314,9 @@ _tmp_275_rule(Parser *p) return _res; } -// _tmp_276: 'as' star_target +// _tmp_275: 'as' star_target static void * -_tmp_276_rule(Parser *p) +_tmp_275_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41391,7 +41332,7 @@ _tmp_276_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_276[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_275[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41400,12 +41341,12 @@ _tmp_276_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_276[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_275[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_276[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_275[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; From 08bd2aa79381eca34bcec9e6307d08ec1104ed0c Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:35:26 +0100 Subject: [PATCH 0755/1206] [3.12] gh-109184: update traceback module doc w.r.t notes (message is no longer always at the end) (#109201) (#109334) gh-109184: update traceback module doc w.r.t notes (message is no longer always at the end) (#109201) (cherry picked from commit 0e76cc359ba5d5e29d7c75355d7c1bc7e817eecf) --- Doc/library/traceback.rst | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 36171a3b5a610d..55ac361b1903a2 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -139,11 +139,11 @@ The module defines the following functions: Format the exception part of a traceback using an exception value such as given by ``sys.last_value``. The return value is a list of strings, each - ending in a newline. Normally, the list contains a single string; however, - for :exc:`SyntaxError` exceptions, it contains several lines that (when - printed) display detailed information about where the syntax error occurred. - The message indicating which exception occurred is the always last string in - the list. + ending in a newline. The list contains the exception's message, which is + normally a single string; however, for :exc:`SyntaxError` exceptions, it + contains several lines that (when printed) display detailed information + about where the syntax error occurred. Following the message, the list + contains the exception's :attr:`notes `. Since Python 3.10, instead of passing *value*, an exception object can be passed as the first argument. If *value* is provided, the first @@ -153,6 +153,9 @@ The module defines the following functions: The *etype* parameter has been renamed to *exc* and is now positional-only. + .. versionchanged:: 3.11 + The returned list now includes any notes attached to the exception. + .. function:: format_exception(exc, /[, value, tb], limit=None, chain=True) @@ -235,6 +238,12 @@ capture data for later printing in a lightweight fashion. group's exceptions array. The formatted output is truncated when either limit is exceeded. + .. versionchanged:: 3.10 + Added the *compact* parameter. + + .. versionchanged:: 3.11 + Added the *max_group_width* and *max_group_depth* parameters. + .. attribute:: __cause__ A :class:`TracebackException` of the original ``__cause__``. @@ -330,28 +339,21 @@ capture data for later printing in a lightweight fashion. some containing internal newlines. :func:`~traceback.print_exception` is a wrapper around this method which just prints the lines to a file. - The message indicating which exception occurred is always the last - string in the output. - .. method:: format_exception_only() Format the exception part of the traceback. The return value is a generator of strings, each ending in a newline. - Normally, the generator emits a single string; however, for - :exc:`SyntaxError` exceptions, it emits several lines that (when - printed) display detailed information about where the syntax - error occurred. + The generator emits the exception's message followed by its notes + (if it has any). The exception message is normally a single string; + however, for :exc:`SyntaxError` exceptions, it consists of several + lines that (when printed) display detailed information about where + the syntax error occurred. - The message indicating which exception occurred is always the last - string in the output. + .. versionchanged:: 3.11 + The exception's notes are now included in the output. - .. versionchanged:: 3.10 - Added the *compact* parameter. - - .. versionchanged:: 3.11 - Added the *max_group_width* and *max_group_depth* parameters. :class:`StackSummary` Objects From 9b8205447f977124dcc41f7d5b0a1bf44e9b8591 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 Sep 2023 03:35:42 -0700 Subject: [PATCH 0756/1206] [3.12] GH-104395: Add a link in 'Meta Information' to the docs download page (GH-104443) (#109345) GH-104395: Add a link in 'Meta Information' to the docs download page (GH-104443) (cherry picked from commit 90cf345ed42ae4d17d2a073718985eb3432a7c20) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/tools/templates/indexcontent.html | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/tools/templates/indexcontent.html b/Doc/tools/templates/indexcontent.html index a96746b69fd41b..1e3ab7cfe02fee 100644 --- a/Doc/tools/templates/indexcontent.html +++ b/Doc/tools/templates/indexcontent.html @@ -62,6 +62,7 @@

{{ docstitle|e }}

+ {% endblock %} From aee0077e7bed04c9359e0efde0947e6067a412c5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 Sep 2023 03:36:03 -0700 Subject: [PATCH 0757/1206] [3.12] Update workflow permissions in require-pr-label Action (GH-109342) (#109348) Update workflow permissions in require-pr-label Action (GH-109342) Change the permission from `read` to `write`. (cherry picked from commit 44c8699196c1951037bc549c895ea5af26c7254e) Co-authored-by: Mariatta --- .github/workflows/require-pr-label.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml index 88aaea039f04f4..6efd31162ebab6 100644 --- a/.github/workflows/require-pr-label.yml +++ b/.github/workflows/require-pr-label.yml @@ -5,8 +5,8 @@ on: types: [opened, reopened, labeled, unlabeled, synchronize] permissions: - issues: read - pull-requests: read + issues: write + pull-requests: write jobs: label: From 3d8e4d7d0c674753c45e216f5bd011ed3274dc20 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 Sep 2023 03:36:30 -0700 Subject: [PATCH 0758/1206] [3.12] gh-109357: Fix test_monitoring.test_gh108976() (GH-109358) (#109359) gh-109357: Fix test_monitoring.test_gh108976() (GH-109358) The test now calls free_tool_id() so it can be run multiple times in the same process. For example, the following command no longer fails: python -m test test_monitoring -R 3:3 (cherry picked from commit 388d91cd474de80355f5a8f6a26e8962813a3128) Co-authored-by: Victor Stinner --- Lib/test/test_monitoring.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 2e4ec244ce6f17..d091572b0880d6 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1721,6 +1721,7 @@ def make_foo_optimized_then_set_event(): def test_gh108976(self): sys.monitoring.use_tool_id(0, "test") + self.addCleanup(sys.monitoring.free_tool_id, 0) sys.monitoring.set_events(0, 0) sys.monitoring.register_callback(0, E.LINE, lambda *args: sys.monitoring.set_events(0, 0)) sys.monitoring.register_callback(0, E.INSTRUCTION, lambda *args: 0) From c30d5df74cee5c2273ed219d3ad28d8b3f6298b4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 Sep 2023 03:37:10 -0700 Subject: [PATCH 0759/1206] [3.12] gh-104736: Fix test_gdb tests on ppc64le with clang (GH-109360) (#109361) gh-104736: Fix test_gdb tests on ppc64le with clang (GH-109360) Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora 38). Search patterns in gdb "bt" command output to detect when gdb fails to retrieve the traceback. For example, skip a test if "Backtrace stopped: frame did not save the PC" is found. (cherry picked from commit 44d9a71ea246e7c3fb478d9be62c16914be6c545) Co-authored-by: Victor Stinner --- Lib/test/test_gdb.py | 8 ++++++++ .../Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst | 4 ++++ 2 files changed, 12 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index fa56761043f8af..b99e0abaa5b151 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -246,6 +246,14 @@ def get_stack_trace(self, source=None, script=None, # gh-91960: On Python built with "clang -Og", gdb gets # "frame=" for _PyEval_EvalFrameDefault() parameter '(unable to read python frame information)', + # gh-104736: On Python built with "clang -Og" on ppc64le, + # "py-bt" displays a truncated or not traceback, but "where" + # logs this error message: + 'Backtrace stopped: frame did not save the PC', + # gh-104736: When "bt" command displays something like: + # "#1 0x0000000000000000 in ?? ()", the traceback is likely + # truncated or wrong. + ' ?? ()', ): if pattern in out: raise unittest.SkipTest(f"{pattern!r} found in gdb output") diff --git a/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst b/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst new file mode 100644 index 00000000000000..85c370fc87ac41 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst @@ -0,0 +1,4 @@ +Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora +38). Search patterns in gdb "bt" command output to detect when gdb fails to +retrieve the traceback. For example, skip a test if ``Backtrace stopped: frame +did not save the PC`` is found. Patch by Victor Stinner. From 47402e235d5c03054105a6c7be07c97be3102b77 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 Sep 2023 03:37:24 -0700 Subject: [PATCH 0760/1206] [3.12] gh-105189: fix importlib.resources.abc deprecation docs (GH-105232) (#109363) gh-105189: fix importlib.resources.abc deprecation docs (GH-105232) (cherry picked from commit 6c0ddca409c1ed27b11c70386cd6c88be5d00115) Co-authored-by: Thomas Grainger Co-authored-by: Hugo van Kemenade Co-authored-by: Alex Waygood --- Doc/library/importlib.resources.abc.rst | 12 -- Doc/library/importlib.rst | 154 ++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 12 deletions(-) diff --git a/Doc/library/importlib.resources.abc.rst b/Doc/library/importlib.resources.abc.rst index 65c42858bbbb7d..c508b6ba965cc0 100644 --- a/Doc/library/importlib.resources.abc.rst +++ b/Doc/library/importlib.resources.abc.rst @@ -43,8 +43,6 @@ :const:`None`. An object compatible with this ABC should only be returned when the specified module is a package. - .. versionadded:: 3.7 - .. deprecated-removed:: 3.12 3.14 Use :class:`importlib.resources.abc.TraversableResources` instead. @@ -95,11 +93,6 @@ For a representation of the object on the file-system, use :meth:`importlib.resources.as_file`. - .. versionadded:: 3.9 - - .. deprecated-removed:: 3.12 3.14 - Use :class:`importlib.resources.abc.Traversable` instead. - .. attribute:: name Abstract. The base name of this object without any parent references. @@ -153,11 +146,6 @@ Loaders that wish to support resource reading are expected to implement this interface. - .. versionadded:: 3.9 - - .. deprecated-removed:: 3.12 3.14 - Use :class:`importlib.resources.abc.TraversableResources` instead. - .. abstractmethod:: files() Returns a :class:`importlib.resources.abc.Traversable` object for the loaded diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index d8cc7079a1d812..fc954724bb72fe 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -645,6 +645,160 @@ ABC hierarchy:: itself does not end in ``__init__``. +.. class:: ResourceReader + + *Superseded by TraversableResources* + + An :term:`abstract base class` to provide the ability to read + *resources*. + + From the perspective of this ABC, a *resource* is a binary + artifact that is shipped within a package. Typically this is + something like a data file that lives next to the ``__init__.py`` + file of the package. The purpose of this class is to help abstract + out the accessing of such data files so that it does not matter if + the package and its data file(s) are stored in a e.g. zip file + versus on the file system. + + For any of methods of this class, a *resource* argument is + expected to be a :term:`path-like object` which represents + conceptually just a file name. This means that no subdirectory + paths should be included in the *resource* argument. This is + because the location of the package the reader is for, acts as the + "directory". Hence the metaphor for directories and file + names is packages and resources, respectively. This is also why + instances of this class are expected to directly correlate to + a specific package (instead of potentially representing multiple + packages or a module). + + Loaders that wish to support resource reading are expected to + provide a method called ``get_resource_reader(fullname)`` which + returns an object implementing this ABC's interface. If the module + specified by fullname is not a package, this method should return + :const:`None`. An object compatible with this ABC should only be + returned when the specified module is a package. + + .. versionadded:: 3.7 + + .. deprecated-removed:: 3.12 3.14 + Use :class:`importlib.resources.abc.TraversableResources` instead. + + .. abstractmethod:: open_resource(resource) + + Returns an opened, :term:`file-like object` for binary reading + of the *resource*. + + If the resource cannot be found, :exc:`FileNotFoundError` is + raised. + + .. abstractmethod:: resource_path(resource) + + Returns the file system path to the *resource*. + + If the resource does not concretely exist on the file system, + raise :exc:`FileNotFoundError`. + + .. abstractmethod:: is_resource(name) + + Returns ``True`` if the named *name* is considered a resource. + :exc:`FileNotFoundError` is raised if *name* does not exist. + + .. abstractmethod:: contents() + + Returns an :term:`iterable` of strings over the contents of + the package. Do note that it is not required that all names + returned by the iterator be actual resources, e.g. it is + acceptable to return names for which :meth:`is_resource` would + be false. + + Allowing non-resource names to be returned is to allow for + situations where how a package and its resources are stored + are known a priori and the non-resource names would be useful. + For instance, returning subdirectory names is allowed so that + when it is known that the package and resources are stored on + the file system then those subdirectory names can be used + directly. + + The abstract method returns an iterable of no items. + + +.. class:: Traversable + + An object with a subset of :class:`pathlib.Path` methods suitable for + traversing directories and opening files. + + For a representation of the object on the file-system, use + :meth:`importlib.resources.as_file`. + + .. versionadded:: 3.9 + + .. deprecated-removed:: 3.12 3.14 + Use :class:`importlib.resources.abc.Traversable` instead. + + .. attribute:: name + + Abstract. The base name of this object without any parent references. + + .. abstractmethod:: iterdir() + + Yield ``Traversable`` objects in ``self``. + + .. abstractmethod:: is_dir() + + Return ``True`` if ``self`` is a directory. + + .. abstractmethod:: is_file() + + Return ``True`` if ``self`` is a file. + + .. abstractmethod:: joinpath(child) + + Return Traversable child in ``self``. + + .. abstractmethod:: __truediv__(child) + + Return ``Traversable`` child in ``self``. + + .. abstractmethod:: open(mode='r', *args, **kwargs) + + *mode* may be 'r' or 'rb' to open as text or binary. Return a handle + suitable for reading (same as :attr:`pathlib.Path.open`). + + When opening as text, accepts encoding parameters such as those + accepted by :attr:`io.TextIOWrapper`. + + .. method:: read_bytes() + + Read contents of ``self`` as bytes. + + .. method:: read_text(encoding=None) + + Read contents of ``self`` as text. + + +.. class:: TraversableResources + + An abstract base class for resource readers capable of serving + the :meth:`importlib.resources.files` interface. Subclasses + :class:`importlib.resources.abc.ResourceReader` and provides + concrete implementations of the :class:`importlib.resources.abc.ResourceReader`'s + abstract methods. Therefore, any loader supplying + :class:`importlib.abc.TraversableResources` also supplies ResourceReader. + + Loaders that wish to support resource reading are expected to + implement this interface. + + .. versionadded:: 3.9 + + .. deprecated-removed:: 3.12 3.14 + Use :class:`importlib.resources.abc.TraversableResources` instead. + + .. abstractmethod:: files() + + Returns a :class:`importlib.resources.abc.Traversable` object for the loaded + package. + + :mod:`importlib.machinery` -- Importers and path hooks ------------------------------------------------------ From 5b38bdeaf1fe51b270b4d45f080854dfbd03a75d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 13 Sep 2023 03:37:46 -0700 Subject: [PATCH 0761/1206] [3.12] Fix variable name in dis documentation example (GH-109343) (#109364) Fix variable name in dis documentation example (GH-109343) BINARY_SUBSCR example erroneously uses two different names `key` and `index` to refer to the same variable. STORE_SUBSCR and DELETE_SUBSCR use only `key` in the same context. Changing `index` to `key` for consistency. (cherry picked from commit a0c06a4f933faccd7f8201701b2491d38464212c) Co-authored-by: Oleksandr Kravets <73752159+olekskrav@users.noreply.github.com> --- Doc/library/dis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 6fadccfc44f92f..b559b085aa728b 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -528,7 +528,7 @@ not have to be) the original ``STACK[-2]``. key = STACK.pop() container = STACK.pop() - STACK.append(container[index]) + STACK.append(container[key]) .. opcode:: STORE_SUBSCR From 36d6ba08d0b143bfa52cbb642dc256d0b6fb040e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 Sep 2023 15:38:54 -0700 Subject: [PATCH 0762/1206] [3.12] gh-60283: Check for redefined test names in CI (GH-109161) (#109365) * gh-60283: Check for redefined test names in CI (GH-109161) (cherry picked from commit 3cb9a8edca6e3fa0f0045b03a9a6444cf8f7affe) Co-authored-by: Hugo van Kemenade Co-authored-by: Alex Waygood Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> * Update exclude list for 3.12 * Explicitly exclude files which failed to lint/parse * Sort to avoid future merge conflicts --------- Co-authored-by: Hugo van Kemenade Co-authored-by: Alex Waygood Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- .github/CODEOWNERS | 1 + .github/workflows/build.yml | 2 +- .github/workflows/lint.yml | 4 ++++ .pre-commit-config.yaml | 10 +++++++++ Lib/test/.ruff.toml | 42 +++++++++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 Lib/test/.ruff.toml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 95fd51b743cd33..913de4e2709284 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,6 +9,7 @@ # pre-commit .pre-commit-config.yaml @hugovk @AlexWaygood +.ruff.toml @hugovk @AlexWaygood # Build system configure* @erlend-aasland @corona10 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3061c8f59fc006..feddecf0a126f1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,7 @@ jobs: # into the PR branch anyway. # # https://github.com/python/core-workflow/issues/373 - git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true + git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc|^\.pre-commit-config\.yaml$|\.ruff\.toml$)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true fi # Check if we should run hypothesis tests diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 27b04ba1d412e3..89f65816b6969d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,6 +5,10 @@ on: [push, pull_request, workflow_dispatch] permissions: contents: read +env: + FORCE_COLOR: 1 + RUFF_FORMAT: github + concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 451cbe8bc84820..19f6a03745d2d0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,17 @@ repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.288 + hooks: + - id: ruff + name: Run Ruff on Lib/test/ + args: [--exit-non-zero-on-fix] + files: ^Lib/test/ + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: + - id: check-toml + exclude: ^Lib/test/test_tomllib/ - id: check-yaml - id: end-of-file-fixer types: [python] diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml new file mode 100644 index 00000000000000..3bdd472c0acd9a --- /dev/null +++ b/Lib/test/.ruff.toml @@ -0,0 +1,42 @@ +fix = true +select = [ + "F811", # Redefinition of unused variable (useful for finding test methods with the same name) +] +extend-exclude = [ + # Failed to lint + "badsyntax_pep3120.py", + "encoded_modules/module_iso_8859_1.py", + "encoded_modules/module_koi8_r.py", + # Failed to parse + "badsyntax_3131.py", + "support/socket_helper.py", + "test_fstring.py", + "test_lib2to3/data/bom.py", + "test_lib2to3/data/crlf.py", + "test_lib2to3/data/different_encoding.py", + "test_lib2to3/data/false_encoding.py", + "test_lib2to3/data/py2_test_grammar.py", + # TODO Fix: F811 Redefinition of unused name + "test_buffer.py", + "test_capi/test_misc.py", + "test_capi/test_unicode.py", + "test_ctypes/test_arrays.py", + "test_ctypes/test_functions.py", + "test_dataclasses.py", + "test_descr.py", + "test_enum.py", + "test_functools.py", + "test_genericclass.py", + "test_grammar.py", + "test_import/__init__.py", + "test_keywordonlyarg.py", + "test_lib2to3/data/py3_test_grammar.py", + "test_pkg.py", + "test_subclassinit.py", + "test_tokenize.py", + "test_typing.py", + "test_yield_from.py", + "time_hashlib.py", + # Pending https://github.com/python/cpython/pull/109139 + "test_monitoring.py", +] From 5c7e8c3b72992bb668cafa101b71d8d14e395830 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 Sep 2023 15:40:19 -0700 Subject: [PATCH 0763/1206] [3.12] gh-109341: Fix crash on compiling invalid AST including TypeAlias (GH-109349) (#109381) gh-109341: Fix crash on compiling invalid AST including TypeAlias (GH-109349) (cherry picked from commit 987b4bc0870e1e29a88275dc3fa39bf2c3dcc763) Co-authored-by: Jelle Zijlstra --- Lib/test/test_compile.py | 20 +++++++++++++++++++ ...-09-12-15-45-49.gh-issue-109341.4V5bkm.rst | 1 + Python/ast.c | 5 +++++ 3 files changed, 26 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 16a59c106bbb67..fde52d40097f40 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -478,6 +478,26 @@ def test_compile_ast(self): ast.body = [_ast.BoolOp()] self.assertRaises(TypeError, compile, ast, '', 'exec') + def test_compile_invalid_typealias(self): + # gh-109341 + m = ast.Module( + body=[ + ast.TypeAlias( + name=ast.Subscript( + value=ast.Name(id="foo", ctx=ast.Load()), + slice=ast.Constant(value="x"), + ctx=ast.Store(), + ), + type_params=[], + value=ast.Name(id="Callable", ctx=ast.Load()), + ) + ], + type_ignores=[], + ) + + with self.assertRaisesRegex(TypeError, "TypeAlias with non-Name name"): + compile(ast.fix_missing_locations(m), "", "exec") + def test_dict_evaluation_order(self): i = 0 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst new file mode 100644 index 00000000000000..9e99ef7eb73273 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst @@ -0,0 +1 @@ +Fix crash when compiling an invalid AST involving a :class:`ast.TypeAlias`. diff --git a/Python/ast.c b/Python/ast.c index 74c97f948d15e6..a3acf78ac95844 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -768,6 +768,11 @@ validate_stmt(struct validator *state, stmt_ty stmt) validate_expr(state, stmt->v.AnnAssign.annotation, Load); break; case TypeAlias_kind: + if (stmt->v.TypeAlias.name->kind != Name_kind) { + PyErr_SetString(PyExc_TypeError, + "TypeAlias with non-Name name"); + return 0; + } ret = validate_expr(state, stmt->v.TypeAlias.name, Store) && validate_type_params(state, stmt->v.TypeAlias.type_params) && validate_expr(state, stmt->v.TypeAlias.value, Load); From 3eae45f94da5b9cdc5aa14844d48871ab85bd537 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 14 Sep 2023 23:41:03 +0100 Subject: [PATCH 0764/1206] [3.12] gh-105658: fix excess trace events for except block ending with a conditional block (#109384) (#109411) gh-105658: fix excess trace events for except block ending with a conditional block (#109384) (cherry picked from commit 4a54074a0f5579d417445ec28427cd0ed5aa01f4) --- Lib/test/test_sys_settrace.py | 31 ++++++++++++++++++- ...-09-13-19-16-51.gh-issue-105658.z2nR2u.rst | 2 ++ Python/compile.c | 16 ++-------- 3 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index eef43e8c0e56ee..c29deeba4b31a2 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -921,6 +921,35 @@ def func(): (6, 'line'), (6, 'return')]) + def test_finally_with_conditional(self): + + # See gh-105658 + condition = True + def func(): + try: + try: + raise Exception + finally: + if condition: + result = 1 + result = 2 + except: + result = 3 + return result + + self.run_and_compare(func, + [(0, 'call'), + (1, 'line'), + (2, 'line'), + (3, 'line'), + (3, 'exception'), + (5, 'line'), + (6, 'line'), + (8, 'line'), + (9, 'line'), + (10, 'line'), + (10, 'return')]) + def test_break_to_continue1(self): def func(): @@ -2092,7 +2121,7 @@ def test_jump_in_nested_finally_3(output): output.append(11) output.append(12) - @jump_test(5, 11, [2, 4], (ValueError, 'exception')) + @jump_test(5, 11, [2, 4], (ValueError, 'comes after the current code block')) def test_no_jump_over_return_try_finally_in_finally_block(output): try: output.append(2) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst new file mode 100644 index 00000000000000..e95f5b84e8e187 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst @@ -0,0 +1,2 @@ +Fix bug where the line trace of an except block ending with a conditional +includes an excess event with the line of the conditional expression. diff --git a/Python/compile.c b/Python/compile.c index b6e5adf1c76418..ddd7b5c795b9ef 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -3184,18 +3184,6 @@ compiler_continue(struct compiler *c, location loc) } -static location -location_of_last_executing_statement(asdl_stmt_seq *stmts) -{ - for (Py_ssize_t i = asdl_seq_LEN(stmts) - 1; i >= 0; i++) { - location loc = LOC((stmt_ty)asdl_seq_GET(stmts, i)); - if (loc.lineno > 0) { - return loc; - } - } - return NO_LOCATION; -} - /* Code generated for "try: finally: " is as follows: SETUP_FINALLY L @@ -3264,9 +3252,9 @@ compiler_try_finally(struct compiler *c, stmt_ty s) RETURN_IF_ERROR( compiler_push_fblock(c, loc, FINALLY_END, end, NO_LABEL, NULL)); VISIT_SEQ(c, stmt, s->v.Try.finalbody); - loc = location_of_last_executing_statement(s->v.Try.finalbody); compiler_pop_fblock(c, FINALLY_END, end); + loc = NO_LOCATION; ADDOP_I(c, loc, RERAISE, 0); USE_LABEL(c, cleanup); @@ -3315,9 +3303,9 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s) compiler_push_fblock(c, loc, FINALLY_END, end, NO_LABEL, NULL)); VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); - loc = location_of_last_executing_statement(s->v.Try.finalbody); compiler_pop_fblock(c, FINALLY_END, end); + loc = NO_LOCATION; ADDOP_I(c, loc, RERAISE, 0); USE_LABEL(c, cleanup); From 3bb8075bcb49383dc226aa1c64cf8e18001c70fd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 Sep 2023 15:41:18 -0700 Subject: [PATCH 0765/1206] [3.12] gh-101100: Fix sphinx warnings in `turtle.rst` (GH-109394) (#109416) gh-101100: Fix sphinx warnings in `turtle.rst` (GH-109394) (cherry picked from commit 21e80f4c1925aaafae199840f8737b5c39a82c70) Co-authored-by: Nikita Sobolev --- Doc/library/turtle.rst | 8 ++++---- Doc/tools/.nitignore | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index cd8254153f765a..4e1a0948b0f678 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -2329,7 +2329,7 @@ Public classes .. class:: RawTurtle(canvas) RawPen(canvas) - :param canvas: a :class:`tkinter.Canvas`, a :class:`ScrolledCanvas` or a + :param canvas: a :class:`!tkinter.Canvas`, a :class:`ScrolledCanvas` or a :class:`TurtleScreen` Create a turtle. The turtle has all methods described above as "methods of @@ -2344,7 +2344,7 @@ Public classes .. class:: TurtleScreen(cv) - :param cv: a :class:`tkinter.Canvas` + :param cv: a :class:`!tkinter.Canvas` Provides screen oriented methods like :func:`bgcolor` etc. that are described above. @@ -2428,7 +2428,7 @@ instance if one is not already present. ``Turtle`` is a subclass of :class:`RawTurtle`, which *doesn't* automatically create a drawing surface - a *canvas* will need to be provided or created for -it. The *canvas* can be a :class:`tkinter.Canvas`, :class:`ScrolledCanvas` +it. The *canvas* can be a :class:`!tkinter.Canvas`, :class:`ScrolledCanvas` or :class:`TurtleScreen`. @@ -2436,7 +2436,7 @@ or :class:`TurtleScreen`. turtle. :class:`Screen` is a subclass of ``TurtleScreen``, and includes :ref:`some additional methods ` for managing its appearance (including size and title) and behaviour. ``TurtleScreen``'s -constructor needs a :class:`tkinter.Canvas` or a +constructor needs a :class:`!tkinter.Canvas` or a :class:`ScrolledCanvas` as an argument. The functional interface for turtle graphics uses the various methods of diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 3f00fef966c01c..3fc3303376cce6 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -143,7 +143,6 @@ Doc/library/tkinter.tix.rst Doc/library/tkinter.ttk.rst Doc/library/traceback.rst Doc/library/tty.rst -Doc/library/turtle.rst Doc/library/unittest.mock.rst Doc/library/unittest.rst Doc/library/urllib.parse.rst From 52a9c5760c600bc96df87bc93641df504d302314 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 Sep 2023 15:41:33 -0700 Subject: [PATCH 0766/1206] [3.12] gh-109396: Fix test_socket.test_hmac_sha1() in FIPS mode (GH-109423) (#109426) gh-109396: Fix test_socket.test_hmac_sha1() in FIPS mode (GH-109423) Use a longer key: FIPS mode requires at least of at least 112 bits. The previous key was only 32 bits. (cherry picked from commit e091b9f20fa8e409003af79f3c468b8225e6dcd3) Co-authored-by: Victor Stinner --- Lib/test/test_socket.py | 10 +++++++--- .../2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index f35618e0281e70..99c4c5cbc4902d 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -6474,12 +6474,16 @@ def test_sha256(self): self.assertEqual(op.recv(512), expected) def test_hmac_sha1(self): - expected = bytes.fromhex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79") + # gh-109396: In FIPS mode, Linux 6.5 requires a key + # of at least 112 bits. Use a key of 152 bits. + key = b"Python loves AF_ALG" + data = b"what do ya want for nothing?" + expected = bytes.fromhex("193dbb43c6297b47ea6277ec0ce67119a3f3aa66") with self.create_alg('hash', 'hmac(sha1)') as algo: - algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, b"Jefe") + algo.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, key) op, _ = algo.accept() with op: - op.sendall(b"what do ya want for nothing?") + op.sendall(data) self.assertEqual(op.recv(512), expected) # Although it should work with 3.19 and newer the test blocks on diff --git a/Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst b/Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst new file mode 100644 index 00000000000000..71150ecae76434 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst @@ -0,0 +1,3 @@ +Fix ``test_socket.test_hmac_sha1()`` in FIPS mode. Use a longer key: FIPS +mode requires at least of at least 112 bits. The previous key was only 32 +bits. Patch by Victor Stinner. From 35c633d245a947b2002b5c033ea46e31aec7d95c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 14 Sep 2023 15:42:39 -0700 Subject: [PATCH 0767/1206] [3.12] gh-109219: propagate free vars through type param scopes (GH-109377) (#109410) gh-109219: propagate free vars through type param scopes (GH-109377) (cherry picked from commit 909adb5092c0ae9426814742d97932204b211cfb) Co-authored-by: Carl Meyer Co-authored-by: Jelle Zijlstra --- Lib/test/test_type_params.py | 13 +++++++++++++ .../2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst | 2 ++ Python/symtable.c | 5 ++--- 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index b1848aee4753a1..25ee188731f31f 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -694,6 +694,19 @@ class Cls: cls = ns["outer"]() self.assertEqual(cls.Alias.__value__, "class") + def test_nested_free(self): + ns = run_code(""" + def f(): + T = str + class C: + T = int + class D[U](T): + x = T + return C + """) + C = ns["f"]() + self.assertIn(int, C.D.__bases__) + self.assertIs(C.D.x, str) class TypeParamsManglingTest(unittest.TestCase): def test_mangling(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst new file mode 100644 index 00000000000000..2c141f09d7e754 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst @@ -0,0 +1,2 @@ +Fix compiling type param scopes that use a name which is also free in an +inner scope. diff --git a/Python/symtable.c b/Python/symtable.c index 691698e00b4619..4989e03d4bf591 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -801,8 +801,7 @@ update_symbols(PyObject *symbols, PyObject *scopes, the class that has the same name as a local or global in the class scope. */ - if (classflag && - PyLong_AS_LONG(v) & (DEF_BOUND | DEF_GLOBAL)) { + if (classflag) { long flags = PyLong_AS_LONG(v) | DEF_FREE_CLASS; v_new = PyLong_FromLong(flags); if (!v_new) { @@ -1037,7 +1036,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, goto error; /* Records the results of the analysis in the symbol table entry */ if (!update_symbols(ste->ste_symbols, scopes, bound, newfree, inlined_cells, - ste->ste_type == ClassBlock)) + (ste->ste_type == ClassBlock) || ste->ste_can_see_class_scope)) goto error; temp = PyNumber_InPlaceOr(free, newfree); From dba95c546b80495e9d80e85cbfd6cb8790090943 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 Sep 2023 02:32:05 -0700 Subject: [PATCH 0768/1206] [3.12] gh-109395: Remove skipped coverage job from Azure Pipelines (GH-109412) (#109433) gh-109395: Remove skipped coverage job from Azure Pipelines (GH-109412) (cherry picked from commit fa493900fbf19cbfac44164f3d8acb4f598ff3c1) Co-authored-by: Hugo van Kemenade --- .azure-pipelines/ci.yml | 30 ------------------- .azure-pipelines/posix-steps.yml | 50 ++++++-------------------------- .azure-pipelines/pr.yml | 30 ------------------- 3 files changed, 9 insertions(+), 101 deletions(-) diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index 63252a76abb69f..ad1576a88fdff7 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -1,6 +1,3 @@ -variables: - coverage: false - trigger: ['main', '3.11', '3.10', '3.9', '3.8', '3.7'] jobs: @@ -51,33 +48,6 @@ jobs: dependencies: apt -- job: Ubuntu_Coverage_CI_Tests - displayName: Ubuntu CI Tests (coverage) - dependsOn: Prebuild - condition: | - and( - and( - succeeded(), - eq(variables['coverage'], 'true') - ), - eq(dependencies.Prebuild.outputs['tests.run'], 'true') - ) - - pool: - vmImage: ubuntu-22.04 - - variables: - testRunTitle: '$(Build.SourceBranchName)-linux-coverage' - testRunPlatform: linux-coverage - openssl_version: 1.1.1u - - steps: - - template: ./posix-steps.yml - parameters: - dependencies: apt - coverage: true - - - job: Windows_CI_Tests displayName: Windows CI Tests dependsOn: Prebuild diff --git a/.azure-pipelines/posix-steps.yml b/.azure-pipelines/posix-steps.yml index 9d7c5e1279f46d..65c29f60413d6a 100644 --- a/.azure-pipelines/posix-steps.yml +++ b/.azure-pipelines/posix-steps.yml @@ -1,5 +1,4 @@ parameters: - coverage: false sudo_dependencies: sudo dependencies: apt patchcheck: true @@ -23,47 +22,16 @@ steps: - script: make -j4 displayName: 'Build CPython' -- ${{ if eq(parameters.coverage, 'true') }}: - - script: ./python -m venv venv && ./venv/bin/python -m pip install -U coverage - displayName: 'Set up virtual environment' +- script: make pythoninfo + displayName: 'Display build info' - - script: ./venv/bin/python -m test.pythoninfo - displayName: 'Display build info' - - - script: | - $COMMAND -m coverage run --pylib -m test \ - --fail-env-changed \ - -uall,-cpu \ - --junit-xml=$(build.binariesDirectory)/test-results.xml \ - -x test_multiprocessing_fork \ - -x test_multiprocessing_forkserver \ - -x test_multiprocessing_spawn \ - -x test_concurrent_futures - displayName: 'Tests with coverage' - env: - ${{ if eq(parameters.xvfb, 'true') }}: - COMMAND: xvfb-run ./venv/bin/python - ${{ if ne(parameters.xvfb, 'true') }}: - COMMAND: ./venv/bin/python - - - script: ./venv/bin/python -m coverage xml - displayName: 'Generate coverage.xml' - - - script: source ./venv/bin/activate && bash <(curl -s https://codecov.io/bash) -y .github/codecov.yml - displayName: 'Publish code coverage results' - - -- ${{ if ne(parameters.coverage, 'true') }}: - - script: make pythoninfo - displayName: 'Display build info' - - - script: $COMMAND buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=$(build.binariesDirectory)/test-results.xml" - displayName: 'Tests' - env: - ${{ if eq(parameters.xvfb, 'true') }}: - COMMAND: xvfb-run make - ${{ if ne(parameters.xvfb, 'true') }}: - COMMAND: make +- script: $COMMAND buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=$(build.binariesDirectory)/test-results.xml" + displayName: 'Tests' + env: + ${{ if eq(parameters.xvfb, 'true') }}: + COMMAND: xvfb-run make + ${{ if ne(parameters.xvfb, 'true') }}: + COMMAND: make - ${{ if eq(parameters.patchcheck, 'true') }}: - script: | diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 939c9b4249a3c2..5f052368a469c7 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -1,6 +1,3 @@ -variables: - coverage: false - pr: ['main', '3.11', '3.10', '3.9', '3.8', '3.7'] jobs: @@ -53,33 +50,6 @@ jobs: dependencies: apt -- job: Ubuntu_Coverage_PR_Tests - displayName: Ubuntu PR Tests (coverage) - dependsOn: Prebuild - condition: | - and( - and( - succeeded(), - eq(variables['coverage'], 'true') - ), - eq(dependencies.Prebuild.outputs['tests.run'], 'true') - ) - - pool: - vmImage: ubuntu-22.04 - - variables: - testRunTitle: '$(Build.SourceBranchName)-linux-coverage' - testRunPlatform: linux-coverage - openssl_version: 1.1.1u - - steps: - - template: ./posix-steps.yml - parameters: - dependencies: apt - coverage: true - - - job: Windows_PR_Tests displayName: Windows PR Tests dependsOn: Prebuild From 316f0ee874f420a900168da29b913582b3877e63 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 Sep 2023 04:23:08 -0700 Subject: [PATCH 0769/1206] [3.12] gh-109395: Remove skipped macOS builds from Azure Pipelines (GH-109400) (#109441) gh-109395: Remove skipped macOS builds from Azure Pipelines (GH-109400) (cherry picked from commit 1ece084be3684e06101aa1efa82d3ed98c99c432) Co-authored-by: Nikita Sobolev --- .azure-pipelines/ci.yml | 18 ------------------ .azure-pipelines/macos-steps.yml | 27 --------------------------- .azure-pipelines/pr.yml | 20 -------------------- 3 files changed, 65 deletions(-) delete mode 100644 .azure-pipelines/macos-steps.yml diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index ad1576a88fdff7..246e059f5d1842 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -11,24 +11,6 @@ jobs: - template: ./prebuild-checks.yml -- job: macOS_CI_Tests - displayName: macOS CI Tests - dependsOn: Prebuild - #condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true')) - # bpo-39837: macOS tests on Azure Pipelines are disabled - condition: false - - variables: - testRunTitle: '$(build.sourceBranchName)-macos' - testRunPlatform: macos - - pool: - vmImage: macos-10.15 - - steps: - - template: ./macos-steps.yml - - - job: Ubuntu_CI_Tests displayName: Ubuntu CI Tests dependsOn: Prebuild diff --git a/.azure-pipelines/macos-steps.yml b/.azure-pipelines/macos-steps.yml deleted file mode 100644 index fa38a0df8c87b8..00000000000000 --- a/.azure-pipelines/macos-steps.yml +++ /dev/null @@ -1,27 +0,0 @@ -steps: -- checkout: self - clean: true - fetchDepth: 5 - -- script: ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl --prefix=/opt/python-azdev - displayName: 'Configure CPython (debug)' - -- script: make -j4 - displayName: 'Build CPython' - -- script: make pythoninfo - displayName: 'Display build info' - -- script: make buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=$(build.binariesDirectory)/test-results.xml" - displayName: 'Tests' - continueOnError: true - timeoutInMinutes: 30 - -- task: PublishTestResults@2 - displayName: 'Publish Test Results' - inputs: - testResultsFiles: '$(build.binariesDirectory)/test-results.xml' - mergeTestResults: true - testRunTitle: $(testRunTitle) - platform: $(testRunPlatform) - condition: succeededOrFailed() diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 5f052368a469c7..0836c780c1cf95 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -11,26 +11,6 @@ jobs: - template: ./prebuild-checks.yml -- job: macOS_PR_Tests - displayName: macOS PR Tests - dependsOn: Prebuild - #condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true')) - # bpo-39837: macOS tests on Azure Pipelines are disabled - condition: false - - variables: - testRunTitle: '$(system.pullRequest.TargetBranch)-macos' - testRunPlatform: macos - - pool: - vmImage: macos-10.15 - - steps: - - template: ./macos-steps.yml - parameters: - targetBranch: $(System.PullRequest.TargetBranch) - - - job: Ubuntu_PR_Tests displayName: Ubuntu PR Tests dependsOn: Prebuild From e9a90523c97c3c7f1937187e2ae24878227c3dd0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 15 Sep 2023 07:11:17 -0700 Subject: [PATCH 0770/1206] [3.12] Docs: Superseded modules: list only module names (GH-109439) (#109445) Docs: Superseded modules: list only module names (GH-109439) (cherry picked from commit b434dd7e3625d442392b4adf952685c8adf769f7) Co-authored-by: Hugo van Kemenade --- Doc/library/superseded.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index aaf66ea121d39c..910e899184eb72 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -9,6 +9,7 @@ backwards compatibility. They have been superseded by other modules. .. toctree:: + :maxdepth: 1 aifc.rst audioop.rst From 52bbb224bace65ec5eead5bdf34301ff0eec96de Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sun, 17 Sep 2023 13:49:42 -0700 Subject: [PATCH 0771/1206] [3.12] gh-109096: Silence test_httpservers fork + threads DeprecationWarning on CGI support (#109471) [3.12] gh-109096: Silence test_httpservers fork + threads DeprecationWarning on CGI support. We're not fixing CGIHTTPRequestHandler as it is deprecated in 3.13 to go away in 3.15. This just removes noise from our test suite when warnings are rightfully enabled. If the long pre-existing fork+threading mix here ever causes anyone deadlocks as is possible, disabling the test entirely on that platform makes sense rather than attempting to fix http.server.CGIHTTPRequestHandler or refactor to not use a threaded server in the test. --- Lib/test/test_httpservers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index cfd8a101dcc1c1..15f944734c608e 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -26,6 +26,7 @@ import datetime import threading from unittest import mock +import warnings from io import BytesIO, StringIO import unittest @@ -699,7 +700,11 @@ def test_html_escape_filename(self): "This test can't be run reliably as root (issue #13308).") class CGIHTTPServerTestCase(BaseTestCase): class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler): - pass + def run_cgi(self): + # Silence the threading + fork DeprecationWarning this causes. + # gh-109096: This is deprecated in 3.13 to go away in 3.15. + with warnings.catch_warnings(action='ignore', category=DeprecationWarning): + return super().run_cgi() linesep = os.linesep.encode('ascii') From 02df0df97c01ee22b12fc543947396e5eb6d8854 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 17 Sep 2023 13:50:00 -0700 Subject: [PATCH 0772/1206] [3.12] gh-109474: Update two Unix packaging URLs (GH-109307) (#109477) gh-109474: Update two Unix packaging URLs (GH-109307) update packaging URLs fix a broken URL for fedora RPM packaging guide and fix a URL redirect for Slackware packaging guide. (cherry picked from commit 0b38ce440bd76b3d25b6d042ee9613841fb4a947) Co-authored-by: partev --- Doc/using/unix.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 0044eb07f56eec..58838c28e6eb86 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -30,9 +30,9 @@ following links: for Debian users https://en.opensuse.org/Portal:Packaging for OpenSuse users - https://docs-old.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch-creating-rpms.html + https://docs.fedoraproject.org/en-US/package-maintainers/Packaging_Tutorial_GNU_Hello/ for Fedora users - http://www.slackbook.org/html/package-management-making-packages.html + https://slackbook.org/html/package-management-making-packages.html for Slackware users From 655287996e01f92ca5a9d579f511991e41a41477 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 17 Sep 2023 13:50:12 -0700 Subject: [PATCH 0773/1206] [3.12] gh-109414: Add some basic information about venvs in the introduction. (GH-109440) (#109481) gh-109414: Add some basic information about venvs in the introduction. (GH-109440) (cherry picked from commit a6846d45ff3c836bc859c40e7684b57df991dc05) Co-authored-by: Vinay Sajip Co-authored-by: Victor Stinner --- Doc/library/venv.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 2482441d649790..18af1d41e4044b 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -30,6 +30,25 @@ When used from within a virtual environment, common installation tools such as `pip`_ will install Python packages into a virtual environment without needing to be told to do so explicitly. +A virtual environment is (amongst other things): + +* Used to contain a specific Python interpreter and software libraries and + binaries which are needed to support a project (library or application). These + are by default isolated from software in other virtual environments and Python + interpreters and libraries installed in the operating system. + +* Contained in a directory, conventionally either named ``venv`` or ``.venv`` in + the project directory, or under a container directory for lots of virtual + environments, such as ``~/.virtualenvs``. + +* Not checked into source control systems such as Git. + +* Considered as disposable -- it should be simple to delete and recreate it from + scratch. You don't place any project code in the environment + +* Not considered as movable or copyable -- you just recreate the same + environment in the target location. + See :pep:`405` for more background on Python virtual environments. .. seealso:: From cc12f6684e8fd9d39d866957860b884b3545a69b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 17 Sep 2023 13:50:37 -0700 Subject: [PATCH 0774/1206] [3.12] gh-109451: Fix wrong format specifier in logging documentation (GH-109465) (#109483) gh-109451: Fix wrong format specifier in logging documentation (GH-109465) (cherry picked from commit 929cc4e4a0999b777e1aa94f9c007db720e67f43) Co-authored-by: AlberLC <37489786+AlberLC@users.noreply.github.com> --- Doc/library/logging.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index d369c53f0f919c..6d1f048d283cee 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -907,7 +907,7 @@ you want to use. In the case of {}-formatting, you can specify formatting flags by placing them after the attribute name, separated from it with a colon. For example: a -placeholder of ``{msecs:03d}`` would format a millisecond value of ``4`` as +placeholder of ``{msecs:03.0f}`` would format a millisecond value of ``4`` as ``004``. Refer to the :meth:`str.format` documentation for full details on the options available to you. From 5c439fbd306b8f1dd6d14838028357098f39d013 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 17 Sep 2023 16:22:15 -0700 Subject: [PATCH 0775/1206] [3.12] gh-109408: Remove Ubuntu unit tests from Azure Pipelines (GH-109452) (#109519) gh-109408: Remove Ubuntu unit tests from Azure Pipelines (GH-109452) (cherry picked from commit a75daed7e004ee9a53b160307c4c072656176a02) Co-authored-by: Hugo van Kemenade --- .azure-pipelines/ci.yml | 19 ---------------- .azure-pipelines/posix-steps.yml | 37 ++++++-------------------------- .azure-pipelines/pr.yml | 6 ++---- 3 files changed, 8 insertions(+), 54 deletions(-) diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index 246e059f5d1842..42eb448bc1c66b 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -11,25 +11,6 @@ jobs: - template: ./prebuild-checks.yml -- job: Ubuntu_CI_Tests - displayName: Ubuntu CI Tests - dependsOn: Prebuild - condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true')) - - pool: - vmImage: ubuntu-22.04 - - variables: - testRunTitle: '$(build.sourceBranchName)-linux' - testRunPlatform: linux - openssl_version: 1.1.1u - - steps: - - template: ./posix-steps.yml - parameters: - dependencies: apt - - - job: Windows_CI_Tests displayName: Windows CI Tests dependsOn: Prebuild diff --git a/.azure-pipelines/posix-steps.yml b/.azure-pipelines/posix-steps.yml index 65c29f60413d6a..e23c7b1dcb55c1 100644 --- a/.azure-pipelines/posix-steps.yml +++ b/.azure-pipelines/posix-steps.yml @@ -1,9 +1,3 @@ -parameters: - sudo_dependencies: sudo - dependencies: apt - patchcheck: true - xvfb: true - steps: - checkout: self clean: true @@ -13,7 +7,7 @@ steps: - script: sudo setfacl -Rb /home/vsts displayName: 'Workaround ACL issue' -- script: ${{ parameters.sudo_dependencies }} ./.azure-pipelines/posix-deps-${{ parameters.dependencies }}.sh $(openssl_version) +- script: sudo ./.azure-pipelines/posix-deps-apt.sh $(openssl_version) displayName: 'Install dependencies' - script: ./configure --with-pydebug @@ -25,27 +19,8 @@ steps: - script: make pythoninfo displayName: 'Display build info' -- script: $COMMAND buildbottest TESTOPTS="-j4 -uall,-cpu --junit-xml=$(build.binariesDirectory)/test-results.xml" - displayName: 'Tests' - env: - ${{ if eq(parameters.xvfb, 'true') }}: - COMMAND: xvfb-run make - ${{ if ne(parameters.xvfb, 'true') }}: - COMMAND: make - -- ${{ if eq(parameters.patchcheck, 'true') }}: - - script: | - git fetch origin - ./python Tools/patchcheck/patchcheck.py --ci true - displayName: 'Run patchcheck.py' - condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) - - -- task: PublishTestResults@2 - displayName: 'Publish Test Results' - inputs: - testResultsFiles: '$(build.binariesDirectory)/test-results.xml' - mergeTestResults: true - testRunTitle: $(testRunTitle) - platform: $(testRunPlatform) - condition: succeededOrFailed() +- script: | + git fetch origin + ./python Tools/patchcheck/patchcheck.py --ci true + displayName: 'Run patchcheck.py' + condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 0836c780c1cf95..3a8728bcda9272 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -11,8 +11,8 @@ jobs: - template: ./prebuild-checks.yml -- job: Ubuntu_PR_Tests - displayName: Ubuntu PR Tests +- job: Ubuntu_Patchcheck + displayName: Ubuntu patchcheck dependsOn: Prebuild condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true')) @@ -26,8 +26,6 @@ jobs: steps: - template: ./posix-steps.yml - parameters: - dependencies: apt - job: Windows_PR_Tests From fbf703ce6e1a17ced464396f4a48f69f1c777b8a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Sep 2023 03:29:19 -0700 Subject: [PATCH 0776/1206] [3.12] Fix extraneous backslashes in hashlib docs (GH-109468) (#109530) Fix extraneous backslashes in hashlib docs (GH-109468) (cherry picked from commit ce5b3e19e6fb940fa72db1b98a8df80f6e464265) Co-authored-by: Anthony Sottile --- Doc/library/hashlib.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 69fb79b49ca2a0..eb650c180ddbb4 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -136,16 +136,16 @@ Using :func:`new` with an algorithm name: '031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406' -.. function:: md5([, data], \*, usedforsecurity=True) -.. function:: sha1([, data], \*, usedforsecurity=True) -.. function:: sha224([, data], \*, usedforsecurity=True) -.. function:: sha256([, data], \*, usedforsecurity=True) -.. function:: sha384([, data], \*, usedforsecurity=True) -.. function:: sha512([, data], \*, usedforsecurity=True) -.. function:: sha3_224([, data], \*, usedforsecurity=True) -.. function:: sha3_256([, data], \*, usedforsecurity=True) -.. function:: sha3_384([, data], \*, usedforsecurity=True) -.. function:: sha3_512([, data], \*, usedforsecurity=True) +.. function:: md5([, data], *, usedforsecurity=True) +.. function:: sha1([, data], *, usedforsecurity=True) +.. function:: sha224([, data], *, usedforsecurity=True) +.. function:: sha256([, data], *, usedforsecurity=True) +.. function:: sha384([, data], *, usedforsecurity=True) +.. function:: sha512([, data], *, usedforsecurity=True) +.. function:: sha3_224([, data], *, usedforsecurity=True) +.. function:: sha3_256([, data], *, usedforsecurity=True) +.. function:: sha3_384([, data], *, usedforsecurity=True) +.. function:: sha3_512([, data], *, usedforsecurity=True) Named constructors such as these are faster than passing an algorithm name to :func:`new`. @@ -234,8 +234,8 @@ A hash object has the following methods: SHAKE variable length digests ----------------------------- -.. function:: shake_128([, data], \*, usedforsecurity=True) -.. function:: shake_256([, data], \*, usedforsecurity=True) +.. function:: shake_128([, data], *, usedforsecurity=True) +.. function:: shake_256([, data], *, usedforsecurity=True) The :func:`shake_128` and :func:`shake_256` algorithms provide variable length digests with length_in_bits//2 up to 128 or 256 bits of security. From f6fc831aa96f82b74c8dae9a20dc88c89e457967 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Sep 2023 07:31:01 -0700 Subject: [PATCH 0777/1206] [3.12] gh-102251: Disable non-rerunnable test in test_import (GH-106013) (#109540) gh-102251: Disable non-rerunnable test in test_import (GH-106013) (cherry picked from commit 4849a80dd1cbbc5010e8749ba60eb91a541ae4e7) Co-authored-by: Erlend E. Aasland --- Lib/test/test_import/__init__.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index f7df6d7e42319f..62585b23a7398f 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -106,6 +106,25 @@ def remove_files(name): rmtree('__pycache__') +def no_rerun(reason): + """Skip rerunning for a particular test. + + WARNING: Use this decorator with care; skipping rerunning makes it + impossible to find reference leaks. Provide a clear reason for skipping the + test using the 'reason' parameter. + """ + def deco(func): + _has_run = False + def wrapper(self): + nonlocal _has_run + if _has_run: + self.skipTest(reason) + func(self) + _has_run = True + return wrapper + return deco + + @contextlib.contextmanager def _ready_to_import(name=None, source=""): # sets up a temporary directory and removes it @@ -2018,10 +2037,6 @@ class SinglephaseInitTests(unittest.TestCase): @classmethod def setUpClass(cls): - if '-R' in sys.argv or '--huntrleaks' in sys.argv: - # https://github.com/python/cpython/issues/102251 - raise unittest.SkipTest('unresolved refleaks (see gh-102251)') - spec = importlib.util.find_spec(cls.NAME) from importlib.machinery import ExtensionFileLoader cls.FILE = spec.origin @@ -2535,6 +2550,7 @@ def test_basic_multiple_interpreters_main_no_reset(self): # * m_copy was copied from interp2 (was from interp1) # * module's global state was updated, not reset + @no_rerun(reason="rerun not possible; module state is never cleared (see gh-102251)") @requires_subinterpreters def test_basic_multiple_interpreters_deleted_no_reset(self): # without resetting; already loaded in a deleted interpreter From 2401b980da571cac49c804edb66696766c4cd9c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Sep 2023 07:44:13 -0700 Subject: [PATCH 0778/1206] [3.12] gh-108843: fix ast.unparse for f-string with many quotes (GH-108981) (#109541) gh-108843: fix ast.unparse for f-string with many quotes (GH-108981) (cherry picked from commit 23f9f6f46454455bc6015e83ae5b5e946dae7698) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Lib/ast.py | 21 ++++++++++++++++++- Lib/test/test_unparse.py | 14 +++++++++++++ ...-09-06-06-17-23.gh-issue-108843.WJMhsS.rst | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst diff --git a/Lib/ast.py b/Lib/ast.py index f4e542cdf253c6..07044706dc3608 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1234,17 +1234,36 @@ def visit_JoinedStr(self, node): new_fstring_parts = [] quote_types = list(_ALL_QUOTES) + fallback_to_repr = False for value, is_constant in fstring_parts: if is_constant: - value, quote_types = self._str_literal_helper( + value, new_quote_types = self._str_literal_helper( value, quote_types=quote_types, escape_special_whitespace=True, ) + if set(new_quote_types).isdisjoint(quote_types): + fallback_to_repr = True + break + quote_types = new_quote_types elif "\n" in value: quote_types = [q for q in quote_types if q in _MULTI_QUOTES] + assert quote_types new_fstring_parts.append(value) + if fallback_to_repr: + # If we weren't able to find a quote type that works for all parts + # of the JoinedStr, fallback to using repr and triple single quotes. + quote_types = ["'''"] + new_fstring_parts.clear() + for value, is_constant in fstring_parts: + if is_constant: + value = repr('"' + value) # force repr to use single quotes + expected_prefix = "'\"" + assert value.startswith(expected_prefix), repr(value) + value = value[len(expected_prefix):-1] + new_fstring_parts.append(value) + value = "".join(new_fstring_parts) quote_type = quote_types[0] self.write(f"{quote_type}{value}{quote_type}") diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 38c59e6d430b58..bdf7b0588bee67 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -635,6 +635,20 @@ def test_star_expr_assign_target_multiple(self): self.check_src_roundtrip("[a, b] = [c, d] = [e, f] = g") self.check_src_roundtrip("a, b = [c, d] = e, f = g") + def test_multiquote_joined_string(self): + self.check_ast_roundtrip("f\"'''{1}\\\"\\\"\\\"\" ") + self.check_ast_roundtrip("""f"'''{1}""\\"" """) + self.check_ast_roundtrip("""f'""\"{1}''' """) + self.check_ast_roundtrip("""f'""\"{1}""\\"' """) + + self.check_ast_roundtrip("""f"'''{"\\n"}""\\"" """) + self.check_ast_roundtrip("""f'""\"{"\\n"}''' """) + self.check_ast_roundtrip("""f'""\"{"\\n"}""\\"' """) + + self.check_ast_roundtrip("""f'''""\"''\\'{"\\n"}''' """) + self.check_ast_roundtrip("""f'''""\"''\\'{"\\n\\"'"}''' """) + self.check_ast_roundtrip("""f'''""\"''\\'{""\"\\n\\"'''""\" '''\\n'''}''' """) + class ManualASTCreationTestCase(unittest.TestCase): """Test that AST nodes created without a type_params field unparse correctly.""" diff --git a/Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst b/Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst new file mode 100644 index 00000000000000..0f15761c14bb7d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst @@ -0,0 +1 @@ +Fix an issue in :func:`ast.unparse` when unparsing f-strings containing many quote types. From 9412a874a765da1241f9ea7c1fb689152d155004 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Sep 2023 08:40:51 -0700 Subject: [PATCH 0779/1206] [3.12] gh-109371: Fix monitoring with instruction events set (gh-109385) (#109542) gh-109371: Fix monitoring with instruction events set (gh-109385) (cherry picked from commit 412f5e85d6b9f2e90c57c54539d06c7a025a472a) Co-authored-by: Tian Gao --- Lib/test/test_monitoring.py | 16 ++++++++++++++++ Lib/test/test_sys_setprofile.py | 13 ++++++++++++- ...023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst | 1 + Python/instrumentation.c | 5 ++++- 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index d091572b0880d6..8c9755d2a41a2d 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -501,6 +501,22 @@ def test_two_with_disable(self): self.assertEqual(sys.monitoring._all_events(), {}) sys.monitoring.restart_events() + def test_with_instruction_event(self): + """Test that the second tool can set events with instruction events set by the first tool.""" + def f(): + pass + code = f.__code__ + + try: + self.assertEqual(sys.monitoring._all_events(), {}) + sys.monitoring.set_local_events(TEST_TOOL, code, E.INSTRUCTION | E.LINE) + sys.monitoring.set_local_events(TEST_TOOL2, code, E.LINE) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.set_events(TEST_TOOL2, 0) + self.assertEqual(sys.monitoring._all_events(), {}) + + class LineMonitoringTest(MonitoringTestBase, unittest.TestCase): def test_lines_single(self): diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index 49e076c77d167a..34c70d6c8de0c4 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -439,7 +439,6 @@ def __del__(self): sys.setprofile(foo) self.assertEqual(sys.getprofile(), bar) - def test_same_object(self): def foo(*args): ... @@ -448,6 +447,18 @@ def foo(*args): del foo sys.setprofile(sys.getprofile()) + def test_profile_after_trace_opcodes(self): + def f(): + ... + + sys._getframe().f_trace_opcodes = True + prev_trace = sys.gettrace() + sys.settrace(lambda *args: None) + f() + sys.settrace(prev_trace) + sys.setprofile(lambda *args: None) + f() + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst new file mode 100644 index 00000000000000..2fb18d5ae88347 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst @@ -0,0 +1 @@ +Deopted instructions correctly for tool initialization and modified the incorrect assertion in instrumentation, when a previous tool already sets INSTRUCTION events diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 0a54eb67c31967..a6ff7a8a98506c 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -647,7 +647,7 @@ instrument(PyCodeObject *code, int i) if (opcode == INSTRUMENTED_INSTRUCTION) { opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; opcode = *opcode_ptr; - CHECK(!is_instrumented(opcode)); + CHECK(opcode != INSTRUMENTED_INSTRUCTION && opcode != INSTRUMENTED_LINE); CHECK(opcode == _PyOpcode_Deopt[opcode]); } CHECK(opcode != 0); @@ -1252,6 +1252,9 @@ initialize_tools(PyCodeObject *code) if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[i].original_opcode; } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode = code->_co_monitoring->per_instruction_opcodes[i]; + } bool instrumented = is_instrumented(opcode); if (instrumented) { opcode = DE_INSTRUMENT[opcode]; From 0620bc7f78782cd2e400827aaf834f358250778f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Sep 2023 08:51:23 -0700 Subject: [PATCH 0780/1206] [3.12] gh-109408: Azure Pipelines: test 3.12 branch (GH-109453) (#109535) gh-109408: Azure Pipelines: test 3.12 branch (GH-109453) (cherry picked from commit dd5d2141abf78fcd787f12654f08bf1ee92288bf) Co-authored-by: Hugo van Kemenade --- .azure-pipelines/ci.yml | 2 +- .azure-pipelines/pr.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index 42eb448bc1c66b..b5b2765e43844f 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -1,4 +1,4 @@ -trigger: ['main', '3.11', '3.10', '3.9', '3.8', '3.7'] +trigger: ['main', '3.12', '3.11', '3.10', '3.9', '3.8', '3.7'] jobs: - job: Prebuild diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 3a8728bcda9272..daa2c7ca97df6a 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -1,4 +1,4 @@ -pr: ['main', '3.11', '3.10', '3.9', '3.8', '3.7'] +pr: ['main', '3.12', '3.11', '3.10', '3.9', '3.8', '3.7'] jobs: - job: Prebuild From 74a7f5d2dacd4c05aad0e64a275dae97d18f5355 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:39:27 -0700 Subject: [PATCH 0781/1206] [3.12] gh-109496: Detect Py_DECREF() after dealloc in debug mode (GH-109539) (#109545) gh-109496: Detect Py_DECREF() after dealloc in debug mode (GH-109539) On a Python built in debug mode, Py_DECREF() now calls _Py_NegativeRefcount() if the object is a dangling pointer to deallocated memory: memory filled with 0xDD "dead byte" by the debug hook on memory allocators. The fix is to check the reference count *before* checking for _Py_IsImmortal(). Add test_decref_freed_object() to test_capi.test_misc. (cherry picked from commit 0bb0d88e2d4e300946e399e088e2ff60de2ccf8c) Co-authored-by: Victor Stinner --- Include/object.h | 10 +++--- Lib/test/test_capi/test_misc.py | 36 +++++++++++++------ ...-09-18-15-35-08.gh-issue-109496.Kleoz3.rst | 5 +++ Modules/_testcapimodule.c | 21 +++++++++++ 4 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst diff --git a/Include/object.h b/Include/object.h index 77434e3bc73c15..5c30c77bc26a40 100644 --- a/Include/object.h +++ b/Include/object.h @@ -679,17 +679,15 @@ static inline void Py_DECREF(PyObject *op) { #elif defined(Py_REF_DEBUG) static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) { + if (op->ob_refcnt <= 0) { + _Py_NegativeRefcount(filename, lineno, op); + } if (_Py_IsImmortal(op)) { return; } _Py_DECREF_STAT_INC(); _Py_DECREF_DecRefTotal(); - if (--op->ob_refcnt != 0) { - if (op->ob_refcnt < 0) { - _Py_NegativeRefcount(filename, lineno, op); - } - } - else { + if (--op->ob_refcnt == 0) { _Py_Dealloc(op); } } diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 2a71ac533d9e07..575635584fb556 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -301,24 +301,40 @@ def test_getitem_with_error(self): def test_buildvalue_N(self): _testcapi.test_buildvalue_N() - @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), - 'need _testcapi.negative_refcount') - def test_negative_refcount(self): + def check_negative_refcount(self, code): # bpo-35059: Check that Py_DECREF() reports the correct filename # when calling _Py_NegativeRefcount() to abort Python. - code = textwrap.dedent(""" - import _testcapi - from test import support - - with support.SuppressCrashReport(): - _testcapi.negative_refcount() - """) + code = textwrap.dedent(code) rc, out, err = assert_python_failure('-c', code) self.assertRegex(err, br'_testcapimodule\.c:[0-9]+: ' br'_Py_NegativeRefcount: Assertion failed: ' br'object has negative ref count') + @unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'), + 'need _testcapi.negative_refcount()') + def test_negative_refcount(self): + code = """ + import _testcapi + from test import support + + with support.SuppressCrashReport(): + _testcapi.negative_refcount() + """ + self.check_negative_refcount(code) + + @unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'), + 'need _testcapi.decref_freed_object()') + def test_decref_freed_object(self): + code = """ + import _testcapi + from test import support + + with support.SuppressCrashReport(): + _testcapi.decref_freed_object() + """ + self.check_negative_refcount(code) + def test_trashcan_subclass(self): # bpo-35983: Check that the trashcan mechanism for "list" is NOT # activated when its tp_dealloc is being called by a subclass diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst new file mode 100644 index 00000000000000..51b2144fed7841 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst @@ -0,0 +1,5 @@ +On a Python built in debug mode, :c:func:`Py_DECREF()` now calls +``_Py_NegativeRefcount()`` if the object is a dangling pointer to +deallocated memory: memory filled with ``0xDD`` "dead byte" by the debug +hook on memory allocators. The fix is to check the reference count *before* +checking for ``_Py_IsImmortal()``. Patch by Victor Stinner. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 4904e8ae33fa1a..c73b297adaa76d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2157,6 +2157,26 @@ negative_refcount(PyObject *self, PyObject *Py_UNUSED(args)) Py_RETURN_NONE; } + +static PyObject * +decref_freed_object(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyObject *obj = PyUnicode_FromString("decref_freed_object"); + if (obj == NULL) { + return NULL; + } + assert(Py_REFCNT(obj) == 1); + + // Deallocate the memory + Py_DECREF(obj); + // obj is a now a dangling pointer + + // gh-109496: If Python is built in debug mode, Py_DECREF() must call + // _Py_NegativeRefcount() and abort Python. + Py_DECREF(obj); + + Py_RETURN_NONE; +} #endif @@ -3306,6 +3326,7 @@ static PyMethodDef TestMethods[] = { {"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL}, #ifdef Py_REF_DEBUG {"negative_refcount", negative_refcount, METH_NOARGS}, + {"decref_freed_object", decref_freed_object, METH_NOARGS}, #endif {"meth_varargs", meth_varargs, METH_VARARGS}, {"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS}, From b973ab3c3b333976d375c0cd4129cc3377769ea8 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Mon, 18 Sep 2023 21:47:01 +0200 Subject: [PATCH 0782/1206] Python 3.12.0rc3 --- Include/patchlevel.h | 4 +- Lib/pydoc_data/topics.py | 2 +- Misc/NEWS.d/3.12.0rc3.rst | 319 ++++++++++++++++++ ...-09-01-01-39-26.gh-issue-108740.JHExAQ.rst | 4 - ...-09-05-20-52-17.gh-issue-108959.6z45Sy.rst | 2 - ...-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst | 2 - ...-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst | 2 - ...-09-07-18-24-42.gh-issue-109118.yPXRAe.rst | 2 - ...-09-08-01-50-41.gh-issue-109114.adqgtb.rst | 3 - ...-09-09-12-49-46.gh-issue-109118.gx0X4h.rst | 2 - ...-09-11-15-51-55.gh-issue-109195.iwxmuo.rst | 4 - ...-09-12-15-45-49.gh-issue-109341.4V5bkm.rst | 1 - ...-09-13-08-42-45.gh-issue-109219.UiN8sc.rst | 2 - ...-09-13-19-16-51.gh-issue-105658.z2nR2u.rst | 2 - ...-09-13-21-04-04.gh-issue-109371.HPEJr8.rst | 1 - ...-09-18-15-35-08.gh-issue-109496.Kleoz3.rst | 5 - ...-03-19-09-39-31.gh-issue-102823.OzsOz0.rst | 2 - ...-09-06-06-17-23.gh-issue-108843.WJMhsS.rst | 1 - ...-09-06-19-33-41.gh-issue-108682.35Xnc5.rst | 2 - ...-04-05-06-45-20.gh-issue-103186.640Eg-.rst | 1 - ...-09-03-02-01-55.gh-issue-108834.iAwXzj.rst | 6 - ...-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst | 2 - ...-09-03-20-15-49.gh-issue-108834.Osvmhf.rst | 3 - ...-09-03-21-18-35.gh-issue-108851.CCuHyI.rst | 2 - ...-09-03-21-41-10.gh-issue-108851.xFTYOE.rst | 3 - ...-09-05-23-00-09.gh-issue-108962.R4NwuU.rst | 3 - ...3-09-06-15-36-51.gh-issue-91960.P3nD5v.rst | 7 - ...-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst | 6 - ...-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst | 5 - ...-09-10-22-32-20.gh-issue-109237.SvgKwD.rst | 4 - ...-09-13-05-58-09.gh-issue-104736.lA25Fu.rst | 4 - ...-09-14-22-58-47.gh-issue-109396.J1a4jR.rst | 3 - README.rst | 2 +- 33 files changed, 323 insertions(+), 90 deletions(-) create mode 100644 Misc/NEWS.d/3.12.0rc3.rst delete mode 100644 Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst delete mode 100644 Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index edb59b7968b219..0977888c475ec7 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 2 +#define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.12.0rc2+" +#define PY_VERSION "3.12.0rc3" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 3436f03b47e4ec..ca92aed373e4da 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Sep 5 23:56:33 2023 +# Autogenerated by Sphinx on Mon Sep 18 21:47:37 2023 # as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' diff --git a/Misc/NEWS.d/3.12.0rc3.rst b/Misc/NEWS.d/3.12.0rc3.rst new file mode 100644 index 00000000000000..8fe0dd298d56c4 --- /dev/null +++ b/Misc/NEWS.d/3.12.0rc3.rst @@ -0,0 +1,319 @@ +.. date: 2023-09-18-15-35-08 +.. gh-issue: 109496 +.. nonce: Kleoz3 +.. release date: 2023-09-18 +.. section: Core and Builtins + +On a Python built in debug mode, :c:func:`Py_DECREF()` now calls +``_Py_NegativeRefcount()`` if the object is a dangling pointer to +deallocated memory: memory filled with ``0xDD`` "dead byte" by the debug +hook on memory allocators. The fix is to check the reference count *before* +checking for ``_Py_IsImmortal()``. Patch by Victor Stinner. + +.. + +.. date: 2023-09-13-21-04-04 +.. gh-issue: 109371 +.. nonce: HPEJr8 +.. section: Core and Builtins + +Deopted instructions correctly for tool initialization and modified the +incorrect assertion in instrumentation, when a previous tool already sets +INSTRUCTION events + +.. + +.. date: 2023-09-13-19-16-51 +.. gh-issue: 105658 +.. nonce: z2nR2u +.. section: Core and Builtins + +Fix bug where the line trace of an except block ending with a conditional +includes an excess event with the line of the conditional expression. + +.. + +.. date: 2023-09-13-08-42-45 +.. gh-issue: 109219 +.. nonce: UiN8sc +.. section: Core and Builtins + +Fix compiling type param scopes that use a name which is also free in an +inner scope. + +.. + +.. date: 2023-09-12-15-45-49 +.. gh-issue: 109341 +.. nonce: 4V5bkm +.. section: Core and Builtins + +Fix crash when compiling an invalid AST involving a :class:`ast.TypeAlias`. + +.. + +.. date: 2023-09-11-15-51-55 +.. gh-issue: 109195 +.. nonce: iwxmuo +.. section: Core and Builtins + +Fix source location for the ``LOAD_*`` instruction preceding a +``LOAD_SUPER_ATTR`` to load the ``super`` global (or shadowing variable) so +that it encompasses only the name ``super`` and not the following +parentheses. + +.. + +.. date: 2023-09-09-12-49-46 +.. gh-issue: 109118 +.. nonce: gx0X4h +.. section: Core and Builtins + +Disallow nested scopes (lambdas, generator expressions, and comprehensions) +within PEP 695 annotation scopes that are nested within classes. + +.. + +.. date: 2023-09-08-01-50-41 +.. gh-issue: 109114 +.. nonce: adqgtb +.. section: Core and Builtins + +Relax the detection of the error message for invalid lambdas inside +f-strings to not search for arbitrary replacement fields to avoid false +positives. Patch by Pablo Galindo + +.. + +.. date: 2023-09-07-18-24-42 +.. gh-issue: 109118 +.. nonce: yPXRAe +.. section: Core and Builtins + +Fix interpreter crash when a NameError is raised inside the type parameters +of a generic class. + +.. + +.. date: 2023-09-06-22-50-25 +.. gh-issue: 108976 +.. nonce: MUKaIJ +.. section: Core and Builtins + +Fix crash that occurs after de-instrumenting a code object in a monitoring +callback. + +.. + +.. date: 2023-09-06-13-28-42 +.. gh-issue: 108732 +.. nonce: I6DkEQ +.. section: Core and Builtins + +Make iteration variables of module- and class-scoped comprehensions visible +to pdb and other tools that use ``frame.f_locals`` again. + +.. + +.. date: 2023-09-05-20-52-17 +.. gh-issue: 108959 +.. nonce: 6z45Sy +.. section: Core and Builtins + +Fix caret placement for error locations for subscript and binary operations +that involve non-semantic parentheses and spaces. Patch by Pablo Galindo + +.. + +.. date: 2023-09-06-19-33-41 +.. gh-issue: 108682 +.. nonce: 35Xnc5 +.. section: Library + +Enum: require ``names=()`` or ``type=...`` to create an empty enum using the +functional syntax. + +.. + +.. date: 2023-09-06-06-17-23 +.. gh-issue: 108843 +.. nonce: WJMhsS +.. section: Library + +Fix an issue in :func:`ast.unparse` when unparsing f-strings containing many +quote types. + +.. + +.. date: 2023-03-19-09-39-31 +.. gh-issue: 102823 +.. nonce: OzsOz0 +.. section: Documentation + +Document the return type of ``x // y`` when ``x`` and ``y`` have type +:class:`float`. + +.. + +.. date: 2023-09-14-22-58-47 +.. gh-issue: 109396 +.. nonce: J1a4jR +.. section: Tests + +Fix ``test_socket.test_hmac_sha1()`` in FIPS mode. Use a longer key: FIPS +mode requires at least of at least 112 bits. The previous key was only 32 +bits. Patch by Victor Stinner. + +.. + +.. date: 2023-09-13-05-58-09 +.. gh-issue: 104736 +.. nonce: lA25Fu +.. section: Tests + +Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora +38). Search patterns in gdb "bt" command output to detect when gdb fails to +retrieve the traceback. For example, skip a test if ``Backtrace stopped: +frame did not save the PC`` is found. Patch by Victor Stinner. + +.. + +.. date: 2023-09-10-22-32-20 +.. gh-issue: 109237 +.. nonce: SvgKwD +.. section: Tests + +Fix ``test_site.test_underpth_basic()`` when the working directory contains +at least one non-ASCII character: encode the ``._pth`` file to UTF-8 and +enable the UTF-8 Mode to use UTF-8 for the child process stdout. Patch by +Victor Stinner. + +.. + +.. date: 2023-09-10-19-59-57 +.. gh-issue: 109230 +.. nonce: SRNLFQ +.. section: Tests + +Fix ``test_pyexpat.test_exception()``: it can now be run from a directory +different than Python source code directory. Before, the test failed in this +case. Skip the test if Modules/pyexpat.c source is not available. Skip also +the test on Python implementations other than CPython. Patch by Victor +Stinner. + +.. + +.. date: 2023-09-06-18-27-53 +.. gh-issue: 109015 +.. nonce: 1dS1AQ +.. section: Tests + +Fix test_asyncio, test_imaplib and test_socket tests on FreeBSD if the TCP +blackhole is enabled (``sysctl net.inet.tcp.blackhole``). Skip the few tests +which failed with ``ETIMEDOUT`` which such non standard configuration. +Currently, the `FreeBSD GCP image enables TCP and UDP blackhole +`_ (``sysctl net.inet.tcp.blackhole=2`` +and ``sysctl net.inet.udp.blackhole=1``). Patch by Victor Stinner. + +.. + +.. date: 2023-09-06-15-36-51 +.. gh-issue: 91960 +.. nonce: P3nD5v +.. section: Tests + +Skip ``test_gdb`` if gdb is unable to retrieve Python frame objects: if a +frame is ````. When Python is built with "clang -Og", gdb can +fail to retrive the *frame* parameter of ``_PyEval_EvalFrameDefault()``. In +this case, tests like ``py_bt()`` are likely to fail. Without getting access +to Python frames, ``python-gdb.py`` is mostly clueless on retrieving the +Python traceback. Moreover, ``test_gdb`` is no longer skipped on macOS if +Python is built with Clang. Patch by Victor Stinner. + +.. + +.. date: 2023-09-05-23-00-09 +.. gh-issue: 108962 +.. nonce: R4NwuU +.. section: Tests + +Skip ``test_tempfile.test_flags()`` if ``chflags()`` fails with "OSError: +[Errno 45] Operation not supported" (ex: on FreeBSD 13). Patch by Victor +Stinner. + +.. + +.. date: 2023-09-03-21-41-10 +.. gh-issue: 108851 +.. nonce: xFTYOE +.. section: Tests + +Fix ``test_tomllib`` recursion tests for WASI buildbots: reduce the +recursion limit and compute the maximum nested array/dict depending on the +current available recursion limit. Patch by Victor Stinner. + +.. + +.. date: 2023-09-03-21-18-35 +.. gh-issue: 108851 +.. nonce: CCuHyI +.. section: Tests + +Add ``get_recursion_available()`` and ``get_recursion_depth()`` functions to +the :mod:`test.support` module. Patch by Victor Stinner. + +.. + +.. date: 2023-09-03-20-15-49 +.. gh-issue: 108834 +.. nonce: Osvmhf +.. section: Tests + +Add ``--fail-rerun option`` option to regrtest: if a test failed when then +passed when rerun in verbose mode, exit the process with exit code 2 +(error), instead of exit code 0 (success). Patch by Victor Stinner. + +.. + +.. date: 2023-09-03-06-17-12 +.. gh-issue: 108834 +.. nonce: fjV-CJ +.. section: Tests + +Rename regrtest ``--verbose2`` option (``-w``) to ``--rerun``. Keep +``--verbose2`` as a deprecated alias. Patch by Victor Stinner. + +.. + +.. date: 2023-09-03-02-01-55 +.. gh-issue: 108834 +.. nonce: iAwXzj +.. section: Tests + +When regrtest reruns failed tests in verbose mode (``./python -m test +--rerun``), tests are now rerun in fresh worker processes rather than being +executed in the main process. If a test does crash or is killed by a +timeout, the main process can detect and handle the killed worker process. +Tests are rerun in parallel if the ``-jN`` option is used to run tests in +parallel. Patch by Victor Stinner. + +.. + +.. date: 2023-04-05-06-45-20 +.. gh-issue: 103186 +.. nonce: 640Eg- +.. section: Tests + +Suppress and assert expected RuntimeWarnings in test_sys_settrace.py + +.. + +.. date: 2023-09-01-01-39-26 +.. gh-issue: 108740 +.. nonce: JHExAQ +.. section: Build + +Fix a race condition in ``make regen-all``. The ``deepfreeze.c`` source and +files generated by Argument Clinic are now generated or updated before +generating "global objects". Previously, some identifiers may miss depending +on the order in which these files were generated. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst b/Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst deleted file mode 100644 index 190d50387f339e..00000000000000 --- a/Misc/NEWS.d/next/Build/2023-09-01-01-39-26.gh-issue-108740.JHExAQ.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix a race condition in ``make regen-all``. The ``deepfreeze.c`` source and -files generated by Argument Clinic are now generated or updated before -generating "global objects". Previously, some identifiers may miss depending -on the order in which these files were generated. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst deleted file mode 100644 index 792bbc454f2b27..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-05-20-52-17.gh-issue-108959.6z45Sy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix caret placement for error locations for subscript and binary operations -that involve non-semantic parentheses and spaces. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst deleted file mode 100644 index 94a143b86b6708..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-06-13-28-42.gh-issue-108732.I6DkEQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make iteration variables of module- and class-scoped comprehensions visible -to pdb and other tools that use ``frame.f_locals`` again. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst deleted file mode 100644 index 4b89375f0f57ef..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-06-22-50-25.gh-issue-108976.MUKaIJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix crash that occurs after de-instrumenting a code object in a monitoring -callback. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst deleted file mode 100644 index f14fce4423896f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-24-42.gh-issue-109118.yPXRAe.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix interpreter crash when a NameError is raised inside the type parameters -of a generic class. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst deleted file mode 100644 index 3d95dd5d29450c..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-08-01-50-41.gh-issue-109114.adqgtb.rst +++ /dev/null @@ -1,3 +0,0 @@ -Relax the detection of the error message for invalid lambdas inside -f-strings to not search for arbitrary replacement fields to avoid false -positives. Patch by Pablo Galindo diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst deleted file mode 100644 index 87069c85870410..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-09-12-49-46.gh-issue-109118.gx0X4h.rst +++ /dev/null @@ -1,2 +0,0 @@ -Disallow nested scopes (lambdas, generator expressions, and comprehensions) -within PEP 695 annotation scopes that are nested within classes. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst deleted file mode 100644 index 5427232c2df9a0..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-11-15-51-55.gh-issue-109195.iwxmuo.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix source location for the ``LOAD_*`` instruction preceding a -``LOAD_SUPER_ATTR`` to load the ``super`` global (or shadowing variable) so -that it encompasses only the name ``super`` and not the following -parentheses. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst deleted file mode 100644 index 9e99ef7eb73273..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash when compiling an invalid AST involving a :class:`ast.TypeAlias`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst deleted file mode 100644 index 2c141f09d7e754..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-08-42-45.gh-issue-109219.UiN8sc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix compiling type param scopes that use a name which is also free in an -inner scope. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst deleted file mode 100644 index e95f5b84e8e187..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-19-16-51.gh-issue-105658.z2nR2u.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where the line trace of an except block ending with a conditional -includes an excess event with the line of the conditional expression. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst deleted file mode 100644 index 2fb18d5ae88347..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-13-21-04-04.gh-issue-109371.HPEJr8.rst +++ /dev/null @@ -1 +0,0 @@ -Deopted instructions correctly for tool initialization and modified the incorrect assertion in instrumentation, when a previous tool already sets INSTRUCTION events diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst deleted file mode 100644 index 51b2144fed7841..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-18-15-35-08.gh-issue-109496.Kleoz3.rst +++ /dev/null @@ -1,5 +0,0 @@ -On a Python built in debug mode, :c:func:`Py_DECREF()` now calls -``_Py_NegativeRefcount()`` if the object is a dangling pointer to -deallocated memory: memory filled with ``0xDD`` "dead byte" by the debug -hook on memory allocators. The fix is to check the reference count *before* -checking for ``_Py_IsImmortal()``. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst b/Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst deleted file mode 100644 index 1e32f3c89231c8..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-03-19-09-39-31.gh-issue-102823.OzsOz0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document the return type of ``x // y`` when ``x`` and ``y`` have type -:class:`float`. diff --git a/Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst b/Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst deleted file mode 100644 index 0f15761c14bb7d..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-09-06-06-17-23.gh-issue-108843.WJMhsS.rst +++ /dev/null @@ -1 +0,0 @@ -Fix an issue in :func:`ast.unparse` when unparsing f-strings containing many quote types. diff --git a/Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst b/Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst deleted file mode 100644 index 8c13d43ee9744b..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-09-06-19-33-41.gh-issue-108682.35Xnc5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Enum: require ``names=()`` or ``type=...`` to create an empty enum using -the functional syntax. diff --git a/Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst b/Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst deleted file mode 100644 index 2f596aa5f47bda..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-04-05-06-45-20.gh-issue-103186.640Eg-.rst +++ /dev/null @@ -1 +0,0 @@ -Suppress and assert expected RuntimeWarnings in test_sys_settrace.py diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst b/Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst deleted file mode 100644 index 43b9948db0075c..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-03-02-01-55.gh-issue-108834.iAwXzj.rst +++ /dev/null @@ -1,6 +0,0 @@ -When regrtest reruns failed tests in verbose mode (``./python -m test ---rerun``), tests are now rerun in fresh worker processes rather than being -executed in the main process. If a test does crash or is killed by a timeout, -the main process can detect and handle the killed worker process. Tests are -rerun in parallel if the ``-jN`` option is used to run tests in parallel. -Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst b/Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst deleted file mode 100644 index 734cc66aebee15..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-03-06-17-12.gh-issue-108834.fjV-CJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Rename regrtest ``--verbose2`` option (``-w``) to ``--rerun``. Keep -``--verbose2`` as a deprecated alias. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst b/Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst deleted file mode 100644 index 098861ffa30374..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-03-20-15-49.gh-issue-108834.Osvmhf.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add ``--fail-rerun option`` option to regrtest: if a test failed when then -passed when rerun in verbose mode, exit the process with exit code 2 -(error), instead of exit code 0 (success). Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst b/Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst deleted file mode 100644 index 7a5b3052af22f2..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-03-21-18-35.gh-issue-108851.CCuHyI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``get_recursion_available()`` and ``get_recursion_depth()`` functions to -the :mod:`test.support` module. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst b/Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst deleted file mode 100644 index b35aaebb410afb..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-03-21-41-10.gh-issue-108851.xFTYOE.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``test_tomllib`` recursion tests for WASI buildbots: reduce the recursion -limit and compute the maximum nested array/dict depending on the current -available recursion limit. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst b/Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst deleted file mode 100644 index 380fb20b8881b2..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-05-23-00-09.gh-issue-108962.R4NwuU.rst +++ /dev/null @@ -1,3 +0,0 @@ -Skip ``test_tempfile.test_flags()`` if ``chflags()`` fails with "OSError: -[Errno 45] Operation not supported" (ex: on FreeBSD 13). Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst b/Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst deleted file mode 100644 index 46472abf9802bc..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-06-15-36-51.gh-issue-91960.P3nD5v.rst +++ /dev/null @@ -1,7 +0,0 @@ -Skip ``test_gdb`` if gdb is unable to retrieve Python frame objects: if a -frame is ````. When Python is built with "clang -Og", gdb can -fail to retrive the *frame* parameter of ``_PyEval_EvalFrameDefault()``. In -this case, tests like ``py_bt()`` are likely to fail. Without getting access -to Python frames, ``python-gdb.py`` is mostly clueless on retrieving the -Python traceback. Moreover, ``test_gdb`` is no longer skipped on macOS if -Python is built with Clang. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst b/Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst deleted file mode 100644 index cb641be9312e1a..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-06-18-27-53.gh-issue-109015.1dS1AQ.rst +++ /dev/null @@ -1,6 +0,0 @@ -Fix test_asyncio, test_imaplib and test_socket tests on FreeBSD if the TCP -blackhole is enabled (``sysctl net.inet.tcp.blackhole``). Skip the few tests -which failed with ``ETIMEDOUT`` which such non standard configuration. -Currently, the `FreeBSD GCP image enables TCP and UDP blackhole -`_ (``sysctl net.inet.tcp.blackhole=2`` -and ``sysctl net.inet.udp.blackhole=1``). Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst b/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst deleted file mode 100644 index 18e1e85242005a..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-10-19-59-57.gh-issue-109230.SRNLFQ.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fix ``test_pyexpat.test_exception()``: it can now be run from a directory -different than Python source code directory. Before, the test failed in this -case. Skip the test if Modules/pyexpat.c source is not available. Skip also -the test on Python implementations other than CPython. Patch by Victor -Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst b/Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst deleted file mode 100644 index 1d762bbe1d2592..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-10-22-32-20.gh-issue-109237.SvgKwD.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix ``test_site.test_underpth_basic()`` when the working directory contains -at least one non-ASCII character: encode the ``._pth`` file to UTF-8 and -enable the UTF-8 Mode to use UTF-8 for the child process stdout. Patch by -Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst b/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst deleted file mode 100644 index 85c370fc87ac41..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora -38). Search patterns in gdb "bt" command output to detect when gdb fails to -retrieve the traceback. For example, skip a test if ``Backtrace stopped: frame -did not save the PC`` is found. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst b/Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst deleted file mode 100644 index 71150ecae76434..00000000000000 --- a/Misc/NEWS.d/next/Tests/2023-09-14-22-58-47.gh-issue-109396.J1a4jR.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix ``test_socket.test_hmac_sha1()`` in FIPS mode. Use a longer key: FIPS -mode requires at least of at least 112 bits. The previous key was only 32 -bits. Patch by Victor Stinner. diff --git a/README.rst b/README.rst index 1d0aee57123731..5390d2a6cf702f 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 release candidate 2 +This is Python version 3.12.0 release candidate 3 ================================================= .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From 4a0c118d6a4080efc538802f70ee79ce5c046e72 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Tue, 19 Sep 2023 13:02:42 +0200 Subject: [PATCH 0783/1206] Post 3.12.0rc3 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 0977888c475ec7..d962d241673e9c 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.12.0rc3" +#define PY_VERSION "3.12.0rc3+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 9e4ac21c46ac1e937cbfbe5603c6e71cc073a3ee Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 05:30:57 -0700 Subject: [PATCH 0784/1206] [3.12] GH-109209: Bump the minimum Sphinx version to 4.2 (GH-109210) (#109636) GH-109209: Bump the minimum Sphinx version to 4.2 (GH-109210) (cherry picked from commit 712cb173f8e1d02c625a40ae03bba57b0c1c032a) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- .github/workflows/reusable-docs.yml | 2 +- Doc/conf.py | 2 +- Doc/requirements-oldest-sphinx.txt | 10 ++++------ .../2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst | 1 + 4 files changed, 7 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 51efa54e8d1b3d..1c4fa4239c1e34 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -74,7 +74,7 @@ jobs: - name: 'Set up Python' uses: actions/setup-python@v4 with: - python-version: '3.11' # known to work with Sphinx 3.2 + python-version: '3.11' # known to work with Sphinx 4.2 cache: 'pip' cache-dependency-path: 'Doc/requirements-oldest-sphinx.txt' - name: 'Install build dependencies' diff --git a/Doc/conf.py b/Doc/conf.py index a8805bd4653a8a..9f01bd89a35d3c 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -66,7 +66,7 @@ highlight_language = 'python3' # Minimum version of sphinx required -needs_sphinx = '3.2' +needs_sphinx = '4.2' # Ignore any .rst files in the includes/ directory; # they're embedded in pages but not rendered individually. diff --git a/Doc/requirements-oldest-sphinx.txt b/Doc/requirements-oldest-sphinx.txt index 94611ca22f09fe..d3ef5bc17650ae 100644 --- a/Doc/requirements-oldest-sphinx.txt +++ b/Doc/requirements-oldest-sphinx.txt @@ -7,12 +7,10 @@ blurb python-docs-theme>=2022.1 # Generated from: -# pip install "Sphinx~=3.2.0" "docutils<0.17" "Jinja2<3" "MarkupSafe<2" +# pip install "Sphinx~=4.2.0" # pip freeze # -# Sphinx 3.2 comes from ``needs_sphinx = '3.2'`` in ``Doc/conf.py``. -# Docutils<0.17, Jinja2<3, and MarkupSafe<2 are additionally specified as -# Sphinx 3.2 is incompatible with newer releases of these packages. +# Sphinx 4.2 comes from ``needs_sphinx = '4.2'`` in ``Doc/conf.py``. alabaster==0.7.13 Babel==2.12.1 @@ -25,10 +23,10 @@ imagesize==1.4.1 Jinja2==2.11.3 MarkupSafe==1.1.1 packaging==23.1 -Pygments==2.15.1 +Pygments==2.16.1 requests==2.31.0 snowballstemmer==2.2.0 -Sphinx==3.2.1 +Sphinx==4.2.0 sphinxcontrib-applehelp==1.0.4 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 diff --git a/Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst b/Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst new file mode 100644 index 00000000000000..79cc0b72ec742f --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst @@ -0,0 +1 @@ +The minimum Sphinx version required for the documentation is now 4.2. From 0015a9aad55acc7d77f6c36ec3dc907828495845 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 05:43:40 -0700 Subject: [PATCH 0785/1206] [3.12] Misc itertool recipe improvements, mostly docstrings and comments (gh-109555) (#109572) (cherry picked from commit f2636d2c45aae0a04960dcfbc7d9a2a8a36ba3bc) Co-authored-by: Raymond Hettinger --- Doc/library/itertools.rst | 81 +++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 7fc1ae913cdba5..8a1c83aa3a2804 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -844,7 +844,7 @@ which incur interpreter overhead. return next(islice(iterable, n, None), default) def quantify(iterable, pred=bool): - "Count how many times the predicate is True" + "Given a predicate that returns True or False, count the True results." return sum(map(pred, iterable)) def all_equal(iterable): @@ -1028,36 +1028,6 @@ The following recipes have a more mathematical flavor: s = list(iterable) return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) - def sieve(n): - "Primes less than n." - # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 - if n > 2: - yield 2 - start = 3 - data = bytearray((0, 1)) * (n // 2) - limit = math.isqrt(n) + 1 - for p in iter_index(data, 1, start, limit): - yield from iter_index(data, 1, start, p*p) - data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) - start = p*p - yield from iter_index(data, 1, start) - - def factor(n): - "Prime factors of n." - # factor(99) --> 3 3 11 - # factor(1_000_000_000_000_007) --> 47 59 360620266859 - # factor(1_000_000_000_000_403) --> 1000000000000403 - for prime in sieve(math.isqrt(n) + 1): - while True: - if n % prime: - break - yield prime - n //= prime - if n == 1: - return - if n > 1: - yield n - def sum_of_squares(it): "Add up the squares of the input values." # sum_of_squares([10, 20, 30]) -> 1400 @@ -1075,14 +1045,21 @@ The following recipes have a more mathematical flavor: return batched(starmap(math.sumprod, product(m1, transpose(m2))), n) def convolve(signal, kernel): - """Linear convolution of two iterables. + """Discrete linear convolution of two iterables. + + The kernel is fully consumed before the calculations begin. + The signal is consumed lazily and can be infinite. + + Convolutions are mathematically commutative. + If the signal and kernel are swapped, + the output will be the same. Article: https://betterexplained.com/articles/intuitive-convolution/ Video: https://www.youtube.com/watch?v=KuXjwB4LzSA """ # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur) - # convolve(data, [1, -1]) --> 1st finite difference (1st derivative) - # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative) + # convolve(data, [1/2, 0, -1/2]) --> 1st derivative estimate + # convolve(data, [1, -2, 1]) --> 2nd derivative estimate kernel = tuple(kernel)[::-1] n = len(kernel) padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1)) @@ -1106,8 +1083,8 @@ The following recipes have a more mathematical flavor: # Evaluate x³ -4x² -17x + 60 at x = 2.5 # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 n = len(coefficients) - if n == 0: - return x * 0 # coerce zero to the type of x + if not n: + return type(x)(0) powers = map(pow, repeat(x), reversed(range(n))) return math.sumprod(coefficients, powers) @@ -1122,6 +1099,36 @@ The following recipes have a more mathematical flavor: powers = reversed(range(1, n)) return list(map(operator.mul, coefficients, powers)) + def sieve(n): + "Primes less than n." + # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 + if n > 2: + yield 2 + start = 3 + data = bytearray((0, 1)) * (n // 2) + limit = math.isqrt(n) + 1 + for p in iter_index(data, 1, start, limit): + yield from iter_index(data, 1, start, p*p) + data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) + start = p*p + yield from iter_index(data, 1, start) + + def factor(n): + "Prime factors of n." + # factor(99) --> 3 3 11 + # factor(1_000_000_000_000_007) --> 47 59 360620266859 + # factor(1_000_000_000_000_403) --> 1000000000000403 + for prime in sieve(math.isqrt(n) + 1): + while True: + if n % prime: + break + yield prime + n //= prime + if n == 1: + return + if n > 1: + yield n + def nth_combination(iterable, r, index): "Equivalent to list(combinations(iterable, r))[index]" pool = tuple(iterable) @@ -1297,7 +1304,7 @@ The following recipes have a more mathematical flavor: >>> polynomial_eval([], Fraction(2, 3)) Fraction(0, 1) >>> polynomial_eval([], Decimal('1.75')) - Decimal('0.00') + Decimal('0') >>> polynomial_eval([11], 7) == 11 True >>> polynomial_eval([11, 2], 7) == 11 * 7 + 2 From 6c8cbb3a7c272d7e108803a493fe530f97c28475 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 05:56:18 -0700 Subject: [PATCH 0786/1206] [3.12] GH-109190: Copyedit 3.12 What's New: PEP 709 (GH-109656) (#109681) (cherry picked from commit 22b70ca480f5a2d19d3123cd35ab968fa65f224d) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3bd9081c793b78..7f024f6f996044 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -247,14 +247,12 @@ PEP 709: Comprehension inlining Dictionary, list, and set comprehensions are now inlined, rather than creating a new single-use function object for each execution of the comprehension. This -speeds up execution of a comprehension by up to 2x. +speeds up execution of a comprehension by up to two times. +See :pep:`709` for further details. -Comprehension iteration variables remain isolated; they don't overwrite a +Comprehension iteration variables remain isolated and don't overwrite a variable of the same name in the outer scope, nor are they visible after the -comprehension. This isolation is now maintained via stack/locals manipulation, -not via separate function scope. - -Inlining does result in a few visible behavior changes: +comprehension. Inlining does result in a few visible behavior changes: * There is no longer a separate frame for the comprehension in tracebacks, and tracing/profiling no longer shows the comprehension as a function call. @@ -271,7 +269,7 @@ Inlining does result in a few visible behavior changes: create a list of keys to iterate over: ``keys = list(locals()); [k for k in keys]``. -Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`. +(Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`.) .. _whatsnew312-pep688: From 92f2e33ebceaf013031d9d96c814df3d702eabf8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 05:57:22 -0700 Subject: [PATCH 0787/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Typing PEPs (GH-109659) (#109684) (cherry picked from commit 11636788da9e5e64ceef2ac80df330e8170a8d08) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 7f024f6f996044..ed03c0c52b1936 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -332,7 +332,7 @@ See :mod:`sys.monitoring` for details. New Features Related to Type Hints ================================== -This section covers major changes affecting :pep:`484` type hints and +This section covers major changes affecting :pep:`type hints <484>` and the :mod:`typing` module. .. _whatsnew312-pep692: @@ -344,7 +344,7 @@ Typing ``**kwargs`` in a function signature as introduced by :pep:`484` allowed for valid annotations only in cases where all of the ``**kwargs`` were of the same type. -This PEP specifies a more precise way of typing ``**kwargs`` by relying on +:pep:`692` specifies a more precise way of typing ``**kwargs`` by relying on typed dictionaries:: from typing import TypedDict, Unpack @@ -388,6 +388,8 @@ Example:: def get_colour(self) -> str: return "red" +See :pep:`698` for more details. + (Contributed by Steven Troxler in :gh:`101561`.) .. _whatsnew312-pep695: @@ -433,8 +435,8 @@ parameters with bounds or constraints:: The value of type aliases and the bound and constraints of type variables created through this syntax are evaluated only on demand (see -:ref:`lazy-evaluation`). This means type aliases are able to refer to other -types defined later in the file. +:ref:`lazy evaluation `). This means type aliases are able to +refer to other types defined later in the file. Type parameters declared through a type parameter list are visible within the scope of the declaration and any nested scopes, but not in the outer scope. For From 5f685ed783bda5aa3ccaaf4f64b7a9ae4c5b796b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 05:58:04 -0700 Subject: [PATCH 0788/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Improved Error Messages (GH-109654) (#109687) (cherry picked from commit 16c24023c1f69f66d1e3313033be275a43329030) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ed03c0c52b1936..eb4e26aece67e7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -99,7 +99,7 @@ Improved Error Messages * Modules from the standard library are now potentially suggested as part of the error messages displayed by the interpreter when a :exc:`NameError` is - raised to the top level. Contributed by Pablo Galindo in :gh:`98254`. + raised to the top level. (Contributed by Pablo Galindo in :gh:`98254`.) >>> sys.version_info Traceback (most recent call last): @@ -110,7 +110,7 @@ Improved Error Messages Now if a :exc:`NameError` is raised in a method and the instance has an attribute that's exactly equal to the name in the exception, the suggestion will include ``self.`` instead of the closest match in the method - scope. Contributed by Pablo Galindo in :gh:`99139`. + scope. (Contributed by Pablo Galindo in :gh:`99139`.) >>> class A: ... def __init__(self): @@ -118,7 +118,7 @@ Improved Error Messages ... ... def foo(self): ... somethin = blech - + ... >>> A().foo() Traceback (most recent call last): File "", line 1 @@ -126,9 +126,8 @@ Improved Error Messages ^^^^^ NameError: name 'blech' is not defined. Did you mean: 'self.blech'? - * Improve the :exc:`SyntaxError` error message when the user types ``import x - from y`` instead of ``from y import x``. Contributed by Pablo Galindo in :gh:`98931`. + from y`` instead of ``from y import x``. (Contributed by Pablo Galindo in :gh:`98931`.) >>> import a.y.z from b.y.z Traceback (most recent call last): @@ -139,7 +138,7 @@ Improved Error Messages * :exc:`ImportError` exceptions raised from failed ``from import `` statements now include suggestions for the value of ```` based on the - available names in ````. Contributed by Pablo Galindo in :gh:`91058`. + available names in ````. (Contributed by Pablo Galindo in :gh:`91058`.) >>> from collections import chainmap Traceback (most recent call last): From 0030c80a5a990724b65c0e03b6ff9b5d11782716 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 05:59:52 -0700 Subject: [PATCH 0789/1206] [3.12] GH-109190: Copyedit 3.12 What's New: PEP 701 (GH-109655) (#109689) (cherry picked from commit e47d12e222507b1873a81f6955fdd3cfb8293b65) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index eb4e26aece67e7..2759c1cf5fb353 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -154,12 +154,13 @@ New Features PEP 701: Syntactic formalization of f-strings --------------------------------------------- -:pep:`701` lifts some restrictions on the usage of f-strings. Expression components -inside f-strings can now be any valid Python expression including backslashes, -unicode escaped sequences, multi-line expressions, comments and strings reusing the -same quote as the containing f-string. Let's cover these in detail: +:pep:`701` lifts some restrictions on the usage of :term:`f-strings `. +Expression components inside f-strings can now be any valid Python expression, +including strings reusing the same quote as the containing f-string, +multi-line expressions, comments, backslashes, and unicode escape sequences. +Let's cover these in detail: -* Quote reuse: in Python 3.11, reusing the same quotes as the containing f-string +* Quote reuse: in Python 3.11, reusing the same quotes as the enclosing f-string raises a :exc:`SyntaxError`, forcing the user to either use other available quotes (like using double quotes or triple quotes if the f-string uses single quotes). In Python 3.12, you can now do things like this: @@ -182,11 +183,12 @@ same quote as the containing f-string. Let's cover these in detail: >>> f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" '2' -* Multi-line expressions and comments: In Python 3.11, f-strings expressions - must be defined in a single line even if outside f-strings expressions could - span multiple lines (like literal lists being defined over multiple lines), - making them harder to read. In Python 3.12 you can now define expressions - spanning multiple lines and include comments on them: +* Multi-line expressions and comments: In Python 3.11, f-string expressions + must be defined in a single line, even if the expression within the f-string + could normally span multiple lines + (like literal lists being defined over multiple lines), + making them harder to read. In Python 3.12 you can now define f-strings + spanning multiple lines, and add inline comments: >>> f"This is the playlist: {", ".join([ ... 'Take me back to Eden', # My, my, those eyes like fire @@ -196,10 +198,10 @@ same quote as the containing f-string. Let's cover these in detail: 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism' * Backslashes and unicode characters: before Python 3.12 f-string expressions - couldn't contain any ``\`` character. This also affected unicode escaped - sequences (such as ``\N{snowman}``) as these contain the ``\N`` part that - previously could not be part of expression components of f-strings. Now, you - can define expressions like this: + couldn't contain any ``\`` character. This also affected unicode :ref:`escape + sequences ` (such as ``\N{snowman}``) as these contain + the ``\N`` part that previously could not be part of expression components of + f-strings. Now, you can define expressions like this: >>> print(f"This is the playlist: {"\n".join(songs)}") This is the playlist: Take me back to Eden @@ -211,7 +213,7 @@ same quote as the containing f-string. Let's cover these in detail: See :pep:`701` for more details. As a positive side-effect of how this feature has been implemented (by parsing f-strings -with the PEG parser (see :pep:`617`), now error messages for f-strings are more precise +with :pep:`the PEG parser <617>`, now error messages for f-strings are more precise and include the exact location of the error. For example, in Python 3.11, the following f-string raises a :exc:`SyntaxError`: From 0100ce5deb33a4696d869fc0275b2c19cbb6ad2a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:02:03 -0700 Subject: [PATCH 0790/1206] [3.12] GH-109190: Copyedit 3.12 What's New: tokenize (GH-109663) (#109715) (cherry picked from commit d3fe1a902fd060cc9fb41b768cc1e3ca5b52244d) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 2759c1cf5fb353..24c2ad8db059e3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -868,8 +868,8 @@ tkinter tokenize -------- -* The :mod:`tokenize` module includes the changes introduced in :pep:`701`. ( - Contributed by Marta Gómez Macías and Pablo Galindo in :gh:`102856`.) +* The :mod:`tokenize` module includes the changes introduced in :pep:`701`. + (Contributed by Marta Gómez Macías and Pablo Galindo in :gh:`102856`.) See :ref:`whatsnew312-porting-to-python312` for more information on the changes to the :mod:`tokenize` module. From b7801d7d1f7a26ec60e9719efcd183eaa7b1294a Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 22 Sep 2023 07:02:27 -0600 Subject: [PATCH 0791/1206] [3.12] GH-109190: Copyedit 3.12 What's New: calendar (GH-109662) (#109716) (cherry picked from commit 34ddcc3fa118168901fa0d3a69b3b5444fc2f943) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 24c2ad8db059e3..dbdac3fa525721 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -608,7 +608,8 @@ asyncio calendar -------- -* Add enums :data:`~calendar.Month` and :data:`~calendar.Day`. +* Add enums :data:`calendar.Month` and :data:`calendar.Day` + defining months of the year and days of the week. (Contributed by Prince Roshan in :gh:`103636`.) csv From 5796d69b00a307fc60aa9c8a541e0ab14a640201 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:21:52 -0700 Subject: [PATCH 0792/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Consistently show module names (GH-109664) (#109713) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 291401389bf76981688d82a0d7bb61fb8355ff14) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Åukasz Langa --- Doc/whatsnew/3.12.rst | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index dbdac3fa525721..62bfccda8e7025 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -570,18 +570,18 @@ asyncio making some use-cases 2x to 5x faster. (Contributed by Jacob Bower & Itamar O in :gh:`102853`, :gh:`104140`, and :gh:`104138`) -* On Linux, :mod:`asyncio` uses :class:`~asyncio.PidfdChildWatcher` by default +* On Linux, :mod:`asyncio` uses :class:`asyncio.PidfdChildWatcher` by default if :func:`os.pidfd_open` is available and functional instead of - :class:`~asyncio.ThreadedChildWatcher`. + :class:`asyncio.ThreadedChildWatcher`. (Contributed by Kumar Aditya in :gh:`98024`.) -* The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`, - :class:`~asyncio.FastChildWatcher`, :class:`~asyncio.AbstractChildWatcher` - and :class:`~asyncio.SafeChildWatcher` are deprecated and +* The child watcher classes :class:`asyncio.MultiLoopChildWatcher`, + :class:`asyncio.FastChildWatcher`, :class:`asyncio.AbstractChildWatcher` + and :class:`asyncio.SafeChildWatcher` are deprecated and will be removed in Python 3.14. It is recommended to not manually configure a child watcher as the event loop now uses the best available - child watcher for each platform (:class:`~asyncio.PidfdChildWatcher` - if supported and :class:`~asyncio.ThreadedChildWatcher` otherwise). + child watcher for each platform (:class:`asyncio.PidfdChildWatcher` + if supported and :class:`asyncio.ThreadedChildWatcher` otherwise). (Contributed by Kumar Aditya in :gh:`94597`.) * :func:`asyncio.set_child_watcher`, :func:`asyncio.get_child_watcher`, @@ -615,9 +615,9 @@ calendar csv --- -* Add :const:`~csv.QUOTE_NOTNULL` and :const:`~csv.QUOTE_STRINGS` flags to +* Add :const:`csv.QUOTE_NOTNULL` and :const:`csv.QUOTE_STRINGS` flags to provide finer grained control of ``None`` and empty strings by - :class:`~csv.writer` objects. + :class:`csv.writer` objects. dis --- @@ -627,7 +627,7 @@ dis :mod:`dis` module. :opcode:`HAVE_ARGUMENT` is still relevant to real opcodes, but it is not useful for pseudo instructions. Use the new - :data:`~dis.hasarg` collection instead. + :data:`dis.hasarg` collection instead. (Contributed by Irit Katriel in :gh:`94216`.) fractions @@ -713,11 +713,11 @@ pathlib ------- * Add support for subclassing :class:`pathlib.PurePath` and - :class:`~pathlib.Path`, plus their Posix- and Windows-specific variants. - Subclasses may override the :meth:`~pathlib.PurePath.with_segments` method + :class:`pathlib.Path`, plus their Posix- and Windows-specific variants. + Subclasses may override the :meth:`pathlib.PurePath.with_segments` method to pass information between path instances. -* Add :meth:`~pathlib.Path.walk` for walking the directory trees and generating +* Add :meth:`pathlib.Path.walk` for walking the directory trees and generating all file or directory names within them, similar to :func:`os.walk`. (Contributed by Stanislav Zmiev in :gh:`90385`.) @@ -786,20 +786,20 @@ sqlite3 * Add a :ref:`command-line interface `. (Contributed by Erlend E. Aasland in :gh:`77617`.) -* Add the :attr:`~sqlite3.Connection.autocommit` attribute - to :class:`~sqlite3.Connection` - and the *autocommit* parameter to :func:`~sqlite3.connect` +* Add the :attr:`sqlite3.Connection.autocommit` attribute + to :class:`sqlite3.Connection` + and the *autocommit* parameter to :func:`sqlite3.connect` to control :pep:`249`-compliant :ref:`transaction handling `. (Contributed by Erlend E. Aasland in :gh:`83638`.) * Add *entrypoint* keyword-only parameter to - :meth:`~sqlite3.Connection.load_extension`, + :meth:`sqlite3.Connection.load_extension`, for overriding the SQLite extension entry point. (Contributed by Erlend E. Aasland in :gh:`103015`.) -* Add :meth:`~sqlite3.Connection.getconfig` and - :meth:`~sqlite3.Connection.setconfig` to :class:`~sqlite3.Connection` +* Add :meth:`sqlite3.Connection.getconfig` and + :meth:`sqlite3.Connection.setconfig` to :class:`sqlite3.Connection` to make configuration changes to a database connection. (Contributed by Erlend E. Aasland in :gh:`103489`.) From 92a347997ffd18862704571fdb5db25cefba4247 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:26:58 -0700 Subject: [PATCH 0793/1206] [3.12] gh-109408: Move Windows builds from Azure Pipelines PR to GitHub Actions (GH-109569) (#109623) gh-109408: Move Windows builds from Azure Pipelines PR to GitHub Actions (GH-109569) (cherry picked from commit 14cdefa667f211401c9dfab33c4695e80b4e5e95) Co-authored-by: Hugo van Kemenade --- .azure-pipelines/pr.yml | 31 ------------------------------- .github/workflows/build.yml | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index daa2c7ca97df6a..335a4b407cb83c 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -26,34 +26,3 @@ jobs: steps: - template: ./posix-steps.yml - - -- job: Windows_PR_Tests - displayName: Windows PR Tests - dependsOn: Prebuild - condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true')) - - pool: - vmImage: windows-2022 - - strategy: - matrix: - win32: - arch: win32 - buildOpt: '-p Win32' - testRunTitle: '$(System.PullRequest.TargetBranch)-win32' - testRunPlatform: win32 - win64: - arch: amd64 - buildOpt: '-p x64' - testRunTitle: '$(System.PullRequest.TargetBranch)-win64' - testRunPlatform: win64 - winarm64: - arch: arm64 - buildOpt: '-p arm64' - maxParallel: 4 - - steps: - - template: ./windows-steps.yml - parameters: - targetBranch: $(System.PullRequest.TargetBranch) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index feddecf0a126f1..827df80ccd237a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,6 +161,8 @@ jobs: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - uses: actions/setup-python@v4 + with: + python-version: '3.x' - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Add ccache to PATH @@ -244,6 +246,21 @@ jobs: - name: Tests run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 + build_win_arm64: + name: 'Windows (arm64)' + runs-on: windows-latest + timeout-minutes: 60 + needs: check_source + if: needs.check_source.outputs.run_tests == 'true' + env: + IncludeUwp: 'true' + steps: + - uses: actions/checkout@v4 + - name: Register MSVC problem matcher + run: echo "::add-matcher::.github/problem-matchers/msvc.json" + - name: Build CPython + run: .\PCbuild\build.bat -e -d -p arm64 + build_macos: name: 'macOS' runs-on: macos-latest @@ -573,6 +590,7 @@ jobs: - check_generated_files - build_win32 - build_win_amd64 + - build_win_arm64 - build_macos - build_ubuntu - build_ubuntu_ssltests @@ -589,6 +607,7 @@ jobs: build_macos, build_ubuntu_ssltests, build_win32, + build_win_arm64, test_hypothesis, allowed-skips: >- ${{ @@ -604,6 +623,7 @@ jobs: check_generated_files, build_win32, build_win_amd64, + build_win_arm64, build_macos, build_ubuntu, build_ubuntu_ssltests, From 107e14820a3d3f158c908ecec506cacd4572b402 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:27:29 +0100 Subject: [PATCH 0794/1206] [3.12] gh-109627: duplicated small exit blocks need to be assigned jump target labels (#109630) (#109632) gh-109627: duplicated smalll exit blocks need to be assigned jump target labels (#109630) (cherry picked from commit 9ccf0545efd5bc5af5aa51774030c471d49a972b) --- Lib/test/test_compile.py | 9 ++++++++ ...-09-20-23-04-15.gh-issue-109627.xxe7De.rst | 2 ++ Python/flowgraph.c | 22 ++++++++++++++----- 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index fde52d40097f40..00fb61988505ee 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1216,6 +1216,15 @@ def f(x, y, z): return a self.assertEqual(f("x", "y", "z"), "y") + def test_duplicated_small_exit_block(self): + # See gh-109627 + def f(): + while element and something: + try: + return something + except: + pass + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst new file mode 100644 index 00000000000000..397d76e291419f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst @@ -0,0 +1,2 @@ +Fix bug where the compiler does not assign a new jump target label to a +duplicated small exit block. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 4fe581beb5fc63..0ea32345f9f9be 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -562,16 +562,23 @@ check_cfg(cfg_builder *g) { return SUCCESS; } -/* Calculate the actual jump target from the target_label */ static int -translate_jump_labels_to_targets(basicblock *entryblock) +get_max_label(basicblock *entryblock) { - int max_label = -1; + int lbl = -1; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_label.id > max_label) { - max_label = b->b_label.id; + if (b->b_label.id > lbl) { + lbl = b->b_label.id; } } + return lbl; +} + +/* Calculate the actual jump target from the target_label */ +static int +translate_jump_labels_to_targets(basicblock *entryblock) +{ + int max_label = get_max_label(entryblock); size_t mapsize = sizeof(basicblock *) * (max_label + 1); basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize); if (!label2block) { @@ -2035,6 +2042,7 @@ is_exit_without_lineno(basicblock *b) { return true; } + /* PEP 626 mandates that the f_lineno of a frame is correct * after a frame terminates. It would be prohibitively expensive * to continuously update the f_lineno field at runtime, @@ -2048,6 +2056,9 @@ static int duplicate_exits_without_lineno(cfg_builder *g) { assert(no_empty_basic_blocks(g)); + + int next_lbl = get_max_label(g->g_entryblock) + 1; + /* Copy all exit blocks without line number that are targets of a jump. */ basicblock *entryblock = g->g_entryblock; @@ -2066,6 +2077,7 @@ duplicate_exits_without_lineno(cfg_builder *g) target->b_predecessors--; new_target->b_predecessors = 1; new_target->b_next = target->b_next; + new_target->b_label.id = next_lbl++; target->b_next = new_target; } } From c03ed79f22655ff7b9576f66d405da6cf961d911 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 22 Sep 2023 07:28:02 -0600 Subject: [PATCH 0795/1206] [3.12] gh-106967: remove Release and Date fields from whatsnew for 3.12 (#109648) fix: remove Release and Date fields from whatsnew python/release-tools template for "What's New" page automatically adds a "Release" field and a "Date" field with the date set to "today", which becomes the day the docs are built, which is forever increasing. This is the topic of https://github.com/python/release-tools/issues/34 which is yet to be fixed. In the meantime, this commit fixes it manually. Co-authored-by: Oliver Rew --- Doc/whatsnew/3.12.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 62bfccda8e7025..894b80e9ffa19f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -3,8 +3,7 @@ What's New In Python 3.12 **************************** -:Release: |release| -:Date: |today| +:Editor: TBD .. Rules for maintenance: From 5030d386f8875d6049b78cc0c3325761ec272cb2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:29:16 -0700 Subject: [PATCH 0796/1206] [3.12] GH-109190: Copyedit 3.12 What's New: bytecode (LOAD_METHOD) (GH-109665) (#109728) GH-109190: Copyedit 3.12 What's New: bytecode (LOAD_METHOD) (GH-109665) (cherry picked from commit d9415f6a45c2c4163b593713ef765cb2a60f8aa7) bytecode: suppress reference to removed LOAD_METHOD Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 894b80e9ffa19f..d38c65b5a1b82c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1000,9 +1000,9 @@ Optimizations CPython bytecode changes ======================== -* Remove the :opcode:`LOAD_METHOD` instruction. It has been merged into +* Remove the :opcode:`!LOAD_METHOD` instruction. It has been merged into :opcode:`LOAD_ATTR`. :opcode:`LOAD_ATTR` will now behave like the old - :opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set. + :opcode:`!LOAD_METHOD` instruction if the low bit of its oparg is set. (Contributed by Ken Jin in :gh:`93429`.) * Remove the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` From 388f90a6733df2fb8b6341dff70b56b609631a04 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:29:36 -0700 Subject: [PATCH 0797/1206] [3.12] GH-109190: Copyedit 3.12 What's New: PEP 684 (GH-109657) (#109729) GH-109190: Copyedit 3.12 What's New: PEP 684 (GH-109657) (cherry picked from commit e94a2232eac07eb526ec93ef01699513cf9b0fa3) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d38c65b5a1b82c..ac9e1fbb9e8ddb 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -291,9 +291,11 @@ can be used to customize buffer creation. PEP 684: A Per-Interpreter GIL ------------------------------ -Sub-interpreters may now be created with a unique GIL per interpreter. +:pep:`684` introduces a per-interpreter :term:`GIL `, +so that sub-interpreters may now be created with a unique GIL per interpreter. This allows Python programs to take full advantage of multiple CPU -cores. +cores. This is currently only available through the C-API, +though a Python API is :pep:`anticipated for 3.13 <554>`. Use the new :c:func:`Py_NewInterpreterFromConfig` function to create an interpreter with its own GIL:: @@ -312,8 +314,6 @@ create an interpreter with its own GIL:: For further examples how to use the C-API for sub-interpreters with a per-interpreter GIL, see :source:`Modules/_xxsubinterpretersmodule.c`. -A Python API is anticipated for 3.13. (See :pep:`554`.) - (Contributed by Eric Snow in :gh:`104210`, etc.) .. _whatsnew312-pep669: From 66a8777c7eb21bb0b0c3d85eb1b5ea6970f53fae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:29:59 -0700 Subject: [PATCH 0798/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Other Language Changes (GH-109660) (#109730) GH-109190: Copyedit 3.12 What's New: Other Language Changes (GH-109660) (cherry picked from commit cade5960ae5949899bccbec3af72b0287d0f6749) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ac9e1fbb9e8ddb..1d099c32cb1ad9 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -459,12 +459,12 @@ and others in :gh:`103764`.) Other Language Changes ====================== -* Add :ref:`perf_profiling` through the new - environment variable :envvar:`PYTHONPERFSUPPORT`, - the new command-line option :option:`-X perf <-X>`, +* Add :ref:`support for the perf profiler ` through the new + environment variable :envvar:`PYTHONPERFSUPPORT` + and command-line option :option:`-X perf <-X>`, as well as the new :func:`sys.activate_stack_trampoline`, :func:`sys.deactivate_stack_trampoline`, - and :func:`sys.is_stack_trampoline_active` APIs. + and :func:`sys.is_stack_trampoline_active` functions. (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) @@ -473,7 +473,7 @@ Other Language Changes have a new a *filter* argument that allows limiting tar features than may be surprising or dangerous, such as creating files outside the destination directory. - See :ref:`tarfile-extraction-filter` for details. + See :ref:`tarfile extraction filters ` for details. In Python 3.14, the default will switch to ``'data'``. (Contributed by Petr Viktorin in :pep:`706`.) @@ -501,8 +501,8 @@ Other Language Changes * A backslash-character pair that is not a valid escape sequence now generates a :exc:`SyntaxWarning`, instead of :exc:`DeprecationWarning`. For example, ``re.compile("\d+\.\d+")`` now emits a :exc:`SyntaxWarning` - (``"\d"`` is an invalid escape sequence), use raw strings for regular - expression: ``re.compile(r"\d+\.\d+")``. + (``"\d"`` is an invalid escape sequence, use raw strings for regular + expression: ``re.compile(r"\d+\.\d+")``). In a future Python version, :exc:`SyntaxError` will eventually be raised, instead of :exc:`SyntaxWarning`. (Contributed by Victor Stinner in :gh:`98401`.) @@ -531,7 +531,7 @@ Other Language Changes floats or mixed ints and floats. (Contributed by Raymond Hettinger in :gh:`100425`.) -* Exceptions raised in a typeobject's ``__set_name__`` method are no longer +* Exceptions raised in a class or type's ``__set_name__`` method are no longer wrapped by a :exc:`RuntimeError`. Context information is added to the exception as a :pep:`678` note. (Contributed by Irit Katriel in :gh:`77757`.) From 8985a77bf6bd90ac31dfc4ce55770c08fc0ecdf6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 07:02:26 -0700 Subject: [PATCH 0799/1206] [3.12] GH-109190: Copyedit 3.12 What's New: PEP 669 (GH-109658) (#109732) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GH-109190: Copyedit 3.12 What's New: PEP 669 (GH-109658) (cherry picked from commit 168c3a8a893fcb42f8a4d078a1e9a6bd7ad65253) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Åukasz Langa Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 1d099c32cb1ad9..adbcdd06babe4d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -321,13 +321,15 @@ per-interpreter GIL, see :source:`Modules/_xxsubinterpretersmodule.c`. PEP 669: Low impact monitoring for CPython ------------------------------------------ -CPython 3.12 now supports the ability to monitor calls, -returns, lines, exceptions and other events using instrumentation. +:pep:`669` defines a new :mod:`API ` for profilers, +debuggers, and other tools to monitor events in CPython. +It covers a wide range of events, including calls, +returns, lines, exceptions, jumps, and more. This means that you only pay for what you use, providing support for near-zero overhead debuggers and coverage tools. - See :mod:`sys.monitoring` for details. +(Contributed by Mark Shannon in :gh:`103083`.) New Features Related to Type Hints ================================== From 284de30f50f0151005b589cf40ef53670a18bfc5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 07:03:00 -0700 Subject: [PATCH 0800/1206] [3.12] GH-109190: Copyedit 3.12 What's New: asyncio (GH-109661) (#109733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GH-109190: Copyedit 3.12 What's New: asyncio (GH-109661) (cherry picked from commit c32abf1f21c4bd32abcefe4d601611b152568961) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Åukasz Langa Co-authored-by: Itamar Oren Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index adbcdd06babe4d..1b3b0c2f7da0dc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -569,7 +569,7 @@ asyncio * Added :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory` functions to allow opting an event loop in to eager task execution, making some use-cases 2x to 5x faster. - (Contributed by Jacob Bower & Itamar O in :gh:`102853`, :gh:`104140`, and :gh:`104138`) + (Contributed by Jacob Bower & Itamar Oren in :gh:`102853`, :gh:`104140`, and :gh:`104138`) * On Linux, :mod:`asyncio` uses :class:`asyncio.PidfdChildWatcher` by default if :func:`os.pidfd_open` is available and functional instead of @@ -596,7 +596,7 @@ asyncio (Contributed by Kumar Aditya in :gh:`99388`.) * Add C implementation of :func:`asyncio.current_task` for 4x-6x speedup. - (Contributed by Itamar Ostricher and Pranav Thulasiram Bhat in :gh:`100344`.) + (Contributed by Itamar Oren and Pranav Thulasiram Bhat in :gh:`100344`.) * :func:`asyncio.iscoroutine` now returns ``False`` for generators as :mod:`asyncio` does not support legacy generator-based coroutines. @@ -987,7 +987,7 @@ Optimizations (Contributed by Serhiy Storchaka in :gh:`91524`.) * Speed up :class:`asyncio.Task` creation by deferring expensive string formatting. - (Contributed by Itamar O in :gh:`103793`.) + (Contributed by Itamar Oren in :gh:`103793`.) * The :func:`tokenize.tokenize` and :func:`tokenize.generate_tokens` functions are up to 64% faster as a side effect of the changes required to cover :pep:`701` in @@ -1841,7 +1841,7 @@ New Features * Added :c:func:`PyCode_AddWatcher` and :c:func:`PyCode_ClearWatcher` APIs to register callbacks to receive notification on creation and destruction of code objects. - (Contributed by Itamar Ostricher in :gh:`91054`.) + (Contributed by Itamar Oren in :gh:`91054`.) * Add :c:func:`PyFrame_GetVar` and :c:func:`PyFrame_GetVarString` functions to get a frame variable by its name. From f6287bd46fce5d9246503ebccac0536f229bd269 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 22 Sep 2023 09:53:20 -0700 Subject: [PATCH 0801/1206] [3.12] ACKS: Fix ordering; Correct Itamar Oren's surname; Add Adam Turner (GH-109737) (#109741) (cherry picked from commit 3e8fcb7df74248530c4280915c77e69811f69c3f) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Misc/ACKS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS index d16ec34a1f0906..ff549dc6b78b6b 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -502,6 +502,7 @@ Daniel Ellis Phil Elson David Ely Victor van den Elzen +Vlad Emelianov Jeff Epler Tom Epperly Gökcen Eraslan @@ -1329,6 +1330,7 @@ Ethan Onstott Ken Jin Ooi Piet van Oostrum Tomas Oppelstrup +Itamar Oren Jason Orendorff Yan "yyyyyyyan" Orestes Bastien Orivel @@ -1339,7 +1341,6 @@ Michele Orrù Tomáš Orsava Oleg Oshmyan Denis Osipov -Itamar Ostricher Denis S. Otkidach Peter Otten Michael Otteneder @@ -1865,6 +1866,7 @@ Steven Troxler Brent Tubbs Anthony Tuininga Erno Tukia +Adam Turner David Turner Stephen Turner Itamar Turner-Trauring @@ -2072,7 +2074,5 @@ Jelle Zijlstra Gennadiy Zlobin Doug Zongker Peter Ã…strand -Vlad Emelianov -Andrey Doroschenko (Entries should be added in rough alphabetical order by last names) From 633bd6e428fa9d2f1c868a3b02b466f69151d1bf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 Sep 2023 04:51:30 -0700 Subject: [PATCH 0802/1206] [3.12] gh-109719: Fix missing jump target labels when compiler reorders cold/warm blocks (GH-109734) (#109749) gh-109719: Fix missing jump target labels when compiler reorders cold/warm blocks (GH-109734) (cherry picked from commit 7c553991724d8d537f8444db73f016008753d77a) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/test/test_compile.py | 11 +++++++++++ .../2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst | 1 + Python/flowgraph.c | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 00fb61988505ee..2e5763eb3d61e9 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1225,6 +1225,17 @@ def f(): except: pass + def test_cold_block_moved_to_end(self): + # See gh-109719 + def f(): + while name: + try: + break + except: + pass + else: + 1 if 1 else 1 + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst new file mode 100644 index 00000000000000..83be54c9ca793e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst @@ -0,0 +1 @@ +Fix missing jump target labels when compiler reorders cold/warm blocks. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 0ea32345f9f9be..d19fe686d01c94 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1945,6 +1945,8 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { } RETURN_IF_ERROR(mark_cold(entryblock)); + int next_lbl = get_max_label(g->g_entryblock) + 1; + /* If we have a cold block with fallthrough to a warm block, add */ /* an explicit jump instead of fallthrough */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { @@ -1953,6 +1955,9 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { if (explicit_jump == NULL) { return ERROR; } + if (!IS_LABEL(b->b_next->b_label)) { + b->b_next->b_label.id = next_lbl++; + } basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION); explicit_jump->b_cold = 1; explicit_jump->b_next = b->b_next; From 722660b48bc380d042ad2e67bf97742b656da4ba Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 24 Sep 2023 05:52:26 -0600 Subject: [PATCH 0803/1206] [3.12] Docs: Update Donghee Na's name (GH-109743) (#109758) * Update Donghee Na's name in Docs/ * Update Donghee Na's name in Misc/ACKS * Update Donghee Na's name in Misc/NEWS.d/ --- Doc/whatsnew/3.10.rst | 8 ++++---- Doc/whatsnew/3.11.rst | 18 +++++++++--------- Doc/whatsnew/3.12.rst | 8 ++++---- Doc/whatsnew/3.8.rst | 4 ++-- Doc/whatsnew/3.9.rst | 32 ++++++++++++++++---------------- Misc/ACKS | 2 +- Misc/NEWS.d/3.10.0a1.rst | 12 ++++++------ Misc/NEWS.d/3.10.0a2.rst | 4 ++-- Misc/NEWS.d/3.10.0a3.rst | 2 +- Misc/NEWS.d/3.10.0a4.rst | 4 ++-- Misc/NEWS.d/3.10.0a6.rst | 2 +- Misc/NEWS.d/3.10.0a7.rst | 4 ++-- Misc/NEWS.d/3.10.0b1.rst | 2 +- Misc/NEWS.d/3.11.0a1.rst | 24 ++++++++++++------------ Misc/NEWS.d/3.11.0a2.rst | 10 +++++----- Misc/NEWS.d/3.11.0a3.rst | 2 +- Misc/NEWS.d/3.11.0a5.rst | 2 +- Misc/NEWS.d/3.11.0a6.rst | 6 +++--- Misc/NEWS.d/3.11.0a7.rst | 4 ++-- Misc/NEWS.d/3.11.0b1.rst | 2 +- Misc/NEWS.d/3.12.0a1.rst | 14 +++++++------- Misc/NEWS.d/3.12.0a2.rst | 2 +- Misc/NEWS.d/3.12.0a3.rst | 2 +- Misc/NEWS.d/3.12.0a4.rst | 2 +- Misc/NEWS.d/3.12.0a5.rst | 6 +++--- Misc/NEWS.d/3.12.0a6.rst | 2 +- Misc/NEWS.d/3.12.0b1.rst | 8 ++++---- Misc/NEWS.d/3.12.0rc2.rst | 2 +- Misc/NEWS.d/3.5.4.rst | 2 +- Misc/NEWS.d/3.5.4rc1.rst | 2 +- Misc/NEWS.d/3.6.2rc1.rst | 6 +++--- Misc/NEWS.d/3.6.3rc1.rst | 2 +- Misc/NEWS.d/3.6.6rc1.rst | 2 +- Misc/NEWS.d/3.7.0a1.rst | 8 ++++---- Misc/NEWS.d/3.7.0a3.rst | 4 ++-- Misc/NEWS.d/3.7.0b5.rst | 2 +- Misc/NEWS.d/3.8.0a1.rst | 4 ++-- Misc/NEWS.d/3.9.0a1.rst | 20 ++++++++++---------- Misc/NEWS.d/3.9.0a3.rst | 16 ++++++++-------- Misc/NEWS.d/3.9.0a4.rst | 6 +++--- Misc/NEWS.d/3.9.0a5.rst | 14 +++++++------- Misc/NEWS.d/3.9.0b1.rst | 6 +++--- 42 files changed, 142 insertions(+), 142 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 47a6f3e1c0839b..42e54fbad2092f 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -878,7 +878,7 @@ Other Language Changes (Contributed by Raymond Hettinger in :issue:`43475`.) * A :exc:`SyntaxError` (instead of a :exc:`NameError`) will be raised when deleting - the :const:`__debug__` constant. (Contributed by Dong-hee Na in :issue:`45000`.) + the :const:`__debug__` constant. (Contributed by Donghee Na in :issue:`45000`.) * :exc:`SyntaxError` exceptions now have ``end_lineno`` and ``end_offset`` attributes. They will be ``None`` if not determined. @@ -1255,7 +1255,7 @@ pipe. (Contributed by Pablo Galindo in :issue:`41625`.) Add :const:`~os.O_EVTONLY`, :const:`~os.O_FSYNC`, :const:`~os.O_SYMLINK` and :const:`~os.O_NOFOLLOW_ANY` for macOS. -(Contributed by Dong-hee Na in :issue:`43106`.) +(Contributed by Donghee Na in :issue:`43106`.) os.path ------- @@ -1582,7 +1582,7 @@ Optimizations * The following built-in functions now support the faster :pep:`590` vectorcall calling convention: :func:`map`, :func:`filter`, :func:`reversed`, :func:`bool` and :func:`float`. - (Contributed by Dong-hee Na and Jeroen Demeyer in :issue:`43575`, :issue:`43287`, :issue:`41922`, :issue:`41873` and :issue:`41870`.) + (Contributed by Donghee Na and Jeroen Demeyer in :issue:`43575`, :issue:`43287`, :issue:`41922`, :issue:`41873` and :issue:`41870`.) * :class:`BZ2File` performance is improved by removing internal ``RLock``. This makes :class:`BZ2File` thread unsafe in the face of multiple simultaneous @@ -1817,7 +1817,7 @@ Removed scheduled to be removed in Python 3.6, but such removals were delayed until after Python 2.7 EOL. Existing users should copy whatever classes they use into their code. - (Contributed by Dong-hee Na and Terry J. Reedy in :issue:`42299`.) + (Contributed by Donghee Na and Terry J. Reedy in :issue:`42299`.) * Removed the :c:func:`!PyModule_GetWarningsModule` function that was useless now due to the :mod:`!_warnings` module was converted to a builtin module in 2.6. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 394cb78400043f..7970591424e33f 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -499,7 +499,7 @@ Other CPython Implementation Changes * The special methods :meth:`~object.__complex__` for :class:`complex` and :meth:`~object.__bytes__` for :class:`bytes` are implemented to support the :class:`typing.SupportsComplex` and :class:`typing.SupportsBytes` protocols. - (Contributed by Mark Dickinson and Dong-hee Na in :issue:`24234`.) + (Contributed by Mark Dickinson and Donghee Na in :issue:`24234`.) * ``siphash13`` is added as a new internal hashing algorithm. It has similar security properties as ``siphash24``, @@ -897,7 +897,7 @@ os * On Windows, :func:`os.urandom` now uses ``BCryptGenRandom()``, instead of ``CryptGenRandom()`` which is deprecated. - (Contributed by Dong-hee Na in :issue:`44611`.) + (Contributed by Donghee Na in :issue:`44611`.) .. _whatsnew311-pathlib: @@ -1089,7 +1089,7 @@ time `_ which has a resolution of 100 nanoseconds (10\ :sup:`-7` seconds). Previously, it had a resolution of 1 millisecond (10\ :sup:`-3` seconds). - (Contributed by Benjamin SzÅ‘ke, Dong-hee Na, Eryk Sun and Victor Stinner in :issue:`21302` and :issue:`45429`.) + (Contributed by Benjamin SzÅ‘ke, Donghee Na, Eryk Sun and Victor Stinner in :issue:`21302` and :issue:`45429`.) .. _whatsnew311-tkinter: @@ -1305,7 +1305,7 @@ This section covers specific optimizations independent of the * :func:`unicodedata.normalize` now normalizes pure-ASCII strings in constant time. - (Contributed by Dong-hee Na in :issue:`44987`.) + (Contributed by Donghee Na in :issue:`44987`.) .. _whatsnew311-faster-cpython: @@ -1452,7 +1452,7 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) | | | | (up to) | | +===============+====================+=======================================================+===================+===================+ | Binary | ``x + x`` | Binary add, multiply and subtract for common types | 10% | Mark Shannon, | -| operations | | such as :class:`int`, :class:`float` and :class:`str` | | Dong-hee Na, | +| operations | | such as :class:`int`, :class:`float` and :class:`str` | | Donghee Na, | | | ``x - x`` | take custom fast paths for their underlying types. | | Brandt Bucher, | | | | | | Dennis Sweeney | | | ``x * x`` | | | | @@ -1839,7 +1839,7 @@ Standard Library * :class:`!webbrowser.MacOSX` is deprecated and will be removed in Python 3.13. It is untested, undocumented, and not used by :mod:`webbrowser` itself. - (Contributed by Dong-hee Na in :issue:`42255`.) + (Contributed by Donghee Na in :issue:`42255`.) * The behavior of returning a value from a :class:`~unittest.TestCase` and :class:`~unittest.IsolatedAsyncioTestCase` test methods (other than the @@ -1984,7 +1984,7 @@ Removed C APIs are :ref:`listed separately `. :meth:`!NullTranslations.set_output_charset` methods, and the *codeset* parameter of :func:`!translation` and :func:`!install`, since they are only used for the :func:`!l*gettext` functions. - (Contributed by Dong-hee Na and Serhiy Storchaka in :issue:`44235`.) + (Contributed by Donghee Na and Serhiy Storchaka in :issue:`44235`.) * Removed from the :mod:`inspect` module: @@ -2009,7 +2009,7 @@ Removed C APIs are :ref:`listed separately `. * Removed the :class:`!MailmanProxy` class in the :mod:`smtpd` module, as it is unusable without the external :mod:`!mailman` package. - (Contributed by Dong-hee Na in :issue:`35800`.) + (Contributed by Donghee Na in :issue:`35800`.) * Removed the deprecated :meth:`!split` method of :class:`!_tkinter.TkappType`. (Contributed by Erlend E. Aasland in :issue:`38371`.) @@ -2151,7 +2151,7 @@ Build Changes * CPython can now be built with the `ThinLTO `_ option via passing ``thin`` to :option:`--with-lto`, i.e. ``--with-lto=thin``. - (Contributed by Dong-hee Na and Brett Holman in :issue:`44340`.) + (Contributed by Donghee Na and Brett Holman in :issue:`44340`.) * Freelists for object structs can now be disabled. A new :program:`configure` option :option:`--without-freelists` can be used to disable all freelists diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 1b3b0c2f7da0dc..14beb3e09044e1 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -484,7 +484,7 @@ Other Language Changes (Contributed by Serhiy Storchaka in :gh:`87995`.) * :class:`memoryview` now supports the half-float type (the "e" format code). - (Contributed by Dong-hee Na and Antoine Pitrou in :gh:`90751`.) + (Contributed by Donghee Na and Antoine Pitrou in :gh:`90751`.) * The parser now raises :exc:`SyntaxError` when parsing source code containing null bytes. (Contributed by Pablo Galindo in :gh:`96670`.) @@ -979,7 +979,7 @@ Optimizations * Added experimental support for using the BOLT binary optimizer in the build process, which improves performance by 1-5%. - (Contributed by Kevin Modzelewski in :gh:`90536` and tuned by Dong-hee Na in :gh:`101525`) + (Contributed by Kevin Modzelewski in :gh:`90536` and tuned by Donghee Na in :gh:`101525`) * Speed up the regular expression substitution (functions :func:`re.sub` and :func:`re.subn` and corresponding :class:`!re.Pattern` methods) for @@ -1636,7 +1636,7 @@ Changes in the Python API so only a very small set of users might be affected. This change helps with interpreter isolation. Furthermore, :mod:`syslog` is a wrapper around process-global resources, which are best managed from the main interpreter. - (Contributed by Dong-hee Na in :gh:`99127`.) + (Contributed by Donghee Na in :gh:`99127`.) * The undocumented locking behavior of :func:`~functools.cached_property` is removed, because it locked across all instances of the class, leading to high @@ -1710,7 +1710,7 @@ Build Changes * CPython now uses the ThinLTO option as the default link time optimization policy if the Clang compiler accepts the flag. - (Contributed by Dong-hee Na in :gh:`89536`.) + (Contributed by Donghee Na in :gh:`89536`.) * Add ``COMPILEALL_OPTS`` variable in Makefile to override :mod:`compileall` options (default: ``-j0``) in ``make install``. Also merged the 3 diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 329fe8cb410dab..5b667851c79942 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -947,7 +947,7 @@ This made it difficult to update, experiment with, or teach the various logging configuration options using the interactive prompt or a Jupyter notebook. -(Suggested by Raymond Hettinger, implemented by Dong-hee Na, and +(Suggested by Raymond Hettinger, implemented by Donghee Na, and reviewed by Vinay Sajip in :issue:`33897`.) @@ -1714,7 +1714,7 @@ Deprecated * The :meth:`~threading.Thread.isAlive()` method of :class:`threading.Thread` has been deprecated. - (Contributed by Dong-hee Na in :issue:`35283`.) + (Contributed by Donghee Na in :issue:`35283`.) * Many builtin and extension functions that take integer arguments will now emit a deprecation warning for :class:`~decimal.Decimal`\ s, diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 6829970900930a..fb73eaf59d5dac 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -415,7 +415,7 @@ datetime The :meth:`~datetime.date.isocalendar()` of :class:`datetime.date` and :meth:`~datetime.datetime.isocalendar()` of :class:`datetime.datetime` methods now returns a :func:`~collections.namedtuple` instead of a :class:`tuple`. -(Contributed by Dong-hee Na in :issue:`24416`.) +(Contributed by Donghee Na in :issue:`24416`.) distutils --------- @@ -429,14 +429,14 @@ fcntl Added constants :const:`~fcntl.F_OFD_GETLK`, :const:`~fcntl.F_OFD_SETLK` and :const:`~fcntl.F_OFD_SETLKW`. -(Contributed by Dong-hee Na in :issue:`38602`.) +(Contributed by Donghee Na in :issue:`38602`.) ftplib ------- :class:`~ftplib.FTP` and :class:`~ftplib.FTP_TLS` now raise a :class:`ValueError` if the given timeout for their constructor is zero to prevent the creation of -a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.) +a non-blocking socket. (Contributed by Donghee Na in :issue:`39259`.) gc -- @@ -468,7 +468,7 @@ http ---- HTTP status codes ``103 EARLY_HINTS``, ``418 IM_A_TEAPOT`` and ``425 TOO_EARLY`` are added to -:class:`http.HTTPStatus`. (Contributed by Dong-hee Na in :issue:`39509` and Ross Rhodes in :issue:`39507`.) +:class:`http.HTTPStatus`. (Contributed by Donghee Na in :issue:`39509` and Ross Rhodes in :issue:`39507`.) IDLE and idlelib ---------------- @@ -509,14 +509,14 @@ an optional *timeout* parameter for their constructors. Also, the :meth:`~imaplib.IMAP4.open` method now has an optional *timeout* parameter with this change. The overridden methods of :class:`~imaplib.IMAP4_SSL` and :class:`~imaplib.IMAP4_stream` were applied to this change. -(Contributed by Dong-hee Na in :issue:`38615`.) +(Contributed by Donghee Na in :issue:`38615`.) :meth:`imaplib.IMAP4.unselect` is added. :meth:`imaplib.IMAP4.unselect` frees server's resources associated with the selected mailbox and returns the server to the authenticated state. This command performs the same actions as :meth:`imaplib.IMAP4.close`, except that no messages are permanently removed from the currently -selected mailbox. (Contributed by Dong-hee Na in :issue:`40375`.) +selected mailbox. (Contributed by Donghee Na in :issue:`40375`.) importlib --------- @@ -588,13 +588,13 @@ nntplib :class:`~nntplib.NNTP` and :class:`~nntplib.NNTP_SSL` now raise a :class:`ValueError` if the given timeout for their constructor is zero to prevent the creation of -a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.) +a non-blocking socket. (Contributed by Donghee Na in :issue:`39259`.) os -- Added :const:`~os.CLD_KILLED` and :const:`~os.CLD_STOPPED` for :attr:`si_code`. -(Contributed by Dong-hee Na in :issue:`38493`.) +(Contributed by Donghee Na in :issue:`38493`.) Exposed the Linux-specific :func:`os.pidfd_open` (:issue:`38692`) and :const:`os.P_PIDFD` (:issue:`38713`) for process management with file @@ -629,7 +629,7 @@ poplib :class:`~poplib.POP3` and :class:`~poplib.POP3_SSL` now raise a :class:`ValueError` if the given timeout for their constructor is zero to prevent the creation of -a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.) +a non-blocking socket. (Contributed by Donghee Na in :issue:`39259`.) pprint ------ @@ -661,10 +661,10 @@ smtplib :class:`~smtplib.SMTP` and :class:`~smtplib.SMTP_SSL` now raise a :class:`ValueError` if the given timeout for their constructor is zero to prevent the creation of -a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.) +a non-blocking socket. (Contributed by Donghee Na in :issue:`39259`.) :class:`~smtplib.LMTP` constructor now has an optional *timeout* parameter. -(Contributed by Dong-hee Na in :issue:`39329`.) +(Contributed by Donghee Na in :issue:`39329`.) socket ------ @@ -777,7 +777,7 @@ Optimizations * A number of Python builtins (:class:`range`, :class:`tuple`, :class:`set`, :class:`frozenset`, :class:`list`, :class:`dict`) are now sped up by using :pep:`590` vectorcall protocol. - (Contributed by Dong-hee Na, Mark Shannon, Jeroen Demeyer and Petr Viktorin in :issue:`37207`.) + (Contributed by Donghee Na, Mark Shannon, Jeroen Demeyer and Petr Viktorin in :issue:`37207`.) * Optimized :func:`~set.difference_update` for the case when the other set is much larger than the base set. @@ -791,7 +791,7 @@ Optimizations * :term:`floor division` of float operation now has a better performance. Also the message of :exc:`ZeroDivisionError` for this operation is updated. - (Contributed by Dong-hee Na in :issue:`39434`.) + (Contributed by Donghee Na in :issue:`39434`.) * Decoding short ASCII strings with UTF-8 and ascii codecs is now about 15% faster. (Contributed by Inada Naoki in :issue:`37348`.) @@ -961,7 +961,7 @@ Removed are not supported or not enabled by NNTP server administrators. For ``xgtitle()``, please use :meth:`nntplib.NNTP.descriptions` or :meth:`nntplib.NNTP.description` instead. - (Contributed by Dong-hee Na in :issue:`39366`.) + (Contributed by Donghee Na in :issue:`39366`.) * :class:`array.array`: ``tostring()`` and ``fromstring()`` methods have been removed. They were aliases to ``tobytes()`` and ``frombytes()``, deprecated @@ -994,7 +994,7 @@ Removed * The :meth:`~threading.Thread.isAlive()` method of :class:`threading.Thread` has been removed. It was deprecated since Python 3.8. Use :meth:`~threading.Thread.is_alive()` instead. - (Contributed by Dong-hee Na in :issue:`37804`.) + (Contributed by Donghee Na in :issue:`37804`.) * Methods ``getchildren()`` and ``getiterator()`` of classes :class:`~xml.etree.ElementTree.ElementTree` and @@ -1315,7 +1315,7 @@ New Features * The :c:func:`PyModule_AddType` function is added to help adding a type to a module. - (Contributed by Dong-hee Na in :issue:`40024`.) + (Contributed by Donghee Na in :issue:`40024`.) * Added the functions :c:func:`PyObject_GC_IsTracked` and :c:func:`PyObject_GC_IsFinalized` to the public API to allow to query if diff --git a/Misc/ACKS b/Misc/ACKS index ff549dc6b78b6b..7deef8bad14a2c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1268,7 +1268,7 @@ R. David Murray Matti Mäki Jörg Müller Kaushik N -Dong-hee Na +Donghee Na Dale Nagata John Nagle Takahiro Nakayama diff --git a/Misc/NEWS.d/3.10.0a1.rst b/Misc/NEWS.d/3.10.0a1.rst index c1437172a38be3..62538d73ce47c7 100644 --- a/Misc/NEWS.d/3.10.0a1.rst +++ b/Misc/NEWS.d/3.10.0a1.rst @@ -68,7 +68,7 @@ getting the ``__bases__`` attribute leads to infinite recursion. .. section: Core and Builtins Speed up calls to ``reversed()`` by using the :pep:`590` ``vectorcall`` -calling convention. Patch by Dong-hee Na. +calling convention. Patch by Donghee Na. .. @@ -88,7 +88,7 @@ convention. Patch by Dennis Sweeney. .. section: Core and Builtins Speed up calls to ``bool()`` by using the :pep:`590` ``vectorcall`` calling -convention. Patch by Dong-hee Na. +convention. Patch by Donghee Na. .. @@ -715,7 +715,7 @@ Fix refleak in _Py_fopen_obj() when PySys_Audit() fails .. section: Core and Builtins Add a state to the :mod:`nis` module (:pep:`3121`) and apply the multiphase -initialization. Patch by Dong-hee Na. +initialization. Patch by Donghee Na. .. @@ -936,7 +936,7 @@ class. Patch by Pablo Galindo. .. section: Core and Builtins :c:func:`Py_TYPE()` is changed to the inline static function. Patch by -Dong-hee Na. +Donghee Na. .. @@ -2596,7 +2596,7 @@ remove multiple items from a list". .. section: Documentation Fix RemovedInSphinx40Warning when building the documentation. Patch by -Dong-hee Na. +Donghee Na. .. @@ -2862,7 +2862,7 @@ Make test_gdb properly run on HP-UX. Patch by Michael Osipov. .. section: Build Update :c:macro:`Py_UNREACHABLE` to use __builtin_unreachable() if only the -compiler is able to use it. Patch by Dong-hee Na. +compiler is able to use it. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.10.0a2.rst b/Misc/NEWS.d/3.10.0a2.rst index 78b25779802d6e..78f4377656b0cc 100644 --- a/Misc/NEWS.d/3.10.0a2.rst +++ b/Misc/NEWS.d/3.10.0a2.rst @@ -185,7 +185,7 @@ Removed special methods ``__int__``, ``__float__``, ``__floordiv__``, Micro optimization when compute :c:member:`~PySequenceMethods.sq_item` and :c:member:`~PyMappingMethods.mp_subscript` of :class:`range`. Patch by -Dong-hee Na. +Donghee Na. .. @@ -205,7 +205,7 @@ error message using the current locale's encoding. .. nonce: iLoMVF .. section: Core and Builtins -Micro optimization for range.index if step is 1. Patch by Dong-hee Na. +Micro optimization for range.index if step is 1. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.10.0a3.rst b/Misc/NEWS.d/3.10.0a3.rst index 70b79f5f250a18..0e89984d4bc821 100644 --- a/Misc/NEWS.d/3.10.0a3.rst +++ b/Misc/NEWS.d/3.10.0a3.rst @@ -394,7 +394,7 @@ Removed the ``formatter`` module, which was deprecated in Python 3.4. It is somewhat obsolete, little used, and not tested. It was originally scheduled to be removed in Python 3.6, but such removals were delayed until after Python 2.7 EOL. Existing users should copy whatever classes they use into -their code. Patch by Dong-hee Na and and Terry J. Reedy. +their code. Patch by Donghee Na and and Terry J. Reedy. .. diff --git a/Misc/NEWS.d/3.10.0a4.rst b/Misc/NEWS.d/3.10.0a4.rst index 95f9319668db45..414823f162d85c 100644 --- a/Misc/NEWS.d/3.10.0a4.rst +++ b/Misc/NEWS.d/3.10.0a4.rst @@ -105,7 +105,7 @@ blocks .. section: Core and Builtins Make the :mod:`atexit` module state per-interpreter. It is now safe have -more than one :mod:`atexit` module instance. Patch by Dong-hee Na and Victor +more than one :mod:`atexit` module instance. Patch by Donghee Na and Victor Stinner. .. @@ -768,7 +768,7 @@ results. Patch by Ammar Askar. .. section: Tests Update test_nntplib to use official group name of news.aioe.org for testing. -Patch by Dong-hee Na. +Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.10.0a6.rst b/Misc/NEWS.d/3.10.0a6.rst index 313aa689254040..c379b968c9885b 100644 --- a/Misc/NEWS.d/3.10.0a6.rst +++ b/Misc/NEWS.d/3.10.0a6.rst @@ -295,7 +295,7 @@ actual dictionary. This created problems for introspection tools. .. section: Library Added :const:`~os.O_EVTONLY`, :const:`~os.O_FSYNC`, :const:`~os.O_SYMLINK` and -:const:`~os.O_NOFOLLOW_ANY` for macOS. Patch by Dong-hee Na. +:const:`~os.O_NOFOLLOW_ANY` for macOS. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.10.0a7.rst b/Misc/NEWS.d/3.10.0a7.rst index 7933f71b01c14d..3a1694f444616a 100644 --- a/Misc/NEWS.d/3.10.0a7.rst +++ b/Misc/NEWS.d/3.10.0a7.rst @@ -113,7 +113,7 @@ in f-strings. Patch by Pablo Galindo. .. section: Core and Builtins Speed up calls to ``map()`` by using the :pep:`590` ``vectorcall`` calling -convention. Patch by Dong-hee Na. +convention. Patch by Donghee Na. .. @@ -240,7 +240,7 @@ of processes that don't use sigaltstack. .. section: Core and Builtins Speed up calls to ``filter()`` by using the :pep:`590` ``vectorcall`` -calling convention. Patch by Dong-hee Na. +calling convention. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.10.0b1.rst b/Misc/NEWS.d/3.10.0b1.rst index 3c71bc73b812a1..e7b6b93d0b6df3 100644 --- a/Misc/NEWS.d/3.10.0b1.rst +++ b/Misc/NEWS.d/3.10.0b1.rst @@ -516,7 +516,7 @@ encoding. .. section: Library Removed an unnecessary list comprehension before looping from -:func:`urllib.parse.parse_qsl`. Patch by Christoph Zwerschke and Dong-hee +:func:`urllib.parse.parse_qsl`. Patch by Christoph Zwerschke and Donghee Na. .. diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index d4d6be870f1701..45fb725aac80e3 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -292,7 +292,7 @@ Fixed pickling of range iterators that iterated for over ``2**32`` times. .. section: Core and Builtins A :exc:`SyntaxError` is now raised when trying to delete :const:`__debug__`. -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -415,7 +415,7 @@ type :class:`float` or :class:`complex`. .. section: Core and Builtins A debug variable :envvar:`PYTHONDUMPREFSFILE` is added for creating a dump -file which is generated by :option:`--with-trace-refs`. Patch by Dong-hee +file which is generated by :option:`--with-trace-refs`. Patch by Donghee Na. .. @@ -670,7 +670,7 @@ Parameter substitution of the union type with wrong types now raises .. section: Core and Builtins Update ``property_descr_set`` to use vectorcall if possible. Patch by -Dong-hee Na. +Donghee Na. .. @@ -732,7 +732,7 @@ Collapse union of equal types. E.g. the result of ``int | int`` is now On Windows, :func:`os.urandom`: uses BCryptGenRandom API instead of CryptGenRandom API which is deprecated from Microsoft Windows API. Patch by -Dong-hee Na. +Donghee Na. .. @@ -1657,7 +1657,7 @@ Patch by Hugo van Kemenade. .. section: Library Pure ASCII strings are now normalized in constant time by -:func:`unicodedata.normalize`. Patch by Dong-hee Na. +:func:`unicodedata.normalize`. Patch by Donghee Na. .. @@ -1968,7 +1968,7 @@ A new function ``operator.call`` has been added, such that :class:`webbrowser.MacOSX` is deprecated and will be removed in Python 3.13. It is untested and undocumented and also not used by webbrowser itself. -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -2465,7 +2465,7 @@ generator .. section: Library Make the implementation consistency of :func:`~operator.indexOf` between C -and Python versions. Patch by Dong-hee Na. +and Python versions. Patch by Donghee Na. .. @@ -2752,7 +2752,7 @@ of reserved filenames, including those with trailing spaces or colons. .. section: Library Fix :meth:`~email.message.MIMEPart.as_string` to pass unixfrom properly. -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -2809,7 +2809,7 @@ behaves differently than the similar implementation in :mod:`sysconfig`. .. section: Library :class:`smtpd.MailmanProxy` is now removed as it is unusable without an -external module, ``mailman``. Patch by Dong-hee Na. +external module, ``mailman``. Patch by Donghee Na. .. @@ -2916,7 +2916,7 @@ Support PEP 515 for Fraction's initialization from string. .. nonce: qFBYpp .. section: Library -Remove deprecated functions in the :mod:`gettext`. Patch by Dong-hee Na. +Remove deprecated functions in the :mod:`gettext`. Patch by Donghee Na. .. @@ -4471,7 +4471,7 @@ and modify the frozen modules. .. section: Build Add support for building with clang thin lto via --with-lto=thin/full. Patch -by Dong-hee Na and Brett Holman. +by Donghee Na and Brett Holman. .. @@ -4798,7 +4798,7 @@ Allow the Argument Clinic tool to handle ``__complex__`` special methods. Removed the 'test2to3' demo project that demonstrated using lib2to3 to support Python 2.x and Python 3.x from a single source in a distutils -package. Patch by Dong-hee Na +package. Patch by Donghee Na .. diff --git a/Misc/NEWS.d/3.11.0a2.rst b/Misc/NEWS.d/3.11.0a2.rst index cf26137dff19ef..503e489b658e4d 100644 --- a/Misc/NEWS.d/3.11.0a2.rst +++ b/Misc/NEWS.d/3.11.0a2.rst @@ -142,7 +142,7 @@ Add SipHash13 for string hash algorithm and use it by default. .. nonce: CTUT8s .. section: Core and Builtins -Fix reference leak from descr_check. Patch by Dong-hee Na. +Fix reference leak from descr_check. Patch by Donghee Na. .. @@ -263,7 +263,7 @@ Improve the generated bytecode for class and mapping patterns. .. section: Core and Builtins Speed up calls to ``enumerate()`` by using the :pep:`590` ``vectorcall`` -calling convention. Patch by Dong-hee Na. +calling convention. Patch by Donghee Na. .. @@ -396,7 +396,7 @@ Patch by Inada Naoki. .. section: Library Update :class:`~typing.ForwardRef` to support ``|`` operator. Patch by -Dong-hee Na. +Donghee Na. .. @@ -486,7 +486,7 @@ Patch by Joongi Kim. .. section: Library Empty escapechar/quotechar is not allowed when initializing -:class:`csv.Dialect`. Patch by Vajrasky Kok and Dong-hee Na. +:class:`csv.Dialect`. Patch by Vajrasky Kok and Donghee Na. .. @@ -569,7 +569,7 @@ formatting options. .. section: Library Improve error message of :class:`csv.Dialect` when initializing. Patch by -Vajrasky Kok and Dong-hee Na. +Vajrasky Kok and Donghee Na. .. diff --git a/Misc/NEWS.d/3.11.0a3.rst b/Misc/NEWS.d/3.11.0a3.rst index 426531904993a9..41a3a4b94c4f3d 100644 --- a/Misc/NEWS.d/3.11.0a3.rst +++ b/Misc/NEWS.d/3.11.0a3.rst @@ -615,7 +615,7 @@ Launch GNOME web browsers via gio tool instead of obsolete gvfs-open .. section: Library On Windows, :func:`time.sleep` now uses a waitable timer which supports -high-resolution timers. Patch by Dong-hee Na and Eryk Sun. +high-resolution timers. Patch by Donghee Na and Eryk Sun. .. diff --git a/Misc/NEWS.d/3.11.0a5.rst b/Misc/NEWS.d/3.11.0a5.rst index c28078da8d8339..08d94e82ed8ccf 100644 --- a/Misc/NEWS.d/3.11.0a5.rst +++ b/Misc/NEWS.d/3.11.0a5.rst @@ -127,7 +127,7 @@ Aditya. .. section: Core and Builtins Speed up calls to :meth:`weakref.ref.__call__` by using the :pep:`590` -``vectorcall`` calling convention. Patch by Dong-hee Na. +``vectorcall`` calling convention. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.11.0a6.rst b/Misc/NEWS.d/3.11.0a6.rst index fcec71c6f59da2..52055b3fafd485 100644 --- a/Misc/NEWS.d/3.11.0a6.rst +++ b/Misc/NEWS.d/3.11.0a6.rst @@ -382,7 +382,7 @@ involving lots of brackets. Patch by Pablo Galindo. .. section: Core and Builtins :mod:`ctypes` now allocates memory on the stack instead of on the heap to -pass arguments while calling a Python callback function. Patch by Dong-hee +pass arguments while calling a Python callback function. Patch by Donghee Na. .. @@ -441,7 +441,7 @@ Add a missing call to ``va_end()`` in ``Modules/_hashopenssl.c``. .. section: Core and Builtins Use :c:func:`PyObject_Vectorcall` while calling ctypes callback function. -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -514,7 +514,7 @@ For performance, use the optimized string-searching implementations from .. section: Library :class:`~http.server.SimpleHTTPRequestHandler` now uses HTML5 grammar. Patch -by Dong-hee Na. +by Donghee Na. .. diff --git a/Misc/NEWS.d/3.11.0a7.rst b/Misc/NEWS.d/3.11.0a7.rst index 2172c02e2fc847..20f2aa3c56ae2e 100644 --- a/Misc/NEWS.d/3.11.0a7.rst +++ b/Misc/NEWS.d/3.11.0a7.rst @@ -89,7 +89,7 @@ problem. Define :c:macro:`PY_CALL_TRAMPOLINE` to enable call trampolines. .. section: Core and Builtins Some Windows system error codes(>= 10000) are now mapped into the correct -errno and may now raise a subclass of :exc:`OSError`. Patch by Dong-hee Na. +errno and may now raise a subclass of :exc:`OSError`. Patch by Donghee Na. .. @@ -1599,7 +1599,7 @@ Call the public :func:`sys.get_asyncgen_hooks` and .. section: C API Remove private functions ``_PySys_GetObjectId()`` and -``_PySys_SetObjectId()``. Patch by Dong-hee Na. +``_PySys_SetObjectId()``. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.11.0b1.rst b/Misc/NEWS.d/3.11.0b1.rst index 1da722b21680ee..c663ca8de98ca2 100644 --- a/Misc/NEWS.d/3.11.0b1.rst +++ b/Misc/NEWS.d/3.11.0b1.rst @@ -185,7 +185,7 @@ functions leave the current exception unchanged. Patch by Victor Stinner. .. section: Core and Builtins Fix a minor memory leak at exit: release the memory of the -:class:`generic_alias_iterator` type. Patch by Dong-hee Na. +:class:`generic_alias_iterator` type. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 84036788774f76..5723d1ab20082a 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -82,7 +82,7 @@ the test failed). .. nonce: eOBh8M .. section: Core and Builtins -Suppress ImportError for invalid query for help() command. Patch by Dong-hee +Suppress ImportError for invalid query for help() command. Patch by Donghee Na. .. @@ -164,7 +164,7 @@ to calculate those doing pointer arithmetic. .. section: Core and Builtins :func:`os.sched_yield` now release the GIL while calling sched_yield(2). -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -465,7 +465,7 @@ Remove dead code from ``CALL_FUNCTION_EX`` opcode. .. nonce: VE8-zf .. section: Core and Builtins -:class:`memoryview` now supports half-floats. Patch by Dong-hee Na and +:class:`memoryview` now supports half-floats. Patch by Donghee Na and Antoine Pitrou. .. @@ -857,7 +857,7 @@ code objects could be "deduplicated" during compilation. .. section: Core and Builtins Reduce allocation size of :class:`list` from :meth:`str.split` and -:meth:`str.rsplit`. Patch by Dong-hee Na and Inada Naoki. +:meth:`str.rsplit`. Patch by Donghee Na and Inada Naoki. .. @@ -3742,7 +3742,7 @@ Fix :func:`ast.unparse` when ``ImportFrom.level`` is None Now :func:`~dis.dis` and :func:`~dis.get_instructions` handle operand values for instructions prefixed by ``EXTENDED_ARG_QUICK``. Patch by Sam Gross and -Dong-hee Na. +Donghee Na. .. @@ -5004,7 +5004,7 @@ Patch by Illia Volochii and Adam Turner. .. section: Build Fix the build process of clang compiler for :program:`_bootstrap_python` if -LTO optimization is applied. Patch by Matthias Görgens and Dong-hee Na. +LTO optimization is applied. Patch by Matthias Görgens and Donghee Na. .. @@ -5024,7 +5024,7 @@ LTO optimization is applied. Patch by Matthias Görgens and Dong-hee Na. .. section: Build CPython now uses the ThinLTO option as the default policy if the Clang -compiler accepts the flag. Patch by Dong-hee Na. +compiler accepts the flag. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index f781e38665a8ea..41f5f67df01d91 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -111,7 +111,7 @@ back to alternative names ("python", "python."). .. section: Core and Builtins Update :mod:`faulthandler` to emit an error message with the proper -unexpected signal number. Patch by Dong-hee Na. +unexpected signal number. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0a3.rst b/Misc/NEWS.d/3.12.0a3.rst index 3e6f8de5d911f2..27bd456f3f05d9 100644 --- a/Misc/NEWS.d/3.12.0a3.rst +++ b/Misc/NEWS.d/3.12.0a3.rst @@ -153,7 +153,7 @@ to specialize attribute accesses on types that haven't had .. section: Core and Builtins Allow some features of :mod:`syslog` to the main interpreter only. Patch by -Dong-hee Na. +Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0a4.rst b/Misc/NEWS.d/3.12.0a4.rst index 8951490f41b94c..b3b39024056ccc 100644 --- a/Misc/NEWS.d/3.12.0a4.rst +++ b/Misc/NEWS.d/3.12.0a4.rst @@ -676,7 +676,7 @@ parameter names in the C implementation. Patch by Alex Waygood. .. section: Library Update :exc:`~urllib.error.HTTPError` to be initialized properly, even if -the ``fp`` is ``None``. Patch by Dong-hee Na. +the ``fp`` is ``None``. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0a5.rst b/Misc/NEWS.d/3.12.0a5.rst index f6f8de46cf70d9..8cf90b0e9cde46 100644 --- a/Misc/NEWS.d/3.12.0a5.rst +++ b/Misc/NEWS.d/3.12.0a5.rst @@ -38,7 +38,7 @@ would get out of sync, causing inconsistent behavior and crashes. .. section: Core and Builtins Fix wrong lineno in exception message on :keyword:`continue` or -:keyword:`break` which are not in a loop. Patch by Dong-hee Na. +:keyword:`break` which are not in a loop. Patch by Donghee Na. .. @@ -48,7 +48,7 @@ Fix wrong lineno in exception message on :keyword:`continue` or .. section: Core and Builtins Fix :func:`~unicodedata.is_normalized` to properly handle the UCD 3.2.0 -cases. Patch by Dong-hee Na. +cases. Patch by Donghee Na. .. @@ -507,7 +507,7 @@ inheritance. .. section: Build Update BOLT configration not to use depreacted usage of ``--split -functions``. Patch by Dong-hee Na. +functions``. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0a6.rst b/Misc/NEWS.d/3.12.0a6.rst index 07967028bdee70..5bd600cd8b6fc0 100644 --- a/Misc/NEWS.d/3.12.0a6.rst +++ b/Misc/NEWS.d/3.12.0a6.rst @@ -220,7 +220,7 @@ access of ``builtins.__dict__`` keys mutates the iter object. .. section: Core and Builtins Update :mod:`tracemalloc` to handle presize of object properly. Patch by -Dong-hee Na. +Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index 23540f71a347cf..4bd2c52b28d236 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -213,7 +213,7 @@ attribute. .. section: Core and Builtins Reduce object creation while calling callback function from gc. Patch by -Dong-hee Na. +Donghee Na. .. @@ -464,7 +464,7 @@ unpickled. .. section: Core and Builtins Migrate :meth:`~ssl.SSLContext.set_ecdh_curve` method not to use deprecated -OpenSSL APIs. Patch by Dong-hee Na. +OpenSSL APIs. Patch by Donghee Na. .. @@ -2073,7 +2073,7 @@ Define ``.PHONY`` / virtual make targets consistently and properly. .. nonce: -W9BJS .. section: Build -Add gcc fallback of mkfifoat/mknodat for macOS. Patch by Dong-hee Na. +Add gcc fallback of mkfifoat/mknodat for macOS. Patch by Donghee Na. .. @@ -2372,7 +2372,7 @@ Add a new C-API function to eagerly assign a version tag to a PyTypeObject: .. section: C API :c:func:`PyObject_GC_Resize` should calculate preheader size if needed. -Patch by Dong-hee Na. +Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.12.0rc2.rst b/Misc/NEWS.d/3.12.0rc2.rst index 3741da94798e50..6ca7cc63cb80db 100644 --- a/Misc/NEWS.d/3.12.0rc2.rst +++ b/Misc/NEWS.d/3.12.0rc2.rst @@ -216,7 +216,7 @@ Erlend E. Aasland. .. section: Library Fix :func:`multiprocessing.set_forkserver_preload` to check the given list -of modules names. Patch by Dong-hee Na. +of modules names. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.5.4.rst b/Misc/NEWS.d/3.5.4.rst index cd0ca4872f1ab0..7839fa2709ecf2 100644 --- a/Misc/NEWS.d/3.5.4.rst +++ b/Misc/NEWS.d/3.5.4.rst @@ -5,4 +5,4 @@ .. section: Library ftplib.FTP.putline() now throws ValueError on commands that contains CR or -LF. Patch by Dong-hee Na. +LF. Patch by Donghee Na. diff --git a/Misc/NEWS.d/3.5.4rc1.rst b/Misc/NEWS.d/3.5.4rc1.rst index 04a035a41e7461..d65d5d14ee78bb 100644 --- a/Misc/NEWS.d/3.5.4rc1.rst +++ b/Misc/NEWS.d/3.5.4rc1.rst @@ -340,7 +340,7 @@ not keep objects alive longer than expected. .. section: Library inspect.signature() now supports callables with variable-argument parameters -wrapped with partialmethod. Patch by Dong-hee Na. +wrapped with partialmethod. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.6.2rc1.rst b/Misc/NEWS.d/3.6.2rc1.rst index cdf4c3d541c4ca..28eb88f79130c5 100644 --- a/Misc/NEWS.d/3.6.2rc1.rst +++ b/Misc/NEWS.d/3.6.2rc1.rst @@ -77,7 +77,7 @@ delivered to the innermost frame. .. section: Core and Builtins sys.getsizeof() on a code object now returns the sizes which includes the -code struct and sizes of objects which it references. Patch by Dong-hee Na. +code struct and sizes of objects which it references. Patch by Donghee Na. .. @@ -163,7 +163,7 @@ no longer ignored. Patch by Mircea Cosbuc. .. nonce: I2mDTz .. section: Library -Functional API of enum allows to create empty enums. Patched by Dong-hee Na +Functional API of enum allows to create empty enums. Patched by Donghee Na .. @@ -202,7 +202,7 @@ not keep objects alive longer than expected. .. section: Library inspect.signature() now supports callables with variable-argument parameters -wrapped with partialmethod. Patch by Dong-hee Na. +wrapped with partialmethod. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.6.3rc1.rst b/Misc/NEWS.d/3.6.3rc1.rst index 4dc2eef5d3b61b..4b2aae9dc88441 100644 --- a/Misc/NEWS.d/3.6.3rc1.rst +++ b/Misc/NEWS.d/3.6.3rc1.rst @@ -506,7 +506,7 @@ Fix handling of long oids in ssl. Based on patch by Christian Heimes. .. section: Library ftplib.FTP.putline() now throws ValueError on commands that contains CR or -LF. Patch by Dong-hee Na. +LF. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.6.6rc1.rst b/Misc/NEWS.d/3.6.6rc1.rst index 71a5c3ec595ba2..9624195c79043b 100644 --- a/Misc/NEWS.d/3.6.6rc1.rst +++ b/Misc/NEWS.d/3.6.6rc1.rst @@ -289,7 +289,7 @@ literals on pydoc. Patch by Andrés Delfino. .. section: Library Update error message when constructing invalid inspect.Parameters Patch by -Dong-hee Na. +Donghee Na. .. diff --git a/Misc/NEWS.d/3.7.0a1.rst b/Misc/NEWS.d/3.7.0a1.rst index 712558bf98d018..bee424241fd712 100644 --- a/Misc/NEWS.d/3.7.0a1.rst +++ b/Misc/NEWS.d/3.7.0a1.rst @@ -529,7 +529,7 @@ name are now supported. .. section: Core and Builtins sys.getsizeof() on a code object now returns the sizes which includes the -code struct and sizes of objects which it references. Patch by Dong-hee Na. +code struct and sizes of objects which it references. Patch by Donghee Na. .. @@ -2260,7 +2260,7 @@ Update zlib to 1.2.11. .. section: Library ftplib.FTP.putline() now throws ValueError on commands that contains CR or -LF. Patch by Dong-hee Na. +LF. Patch by Donghee Na. .. @@ -2329,7 +2329,7 @@ always return bytes. .. nonce: I2mDTz .. section: Library -Functional API of enum allows to create empty enums. Patched by Dong-hee Na +Functional API of enum allows to create empty enums. Patched by Donghee Na .. @@ -2612,7 +2612,7 @@ Fix handling escape characters in HZ codec. Based on patch by Ma Lin. .. section: Library inspect.signature() now supports callables with variable-argument parameters -wrapped with partialmethod. Patch by Dong-hee Na. +wrapped with partialmethod. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.7.0a3.rst b/Misc/NEWS.d/3.7.0a3.rst index 92b0f328851208..69db9fcd1c8228 100644 --- a/Misc/NEWS.d/3.7.0a3.rst +++ b/Misc/NEWS.d/3.7.0a3.rst @@ -539,7 +539,7 @@ optional .. section: Library Updates 2to3 to convert from operator.isCallable(obj) to callable(obj). -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -549,7 +549,7 @@ Patch by Dong-hee Na. .. section: Library inspect.signature should follow :pep:`8`, if the parameter has an annotation -and a default value. Patch by Dong-hee Na. +and a default value. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.7.0b5.rst b/Misc/NEWS.d/3.7.0b5.rst index 20476993b9652a..fb29109869188b 100644 --- a/Misc/NEWS.d/3.7.0b5.rst +++ b/Misc/NEWS.d/3.7.0b5.rst @@ -418,7 +418,7 @@ trigger a ``DeprecationWarning`` and have been marked for removal in Python .. section: Library Update error message when constructing invalid inspect.Parameters Patch by -Dong-hee Na. +Donghee Na. .. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index c5a4e407e85c92..0c0dd5377c2113 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -1965,7 +1965,7 @@ result of an internal future if it's already done. .. section: Library Add a deprecated warning for the :meth:`threading.Thread.isAlive` method. -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -4974,7 +4974,7 @@ Enum members. .. section: Library Update error message when constructing invalid inspect.Parameters Patch by -Dong-hee Na. +Donghee Na. .. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 367c194c1ea181..5f4e04b8b8ddcc 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -33,7 +33,7 @@ Fixes audit event for :func:`os.system` to be named ``os.system``. .. section: Security Escape the server title of :class:`xmlrpc.server.DocXMLRPCServer` when -rendering the document page as HTML. (Contributed by Dong-hee Na in +rendering the document page as HTML. (Contributed by Donghee Na in :issue:`38243`.) .. @@ -203,7 +203,7 @@ arguments in decorators. .. section: Core and Builtins Fix a segmentation fault when using reverse iterators of empty ``dict`` -objects. Patch by Dong-hee Na and Inada Naoki. +objects. Patch by Donghee Na and Inada Naoki. .. @@ -280,7 +280,7 @@ visited by ``tp_traverse()`` are valid. .. section: Core and Builtins Remove unnecessary intersection and update set operation in dictview with -empty set. (Contributed by Dong-hee Na in :issue:`38210`.) +empty set. (Contributed by Donghee Na in :issue:`38210`.) .. @@ -1194,7 +1194,7 @@ Expose the Linux ``pidfd_open`` syscall as :func:`os.pidfd_open`. .. section: Library Added constants :const:`~fcntl.F_OFD_GETLK`, :const:`~fcntl.F_OFD_SETLK` and -:const:`~fcntl.F_OFD_SETLKW` to the :mod:`fcntl` module. Patch by Dong-hee +:const:`~fcntl.F_OFD_SETLKW` to the :mod:`fcntl` module. Patch by Donghee Na. .. @@ -1284,7 +1284,7 @@ Fixed erroneous equality comparison in statistics.NormalDist(). .. section: Library Added :const:`~os.CLD_KILLED` and :const:`~os.CLD_STOPPED` for -:attr:`si_code`. Patch by Dong-hee Na. +:attr:`si_code`. Patch by Donghee Na. .. @@ -1882,7 +1882,7 @@ avoid dynamic lookup. .. section: Library Update :class:`importlib.machinery.BuiltinImporter` to use -``loader._ORIGIN`` instead of a hardcoded value. Patch by Dong-hee Na. +``loader._ORIGIN`` instead of a hardcoded value. Patch by Donghee Na. .. @@ -2080,7 +2080,7 @@ method which emits a deprecation warning and calls corresponding methody .. section: Library Update test_statistics.py to verify that the statistics module works well -for both C and Python implementations. Patch by Dong-hee Na +for both C and Python implementations. Patch by Donghee Na .. @@ -2201,7 +2201,7 @@ uses more than ``SIGSTKSZ`` bytes of stack memory on some platforms. .. nonce: AmXrik .. section: Library -Add C fastpath for statistics.NormalDist.inv_cdf() Patch by Dong-hee Na +Add C fastpath for statistics.NormalDist.inv_cdf() Patch by Donghee Na .. @@ -2210,7 +2210,7 @@ Add C fastpath for statistics.NormalDist.inv_cdf() Patch by Dong-hee Na .. nonce: Ene6L- .. section: Library -Remove the deprecated method `threading.Thread.isAlive()`. Patch by Dong-hee +Remove the deprecated method `threading.Thread.isAlive()`. Patch by Donghee Na. .. @@ -4089,7 +4089,7 @@ Increase code coverage for multiprocessing.shared_memory. .. nonce: Kl1sti .. section: Tests -Add tests for json.dump(..., skipkeys=True). Patch by Dong-hee Na. +Add tests for json.dump(..., skipkeys=True). Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.9.0a3.rst b/Misc/NEWS.d/3.9.0a3.rst index 54b61ca3b7785f..a56573dd2c3d95 100644 --- a/Misc/NEWS.d/3.9.0a3.rst +++ b/Misc/NEWS.d/3.9.0a3.rst @@ -149,7 +149,7 @@ argument - by Anthony Sottile. .. section: Core and Builtins Correct the error message when calling the :func:`min` or :func:`max` with -no arguments. Patch by Dong-hee Na. +no arguments. Patch by Donghee Na. .. @@ -392,7 +392,7 @@ Remove ``fractions.gcd()`` function, deprecated since Python 3.5 .. section: Library :class:`~smtplib.LMTP` constructor now has an optional *timeout* parameter. -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -414,7 +414,7 @@ Taskaya. :class:`~ftplib.FTP_TLS` and :class:`~ftplib.FTP_TLS` now raise a :class:`ValueError` if the given timeout for their constructor is zero to -prevent the creation of a non-blocking socket. Patch by Dong-hee Na. +prevent the creation of a non-blocking socket. Patch by Donghee Na. .. @@ -425,7 +425,7 @@ prevent the creation of a non-blocking socket. Patch by Dong-hee Na. :class:`~smtplib.SMTP` and :class:`~smtplib.SMTP_SSL` now raise a :class:`ValueError` if the given timeout for their constructor is zero to -prevent the creation of a non-blocking socket. Patch by Dong-hee Na. +prevent the creation of a non-blocking socket. Patch by Donghee Na. .. @@ -456,7 +456,7 @@ resilients to inaccessible sys.path entries (importlib_metadata v1.4.0). :class:`~nntplib.NNTP` and :class:`~nntplib.NNTP_SSL` now raise a :class:`ValueError` if the given timeout for their constructor is zero to -prevent the creation of a non-blocking socket. Patch by Dong-hee Na. +prevent the creation of a non-blocking socket. Patch by Donghee Na. .. @@ -488,7 +488,7 @@ towards *y*. :class:`~poplib.POP3` and :class:`~poplib.POP3_SSL` now raise a :class:`ValueError` if the given timeout for their constructor is zero to -prevent the creation of a non-blocking socket. Patch by Dong-hee Na. +prevent the creation of a non-blocking socket. Patch by Donghee Na. .. @@ -571,7 +571,7 @@ new task spawning before exception raising. .. section: Library Correctly parenthesize filter-based statements that contain lambda -expressions in mod:`lib2to3`. Patch by Dong-hee Na. +expressions in mod:`lib2to3`. Patch by Donghee Na. .. @@ -699,7 +699,7 @@ upon inheritance. Patch by Bar Harel. :meth:`~imaplib.IMAP4.open` method now has an optional *timeout* parameter with this change. The overridden methods of :class:`~imaplib.IMAP4_SSL` and :class:`~imaplib.IMAP4_stream` were applied to this change. Patch by -Dong-hee Na. +Donghee Na. .. diff --git a/Misc/NEWS.d/3.9.0a4.rst b/Misc/NEWS.d/3.9.0a4.rst index 019b34c4082d10..e59435b5509acf 100644 --- a/Misc/NEWS.d/3.9.0a4.rst +++ b/Misc/NEWS.d/3.9.0a4.rst @@ -43,7 +43,7 @@ first item. Patch by Yonatan Goldschmidt. .. nonce: BIIX2M .. section: Core and Builtins -Update clinic tool to use :c:func:`Py_IS_TYPE`. Patch by Dong-hee Na. +Update clinic tool to use :c:func:`Py_IS_TYPE`. Patch by Donghee Na. .. @@ -141,7 +141,7 @@ collection of deleted, pickled objects. .. section: Core and Builtins Fixed a possible crash in :meth:`list.__contains__` when a list is changed -during comparing items. Patch by Dong-hee Na. +during comparing items. Patch by Donghee Na. .. @@ -152,7 +152,7 @@ during comparing items. Patch by Dong-hee Na. :term:`floor division` of float operation now has a better performance. Also the message of :exc:`ZeroDivisionError` for this operation is updated. Patch -by Dong-hee Na. +by Donghee Na. .. diff --git a/Misc/NEWS.d/3.9.0a5.rst b/Misc/NEWS.d/3.9.0a5.rst index 19ad20ad3db042..6ff05788214723 100644 --- a/Misc/NEWS.d/3.9.0a5.rst +++ b/Misc/NEWS.d/3.9.0a5.rst @@ -96,7 +96,7 @@ Port itertools module to multiphase initialization (:pep:`489`). .. section: Core and Builtins Speed up calls to ``frozenset()`` by using the :pep:`590` ``vectorcall`` -calling convention. Patch by Dong-hee Na. +calling convention. Patch by Donghee Na. .. @@ -117,7 +117,7 @@ own variable. .. section: Core and Builtins Speed up calls to ``set()`` by using the :pep:`590` ``vectorcall`` calling -convention. Patch by Dong-hee Na. +convention. Patch by Donghee Na. .. @@ -166,7 +166,7 @@ Allow executing asynchronous comprehensions on the top level when the .. section: Core and Builtins Speed up calls to ``tuple()`` by using the :pep:`590` ``vectorcall`` calling -convention. Patch by Dong-hee Na. +convention. Patch by Donghee Na. .. @@ -571,7 +571,7 @@ Fixed :func:`ast.unparse` for extended slices containing a single element .. nonce: yWq9NJ .. section: Library -Fix :mod:`json.tool` to catch :exc:`BrokenPipeError`. Patch by Dong-hee Na. +Fix :mod:`json.tool` to catch :exc:`BrokenPipeError`. Patch by Donghee Na. .. @@ -783,7 +783,7 @@ when the optional ``qop`` parameter is not present. .. section: Library HTTP status codes ``103 EARLY_HINTS`` and ``425 TOO_EARLY`` are added to -:class:`http.HTTPStatus`. Patch by Dong-hee Na. +:class:`http.HTTPStatus`. Patch by Donghee Na. .. @@ -1133,7 +1133,7 @@ module. Patch by José Roberto Meza Cabrera. .. section: C API Add :c:func:`PyModule_AddType` helper function: add a type to a module. -Patch by Dong-hee Na. +Patch by Donghee Na. .. @@ -1163,7 +1163,7 @@ Python thread state. .. nonce: R3jaTy .. section: C API -Add _PyArg_NoKwnames helper function. Patch by Dong-hee Na. +Add _PyArg_NoKwnames helper function. Patch by Donghee Na. .. diff --git a/Misc/NEWS.d/3.9.0b1.rst b/Misc/NEWS.d/3.9.0b1.rst index a7f52f81a5cd3a..49418640093a0d 100644 --- a/Misc/NEWS.d/3.9.0b1.rst +++ b/Misc/NEWS.d/3.9.0b1.rst @@ -490,7 +490,7 @@ The first argument of :func:`pickle.loads` is now positional-only. .. section: Library Update :mod:`nntplib` to merge :class:`nntplib.NNTP` and -:class:`nntplib._NNTPBase`. Patch by Dong-hee Na. +:class:`nntplib._NNTPBase`. Patch by Donghee Na. .. @@ -500,7 +500,7 @@ Update :mod:`nntplib` to merge :class:`nntplib.NNTP` and .. section: Library Update :mod:`dbm.gnu` to use gdbm_count if possible when calling -:func:`len`. Patch by Dong-hee Na. +:func:`len`. Patch by Donghee Na. .. @@ -592,7 +592,7 @@ subdirectories in package data, matching backport in importlib_resources .. nonce: 5GuK2A .. section: Library -:meth:`imaplib.IMAP4.unselect` is added. Patch by Dong-hee Na. +:meth:`imaplib.IMAP4.unselect` is added. Patch by Donghee Na. .. From 46207624b766996b141d9937f203727dca09f5d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 Sep 2023 04:53:27 -0700 Subject: [PATCH 0804/1206] [3.12] GH-95913: Add the release date for Python 3.11 (GH-109750) (#109771) GH-95913: Add the release date for Python 3.11 (GH-109750) (cherry picked from commit b10de68c6ceae1076cdc98c890b9802dc81a7f44) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.11.rst | 2 +- Doc/whatsnew/3.9.rst | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 7970591424e33f..9aef37d848ab97 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -45,7 +45,7 @@ when researching a change. This article explains the new features in Python 3.11, compared to 3.10. - +Python 3.11 was released on October 24, 2022. For full details, see the :ref:`changelog `. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index fb73eaf59d5dac..6e6961e48c4ee8 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -44,7 +44,6 @@ This article explains the new features in Python 3.9, compared to 3.8. Python 3.9 was released on October 5, 2020. - For full details, see the :ref:`changelog `. .. seealso:: From 62df559448362f9a4291661d64aee30474dec025 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 Sep 2023 04:53:56 -0700 Subject: [PATCH 0805/1206] [3.12] gh-100228: Document the os.fork threads DeprecationWarning. (GH-109767) (#109773) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * gh-100228: Document the os.fork threads DeprecationWarning. (GH-109767) Document the `os.fork` posix threads detected `DeprecationWarning` in 3.12 What's New, os, multiprocessing, and concurrent.futures docs. Many reviews and doc cleanup edits by Adam & Hugo. 🥳 (cherry picked from commit 5e7ea95d9d5c3b80a67ffbeebd76ce4fc327dd8e) Co-authored-by: Gregory P. Smith Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade * link to the discussion thread from whatsnew Include the link to the discussion in the what's new text per @malemberg's comment on. https://github.com/python/cpython/pull/109767 (i'll follow up with a PR to main to include this edit there as well) --------- Co-authored-by: Gregory P. Smith Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/library/concurrent.futures.rst | 8 +++++++ Doc/library/multiprocessing.rst | 6 +++++ Doc/library/os.rst | 36 ++++++++++++++++++++++++++---- Doc/whatsnew/3.12.rst | 14 ++++++++++++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 09c9fc4e6e227a..6503d1fcf70a32 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -293,6 +293,14 @@ to a :class:`ProcessPoolExecutor` will result in deadlock. The *max_tasks_per_child* argument was added to allow users to control the lifetime of workers in the pool. + .. versionchanged:: 3.12 + On POSIX systems, if your application has multiple threads and the + :mod:`multiprocessing` context uses the ``"fork"`` start method: + The :func:`os.fork` function called internally to spawn workers may raise a + :exc:`DeprecationWarning`. Pass a *mp_context* configured to use a + different start method. See the :func:`os.fork` documentation for + further explanation. + .. _processpoolexecutor-example: ProcessPoolExecutor Example diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 38d24a86072970..2f0f1f800fdc94 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -131,6 +131,12 @@ to start a process. These *start methods* are Code that requires *fork* should explicitly specify that via :func:`get_context` or :func:`set_start_method`. + .. versionchanged:: 3.12 + If Python is able to detect that your process has multiple threads, the + :func:`os.fork` function that this start method calls internally will + raise a :exc:`DeprecationWarning`. Use a different start method. + See the :func:`os.fork` documentation for further explanation. + *forkserver* When the program starts and selects the *forkserver* start method, a server process is spawned. From then on, whenever a new process diff --git a/Doc/library/os.rst b/Doc/library/os.rst index c67b966f777db8..74897a76b1d20a 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -4157,15 +4157,38 @@ written in Python, such as a mail server's external command delivery program. .. audit-event:: os.fork "" os.fork + .. warning:: + + If you use TLS sockets in an application calling ``fork()``, see + the warning in the :mod:`ssl` documentation. + .. versionchanged:: 3.8 Calling ``fork()`` in a subinterpreter is no longer supported (:exc:`RuntimeError` is raised). - .. warning:: - - See :mod:`ssl` for applications that use the SSL module with fork(). + .. versionchanged:: 3.12 + If Python is able to detect that your process has multiple + threads, :func:`os.fork` now raises a :exc:`DeprecationWarning`. + + We chose to surface this as a warning, when detectable, to better + inform developers of a design problem that the POSIX platform + specifically notes as not supported. Even in code that + *appears* to work, it has never been safe to mix threading with + :func:`os.fork` on POSIX platforms. The CPython runtime itself has + always made API calls that are not safe for use in the child + process when threads existed in the parent (such as ``malloc`` and + ``free``). + + Users of macOS or users of libc or malloc implementations other + than those typically found in glibc to date are among those + already more likely to experience deadlocks running such code. + + See `this discussion on fork being incompatible with threads + `_ + for technical details of why we're surfacing this longstanding + platform compatibility problem to developers. - .. availability:: Unix, not Emscripten, not WASI. + .. availability:: POSIX, not Emscripten, not WASI. .. function:: forkpty() @@ -4178,6 +4201,11 @@ written in Python, such as a mail server's external command delivery program. .. audit-event:: os.forkpty "" os.forkpty + .. versionchanged:: 3.12 + If Python is able to detect that your process has multiple + threads, this now raises a :exc:`DeprecationWarning`. See the + longer explanation on :func:`os.fork`. + .. versionchanged:: 3.8 Calling ``forkpty()`` in a subinterpreter is no longer supported (:exc:`RuntimeError` is raised). diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 14beb3e09044e1..04adf57865215c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1065,6 +1065,20 @@ Deprecated contain the creation time, which is also available in the new ``st_birthtime`` field. (Contributed by Steve Dower in :gh:`99726`.) +* :mod:`os`: On POSIX platforms, :func:`os.fork` can now raise a + :exc:`DeprecationWarning` when it can detect being called from a + multithreaded process. There has always been a fundamental incompatibility + with the POSIX platform when doing so. Even if such code *appeared* to work. + We added the warning to to raise awareness as issues encounted by code doing + this are becoming more frequent. See the :func:`os.fork` documentation for + more details along with `this discussion on fork being incompatible with threads + `_ for *why* we're now surfacing this + longstanding platform compatibility problem to developers. + + When this warning appears due to usage of :mod:`multiprocessing` or + :mod:`concurrent.futures` the fix is to use a different + :mod:`multiprocessing` start method such as ``"spawn"`` or ``"forkserver"``. + * :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) From 2622b130469f8be02627cd9b42187b1a392f6e42 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 Sep 2023 04:54:36 -0700 Subject: [PATCH 0806/1206] [3.12] gh-109634: Use :samp: role (GH-109635) (#109776) gh-109634: Use :samp: role (GH-109635) (cherry picked from commit 92af0cc580051fd1129c7a86af2cbadeb2aa36dc) Co-authored-by: Serhiy Storchaka --- Doc/extending/windows.rst | 2 +- Doc/howto/logging-cookbook.rst | 4 +- Doc/howto/logging.rst | 2 +- Doc/library/codecs.rst | 26 +++++---- Doc/library/compileall.rst | 2 +- Doc/library/ensurepip.rst | 2 +- Doc/library/functions.rst | 2 +- Doc/library/html.parser.rst | 2 +- Doc/library/http.server.rst | 2 +- Doc/library/os.rst | 4 +- Doc/library/re.rst | 2 +- Doc/library/sys.rst | 4 +- Doc/library/urllib.parse.rst | 6 +-- Doc/reference/lexical_analysis.rst | 84 +++++++++++++++--------------- Doc/using/configure.rst | 10 ++-- Doc/using/windows.rst | 4 +- Doc/whatsnew/2.0.rst | 4 +- Doc/whatsnew/2.6.rst | 2 +- Doc/whatsnew/3.11.rst | 6 +-- Doc/whatsnew/3.3.rst | 2 +- Doc/whatsnew/3.4.rst | 2 +- Doc/whatsnew/3.8.rst | 2 +- Misc/NEWS.d/3.12.0a1.rst | 2 +- Misc/NEWS.d/3.12.0a2.rst | 2 +- Misc/NEWS.d/3.12.0a3.rst | 2 +- Misc/NEWS.d/3.5.0rc1.rst | 2 +- Misc/NEWS.d/3.5.1rc1.rst | 2 +- Misc/NEWS.d/3.8.0a1.rst | 2 +- Misc/NEWS.d/3.8.0a4.rst | 2 +- Misc/NEWS.d/3.9.0a1.rst | 4 +- 30 files changed, 99 insertions(+), 95 deletions(-) diff --git a/Doc/extending/windows.rst b/Doc/extending/windows.rst index 1129b0968bc4e6..e366d6cb9f79e3 100644 --- a/Doc/extending/windows.rst +++ b/Doc/extending/windows.rst @@ -132,4 +132,4 @@ modules (including Python) to be able to see your identifiers, you have to say Developer Studio will throw in a lot of import libraries that you do not really need, adding about 100K to your executable. To get rid of them, use the Project Settings dialog, Link tab, to specify *ignore default libraries*. Add the -correct :file:`msvcrtxx.lib` to the list of libraries. +correct :file:`msvcrt{xx}.lib` to the list of libraries. diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 772973edadd9d8..588f5a0a53ded0 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1728,7 +1728,7 @@ when (and if) the logged message is actually about to be output to a log by a handler. So the only slightly unusual thing which might trip you up is that the parentheses go around the format string and the arguments, not just the format string. That's because the __ notation is just syntax sugar for a constructor -call to one of the XXXMessage classes. +call to one of the :samp:`{XXX}Message` classes. If you prefer, you can use a :class:`LoggerAdapter` to achieve a similar effect to the above, as in the following example:: @@ -2644,7 +2644,7 @@ when (and if) the logged message is actually about to be output to a log by a handler. So the only slightly unusual thing which might trip you up is that the parentheses go around the format string and the arguments, not just the format string. That’s because the __ notation is just syntax sugar for a constructor -call to one of the ``XXXMessage`` classes shown above. +call to one of the :samp:`{XXX}Message` classes shown above. .. _filters-dictconfig: diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index a72e9a820ef347..7330cf675baa36 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -979,7 +979,7 @@ provided: #. :class:`NullHandler` instances do nothing with error messages. They are used by library developers who want to use logging, but want to avoid the 'No - handlers could be found for logger XXX' message which can be displayed if + handlers could be found for logger *XXX*' message which can be displayed if the library user has not configured logging. See :ref:`library-config` for more information. diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 8225236350d22e..053bf64addb821 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -345,9 +345,10 @@ The following error handlers can be used with all Python +-------------------------+-----------------------------------------------+ | ``'backslashreplace'`` | Replace with backslashed escape sequences. | | | On encoding, use hexadecimal form of Unicode | -| | code point with formats ``\xhh`` ``\uxxxx`` | -| | ``\Uxxxxxxxx``. On decoding, use hexadecimal | -| | form of byte value with format ``\xhh``. | +| | code point with formats :samp:`\\x{hh}` | +| | :samp:`\\u{xxxx}` :samp:`\\U{xxxxxxxx}`. | +| | On decoding, use hexadecimal form of byte | +| | value with format :samp:`\\x{hh}`. | | | Implemented in | | | :func:`backslashreplace_errors`. | +-------------------------+-----------------------------------------------+ @@ -373,8 +374,9 @@ The following error handlers are only applicable to encoding (within +=========================+===============================================+ | ``'xmlcharrefreplace'`` | Replace with XML/HTML numeric character | | | reference, which is a decimal form of Unicode | -| | code point with format ``&#num;`` Implemented | -| | in :func:`xmlcharrefreplace_errors`. | +| | code point with format :samp:`&#{num};`. | +| | Implemented in | +| | :func:`xmlcharrefreplace_errors`. | +-------------------------+-----------------------------------------------+ | ``'namereplace'`` | Replace with ``\N{...}`` escape sequences, | | | what appears in the braces is the Name | @@ -478,8 +480,9 @@ functions: Malformed data is replaced by a backslashed escape sequence. On encoding, use the hexadecimal form of Unicode code point with formats - ``\xhh`` ``\uxxxx`` ``\Uxxxxxxxx``. On decoding, use the hexadecimal form of - byte value with format ``\xhh``. + :samp:`\\x{hh}` :samp:`\\u{xxxx}` :samp:`\\U{xxxxxxxx}`. + On decoding, use the hexadecimal form of + byte value with format :samp:`\\x{hh}`. .. versionchanged:: 3.5 Works with decoding and translating. @@ -492,7 +495,7 @@ functions: The unencodable character is replaced by an appropriate XML/HTML numeric character reference, which is a decimal form of Unicode code point with - format ``&#num;`` . + format :samp:`&#{num};` . .. function:: namereplace_errors(exception) @@ -1346,9 +1349,10 @@ encodings. | | | supported. | +--------------------+---------+---------------------------+ | raw_unicode_escape | | Latin-1 encoding with | -| | | ``\uXXXX`` and | -| | | ``\UXXXXXXXX`` for other | -| | | code points. Existing | +| | | :samp:`\\u{XXXX}` and | +| | | :samp:`\\U{XXXXXXXX}`` | +| | | for other code points. | +| | | Existing | | | | backslashes are not | | | | escaped in any way. | | | | It is used in the Python | diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst index 4226348a17240a..75b97d6ff4588e 100644 --- a/Doc/library/compileall.rst +++ b/Doc/library/compileall.rst @@ -29,7 +29,7 @@ compile Python sources. Positional arguments are files to compile or directories that contain source files, traversed recursively. If no argument is given, behave as if - the command line was ``-l ``. + the command line was :samp:`-l {}`. .. cmdoption:: -l diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index d7f89cf96368b5..de3b93f5e61073 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -61,7 +61,7 @@ By default, ``pip`` is installed into the current virtual environment active virtual environment). The installation location can be controlled through two additional command line options: -* ``--root ``: Installs ``pip`` relative to the given root directory +* :samp:`--root {dir}`: Installs ``pip`` relative to the given root directory rather than the root of the currently active virtual environment (if any) or the default root for the current Python installation. * ``--user``: Installs ``pip`` into the user site packages directory rather diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 593591f6ceca17..3cb70b7fda8d78 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1271,7 +1271,7 @@ are always available. They are listed here in alphabetical order. * ``'xmlcharrefreplace'`` is only supported when writing to a file. Characters not supported by the encoding are replaced with the - appropriate XML character reference ``&#nnn;``. + appropriate XML character reference :samp:`&#{nnn};`. * ``'backslashreplace'`` replaces malformed data by Python's backslashed escape sequences. diff --git a/Doc/library/html.parser.rst b/Doc/library/html.parser.rst index 03aff25ce6117a..d35090111e0822 100644 --- a/Doc/library/html.parser.rst +++ b/Doc/library/html.parser.rst @@ -173,7 +173,7 @@ implementations do nothing (except for :meth:`~HTMLParser.handle_startendtag`): .. method:: HTMLParser.handle_charref(name) This method is called to process decimal and hexadecimal numeric character - references of the form ``&#NNN;`` and ``&#xNNN;``. For example, the decimal + references of the form :samp:`&#{NNN};` and :samp:`&#x{NNN};`. For example, the decimal equivalent for ``>`` is ``>``, whereas the hexadecimal is ``>``; in this case the method will receive ``'62'`` or ``'x3E'``. This method is never called if *convert_charrefs* is ``True``. diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index ae75e6dc5fdcf3..f9b9425bec3e8d 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -217,7 +217,7 @@ provides three different variants: attribute holds the default values for *message* and *explain* that will be used if no value is provided; for unknown codes the default value for both is the string ``???``. The body will be empty if the method is - HEAD or the response code is one of the following: ``1xx``, + HEAD or the response code is one of the following: :samp:`1{xx}`, ``204 No Content``, ``205 Reset Content``, ``304 Not Modified``. .. versionchanged:: 3.4 diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 74897a76b1d20a..4ffd520f9ecd8b 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -88,8 +88,8 @@ startup by the :c:func:`PyConfig_Read` function: see On some systems, conversion using the file system encoding may fail. In this case, Python uses the :ref:`surrogateescape encoding error handler `, which means that undecodable bytes are replaced by a - Unicode character U+DCxx on decoding, and these are again translated to the - original byte on encoding. + Unicode character U+DC\ *xx* on decoding, and these are again + translated to the original byte on encoding. The :term:`file system encoding ` must diff --git a/Doc/library/re.rst b/Doc/library/re.rst index d4334d330aed76..92aae10030f8a2 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -660,7 +660,7 @@ three digits in length. Unknown escapes consisting of ``'\'`` and an ASCII letter now are errors. .. versionchanged:: 3.8 - The ``'\N{name}'`` escape sequence has been added. As in string literals, + The :samp:`'\\N\\{{name}\\}'` escape sequence has been added. As in string literals, it expands to the named Unicode character (e.g. ``'\N{EM DASH}'``). diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 26bee990cf5d7f..6fb4c0f1c53893 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -753,7 +753,7 @@ always available. Return the current value of the flags that are used for :c:func:`dlopen` calls. Symbolic names for the flag values can be - found in the :mod:`os` module (``RTLD_xxx`` constants, e.g. + found in the :mod:`os` module (:samp:`RTLD_{xxx}` constants, e.g. :const:`os.RTLD_LAZY`). .. availability:: Unix. @@ -1441,7 +1441,7 @@ always available. lazy resolving of symbols when importing a module, if called as ``sys.setdlopenflags(0)``. To share symbols across extension modules, call as ``sys.setdlopenflags(os.RTLD_GLOBAL)``. Symbolic names for the flag values - can be found in the :mod:`os` module (``RTLD_xxx`` constants, e.g. + can be found in the :mod:`os` module (:samp:`RTLD_{xxx}` constants, e.g. :const:`os.RTLD_LAZY`). .. availability:: Unix. diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index e1aa4ebb0964dd..53e5f0395715d7 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -598,7 +598,7 @@ task isn't already covered by the URL parsing functions above. .. function:: quote(string, safe='/', encoding=None, errors=None) - Replace special characters in *string* using the ``%xx`` escape. Letters, + Replace special characters in *string* using the :samp:`%{xx}` escape. Letters, digits, and the characters ``'_.-~'`` are never quoted. By default, this function is intended for quoting the path section of a URL. The optional *safe* parameter specifies additional ASCII characters that should not be @@ -645,7 +645,7 @@ task isn't already covered by the URL parsing functions above. .. function:: unquote(string, encoding='utf-8', errors='replace') - Replace ``%xx`` escapes with their single-character equivalent. + Replace :samp:`%{xx}` escapes with their single-character equivalent. The optional *encoding* and *errors* parameters specify how to decode percent-encoded sequences into Unicode characters, as accepted by the :meth:`bytes.decode` method. @@ -676,7 +676,7 @@ task isn't already covered by the URL parsing functions above. .. function:: unquote_to_bytes(string) - Replace ``%xx`` escapes with their single-octet equivalent, and return a + Replace :samp:`%{xx}` escapes with their single-octet equivalent, and return a :class:`bytes` object. *string* may be either a :class:`str` or a :class:`bytes` object. diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 83cd4402a36cf6..9cad790fed4ef0 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -557,51 +557,51 @@ Unless an ``'r'`` or ``'R'`` prefix is present, escape sequences in string and bytes literals are interpreted according to rules similar to those used by Standard C. The recognized escape sequences are: -+-----------------+---------------------------------+-------+ -| Escape Sequence | Meaning | Notes | -+=================+=================================+=======+ -| ``\``\ | Backslash and newline ignored | \(1) | -+-----------------+---------------------------------+-------+ -| ``\\`` | Backslash (``\``) | | -+-----------------+---------------------------------+-------+ -| ``\'`` | Single quote (``'``) | | -+-----------------+---------------------------------+-------+ -| ``\"`` | Double quote (``"``) | | -+-----------------+---------------------------------+-------+ -| ``\a`` | ASCII Bell (BEL) | | -+-----------------+---------------------------------+-------+ -| ``\b`` | ASCII Backspace (BS) | | -+-----------------+---------------------------------+-------+ -| ``\f`` | ASCII Formfeed (FF) | | -+-----------------+---------------------------------+-------+ -| ``\n`` | ASCII Linefeed (LF) | | -+-----------------+---------------------------------+-------+ -| ``\r`` | ASCII Carriage Return (CR) | | -+-----------------+---------------------------------+-------+ -| ``\t`` | ASCII Horizontal Tab (TAB) | | -+-----------------+---------------------------------+-------+ -| ``\v`` | ASCII Vertical Tab (VT) | | -+-----------------+---------------------------------+-------+ -| ``\ooo`` | Character with octal value | (2,4) | -| | *ooo* | | -+-----------------+---------------------------------+-------+ -| ``\xhh`` | Character with hex value *hh* | (3,4) | -+-----------------+---------------------------------+-------+ ++-------------------------+---------------------------------+-------+ +| Escape Sequence | Meaning | Notes | ++=========================+=================================+=======+ +| ``\``\ | Backslash and newline ignored | \(1) | ++-------------------------+---------------------------------+-------+ +| ``\\`` | Backslash (``\``) | | ++-------------------------+---------------------------------+-------+ +| ``\'`` | Single quote (``'``) | | ++-------------------------+---------------------------------+-------+ +| ``\"`` | Double quote (``"``) | | ++-------------------------+---------------------------------+-------+ +| ``\a`` | ASCII Bell (BEL) | | ++-------------------------+---------------------------------+-------+ +| ``\b`` | ASCII Backspace (BS) | | ++-------------------------+---------------------------------+-------+ +| ``\f`` | ASCII Formfeed (FF) | | ++-------------------------+---------------------------------+-------+ +| ``\n`` | ASCII Linefeed (LF) | | ++-------------------------+---------------------------------+-------+ +| ``\r`` | ASCII Carriage Return (CR) | | ++-------------------------+---------------------------------+-------+ +| ``\t`` | ASCII Horizontal Tab (TAB) | | ++-------------------------+---------------------------------+-------+ +| ``\v`` | ASCII Vertical Tab (VT) | | ++-------------------------+---------------------------------+-------+ +| :samp:`\\{ooo}` | Character with octal value | (2,4) | +| | *ooo* | | ++-------------------------+---------------------------------+-------+ +| :samp:`\\x{hh}` | Character with hex value *hh* | (3,4) | ++-------------------------+---------------------------------+-------+ Escape sequences only recognized in string literals are: -+-----------------+---------------------------------+-------+ -| Escape Sequence | Meaning | Notes | -+=================+=================================+=======+ -| ``\N{name}`` | Character named *name* in the | \(5) | -| | Unicode database | | -+-----------------+---------------------------------+-------+ -| ``\uxxxx`` | Character with 16-bit hex value | \(6) | -| | *xxxx* | | -+-----------------+---------------------------------+-------+ -| ``\Uxxxxxxxx`` | Character with 32-bit hex value | \(7) | -| | *xxxxxxxx* | | -+-----------------+---------------------------------+-------+ ++-------------------------+---------------------------------+-------+ +| Escape Sequence | Meaning | Notes | ++=========================+=================================+=======+ +| :samp:`\\N\\{{name}\\}` | Character named *name* in the | \(5) | +| | Unicode database | | ++-------------------------+---------------------------------+-------+ +| :samp:`\\u{xxxx}` | Character with 16-bit hex value | \(6) | +| | *xxxx* | | ++-------------------------+---------------------------------+-------+ +| :samp:`\\U{xxxxxxxx}` | Character with 32-bit hex value | \(7) | +| | *xxxxxxxx* | | ++-------------------------+---------------------------------+-------+ Notes: diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 00520000b871cd..d9d52945bcdbe2 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -777,7 +777,7 @@ differently depending if the ``Py_BUILD_CORE_MODULE`` macro is defined: * Use ``Py_IMPORTED_SYMBOL`` otherwise. If the ``Py_BUILD_CORE_BUILTIN`` macro is used by mistake on a C extension -built as a shared library, its ``PyInit_xxx()`` function is not exported, +built as a shared library, its :samp:`PyInit_{xxx}()` function is not exported, causing an :exc:`ImportError` on import. @@ -798,8 +798,8 @@ Preprocessor flags .. envvar:: CPPFLAGS - (Objective) C/C++ preprocessor flags, e.g. ``-I`` if you have - headers in a nonstandard directory ````. + (Objective) C/C++ preprocessor flags, e.g. :samp:`-I{include_dir}` if you have + headers in a nonstandard directory *include_dir*. Both :envvar:`CPPFLAGS` and :envvar:`LDFLAGS` need to contain the shell's value to be able to build extension modules using the @@ -988,8 +988,8 @@ Linker flags .. envvar:: LDFLAGS - Linker flags, e.g. ``-L`` if you have libraries in a nonstandard - directory ````. + Linker flags, e.g. :samp:`-L{lib_dir}` if you have libraries in a nonstandard + directory *lib_dir*. Both :envvar:`CPPFLAGS` and :envvar:`LDFLAGS` need to contain the shell's value to be able to build extension modules using the diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 1c305d983dfa41..919b76f2816a80 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -889,7 +889,7 @@ minor version. I.e. ``/usr/bin/python3.7-32`` will request usage of the The "-64" suffix is deprecated, and now implies "any architecture that is not provably i386/32-bit". To request a specific environment, use the new - ``-V:`` argument with the complete tag. + :samp:`-V:{TAG}` argument with the complete tag. The ``/usr/bin/env`` form of shebang line has one further special property. Before looking for installed Python interpreters, this form will search the @@ -1192,7 +1192,7 @@ non-standard paths in the registry and user site-packages. * Adds ``._pth`` file support and removes ``applocal`` option from ``pyvenv.cfg``. - * Adds ``pythonXX.zip`` as a potential landmark when directly adjacent + * Adds :file:`python{XX}.zip` as a potential landmark when directly adjacent to the executable. .. deprecated:: diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst index 5e9d03e48d97c1..a5fc847de24081 100644 --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -153,9 +153,9 @@ Lundh. A detailed explanation of the interface was written up as :pep:`100`, significant points about the Unicode interfaces. In Python source code, Unicode strings are written as ``u"string"``. Arbitrary -Unicode characters can be written using a new escape sequence, ``\uHHHH``, where +Unicode characters can be written using a new escape sequence, :samp:`\\u{HHHH}`, where *HHHH* is a 4-digit hexadecimal number from 0000 to FFFF. The existing -``\xHHHH`` escape sequence can also be used, and octal escapes can be used for +:samp:`\\x{HH}` escape sequence can also be used, and octal escapes can be used for characters up to U+01FF, which is represented by ``\777``. Unicode strings, just like regular strings, are an immutable sequence type. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index b975aea7d6894a..128407e3fba132 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -125,7 +125,7 @@ and to C extension code as :c:data:`Py_Py3kWarningFlag`. .. seealso:: - The 3xxx series of PEPs, which contains proposals for Python 3.0. + The 3\ *xxx* series of PEPs, which contains proposals for Python 3.0. :pep:`3000` describes the development process for Python 3.0. Start with :pep:`3100` that describes the general goals for Python 3.0, and then explore the higher-numbered PEPS that propose diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 9aef37d848ab97..88eaee9791415b 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -218,7 +218,7 @@ Windows ``py.exe`` launcher improvements The copy of the :ref:`launcher` included with Python 3.11 has been significantly updated. It now supports company/tag syntax as defined in :pep:`514` using the -``-V:/`` argument instead of the limited ``-.``. +:samp:`-V:{}/{}` argument instead of the limited :samp:`-{}.{}`. This allows launching distributions other than ``PythonCore``, the one hosted on `python.org `_. @@ -227,8 +227,8 @@ installs will be searched. For example, ``-V:OtherPython/`` will select the "best" tag registered for ``OtherPython``, while ``-V:3.11`` or ``-V:/3.11`` will select the "best" distribution with tag ``3.11``. -When using the legacy ``-``, ``-.``, -``--`` or ``-.-`` arguments, +When using the legacy :samp:`-{}`, :samp:`-{}.{}`, +:samp:`-{}-{}` or :samp:`-{}.{}-{}` arguments, all existing behaviour should be preserved from past versions, and only releases from ``PythonCore`` will be selected. However, the ``-64`` suffix now implies "not 32-bit" (not necessarily x86-64), diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 8d2bd0a2ae8da0..3361789ff6f35a 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -2067,7 +2067,7 @@ The :pep:`418` added new functions to the :mod:`time` module: Other new functions: * :func:`~time.clock_getres`, :func:`~time.clock_gettime` and - :func:`~time.clock_settime` functions with ``CLOCK_xxx`` constants. + :func:`~time.clock_settime` functions with :samp:`CLOCK_{xxx}` constants. (Contributed by Victor Stinner in :issue:`10278`.) To improve cross platform consistency, :func:`~time.sleep` now raises a diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index acb662188b05ac..8e2d0427dafb2d 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2085,7 +2085,7 @@ Deprecations in the Python API :meth:`importlib.abc.MetaPathFinder.find_spec`; :meth:`!importlib.abc.PathEntryFinder.find_loader` and :meth:`!find_module` are replaced by - :meth:`importlib.abc.PathEntryFinder.find_spec`; all of the ``xxxLoader`` ABC + :meth:`importlib.abc.PathEntryFinder.find_spec`; all of the :samp:`{xxx}Loader` ABC ``load_module`` methods (:meth:`!importlib.abc.Loader.load_module`, :meth:`!importlib.abc.InspectLoader.load_module`, :meth:`!importlib.abc.FileLoader.load_module`, diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 5b667851c79942..68fd4d7759a127 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -404,7 +404,7 @@ Other Language Changes or :meth:`~object.__complex__` is not available. (Contributed by Serhiy Storchaka in :issue:`20092`.) -* Added support of ``\N{name}`` escapes in :mod:`regular expressions `:: +* Added support of :samp:`\\N\\{{name}\\}` escapes in :mod:`regular expressions `:: >>> notice = 'Copyright © 2019' >>> copyright_year_pattern = re.compile(r'\N{copyright sign}\s*(\d{4})') diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 5723d1ab20082a..15630b590fb210 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -5350,7 +5350,7 @@ in a virtual environment. .. nonce: FbHZuS .. section: Windows -Fix :file:`py.exe` launcher handling of ``-V:/`` option when +Fix :file:`py.exe` launcher handling of :samp:`-V:{}/` option when default preferences have been set in environment variables or configuration files. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 41f5f67df01d91..1a04ed473f329d 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -8,7 +8,7 @@ The IDNA codec decoder used on DNS hostnames by :mod:`socket` or :mod:`asyncio` related name resolution functions no longer involves a quadratic algorithm. This prevents a potential CPU denial of service if an out-of-spec excessive length hostname involving bidirectional characters -were decoded. Some protocols such as :mod:`urllib` http ``3xx`` redirects +were decoded. Some protocols such as :mod:`urllib` http :samp:`3{xx}` redirects potentially allow for an attacker to supply such a name. Individual labels within an IDNA encoded DNS name will now raise an error diff --git a/Misc/NEWS.d/3.12.0a3.rst b/Misc/NEWS.d/3.12.0a3.rst index 27bd456f3f05d9..ce128fd5f80c77 100644 --- a/Misc/NEWS.d/3.12.0a3.rst +++ b/Misc/NEWS.d/3.12.0a3.rst @@ -9,7 +9,7 @@ within a garbage request to be printed to the stderr server log. This is done by changing the :mod:`http.server` :class:`BaseHTTPRequestHandler` ``.log_message`` method to replace control -characters with a ``\xHH`` hex escape before printing. +characters with a :samp:`\\x{HH}` hex escape before printing. .. diff --git a/Misc/NEWS.d/3.5.0rc1.rst b/Misc/NEWS.d/3.5.0rc1.rst index 1fb9bc6c04da38..64e9435b252acb 100644 --- a/Misc/NEWS.d/3.5.0rc1.rst +++ b/Misc/NEWS.d/3.5.0rc1.rst @@ -168,7 +168,7 @@ Sanad Zaki Rizvi. Idle editor default font. Switch from Courier to platform-sensitive TkFixedFont. This should not affect current customized font selections. If -there is a problem, edit $HOME/.idlerc/config-main.cfg and remove 'fontxxx' +there is a problem, edit $HOME/.idlerc/config-main.cfg and remove ':samp:`font{xxx}`' entries from [Editor Window]. Patch by Mark Roseman. .. diff --git a/Misc/NEWS.d/3.5.1rc1.rst b/Misc/NEWS.d/3.5.1rc1.rst index dc247ce2096a7d..05e1ecfaf6bc79 100644 --- a/Misc/NEWS.d/3.5.1rc1.rst +++ b/Misc/NEWS.d/3.5.1rc1.rst @@ -189,7 +189,7 @@ comprehensions correspond to the opening brace. .. nonce: 0Gh-Ty .. section: Core and Builtins -Hide the private _Py_atomic_xxx symbols from the public Python.h header to +Hide the private :samp:`_Py_atomic_{xxx}` symbols from the public Python.h header to fix a compilation error with OpenMP. PyThreadState_GET() becomes an alias to PyThreadState_Get() to avoid ABI incompatibilities. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index 0c0dd5377c2113..d4e6ddc9c183cd 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -8253,7 +8253,7 @@ Explain how IDLE's Shell displays output. Improve the doc about IDLE running user code. The section is renamed from "IDLE -- console differences" is renamed "Running user code". It mostly -covers the implications of using custom sys.stdxxx objects. +covers the implications of using custom :samp:sys.std{xxx}` objects. .. diff --git a/Misc/NEWS.d/3.8.0a4.rst b/Misc/NEWS.d/3.8.0a4.rst index 2ce60f39539e8c..f19717c8e2fe90 100644 --- a/Misc/NEWS.d/3.8.0a4.rst +++ b/Misc/NEWS.d/3.8.0a4.rst @@ -1087,7 +1087,7 @@ on the ABI. Change ``PyAPI_FUNC(type)``, ``PyAPI_DATA(type)`` and ``PyMODINIT_FUNC`` macros of ``pyport.h`` when ``Py_BUILD_CORE_MODULE`` is defined. The ``Py_BUILD_CORE_MODULE`` define must be now be used to build a C extension -as a dynamic library accessing Python internals: export the PyInit_xxx() +as a dynamic library accessing Python internals: export the :samp:`PyInit_{xxx}()` function in DLL exports on Windows. .. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 5f4e04b8b8ddcc..a4d71d0290ce1a 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -4118,7 +4118,7 @@ Add tests for ROT-13 codec. .. nonce: Zoe9ek .. section: Tests -Added tests for PyDateTime_xxx_GET_xxx() macros of the C API of the +Added tests for :samp:`PyDateTime_{xxx}_GET_{xxx}()` macros of the C API of the :mod:`datetime` module. Patch by Joannah Nanjekye. .. @@ -4576,7 +4576,7 @@ distutils bdist_wininst: bdist_wininst only works on Windows. .. nonce: j5ebdT .. section: Build -Many ``PyRun_XXX()`` functions like :c:func:`PyRun_String` were no longer +Many :samp:`PyRun_{XXX}()` functions like :c:func:`PyRun_String` were no longer exported in ``libpython38.dll`` by mistake. Export them again to fix the ABI compatibility. From 6f1d4552b3e273ddce92b03fe50094523875aafd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 24 Sep 2023 04:55:28 -0700 Subject: [PATCH 0807/1206] [3.12] gh-101100: Fix sphinx warnings in `Doc/library/xml.etree.elementtree.rst` (GH-109799) (#109800) gh-101100: Fix sphinx warnings in `Doc/library/xml.etree.elementtree.rst` (GH-109799) (cherry picked from commit 649768fb6781ba810df44017fee1975a11d65e2f) gh-101100: Fix shpinx warnings in `Doc/library/xml.etree.elementtree.rst` Co-authored-by: Nikita Sobolev --- Doc/library/xml.etree.elementtree.rst | 7 ++++++- Doc/tools/.nitignore | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index f9290f528e5555..54c93008503c02 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -17,7 +17,7 @@ for parsing and creating XML data. This module will use a fast implementation whenever available. .. deprecated:: 3.3 - The :mod:`xml.etree.cElementTree` module is deprecated. + The :mod:`!xml.etree.cElementTree` module is deprecated. .. warning:: @@ -825,6 +825,8 @@ Reference Functions ^^^^^^^^^ +.. module:: xml.etree.ElementInclude + .. function:: xml.etree.ElementInclude.default_loader( href, parse, encoding=None) :module: @@ -862,6 +864,9 @@ Functions Element Objects ^^^^^^^^^^^^^^^ +.. module:: xml.etree.ElementTree + :noindex: + .. class:: Element(tag, attrib={}, **extra) Element class. This class defines the Element interface, and provides a diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 3fc3303376cce6..e6b47ec6e2d25c 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -154,7 +154,6 @@ Doc/library/xdrlib.rst Doc/library/xml.dom.minidom.rst Doc/library/xml.dom.pulldom.rst Doc/library/xml.dom.rst -Doc/library/xml.etree.elementtree.rst Doc/library/xml.rst Doc/library/xml.sax.handler.rst Doc/library/xml.sax.reader.rst From d56835f85570b57341e1b44e40f1393bdcd4de82 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 03:15:46 -0700 Subject: [PATCH 0808/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Use the ``:file:`` role (GH-109756) (#109806) GH-109190: Copyedit 3.12 What's New: Use the ``:file:`` role (GH-109756) (cherry picked from commit 8d365b60bacf0a7edda24eba2d45aba1c2626fbc) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.12.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 04adf57865215c..efb1b13c65c167 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1584,7 +1584,7 @@ zipimport Others ------ -* Removed the ``suspicious`` rule from the documentation Makefile, and +* Removed the ``suspicious`` rule from the documentation :file:`Makefile`, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint `_. (Contributed by Julien Palard in :gh:`98179`.) @@ -1711,9 +1711,9 @@ Changes in the Python API Build Changes ============= -* Python no longer uses ``setup.py`` to build shared C extension modules. +* Python no longer uses :file:`setup.py` to build shared C extension modules. Build parameters like headers and libraries are detected in ``configure`` - script. Extensions are built by ``Makefile``. Most extensions use + script. Extensions are built by :file:`Makefile`. Most extensions use ``pkg-config`` and fall back to manual detection. (Contributed by Christian Heimes in :gh:`93939`.) @@ -1726,7 +1726,7 @@ Build Changes if the Clang compiler accepts the flag. (Contributed by Donghee Na in :gh:`89536`.) -* Add ``COMPILEALL_OPTS`` variable in Makefile to override :mod:`compileall` +* Add ``COMPILEALL_OPTS`` variable in :file:`Makefile` to override :mod:`compileall` options (default: ``-j0``) in ``make install``. Also merged the 3 ``compileall`` commands into a single command to build .pyc files for all optimization levels (0, 1, 2) at once. @@ -1895,7 +1895,7 @@ New Features - ``SSTATE_INTERNED_IMMORTAL_STATIC`` An identifier for interned unicode objects that are immortal and static - ``sys.getunicodeinternedsize`` This returns the total number of unicode - objects that have been interned. This is now needed for refleak.py to + objects that have been interned. This is now needed for :file:`refleak.py` to correctly track reference counts and allocated blocks (Contributed by Eddie Elizondo in :gh:`84436`.) @@ -2086,10 +2086,10 @@ Deprecated * Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases is deprecated and will be disabled in Python 3.14. -* The ``structmember.h`` header is deprecated, though it continues to be +* The :file:`structmember.h` header is deprecated, though it continues to be available and there are no plans to remove it. - Its contents are now available just by including ``Python.h``, + Its contents are now available just by including :file:`Python.h`, with a ``Py`` prefix added if it was missing: - :c:struct:`PyMemberDef`, :c:func:`PyMember_GetOne` and @@ -2099,14 +2099,14 @@ Deprecated - The flags :c:macro:`Py_READONLY` (previously ``READONLY``) and :c:macro:`Py_AUDIT_READ` (previously all uppercase) - Several items are not exposed from ``Python.h``: + Several items are not exposed from :file:`Python.h`: - :c:macro:`T_OBJECT` (use :c:macro:`Py_T_OBJECT_EX`) - :c:macro:`T_NONE` (previously undocumented, and pretty quirky) - The macro ``WRITE_RESTRICTED`` which does nothing. - The macros ``RESTRICTED`` and ``READ_RESTRICTED``, equivalents of :c:macro:`Py_AUDIT_READ`. - - In some configurations, ```` is not included from ``Python.h``. + - In some configurations, ```` is not included from :file:`Python.h`. It should be included manually when using ``offsetof()``. The deprecated header continues to provide its original @@ -2136,8 +2136,8 @@ Deprecated Removed ------- -* Remove the ``token.h`` header file. There was never any public tokenizer C - API. The ``token.h`` header file was only designed to be used by Python +* Remove the :file:`token.h` header file. There was never any public tokenizer C + API. The :file:`token.h` header file was only designed to be used by Python internals. (Contributed by Victor Stinner in :gh:`92651`.) From cb4a8c273da848a8b6bd9670e77731f997cb1bbd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 03:16:00 -0700 Subject: [PATCH 0809/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Increase the prominence of the setuptools removal (GH-109768) (#109815) GH-109190: Copyedit 3.12 What's New: Increase the prominence of the setuptools removal (GH-109768) (cherry picked from commit 09a73d50f687b9b388b0386f400d9ba5a7c5f2a5) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index efb1b13c65c167..c2e7068ce0962c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -93,6 +93,13 @@ Important deprecations, removals or restrictions: `the migration guide `_ for advice on its replacement. +* :gh:`95299`: Do not pre-install ``setuptools`` in virtual environments + created with :mod:`venv`. + This means that ``distutils``, ``setuptools``, ``pkg_resources``, + and ``easy_install`` will no longer available by default; to access these + run ``pip install setuptools`` in the :ref:`activated ` + virtual environment. + Improved Error Messages ======================= From 52b2f9f66855c18c41e494ab9402f6e16b738c74 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 03:16:13 -0700 Subject: [PATCH 0810/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Update the ``imp`` porting guidance (GH-109755) (#109816) GH-109190: Copyedit 3.12 What's New: Update the ``imp`` porting guidance (GH-109755) (cherry picked from commit 7b8bfe1644c3d008c1b5c19a537ee7d19bc32c59) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index c2e7068ce0962c..285cd4f9f779ab 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1410,7 +1410,7 @@ imp * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in :gh:`98040`.) -* Replace removed :mod:`!imp` functions with :mod:`importlib` functions: + To migrate, consult the following correspondence table: ================================= ======================================= imp importlib @@ -1425,9 +1425,10 @@ imp ``imp.new_module(name)`` ``types.ModuleType(name)`` ``imp.reload()`` :func:`importlib.reload` ``imp.source_from_cache()`` :func:`importlib.util.source_from_cache` + ``imp.load_source()`` *See below* ================================= ======================================= -* Replace ``imp.load_source()`` with:: + Replace ``imp.load_source()`` with:: import importlib.util import importlib.machinery From d158bbc2efff61630a5c01522735d4387d3e6392 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 05:25:16 -0700 Subject: [PATCH 0811/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Prefer GitHub issues links (GH-109753) (#109825) GH-109190: Copyedit 3.12 What's New: Prefer GitHub issues links (GH-109753) (cherry picked from commit 7495a93e0f843c40ebc5925c6a35225d41e52654) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 285cd4f9f779ab..bb622c5a2be451 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -659,7 +659,7 @@ inspect * Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals` for determining the current state of asynchronous generators. - (Contributed by Thomas Krennwallner in :issue:`35759`.) + (Contributed by Thomas Krennwallner in :gh:`79940`.) * The performance of :func:`inspect.getattr_static` has been considerably improved. Most calls to the function should be at least 2x faster than they @@ -732,7 +732,7 @@ pathlib * Add *walk_up* optional parameter to :meth:`pathlib.PurePath.relative_to` to allow the insertion of ``..`` entries in the result; this behavior is more consistent with :func:`os.path.relpath`. - (Contributed by Domenico Ragusa in :issue:`40358`.) + (Contributed by Domenico Ragusa in :gh:`84538`.) * Add :meth:`pathlib.Path.is_junction` as a proxy to :func:`os.path.isjunction`. (Contributed by Charles Machalow in :gh:`99547`.) @@ -968,7 +968,7 @@ Added ``--durations`` command line option, showing the N slowest test cases:: OK (skipped=3) -(Contributed by Giampaolo Rodola in :issue:`4080`) +(Contributed by Giampaolo Rodola in :gh:`48330`) uuid ---- @@ -1563,7 +1563,7 @@ unittest * An alias of the :class:`~unittest.TextTestResult` class: ``_TextTestResult`` (deprecated in Python 3.2). - (Contributed by Serhiy Storchaka in :issue:`45162`.) + (Contributed by Serhiy Storchaka in :gh:`89325`.) webbrowser ---------- From d4dd8a17e161fe8b3b174a2b3362d36a6e9d35fc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 05:25:27 -0700 Subject: [PATCH 0812/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Trivia (GH-109760) (#109826) GH-109190: Copyedit 3.12 What's New: Trivia (GH-109760) (cherry picked from commit f08772cfd8f6602077e0989c1daa8bf74a8c15f1) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index bb622c5a2be451..4d8cf9fc8fe74f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -3,7 +3,7 @@ What's New In Python 3.12 **************************** -:Editor: TBD +:Editor: Adam Turner .. Rules for maintenance: @@ -46,15 +46,12 @@ researching a change. This article explains the new features in Python 3.12, compared to 3.11. - +Python 3.12 will be released on October 2, 2023. For full details, see the :ref:`changelog `. -.. note:: - - Prerelease users should be aware that this document is currently in draft - form. It will be updated substantially as Python 3.12 moves towards release, - so it's worth checking back even after reading earlier versions. +.. seealso:: + :pep:`693` -- Python 3.12 Release Schedule Summary -- Release highlights ============================= From de6d17c5dda49b7df93c77a73759ea3efc0ec8b4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:36:31 -0700 Subject: [PATCH 0813/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Use the present tense (GH-109754) (#109827) GH-109190: Copyedit 3.12 What's New: Use the present tense (GH-109754) (cherry picked from commit 4e478534d73e46aea5d10fb4e0ddf2c34440d0f6) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 60 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4d8cf9fc8fe74f..a14a231ec7e903 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -570,7 +570,7 @@ asyncio writing to sockets and uses :meth:`~socket.socket.sendmsg` if the platform supports it. (Contributed by Kumar Aditya in :gh:`91166`.) -* Added :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory` +* Add :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory` functions to allow opting an event loop in to eager task execution, making some use-cases 2x to 5x faster. (Contributed by Jacob Bower & Itamar Oren in :gh:`102853`, :gh:`104140`, and :gh:`104138`) @@ -666,17 +666,17 @@ inspect itertools --------- -* Added :class:`itertools.batched()` for collecting into even-sized +* Add :class:`itertools.batched()` for collecting into even-sized tuples where the last batch may be shorter than the rest. (Contributed by Raymond Hettinger in :gh:`98363`.) math ---- -* Added :func:`math.sumprod` for computing a sum of products. +* Add :func:`math.sumprod` for computing a sum of products. (Contributed by Raymond Hettinger in :gh:`100485`.) -* Extended :func:`math.nextafter` to include a *steps* argument +* Extend :func:`math.nextafter` to include a *steps* argument for moving up or down multiple steps at a time. (By Matthias Goergens, Mark Dickinson, and Raymond Hettinger in :gh:`94906`.) @@ -749,10 +749,10 @@ pdb random ------ -* Added :func:`random.binomialvariate`. +* Add :func:`random.binomialvariate`. (Contributed by Raymond Hettinger in :gh:`81620`.) -* Added a default of ``lamb=1.0`` to :func:`random.expovariate`. +* Add a default of ``lamb=1.0`` to :func:`random.expovariate`. (Contributed by Raymond Hettinger in :gh:`100234`.) shutil @@ -811,7 +811,7 @@ sqlite3 statistics ---------- -* Extended :func:`statistics.correlation` to include as a ``ranked`` method +* Extend :func:`statistics.correlation` to include as a ``ranked`` method for computing the Spearman correlation of ranked data. (Contributed by Raymond Hettinger in :gh:`95861`.) @@ -949,7 +949,7 @@ unicodedata unittest -------- -Added ``--durations`` command line option, showing the N slowest test cases:: +Add a ``--durations`` command line option, showing the N slowest test cases:: python3 -m unittest --durations=3 lib.tests.test_threading ..... @@ -977,11 +977,11 @@ uuid Optimizations ============= -* Removed ``wstr`` and ``wstr_length`` members from Unicode objects. +* Remove ``wstr`` and ``wstr_length`` members from Unicode objects. It reduces object size by 8 or 16 bytes on 64bit platform. (:pep:`623`) (Contributed by Inada Naoki in :gh:`92536`.) -* Added experimental support for using the BOLT binary optimizer in the build +* Add experimental support for using the BOLT binary optimizer in the build process, which improves performance by 1-5%. (Contributed by Kevin Modzelewski in :gh:`90536` and tuned by Donghee Na in :gh:`101525`) @@ -1014,7 +1014,7 @@ CPython bytecode changes * Remove the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` instructions. (Contributed by Irit Katriel in :gh:`102859`.) -* Removed the :opcode:`!PRECALL` instruction. (Contributed by Mark Shannon in +* Remove the :opcode:`!PRECALL` instruction. (Contributed by Mark Shannon in :gh:`92925`.) * Add the :opcode:`LOAD_FAST_AND_CLEAR` instruction as part of the @@ -1440,9 +1440,9 @@ imp loader.exec_module(module) return module -* Removed :mod:`!imp` functions and attributes with no replacements: +* Remove :mod:`!imp` functions and attributes with no replacements: - * undocumented functions: + * Undocumented functions: * ``imp.init_builtin()`` * ``imp.load_compiled()`` @@ -1523,7 +1523,7 @@ ssl unittest -------- -* Removed many old deprecated :mod:`unittest` features: +* Remove many long-deprecated :mod:`unittest` features: * A number of :class:`~unittest.TestCase` method aliases: @@ -1566,7 +1566,7 @@ webbrowser ---------- * Remove support for obsolete browsers from :mod:`webbrowser`. - Removed browsers include: Grail, Mosaic, Netscape, Galeon, Skipstone, + The removed browsers include: Grail, Mosaic, Netscape, Galeon, Skipstone, Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). xml.etree.ElementTree @@ -1589,8 +1589,8 @@ zipimport Others ------ -* Removed the ``suspicious`` rule from the documentation :file:`Makefile`, and - removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint +* Remove the ``suspicious`` rule from the documentation :file:`Makefile` and + :file:`Doc/tools/rstlint.py`, both in favor of `sphinx-lint `_. (Contributed by Julien Palard in :gh:`98179`.) @@ -1620,7 +1620,7 @@ Changes in the Python API contain ASCII letters and digits and underscore. (Contributed by Serhiy Storchaka in :gh:`91760`.) -* Removed ``randrange()`` functionality deprecated since Python 3.10. Formerly, +* Remove ``randrange()`` functionality deprecated since Python 3.10. Formerly, ``randrange(10.0)`` losslessly converted to ``randrange(10)``. Now, it raises a :exc:`TypeError`. Also, the exception raised for non-integer values such as ``randrange(10.5)`` or ``randrange('10')`` has been changed from :exc:`ValueError` to @@ -1634,7 +1634,7 @@ Changes in the Python API to :term:`filesystem encoding and error handler`. Argument files should be encoded in UTF-8 instead of ANSI Codepage on Windows. -* Removed the ``asyncore``-based ``smtpd`` module deprecated in Python 3.4.7 +* Remove the ``asyncore``-based ``smtpd`` module deprecated in Python 3.4.7 and 3.5.4. A recommended replacement is the :mod:`asyncio`-based aiosmtpd_ PyPI module. @@ -1761,7 +1761,7 @@ New Features ------------ -* :pep:`697`: Introduced the :ref:`Unstable C API tier `, +* :pep:`697`: Introduce the :ref:`Unstable C API tier `, intended for low-level tools like debuggers and JIT compilers. This API may change in each minor release of CPython without deprecation warnings. @@ -1783,7 +1783,7 @@ New Features (Contributed by Petr Viktorin in :gh:`101101`.) -* :pep:`697`: Added API for extending types whose instance memory layout is +* :pep:`697`: Add an API for extending types whose instance memory layout is opaque: - :c:member:`PyType_Spec.basicsize` can be zero or negative to specify @@ -1798,7 +1798,7 @@ New Features (Contributed by Petr Viktorin in :gh:`103509`.) -* Added the new :ref:`limited C API ` function :c:func:`PyType_FromMetaclass`, +* Add the new :ref:`limited C API ` function :c:func:`PyType_FromMetaclass`, which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using an additional metaclass argument. (Contributed by Wenzel Jakob in :gh:`93012`.) @@ -1837,13 +1837,13 @@ New Features protocol are now available in the :ref:`Limited API `. (Contributed by Wenzel Jakob in :gh:`98586`.) -* Added two new public functions, +* Add two new public functions, :c:func:`PyEval_SetProfileAllThreads` and :c:func:`PyEval_SetTraceAllThreads`, that allow to set tracing and profiling functions in all running threads in addition to the calling one. (Contributed by Pablo Galindo in :gh:`93503`.) -* Added new function :c:func:`PyFunction_SetVectorcall` to the C API +* Add new function :c:func:`PyFunction_SetVectorcall` to the C API which sets the vectorcall field of a given :c:type:`PyFunctionObject`. (Contributed by Andrew Frost in :gh:`92257`.) @@ -1853,11 +1853,11 @@ New Features compilers, or debuggers. (Contributed by Carl Meyer in :gh:`91052`.) -* Added :c:func:`PyType_AddWatcher` and :c:func:`PyType_Watch` API to register +* Add :c:func:`PyType_AddWatcher` and :c:func:`PyType_Watch` API to register callbacks to receive notification on changes to a type. (Contributed by Carl Meyer in :gh:`91051`.) -* Added :c:func:`PyCode_AddWatcher` and :c:func:`PyCode_ClearWatcher` +* Add :c:func:`PyCode_AddWatcher` and :c:func:`PyCode_ClearWatcher` APIs to register callbacks to receive notification on creation and destruction of code objects. (Contributed by Itamar Oren in :gh:`91054`.) @@ -1887,8 +1887,8 @@ New Features to replace the legacy-api :c:func:`!PyErr_Display`. (Contributed by Irit Katriel in :gh:`102755`). -* :pep:`683`: Introduced Immortal Objects to Python which allows objects - to bypass reference counts and introduced changes to the C-API: +* :pep:`683`: Introduce *Immortal Objects*, which allows objects + to bypass reference counts, and related changes to the C-API: - ``_Py_IMMORTAL_REFCNT``: The reference count that defines an object as immortal. @@ -1905,7 +1905,7 @@ New Features (Contributed by Eddie Elizondo in :gh:`84436`.) -* :pep:`684`: Added the new :c:func:`Py_NewInterpreterFromConfig` +* :pep:`684`: Add the new :c:func:`Py_NewInterpreterFromConfig` function and :c:type:`PyInterpreterConfig`, which may be used to create sub-interpreters with their own GILs. (See :ref:`whatsnew312-pep684` for more info.) @@ -1954,7 +1954,7 @@ Porting to Python 3.12 copied as-is to the result string, and any extra arguments discarded. (Contributed by Serhiy Storchaka in :gh:`95781`.) -* Fixed wrong sign placement in :c:func:`PyUnicode_FromFormat` and +* Fix wrong sign placement in :c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`. (Contributed by Philip Georgi in :gh:`95504`.) From a19251764a3d0bd85e5217879a6b1cb1a649c25d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:37:26 -0700 Subject: [PATCH 0814/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Improve the C-API deprecations section (GH-109751) (#109830) * GH-109190: Copyedit 3.12 What's New: Improve the C-API deprecations section (GH-109751) (cherry picked from commit bccc1b78002c924e8f4121fea5de7df5eb127548) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Serhiy Storchaka * Remove the weakref get object functions --------- Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Serhiy Storchaka --- Doc/whatsnew/3.12.rst | 107 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 13 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a14a231ec7e903..b8cf4e7dfd93e3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1126,11 +1126,6 @@ Deprecated :exc:`ImportWarning`). (Contributed by Brett Cannon in :gh:`65961`.) -* In accordance with :pep:`699`, the ``ma_version_tag`` field in :c:type:`PyDictObject` - is deprecated for extension modules. Accessing this field will generate a compiler - warning at compile time. This field will be removed in Python 3.14. - (Contributed by Ramvikrams and Kumar Aditya in :gh:`101193`. PEP by Ken Jin.) - * The bitwise inversion operator (``~``) on bool is deprecated. It will throw an error in Python 3.14. Use ``not`` for logical negation of bools instead. In the rare case that you really need the bitwise inversion of the underlying @@ -1260,9 +1255,6 @@ Pending Removal in Python 3.14 * :mod:`xml.etree.ElementTree`: Testing the truth value of an :class:`xml.etree.ElementTree.Element` is deprecated and will raise an exception in Python 3.14. -* Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable - bases using the C API (:gh:`95388`). - * ``__package__`` and ``__cached__`` will cease to be set or taken into consideration by the import system (:gh:`97879`). @@ -1272,9 +1264,6 @@ Pending Removal in Python 3.14 May be removed in 3.14. (Contributed by Nikita Sobolev in :gh:`101866`.) -* Creating :c:data:`immutable types ` with mutable - bases using the C API (:gh:`95388`) - Pending Removal in Future Versions ---------------------------------- @@ -2059,6 +2048,11 @@ Porting to Python 3.12 Deprecated ---------- +* In accordance with :pep:`699`, the ``ma_version_tag`` field in :c:type:`PyDictObject` + is deprecated for extension modules. Accessing this field will generate a compiler + warning at compile time. This field will be removed in Python 3.14. + (Contributed by Ramvikrams and Kumar Aditya in :gh:`101193`. PEP by Ken Jin.) + * Deprecate global configuration variable: * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` @@ -2088,8 +2082,8 @@ Deprecated :c:type:`PyConfig` instead. (Contributed by Victor Stinner in :gh:`77782`.) -* Creating immutable types (:c:macro:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable - bases is deprecated and will be disabled in Python 3.14. +* Creating :c:data:`immutable types ` with mutable + bases is deprecated and will be disabled in Python 3.14. (:gh:`95388`) * The :file:`structmember.h` header is deprecated, though it continues to be available and there are no plans to remove it. @@ -2138,6 +2132,93 @@ Deprecated overrides :c:member:`~PyTypeObject.tp_new` is deprecated. Call the metaclass instead. +Pending Removal in Python 3.14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The ``ma_version_tag`` field in :c:type:`PyDictObject` for extension modules + (:pep:`699`; :gh:`101193`). + +* Global configuration variables: + + * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` + * :c:var:`Py_VerboseFlag`: use :c:member:`PyConfig.verbose` + * :c:var:`Py_QuietFlag`: use :c:member:`PyConfig.quiet` + * :c:var:`Py_InteractiveFlag`: use :c:member:`PyConfig.interactive` + * :c:var:`Py_InspectFlag`: use :c:member:`PyConfig.inspect` + * :c:var:`Py_OptimizeFlag`: use :c:member:`PyConfig.optimization_level` + * :c:var:`Py_NoSiteFlag`: use :c:member:`PyConfig.site_import` + * :c:var:`Py_BytesWarningFlag`: use :c:member:`PyConfig.bytes_warning` + * :c:var:`Py_FrozenFlag`: use :c:member:`PyConfig.pathconfig_warnings` + * :c:var:`Py_IgnoreEnvironmentFlag`: use :c:member:`PyConfig.use_environment` + * :c:var:`Py_DontWriteBytecodeFlag`: use :c:member:`PyConfig.write_bytecode` + * :c:var:`Py_NoUserSiteDirectory`: use :c:member:`PyConfig.user_site_directory` + * :c:var:`Py_UnbufferedStdioFlag`: use :c:member:`PyConfig.buffered_stdio` + * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed` + and :c:member:`PyConfig.hash_seed` + * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` + * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` + * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` + * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` + * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) + + The :c:func:`Py_InitializeFromConfig` API should be used with + :c:type:`PyConfig` instead. + +* Creating :c:data:`immutable types ` with mutable + bases (:gh:`95388`). + +Pending Removal in Python 3.15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* :c:func:`PyImport_ImportModuleNoBlock`: use :c:func:`PyImport_ImportModule` +* :c:type:`!Py_UNICODE_WIDE` type: use :c:type:`wchar_t` +* :c:type:`Py_UNICODE` type: use :c:type:`wchar_t` +* Python initialization functions: + + * :c:func:`PySys_ResetWarnOptions`: clear :data:`sys.warnoptions` and + :data:`!warnings.filters` + * :c:func:`Py_GetExecPrefix`: get :data:`sys.exec_prefix` + * :c:func:`Py_GetPath`: get :data:`sys.path` + * :c:func:`Py_GetPrefix`: get :data:`sys.prefix` + * :c:func:`Py_GetProgramFullPath`: get :data:`sys.executable` + * :c:func:`Py_GetProgramName`: get :data:`sys.executable` + * :c:func:`Py_GetPythonHome`: get :c:member:`PyConfig.home` or + the :envvar:`PYTHONHOME` environment variable + +Pending Removal in Future Versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following APIs are deprecated and will be removed, +although there is currently no date scheduled for their removal. + +* :c:macro:`Py_TPFLAGS_HAVE_FINALIZE`: unneeded since Python 3.8 +* :c:func:`PyErr_Fetch`: use :c:func:`PyErr_GetRaisedException` +* :c:func:`PyErr_NormalizeException`: use :c:func:`PyErr_GetRaisedException` +* :c:func:`PyErr_Restore`: use :c:func:`PyErr_SetRaisedException` +* :c:func:`PyModule_GetFilename`: use :c:func:`PyModule_GetFilenameObject` +* :c:func:`PyOS_AfterFork`: use :c:func:`PyOS_AfterFork_Child` +* :c:func:`PySlice_GetIndicesEx`: use :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices` +* :c:func:`!PyUnicode_AsDecodedObject`: use :c:func:`PyCodec_Decode` +* :c:func:`!PyUnicode_AsDecodedUnicode`: use :c:func:`PyCodec_Decode` +* :c:func:`!PyUnicode_AsEncodedObject`: use :c:func:`PyCodec_Encode` +* :c:func:`!PyUnicode_AsEncodedUnicode`: use :c:func:`PyCodec_Encode` +* :c:func:`PyUnicode_READY`: unneeded since Python 3.12 +* :c:func:`!PyErr_Display`: use :c:func:`PyErr_DisplayException` +* :c:func:`!_PyErr_ChainExceptions`: use ``_PyErr_ChainExceptions1`` +* :c:member:`!PyBytesObject.ob_shash` member: + call :c:func:`PyObject_Hash` instead +* :c:member:`!PyDictObject.ma_version_tag` member +* Thread Local Storage (TLS) API: + + * :c:func:`PyThread_create_key`: use :c:func:`PyThread_tss_alloc` + * :c:func:`PyThread_delete_key`: use :c:func:`PyThread_tss_free` + * :c:func:`PyThread_set_key_value`: use :c:func:`PyThread_tss_set` + * :c:func:`PyThread_get_key_value`: use :c:func:`PyThread_tss_get` + * :c:func:`PyThread_delete_key_value`: use :c:func:`PyThread_tss_delete` + * :c:func:`PyThread_ReInitTLS`: unneeded since Python 3.7 + Removed ------- From 538f505a3744ab1dd29861a859ab81ab65436144 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:37:52 -0700 Subject: [PATCH 0815/1206] [3.12] gh-109823: Adjust labels in compiler when removing an empty basic block which is a jump target (GH-109839) (#109865) gh-109823: Adjust labels in compiler when removing an empty basic block which is a jump target (GH-109839) (cherry picked from commit d73c12b88c2275fd44e27c91c24f3ac85419d2b8) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/test/test_compile.py | 5 +++++ .../2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst | 2 ++ Python/flowgraph.c | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 2e5763eb3d61e9..e377620a0c87b8 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1236,6 +1236,11 @@ def f(): else: 1 if 1 else 1 + def test_remove_empty_basic_block_with_jump_target_label(self): + # See gh-109823 + def f(x): + while x: + 0 if 1 else 0 @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst new file mode 100644 index 00000000000000..793c89f4445f54 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst @@ -0,0 +1,2 @@ +Fix bug where compiler does not adjust labels when removing an empty basic +block which is a jump target. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index d19fe686d01c94..ccf078c7feab2d 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -922,6 +922,7 @@ eliminate_empty_basic_blocks(cfg_builder *g) { while(g->g_entryblock && g->g_entryblock->b_iused == 0) { g->g_entryblock = g->g_entryblock->b_next; } + int next_lbl = get_max_label(g->g_entryblock) + 1; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { assert(b->b_iused > 0); for (int i = 0; i < b->b_iused; i++) { @@ -931,7 +932,13 @@ eliminate_empty_basic_blocks(cfg_builder *g) { while (target->b_iused == 0) { target = target->b_next; } - instr->i_target = target; + if (instr->i_target != target) { + if (!IS_LABEL(target->b_label)) { + target->b_label.id = next_lbl++; + } + instr->i_target = target; + instr->i_oparg = target->b_label.id; + } assert(instr->i_target && instr->i_target->b_iused > 0); } } From d2a2e25855f294e21d71089e19b897ae99a0244c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 26 Sep 2023 16:03:03 +0100 Subject: [PATCH 0816/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Sort Other Language Changes (GH-109836). (#109880) (cherry picked from commit 86e7c611ac5bf067a697afbee6f9162704fd22db) --- Doc/whatsnew/3.12.rst | 94 +++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b8cf4e7dfd93e3..f3c4e3bf794213 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -465,45 +465,9 @@ and others in :gh:`103764`.) Other Language Changes ====================== -* Add :ref:`support for the perf profiler ` through the new - environment variable :envvar:`PYTHONPERFSUPPORT` - and command-line option :option:`-X perf <-X>`, - as well as the new :func:`sys.activate_stack_trampoline`, - :func:`sys.deactivate_stack_trampoline`, - and :func:`sys.is_stack_trampoline_active` functions. - (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes - with contributions from Gregory P. Smith [Google] and Mark Shannon - in :gh:`96123`.) - -* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, - have a new a *filter* argument that allows limiting tar features than may be - surprising or dangerous, such as creating files outside the destination - directory. - See :ref:`tarfile extraction filters ` for details. - In Python 3.14, the default will switch to ``'data'``. - (Contributed by Petr Viktorin in :pep:`706`.) - -* :class:`types.MappingProxyType` instances are now hashable if the underlying - mapping is hashable. - (Contributed by Serhiy Storchaka in :gh:`87995`.) - -* :class:`memoryview` now supports the half-float type (the "e" format code). - (Contributed by Donghee Na and Antoine Pitrou in :gh:`90751`.) - * The parser now raises :exc:`SyntaxError` when parsing source code containing null bytes. (Contributed by Pablo Galindo in :gh:`96670`.) -* :func:`ast.parse` now raises :exc:`SyntaxError` instead of :exc:`ValueError` - when parsing source code containing null bytes. (Contributed by Pablo Galindo - in :gh:`96670`.) - -* The Garbage Collector now runs only on the eval breaker mechanism of the - Python bytecode evaluation loop instead of object allocations. The GC can - also run when :c:func:`PyErr_CheckSignals` is called so C extensions that - need to run for a long time without executing any Python code also have a - chance to execute the GC periodically. (Contributed by Pablo Galindo in - :gh:`97922`.) - * A backslash-character pair that is not a valid escape sequence now generates a :exc:`SyntaxWarning`, instead of :exc:`DeprecationWarning`. For example, ``re.compile("\d+\.\d+")`` now emits a :exc:`SyntaxWarning` @@ -519,10 +483,6 @@ Other Language Changes In a future Python version they will be eventually a :exc:`SyntaxError`. (Contributed by Victor Stinner in :gh:`98401`.) -* All builtin and extension callables expecting boolean parameters now accept - arguments of any type instead of just :class:`bool` and :class:`int`. - (Contributed by Serhiy Storchaka in :gh:`60203`.) - * Variables used in the target part of comprehensions that are not stored to can now be used in assignment expressions (``:=``). For example, in ``[(b := 1) for a, b.prop in some_iter]``, the assignment to @@ -530,13 +490,6 @@ Other Language Changes part of comprehensions (like ``a``) is still disallowed, as per :pep:`572`. (Contributed by Nikita Sobolev in :gh:`100581`.) -* :class:`slice` objects are now hashable, allowing them to be used as dict keys and - set items. (Contributed by Will Bradshaw, Furkan Onder, and Raymond Hettinger in :gh:`101264`.) - -* :func:`sum` now uses Neumaier summation to improve accuracy when summing - floats or mixed ints and floats. - (Contributed by Raymond Hettinger in :gh:`100425`.) - * Exceptions raised in a class or type's ``__set_name__`` method are no longer wrapped by a :exc:`RuntimeError`. Context information is added to the exception as a :pep:`678` note. (Contributed by Irit Katriel in :gh:`77757`.) @@ -546,6 +499,53 @@ Other Language Changes :exc:`ExceptionGroup`. Also changed in version 3.11.4. (Contributed by Irit Katriel in :gh:`103590`.) +* The Garbage Collector now runs only on the eval breaker mechanism of the + Python bytecode evaluation loop instead of object allocations. The GC can + also run when :c:func:`PyErr_CheckSignals` is called so C extensions that + need to run for a long time without executing any Python code also have a + chance to execute the GC periodically. (Contributed by Pablo Galindo in + :gh:`97922`.) + +* All builtin and extension callables expecting boolean parameters now accept + arguments of any type instead of just :class:`bool` and :class:`int`. + (Contributed by Serhiy Storchaka in :gh:`60203`.) + +* :class:`memoryview` now supports the half-float type (the "e" format code). + (Contributed by Donghee Na and Antoine Pitrou in :gh:`90751`.) + +* :class:`slice` objects are now hashable, allowing them to be used as dict keys and + set items. (Contributed by Will Bradshaw, Furkan Onder, and Raymond Hettinger in :gh:`101264`.) + +* :func:`sum` now uses Neumaier summation to improve accuracy and commutativity + when summing floats or mixed ints and floats. + (Contributed by Raymond Hettinger in :gh:`100425`.) + +* :func:`ast.parse` now raises :exc:`SyntaxError` instead of :exc:`ValueError` + when parsing source code containing null bytes. (Contributed by Pablo Galindo + in :gh:`96670`.) + +* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, + have a new a *filter* argument that allows limiting tar features than may be + surprising or dangerous, such as creating files outside the destination + directory. + See :ref:`tarfile extraction filters ` for details. + In Python 3.14, the default will switch to ``'data'``. + (Contributed by Petr Viktorin in :pep:`706`.) + +* :class:`types.MappingProxyType` instances are now hashable if the underlying + mapping is hashable. + (Contributed by Serhiy Storchaka in :gh:`87995`.) + +* Add :ref:`support for the perf profiler ` through the new + environment variable :envvar:`PYTHONPERFSUPPORT` + and command-line option :option:`-X perf <-X>`, + as well as the new :func:`sys.activate_stack_trampoline`, + :func:`sys.deactivate_stack_trampoline`, + and :func:`sys.is_stack_trampoline_active` functions. + (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes + with contributions from Gregory P. Smith [Google] and Mark Shannon + in :gh:`96123`.) + New Modules =========== From 57ff2162150340bab4f91654f1918b9b68ed62da Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 26 Sep 2023 09:03:31 -0600 Subject: [PATCH 0817/1206] [3.12] gh-101100: Fix Sphinx warnings in `Doc/library/weakref.rst` (GH-109881) (#109884) [3.12] gh-101100: Fix Sphinx warnings in `Doc/library/weakref.rst` (GH-109881). (cherry picked from commit 7c61a361fc2e93375e22849fffbc20b60e94dbde) Co-authored-by: Nikita Sobolev --- Doc/library/weakref.rst | 19 +++++++++---------- Doc/tools/.nitignore | 1 - 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 1406b663c6a8e2..d6e062df945c64 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -111,7 +111,7 @@ See :ref:`__slots__ documentation ` for details. Exceptions raised by the callback will be noted on the standard error output, but cannot be propagated; they are handled in exactly the same way as exceptions - raised from an object's :meth:`__del__` method. + raised from an object's :meth:`~object.__del__` method. Weak references are :term:`hashable` if the *object* is hashable. They will maintain their hash value even after the *object* was deleted. If @@ -221,8 +221,7 @@ than needed. Added support for ``|`` and ``|=`` operators, as specified in :pep:`584`. :class:`WeakValueDictionary` objects have an additional method that has the -same issues as the :meth:`keyrefs` method of :class:`WeakKeyDictionary` -objects. +same issues as the :meth:`WeakKeyDictionary.keyrefs` method. .. method:: WeakValueDictionary.valuerefs() @@ -281,7 +280,7 @@ objects. Exceptions raised by finalizer callbacks during garbage collection will be shown on the standard error output, but cannot be propagated. They are handled in the same way as exceptions raised - from an object's :meth:`__del__` method or a weak reference's + from an object's :meth:`~object.__del__` method or a weak reference's callback. When the program exits, each remaining live finalizer is called @@ -523,18 +522,18 @@ is still alive. For instance obj dead or exiting -Comparing finalizers with :meth:`__del__` methods -------------------------------------------------- +Comparing finalizers with :meth:`~object.__del__` methods +--------------------------------------------------------- Suppose we want to create a class whose instances represent temporary directories. The directories should be deleted with their contents when the first of the following events occurs: * the object is garbage collected, -* the object's :meth:`remove` method is called, or +* the object's :meth:`!remove` method is called, or * the program exits. -We might try to implement the class using a :meth:`__del__` method as +We might try to implement the class using a :meth:`~object.__del__` method as follows:: class TempDir: @@ -553,12 +552,12 @@ follows:: def __del__(self): self.remove() -Starting with Python 3.4, :meth:`__del__` methods no longer prevent +Starting with Python 3.4, :meth:`~object.__del__` methods no longer prevent reference cycles from being garbage collected, and module globals are no longer forced to :const:`None` during :term:`interpreter shutdown`. So this code should work without any issues on CPython. -However, handling of :meth:`__del__` methods is notoriously implementation +However, handling of :meth:`~object.__del__` methods is notoriously implementation specific, since it depends on internal details of the interpreter's garbage collector implementation. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index e6b47ec6e2d25c..72ace87069eaac 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -147,7 +147,6 @@ Doc/library/unittest.mock.rst Doc/library/unittest.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst -Doc/library/weakref.rst Doc/library/webbrowser.rst Doc/library/wsgiref.rst Doc/library/xdrlib.rst From 648198c37f2b1ba4baef1f1a4c6fd14708f879d8 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 26 Sep 2023 16:17:32 +0100 Subject: [PATCH 0818/1206] [3.12] gh-109889: comment out assertion indicating a failed optimization of a redundant NOP (#109899) * [3.12] gh-109889: comment out assertion indicating a failed optimization of a redundant NOP * comment out the function to avoid warnings on it being unused --- Python/flowgraph.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index ccf078c7feab2d..f860631a6c21dd 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -366,6 +366,7 @@ _PyCfgBuilder_Addop(cfg_builder *g, int opcode, int oparg, location loc) #ifndef NDEBUG static int remove_redundant_nops(basicblock *bb); +/* static bool no_redundant_nops(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { @@ -375,6 +376,7 @@ no_redundant_nops(cfg_builder *g) { } return true; } +*/ static bool no_empty_basic_blocks(cfg_builder *g) { @@ -1595,7 +1597,11 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache) remove_redundant_nops(b); } eliminate_empty_basic_blocks(g); - assert(no_redundant_nops(g)); + /* This assertion fails in an edge case (See gh-109889). + * Remove it for the release (it's just one more NOP in the + * bytecode for unlikely code). + */ + // assert(no_redundant_nops(g)); RETURN_IF_ERROR(remove_redundant_jumps(g)); return SUCCESS; } From 1d6ef7e609ed0222b6e96c660c9f6881cbfa3133 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:13:14 -0700 Subject: [PATCH 0819/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Deprecations (GH-109766) (#109925) * GH-109190: Copyedit 3.12 What's New: Deprecations (GH-109766) (cherry picked from commit 87ddfa74e2d37f6837351ed2bafc7d6d55fe2fd0) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> * GH-109190: Copyedit 3.12 What's New: Deprecations (``os`` fix) (#109927) Merge the two ``os`` entries (cherry picked from commit 0e28d0f7a1bc3776cc07e0f8b91bc43fcdbb4206) --------- Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 277 ++++++++++++++++++++++++++---------------- 1 file changed, 170 insertions(+), 107 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f3c4e3bf794213..f2a3c146d2b87b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -580,19 +580,10 @@ asyncio :class:`asyncio.ThreadedChildWatcher`. (Contributed by Kumar Aditya in :gh:`98024`.) -* The child watcher classes :class:`asyncio.MultiLoopChildWatcher`, - :class:`asyncio.FastChildWatcher`, :class:`asyncio.AbstractChildWatcher` - and :class:`asyncio.SafeChildWatcher` are deprecated and - will be removed in Python 3.14. It is recommended to not manually - configure a child watcher as the event loop now uses the best available - child watcher for each platform (:class:`asyncio.PidfdChildWatcher` - if supported and :class:`asyncio.ThreadedChildWatcher` otherwise). - (Contributed by Kumar Aditya in :gh:`94597`.) - -* :func:`asyncio.set_child_watcher`, :func:`asyncio.get_child_watcher`, - :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` and - :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` are deprecated - and will be removed in Python 3.14. +* The event loop now uses the best available child watcher for each platform + (:class:`asyncio.PidfdChildWatcher` if supported and + :class:`asyncio.ThreadedChildWatcher` otherwise), so manually + configuring a child watcher is not recommended. (Contributed by Kumar Aditya in :gh:`94597`.) * Add *loop_factory* parameter to :func:`asyncio.run` to allow specifying @@ -1046,15 +1037,52 @@ Demos and Tools Deprecated ========== -* :mod:`asyncio`: The :meth:`~asyncio.get_event_loop` method of the - default event loop policy now emits a :exc:`DeprecationWarning` if there - is no current event loop set and it decides to create one. - (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) +* :mod:`argparse`: The *type*, *choices*, and *metavar* parameters + of :class:`!argparse.BooleanOptionalAction` are deprecated + and will be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`92248`.) + +* :mod:`ast`: The following :mod:`ast` features have been deprecated in documentation since + Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at runtime + when they are accessed or used, and will be removed in Python 3.14: + + * :class:`!ast.Num` + * :class:`!ast.Str` + * :class:`!ast.Bytes` + * :class:`!ast.NameConstant` + * :class:`!ast.Ellipsis` + + Use :class:`ast.Constant` instead. + (Contributed by Serhiy Storchaka in :gh:`90953`.) + +* :mod:`asyncio`: + + * The child watcher classes :class:`asyncio.MultiLoopChildWatcher`, + :class:`asyncio.FastChildWatcher`, :class:`asyncio.AbstractChildWatcher` + and :class:`asyncio.SafeChildWatcher` are deprecated and + will be removed in Python 3.14. + (Contributed by Kumar Aditya in :gh:`94597`.) + + * :func:`asyncio.set_child_watcher`, :func:`asyncio.get_child_watcher`, + :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` and + :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` are deprecated + and will be removed in Python 3.14. + (Contributed by Kumar Aditya in :gh:`94597`.) + + * The :meth:`~asyncio.get_event_loop` method of the + default event loop policy now emits a :exc:`DeprecationWarning` if there + is no current event loop set and it decides to create one. + (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) * :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are deprecated and replaced by :data:`calendar.JANUARY` and :data:`calendar.FEBRUARY`. (Contributed by Prince Roshan in :gh:`103636`.) +* :mod:`collections.abc`: Deprecated :class:`collections.abc.ByteString`. + Prefer :class:`Sequence` or :class:`collections.abc.Buffer`. + For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. + (Contributed by Shantanu Jain in :gh:`91896`.) + * :mod:`datetime`: :class:`datetime.datetime`'s :meth:`~datetime.datetime.utcnow` and :meth:`~datetime.datetime.utcfromtimestamp` are deprecated and will be removed in a future version. Instead, use timezone-aware objects to represent @@ -1063,42 +1091,88 @@ Deprecated :const:`datetime.UTC`. (Contributed by Paul Ganssle in :gh:`103857`.) -* :mod:`os`: The ``st_ctime`` fields return by :func:`os.stat` and :func:`os.lstat` on - Windows are deprecated. In a future release, they will contain the last - metadata change time, consistent with other platforms. For now, they still - contain the creation time, which is also available in the new ``st_birthtime`` - field. (Contributed by Steve Dower in :gh:`99726`.) - -* :mod:`os`: On POSIX platforms, :func:`os.fork` can now raise a - :exc:`DeprecationWarning` when it can detect being called from a - multithreaded process. There has always been a fundamental incompatibility - with the POSIX platform when doing so. Even if such code *appeared* to work. - We added the warning to to raise awareness as issues encounted by code doing - this are becoming more frequent. See the :func:`os.fork` documentation for - more details along with `this discussion on fork being incompatible with threads - `_ for *why* we're now surfacing this - longstanding platform compatibility problem to developers. +* :mod:`email`: Deprecate the *isdst* parameter in :func:`email.utils.localtime`. + (Contributed by Alan Williams in :gh:`72346`.) + +* :mod:`importlib.abc`: Deprecated the following classes, scheduled for removal in + Python 3.14: + + * :class:`!importlib.abc.ResourceReader` + * :class:`!importlib.abc.Traversable` + * :class:`!importlib.abc.TraversableResources` + + Use :mod:`importlib.resources.abc` classes instead: + + * :class:`importlib.resources.abc.Traversable` + * :class:`importlib.resources.abc.TraversableResources` + + (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) + +* :mod:`itertools`: Deprecate the support for copy, deepcopy, and pickle operations, + which is undocumented, inefficient, historically buggy, and inconsistent. + This will be removed in 3.14 for a significant reduction in code + volume and maintenance burden. + (Contributed by Raymond Hettinger in :gh:`101588`.) + +* :mod:`multiprocessing`: In Python 3.14, the default :mod:`multiprocessing` + start method will change to a safer one on Linux, BSDs, + and other non-macOS POSIX platforms where ``'fork'`` is currently + the default (:gh:`84559`). Adding a runtime warning about this was deemed too + disruptive as the majority of code is not expected to care. Use the + :func:`~multiprocessing.get_context` or + :func:`~multiprocessing.set_start_method` APIs to explicitly specify when + your code *requires* ``'fork'``. See :ref:`contexts and start methods + `. + +* :mod:`pkgutil`: :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` + are deprecated and will be removed in Python 3.14; + use :func:`importlib.util.find_spec` instead. + (Contributed by Nikita Sobolev in :gh:`97850`.) + +* :mod:`pty`: The module has two undocumented ``master_open()`` and ``slave_open()`` + functions that have been deprecated since Python 2 but only gained a + proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. + (Contributed by Soumendra Ganguly and Gregory P. Smith in :gh:`85984`.) + +* :mod:`os`: + + * The ``st_ctime`` fields return by :func:`os.stat` and :func:`os.lstat` on + Windows are deprecated. In a future release, they will contain the last + metadata change time, consistent with other platforms. For now, they still + contain the creation time, which is also available in the new ``st_birthtime`` + field. (Contributed by Steve Dower in :gh:`99726`.) + + * On POSIX platforms, :func:`os.fork` can now raise a + :exc:`DeprecationWarning` when it can detect being called from a + multithreaded process. There has always been a fundamental incompatibility + with the POSIX platform when doing so. Even if such code *appeared* to work. + We added the warning to to raise awareness as issues encounted by code doing + this are becoming more frequent. See the :func:`os.fork` documentation for + more details along with `this discussion on fork being incompatible with threads + `_ for *why* we're now surfacing this + longstanding platform compatibility problem to developers. When this warning appears due to usage of :mod:`multiprocessing` or :mod:`concurrent.futures` the fix is to use a different :mod:`multiprocessing` start method such as ``"spawn"`` or ``"forkserver"``. -* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed +* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated and will be removed in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) * :mod:`sqlite3`: - * :ref:`default adapters and converters - ` are now deprecated. - Instead, use the :ref:`sqlite3-adapter-converter-recipes` - and tailor them to your needs. - (Contributed by Erlend E. Aasland in :gh:`90016`.) - - * In :meth:`~sqlite3.Cursor.execute`, :exc:`DeprecationWarning` is now emitted - when :ref:`named placeholders ` are used together with - parameters supplied as a :term:`sequence` instead of as a :class:`dict`. - Starting from Python 3.14, using named placeholders with parameters supplied - as a sequence will raise a :exc:`~sqlite3.ProgrammingError`. - (Contributed by Erlend E. Aasland in :gh:`101698`.) + + * :ref:`default adapters and converters + ` are now deprecated. + Instead, use the :ref:`sqlite3-adapter-converter-recipes` + and tailor them to your needs. + (Contributed by Erlend E. Aasland in :gh:`90016`.) + + * In :meth:`~sqlite3.Cursor.execute`, :exc:`DeprecationWarning` is now emitted + when :ref:`named placeholders ` are used together with + parameters supplied as a :term:`sequence` instead of as a :class:`dict`. + Starting from Python 3.14, using named placeholders with parameters supplied + as a sequence will raise a :exc:`~sqlite3.ProgrammingError`. + (Contributed by Erlend E. Aasland in :gh:`101698`.) * :mod:`sys`: The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` fields are deprecated. Use :data:`sys.last_exc` instead. @@ -1108,16 +1182,24 @@ Deprecated Python 3.14, when ``'data'`` filter will become the default. See :ref:`tarfile-extraction-filter` for details. -* :mod:`typing`: :class:`typing.Hashable` and :class:`typing.Sized` aliases for :class:`collections.abc.Hashable` - and :class:`collections.abc.Sized`. (:gh:`94309`.) +* :mod:`typing`: + + * :class:`typing.Hashable` and :class:`typing.Sized` aliases for :class:`collections.abc.Hashable` + and :class:`collections.abc.Sized`. (:gh:`94309`.) + + * :class:`typing.ByteString`, deprecated since Python 3.9, now causes a + :exc:`DeprecationWarning` to be emitted when it is used. + (Contributed by Alex Waygood in :gh:`91896`.) * :mod:`xml.etree.ElementTree`: The module now emits :exc:`DeprecationWarning` when testing the truth value of an :class:`xml.etree.ElementTree.Element`. Before, the Python implementation emitted :exc:`FutureWarning`, and the C implementation emitted nothing. + (Contributed by Jacob Walls in :gh:`83122`.) -* The 3-arg signatures (type, value, traceback) of :meth:`~coroutine.throw`, - :meth:`~generator.throw` and :meth:`~agen.athrow` are deprecated and +* The 3-arg signatures (type, value, traceback) of :meth:`coroutine throw() + `, :meth:`generator throw() ` and + :meth:`async generator throw() ` are deprecated and may be removed in a future version of Python. Use the single-arg versions of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.) @@ -1126,12 +1208,21 @@ Deprecated :exc:`ImportWarning`). (Contributed by Brett Cannon in :gh:`65961`.) +* Setting ``__package__`` or ``__cached__`` on a module is deprecated, + and will cease to be set or taken into consideration by the import system in Python 3.14. + (Contributed by Brett Cannon in :gh:`65961`.) + * The bitwise inversion operator (``~``) on bool is deprecated. It will throw an error in Python 3.14. Use ``not`` for logical negation of bools instead. In the rare case that you really need the bitwise inversion of the underlying - ``int``, convert to int explicitly with ``~int(x)``. (Contributed by Tim Hoffmann + ``int``, convert to int explicitly: ``~int(x)``. (Contributed by Tim Hoffmann in :gh:`103487`.) +* Accessing ``co_lnotab`` on code objects was deprecated in Python 3.10 via :pep:`626`, + but it only got a proper :exc:`DeprecationWarning` in 3.12, + therefore it will be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`101866`.) + Pending Removal in Python 3.13 ------------------------------ @@ -1179,14 +1270,13 @@ APIs: Pending Removal in Python 3.14 ------------------------------ +The following APIs have been deprecated +and will be removed in Python 3.14. + * :mod:`argparse`: The *type*, *choices*, and *metavar* parameters - of :class:`!argparse.BooleanOptionalAction` are deprecated - and will be removed in 3.14. - (Contributed by Nikita Sobolev in :gh:`92248`.) + of :class:`!argparse.BooleanOptionalAction` -* :mod:`ast`: The following :mod:`ast` features have been deprecated in documentation since - Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at runtime - when they are accessed or used, and will be removed in Python 3.14: +* :mod:`ast`: * :class:`!ast.Num` * :class:`!ast.Str` @@ -1194,75 +1284,48 @@ Pending Removal in Python 3.14 * :class:`!ast.NameConstant` * :class:`!ast.Ellipsis` - Use :class:`ast.Constant` instead. - (Contributed by Serhiy Storchaka in :gh:`90953`.) +* :mod:`asyncio`: -* :mod:`asyncio`: the *msg* parameter of both - :meth:`asyncio.Future.cancel` and - :meth:`asyncio.Task.cancel` (:gh:`90985`) + * :class:`!asyncio.MultiLoopChildWatcher` + * :class:`!asyncio.FastChildWatcher` + * :class:`!asyncio.AbstractChildWatcher` + * :class:`!asyncio.SafeChildWatcher` + * :func:`!asyncio.set_child_watcher` + * :func:`!asyncio.get_child_watcher`, + * :meth:`!asyncio.AbstractEventLoopPolicy.set_child_watcher` + * :meth:`!asyncio.AbstractEventLoopPolicy.get_child_watcher` -* :mod:`collections.abc`: Deprecated :class:`collections.abc.ByteString`. - Prefer :class:`Sequence` or :class:`collections.abc.Buffer`. - For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. - (Contributed by Shantanu Jain in :gh:`91896`.) +* :mod:`collections.abc`: :class:`!collections.abc.ByteString`. -* :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`. - (Contributed by Alan Williams in :gh:`72346`.) +* :mod:`email`: the *isdst* parameter in :func:`email.utils.localtime`. -* :mod:`importlib.abc`: Deprecated the following classes, scheduled for removal in - Python 3.14: +* :mod:`importlib.abc`: * :class:`!importlib.abc.ResourceReader` * :class:`!importlib.abc.Traversable` * :class:`!importlib.abc.TraversableResources` - Use :mod:`importlib.resources.abc` classes instead: +* :mod:`itertools`: Support for copy, deepcopy, and pickle operations. - * :class:`importlib.resources.abc.Traversable` - * :class:`importlib.resources.abc.TraversableResources` - - (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) - -* :mod:`itertools`: The module had undocumented, inefficient, historically buggy, - and inconsistent support for copy, deepcopy, and pickle operations. - This will be removed in 3.14 for a significant reduction in code - volume and maintenance burden. - (Contributed by Raymond Hettinger in :gh:`101588`.) +* :mod:`pkgutil`: -* :mod:`multiprocessing`: The default :mod:`multiprocessing` start method will change to a safer one on - Linux, BSDs, and other non-macOS POSIX platforms where ``'fork'`` is currently - the default (:gh:`84559`). Adding a runtime warning about this was deemed too - disruptive as the majority of code is not expected to care. Use the - :func:`~multiprocessing.get_context` or - :func:`~multiprocessing.set_start_method` APIs to explicitly specify when - your code *requires* ``'fork'``. See :ref:`multiprocessing-start-methods`. + * :func:`!pkgutil.find_loader` + * :func:`!pkgutil.get_loader`. -* :mod:`pkgutil`: :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` - now raise :exc:`DeprecationWarning`; - use :func:`importlib.util.find_spec` instead. - (Contributed by Nikita Sobolev in :gh:`97850`.) +* :mod:`pty`: -* :mod:`pty`: The module has two undocumented ``master_open()`` and ``slave_open()`` - functions that have been deprecated since Python 2 but only gained a - proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. + * :func:`!pty.master_open` + * :func:`!pty.slave_open` -* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, - and will be removed in 3.14. +* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` -* :mod:`typing`: :class:`typing.ByteString`, deprecated since Python 3.9, now causes a - :exc:`DeprecationWarning` to be emitted when it is used. +* :mod:`typing`: :class:`!typing.ByteString` -* :mod:`xml.etree.ElementTree`: Testing the truth value of an :class:`xml.etree.ElementTree.Element` - is deprecated and will raise an exception in Python 3.14. +* :mod:`xml.etree.ElementTree`: Testing the truth value of an :class:`xml.etree.ElementTree.Element`. -* ``__package__`` and ``__cached__`` will cease to be set or taken - into consideration by the import system (:gh:`97879`). +* The ``__package__`` and ``__cached__`` attributes on module objects. -* Accessing ``co_lnotab`` was deprecated in :pep:`626` since 3.10 - and was planned to be removed in 3.12 - but it only got a proper :exc:`DeprecationWarning` in 3.12. - May be removed in 3.14. - (Contributed by Nikita Sobolev in :gh:`101866`.) +* The ``co_lnotab`` attribute of code objects. Pending Removal in Future Versions ---------------------------------- From fc4fddb139d61c7c39e19e8e8164978af1b1a3fd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:38:28 -0700 Subject: [PATCH 0820/1206] [3.12] gh-107298: Document PyMODINIT_FUNC macro (GH-109236) (#109947) gh-107298: Document PyMODINIT_FUNC macro (GH-109236) Document PyMODINIT_FUNC macro. Remove links to PyAPI_FUNC() and PyAPI_DATA() macros since they are not documented. These macros should only be used to define the Python C API. They should not be used outside Python code base. (cherry picked from commit d7a27e527d7e669d2e45cff80ad725978226477c) Co-authored-by: Victor Stinner --- Doc/c-api/intro.rst | 24 ++++++++++++++++++++++++ Doc/using/configure.rst | 4 ++-- Doc/whatsnew/2.3.rst | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 4a6cb7ab3b8381..26c0168dbbb18c 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -105,6 +105,30 @@ defined closer to where they are useful (e.g. :c:macro:`Py_RETURN_NONE`). Others of a more general utility are defined here. This is not necessarily a complete listing. +.. c:macro:: PyMODINIT_FUNC + + Declare an extension module ``PyInit`` initialization function. The function + return type is :c:expr:`PyObject*`. The macro declares any special linkage + declarations required by the platform, and for C++ declares the function as + ``extern "C"``. + + The initialization function must be named :samp:`PyInit_{name}`, where + *name* is the name of the module, and should be the only non-\ ``static`` + item defined in the module file. Example:: + + static struct PyModuleDef spam_module = { + PyModuleDef_HEAD_INIT, + .m_name = "spam", + ... + }; + + PyMODINIT_FUNC + PyInit_spam(void) + { + return PyModule_Create(&spam_module); + } + + .. c:macro:: Py_ABS(x) Return the absolute value of ``x``. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index d9d52945bcdbe2..6fe06381d16841 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -769,8 +769,8 @@ Example on Linux x86-64:: At the beginning of the files, C extensions are built as built-in modules. Extensions defined after the ``*shared*`` marker are built as dynamic libraries. -The :c:macro:`PyAPI_FUNC()`, :c:macro:`PyAPI_DATA()` and -:c:macro:`PyMODINIT_FUNC` macros of :file:`Include/pyport.h` are defined +The :c:macro:`!PyAPI_FUNC()`, :c:macro:`!PyAPI_DATA()` and +:c:macro:`PyMODINIT_FUNC` macros of :file:`Include/exports.h` are defined differently depending if the ``Py_BUILD_CORE_MODULE`` macro is defined: * Use ``Py_EXPORTED_SYMBOL`` if the ``Py_BUILD_CORE_MODULE`` is defined diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index c06fd9582627e2..0442c9fdd08ce3 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1889,7 +1889,7 @@ Changes to Python's build process and to the C API include: * The :c:macro:`!DL_EXPORT` and :c:macro:`!DL_IMPORT` macros are now deprecated. Initialization functions for Python extension modules should now be declared using the new macro :c:macro:`PyMODINIT_FUNC`, while the Python core will - generally use the :c:macro:`PyAPI_FUNC` and :c:macro:`PyAPI_DATA` macros. + generally use the :c:macro:`!PyAPI_FUNC` and :c:macro:`!PyAPI_DATA` macros. * The interpreter can be compiled without any docstrings for the built-in functions and modules by supplying :option:`!--without-doc-strings` to the From 2c557932e9eeba3c4bcd64b674546f709b6ec4dd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:38:42 -0700 Subject: [PATCH 0821/1206] [3.12] gh-101100: Fix sphinx warnings in `library/devmode.rst` (GH-109963) (#109966) gh-101100: Fix sphinx warnings in `library/devmode.rst` (GH-109963) (cherry picked from commit d9809e84fbf22ed8d90b212a9322260f7074bc9c) Co-authored-by: Nikita Sobolev Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/devmode.rst | 5 +++-- Doc/tools/.nitignore | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/devmode.rst b/Doc/library/devmode.rst index 914aa45cf9cbc3..5b8a9bd1908456 100644 --- a/Doc/library/devmode.rst +++ b/Doc/library/devmode.rst @@ -59,8 +59,9 @@ Effects of the Python Development Mode: ``default``. * Call :func:`faulthandler.enable` at Python startup to install handlers for - the :const:`SIGSEGV`, :const:`SIGFPE`, :const:`SIGABRT`, :const:`SIGBUS` and - :const:`SIGILL` signals to dump the Python traceback on a crash. + the :const:`~signal.SIGSEGV`, :const:`~signal.SIGFPE`, + :const:`~signal.SIGABRT`, :const:`~signal.SIGBUS` and + :const:`~signal.SIGILL` signals to dump the Python traceback on a crash. It behaves as if the :option:`-X faulthandler <-X>` command line option is used or if the :envvar:`PYTHONFAULTHANDLER` environment variable is set to diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 72ace87069eaac..922f99f3fe2350 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -60,7 +60,6 @@ Doc/library/csv.rst Doc/library/datetime.rst Doc/library/dbm.rst Doc/library/decimal.rst -Doc/library/devmode.rst Doc/library/difflib.rst Doc/library/doctest.rst Doc/library/email.charset.rst From 26f542de228e332c21d8076e11457026e7020d77 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:39:10 -0700 Subject: [PATCH 0822/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Release highlights (GH-109770) (#109971) * GH-109190: Copyedit 3.12 What's New: Release highlights (GH-109770) (cherry picked from commit b35f0843fc15486b17bc945dde08b306b8e4e81f) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> * Delete bad merge leftovers --------- Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 414 +++++++++++++++++++++++++----------------- 1 file changed, 247 insertions(+), 167 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f2a3c146d2b87b..d07ffbb454ccd3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -59,36 +59,106 @@ Summary -- Release highlights .. This section singles out the most important changes in Python 3.12. Brevity is key. +Python 3.12 is the latest stable release of the Python programming language, +with a mix of changes to the language and the standard library. +The library changes focus on cleaning up deprecated APIs, usability, and correctness. +Of note, the :mod:`!distutils` package has been removed from the standard library. +Filesystem support in :mod:`os` and :mod:`pathlib` has seen a number of improvements, +and several modules have better performance. + +The language changes focus on usability, +as :term:`f-strings ` have had many limitations removed +and 'Did you mean ...' suggestions continue to improve. +The new :ref:`type parameter syntax ` +and :keyword:`type` statement improve ergonomics for using :term:`generic types +` and :term:`type aliases ` with static type checkers. + +This article doesn't attempt to provide a complete specification of all new features, +but instead gives a convenient overview. +For full details, you should refer to the documentation, +such as the :ref:`Library Reference ` +and :ref:`Language Reference `. +If you want to understand the complete implementation and design rationale for a change, +refer to the PEP for a particular new feature; +but note that PEPs usually are not kept up-to-date +once a feature has been fully implemented. + +-------------- .. PEP-sized items next. +New syntax features: + +* :ref:`PEP 695 `, type parameter syntax and the :keyword:`type` statement + New grammar features: -* :ref:`whatsnew312-pep701` +* :ref:`PEP 701 `, :term:`f-strings ` in the grammar Interpreter improvements: -* :ref:`whatsnew312-pep684` +* :ref:`PEP 684 `, a unique per-interpreter :term:`GIL + ` +* :ref:`PEP 669 `, low impact monitoring +* `Improved 'Did you mean ...' suggestions `_ + for :exc:`NameError`, :exc:`ImportError`, and :exc:`SyntaxError` exceptions -* :ref:`whatsnew312-pep669` +Python data model improvements: -New typing features: +* :ref:`PEP 688 `, using the :ref:`buffer protocol + ` from Python + +Significant improvements in the standard library: + +* The :class:`pathlib.Path` class now supports subclassing +* The :mod:`os` module received several improvements for Windows support +* A :ref:`command-line interface ` has been added to the + :mod:`sqlite3` module +* :func:`isinstance` checks against :func:`runtime-checkable protocols + ` enjoy a speed up of between two and 20 times +* The :mod:`asyncio` package has had a number of performance improvements, + with some benchmarks showing a 75% speed up. +* A :ref:`command-line interface ` has been added to the + :mod:`uuid` module +* Due to the changes in :ref:`PEP 701 `, + producing tokens via the :mod:`tokenize` module is up to up to 64% faster. -* :ref:`whatsnew312-pep688` +Security improvements: -* :ref:`whatsnew312-pep692` +* Replace the builtin :mod:`hashlib` implementations of + SHA1, SHA3, SHA2-384, SHA2-512, and MD5 with formally verified code from the + `HACL* `__ project. + These builtin implementations remain as fallbacks that are only used when + OpenSSL does not provide them. -* :ref:`whatsnew312-pep695` +C API improvements: + +* :ref:`PEP 697 `, unstable C API tier +* :ref:`PEP 683 `, immortal objects + +CPython implementation improvements: + +* :ref:`PEP 709 `, comprehension inlining +* :ref:`CPython support ` for the Linux ``perf`` profiler +* Implement stack overflow protection on supported platforms + +New typing features: -* :ref:`whatsnew312-pep698` +* :ref:`PEP 692 `, using :class:`~typing.TypedDict` to + annotate :term:`**kwargs ` +* :ref:`PEP 698 `, :func:`typing.override` decorator Important deprecations, removals or restrictions: -* :pep:`623`: Remove wstr from Unicode +* :pep:`623`: Remove ``wstr`` from Unicode objects in Python's C API, + reducing the size of every :class:`str` object by at least 8 bytes. -* :pep:`632`: Remove the ``distutils`` package. See - `the migration guide `_ - for advice on its replacement. +* :pep:`632`: Remove the :mod:`!distutils` package. + See `the migration guide `_ + for advice replacing the APIs it provided. + The third-party `Setuptools `__ + package continues to provide :mod:`!distutils`, + if you still require it in Python 3.12 and beyond. * :gh:`95299`: Do not pre-install ``setuptools`` in virtual environments created with :mod:`venv`. @@ -97,60 +167,77 @@ Important deprecations, removals or restrictions: run ``pip install setuptools`` in the :ref:`activated ` virtual environment. -Improved Error Messages -======================= +* The :mod:`!asynchat`, :mod:`!asyncore`, and :mod:`!imp` modules have been + removed, along with several :class:`unittest.TestCase` + `method aliases `_. -* Modules from the standard library are now potentially suggested as part of - the error messages displayed by the interpreter when a :exc:`NameError` is - raised to the top level. (Contributed by Pablo Galindo in :gh:`98254`.) - >>> sys.version_info - Traceback (most recent call last): - File "", line 1, in - NameError: name 'sys' is not defined. Did you forget to import 'sys'? +New Features +============ -* Improve the error suggestion for :exc:`NameError` exceptions for instances. - Now if a :exc:`NameError` is raised in a method and the instance has an - attribute that's exactly equal to the name in the exception, the suggestion - will include ``self.`` instead of the closest match in the method - scope. (Contributed by Pablo Galindo in :gh:`99139`.) +.. _whatsnew312-pep695: - >>> class A: - ... def __init__(self): - ... self.blech = 1 - ... - ... def foo(self): - ... somethin = blech - ... - >>> A().foo() - Traceback (most recent call last): - File "", line 1 - somethin = blech - ^^^^^ - NameError: name 'blech' is not defined. Did you mean: 'self.blech'? +PEP 695: Type Parameter Syntax +------------------------------ -* Improve the :exc:`SyntaxError` error message when the user types ``import x - from y`` instead of ``from y import x``. (Contributed by Pablo Galindo in :gh:`98931`.) +Generic classes and functions under :pep:`484` were declared using a verbose syntax +that left the scope of type parameters unclear and required explicit declarations of +variance. - >>> import a.y.z from b.y.z - Traceback (most recent call last): - File "", line 1 - import a.y.z from b.y.z - ^^^^^^^^^^^^^^^^^^^^^^^ - SyntaxError: Did you mean to use 'from ... import ...' instead? +:pep:`695` introduces a new, more compact and explicit way to create +:ref:`generic classes ` and :ref:`functions `:: -* :exc:`ImportError` exceptions raised from failed ``from import - `` statements now include suggestions for the value of ```` based on the - available names in ````. (Contributed by Pablo Galindo in :gh:`91058`.) + def max[T](args: Iterable[T]) -> T: + ... - >>> from collections import chainmap - Traceback (most recent call last): - File "", line 1, in - ImportError: cannot import name 'chainmap' from 'collections'. Did you mean: 'ChainMap'? + class list[T]: + def __getitem__(self, index: int, /) -> T: + ... + def append(self, element: T) -> None: + ... -New Features -============ +In addition, the PEP introduces a new way to declare :ref:`type aliases ` +using the :keyword:`type` statement, which creates an instance of +:class:`~typing.TypeAliasType`:: + + type Point = tuple[float, float] + +Type aliases can also be :ref:`generic `:: + + type Point[T] = tuple[T, T] + +The new syntax allows declaring :class:`~typing.TypeVarTuple` +and :class:`~typing.ParamSpec` parameters, as well as :class:`~typing.TypeVar` +parameters with bounds or constraints:: + + type IntFunc[**P] = Callable[P, int] # ParamSpec + type LabeledTuple[*Ts] = tuple[str, *Ts] # TypeVarTuple + type HashableSequence[T: Hashable] = Sequence[T] # TypeVar with bound + type IntOrStrSequence[T: (int, str)] = Sequence[T] # TypeVar with constraints + +The value of type aliases and the bound and constraints of type variables +created through this syntax are evaluated only on demand (see +:ref:`lazy evaluation `). This means type aliases are able to +refer to other types defined later in the file. + +Type parameters declared through a type parameter list are visible within the +scope of the declaration and any nested scopes, but not in the outer scope. For +example, they can be used in the type annotations for the methods of a generic +class or in the class body. However, they cannot be used in the module scope after +the class is defined. See :ref:`type-params` for a detailed description of the +runtime semantics of type parameters. + +In order to support these scoping semantics, a new kind of scope is introduced, +the :ref:`annotation scope `. Annotation scopes behave for the +most part like function scopes, but interact differently with enclosing class scopes. +In Python 3.13, :term:`annotations ` will also be evaluated in +annotation scopes. + +See :pep:`695` for more details. + +(PEP written by Eric Traut. Implementation by Jelle Zijlstra, Eric Traut, +and others in :gh:`103764`.) .. _whatsnew312-pep701: @@ -244,52 +331,6 @@ are parsed with the PEG parser, error messages can be more precise and show the Maureira-Fredes and Marta Gómez in :gh:`102856`. PEP written by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou and Marta Gómez). -.. _whatsnew312-pep709: - -PEP 709: Comprehension inlining -------------------------------- - -Dictionary, list, and set comprehensions are now inlined, rather than creating a -new single-use function object for each execution of the comprehension. This -speeds up execution of a comprehension by up to two times. -See :pep:`709` for further details. - -Comprehension iteration variables remain isolated and don't overwrite a -variable of the same name in the outer scope, nor are they visible after the -comprehension. Inlining does result in a few visible behavior changes: - -* There is no longer a separate frame for the comprehension in tracebacks, - and tracing/profiling no longer shows the comprehension as a function call. -* The :mod:`symtable` module will no longer produce child symbol tables for each - comprehension; instead, the comprehension's locals will be included in the - parent function's symbol table. -* Calling :func:`locals` inside a comprehension now includes variables - from outside the comprehension, and no longer includes the synthetic ``.0`` - variable for the comprehension "argument". -* A comprehension iterating directly over ``locals()`` (e.g. ``[k for k in - locals()]``) may see "RuntimeError: dictionary changed size during iteration" - when run under tracing (e.g. code coverage measurement). This is the same - behavior already seen in e.g. ``for k in locals():``. To avoid the error, first - create a list of keys to iterate over: ``keys = list(locals()); [k for k in - keys]``. - -(Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`.) - -.. _whatsnew312-pep688: - -PEP 688: Making the buffer protocol accessible in Python --------------------------------------------------------- - -:pep:`688` introduces a way to use the :ref:`buffer protocol ` -from Python code. Classes that implement the :meth:`~object.__buffer__` method -are now usable as buffer types. - -The new :class:`collections.abc.Buffer` ABC provides a standard -way to represent buffer objects, for example in type annotations. -The new :class:`inspect.BufferFlags` enum represents the flags that -can be used to customize buffer creation. -(Contributed by Jelle Zijlstra in :gh:`102500`.) - .. _whatsnew312-pep684: PEP 684: A Per-Interpreter GIL @@ -333,7 +374,105 @@ This means that you only pay for what you use, providing support for near-zero overhead debuggers and coverage tools. See :mod:`sys.monitoring` for details. -(Contributed by Mark Shannon in :gh:`103083`.) +(Contributed by Mark Shannon in :gh:`103082`.) + +.. _whatsnew312-pep688: + +PEP 688: Making the buffer protocol accessible in Python +-------------------------------------------------------- + +:pep:`688` introduces a way to use the :ref:`buffer protocol ` +from Python code. Classes that implement the :meth:`~object.__buffer__` method +are now usable as buffer types. + +The new :class:`collections.abc.Buffer` ABC provides a standard +way to represent buffer objects, for example in type annotations. +The new :class:`inspect.BufferFlags` enum represents the flags that +can be used to customize buffer creation. +(Contributed by Jelle Zijlstra in :gh:`102500`.) + +.. _whatsnew312-pep709: + +PEP 709: Comprehension inlining +------------------------------- + +Dictionary, list, and set comprehensions are now inlined, rather than creating a +new single-use function object for each execution of the comprehension. This +speeds up execution of a comprehension by up to two times. +See :pep:`709` for further details. + +Comprehension iteration variables remain isolated and don't overwrite a +variable of the same name in the outer scope, nor are they visible after the +comprehension. Inlining does result in a few visible behavior changes: + +* There is no longer a separate frame for the comprehension in tracebacks, + and tracing/profiling no longer shows the comprehension as a function call. +* The :mod:`symtable` module will no longer produce child symbol tables for each + comprehension; instead, the comprehension's locals will be included in the + parent function's symbol table. +* Calling :func:`locals` inside a comprehension now includes variables + from outside the comprehension, and no longer includes the synthetic ``.0`` + variable for the comprehension "argument". +* A comprehension iterating directly over ``locals()`` (e.g. ``[k for k in + locals()]``) may see "RuntimeError: dictionary changed size during iteration" + when run under tracing (e.g. code coverage measurement). This is the same + behavior already seen in e.g. ``for k in locals():``. To avoid the error, first + create a list of keys to iterate over: ``keys = list(locals()); [k for k in + keys]``. + +(Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`.) + +Improved Error Messages +----------------------- + +* Modules from the standard library are now potentially suggested as part of + the error messages displayed by the interpreter when a :exc:`NameError` is + raised to the top level. (Contributed by Pablo Galindo in :gh:`98254`.) + + >>> sys.version_info + Traceback (most recent call last): + File "", line 1, in + NameError: name 'sys' is not defined. Did you forget to import 'sys'? + +* Improve the error suggestion for :exc:`NameError` exceptions for instances. + Now if a :exc:`NameError` is raised in a method and the instance has an + attribute that's exactly equal to the name in the exception, the suggestion + will include ``self.`` instead of the closest match in the method + scope. (Contributed by Pablo Galindo in :gh:`99139`.) + + >>> class A: + ... def __init__(self): + ... self.blech = 1 + ... + ... def foo(self): + ... somethin = blech + ... + >>> A().foo() + Traceback (most recent call last): + File "", line 1 + somethin = blech + ^^^^^ + NameError: name 'blech' is not defined. Did you mean: 'self.blech'? + +* Improve the :exc:`SyntaxError` error message when the user types ``import x + from y`` instead of ``from y import x``. (Contributed by Pablo Galindo in :gh:`98931`.) + + >>> import a.y.z from b.y.z + Traceback (most recent call last): + File "", line 1 + import a.y.z from b.y.z + ^^^^^^^^^^^^^^^^^^^^^^^ + SyntaxError: Did you mean to use 'from ... import ...' instead? + +* :exc:`ImportError` exceptions raised from failed ``from import + `` statements now include suggestions for the value of ```` based on the + available names in ````. (Contributed by Pablo Galindo in :gh:`91058`.) + + >>> from collections import chainmap + Traceback (most recent call last): + File "", line 1, in + ImportError: cannot import name 'chainmap' from 'collections'. Did you mean: 'ChainMap'? + New Features Related to Type Hints ================================== @@ -398,70 +537,6 @@ See :pep:`698` for more details. (Contributed by Steven Troxler in :gh:`101561`.) -.. _whatsnew312-pep695: - -PEP 695: Type Parameter Syntax ------------------------------- - -Generic classes and functions under :pep:`484` were declared using a verbose syntax -that left the scope of type parameters unclear and required explicit declarations of -variance. - -:pep:`695` introduces a new, more compact and explicit way to create -:ref:`generic classes ` and :ref:`functions `:: - - def max[T](args: Iterable[T]) -> T: - ... - - class list[T]: - def __getitem__(self, index: int, /) -> T: - ... - - def append(self, element: T) -> None: - ... - -In addition, the PEP introduces a new way to declare :ref:`type aliases ` -using the :keyword:`type` statement, which creates an instance of -:class:`~typing.TypeAliasType`:: - - type Point = tuple[float, float] - -Type aliases can also be :ref:`generic `:: - - type Point[T] = tuple[T, T] - -The new syntax allows declaring :class:`~typing.TypeVarTuple` -and :class:`~typing.ParamSpec` parameters, as well as :class:`~typing.TypeVar` -parameters with bounds or constraints:: - - type IntFunc[**P] = Callable[P, int] # ParamSpec - type LabeledTuple[*Ts] = tuple[str, *Ts] # TypeVarTuple - type HashableSequence[T: Hashable] = Sequence[T] # TypeVar with bound - type IntOrStrSequence[T: (int, str)] = Sequence[T] # TypeVar with constraints - -The value of type aliases and the bound and constraints of type variables -created through this syntax are evaluated only on demand (see -:ref:`lazy evaluation `). This means type aliases are able to -refer to other types defined later in the file. - -Type parameters declared through a type parameter list are visible within the -scope of the declaration and any nested scopes, but not in the outer scope. For -example, they can be used in the type annotations for the methods of a generic -class or in the class body. However, they cannot be used in the module scope after -the class is defined. See :ref:`type-params` for a detailed description of the -runtime semantics of type parameters. - -In order to support these scoping semantics, a new kind of scope is introduced, -the :ref:`annotation scope `. Annotation scopes behave for the -most part like function scopes, but interact differently with enclosing class scopes. -In Python 3.13, :term:`annotations ` will also be evaluated in -annotation scopes. - -See :pep:`695` for more details. - -(PEP written by Eric Traut. Implementation by Jelle Zijlstra, Eric Traut, -and others in :gh:`103764`.) - Other Language Changes ====================== @@ -1577,6 +1652,8 @@ unittest * Remove many long-deprecated :mod:`unittest` features: + .. _unittest-TestCase-removed-aliases: + * A number of :class:`~unittest.TestCase` method aliases: ============================ =============================== =============== @@ -1812,6 +1889,7 @@ C API Changes New Features ------------ +.. _whatsnew312-pep697: * :pep:`697`: Introduce the :ref:`Unstable C API tier `, intended for low-level tools like debuggers and JIT compilers. @@ -1939,6 +2017,8 @@ New Features to replace the legacy-api :c:func:`!PyErr_Display`. (Contributed by Irit Katriel in :gh:`102755`). +.. _whatsnew312-pep683: + * :pep:`683`: Introduce *Immortal Objects*, which allows objects to bypass reference counts, and related changes to the C-API: From 98a2d0e13b9483d3f83d3b55db29e93fe67a62a3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:39:36 -0700 Subject: [PATCH 0823/1206] [3.12] no-issue: Fix a typo in the parameter name of random.expovariate. (gh-109902) (#109904) no-issue: Fix a typo in the parameter name of random.expovariate. (gh-109902) (cherry picked from commit 8100612bac2df1cbbb3a4cf646c4b82febf7807f) Co-authored-by: lohaswinner --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d07ffbb454ccd3..f2e94f9a5c5f19 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -818,7 +818,7 @@ random * Add :func:`random.binomialvariate`. (Contributed by Raymond Hettinger in :gh:`81620`.) -* Add a default of ``lamb=1.0`` to :func:`random.expovariate`. +* Add a default of ``lambd=1.0`` to :func:`random.expovariate`. (Contributed by Raymond Hettinger in :gh:`100234`.) shutil From 60046a7713af28dc044a91ad4733d52a17000288 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 28 Sep 2023 08:17:02 -0700 Subject: [PATCH 0824/1206] [3.12] gh-101100: Fix Sphinx warnings in Doc/using/configure.rst (GH-109931) (#109937) gh-101100: Fix Sphinx warnings in Doc/using/configure.rst (GH-109931) (cherry picked from commit 3538930d87e6bdd2bfffa3f674a62cc91d359d31) Co-authored-by: Victor Stinner --- Doc/tools/.nitignore | 1 - Doc/using/configure.rst | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 922f99f3fe2350..fb3ed71ac9099c 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -168,7 +168,6 @@ Doc/tutorial/controlflow.rst Doc/tutorial/datastructures.rst Doc/tutorial/introduction.rst Doc/using/cmdline.rst -Doc/using/configure.rst Doc/using/windows.rst Doc/whatsnew/2.0.rst Doc/whatsnew/2.1.rst diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 6fe06381d16841..3fe2a63587111c 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -82,8 +82,8 @@ General Options .. cmdoption:: --enable-loadable-sqlite-extensions - Support loadable extensions in the :mod:`_sqlite` extension module (default - is no). + Support loadable extensions in the :mod:`!_sqlite` extension module (default + is no) of the :mod:`sqlite3` module. See the :meth:`sqlite3.Connection.enable_load_extension` method of the :mod:`sqlite3` module. @@ -181,7 +181,7 @@ General Options Some Linux distribution packaging policies recommend against bundling dependencies. For example, Fedora installs wheel packages in the ``/usr/share/python-wheels/`` directory and don't install the - :mod:`ensurepip._bundled` package. + :mod:`!ensurepip._bundled` package. .. versionadded:: 3.10 @@ -258,7 +258,7 @@ Install Options .. cmdoption:: --disable-test-modules Don't build nor install test modules, like the :mod:`test` package or the - :mod:`_testcapi` extension module (built and installed by default). + :mod:`!_testcapi` extension module (built and installed by default). .. versionadded:: 3.10 @@ -391,7 +391,7 @@ Effects of a debug build: * Display all warnings by default: the list of default warning filters is empty in the :mod:`warnings` module. * Add ``d`` to :data:`sys.abiflags`. -* Add :func:`sys.gettotalrefcount` function. +* Add :func:`!sys.gettotalrefcount` function. * Add :option:`-X showrefcount <-X>` command line option. * Add :option:`-d` command line option and :envvar:`PYTHONDEBUG` environment variable to debug the parser. @@ -413,7 +413,7 @@ Effects of a debug build: * Check that deallocator functions don't change the current exception. * The garbage collector (:func:`gc.collect` function) runs some basic checks on objects consistency. - * The :c:macro:`Py_SAFE_DOWNCAST()` macro checks for integer underflow and + * The :c:macro:`!Py_SAFE_DOWNCAST()` macro checks for integer underflow and overflow when downcasting from wide types to narrow types. See also the :ref:`Python Development Mode ` and the @@ -441,7 +441,7 @@ Debug options Effects: * Define the ``Py_TRACE_REFS`` macro. - * Add :func:`sys.getobjects` function. + * Add :func:`!sys.getobjects` function. * Add :envvar:`PYTHONDUMPREFS` environment variable. This build is not ABI compatible with release build (default build) or debug @@ -519,7 +519,7 @@ Libraries options .. cmdoption:: --with-system-expat - Build the :mod:`pyexpat` module using an installed ``expat`` library + Build the :mod:`!pyexpat` module using an installed ``expat`` library (default is no). .. cmdoption:: --with-system-libmpdec From f3b61850ce78f95d64512189207f119fe0178123 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Thu, 28 Sep 2023 11:20:36 -0400 Subject: [PATCH 0825/1206] [3.12] gh-109991: Update macOS installer to use OpenSSL 3.0.10. (#110004) gh-109991: Update macOS installer to use OpenSSL 3.0.10. (cherry picked from commit 884cd180876f60dc65bf00e33c0435be9918e410) --- Mac/BuildScript/build-installer.py | 6 +++--- .../macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index c108ee21a7a2a3..c54de880c20360 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -246,9 +246,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 3.0.10", - url="https://www.openssl.org/source/openssl-3.0.10.tar.gz", - checksum='1761d4f5b13a1028b9b6f3d4b8e17feb0cedc9370f6afe61d7193d2cdce83323', + name="OpenSSL 3.0.11", + url="https://www.openssl.org/source/openssl-3.0.11.tar.gz", + checksum='b3425d3bb4a2218d0697eb41f7fc0cdede016ed19ca49d168b78e8d947887f55', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst b/Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst new file mode 100644 index 00000000000000..8d369988274f28 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst @@ -0,0 +1 @@ +Update macOS installer to use OpenSSL 3.0.11. From ef99f5e968be2d6a15232a4fbb9bdf5f7a8c2686 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 28 Sep 2023 08:21:09 -0700 Subject: [PATCH 0826/1206] [3.12] gh-109991: Update GitHub CI workflows to use OpenSSL 3.0.11 and multissltests to use 1.1.1w, 3.0.11, and 3.1.3. (gh-110002) (#110005) gh-109991: Update GitHub CI workflows to use OpenSSL 3.0.11 and multissltests to use 1.1.1w, 3.0.11, and 3.1.3. (gh-110002) (cherry picked from commit c88037d137a98d7c399c7bd74d5117b5bcae1543) Co-authored-by: Ned Deily --- .github/workflows/build.yml | 8 ++++---- .../2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst | 2 ++ Tools/ssl/multissltests.py | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 827df80ccd237a..af674de20c94ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -304,7 +304,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1v + OPENSSL_VER: 3.0.11 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v4 @@ -373,7 +373,7 @@ jobs: strategy: fail-fast: false matrix: - openssl_ver: [1.1.1v, 3.0.10, 3.1.2] + openssl_ver: [1.1.1w, 3.0.11, 3.1.3] env: OPENSSL_VER: ${{ matrix.openssl_ver }} MULTISSL_DIR: ${{ github.workspace }}/multissl @@ -425,7 +425,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_hypothesis == 'true' env: - OPENSSL_VER: 1.1.1v + OPENSSL_VER: 3.0.11 PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout@v4 @@ -534,7 +534,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1v + OPENSSL_VER: 3.0.11 PYTHONSTRICTEXTENSIONBUILD: 1 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 steps: diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst b/Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst new file mode 100644 index 00000000000000..13c1163ab53443 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst @@ -0,0 +1,2 @@ +Update GitHub CI workflows to use OpenSSL 3.0.11 and multissltests to use +1.1.1w, 3.0.11, and 3.1.3. diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index fc261c770d6944..f066fb52cfd496 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -46,9 +46,9 @@ ] OPENSSL_RECENT_VERSIONS = [ - "1.1.1v", - "3.0.10", - "3.1.2", + "1.1.1w", + "3.0.11", + "3.1.3", ] LIBRESSL_OLD_VERSIONS = [ From 335e3d59e04d53c11574b37f320b22061bdcce41 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 28 Sep 2023 22:38:08 +0100 Subject: [PATCH 0827/1206] [3.12] GH-109190: Copyedit 3.12 What's New: Bytecode (GH-109821) (#110047) . (cherry picked from commit 526380e28644236bde9e41b949497ca1ee22653f) --- Doc/whatsnew/3.12.rst | 27 +++++++++++++++++++++++++++ Misc/NEWS.d/3.12.0a4.rst | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f2e94f9a5c5f19..caef15f1eb74ce 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -701,6 +701,9 @@ dis :data:`dis.hasarg` collection instead. (Contributed by Irit Katriel in :gh:`94216`.) +* Add the :data:`dis.hasexc` collection to signify instructions that set + an exception handler. (Contributed by Irit Katriel in :gh:`94216`.) + fractions --------- @@ -884,6 +887,10 @@ statistics sys --- +* Add the :mod:`sys.monitoring` namespace to expose the new :ref:`PEP 669 + ` monitoring API. + (Contributed by Mark Shannon in :gh:`103082`.) + * Add :func:`sys.activate_stack_trampoline` and :func:`sys.deactivate_stack_trampoline` for activating and deactivating stack profiler trampolines, @@ -1083,9 +1090,27 @@ CPython bytecode changes * Remove the :opcode:`!PRECALL` instruction. (Contributed by Mark Shannon in :gh:`92925`.) +* Add the :opcode:`BINARY_SLICE` and :opcode:`STORE_SLICE` instructions. + (Contributed by Mark Shannon in :gh:`94163`.) + +* Add the :opcode:`CALL_INTRINSIC_1` instructions. + (Contributed by Mark Shannon in :gh:`99005`.) + +* Add the :opcode:`CALL_INTRINSIC_2` instruction. + (Contributed by Irit Katriel in :gh:`101799`.) + +* Add the :opcode:`CLEANUP_THROW` instruction. + (Contributed by Brandt Bucher in :gh:`90997`.) + +* Add the :opcode:`!END_SEND` instruction. + (Contributed by Mark Shannon in :gh:`103082`.) + * Add the :opcode:`LOAD_FAST_AND_CLEAR` instruction as part of the implementation of :pep:`709`. (Contributed by Carl Meyer in :gh:`101441`.) +* Add the :opcode:`LOAD_FAST_CHECK` instruction. + (Contributed by Dennis Sweeney in :gh:`93143`.) + * Add the :opcode:`LOAD_FROM_DICT_OR_DEREF`, :opcode:`LOAD_FROM_DICT_OR_GLOBALS`, and :opcode:`LOAD_LOCALS` opcodes as part of the implementation of :pep:`695`. Remove the :opcode:`!LOAD_CLASSDEREF` opcode, which can be replaced with @@ -1095,6 +1120,8 @@ CPython bytecode changes * Add the :opcode:`LOAD_SUPER_ATTR` instruction. (Contributed by Carl Meyer and Vladimir Matveev in :gh:`103497`.) +* Add the :opcode:`RETURN_CONST` instruction. (Contributed by Wenyang Wang in :gh:`101632`.) + Demos and Tools =============== diff --git a/Misc/NEWS.d/3.12.0a4.rst b/Misc/NEWS.d/3.12.0a4.rst index b3b39024056ccc..75246f3f13503e 100644 --- a/Misc/NEWS.d/3.12.0a4.rst +++ b/Misc/NEWS.d/3.12.0a4.rst @@ -23,10 +23,10 @@ Remove :opcode:`UNARY_POSITIVE`, :opcode:`ASYNC_GEN_WRAP` and .. nonce: D7H6j4 .. section: Core and Builtins -Add new :opcode:`CALL_INSTRINSIC_1` instruction. Remove +Add new :opcode:`CALL_INTRINSIC_1` instruction. Remove :opcode:`IMPORT_STAR`, :opcode:`PRINT_EXPR` and :opcode:`STOPITERATION_ERROR`, replacing them with the -:opcode:`CALL_INSTRINSIC_1` instruction. +:opcode:`CALL_INTRINSIC_1` instruction. .. From 69a9f471253ca58357c39a475872da7229c7b81e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 28 Sep 2023 23:10:22 -0700 Subject: [PATCH 0828/1206] [3.12] gh-110045: Update symtable module for PEP 695 (GH-110066) (#110070) gh-110045: Update symtable module for PEP 695 (GH-110066) (cherry picked from commit 7dc2c5093ef027aab57bca953ac2d6477a4a440b) Co-authored-by: Jelle Zijlstra --- Doc/library/symtable.rst | 12 ++++++- Lib/symtable.py | 15 ++++++--- Lib/test/test_symtable.py | 31 +++++++++++++++++++ ...-09-28-18-08-02.gh-issue-110045.0YIGKv.rst | 2 ++ Modules/symtablemodule.c | 8 +++++ 5 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index 65ff5bfe7abd61..85eae5f3822575 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -38,7 +38,13 @@ Examining Symbol Tables .. method:: get_type() Return the type of the symbol table. Possible values are ``'class'``, - ``'module'``, and ``'function'``. + ``'module'``, ``'function'``, ``'annotation'``, ``'TypeVar bound'``, + ``'type alias'``, and ``'type parameter'``. The latter four refer to + different flavors of :ref:`annotation scopes `. + + .. versionchanged:: 3.12 + Added ``'annotation'``, ``'TypeVar bound'``, ``'type alias'``, + and ``'type parameter'`` as possible return values. .. method:: get_id() @@ -49,6 +55,10 @@ Examining Symbol Tables Return the table's name. This is the name of the class if the table is for a class, the name of the function if the table is for a function, or ``'top'`` if the table is global (:meth:`get_type` returns ``'module'``). + For type parameter scopes (which are used for generic classes, functions, + and type aliases), it is the name of the underlying class, function, or + type alias. For type alias scopes, it is the name of the type alias. + For :class:`~typing.TypeVar` bound scopes, it is the name of the ``TypeVar``. .. method:: get_lineno() diff --git a/Lib/symtable.py b/Lib/symtable.py index 5dd71ffc6b4f19..4b0bc6f497a553 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -62,8 +62,8 @@ def __repr__(self): def get_type(self): """Return the type of the symbol table. - The values returned are 'class', 'module' and - 'function'. + The values returned are 'class', 'module', 'function', + 'annotation', 'TypeVar bound', 'type alias', and 'type parameter'. """ if self._table.type == _symtable.TYPE_MODULE: return "module" @@ -71,8 +71,15 @@ def get_type(self): return "function" if self._table.type == _symtable.TYPE_CLASS: return "class" - assert self._table.type in (1, 2, 3), \ - "unexpected type: {0}".format(self._table.type) + if self._table.type == _symtable.TYPE_ANNOTATION: + return "annotation" + if self._table.type == _symtable.TYPE_TYPE_VAR_BOUND: + return "TypeVar bound" + if self._table.type == _symtable.TYPE_TYPE_ALIAS: + return "type alias" + if self._table.type == _symtable.TYPE_TYPE_PARAM: + return "type parameter" + assert False, f"unexpected type: {self._table.type}" def get_id(self): """Return an identifier for the table. diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index 25714aecda3a15..61fda767e3ecd0 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -40,6 +40,15 @@ def foo(): def namespace_test(): pass def namespace_test(): pass + +type Alias = int +type GenericAlias[T] = list[T] + +def generic_spam[T](a): + pass + +class GenericMine[T: int]: + pass """ @@ -59,6 +68,14 @@ class SymtableTest(unittest.TestCase): internal = find_block(spam, "internal") other_internal = find_block(spam, "other_internal") foo = find_block(top, "foo") + Alias = find_block(top, "Alias") + GenericAlias = find_block(top, "GenericAlias") + GenericAlias_inner = find_block(GenericAlias, "GenericAlias") + generic_spam = find_block(top, "generic_spam") + generic_spam_inner = find_block(generic_spam, "generic_spam") + GenericMine = find_block(top, "GenericMine") + GenericMine_inner = find_block(GenericMine, "GenericMine") + T = find_block(GenericMine, "T") def test_type(self): self.assertEqual(self.top.get_type(), "module") @@ -66,6 +83,15 @@ def test_type(self): self.assertEqual(self.a_method.get_type(), "function") self.assertEqual(self.spam.get_type(), "function") self.assertEqual(self.internal.get_type(), "function") + self.assertEqual(self.foo.get_type(), "function") + self.assertEqual(self.Alias.get_type(), "type alias") + self.assertEqual(self.GenericAlias.get_type(), "type parameter") + self.assertEqual(self.GenericAlias_inner.get_type(), "type alias") + self.assertEqual(self.generic_spam.get_type(), "type parameter") + self.assertEqual(self.generic_spam_inner.get_type(), "function") + self.assertEqual(self.GenericMine.get_type(), "type parameter") + self.assertEqual(self.GenericMine_inner.get_type(), "class") + self.assertEqual(self.T.get_type(), "TypeVar bound") def test_id(self): self.assertGreater(self.top.get_id(), 0) @@ -73,6 +99,11 @@ def test_id(self): self.assertGreater(self.a_method.get_id(), 0) self.assertGreater(self.spam.get_id(), 0) self.assertGreater(self.internal.get_id(), 0) + self.assertGreater(self.foo.get_id(), 0) + self.assertGreater(self.Alias.get_id(), 0) + self.assertGreater(self.GenericAlias.get_id(), 0) + self.assertGreater(self.generic_spam.get_id(), 0) + self.assertGreater(self.GenericMine.get_id(), 0) def test_optimized(self): self.assertFalse(self.top.is_optimized()) diff --git a/Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst b/Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst new file mode 100644 index 00000000000000..44a6df1083762f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst @@ -0,0 +1,2 @@ +Update the :mod:`symtable` module to support the new scopes introduced by +:pep:`695`. diff --git a/Modules/symtablemodule.c b/Modules/symtablemodule.c index 1cc319cc3410d8..1f09c23bb855f2 100644 --- a/Modules/symtablemodule.c +++ b/Modules/symtablemodule.c @@ -85,6 +85,14 @@ symtable_init_constants(PyObject *m) if (PyModule_AddIntConstant(m, "TYPE_CLASS", ClassBlock) < 0) return -1; if (PyModule_AddIntConstant(m, "TYPE_MODULE", ModuleBlock) < 0) return -1; + if (PyModule_AddIntConstant(m, "TYPE_ANNOTATION", AnnotationBlock) < 0) + return -1; + if (PyModule_AddIntConstant(m, "TYPE_TYPE_VAR_BOUND", TypeVarBoundBlock) < 0) + return -1; + if (PyModule_AddIntConstant(m, "TYPE_TYPE_ALIAS", TypeAliasBlock) < 0) + return -1; + if (PyModule_AddIntConstant(m, "TYPE_TYPE_PARAM", TypeParamBlock) < 0) + return -1; if (PyModule_AddIntMacro(m, LOCAL) < 0) return -1; if (PyModule_AddIntMacro(m, GLOBAL_EXPLICIT) < 0) return -1; From 297104cce56deb38813a9db8efc422ae768da639 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 Sep 2023 06:29:14 -0700 Subject: [PATCH 0829/1206] [3.12] gh-101100: Fix sphinx warnings in `library/difflib.rst` (GH-110074) (#110081) gh-101100: Fix sphinx warnings in `library/difflib.rst` (GH-110074) (cherry picked from commit d102d39bbe175f179f28e4d4bea99dc122da5f8e) Co-authored-by: Nikita Sobolev --- Doc/library/difflib.rst | 18 +++++++++--------- Doc/tools/.nitignore | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index 5ee1f4a02c6816..c553611401d018 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -570,8 +570,8 @@ The :class:`SequenceMatcher` class has this constructor: The three methods that return the ratio of matching to total characters can give different results due to differing levels of approximation, although -:meth:`quick_ratio` and :meth:`real_quick_ratio` are always at least as large as -:meth:`ratio`: +:meth:`~SequenceMatcher.quick_ratio` and :meth:`~SequenceMatcher.real_quick_ratio` +are always at least as large as :meth:`~SequenceMatcher.ratio`: >>> s = SequenceMatcher(None, "abcd", "bcde") >>> s.ratio() @@ -593,15 +593,15 @@ This example compares two strings, considering blanks to be "junk": ... "private Thread currentThread;", ... "private volatile Thread currentThread;") -:meth:`ratio` returns a float in [0, 1], measuring the similarity of the -sequences. As a rule of thumb, a :meth:`ratio` value over 0.6 means the +:meth:`~SequenceMatcher.ratio` returns a float in [0, 1], measuring the similarity of the +sequences. As a rule of thumb, a :meth:`~SequenceMatcher.ratio` value over 0.6 means the sequences are close matches: >>> print(round(s.ratio(), 3)) 0.866 If you're only interested in where the sequences match, -:meth:`get_matching_blocks` is handy: +:meth:`~SequenceMatcher.get_matching_blocks` is handy: >>> for block in s.get_matching_blocks(): ... print("a[%d] and b[%d] match for %d elements" % block) @@ -609,12 +609,12 @@ If you're only interested in where the sequences match, a[8] and b[17] match for 21 elements a[29] and b[38] match for 0 elements -Note that the last tuple returned by :meth:`get_matching_blocks` is always a -dummy, ``(len(a), len(b), 0)``, and this is the only case in which the last +Note that the last tuple returned by :meth:`~SequenceMatcher.get_matching_blocks` +is always a dummy, ``(len(a), len(b), 0)``, and this is the only case in which the last tuple element (number of elements matched) is ``0``. If you want to know how to change the first sequence into the second, use -:meth:`get_opcodes`: +:meth:`~SequenceMatcher.get_opcodes`: >>> for opcode in s.get_opcodes(): ... print("%6s a[%d:%d] b[%d:%d]" % opcode) @@ -689,7 +689,7 @@ Differ Example This example compares two texts. First we set up the texts, sequences of individual single-line strings ending with newlines (such sequences can also be -obtained from the :meth:`~io.BaseIO.readlines` method of file-like objects): +obtained from the :meth:`~io.IOBase.readlines` method of file-like objects): >>> text1 = ''' 1. Beautiful is better than ugly. ... 2. Explicit is better than implicit. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index fb3ed71ac9099c..5ec46979482291 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -60,7 +60,6 @@ Doc/library/csv.rst Doc/library/datetime.rst Doc/library/dbm.rst Doc/library/decimal.rst -Doc/library/difflib.rst Doc/library/doctest.rst Doc/library/email.charset.rst Doc/library/email.compat32-message.rst From c89844aaec272f0c6715cf600a7753fb817c30f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 Sep 2023 06:29:39 -0700 Subject: [PATCH 0830/1206] [3.12] gh-101100: Fix Sphinx warnings in `tutorial/controlflow.rst` (GH-109424) (#110084) gh-101100: Fix Sphinx warnings in `tutorial/controlflow.rst` (GH-109424) (cherry picked from commit 8898a8683b5631c24d51a6a7babf55a255874950) Co-authored-by: Maciej Olko Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/tools/.nitignore | 1 - Doc/tutorial/controlflow.rst | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 5ec46979482291..bd79e4445062e3 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -163,7 +163,6 @@ Doc/reference/datamodel.rst Doc/reference/expressions.rst Doc/reference/import.rst Doc/reference/simple_stmts.rst -Doc/tutorial/controlflow.rst Doc/tutorial/datastructures.rst Doc/tutorial/introduction.rst Doc/using/cmdline.rst diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 4bcc3768111ccd..aa9caa101da40a 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -534,7 +534,7 @@ This example, as usual, demonstrates some new Python features: Different types define different methods. Methods of different types may have the same name without causing ambiguity. (It is possible to define your own object types and methods, using *classes*, see :ref:`tut-classes`) - The method :meth:`~list.append` shown in the example is defined for list objects; it + The method :meth:`!append` shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent to ``result = result + [a]``, but more efficient. @@ -1046,7 +1046,7 @@ Function Annotations information about the types used by user-defined functions (see :pep:`3107` and :pep:`484` for more information). -:term:`Annotations ` are stored in the :attr:`__annotations__` +:term:`Annotations ` are stored in the :attr:`!__annotations__` attribute of the function as a dictionary and have no effect on any other part of the function. Parameter annotations are defined by a colon after the parameter name, followed by an expression evaluating to the value of the annotation. Return annotations are From d2a31319a5faa3707e9ec4547f3ff53e8c969611 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 Sep 2023 06:30:44 -0700 Subject: [PATCH 0831/1206] [3.12] gh-101100: Fix references to ``URLError`` and ``HTTPError`` in ``howto/urllib2.rst`` (GH-107966) (#110086) gh-101100: Fix references to ``URLError`` and ``HTTPError`` in ``howto/urllib2.rst`` (GH-107966) (cherry picked from commit bfd94ab9e9f4055ecedaa500b46b0270da9ffe12) Co-authored-by: Yuki K Co-authored-by: Hugo van Kemenade --- Doc/howto/urllib2.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 86137fb38c9b93..570435d48866d3 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -194,11 +194,11 @@ which comes after we have a look at what happens when things go wrong. Handling Exceptions =================== -*urlopen* raises :exc:`URLError` when it cannot handle a response (though as +*urlopen* raises :exc:`~urllib.error.URLError` when it cannot handle a response (though as usual with Python APIs, built-in exceptions such as :exc:`ValueError`, :exc:`TypeError` etc. may also be raised). -:exc:`HTTPError` is the subclass of :exc:`URLError` raised in the specific case of +:exc:`~urllib.error.HTTPError` is the subclass of :exc:`~urllib.error.URLError` raised in the specific case of HTTP URLs. The exception classes are exported from the :mod:`urllib.error` module. @@ -229,12 +229,12 @@ the status code indicates that the server is unable to fulfil the request. The default handlers will handle some of these responses for you (for example, if the response is a "redirection" that requests the client fetch the document from a different URL, urllib will handle that for you). For those it can't handle, -urlopen will raise an :exc:`HTTPError`. Typical errors include '404' (page not +urlopen will raise an :exc:`~urllib.error.HTTPError`. Typical errors include '404' (page not found), '403' (request forbidden), and '401' (authentication required). See section 10 of :rfc:`2616` for a reference on all the HTTP error codes. -The :exc:`HTTPError` instance raised will have an integer 'code' attribute, which +The :exc:`~urllib.error.HTTPError` instance raised will have an integer 'code' attribute, which corresponds to the error sent by the server. Error Codes @@ -317,7 +317,7 @@ dictionary is reproduced here for convenience :: } When an error is raised the server responds by returning an HTTP error code -*and* an error page. You can use the :exc:`HTTPError` instance as a response on the +*and* an error page. You can use the :exc:`~urllib.error.HTTPError` instance as a response on the page returned. This means that as well as the code attribute, it also has read, geturl, and info, methods as returned by the ``urllib.response`` module:: @@ -338,7 +338,7 @@ geturl, and info, methods as returned by the ``urllib.response`` module:: Wrapping it Up -------------- -So if you want to be prepared for :exc:`HTTPError` *or* :exc:`URLError` there are two +So if you want to be prepared for :exc:`~urllib.error.HTTPError` *or* :exc:`~urllib.error.URLError` there are two basic approaches. I prefer the second approach. Number 1 @@ -365,7 +365,7 @@ Number 1 .. note:: The ``except HTTPError`` *must* come first, otherwise ``except URLError`` - will *also* catch an :exc:`HTTPError`. + will *also* catch an :exc:`~urllib.error.HTTPError`. Number 2 ~~~~~~~~ @@ -391,7 +391,7 @@ Number 2 info and geturl =============== -The response returned by urlopen (or the :exc:`HTTPError` instance) has two +The response returned by urlopen (or the :exc:`~urllib.error.HTTPError` instance) has two useful methods :meth:`info` and :meth:`geturl` and is defined in the module :mod:`urllib.response`.. From 8882b30dab237c8b460cb8d18cecc8b8d031da25 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 29 Sep 2023 06:31:10 -0700 Subject: [PATCH 0832/1206] [3.12] gh-109634: Fix `:samp:` syntax (GH-110073) (#110095) gh-109634: Fix `:samp:` syntax (GH-110073) (cherry picked from commit e27adc68ccee8345e05b7516e6b46f6c7ff53371) Co-authored-by: Jacob Coffee --- Doc/library/codecs.rst | 2 +- Doc/reference/lexical_analysis.rst | 2 +- Misc/NEWS.d/3.8.0a1.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 053bf64addb821..2db4a67d1973d5 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1350,7 +1350,7 @@ encodings. +--------------------+---------+---------------------------+ | raw_unicode_escape | | Latin-1 encoding with | | | | :samp:`\\u{XXXX}` and | -| | | :samp:`\\U{XXXXXXXX}`` | +| | | :samp:`\\U{XXXXXXXX}` | | | | for other code points. | | | | Existing | | | | backslashes are not | diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 9cad790fed4ef0..816de9b57536a7 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -582,7 +582,7 @@ Standard C. The recognized escape sequences are: +-------------------------+---------------------------------+-------+ | ``\v`` | ASCII Vertical Tab (VT) | | +-------------------------+---------------------------------+-------+ -| :samp:`\\{ooo}` | Character with octal value | (2,4) | +| :samp:`\\\\{ooo}` | Character with octal value | (2,4) | | | *ooo* | | +-------------------------+---------------------------------+-------+ | :samp:`\\x{hh}` | Character with hex value *hh* | (3,4) | diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index d4e6ddc9c183cd..bf1cfaa9497ec2 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -8253,7 +8253,7 @@ Explain how IDLE's Shell displays output. Improve the doc about IDLE running user code. The section is renamed from "IDLE -- console differences" is renamed "Running user code". It mostly -covers the implications of using custom :samp:sys.std{xxx}` objects. +covers the implications of using custom :samp:`sys.std{xxx}` objects. .. From a6773ec099469bee0af02f086da6463283b2589e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 02:59:52 -0700 Subject: [PATCH 0833/1206] [3.12] gh-109991: Update Windows build to use OpenSSL 3.0.11 (GH-110054) (#110056) gh-109991: Update Windows build to use OpenSSL 3.0.11 (GH-110054) (cherry picked from commit cf4c29725636e1a0dd2ebab443613b56ca6c9486) Co-authored-by: Zachary Ware --- .../Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst | 1 + PCbuild/get_externals.bat | 4 ++-- PCbuild/python.props | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst diff --git a/Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst b/Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst new file mode 100644 index 00000000000000..ee988f90863426 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst @@ -0,0 +1 @@ +Update Windows build to use OpenSSL 3.0.11. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 99c2e20a267b2b..181ddfb60a3127 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.10 +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.11 set libraries=%libraries% sqlite-3.42.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 @@ -77,7 +77,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.10 +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.11 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.13.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/python.props b/PCbuild/python.props index 94faa8221eac5a..35c6e92be45dc9 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -74,8 +74,8 @@ $(ExternalsDir)libffi-3.4.4\ $(libffiDir)$(ArchName)\ $(libffiOutDir)include - $(ExternalsDir)openssl-3.0.10\ - $(ExternalsDir)openssl-bin-3.0.10\$(ArchName)\ + $(ExternalsDir)openssl-3.0.11\ + $(ExternalsDir)openssl-bin-3.0.11\$(ArchName)\ $(opensslOutDir)include $(ExternalsDir)\nasm-2.11.06\ $(ExternalsDir)\zlib-1.2.13\ From 54ffee0e519f1b684e9974958dd338f65bbebd96 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 03:01:26 -0700 Subject: [PATCH 0834/1206] [3.12] GH-101100: Fix reference warnings for ``gettext`` (GH-110115) (#110140) GH-101100: Fix reference warnings for ``gettext`` (GH-110115) (cherry picked from commit 0449fe999d56ba795a852d83380fe06514139935) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/gettext.rst | 55 +++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index 88a65b980d310f..7ebe91b372d35a 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -58,7 +58,7 @@ class-based API instead. Return the localized translation of *message*, based on the current global domain, language, and locale directory. This function is usually aliased as - :func:`_` in the local namespace (see examples below). + :func:`!_` in the local namespace (see examples below). .. function:: dgettext(domain, message) @@ -98,7 +98,7 @@ class-based API instead. .. versionadded:: 3.8 -Note that GNU :program:`gettext` also defines a :func:`dcgettext` method, but +Note that GNU :program:`gettext` also defines a :func:`!dcgettext` method, but this was deemed not useful and so it is currently unimplemented. Here's an example of typical usage for this API:: @@ -119,7 +119,7 @@ greater convenience than the GNU :program:`gettext` API. It is the recommended way of localizing your Python applications and modules. :mod:`!gettext` defines a :class:`GNUTranslations` class which implements the parsing of GNU :file:`.mo` format files, and has methods for returning strings. Instances of this class can also -install themselves in the built-in namespace as the function :func:`_`. +install themselves in the built-in namespace as the function :func:`!_`. .. function:: find(domain, localedir=None, languages=None, all=False) @@ -150,15 +150,12 @@ install themselves in the built-in namespace as the function :func:`_`. .. function:: translation(domain, localedir=None, languages=None, class_=None, fallback=False) - Return a :class:`*Translations` instance based on the *domain*, *localedir*, + Return a ``*Translations`` instance based on the *domain*, *localedir*, and *languages*, which are first passed to :func:`find` to get a list of the associated :file:`.mo` file paths. Instances with identical :file:`.mo` file names are cached. The actual class instantiated is *class_* if provided, otherwise :class:`GNUTranslations`. The class's constructor must - take a single :term:`file object` argument. If provided, *codeset* will change - the charset used to encode translated strings in the - :meth:`~NullTranslations.lgettext` and :meth:`~NullTranslations.lngettext` - methods. + take a single :term:`file object` argument. If multiple files are found, later files are used as fallbacks for earlier ones. To allow setting the fallback, :func:`copy.copy` is used to clone each @@ -177,19 +174,19 @@ install themselves in the built-in namespace as the function :func:`_`. .. function:: install(domain, localedir=None, *, names=None) - This installs the function :func:`_` in Python's builtins namespace, based on + This installs the function :func:`!_` in Python's builtins namespace, based on *domain* and *localedir* which are passed to the function :func:`translation`. For the *names* parameter, please see the description of the translation object's :meth:`~NullTranslations.install` method. As seen below, you usually mark the strings in your application that are - candidates for translation, by wrapping them in a call to the :func:`_` + candidates for translation, by wrapping them in a call to the :func:`!_` function, like this:: print(_('This string will be translated.')) - For convenience, you want the :func:`_` function to be installed in Python's + For convenience, you want the :func:`!_` function to be installed in Python's builtins namespace, so it is easily accessible in all modules of your application. @@ -276,20 +273,20 @@ are the methods of :class:`!NullTranslations`: If the *names* parameter is given, it must be a sequence containing the names of functions you want to install in the builtins namespace in - addition to :func:`_`. Supported names are ``'gettext'``, ``'ngettext'``, - ``'pgettext'``, ``'npgettext'``, ``'lgettext'``, and ``'lngettext'``. + addition to :func:`!_`. Supported names are ``'gettext'``, ``'ngettext'``, + ``'pgettext'``, and ``'npgettext'``. Note that this is only one way, albeit the most convenient way, to make - the :func:`_` function available to your application. Because it affects + the :func:`!_` function available to your application. Because it affects the entire application globally, and specifically the built-in namespace, - localized modules should never install :func:`_`. Instead, they should use - this code to make :func:`_` available to their module:: + localized modules should never install :func:`!_`. Instead, they should use + this code to make :func:`!_` available to their module:: import gettext t = gettext.translation('mymodule', ...) _ = t.gettext - This puts :func:`_` only in the module's global namespace and so only + This puts :func:`!_` only in the module's global namespace and so only affects calls within this module. .. versionchanged:: 3.8 @@ -314,7 +311,7 @@ initialize the "protected" :attr:`_charset` instance variable, defaulting to ids and message strings read from the catalog are converted to Unicode using this encoding, else ASCII is assumed. -Since message ids are read as Unicode strings too, all :meth:`*gettext` methods +Since message ids are read as Unicode strings too, all ``*gettext()`` methods will assume message ids as Unicode strings, not byte strings. The entire set of key/value pairs are placed into a dictionary and set as the @@ -404,7 +401,7 @@ version has a slightly different API. Its documented usage was:: _ = cat.gettext print(_('hello world')) -For compatibility with this older module, the function :func:`Catalog` is an +For compatibility with this older module, the function :func:`!Catalog` is an alias for the :func:`translation` function described above. One difference between this module and Henstridge's: his catalog objects @@ -432,7 +429,7 @@ take the following steps: In order to prepare your code for I18N, you need to look at all the strings in your files. Any string that needs to be translated should be marked by wrapping -it in ``_('...')`` --- that is, a call to the function :func:`_`. For example:: +it in ``_('...')`` --- that is, a call to the function :func:`_ `. For example:: filename = 'mylog.txt' message = _('writing a log message') @@ -504,7 +501,7 @@ module:: Localizing your application ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you are localizing your application, you can install the :func:`_` function +If you are localizing your application, you can install the :func:`!_` function globally into the built-in namespace, usually in the main driver file of your application. This will let all your application-specific files just use ``_('...')`` without having to explicitly install it in each file. @@ -581,13 +578,13 @@ Here is one way you can handle this situation:: for a in animals: print(_(a)) -This works because the dummy definition of :func:`_` simply returns the string +This works because the dummy definition of :func:`!_` simply returns the string unchanged. And this dummy definition will temporarily override any definition -of :func:`_` in the built-in namespace (until the :keyword:`del` command). Take -care, though if you have a previous definition of :func:`_` in the local +of :func:`!_` in the built-in namespace (until the :keyword:`del` command). Take +care, though if you have a previous definition of :func:`!_` in the local namespace. -Note that the second use of :func:`_` will not identify "a" as being +Note that the second use of :func:`!_` will not identify "a" as being translatable to the :program:`gettext` program, because the parameter is not a string literal. @@ -606,13 +603,13 @@ Another way to handle this is with the following example:: print(_(a)) In this case, you are marking translatable strings with the function -:func:`N_`, which won't conflict with any definition of :func:`_`. +:func:`!N_`, which won't conflict with any definition of :func:`!_`. However, you will need to teach your message extraction program to -look for translatable strings marked with :func:`N_`. :program:`xgettext`, +look for translatable strings marked with :func:`!N_`. :program:`xgettext`, :program:`pygettext`, ``pybabel extract``, and :program:`xpot` all support this through the use of the :option:`!-k` command-line switch. -The choice of :func:`N_` here is totally arbitrary; it could have just -as easily been :func:`MarkThisStringForTranslation`. +The choice of :func:`!N_` here is totally arbitrary; it could have just +as easily been :func:`!MarkThisStringForTranslation`. Acknowledgements From 96110e942935cbc812006c63fcba1458d67771a7 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 2 Oct 2023 04:02:29 -0600 Subject: [PATCH 0835/1206] [3.12] gh-101100: Fix sphinx warnings in `library/site.rst` (GH-110144) (#110187) (cherry picked from commit 31097df611bb5c8084190202e095ae47e8b81c0f) Co-authored-by: Nikita Sobolev Co-authored-by: Alex Waygood --- Doc/library/exceptions.rst | 14 ++++++++++---- Doc/library/site.rst | 22 +++++++++++++++------- Doc/tools/.nitignore | 2 -- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index dcfbc486eeb358..d210f82f3926f7 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -220,10 +220,16 @@ The following exceptions are the exceptions that are usually raised. load a module. Also raised when the "from list" in ``from ... import`` has a name that cannot be found. - The :attr:`name` and :attr:`path` attributes can be set using keyword-only - arguments to the constructor. When set they represent the name of the module - that was attempted to be imported and the path to any file which triggered - the exception, respectively. + The optional *name* and *path* keyword-only arguments + set the corresponding attributes: + + .. attribute:: name + + The name of the module that was attempted to be imported. + + .. attribute:: path + + The path to any file which triggered the exception. .. versionchanged:: 3.3 Added the :attr:`name` and :attr:`path` attributes. diff --git a/Doc/library/site.rst b/Doc/library/site.rst index ea3b2e996574ef..ebd78917a01373 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -19,7 +19,7 @@ Importing this module will append site-specific paths to the module search path and add a few builtins, unless :option:`-S` was used. In that case, this module can be safely imported with no automatic modifications to the module search path or additions to the builtins. To explicitly trigger the usual site-specific -additions, call the :func:`site.main` function. +additions, call the :func:`main` function. .. versionchanged:: 3.3 Importing the module used to trigger paths manipulation even when using @@ -109,32 +109,40 @@ directory precedes the :file:`foo` directory because :file:`bar.pth` comes alphabetically before :file:`foo.pth`; and :file:`spam` is omitted because it is not mentioned in either path configuration file. -.. index:: pair: module; sitecustomize +:mod:`sitecustomize` +-------------------- + +.. module:: sitecustomize After these path manipulations, an attempt is made to import a module named :mod:`sitecustomize`, which can perform arbitrary site-specific customizations. It is typically created by a system administrator in the site-packages directory. If this import fails with an :exc:`ImportError` or its subclass -exception, and the exception's :attr:`name` attribute equals to ``'sitecustomize'``, +exception, and the exception's :attr:`~ImportError.name` +attribute equals to ``'sitecustomize'``, it is silently ignored. If Python is started without output streams available, as with :file:`pythonw.exe` on Windows (which is used by default to start IDLE), attempted output from :mod:`sitecustomize` is ignored. Any other exception causes a silent and perhaps mysterious failure of the process. -.. index:: pair: module; usercustomize +:mod:`usercustomize` +-------------------- + +.. module:: usercustomize After this, an attempt is made to import a module named :mod:`usercustomize`, which can perform arbitrary user-specific customizations, if -:data:`ENABLE_USER_SITE` is true. This file is intended to be created in the +:data:`~site.ENABLE_USER_SITE` is true. This file is intended to be created in the user site-packages directory (see below), which is part of ``sys.path`` unless disabled by :option:`-s`. If this import fails with an :exc:`ImportError` or -its subclass exception, and the exception's :attr:`name` attribute equals to -``'usercustomize'``, it is silently ignored. +its subclass exception, and the exception's :attr:`~ImportError.name` +attribute equals to ``'usercustomize'``, it is silently ignored. Note that for some non-Unix systems, ``sys.prefix`` and ``sys.exec_prefix`` are empty, and the path manipulations are skipped; however the import of :mod:`sitecustomize` and :mod:`usercustomize` is still attempted. +.. currentmodule:: site .. _rlcompleter-config: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index bd79e4445062e3..90a66ac8a282a0 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -118,7 +118,6 @@ Doc/library/select.rst Doc/library/selectors.rst Doc/library/shelve.rst Doc/library/signal.rst -Doc/library/site.rst Doc/library/smtplib.rst Doc/library/socket.rst Doc/library/socketserver.rst @@ -127,7 +126,6 @@ Doc/library/stdtypes.rst Doc/library/string.rst Doc/library/subprocess.rst Doc/library/sunau.rst -Doc/library/sys_path_init.rst Doc/library/syslog.rst Doc/library/tarfile.rst Doc/library/telnetlib.rst From b0a8cb2901be6b5148b3ed1213035c625349e9f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 03:03:12 -0700 Subject: [PATCH 0836/1206] [3.12] gh-110138: Improve grammar in idiomatic usage of ``__main__.py`` (GH-110142) (#110188) gh-110138: Improve grammar in idiomatic usage of ``__main__.py`` (GH-110142) (cherry picked from commit adf0f15a06c6e8ddd1a6d59b28efcbb26289f080) Co-authored-by: Quentin Agren --- Doc/library/__main__.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index fd60d92d4eb0f9..d378e40b3906c6 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -238,9 +238,9 @@ package. For more details, see :ref:`intra-package-references` in the Idiomatic Usage ^^^^^^^^^^^^^^^ -The contents of ``__main__.py`` typically isn't fenced with -``if __name__ == '__main__'`` blocks. Instead, those files are kept short, -functions to execute from other modules. Those other modules can then be +The content of ``__main__.py`` typically isn't fenced with an +``if __name__ == '__main__'`` block. Instead, those files are kept +short and import functions to execute from other modules. Those other modules can then be easily unit-tested and are properly reusable. If used, an ``if __name__ == '__main__'`` block will still work as expected From 6f6ca1daa4a1452bcb4a3e900767333d1f97b937 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 03:07:58 -0700 Subject: [PATCH 0837/1206] [3.12] GH-101100: Fix reference warnings for ``namedtuple`` (GH-110113) (#110135) GH-101100: Fix reference warnings for ``namedtuple`` (GH-110113) (cherry picked from commit cbdacc738a52a876aae5b74b4665d30a5f204766) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/2.6.rst | 6 +++--- Misc/NEWS.d/3.8.0a1.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 128407e3fba132..96d9b792b3723a 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1850,8 +1850,8 @@ changes, or look through the Subversion logs for all the details. special values and floating-point exceptions in a manner consistent with Annex 'G' of the C99 standard. -* A new data type in the :mod:`collections` module: :class:`namedtuple(typename, - fieldnames)` is a factory function that creates subclasses of the standard tuple +* A new data type in the :mod:`collections` module: ``namedtuple(typename, fieldnames)`` + is a factory function that creates subclasses of the standard tuple whose fields are accessible by name as well as index. For example:: >>> var_type = collections.namedtuple('variable', @@ -1873,7 +1873,7 @@ changes, or look through the Subversion logs for all the details. variable(id=1, name='amplitude', type='int', size=4) Several places in the standard library that returned tuples have - been modified to return :class:`namedtuple` instances. For example, + been modified to return :func:`namedtuple` instances. For example, the :meth:`Decimal.as_tuple` method now returns a named tuple with :attr:`sign`, :attr:`digits`, and :attr:`exponent` fields. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index bf1cfaa9497ec2..cb635e617e3ac6 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -380,7 +380,7 @@ Implement :pep:`572` (assignment expressions). Patch by Emily Morehouse. .. nonce: voIdcp .. section: Core and Builtins -Speed up :class:`namedtuple` attribute access by 1.6x using a C fast-path +Speed up :func:`namedtuple` attribute access by 1.6x using a C fast-path for the name descriptors. Patch by Pablo Galindo. .. From bb35fc3706a8b605c66ef161b7afb9b64cb7a339 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 03:09:54 -0700 Subject: [PATCH 0838/1206] [3.12] gh-107888: Fix test_mmap.test_access_parameter() on macOS 14 (GH-109928) (#109929) gh-107888: Fix test_mmap.test_access_parameter() on macOS 14 (GH-109928) (cherry picked from commit 9dbfe2dc8e7bba25e52f9470ae6969821a365297) Co-authored-by: Victor Stinner --- Lib/test/test_mmap.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index bab868600895c1..dfcf3039422af5 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -255,10 +255,15 @@ def test_access_parameter(self): # Try writing with PROT_EXEC and without PROT_WRITE prot = mmap.PROT_READ | getattr(mmap, 'PROT_EXEC', 0) with open(TESTFN, "r+b") as f: - m = mmap.mmap(f.fileno(), mapsize, prot=prot) - self.assertRaises(TypeError, m.write, b"abcdef") - self.assertRaises(TypeError, m.write_byte, 0) - m.close() + try: + m = mmap.mmap(f.fileno(), mapsize, prot=prot) + except PermissionError: + # on macOS 14, PROT_READ | PROT_EXEC is not allowed + pass + else: + self.assertRaises(TypeError, m.write, b"abcdef") + self.assertRaises(TypeError, m.write_byte, 0) + m.close() def test_bad_file_desc(self): # Try opening a bad file descriptor... From 48afd1cf1735ff8b4a0e7506943a6272246b926f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 03:50:28 -0700 Subject: [PATCH 0839/1206] [3.12] GH-92584: Move installation schemes overview to sysconfig docs (GH-108018) (#110213) GH-92584: Move installation schemes overview to sysconfig docs (GH-108018) * Add new installation path functions subsection * Add content from install/index to sysconfig * Fix table * Update note about installers * Clean up the list of schemes, remove references to Distutils (cherry picked from commit f16e81f368d08891e28dc1f038c1826ea80d7801) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/site.rst | 2 +- Doc/library/sysconfig.rst | 181 ++++++++++++++++++++++++++++++++++---- Doc/using/cmdline.rst | 2 +- 3 files changed, 167 insertions(+), 18 deletions(-) diff --git a/Doc/library/site.rst b/Doc/library/site.rst index ebd78917a01373..02880c56416615 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -199,7 +199,7 @@ Module contents :file:`~/Library/Python/{X.Y}` for macOS framework builds, and :file:`{%APPDATA%}\\Python` for Windows. This value is used to compute the installation directories for scripts, data files, Python modules, - etc. for the user installation scheme. + etc. for the :ref:`user installation scheme `. See also :envvar:`PYTHONUSERBASE`. diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index 26344ea4e7e2ab..e5ed45b8529a57 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -20,6 +20,7 @@ The :mod:`sysconfig` module provides access to Python's configuration information like the list of installation paths and the configuration variables relevant for the current platform. + Configuration variables ----------------------- @@ -60,6 +61,7 @@ Example of usage:: >>> sysconfig.get_config_vars('AR', 'CXX') ['ar', 'g++'] + .. _installation_paths: Installation paths @@ -68,27 +70,24 @@ Installation paths Python uses an installation scheme that differs depending on the platform and on the installation options. These schemes are stored in :mod:`sysconfig` under unique identifiers based on the value returned by :const:`os.name`. - -Every new component that is installed using :mod:`!distutils` or a -Distutils-based system will follow the same scheme to copy its file in the right -places. +The schemes are used by package installers to determine where to copy files to. Python currently supports nine schemes: - *posix_prefix*: scheme for POSIX platforms like Linux or macOS. This is the default scheme used when Python or a component is installed. -- *posix_home*: scheme for POSIX platforms used when a *home* option is used - upon installation. This scheme is used when a component is installed through - Distutils with a specific home prefix. -- *posix_user*: scheme for POSIX platforms used when a component is installed - through Distutils and the *user* option is used. This scheme defines paths - located under the user home directory. +- *posix_home*: scheme for POSIX platforms, when the *home* option is used. + This scheme defines paths located under a specific home prefix. +- *posix_user*: scheme for POSIX platforms, when the *user* option is used. + This scheme defines paths located under the user's home directory + (:const:`site.USER_BASE`). - *posix_venv*: scheme for :mod:`Python virtual environments ` on POSIX platforms; by default it is the same as *posix_prefix*. -- *nt*: scheme for NT platforms like Windows. -- *nt_user*: scheme for NT platforms, when the *user* option is used. -- *nt_venv*: scheme for :mod:`Python virtual environments ` on NT - platforms; by default it is the same as *nt*. +- *nt*: scheme for Windows. + This is the default scheme used when Python or a component is installed. +- *nt_user*: scheme for Windows, when the *user* option is used. +- *nt_venv*: scheme for :mod:`Python virtual environments ` on Windows; + by default it is the same as *nt*. - *venv*: a scheme with values from either *posix_venv* or *nt_venv* depending on the platform Python runs on. - *osx_framework_user*: scheme for macOS, when the *user* option is used. @@ -101,7 +100,7 @@ identifier. Python currently uses eight paths: - *platstdlib*: directory containing the standard Python library files that are platform-specific. - *platlib*: directory for site-specific, platform-specific files. -- *purelib*: directory for site-specific, non-platform-specific files. +- *purelib*: directory for site-specific, non-platform-specific files ('pure' Python). - *include*: directory for non-platform-specific header files for the Python C-API. - *platinclude*: directory for platform-specific header files for @@ -109,7 +108,157 @@ identifier. Python currently uses eight paths: - *scripts*: directory for script files. - *data*: directory for data files. -:mod:`sysconfig` provides some functions to determine these paths. + +.. _sysconfig-user-scheme: + +User scheme +--------------- + +This scheme is designed to be the most convenient solution for users that don't +have write permission to the global site-packages directory or don't want to +install into it. + +Files will be installed into subdirectories of :const:`site.USER_BASE` (written +as :file:`{userbase}` hereafter). This scheme installs pure Python modules and +extension modules in the same location (also known as :const:`site.USER_SITE`). + +``posix_user`` +^^^^^^^^^^^^^^ + +============== =========================================================== +Path Installation directory +============== =========================================================== +*stdlib* :file:`{userbase}/lib/python{X.Y}` +*platstdlib* :file:`{userbase}/lib/python{X.Y}` +*platlib* :file:`{userbase}/lib/python{X.Y}/site-packages` +*purelib* :file:`{userbase}/lib/python{X.Y}/site-packages` +*include* :file:`{userbase}/include/python{X.Y}` +*scripts* :file:`{userbase}/bin` +*data* :file:`{userbase}` +============== =========================================================== + +``nt_user`` +^^^^^^^^^^^ + +============== =========================================================== +Path Installation directory +============== =========================================================== +*stdlib* :file:`{userbase}\\Python{XY}` +*platstdlib* :file:`{userbase}\\Python{XY}` +*platlib* :file:`{userbase}\\Python{XY}\\site-packages` +*purelib* :file:`{userbase}\\Python{XY}\\site-packages` +*include* :file:`{userbase}\\Python{XY}\\Include` +*scripts* :file:`{userbase}\\Python{XY}\\Scripts` +*data* :file:`{userbase}` +============== =========================================================== + +``osx_framework_user`` +^^^^^^^^^^^^^^^^^^^^^^ + +============== =========================================================== +Path Installation directory +============== =========================================================== +*stdlib* :file:`{userbase}/lib/python` +*platstdlib* :file:`{userbase}/lib/python` +*platlib* :file:`{userbase}/lib/python/site-packages` +*purelib* :file:`{userbase}/lib/python/site-packages` +*include* :file:`{userbase}/include/python{X.Y}` +*scripts* :file:`{userbase}/bin` +*data* :file:`{userbase}` +============== =========================================================== + + +.. _sysconfig-home-scheme: + +Home scheme +----------- + +The idea behind the "home scheme" is that you build and maintain a personal +stash of Python modules. This scheme's name is derived from the idea of a +"home" directory on Unix, since it's not unusual for a Unix user to make their +home directory have a layout similar to :file:`/usr/` or :file:`/usr/local/`. +This scheme can be used by anyone, regardless of the operating system they +are installing for. + +``posix_home`` +^^^^^^^^^^^^^^ + +============== =========================================================== +Path Installation directory +============== =========================================================== +*stdlib* :file:`{home}/lib/python` +*platstdlib* :file:`{home}/lib/python` +*platlib* :file:`{home}/lib/python` +*purelib* :file:`{home}/lib/python` +*include* :file:`{home}/include/python` +*platinclude* :file:`{home}/include/python` +*scripts* :file:`{home}/bin` +*data* :file:`{home}` +============== =========================================================== + + +.. _sysconfig-prefix-scheme: + +Prefix scheme +------------- + +The "prefix scheme" is useful when you wish to use one Python installation to +perform the build/install (i.e., to run the setup script), but install modules +into the third-party module directory of a different Python installation (or +something that looks like a different Python installation). If this sounds a +trifle unusual, it is---that's why the user and home schemes come before. However, +there are at least two known cases where the prefix scheme will be useful. + +First, consider that many Linux distributions put Python in :file:`/usr`, rather +than the more traditional :file:`/usr/local`. This is entirely appropriate, +since in those cases Python is part of "the system" rather than a local add-on. +However, if you are installing Python modules from source, you probably want +them to go in :file:`/usr/local/lib/python2.{X}` rather than +:file:`/usr/lib/python2.{X}`. + +Another possibility is a network filesystem where the name used to write to a +remote directory is different from the name used to read it: for example, the +Python interpreter accessed as :file:`/usr/local/bin/python` might search for +modules in :file:`/usr/local/lib/python2.{X}`, but those modules would have to +be installed to, say, :file:`/mnt/{@server}/export/lib/python2.{X}`. + +``posix_prefix`` +^^^^^^^^^^^^^^^^ + +============== ========================================================== +Path Installation directory +============== ========================================================== +*stdlib* :file:`{prefix}/lib/python{X.Y}` +*platstdlib* :file:`{prefix}/lib/python{X.Y}` +*platlib* :file:`{prefix}/lib/python{X.Y}/site-packages` +*purelib* :file:`{prefix}/lib/python{X.Y}/site-packages` +*include* :file:`{prefix}/include/python{X.Y}` +*platinclude* :file:`{prefix}/include/python{X.Y}` +*scripts* :file:`{prefix}/bin` +*data* :file:`{prefix}` +============== ========================================================== + +``nt`` +^^^^^^ + +============== ========================================================== +Path Installation directory +============== ========================================================== +*stdlib* :file:`{prefix}\\Lib` +*platstdlib* :file:`{prefix}\\Lib` +*platlib* :file:`{prefix}\\Lib\\site-packages` +*purelib* :file:`{prefix}\\Lib\\site-packages` +*include* :file:`{prefix}\\Include` +*platinclude* :file:`{prefix}\\Include` +*scripts* :file:`{prefix}\\Scripts` +*data* :file:`{prefix}` +============== ========================================================== + + +Installation path functions +--------------------------- + +:mod:`sysconfig` provides some functions to determine these installation paths. .. function:: get_scheme_names() diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 921b6a6961c7b2..bade3ca6650e62 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -811,7 +811,7 @@ conflict. Defines the :data:`user base directory `, which is used to compute the path of the :data:`user site-packages directory ` - and installation paths for + and :ref:`installation paths ` for ``python -m pip install --user``. .. seealso:: From 8811f3d7f94fee2d4800e767115d5bbb3ca1d828 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 03:50:52 -0700 Subject: [PATCH 0840/1206] [3.12] Docs: bump Pygments to fix contrast ratios to meet WCAG AA guidelines (GH-110208) (#110210) Docs: bump Pygments to fix contrast ratios to meet WCAG AA guidelines (GH-110208) (cherry picked from commit 9cb8927bfc73b66e7c36ab02ca2a3077172ea0ac) Co-authored-by: Hugo van Kemenade --- Doc/constraints.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/constraints.txt b/Doc/constraints.txt index 54888eaab242ee..147de1271eb2b7 100644 --- a/Doc/constraints.txt +++ b/Doc/constraints.txt @@ -10,8 +10,7 @@ colorama<0.5 imagesize<1.5 Jinja2<3.2 packaging<24 -# Pygments==2.15.0 breaks CI -Pygments<2.16,!=2.15.0 +Pygments>=2.16.1,<3 requests<3 snowballstemmer<3 sphinxcontrib-applehelp<1.1 From f4f919e3d811251f87c5b412b5238702f66879fd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 04:26:30 -0700 Subject: [PATCH 0841/1206] [3.12] GH-109190: Announce final release in What's New in Python 3.12 (GH-110117) (#110215) GH-109190: Announce final release in What's New in Python 3.12 (GH-110117) Prepare What's New in Python 3.12 for final release (cherry picked from commit 6139bf5e0c755ed22bdfb027a5299493f0c71be9) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index caef15f1eb74ce..fad94d6d78616a 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -46,7 +46,7 @@ researching a change. This article explains the new features in Python 3.12, compared to 3.11. -Python 3.12 will be released on October 2, 2023. +Python 3.12 was released on October 2, 2023. For full details, see the :ref:`changelog `. .. seealso:: From 0fb18b02c8ad56299d6a2910be0bab8ad601ef24 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Mon, 2 Oct 2023 13:44:36 +0200 Subject: [PATCH 0842/1206] Python 3.12.0 --- Include/patchlevel.h | 6 +- Lib/pydoc_data/topics.py | 110 +++++++++--------- Misc/NEWS.d/3.12.0.rst | 74 ++++++++++++ ...-09-20-23-04-15.gh-issue-109627.xxe7De.rst | 2 - ...-09-22-13-38-17.gh-issue-109719.fx5OTz.rst | 1 - ...-09-25-14-28-14.gh-issue-109823.kbVTKF.rst | 2 - ...-09-10-02-39-06.gh-issue-109209.0LBewo.rst | 1 - ...-09-28-18-08-02.gh-issue-110045.0YIGKv.rst | 2 - ...-09-27-23-31-54.gh-issue-109991.sUUYY8.rst | 2 - ...-09-28-17-09-23.gh-issue-109991.CIMftz.rst | 1 - ...-09-27-22-35-22.gh-issue-109991.-xJzaF.rst | 1 - README.rst | 4 +- 12 files changed, 134 insertions(+), 72 deletions(-) create mode 100644 Misc/NEWS.d/3.12.0.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst delete mode 100644 Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst delete mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst delete mode 100644 Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst delete mode 100644 Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index d962d241673e9c..bb4598641c259d 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -19,11 +19,11 @@ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 3 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.12.0rc3+" +#define PY_VERSION "3.12.0" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index ca92aed373e4da..28a5e06df9bfb2 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Mon Sep 18 21:47:37 2023 +# Autogenerated by Sphinx on Mon Oct 2 13:45:14 2023 # as part of the release process. topics = {'assert': 'The "assert" statement\n' '**********************\n' @@ -13016,71 +13016,71 @@ 'those\n' 'used by Standard C. The recognized escape sequences are:\n' '\n' - '+-------------------+-----------------------------------+---------+\n' - '| Escape Sequence | Meaning | Notes ' - '|\n' - '|===================|===================================|=========|\n' - '| "\\" | Backslash and newline ignored | ' - '(1) |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\\\" | Backslash ("\\") ' + '+---------------------------+-----------------------------------+---------+\n' + '| Escape Sequence | Meaning | ' + 'Notes |\n' + '|===========================|===================================|=========|\n' + '| "\\" | Backslash and newline ignored ' + '| (1) |\n' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\\\" | Backslash ' + '("\\") | |\n' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\\'" | Single quote ' + '("\'") | |\n' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\"" | Double quote (""") ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\\'" | Single quote ("\'") ' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\a" | ASCII Bell (BEL) ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\"" | Double quote (""") ' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\b" | ASCII Backspace (BS) ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\a" | ASCII Bell (BEL) ' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\f" | ASCII Formfeed (FF) ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\b" | ASCII Backspace (BS) ' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\n" | ASCII Linefeed (LF) ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\f" | ASCII Formfeed (FF) ' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\r" | ASCII Carriage Return (CR) ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\n" | ASCII Linefeed (LF) ' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\t" | ASCII Horizontal Tab (TAB) ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\r" | ASCII Carriage Return (CR) ' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\v" | ASCII Vertical Tab (VT) ' '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\t" | ASCII Horizontal Tab (TAB) ' - '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\v" | ASCII Vertical Tab (VT) ' - '| |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\ooo" | Character with octal value *ooo* | ' - '(2,4) |\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\xhh" | Character with hex value *hh* | ' - '(3,4) |\n' - '+-------------------+-----------------------------------+---------+\n' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\*ooo*" | Character with octal value *ooo* ' + '| (2,4) |\n' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\x*hh*" | Character with hex value *hh* ' + '| (3,4) |\n' + '+---------------------------+-----------------------------------+---------+\n' '\n' 'Escape sequences only recognized in string literals are:\n' '\n' - '+-------------------+-----------------------------------+---------+\n' - '| Escape Sequence | Meaning | Notes ' - '|\n' - '|===================|===================================|=========|\n' - '| "\\N{name}" | Character named *name* in the | ' - '(5) |\n' - '| | Unicode database | ' - '|\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\uxxxx" | Character with 16-bit hex value | ' - '(6) |\n' - '| | *xxxx* | ' - '|\n' - '+-------------------+-----------------------------------+---------+\n' - '| "\\Uxxxxxxxx" | Character with 32-bit hex value | ' - '(7) |\n' - '| | *xxxxxxxx* | ' - '|\n' - '+-------------------+-----------------------------------+---------+\n' + '+---------------------------+-----------------------------------+---------+\n' + '| Escape Sequence | Meaning | ' + 'Notes |\n' + '|===========================|===================================|=========|\n' + '| "\\N{*name*}" | Character named *name* in the ' + '| (5) |\n' + '| | Unicode database ' + '| |\n' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\u*xxxx*" | Character with 16-bit hex value ' + '| (6) |\n' + '| | *xxxx* ' + '| |\n' + '+---------------------------+-----------------------------------+---------+\n' + '| "\\U*xxxxxxxx*" | Character with 32-bit hex value ' + '| (7) |\n' + '| | *xxxxxxxx* ' + '| |\n' + '+---------------------------+-----------------------------------+---------+\n' '\n' 'Notes:\n' '\n' diff --git a/Misc/NEWS.d/3.12.0.rst b/Misc/NEWS.d/3.12.0.rst new file mode 100644 index 00000000000000..70af59057730f4 --- /dev/null +++ b/Misc/NEWS.d/3.12.0.rst @@ -0,0 +1,74 @@ +.. date: 2023-09-25-14-28-14 +.. gh-issue: 109823 +.. nonce: kbVTKF +.. release date: 2023-10-02 +.. section: Core and Builtins + +Fix bug where compiler does not adjust labels when removing an empty basic +block which is a jump target. + +.. + +.. date: 2023-09-22-13-38-17 +.. gh-issue: 109719 +.. nonce: fx5OTz +.. section: Core and Builtins + +Fix missing jump target labels when compiler reorders cold/warm blocks. + +.. + +.. date: 2023-09-20-23-04-15 +.. gh-issue: 109627 +.. nonce: xxe7De +.. section: Core and Builtins + +Fix bug where the compiler does not assign a new jump target label to a +duplicated small exit block. + +.. + +.. date: 2023-09-28-18-08-02 +.. gh-issue: 110045 +.. nonce: 0YIGKv +.. section: Library + +Update the :mod:`symtable` module to support the new scopes introduced by +:pep:`695`. + +.. + +.. date: 2023-09-10-02-39-06 +.. gh-issue: 109209 +.. nonce: 0LBewo +.. section: Documentation + +The minimum Sphinx version required for the documentation is now 4.2. + +.. + +.. date: 2023-09-28-17-09-23 +.. gh-issue: 109991 +.. nonce: CIMftz +.. section: Windows + +Update Windows build to use OpenSSL 3.0.11. + +.. + +.. date: 2023-09-27-22-35-22 +.. gh-issue: 109991 +.. nonce: -xJzaF +.. section: macOS + +Update macOS installer to use OpenSSL 3.0.11. + +.. + +.. date: 2023-09-27-23-31-54 +.. gh-issue: 109991 +.. nonce: sUUYY8 +.. section: Tools/Demos + +Update GitHub CI workflows to use OpenSSL 3.0.11 and multissltests to use +1.1.1w, 3.0.11, and 3.1.3. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst deleted file mode 100644 index 397d76e291419f..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where the compiler does not assign a new jump target label to a -duplicated small exit block. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst deleted file mode 100644 index 83be54c9ca793e..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-22-13-38-17.gh-issue-109719.fx5OTz.rst +++ /dev/null @@ -1 +0,0 @@ -Fix missing jump target labels when compiler reorders cold/warm blocks. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst deleted file mode 100644 index 793c89f4445f54..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-09-25-14-28-14.gh-issue-109823.kbVTKF.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix bug where compiler does not adjust labels when removing an empty basic -block which is a jump target. diff --git a/Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst b/Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst deleted file mode 100644 index 79cc0b72ec742f..00000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-09-10-02-39-06.gh-issue-109209.0LBewo.rst +++ /dev/null @@ -1 +0,0 @@ -The minimum Sphinx version required for the documentation is now 4.2. diff --git a/Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst b/Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst deleted file mode 100644 index 44a6df1083762f..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-09-28-18-08-02.gh-issue-110045.0YIGKv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update the :mod:`symtable` module to support the new scopes introduced by -:pep:`695`. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst b/Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst deleted file mode 100644 index 13c1163ab53443..00000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-09-27-23-31-54.gh-issue-109991.sUUYY8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update GitHub CI workflows to use OpenSSL 3.0.11 and multissltests to use -1.1.1w, 3.0.11, and 3.1.3. diff --git a/Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst b/Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst deleted file mode 100644 index ee988f90863426..00000000000000 --- a/Misc/NEWS.d/next/Windows/2023-09-28-17-09-23.gh-issue-109991.CIMftz.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows build to use OpenSSL 3.0.11. diff --git a/Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst b/Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst deleted file mode 100644 index 8d369988274f28..00000000000000 --- a/Misc/NEWS.d/next/macOS/2023-09-27-22-35-22.gh-issue-109991.-xJzaF.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to use OpenSSL 3.0.11. diff --git a/README.rst b/README.rst index 5390d2a6cf702f..979ca01896a6db 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -This is Python version 3.12.0 release candidate 3 -================================================= +This is Python version 3.12.0 +============================= .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg :alt: CPython build status on GitHub Actions From 62d9ae414f1a9f8335c04e8c73571527eabc5085 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:09:35 -0700 Subject: [PATCH 0843/1206] [3.12] gh-109496: Skip test_capi.test_decref_freed_object() on ASAN (GH-109573) (#109578) Co-authored-by: Victor Stinner --- Lib/test/test_capi/test_misc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 575635584fb556..66d5ebed66d670 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -325,6 +325,8 @@ def test_negative_refcount(self): @unittest.skipUnless(hasattr(_testcapi, 'decref_freed_object'), 'need _testcapi.decref_freed_object()') + @support.skip_if_sanitizer("use after free on purpose", + address=True, memory=True, ub=True) def test_decref_freed_object(self): code = """ import _testcapi From 531d2df28031a2e1590ef7a0ea5de3b86d9183ec Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Mon, 2 Oct 2023 16:41:41 +0200 Subject: [PATCH 0844/1206] Post 3.12.0 --- Include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h index bb4598641c259d..c8440667d81265 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.12.0" +#define PY_VERSION "3.12.0+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From 9207c870bec173dafd3f2e6c811482c782db034f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:54:16 -0700 Subject: [PATCH 0845/1206] [3.12] gh-88943: Improve syntax error for non-ASCII character that follows a numerical literal (GH-109081) (#109090) gh-88943: Improve syntax error for non-ASCII character that follows a numerical literal (GH-109081) It now points on the invalid non-ASCII character, not on the valid numerical literal. (cherry picked from commit b2729e93e9d73503b1fda4ea4fecd77c58909091) Co-authored-by: Serhiy Storchaka --- Lib/test/test_grammar.py | 4 ++++ .../2023-09-07-16-05-36.gh-issue-88943.rH_X3W.rst | 3 +++ Parser/tokenizer.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-07-16-05-36.gh-issue-88943.rH_X3W.rst diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index b2415d579145f5..ad9f6c764319a9 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -236,6 +236,10 @@ def check(test, error=False): check(f"[{num}for x in ()]") check(f"{num}spam", error=True) + # gh-88943: Invalid non-ASCII character following a numerical literal. + with self.assertRaisesRegex(SyntaxError, r"invalid character 'â„' \(U\+2044\)"): + compile(f"{num}â„7", "", "eval") + with self.assertWarnsRegex(SyntaxWarning, r'invalid \w+ literal'): compile(f"{num}is x", "", "eval") with warnings.catch_warnings(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-07-16-05-36.gh-issue-88943.rH_X3W.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-16-05-36.gh-issue-88943.rH_X3W.rst new file mode 100644 index 00000000000000..a99830fe4227c9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-16-05-36.gh-issue-88943.rH_X3W.rst @@ -0,0 +1,3 @@ +Improve syntax error for non-ASCII character that follows a numerical +literal. It now points on the invalid non-ASCII character, not on the valid +numerical literal. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index c4c345e4c358e5..9911fa55d47c9f 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1648,7 +1648,7 @@ verify_end_of_number(struct tok_state *tok, int c, const char *kind) { tok_nextc(tok); } else /* In future releases, only error will remain. */ - if (is_potential_identifier_char(c)) { + if (c < 128 && is_potential_identifier_char(c)) { tok_backup(tok, c); syntaxerror(tok, "invalid %s literal", kind); return 0; From 30748d36b33fe08be98c8be4e629418584c796b0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 16:55:06 +0200 Subject: [PATCH 0846/1206] [3.12] gh-104690: thread_run() checks for tstate dangling pointer (#109056) (#109133) gh-104690: thread_run() checks for tstate dangling pointer (#109056) thread_run() of _threadmodule.c now calls _PyThreadState_CheckConsistency() to check if tstate is a dangling pointer when Python is built in debug mode. Rename ceval_gil.c is_tstate_valid() to _PyThreadState_CheckConsistency() to reuse it in _threadmodule.c. (cherry picked from commit f63d37877ad166041489a968233b57540f8456e8) --- Include/internal/pycore_pystate.h | 4 ++++ Modules/_threadmodule.c | 7 +++++-- Python/ceval_gil.c | 26 ++++++++------------------ Python/pystate.c | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index ccfc2586f0f235..218c3978e64dce 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -68,6 +68,10 @@ extern _Py_thread_local PyThreadState *_Py_tss_tstate; #endif PyAPI_DATA(PyThreadState *) _PyThreadState_GetCurrent(void); +#ifndef NDEBUG +extern int _PyThreadState_CheckConsistency(PyThreadState *tstate); +#endif + /* Get the current Python thread state. This function is unsafe: it does not check for error and it can return NULL. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 04f4400a9315ba..4514dfd3fc85eb 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1072,9 +1072,12 @@ static void thread_run(void *boot_raw) { struct bootstate *boot = (struct bootstate *) boot_raw; - PyThreadState *tstate; + PyThreadState *tstate = boot->tstate; + + // gh-104690: If Python is being finalized and PyInterpreterState_Delete() + // was called, tstate becomes a dangling pointer. + assert(_PyThreadState_CheckConsistency(tstate)); - tstate = boot->tstate; _PyThreadState_Bind(tstate); PyEval_AcquireThread(tstate); tstate->interp->threads.count++; diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index aacf2b5c2e2c4f..b44cb0b9b6e09d 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -162,16 +162,6 @@ UNSIGNAL_ASYNC_EXC(PyInterpreterState *interp) COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } -#ifndef NDEBUG -/* Ensure that tstate is valid */ -static int -is_tstate_valid(PyThreadState *tstate) -{ - assert(!_PyMem_IsPtrFreed(tstate)); - assert(!_PyMem_IsPtrFreed(tstate->interp)); - return 1; -} -#endif /* * Implementation of the Global Interpreter Lock (GIL). @@ -324,7 +314,7 @@ drop_gil(struct _ceval_state *ceval, PyThreadState *tstate) /* Not switched yet => wait */ if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate) { - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); RESET_GIL_DROP_REQUEST(tstate->interp); /* NOTE: if COND_WAIT does not atomically start waiting when releasing the mutex, another thread can run through, take @@ -385,7 +375,7 @@ take_gil(PyThreadState *tstate) PyThread_exit_thread(); } - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); PyInterpreterState *interp = tstate->interp; struct _ceval_state *ceval = &interp->ceval; struct _gil_runtime_state *gil = ceval->gil; @@ -426,7 +416,7 @@ take_gil(PyThreadState *tstate) } PyThread_exit_thread(); } - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); SET_GIL_DROP_REQUEST(interp); drop_requested = 1; @@ -465,7 +455,7 @@ take_gil(PyThreadState *tstate) drop_gil(ceval, tstate); PyThread_exit_thread(); } - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) { RESET_GIL_DROP_REQUEST(interp); @@ -673,7 +663,7 @@ PyEval_AcquireThread(PyThreadState *tstate) void PyEval_ReleaseThread(PyThreadState *tstate) { - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); PyThreadState *new_tstate = _PyThreadState_SwapNoGIL(NULL); if (new_tstate != tstate) { @@ -871,7 +861,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg) static int handle_signals(PyThreadState *tstate) { - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); if (!_Py_ThreadCanHandleSignals(tstate->interp)) { return 0; } @@ -977,7 +967,7 @@ void _Py_FinishPendingCalls(PyThreadState *tstate) { assert(PyGILState_Check()); - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); if (make_pending_calls(tstate->interp) < 0) { PyObject *exc = _PyErr_GetRaisedException(tstate); @@ -1018,7 +1008,7 @@ Py_MakePendingCalls(void) assert(PyGILState_Check()); PyThreadState *tstate = _PyThreadState_GET(); - assert(is_tstate_valid(tstate)); + assert(_PyThreadState_CheckConsistency(tstate)); /* Only execute pending calls on the main thread. */ if (!_Py_IsMainThread() || !_Py_IsMainInterpreter(tstate->interp)) { diff --git a/Python/pystate.c b/Python/pystate.c index 2ee16e3de25da3..1fe88fdf5a8218 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2848,6 +2848,24 @@ _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame * frame) } +#ifndef NDEBUG +// Check that a Python thread state valid. In practice, this function is used +// on a Python debug build to check if 'tstate' is a dangling pointer, if the +// PyThreadState memory has been freed. +// +// Usage: +// +// assert(_PyThreadState_CheckConsistency(tstate)); +int +_PyThreadState_CheckConsistency(PyThreadState *tstate) +{ + assert(!_PyMem_IsPtrFreed(tstate)); + assert(!_PyMem_IsPtrFreed(tstate->interp)); + return 1; +} +#endif + + #ifdef __cplusplus } #endif From 1c223ae58db4338c3376d3d8a832671b16057799 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:55:24 -0700 Subject: [PATCH 0847/1206] [3.12] Check the result of PySet_Contains() for error in Python/symtable.c (GH-109146) (#109153) Check the result of PySet_Contains() for error in Python/symtable.c (GH-109146) (cherry picked from commit 87a7faf6b68c8076e640a9a1347a255f132d8382) Co-authored-by: Serhiy Storchaka --- Python/symtable.c | 72 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c index 4989e03d4bf591..865181273663c2 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -523,6 +523,7 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, PyObject *bound, PyObject *local, PyObject *free, PyObject *global, PyObject *type_params, PySTEntryObject *class_entry) { + int contains; if (flags & DEF_GLOBAL) { if (flags & DEF_NONLOCAL) { PyErr_Format(PyExc_SyntaxError, @@ -543,14 +544,22 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, "nonlocal declaration not allowed at module level"); return error_at_directive(ste, name); } - if (!PySet_Contains(bound, name)) { + contains = PySet_Contains(bound, name); + if (contains < 0) { + return 0; + } + if (!contains) { PyErr_Format(PyExc_SyntaxError, "no binding for nonlocal '%U' found", name); return error_at_directive(ste, name); } - if (PySet_Contains(type_params, name)) { + contains = PySet_Contains(type_params, name); + if (contains < 0) { + return 0; + } + if (contains) { PyErr_Format(PyExc_SyntaxError, "nonlocal binding not allowed for type parameter '%U'", name); @@ -599,17 +608,29 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, Note that having a non-NULL bound implies that the block is nested. */ - if (bound && PySet_Contains(bound, name)) { - SET_SCOPE(scopes, name, FREE); - ste->ste_free = 1; - return PySet_Add(free, name) >= 0; + if (bound) { + contains = PySet_Contains(bound, name); + if (contains < 0) { + return 0; + } + if (contains) { + SET_SCOPE(scopes, name, FREE); + ste->ste_free = 1; + return PySet_Add(free, name) >= 0; + } } /* If a parent has a global statement, then call it global explicit? It could also be global implicit. */ - if (global && PySet_Contains(global, name)) { - SET_SCOPE(scopes, name, GLOBAL_IMPLICIT); - return 1; + if (global) { + contains = PySet_Contains(global, name); + if (contains < 0) { + return 0; + } + if (contains) { + SET_SCOPE(scopes, name, GLOBAL_IMPLICIT); + return 1; + } } if (ste->ste_nested) ste->ste_free = 1; @@ -712,8 +733,19 @@ analyze_cells(PyObject *scopes, PyObject *free, PyObject *inlined_cells) scope = PyLong_AS_LONG(v); if (scope != LOCAL) continue; - if (!PySet_Contains(free, name) && !PySet_Contains(inlined_cells, name)) - continue; + int contains = PySet_Contains(free, name); + if (contains < 0) { + goto error; + } + if (!contains) { + contains = PySet_Contains(inlined_cells, name); + if (contains < 0) { + goto error; + } + if (!contains) { + continue; + } + } /* Replace LOCAL with CELL for this name, and remove from free. It is safe to replace the value of name in the dict, because it will not cause a resize. @@ -764,7 +796,11 @@ update_symbols(PyObject *symbols, PyObject *scopes, long scope, flags; assert(PyLong_Check(v)); flags = PyLong_AS_LONG(v); - if (PySet_Contains(inlined_cells, name)) { + int contains = PySet_Contains(inlined_cells, name); + if (contains < 0) { + return 0; + } + if (contains) { flags |= DEF_COMP_CELL; } v_scope = PyDict_GetItemWithError(scopes, name); @@ -821,9 +857,15 @@ update_symbols(PyObject *symbols, PyObject *scopes, goto error; } /* Handle global symbol */ - if (bound && !PySet_Contains(bound, name)) { - Py_DECREF(name); - continue; /* it's a global */ + if (bound) { + int contains = PySet_Contains(bound, name); + if (contains < 0) { + goto error; + } + if (!contains) { + Py_DECREF(name); + continue; /* it's a global */ + } } /* Propagate new free symbol up the lexical stack */ if (PyDict_SetItem(symbols, name, v_free) < 0) { From be8255ad8c3af2ccd452cfdfae10bd72e966cb25 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:55:41 -0700 Subject: [PATCH 0848/1206] [3.12] gh-109207: Fix SystemError when printing symtable entry object. (GH-109225) (#109227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-109207: Fix SystemError when printing symtable entry object. (GH-109225) (cherry picked from commit 429749969621b149c1a7c3c004bd44f52bec8f44) Co-authored-by: 云line <31395137+yunline@users.noreply.github.com> --- Lib/test/test_symtable.py | 4 ++++ .../2023-09-10-18-53-55.gh-issue-109207.Fei8bY.rst | 1 + Python/symtable.c | 5 ++--- 3 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-10-18-53-55.gh-issue-109207.Fei8bY.rst diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index 61fda767e3ecd0..82c1d7c856a1e5 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -282,6 +282,10 @@ def test_symtable_repr(self): self.assertEqual(str(self.top), "") self.assertEqual(str(self.spam), "") + def test_symtable_entry_repr(self): + expected = f"" + self.assertEqual(repr(self.top._table), expected) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-10-18-53-55.gh-issue-109207.Fei8bY.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-10-18-53-55.gh-issue-109207.Fei8bY.rst new file mode 100644 index 00000000000000..f9da3ac4d1abbd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-10-18-53-55.gh-issue-109207.Fei8bY.rst @@ -0,0 +1 @@ +Fix a SystemError in ``__repr__`` of symtable entry object. diff --git a/Python/symtable.c b/Python/symtable.c index 865181273663c2..70b6eacd4ac071 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -150,9 +150,8 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block, static PyObject * ste_repr(PySTEntryObject *ste) { - return PyUnicode_FromFormat("", - ste->ste_name, - PyLong_AS_LONG(ste->ste_id), ste->ste_lineno); + return PyUnicode_FromFormat("", + ste->ste_name, ste->ste_id, ste->ste_lineno); } static void From 3e1c9e8264ad9acfef60b3aa9b3aa59bee5becca Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:55:52 -0700 Subject: [PATCH 0849/1206] [3.12] gh-50644: Forbid pickling of codecs streams (GH-109180) (#109231) gh-50644: Forbid pickling of codecs streams (GH-109180) Attempts to pickle or create a shallow or deep copy of codecs streams now raise a TypeError. Previously, copying failed with a RecursionError, while pickling produced wrong results that eventually caused unpickling to fail with a RecursionError. (cherry picked from commit d6892c2b9263b39ea1c7905667942914b6a24b2c) Co-authored-by: Serhiy Storchaka --- Lib/codecs.py | 12 +++ Lib/test/test_codecs.py | 79 +++++++++++++++++++ ...3-09-09-15-08-37.gh-issue-50644.JUAZOh.rst | 4 + 3 files changed, 95 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-09-09-15-08-37.gh-issue-50644.JUAZOh.rst diff --git a/Lib/codecs.py b/Lib/codecs.py index c1c55d8afef389..82f23983e719c2 100644 --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -414,6 +414,9 @@ def __enter__(self): def __exit__(self, type, value, tb): self.stream.close() + def __reduce_ex__(self, proto): + raise TypeError("can't serialize %s" % self.__class__.__name__) + ### class StreamReader(Codec): @@ -663,6 +666,9 @@ def __enter__(self): def __exit__(self, type, value, tb): self.stream.close() + def __reduce_ex__(self, proto): + raise TypeError("can't serialize %s" % self.__class__.__name__) + ### class StreamReaderWriter: @@ -750,6 +756,9 @@ def __enter__(self): def __exit__(self, type, value, tb): self.stream.close() + def __reduce_ex__(self, proto): + raise TypeError("can't serialize %s" % self.__class__.__name__) + ### class StreamRecoder: @@ -866,6 +875,9 @@ def __enter__(self): def __exit__(self, type, value, tb): self.stream.close() + def __reduce_ex__(self, proto): + raise TypeError("can't serialize %s" % self.__class__.__name__) + ### Shortcuts def open(filename, mode='r', encoding=None, errors='strict', buffering=-1): diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 91d7eaf997ae20..b5e9271ac0c3cd 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -1,7 +1,9 @@ import codecs import contextlib +import copy import io import locale +import pickle import sys import unittest import encodings @@ -1771,6 +1773,61 @@ def test_readlines(self): f = self.reader(self.stream) self.assertEqual(f.readlines(), ['\ud55c\n', '\uae00']) + def test_copy(self): + f = self.reader(Queue(b'\xed\x95\x9c\n\xea\xb8\x80')) + with self.assertRaisesRegex(TypeError, 'StreamReader'): + copy.copy(f) + with self.assertRaisesRegex(TypeError, 'StreamReader'): + copy.deepcopy(f) + + def test_pickle(self): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=proto): + f = self.reader(Queue(b'\xed\x95\x9c\n\xea\xb8\x80')) + with self.assertRaisesRegex(TypeError, 'StreamReader'): + pickle.dumps(f, proto) + + +class StreamWriterTest(unittest.TestCase): + + def setUp(self): + self.writer = codecs.getwriter('utf-8') + + def test_copy(self): + f = self.writer(Queue(b'')) + with self.assertRaisesRegex(TypeError, 'StreamWriter'): + copy.copy(f) + with self.assertRaisesRegex(TypeError, 'StreamWriter'): + copy.deepcopy(f) + + def test_pickle(self): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=proto): + f = self.writer(Queue(b'')) + with self.assertRaisesRegex(TypeError, 'StreamWriter'): + pickle.dumps(f, proto) + + +class StreamReaderWriterTest(unittest.TestCase): + + def setUp(self): + self.reader = codecs.getreader('latin1') + self.writer = codecs.getwriter('utf-8') + + def test_copy(self): + f = codecs.StreamReaderWriter(Queue(b''), self.reader, self.writer) + with self.assertRaisesRegex(TypeError, 'StreamReaderWriter'): + copy.copy(f) + with self.assertRaisesRegex(TypeError, 'StreamReaderWriter'): + copy.deepcopy(f) + + def test_pickle(self): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=proto): + f = codecs.StreamReaderWriter(Queue(b''), self.reader, self.writer) + with self.assertRaisesRegex(TypeError, 'StreamReaderWriter'): + pickle.dumps(f, proto) + class EncodedFileTest(unittest.TestCase): @@ -3346,6 +3403,28 @@ def test_seeking_write(self): self.assertEqual(sr.readline(), b'abc\n') self.assertEqual(sr.readline(), b'789\n') + def test_copy(self): + bio = io.BytesIO() + codec = codecs.lookup('ascii') + sr = codecs.StreamRecoder(bio, codec.encode, codec.decode, + encodings.ascii.StreamReader, encodings.ascii.StreamWriter) + + with self.assertRaisesRegex(TypeError, 'StreamRecoder'): + copy.copy(sr) + with self.assertRaisesRegex(TypeError, 'StreamRecoder'): + copy.deepcopy(sr) + + def test_pickle(self): + q = Queue(b'') + codec = codecs.lookup('ascii') + sr = codecs.StreamRecoder(q, codec.encode, codec.decode, + encodings.ascii.StreamReader, encodings.ascii.StreamWriter) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(protocol=proto): + with self.assertRaisesRegex(TypeError, 'StreamRecoder'): + pickle.dumps(sr, proto) + @unittest.skipIf(_testinternalcapi is None, 'need _testinternalcapi module') class LocaleCodecTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-09-09-15-08-37.gh-issue-50644.JUAZOh.rst b/Misc/NEWS.d/next/Library/2023-09-09-15-08-37.gh-issue-50644.JUAZOh.rst new file mode 100644 index 00000000000000..a7a442e35289d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-09-15-08-37.gh-issue-50644.JUAZOh.rst @@ -0,0 +1,4 @@ +Attempts to pickle or create a shallow or deep copy of :mod:`codecs` streams +now raise a TypeError. Previously, copying failed with a RecursionError, +while pickling produced wrong results that eventually caused unpickling +to fail with a RecursionError. From 1d8c18c39df9ab2a66151041aedb41e450779d96 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:56:09 -0700 Subject: [PATCH 0850/1206] [3.12] gh-107219: Fix concurrent.futures terminate_broken() (GH-109244) (#109254) gh-107219: Fix concurrent.futures terminate_broken() (GH-109244) Fix a race condition in concurrent.futures. When a process in the process pool was terminated abruptly (while the future was running or pending), close the connection write end. If the call queue is blocked on sending bytes to a worker process, closing the connection write end interrupts the send, so the queue can be closed. Changes: * _ExecutorManagerThread.terminate_broken() now closes call_queue._writer. * multiprocessing PipeConnection.close() now interrupts WaitForMultipleObjects() in _send_bytes() by cancelling the overlapped operation. (cherry picked from commit a9b1f84790e977fb09f75b148c4c4f5924a6ef99) Co-authored-by: Victor Stinner --- Lib/concurrent/futures/process.py | 4 ++++ Lib/multiprocessing/connection.py | 18 ++++++++++++++++++ ...3-09-11-00-32-18.gh-issue-107219.3zqyFT.rst | 5 +++++ 3 files changed, 27 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-09-11-00-32-18.gh-issue-107219.3zqyFT.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 301207f59de37a..a8dab1302aabb1 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -503,6 +503,10 @@ def terminate_broken(self, cause): # https://github.com/python/cpython/issues/94777 self.call_queue._reader.close() + # gh-107219: Close the connection writer which can unblock + # Queue._feed() if it was stuck in send_bytes(). + self.call_queue._writer.close() + # clean up resources self.join_executor_internals() diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 04eaea811cfbbe..7c425a2d8e7034 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -9,6 +9,7 @@ __all__ = [ 'Client', 'Listener', 'Pipe', 'wait' ] +import errno import io import os import sys @@ -41,6 +42,7 @@ BUFSIZE = 8192 # A very generous timeout when it comes to local connections... CONNECTION_TIMEOUT = 20. +WSA_OPERATION_ABORTED = 995 _mmap_counter = itertools.count() @@ -271,12 +273,22 @@ class PipeConnection(_ConnectionBase): with FILE_FLAG_OVERLAPPED. """ _got_empty_message = False + _send_ov = None def _close(self, _CloseHandle=_winapi.CloseHandle): + ov = self._send_ov + if ov is not None: + # Interrupt WaitForMultipleObjects() in _send_bytes() + ov.cancel() _CloseHandle(self._handle) def _send_bytes(self, buf): + if self._send_ov is not None: + # A connection should only be used by a single thread + raise ValueError("concurrent send_bytes() calls " + "are not supported") ov, err = _winapi.WriteFile(self._handle, buf, overlapped=True) + self._send_ov = ov try: if err == _winapi.ERROR_IO_PENDING: waitres = _winapi.WaitForMultipleObjects( @@ -286,7 +298,13 @@ def _send_bytes(self, buf): ov.cancel() raise finally: + self._send_ov = None nwritten, err = ov.GetOverlappedResult(True) + if err == WSA_OPERATION_ABORTED: + # close() was called by another thread while + # WaitForMultipleObjects() was waiting for the overlapped + # operation. + raise OSError(errno.EPIPE, "handle is closed") assert err == 0 assert nwritten == len(buf) diff --git a/Misc/NEWS.d/next/Library/2023-09-11-00-32-18.gh-issue-107219.3zqyFT.rst b/Misc/NEWS.d/next/Library/2023-09-11-00-32-18.gh-issue-107219.3zqyFT.rst new file mode 100644 index 00000000000000..10afbcf823386a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-11-00-32-18.gh-issue-107219.3zqyFT.rst @@ -0,0 +1,5 @@ +Fix a race condition in ``concurrent.futures``. When a process in the +process pool was terminated abruptly (while the future was running or +pending), close the connection write end. If the call queue is blocked on +sending bytes to a worker process, closing the connection write end interrupts +the send, so the queue can be closed. Patch by Victor Stinner. From a8431123c23c248e36ecb5d2c01ba3f8b5197360 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 2 Oct 2023 15:56:34 +0100 Subject: [PATCH 0851/1206] [3.12] gh-109179: Fix traceback display for SyntaxErrors with notes (#109197) (#109280) (cherry picked from commit ecd21a629a2a30bcae89902f7cad5670e9441e2c) --- Lib/test/test_traceback.py | 43 ++++++++++--------- ...-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst | 1 + Python/pythonrun.c | 24 +++++------ 3 files changed, 34 insertions(+), 34 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index e84e8fecdf1b50..b9b0463f1700a5 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1599,27 +1599,28 @@ def __repr__(self): err_msg = "b'please do not show me as numbers'" self.assertEqual(self.get_report(e), vanilla + err_msg + '\n') - def test_exception_with_note_with_multiple_notes(self): - e = ValueError(42) - vanilla = self.get_report(e) - - e.add_note('Note 1') - e.add_note('Note 2') - e.add_note('Note 3') - - self.assertEqual( - self.get_report(e), - vanilla + 'Note 1\n' + 'Note 2\n' + 'Note 3\n') - - del e.__notes__ - e.add_note('Note 4') - del e.__notes__ - e.add_note('Note 5') - e.add_note('Note 6') - - self.assertEqual( - self.get_report(e), - vanilla + 'Note 5\n' + 'Note 6\n') + def test_exception_with_multiple_notes(self): + for e in [ValueError(42), SyntaxError('bad syntax')]: + with self.subTest(e=e): + vanilla = self.get_report(e) + + e.add_note('Note 1') + e.add_note('Note 2') + e.add_note('Note 3') + + self.assertEqual( + self.get_report(e), + vanilla + 'Note 1\n' + 'Note 2\n' + 'Note 3\n') + + del e.__notes__ + e.add_note('Note 4') + del e.__notes__ + e.add_note('Note 5') + e.add_note('Note 6') + + self.assertEqual( + self.get_report(e), + vanilla + 'Note 5\n' + 'Note 6\n') def test_exception_qualname(self): class A: diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst new file mode 100644 index 00000000000000..dd95a8ec7920aa --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-09-21-17-18.gh-issue-109179.ZR8qs2.rst @@ -0,0 +1 @@ +Fix bug where the C traceback display drops notes from :exc:`SyntaxError`. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 99e2eec453ee4b..f4c5d39c59b166 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1092,21 +1092,16 @@ print_exception_suggestions(struct exception_print_context *ctx, } static int -print_exception_notes(struct exception_print_context *ctx, PyObject *value) +print_exception_notes(struct exception_print_context *ctx, PyObject *notes) { PyObject *f = ctx->file; - if (!PyExceptionInstance_Check(value)) { + if (notes == NULL) { return 0; } - PyObject *notes; - int res = _PyObject_LookupAttr(value, &_Py_ID(__notes__), ¬es); - if (res <= 0) { - return res; - } if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) { - res = 0; + int res = 0; if (write_indented_margin(ctx, f) < 0) { res = -1; } @@ -1119,7 +1114,6 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value) res = PyFile_WriteObject(s, f, Py_PRINT_RAW); Py_DECREF(s); } - Py_DECREF(notes); if (PyFile_WriteString("\n", f) < 0) { res = -1; } @@ -1164,17 +1158,16 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value) } } - Py_DECREF(notes); return 0; error: Py_XDECREF(lines); - Py_DECREF(notes); return -1; } static int print_exception(struct exception_print_context *ctx, PyObject *value) { + PyObject *notes = NULL; PyObject *f = ctx->file; if (!PyExceptionInstance_Check(value)) { @@ -1188,8 +1181,11 @@ print_exception(struct exception_print_context *ctx, PyObject *value) goto error; } - /* grab the type now because value can change below */ + /* grab the type and notes now because value can change below */ PyObject *type = (PyObject *) Py_TYPE(value); + if (_PyObject_LookupAttr(value, &_Py_ID(__notes__), ¬es) < 0) { + goto error; + } if (print_exception_file_and_line(ctx, &value) < 0) { goto error; @@ -1203,14 +1199,16 @@ print_exception(struct exception_print_context *ctx, PyObject *value) if (PyFile_WriteString("\n", f) < 0) { goto error; } - if (print_exception_notes(ctx, value) < 0) { + if (print_exception_notes(ctx, notes) < 0) { goto error; } + Py_XDECREF(notes); Py_DECREF(value); assert(!PyErr_Occurred()); return 0; error: + Py_XDECREF(notes); Py_DECREF(value); return -1; } From 2fb39f73ed0b96c0097106226d44f27472be630c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:57:44 -0700 Subject: [PATCH 0852/1206] [3.12] gh-84867: Do not load tests from TestCase and FunctionTestCase (GH-100497) (#109327) gh-84867: Do not load tests from TestCase and FunctionTestCase (GH-100497) (cherry picked from commit 66d1d7eb067d445f1ade151f4a6db3864dd9109f) Co-authored-by: Nikita Sobolev --- Lib/test/test_unittest/test_loader.py | 29 +++++++++++++++++++ Lib/unittest/loader.py | 22 ++++++++++---- ...2-12-24-12-50-54.gh-issue-84867.OhaLbU.rst | 2 ++ 3 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-12-24-12-50-54.gh-issue-84867.OhaLbU.rst diff --git a/Lib/test/test_unittest/test_loader.py b/Lib/test/test_unittest/test_loader.py index a203145a791b1a..9fc0d95816af40 100644 --- a/Lib/test/test_unittest/test_loader.py +++ b/Lib/test/test_unittest/test_loader.py @@ -82,6 +82,22 @@ def runTest(self): self.assertIsInstance(suite, loader.suiteClass) self.assertEqual(list(suite), [Foo('runTest')]) + # "Do not load any tests from `TestCase` class itself." + def test_loadTestsFromTestCase__from_TestCase(self): + loader = unittest.TestLoader() + + suite = loader.loadTestsFromTestCase(unittest.TestCase) + self.assertIsInstance(suite, loader.suiteClass) + self.assertEqual(list(suite), []) + + # "Do not load any tests from `FunctionTestCase` class." + def test_loadTestsFromTestCase__from_FunctionTestCase(self): + loader = unittest.TestLoader() + + suite = loader.loadTestsFromTestCase(unittest.FunctionTestCase) + self.assertIsInstance(suite, loader.suiteClass) + self.assertEqual(list(suite), []) + ################################################################ ### /Tests for TestLoader.loadTestsFromTestCase @@ -103,6 +119,19 @@ def test(self): expected = [loader.suiteClass([MyTestCase('test')])] self.assertEqual(list(suite), expected) + # "This test ensures that internal `TestCase` subclasses are not loaded" + def test_loadTestsFromModule__TestCase_subclass_internals(self): + # See https://github.com/python/cpython/issues/84867 + m = types.ModuleType('m') + # Simulate imported names: + m.TestCase = unittest.TestCase + m.FunctionTestCase = unittest.FunctionTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromModule(m) + self.assertIsInstance(suite, loader.suiteClass) + self.assertEqual(list(suite), []) + # "This method searches `module` for classes derived from TestCase" # # What happens if no tests are found (no TestCase instances)? diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py index b989284a640e14..f7c1d61f41b857 100644 --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -84,9 +84,13 @@ def loadTestsFromTestCase(self, testCaseClass): raise TypeError("Test cases should not be derived from " "TestSuite. Maybe you meant to derive from " "TestCase?") - testCaseNames = self.getTestCaseNames(testCaseClass) - if not testCaseNames and hasattr(testCaseClass, 'runTest'): - testCaseNames = ['runTest'] + if testCaseClass in (case.TestCase, case.FunctionTestCase): + # We don't load any tests from base types that should not be loaded. + testCaseNames = [] + else: + testCaseNames = self.getTestCaseNames(testCaseClass) + if not testCaseNames and hasattr(testCaseClass, 'runTest'): + testCaseNames = ['runTest'] loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) return loaded_suite @@ -95,7 +99,11 @@ def loadTestsFromModule(self, module, *, pattern=None): tests = [] for name in dir(module): obj = getattr(module, name) - if isinstance(obj, type) and issubclass(obj, case.TestCase): + if ( + isinstance(obj, type) + and issubclass(obj, case.TestCase) + and obj not in (case.TestCase, case.FunctionTestCase) + ): tests.append(self.loadTestsFromTestCase(obj)) load_tests = getattr(module, 'load_tests', None) @@ -164,7 +172,11 @@ def loadTestsFromName(self, name, module=None): if isinstance(obj, types.ModuleType): return self.loadTestsFromModule(obj) - elif isinstance(obj, type) and issubclass(obj, case.TestCase): + elif ( + isinstance(obj, type) + and issubclass(obj, case.TestCase) + and obj not in (case.TestCase, case.FunctionTestCase) + ): return self.loadTestsFromTestCase(obj) elif (isinstance(obj, types.FunctionType) and isinstance(parent, type) and diff --git a/Misc/NEWS.d/next/Library/2022-12-24-12-50-54.gh-issue-84867.OhaLbU.rst b/Misc/NEWS.d/next/Library/2022-12-24-12-50-54.gh-issue-84867.OhaLbU.rst new file mode 100644 index 00000000000000..8b45dcee481916 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-24-12-50-54.gh-issue-84867.OhaLbU.rst @@ -0,0 +1,2 @@ +:class:`unittest.TestLoader` no longer loads test cases from exact +:class:`unittest.TestCase` and :class:`unittest.FunctionTestCase` classes. From 4b2ba3d0b8a1b2a722aeeefc01fd3162f46d95fc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:58:06 -0700 Subject: [PATCH 0853/1206] [3.12] gh-109351: Fix crash when compiling AST with invalid NamedExpr (GH-109352) (#109379) gh-109351: Fix crash when compiling AST with invalid NamedExpr (GH-109352) (cherry picked from commit 79101edb03b7381b514126c68acabfcbbba2f842) Co-authored-by: Jelle Zijlstra --- Lib/test/test_compile.py | 27 +++++++++++++++++++ ...-09-12-16-00-42.gh-issue-109351.kznGeR.rst | 2 ++ Python/ast.c | 5 ++++ 3 files changed, 34 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-12-16-00-42.gh-issue-109351.kznGeR.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e377620a0c87b8..b75d1c59591e91 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -443,6 +443,33 @@ def f(): self.assertIn("_A__mangled_mod", A.f.__code__.co_varnames) self.assertIn("__package__", A.f.__code__.co_varnames) + def test_compile_invalid_namedexpr(self): + # gh-109351 + m = ast.Module( + body=[ + ast.Expr( + value=ast.ListComp( + elt=ast.NamedExpr( + target=ast.Constant(value=1), + value=ast.Constant(value=3), + ), + generators=[ + ast.comprehension( + target=ast.Name(id="x", ctx=ast.Store()), + iter=ast.Name(id="y", ctx=ast.Load()), + ifs=[], + is_async=0, + ) + ], + ) + ) + ], + type_ignores=[], + ) + + with self.assertRaisesRegex(TypeError, "NamedExpr target must be a Name"): + compile(ast.fix_missing_locations(m), "", "exec") + def test_compile_ast(self): fname = __file__ if fname.lower().endswith('pyc'): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-12-16-00-42.gh-issue-109351.kznGeR.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-12-16-00-42.gh-issue-109351.kznGeR.rst new file mode 100644 index 00000000000000..23b81c1c0a3baa --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-12-16-00-42.gh-issue-109351.kznGeR.rst @@ -0,0 +1,2 @@ +Fix crash when compiling an invalid AST involving a named (walrus) +expression. diff --git a/Python/ast.c b/Python/ast.c index a3acf78ac95844..82d7beec0ee510 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -381,6 +381,11 @@ validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) ret = validate_exprs(state, exp->v.Tuple.elts, ctx, 0); break; case NamedExpr_kind: + if (exp->v.NamedExpr.target->kind != Name_kind) { + PyErr_SetString(PyExc_TypeError, + "NamedExpr target must be a Name"); + return 0; + } ret = validate_expr(state, exp->v.NamedExpr.value, Load); break; /* This last case doesn't have any checking. */ From 775fd782fca77037c3f9bca6f7c528bcef669acb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:58:22 -0700 Subject: [PATCH 0854/1206] [3.12] gh-109375: Fix bug where pdb registers an alias without an associated command (GH-109376) (#109429) gh-109375: Fix bug where pdb registers an alias without an associated command (GH-109376) (cherry picked from commit 68a6f21f47e779ddd70e33cf04d170a63f077fcd) Co-authored-by: buermarc <44375277+buermarc@users.noreply.github.com> --- Lib/pdb.py | 7 +++++-- Lib/test/test_pdb.py | 6 ++++++ Misc/ACKS | 1 + .../Library/2023-09-13-17-22-44.gh-issue-109375.ijJHZ9.rst | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-13-17-22-44.gh-issue-109375.ijJHZ9.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 6b6feac1ddead1..646695ccd1f4dd 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1559,8 +1559,11 @@ def do_alias(self, arg): for alias in keys: self.message("%s = %s" % (alias, self.aliases[alias])) return - if args[0] in self.aliases and len(args) == 1: - self.message("%s = %s" % (args[0], self.aliases[args[0]])) + if len(args) == 1: + if args[0] in self.aliases: + self.message("%s = %s" % (args[0], self.aliases[args[0]])) + else: + self.error(f"Unknown alias '{args[0]}'") else: self.aliases[args[0]] = ' '.join(args[1:]) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 5793dbfbfdf4d0..c0fb61253be5ad 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -662,8 +662,10 @@ def test_pdb_alias_command(): ... o.method() >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'alias pi', ... 'alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}")', ... 'alias ps pi self', + ... 'alias ps', ... 'pi o', ... 's', ... 'ps', @@ -672,8 +674,12 @@ def test_pdb_alias_command(): ... test_function() > (4)test_function() -> o.method() + (Pdb) alias pi + *** Unknown alias 'pi' (Pdb) alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") (Pdb) alias ps pi self + (Pdb) alias ps + ps = pi self (Pdb) pi o o.attr1 = 10 o.attr2 = str diff --git a/Misc/ACKS b/Misc/ACKS index 7deef8bad14a2c..5bba961158e684 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -254,6 +254,7 @@ Curtis Bucher Colm Buckley Erik de Bueger Jan-Hein Bührman +Marc Bürg Lars Buitinck Artem Bulgakov Dick Bulterman diff --git a/Misc/NEWS.d/next/Library/2023-09-13-17-22-44.gh-issue-109375.ijJHZ9.rst b/Misc/NEWS.d/next/Library/2023-09-13-17-22-44.gh-issue-109375.ijJHZ9.rst new file mode 100644 index 00000000000000..9b7a85d05f66ca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-13-17-22-44.gh-issue-109375.ijJHZ9.rst @@ -0,0 +1 @@ +The :mod:`pdb` ``alias`` command now prevents registering aliases without arguments. From e5c860f9d03669f152292fb82665edfc2c01e5ec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:58:43 -0700 Subject: [PATCH 0855/1206] [3.12] Fix date.__repr__() docstring (GH-109422) (#109448) Fix date.__repr__() docstring (GH-109422) (cherry picked from commit 5eec58a9e57383128ade7b527965b1efc474735b) Co-authored-by: Christopher Yeh --- Lib/_pydatetime.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Lib/_pydatetime.py b/Lib/_pydatetime.py index a6d43399f9e703..0e34d8aacf531d 100644 --- a/Lib/_pydatetime.py +++ b/Lib/_pydatetime.py @@ -1015,13 +1015,9 @@ def fromisocalendar(cls, year, week, day): def __repr__(self): """Convert to formal string, for repr(). - >>> dt = datetime(2010, 1, 1) - >>> repr(dt) - 'datetime.datetime(2010, 1, 1, 0, 0)' - - >>> dt = datetime(2010, 1, 1, tzinfo=timezone.utc) - >>> repr(dt) - 'datetime.datetime(2010, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)' + >>> d = date(2010, 1, 1) + >>> repr(d) + 'datetime.date(2010, 1, 1)' """ return "%s.%s(%d, %d, %d)" % (_get_class_module(self), self.__class__.__qualname__, From df2cdcf22f63ca8b958e99406aff41e7c98f16ad Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:58:58 -0700 Subject: [PATCH 0856/1206] [3.12] Fix error handling in _PySys_UpdateConfig() (GH-109524) (#109550) Fix error handling in _PySys_UpdateConfig() (GH-109524) (cherry picked from commit c829975428253568d47ebfc3104fa7386b5e0b58) Co-authored-by: Serhiy Storchaka --- Python/sysmodule.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 4bd38b4b267873..14f4447425d025 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3466,7 +3466,9 @@ _PySys_UpdateConfig(PyThreadState *tstate) if (config->pycache_prefix != NULL) { SET_SYS_FROM_WSTR("pycache_prefix", config->pycache_prefix); } else { - PyDict_SetItemString(sysdict, "pycache_prefix", Py_None); + if (PyDict_SetItemString(sysdict, "pycache_prefix", Py_None) < 0) { + return -1; + } } COPY_LIST("argv", config->argv); @@ -3480,7 +3482,9 @@ _PySys_UpdateConfig(PyThreadState *tstate) SET_SYS_FROM_WSTR("_stdlib_dir", stdlibdir); } else { - PyDict_SetItemString(sysdict, "_stdlib_dir", Py_None); + if (PyDict_SetItemString(sysdict, "_stdlib_dir", Py_None) < 0) { + return -1; + } } #undef SET_SYS_FROM_WSTR @@ -3490,6 +3494,9 @@ _PySys_UpdateConfig(PyThreadState *tstate) // sys.flags PyObject *flags = _PySys_GetObject(interp, "flags"); // borrowed ref if (flags == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetString(tstate, PyExc_RuntimeError, "lost sys.flags"); + } return -1; } if (set_flags_from_config(interp, flags) < 0) { From acb675323341c9105feacba8105fc9a4cb68eb45 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:59:26 -0700 Subject: [PATCH 0857/1206] [3.12] gh-109546: Add more tests for formatting floats and fractions (GH-109548) (#109557) gh-109546: Add more tests for formatting floats and fractions (GH-109548) (cherry picked from commit beb5ec5817b645562ebbdd59f25683a93061c32c) Co-authored-by: Serhiy Storchaka --- Lib/test/test_float.py | 9 +++++++-- Lib/test/test_fractions.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index c4ee1e08251d63..84270ce7dd4780 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -733,8 +733,13 @@ def test_format_testfile(self): lhs, rhs = map(str.strip, line.split('->')) fmt, arg = lhs.split() - self.assertEqual(fmt % float(arg), rhs) - self.assertEqual(fmt % -float(arg), '-' + rhs) + f = float(arg) + self.assertEqual(fmt % f, rhs) + self.assertEqual(fmt % -f, '-' + rhs) + if fmt != '%r': + fmt2 = fmt[1:] + self.assertEqual(format(f, fmt2), rhs) + self.assertEqual(format(-f, fmt2), '-' + rhs) def test_issue5864(self): self.assertEqual(format(123.456, '.4'), '123.5') diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index e112f49d2e7944..4f4ea7c03f9a4c 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -7,6 +7,7 @@ import operator import fractions import functools +import os import sys import typing import unittest @@ -15,6 +16,9 @@ from pickle import dumps, loads F = fractions.Fraction +#locate file with float format test values +test_dir = os.path.dirname(__file__) or os.curdir +format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt') class DummyFloat(object): """Dummy float class for testing comparisons with Fractions""" @@ -1220,6 +1224,30 @@ def test_invalid_formats(self): with self.assertRaises(ValueError): format(fraction, spec) + @requires_IEEE_754 + def test_float_format_testfile(self): + with open(format_testfile, encoding="utf-8") as testfile: + for line in testfile: + if line.startswith('--'): + continue + line = line.strip() + if not line: + continue + + lhs, rhs = map(str.strip, line.split('->')) + fmt, arg = lhs.split() + if fmt == '%r': + continue + fmt2 = fmt[1:] + with self.subTest(fmt=fmt, arg=arg): + f = F(float(arg)) + self.assertEqual(format(f, fmt2), rhs) + if f: # skip negative zero + self.assertEqual(format(-f, fmt2), '-' + rhs) + f = F(arg) + self.assertEqual(float(format(f, fmt2)), float(rhs)) + self.assertEqual(float(format(-f, fmt2)), float('-' + rhs)) + if __name__ == '__main__': unittest.main() From ddc0adcdb3ac0fbd14367876304ae61f68cb1813 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:59:43 -0700 Subject: [PATCH 0858/1206] [3.12] gh-109469: Silence compiler warnings on string comparisons in _testcapi (GH-109533) (#109558) gh-109469: Silence compiler warnings on string comparisons in _testcapi (GH-109533) (cherry picked from commit ed582a2ed980efba2d0da365ae37bff4a2b99873) Co-authored-by: Serhiy Storchaka --- Modules/_testcapi/util.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_testcapi/util.h b/Modules/_testcapi/util.h index 4cf7e226382bfc..f26d7656a10138 100644 --- a/Modules/_testcapi/util.h +++ b/Modules/_testcapi/util.h @@ -25,7 +25,8 @@ } while (0) /* Marker to check that pointer value was set. */ -#define UNINITIALIZED_PTR ((void *)"uninitialized") +static const char uninitialized[] = "uninitialized"; +#define UNINITIALIZED_PTR ((void *)uninitialized) /* Marker to check that Py_ssize_t value was set. */ #define UNINITIALIZED_SIZE ((Py_ssize_t)236892191) /* Marker to check that integer value was set. */ From c3038bed1df2dc0399379cec81544a3d725674ef Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:00:11 -0700 Subject: [PATCH 0859/1206] [3.12] gh-109580: Skip test_perf_profiler on ASAN build (GH-109584) (#109585) gh-109580: Skip test_perf_profiler on ASAN build (GH-109584) Skip test_perf_profiler if Python is built with ASAN, MSAN or UBSAN sanitizer. Python does crash randomly in this test on such build. (cherry picked from commit 754519a9f8c2bb06d85ff9b3e9fe6f967ac46d5c) Co-authored-by: Victor Stinner --- Lib/test/test_perf_profiler.py | 6 +++++- .../Tests/2023-09-19-19-08-22.gh-issue-109580.G02Zam.rst | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-19-19-08-22.gh-issue-109580.G02Zam.rst diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 5418f9f35485f8..fe8707a156e9dc 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -17,6 +17,11 @@ if not support.has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") +if support.check_sanitizer(address=True, memory=True, ub=True): + # gh-109580: Skip the test because it does crash randomly if Python is + # built with ASAN. + raise unittest.SkipTest("test crash randomly on ASAN/MSAN/UBSAN build") + def supports_trampoline_profiling(): perf_trampoline = sysconfig.get_config_var("PY_HAVE_PERF_TRAMPOLINE") @@ -287,7 +292,6 @@ def run_perf(cwd, *args, **env_vars): @unittest.skipUnless(perf_command_works(), "perf command doesn't work") @unittest.skipUnless(is_unwinding_reliable(), "Unwinding is unreliable") -@support.skip_if_sanitizer(address=True, memory=True, ub=True) class TestPerfProfiler(unittest.TestCase): def setUp(self): super().setUp() diff --git a/Misc/NEWS.d/next/Tests/2023-09-19-19-08-22.gh-issue-109580.G02Zam.rst b/Misc/NEWS.d/next/Tests/2023-09-19-19-08-22.gh-issue-109580.G02Zam.rst new file mode 100644 index 00000000000000..b917cbf6fd0a05 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-19-19-08-22.gh-issue-109580.G02Zam.rst @@ -0,0 +1,3 @@ +Skip ``test_perf_profiler`` if Python is built with ASAN, MSAN or UBSAN +sanitizer. Python does crash randomly in this test on such build. Patch by +Victor Stinner. From 5ba9d2b98f13c509cec560cb1de8de1630463e5c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:03:51 -0700 Subject: [PATCH 0860/1206] [3.12] gh-108973: Fix asyncio test_subprocess_consistent_callbacks() (GH-109431) (#109609) gh-108973: Fix asyncio test_subprocess_consistent_callbacks() (GH-109431) SubprocessProtocol process_exited() method can be called before pipe_data_received() and pipe_connection_lost() methods. Document it and adapt the test for that. Revert commit 282edd7b2a74c4dfe1bfe3c5b1d30f9c21d554d6. _child_watcher_callback() calls immediately _process_exited(): don't add an additional delay with call_soon(). The reverted change didn't make _process_exited() more determistic: it can still be called before pipe_connection_lost() for example. (cherry picked from commit ced6924630037f1e5b3d1dbef2b600152fb07fbb) Co-authored-by: Victor Stinner Co-authored-by: Davide Rizzo --- Doc/library/asyncio-llapi-index.rst | 10 ++--- Doc/library/asyncio-protocol.rst | 19 ++++++++- Lib/asyncio/unix_events.py | 3 +- Lib/test/test_asyncio/test_subprocess.py | 54 +++++++++++++++++++----- 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/Doc/library/asyncio-llapi-index.rst b/Doc/library/asyncio-llapi-index.rst index 9ce48a24444e66..67136ba69ec875 100644 --- a/Doc/library/asyncio-llapi-index.rst +++ b/Doc/library/asyncio-llapi-index.rst @@ -484,19 +484,19 @@ Protocol classes can implement the following **callback methods**: :widths: 50 50 :class: full-width-table - * - ``callback`` :meth:`pipe_data_received() - ` + * - ``callback`` :meth:`~SubprocessProtocol.pipe_data_received` - Called when the child process writes data into its *stdout* or *stderr* pipe. - * - ``callback`` :meth:`pipe_connection_lost() - ` + * - ``callback`` :meth:`~SubprocessProtocol.pipe_connection_lost` - Called when one of the pipes communicating with the child process is closed. * - ``callback`` :meth:`process_exited() ` - - Called when the child process has exited. + - Called when the child process has exited. It can be called before + :meth:`~SubprocessProtocol.pipe_data_received` and + :meth:`~SubprocessProtocol.pipe_connection_lost` methods. Event Loop Policies diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 7bc906eaafc1f2..48fa02937b5237 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -708,6 +708,9 @@ factories passed to the :meth:`loop.subprocess_exec` and Called when the child process has exited. + It can be called before :meth:`~SubprocessProtocol.pipe_data_received` and + :meth:`~SubprocessProtocol.pipe_connection_lost` methods. + Examples ======== @@ -1003,12 +1006,26 @@ The subprocess is created by the :meth:`loop.subprocess_exec` method:: def __init__(self, exit_future): self.exit_future = exit_future self.output = bytearray() + self.pipe_closed = False + self.exited = False + + def pipe_connection_lost(self, fd, exc): + self.pipe_closed = True + self.check_for_exit() def pipe_data_received(self, fd, data): self.output.extend(data) def process_exited(self): - self.exit_future.set_result(True) + self.exited = True + # process_exited() method can be called before + # pipe_connection_lost() method: wait until both methods are + # called. + self.check_for_exit() + + def check_for_exit(self): + if self.pipe_closed and self.exited: + self.exit_future.set_result(True) async def get_date(): # Get a reference to the event loop as we plan to use diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 17fb4d5f7646ce..f985f9776ed0aa 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -226,8 +226,7 @@ async def _make_subprocess_transport(self, protocol, args, shell, return transp def _child_watcher_callback(self, pid, returncode, transp): - # Skip one iteration for callbacks to be executed - self.call_soon_threadsafe(self.call_soon, transp._process_exited, returncode) + self.call_soon_threadsafe(transp._process_exited, returncode) async def create_unix_connection( self, protocol_factory, path=None, *, diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index eeeca40c15cd28..429ef16fdb0e05 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -753,21 +753,44 @@ async def main() -> None: self.loop.run_until_complete(main()) - def test_subprocess_consistent_callbacks(self): + def test_subprocess_protocol_events(self): + # gh-108973: Test that all subprocess protocol methods are called. + # The protocol methods are not called in a determistic order. + # The order depends on the event loop and the operating system. events = [] + fds = [1, 2] + expected = [ + ('pipe_data_received', 1, b'stdout'), + ('pipe_data_received', 2, b'stderr'), + ('pipe_connection_lost', 1), + ('pipe_connection_lost', 2), + 'process_exited', + ] + per_fd_expected = [ + 'pipe_data_received', + 'pipe_connection_lost', + ] + class MyProtocol(asyncio.SubprocessProtocol): def __init__(self, exit_future: asyncio.Future) -> None: self.exit_future = exit_future def pipe_data_received(self, fd, data) -> None: events.append(('pipe_data_received', fd, data)) + self.exit_maybe() def pipe_connection_lost(self, fd, exc) -> None: - events.append('pipe_connection_lost') + events.append(('pipe_connection_lost', fd)) + self.exit_maybe() def process_exited(self) -> None: events.append('process_exited') - self.exit_future.set_result(True) + self.exit_maybe() + + def exit_maybe(self): + # Only exit when we got all expected events + if len(events) >= len(expected): + self.exit_future.set_result(True) async def main() -> None: loop = asyncio.get_running_loop() @@ -777,15 +800,24 @@ async def main() -> None: sys.executable, '-c', code, stdin=None) await exit_future transport.close() - self.assertEqual(events, [ - ('pipe_data_received', 1, b'stdout'), - ('pipe_data_received', 2, b'stderr'), - 'pipe_connection_lost', - 'pipe_connection_lost', - 'process_exited', - ]) - self.loop.run_until_complete(main()) + return events + + events = self.loop.run_until_complete(main()) + + # First, make sure that we received all events + self.assertSetEqual(set(events), set(expected)) + + # Second, check order of pipe events per file descriptor + per_fd_events = {fd: [] for fd in fds} + for event in events: + if event == 'process_exited': + continue + name, fd = event[:2] + per_fd_events[fd].append(name) + + for fd in fds: + self.assertEqual(per_fd_events[fd], per_fd_expected, (fd, events)) def test_subprocess_communicate_stdout(self): # See https://github.com/python/cpython/issues/100133 From dc70d30732fda7e88d7c38917968f59415a3f534 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:04:19 +0200 Subject: [PATCH 0861/1206] [3.12] gh-103053: Skip test_freeze_simple_script() on PGO build (#109591) (#109614) gh-103053: Skip test_freeze_simple_script() on PGO build (#109591) Skip test_freeze_simple_script() of test_tools.test_freeze if Python is built with "./configure --enable-optimizations", which means with Profile Guided Optimization (PGO): it just makes the test too slow. The freeze tool is tested by many other CIs with other (faster) compiler flags. test.pythoninfo now gets also get_build_info() of test.libregrtests.utils. (cherry picked from commit 81cd1bd713624c3d26b647f3d28f2fd905887a0d) --- Lib/test/libregrtest/utils.py | 12 ++---------- Lib/test/pythoninfo.py | 10 ++++++++++ Lib/test/support/__init__.py | 15 +++++++++++++++ Lib/test/test_tools/test_freeze.py | 4 ++++ ...2023-09-20-02-32-17.gh-issue-103053.AoUJuK.rst | 4 ++++ 5 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-20-02-32-17.gh-issue-103053.AoUJuK.rst diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index 5e16b1ae054a26..28acb531f4d93e 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -259,16 +259,8 @@ def get_build_info(): elif '-flto' in ldflags_nodist: optimizations.append('LTO') - # --enable-optimizations - pgo_options = ( - # GCC - '-fprofile-use', - # clang: -fprofile-instr-use=code.profclangd - '-fprofile-instr-use', - # ICC - "-prof-use", - ) - if any(option in cflags_nodist for option in pgo_options): + if support.check_cflags_pgo(): + # PGO (--enable-optimizations) optimizations.append('PGO') if optimizations: build.append('+'.join(optimizations)) diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 8d7fb9f4f2103b..860c4cc4e0a818 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -867,6 +867,15 @@ def collect_fips(info_add): pass +def collect_libregrtest_utils(info_add): + try: + from test.libregrtest import utils + except ImportError: + return + + info_add('libregrtests.build_info', ' '.join(utils.get_build_info())) + + def collect_info(info): error = False info_add = info.add @@ -904,6 +913,7 @@ def collect_info(info): collect_tkinter, collect_windows, collect_zlib, + collect_libregrtest_utils, # Collecting from tests should be last as they have side effects. collect_test_socket, diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index b6350e4e5292fe..389d39c83bc006 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -781,6 +781,21 @@ def python_is_optimized(): return final_opt not in ('', '-O0', '-Og') +def check_cflags_pgo(): + # Check if Python was built with ./configure --enable-optimizations: + # with Profile Guided Optimization (PGO). + cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST') or '' + pgo_options = ( + # GCC + '-fprofile-use', + # clang: -fprofile-instr-use=code.profclangd + '-fprofile-instr-use', + # ICC + "-prof-use", + ) + return any(option in cflags_nodist for option in pgo_options) + + _header = 'nP' _align = '0n' if hasattr(sys, "getobjects"): diff --git a/Lib/test/test_tools/test_freeze.py b/Lib/test/test_tools/test_freeze.py index 922e74b441457a..671ec2961e7f8f 100644 --- a/Lib/test/test_tools/test_freeze.py +++ b/Lib/test/test_tools/test_freeze.py @@ -15,6 +15,10 @@ @support.requires_zlib() @unittest.skipIf(sys.platform.startswith('win'), 'not supported on Windows') @support.skip_if_buildbot('not all buildbots have enough space') +# gh-103053: Skip test if Python is built with Profile Guided Optimization +# (PGO), since the test is just too slow in this case. +@unittest.skipIf(support.check_cflags_pgo(), + 'test is too slow with PGO') class TestFreeze(unittest.TestCase): @support.requires_resource('cpu') # Building Python is slow diff --git a/Misc/NEWS.d/next/Tests/2023-09-20-02-32-17.gh-issue-103053.AoUJuK.rst b/Misc/NEWS.d/next/Tests/2023-09-20-02-32-17.gh-issue-103053.AoUJuK.rst new file mode 100644 index 00000000000000..6d67bf237bdbb2 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-20-02-32-17.gh-issue-103053.AoUJuK.rst @@ -0,0 +1,4 @@ +Skip test_freeze_simple_script() of test_tools.test_freeze if Python is built +with ``./configure --enable-optimizations``, which means with Profile Guided +Optimization (PGO): it just makes the test too slow. The freeze tool is tested +by many other CIs with other (faster) compiler flags. Patch by Victor Stinner. From 47e96c6782f6751e8a09991909073039b867d10c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:09:45 -0700 Subject: [PATCH 0862/1206] [3.12] gh-109613: _pystat_fromstructstat() checks for exceptions (GH-109618) (#109641) gh-109613: _pystat_fromstructstat() checks for exceptions (GH-109618) Fix os.stat() and os.DirEntry.stat(): check for exceptions. Previously, on Python built in debug mode, these functions could trigger a fatal Python error (and abort the process) when a function succeeded with an exception set. _pystat_fromstructstat() now exits immediately if an exception is raised, rather only checking for exceptions at the end. It fix following fatal error in fill_time(): Fatal Python error: _Py_CheckSlotResult: Slot * of type int succeeded with an exception set (cherry picked from commit d4cea794a7b9b745817d2bd982d35412aef04710) Co-authored-by: Victor Stinner --- ...-09-20-17-45-46.gh-issue-109613.P13ogN.rst | 4 + Modules/posixmodule.c | 121 +++++++++++------- 2 files changed, 76 insertions(+), 49 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-20-17-45-46.gh-issue-109613.P13ogN.rst diff --git a/Misc/NEWS.d/next/Library/2023-09-20-17-45-46.gh-issue-109613.P13ogN.rst b/Misc/NEWS.d/next/Library/2023-09-20-17-45-46.gh-issue-109613.P13ogN.rst new file mode 100644 index 00000000000000..e21a758fc2eb05 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-20-17-45-46.gh-issue-109613.P13ogN.rst @@ -0,0 +1,4 @@ +Fix :func:`os.stat` and :meth:`os.DirEntry.stat`: check for exceptions. +Previously, on Python built in debug mode, these functions could trigger a +fatal Python error (and abort the process) when a function succeeded with an +exception set. Patch by Victor Stinner. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b9ca2865c0374e..816601da488d62 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2385,21 +2385,26 @@ _posix_free(void *module) _posix_clear((PyObject *)module); } -static void +static int fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec) { - PyObject *s = _PyLong_FromTime_t(sec); - PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); + assert(!PyErr_Occurred()); + + int res = -1; PyObject *s_in_ns = NULL; PyObject *ns_total = NULL; PyObject *float_s = NULL; - if (!(s && ns_fractional)) + PyObject *s = _PyLong_FromTime_t(sec); + PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); + if (!(s && ns_fractional)) { goto exit; + } s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion); - if (!s_in_ns) + if (!s_in_ns) { goto exit; + } ns_total = PyNumber_Add(s_in_ns, ns_fractional); if (!ns_total) @@ -2422,12 +2427,17 @@ fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, PyStructSequence_SET_ITEM(v, ns_index, ns_total); ns_total = NULL; } + + assert(!PyErr_Occurred()); + res = 0; + exit: Py_XDECREF(s); Py_XDECREF(ns_fractional); Py_XDECREF(s_in_ns); Py_XDECREF(ns_total); Py_XDECREF(float_s); + return res; } #ifdef MS_WINDOWS @@ -2462,34 +2472,47 @@ _pystat_l128_from_l64_l64(uint64_t low, uint64_t high) static PyObject* _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) { - unsigned long ansec, mnsec, cnsec; + assert(!PyErr_Occurred()); + PyObject *StatResultType = get_posix_state(module)->StatResultType; PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType); - if (v == NULL) + if (v == NULL) { return NULL; + } + +#define SET_ITEM(pos, expr) \ + do { \ + PyObject *obj = (expr); \ + if (obj == NULL) { \ + goto error; \ + } \ + PyStructSequence_SET_ITEM(v, (pos), obj); \ + } while (0) - PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); + SET_ITEM(0, PyLong_FromLong((long)st->st_mode)); #ifdef MS_WINDOWS - PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); - PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLongLong(st->st_dev)); + SET_ITEM(1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); + SET_ITEM(2, PyLong_FromUnsignedLongLong(st->st_dev)); #else static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino), "stat.st_ino is larger than unsigned long long"); - PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino)); - PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev)); + SET_ITEM(1, PyLong_FromUnsignedLongLong(st->st_ino)); + SET_ITEM(2, _PyLong_FromDev(st->st_dev)); #endif - PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink)); + SET_ITEM(3, PyLong_FromLong((long)st->st_nlink)); #if defined(MS_WINDOWS) - PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0)); - PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0)); + SET_ITEM(4, PyLong_FromLong(0)); + SET_ITEM(5, PyLong_FromLong(0)); #else - PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid)); - PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid)); + SET_ITEM(4, _PyLong_FromUid(st->st_uid)); + SET_ITEM(5, _PyLong_FromGid(st->st_gid)); #endif static_assert(sizeof(long long) >= sizeof(st->st_size), "stat.st_size is larger than long long"); - PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size)); + SET_ITEM(6, PyLong_FromLongLong(st->st_size)); + // Set st_atime, st_mtime and st_ctime + unsigned long ansec, mnsec, cnsec; #if defined(HAVE_STAT_TV_NSEC) ansec = st->st_atim.tv_nsec; mnsec = st->st_mtim.tv_nsec; @@ -2505,67 +2528,67 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) #else ansec = mnsec = cnsec = 0; #endif - fill_time(module, v, 7, 10, 13, st->st_atime, ansec); - fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec); - fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec); + if (fill_time(module, v, 7, 10, 13, st->st_atime, ansec) < 0) { + goto error; + } + if (fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec) < 0) { + goto error; + } + if (fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec) < 0) { + goto error; + } #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX, - PyLong_FromLong((long)st->st_blksize)); + SET_ITEM(ST_BLKSIZE_IDX, PyLong_FromLong((long)st->st_blksize)); #endif #ifdef HAVE_STRUCT_STAT_ST_BLOCKS - PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX, - PyLong_FromLong((long)st->st_blocks)); + SET_ITEM(ST_BLOCKS_IDX, PyLong_FromLong((long)st->st_blocks)); #endif #ifdef HAVE_STRUCT_STAT_ST_RDEV - PyStructSequence_SET_ITEM(v, ST_RDEV_IDX, - PyLong_FromLong((long)st->st_rdev)); + SET_ITEM(ST_RDEV_IDX, PyLong_FromLong((long)st->st_rdev)); #endif #ifdef HAVE_STRUCT_STAT_ST_GEN - PyStructSequence_SET_ITEM(v, ST_GEN_IDX, - PyLong_FromLong((long)st->st_gen)); + SET_ITEM(ST_GEN_IDX, PyLong_FromLong((long)st->st_gen)); #endif #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) { - PyObject *val; - unsigned long bsec,bnsec; + unsigned long bsec, bnsec; bsec = (long)st->st_birthtime; #ifdef HAVE_STAT_TV_NSEC2 bnsec = st->st_birthtimespec.tv_nsec; #else bnsec = 0; #endif - val = PyFloat_FromDouble(bsec + 1e-9*bnsec); - PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, - val); + SET_ITEM(ST_BIRTHTIME_IDX, PyFloat_FromDouble(bsec + bnsec * 1e-9)); } #elif defined(MS_WINDOWS) - fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, - st->st_birthtime, st->st_birthtime_nsec); + if (fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, + st->st_birthtime, st->st_birthtime_nsec) < 0) { + goto error; + } #endif #ifdef HAVE_STRUCT_STAT_ST_FLAGS - PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, - PyLong_FromLong((long)st->st_flags)); + SET_ITEM(ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags)); #endif #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES - PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX, - PyLong_FromUnsignedLong(st->st_file_attributes)); + SET_ITEM(ST_FILE_ATTRIBUTES_IDX, + PyLong_FromUnsignedLong(st->st_file_attributes)); #endif #ifdef HAVE_STRUCT_STAT_ST_FSTYPE - PyStructSequence_SET_ITEM(v, ST_FSTYPE_IDX, - PyUnicode_FromString(st->st_fstype)); + SET_ITEM(ST_FSTYPE_IDX, PyUnicode_FromString(st->st_fstype)); #endif #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG - PyStructSequence_SET_ITEM(v, ST_REPARSE_TAG_IDX, - PyLong_FromUnsignedLong(st->st_reparse_tag)); + SET_ITEM(ST_REPARSE_TAG_IDX, PyLong_FromUnsignedLong(st->st_reparse_tag)); #endif - if (PyErr_Occurred()) { - Py_DECREF(v); - return NULL; - } - + assert(!PyErr_Occurred()); return v; + +error: + Py_DECREF(v); + return NULL; + +#undef SET_ITEM } /* POSIX methods */ From 1dfb41d2626e489e0b4bd2d56dc804a350a2f58d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:10:04 -0700 Subject: [PATCH 0863/1206] [3.12] gh-108303: Remove unused Lib/test/sgml_input.html (GH-108305) (#109671) gh-108303: Remove unused Lib/test/sgml_input.html (GH-108305) In Python 2.7, the file was used by Lib/test/test_sgmllib.py to test Lib/sgmllib.py. The sgmllib module and its tests have been removed in Python 3.0. (cherry picked from commit d2879f2095abd5c8186c7f69c964a341c2053572) Co-authored-by: Victor Stinner --- Lib/test/sgml_input.html | 212 --------------------------------------- 1 file changed, 212 deletions(-) delete mode 100644 Lib/test/sgml_input.html diff --git a/Lib/test/sgml_input.html b/Lib/test/sgml_input.html deleted file mode 100644 index f4d2e6cc805e6a..00000000000000 --- a/Lib/test/sgml_input.html +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - - -
- - - - - -
-
- - - - - -
- - -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
  MetalCristalDeuterioEnergía  
160.6363.40639.230-80/3.965
-
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Flotas (max. 9)
Num.MisiónCantidadComienzoSalidaObjetivoLlegadaOrden
1 - Espionaje - (F) - 3[2:250:6]Wed Aug 9 18:00:02[2:242:5]Wed Aug 9 18:01:02 -
- - -
-
2 - Espionaje - (V) - 3[2:250:6]Wed Aug 9 17:59:55[2:242:1]Wed Aug 9 18:01:55 -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Nueva misión: elegir naves
NavesDisponibles--
Nave pequeña de carga10máx
Nave grande de carga19máx
Crucero6máx
Reciclador1máx
Sonda de espionaje139máx
Ninguna naveTodas las naves
- -

-
- - From b153cab6d8f32fb62778ea55ffb9c4df40da91e8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:10:33 -0700 Subject: [PATCH 0864/1206] [3.12] gh-108303: Move `ann_module*.py` files to `typinganndata/` folder (GH-108354) (#109672) gh-108303: Move `ann_module*.py` files to `typinganndata/` folder (GH-108354) (cherry picked from commit 3f61cf646d0506baa0c0c2118f05110446519c62) Co-authored-by: Nikita Sobolev --- Lib/test/test_grammar.py | 6 +++--- Lib/test/test_inspect.py | 2 +- Lib/test/test_module/__init__.py | 4 +++- Lib/test/test_opcodes.py | 3 ++- Lib/test/test_typing.py | 6 ++++-- Lib/test/{ => typinganndata}/ann_module.py | 0 Lib/test/{ => typinganndata}/ann_module2.py | 0 Lib/test/{ => typinganndata}/ann_module3.py | 0 Lib/test/{ => typinganndata}/ann_module4.py | 0 Lib/test/{ => typinganndata}/ann_module5.py | 0 Lib/test/{ => typinganndata}/ann_module6.py | 0 Lib/test/{ => typinganndata}/ann_module7.py | 0 Lib/test/{ => typinganndata}/ann_module8.py | 0 13 files changed, 13 insertions(+), 8 deletions(-) rename Lib/test/{ => typinganndata}/ann_module.py (100%) rename Lib/test/{ => typinganndata}/ann_module2.py (100%) rename Lib/test/{ => typinganndata}/ann_module3.py (100%) rename Lib/test/{ => typinganndata}/ann_module4.py (100%) rename Lib/test/{ => typinganndata}/ann_module5.py (100%) rename Lib/test/{ => typinganndata}/ann_module6.py (100%) rename Lib/test/{ => typinganndata}/ann_module7.py (100%) rename Lib/test/{ => typinganndata}/ann_module8.py (100%) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index ad9f6c764319a9..8501006b799262 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -12,9 +12,9 @@ # different import patterns to check that __annotations__ does not interfere # with import machinery -import test.ann_module as ann_module +import test.typinganndata.ann_module as ann_module import typing -from test import ann_module2 +from test.typinganndata import ann_module2 import test # These are shared with test_tokenize and other test modules. @@ -467,7 +467,7 @@ def test_var_annot_module_semantics(self): def test_var_annot_in_module(self): # check that functions fail the same way when executed # outside of module where they were defined - ann_module3 = import_helper.import_fresh_module("test.ann_module3") + ann_module3 = import_helper.import_fresh_module("test.typinganndata.ann_module3") with self.assertRaises(NameError): ann_module3.f_bad_ann() with self.assertRaises(NameError): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index d89953ab60f022..f0ee83187c96bf 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -4584,7 +4584,7 @@ def func(*args, **kwargs): def test_base_class_have_text_signature(self): # see issue 43118 - from test.ann_module7 import BufferedReader + from test.typinganndata.ann_module7 import BufferedReader class MyBufferedReader(BufferedReader): """buffer reader class.""" diff --git a/Lib/test/test_module/__init__.py b/Lib/test/test_module/__init__.py index cfc4d9ccf1cc81..2524e6c87cb459 100644 --- a/Lib/test/test_module/__init__.py +++ b/Lib/test/test_module/__init__.py @@ -324,7 +324,9 @@ def test_annotations_getset_raises(self): del foo.__annotations__ def test_annotations_are_created_correctly(self): - ann_module4 = import_helper.import_fresh_module('test.ann_module4') + ann_module4 = import_helper.import_fresh_module( + 'test.typinganndata.ann_module4', + ) self.assertTrue("__annotations__" in ann_module4.__dict__) del ann_module4.__annotations__ self.assertFalse("__annotations__" in ann_module4.__dict__) diff --git a/Lib/test/test_opcodes.py b/Lib/test/test_opcodes.py index e880c3f1ac875e..72488b2bb6b4ff 100644 --- a/Lib/test/test_opcodes.py +++ b/Lib/test/test_opcodes.py @@ -1,7 +1,8 @@ # Python test set -- part 2, opcodes import unittest -from test import ann_module, support +from test import support +from test.typinganndata import ann_module class OpcodeTest(unittest.TestCase): diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 6c9f168b63f96d..eb7617737b8c1d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -5306,7 +5306,7 @@ def test_errors(self): # We need this to make sure that `@no_type_check` respects `__module__` attr: -from test import ann_module8 +from test.typinganndata import ann_module8 @no_type_check class NoTypeCheck_Outer: @@ -5893,7 +5893,9 @@ def test_overload_registry_repeated(self): # Definitions needed for features introduced in Python 3.6 -from test import ann_module, ann_module2, ann_module3, ann_module5, ann_module6 +from test.typinganndata import ( + ann_module, ann_module2, ann_module3, ann_module5, ann_module6, +) T_a = TypeVar('T_a') diff --git a/Lib/test/ann_module.py b/Lib/test/typinganndata/ann_module.py similarity index 100% rename from Lib/test/ann_module.py rename to Lib/test/typinganndata/ann_module.py diff --git a/Lib/test/ann_module2.py b/Lib/test/typinganndata/ann_module2.py similarity index 100% rename from Lib/test/ann_module2.py rename to Lib/test/typinganndata/ann_module2.py diff --git a/Lib/test/ann_module3.py b/Lib/test/typinganndata/ann_module3.py similarity index 100% rename from Lib/test/ann_module3.py rename to Lib/test/typinganndata/ann_module3.py diff --git a/Lib/test/ann_module4.py b/Lib/test/typinganndata/ann_module4.py similarity index 100% rename from Lib/test/ann_module4.py rename to Lib/test/typinganndata/ann_module4.py diff --git a/Lib/test/ann_module5.py b/Lib/test/typinganndata/ann_module5.py similarity index 100% rename from Lib/test/ann_module5.py rename to Lib/test/typinganndata/ann_module5.py diff --git a/Lib/test/ann_module6.py b/Lib/test/typinganndata/ann_module6.py similarity index 100% rename from Lib/test/ann_module6.py rename to Lib/test/typinganndata/ann_module6.py diff --git a/Lib/test/ann_module7.py b/Lib/test/typinganndata/ann_module7.py similarity index 100% rename from Lib/test/ann_module7.py rename to Lib/test/typinganndata/ann_module7.py diff --git a/Lib/test/ann_module8.py b/Lib/test/typinganndata/ann_module8.py similarity index 100% rename from Lib/test/ann_module8.py rename to Lib/test/typinganndata/ann_module8.py From 9bceb8a79b73b3a0791a6621a40469c84869460a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:11:03 -0700 Subject: [PATCH 0865/1206] [3.12] gh-108303: Create Lib/test/test_dataclasses/ directory (GH-108978) (#109674) * gh-108303: Create Lib/test/test_dataclasses/ directory (GH-108978) Move test_dataclasses.py and its "dataclass_*.py" modules into the new Lib/test/test_dataclasses/ subdirectory. (cherry picked from commit 14d6e197cc56e5256d501839a4e66e3864ab15f0) Co-authored-by: Victor Stinner * Fix Lint job: update Lib/test/.ruff.toml --------- Co-authored-by: Victor Stinner --- Lib/test/.ruff.toml | 2 +- .../__init__.py} | 10 +++++----- Lib/test/{ => test_dataclasses}/dataclass_module_1.py | 0 .../{ => test_dataclasses}/dataclass_module_1_str.py | 0 Lib/test/{ => test_dataclasses}/dataclass_module_2.py | 0 .../{ => test_dataclasses}/dataclass_module_2_str.py | 0 Lib/test/{ => test_dataclasses}/dataclass_textanno.py | 0 Makefile.pre.in | 1 + 8 files changed, 7 insertions(+), 6 deletions(-) rename Lib/test/{test_dataclasses.py => test_dataclasses/__init__.py} (99%) rename Lib/test/{ => test_dataclasses}/dataclass_module_1.py (100%) rename Lib/test/{ => test_dataclasses}/dataclass_module_1_str.py (100%) rename Lib/test/{ => test_dataclasses}/dataclass_module_2.py (100%) rename Lib/test/{ => test_dataclasses}/dataclass_module_2_str.py (100%) rename Lib/test/{ => test_dataclasses}/dataclass_textanno.py (100%) diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml index 3bdd472c0acd9a..2d9c9eeae6c0c6 100644 --- a/Lib/test/.ruff.toml +++ b/Lib/test/.ruff.toml @@ -22,7 +22,7 @@ extend-exclude = [ "test_capi/test_unicode.py", "test_ctypes/test_arrays.py", "test_ctypes/test_functions.py", - "test_dataclasses.py", + "test_dataclasses/__init__.py", "test_descr.py", "test_enum.py", "test_functools.py", diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses/__init__.py similarity index 99% rename from Lib/test/test_dataclasses.py rename to Lib/test/test_dataclasses/__init__.py index 6669f1c57e2e78..2b09db03d4d248 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -3684,10 +3684,10 @@ class C: self.assertEqual(C(10).x, 10) def test_classvar_module_level_import(self): - from test import dataclass_module_1 - from test import dataclass_module_1_str - from test import dataclass_module_2 - from test import dataclass_module_2_str + from test.test_dataclasses import dataclass_module_1 + from test.test_dataclasses import dataclass_module_1_str + from test.test_dataclasses import dataclass_module_2 + from test.test_dataclasses import dataclass_module_2_str for m in (dataclass_module_1, dataclass_module_1_str, dataclass_module_2, dataclass_module_2_str, @@ -3725,7 +3725,7 @@ def test_classvar_module_level_import(self): self.assertNotIn('not_iv4', c.__dict__) def test_text_annotations(self): - from test import dataclass_textanno + from test.test_dataclasses import dataclass_textanno self.assertEqual( get_type_hints(dataclass_textanno.Bar), diff --git a/Lib/test/dataclass_module_1.py b/Lib/test/test_dataclasses/dataclass_module_1.py similarity index 100% rename from Lib/test/dataclass_module_1.py rename to Lib/test/test_dataclasses/dataclass_module_1.py diff --git a/Lib/test/dataclass_module_1_str.py b/Lib/test/test_dataclasses/dataclass_module_1_str.py similarity index 100% rename from Lib/test/dataclass_module_1_str.py rename to Lib/test/test_dataclasses/dataclass_module_1_str.py diff --git a/Lib/test/dataclass_module_2.py b/Lib/test/test_dataclasses/dataclass_module_2.py similarity index 100% rename from Lib/test/dataclass_module_2.py rename to Lib/test/test_dataclasses/dataclass_module_2.py diff --git a/Lib/test/dataclass_module_2_str.py b/Lib/test/test_dataclasses/dataclass_module_2_str.py similarity index 100% rename from Lib/test/dataclass_module_2_str.py rename to Lib/test/test_dataclasses/dataclass_module_2_str.py diff --git a/Lib/test/dataclass_textanno.py b/Lib/test/test_dataclasses/dataclass_textanno.py similarity index 100% rename from Lib/test/dataclass_textanno.py rename to Lib/test/test_dataclasses/dataclass_textanno.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 09ceccda1dcde5..cf054c19de6cf2 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2134,6 +2134,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_capi \ test/test_cppext \ test/test_ctypes \ + test/test_dataclasses \ test/test_email \ test/test_email/data \ test/test_import \ From ed4ffd74042f5ac34a92514fdef8b61669e309ea Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:11:24 +0200 Subject: [PATCH 0866/1206] [3.12] gh-108303: Move tokenize-related data to Lib/test/tokenizedata (GH-109265) (#109677) * gh-108303: Move tokenize-related data to Lib/test/tokenizedata (GH-109265) (cherry picked from commit 1110c5bc828218086f6397ec05a9312fb73ea30a) * gh-108303: Add `Lib/test/tokenizedata` to `TESTSUBDIRS` (#109314) (cherry picked from commit 42ab2cbd7b5e76e919b70883ae683e789dbd913d) --------- Co-authored-by: Nikita Sobolev --- .gitattributes | 2 +- .pre-commit-config.yaml | 2 +- Lib/test/test_py_compile.py | 16 +++++++--- Lib/test/test_source_encoding.py | 5 ++-- Lib/test/test_tarfile.py | 29 ++++++++++++------- Lib/test/test_tokenize.py | 7 ++--- Lib/test/test_tools/test_reindent.py | 2 +- Lib/test/test_unicode_identifiers.py | 2 +- Lib/test/tokenizedata/__init__.py | 0 Lib/test/{ => tokenizedata}/bad_coding.py | 0 Lib/test/{ => tokenizedata}/bad_coding2.py | 0 Lib/test/{ => tokenizedata}/badsyntax_3131.py | 0 Lib/test/{ => tokenizedata}/coding20731.py | 0 ...-latin1-coding-cookie-and-utf8-bom-sig.txt | 0 ...no-coding-cookie-and-utf8-bom-sig-only.txt | 0 ...utf8-coding-cookie-and-no-utf8-bom-sig.txt | 0 ...ts-utf8-coding-cookie-and-utf8-bom-sig.txt | 0 .../{ => tokenizedata}/tokenize_tests.txt | 0 Makefile.pre.in | 1 + 19 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 Lib/test/tokenizedata/__init__.py rename Lib/test/{ => tokenizedata}/bad_coding.py (100%) rename Lib/test/{ => tokenizedata}/bad_coding2.py (100%) rename Lib/test/{ => tokenizedata}/badsyntax_3131.py (100%) rename Lib/test/{ => tokenizedata}/coding20731.py (100%) rename Lib/test/{ => tokenizedata}/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt (100%) rename Lib/test/{ => tokenizedata}/tokenize_tests-no-coding-cookie-and-utf8-bom-sig-only.txt (100%) rename Lib/test/{ => tokenizedata}/tokenize_tests-utf8-coding-cookie-and-no-utf8-bom-sig.txt (100%) rename Lib/test/{ => tokenizedata}/tokenize_tests-utf8-coding-cookie-and-utf8-bom-sig.txt (100%) rename Lib/test/{ => tokenizedata}/tokenize_tests.txt (100%) diff --git a/.gitattributes b/.gitattributes index 4ed95069442f3d..2bfd4bf9f9b202 100644 --- a/.gitattributes +++ b/.gitattributes @@ -25,7 +25,7 @@ PC/classicAppCompat.* binary [attr]noeol -text Lib/test/cjkencodings/* noeol -Lib/test/coding20731.py noeol +Lib/test/tokenizedata/coding20731.py noeol Lib/test/decimaltestdata/*.decTest noeol Lib/test/test_email/data/*.txt noeol Lib/test/test_importlib/resources/data01/* noeol diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 19f6a03745d2d0..4c1fd20ea921b8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: - id: check-yaml - id: end-of-file-fixer types: [python] - exclude: Lib/test/coding20731.py + exclude: Lib/test/tokenizedata/coding20731.py - id: trailing-whitespace types_or: [c, python, rst] diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py index 5e0a44ad9691ec..c4e6551f605782 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -132,7 +132,9 @@ def test_exceptions_propagate(self): os.chmod(self.directory, mode.st_mode) def test_bad_coding(self): - bad_coding = os.path.join(os.path.dirname(__file__), 'bad_coding2.py') + bad_coding = os.path.join(os.path.dirname(__file__), + 'tokenizedata', + 'bad_coding2.py') with support.captured_stderr(): self.assertIsNone(py_compile.compile(bad_coding, doraise=False)) self.assertFalse(os.path.exists( @@ -195,7 +197,9 @@ def test_invalidation_mode(self): self.assertEqual(flags, 0b1) def test_quiet(self): - bad_coding = os.path.join(os.path.dirname(__file__), 'bad_coding2.py') + bad_coding = os.path.join(os.path.dirname(__file__), + 'tokenizedata', + 'bad_coding2.py') with support.captured_stderr() as stderr: self.assertIsNone(py_compile.compile(bad_coding, doraise=False, quiet=2)) self.assertIsNone(py_compile.compile(bad_coding, doraise=True, quiet=2)) @@ -260,14 +264,18 @@ def test_with_files(self): self.assertTrue(os.path.exists(self.cache_path)) def test_bad_syntax(self): - bad_syntax = os.path.join(os.path.dirname(__file__), 'badsyntax_3131.py') + bad_syntax = os.path.join(os.path.dirname(__file__), + 'tokenizedata', + 'badsyntax_3131.py') rc, stdout, stderr = self.pycompilecmd_failure(bad_syntax) self.assertEqual(rc, 1) self.assertEqual(stdout, b'') self.assertIn(b'SyntaxError', stderr) def test_bad_syntax_with_quiet(self): - bad_syntax = os.path.join(os.path.dirname(__file__), 'badsyntax_3131.py') + bad_syntax = os.path.join(os.path.dirname(__file__), + 'tokenizedata', + 'badsyntax_3131.py') rc, stdout, stderr = self.pycompilecmd_failure('-q', bad_syntax) self.assertEqual(rc, 1) self.assertEqual(stdout, b'') diff --git a/Lib/test/test_source_encoding.py b/Lib/test/test_source_encoding.py index 72c2b47779e005..27871378f1c79e 100644 --- a/Lib/test/test_source_encoding.py +++ b/Lib/test/test_source_encoding.py @@ -68,6 +68,7 @@ def test_issue7820(self): def test_20731(self): sub = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), + 'tokenizedata', 'coding20731.py')], stderr=subprocess.PIPE) err = sub.communicate()[1] @@ -100,10 +101,10 @@ def test_bad_coding2(self): self.verify_bad_module(module_name) def verify_bad_module(self, module_name): - self.assertRaises(SyntaxError, __import__, 'test.' + module_name) + self.assertRaises(SyntaxError, __import__, 'test.tokenizedata.' + module_name) path = os.path.dirname(__file__) - filename = os.path.join(path, module_name + '.py') + filename = os.path.join(path, 'tokenizedata', module_name + '.py') with open(filename, "rb") as fp: bytes = fp.read() self.assertRaises(SyntaxError, compile, bytes, filename, 'exec') diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 013c62630bc44b..5d9714eb287e10 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -2564,16 +2564,17 @@ def tarfilecmd_failure(self, *args): return script_helper.assert_python_failure('-m', 'tarfile', *args) def make_simple_tarfile(self, tar_name): - files = [support.findfile('tokenize_tests.txt'), + files = [support.findfile('tokenize_tests.txt', + subdir='tokenizedata'), support.findfile('tokenize_tests-no-coding-cookie-' - 'and-utf8-bom-sig-only.txt')] + 'and-utf8-bom-sig-only.txt', + subdir='tokenizedata')] self.addCleanup(os_helper.unlink, tar_name) with tarfile.open(tar_name, 'w') as tf: for tardata in files: tf.add(tardata, arcname=os.path.basename(tardata)) def make_evil_tarfile(self, tar_name): - files = [support.findfile('tokenize_tests.txt')] self.addCleanup(os_helper.unlink, tar_name) with tarfile.open(tar_name, 'w') as tf: benign = tarfile.TarInfo('benign') @@ -2654,9 +2655,11 @@ def test_list_command_invalid_file(self): self.assertEqual(rc, 1) def test_create_command(self): - files = [support.findfile('tokenize_tests.txt'), + files = [support.findfile('tokenize_tests.txt', + subdir='tokenizedata'), support.findfile('tokenize_tests-no-coding-cookie-' - 'and-utf8-bom-sig-only.txt')] + 'and-utf8-bom-sig-only.txt', + subdir='tokenizedata')] for opt in '-c', '--create': try: out = self.tarfilecmd(opt, tmpname, *files) @@ -2667,9 +2670,11 @@ def test_create_command(self): os_helper.unlink(tmpname) def test_create_command_verbose(self): - files = [support.findfile('tokenize_tests.txt'), + files = [support.findfile('tokenize_tests.txt', + subdir='tokenizedata'), support.findfile('tokenize_tests-no-coding-cookie-' - 'and-utf8-bom-sig-only.txt')] + 'and-utf8-bom-sig-only.txt', + subdir='tokenizedata')] for opt in '-v', '--verbose': try: out = self.tarfilecmd(opt, '-c', tmpname, *files, @@ -2681,7 +2686,7 @@ def test_create_command_verbose(self): os_helper.unlink(tmpname) def test_create_command_dotless_filename(self): - files = [support.findfile('tokenize_tests.txt')] + files = [support.findfile('tokenize_tests.txt', subdir='tokenizedata')] try: out = self.tarfilecmd('-c', dotlessname, *files) self.assertEqual(out, b'') @@ -2692,7 +2697,7 @@ def test_create_command_dotless_filename(self): def test_create_command_dot_started_filename(self): tar_name = os.path.join(TEMPDIR, ".testtar") - files = [support.findfile('tokenize_tests.txt')] + files = [support.findfile('tokenize_tests.txt', subdir='tokenizedata')] try: out = self.tarfilecmd('-c', tar_name, *files) self.assertEqual(out, b'') @@ -2702,9 +2707,11 @@ def test_create_command_dot_started_filename(self): os_helper.unlink(tar_name) def test_create_command_compressed(self): - files = [support.findfile('tokenize_tests.txt'), + files = [support.findfile('tokenize_tests.txt', + subdir='tokenizedata'), support.findfile('tokenize_tests-no-coding-cookie-' - 'and-utf8-bom-sig-only.txt')] + 'and-utf8-bom-sig-only.txt', + subdir='tokenizedata')] for filetype in (GzipTest, Bz2Test, LzmaTest): if not filetype.open: continue diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index c320478cf3a7bf..40680f004723c5 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1198,7 +1198,7 @@ class TestTokenizerAdheresToPep0263(TestCase): """ def _testFile(self, filename): - path = os.path.join(os.path.dirname(__file__), filename) + path = os.path.join(os.path.dirname(__file__), 'tokenizedata', filename) with open(path, 'rb') as f: TestRoundtrip.check_roundtrip(self, f) @@ -1791,7 +1791,7 @@ def test_roundtrip(self): self.check_roundtrip("if x == 1 : \n" " print(x)\n") - fn = support.findfile("tokenize_tests.txt") + fn = support.findfile("tokenize_tests.txt", subdir="tokenizedata") with open(fn, 'rb') as f: self.check_roundtrip(f) self.check_roundtrip("if x == 1:\n" @@ -1846,8 +1846,7 @@ def test_random_files(self): # pass the '-ucpu' option to process the full directory. import glob, random - fn = support.findfile("tokenize_tests.txt") - tempdir = os.path.dirname(fn) or os.curdir + tempdir = os.path.dirname(__file__) or os.curdir testfiles = glob.glob(os.path.join(glob.escape(tempdir), "test*.py")) # Tokenize is broken on test_pep3131.py because regular expressions are diff --git a/Lib/test/test_tools/test_reindent.py b/Lib/test/test_tools/test_reindent.py index 3b0c793a38e4da..64e31c2b7703c0 100644 --- a/Lib/test/test_tools/test_reindent.py +++ b/Lib/test/test_tools/test_reindent.py @@ -25,7 +25,7 @@ def test_help(self): self.assertGreater(err, b'') def test_reindent_file_with_bad_encoding(self): - bad_coding_path = findfile('bad_coding.py') + bad_coding_path = findfile('bad_coding.py', subdir='tokenizedata') rc, out, err = assert_python_ok(self.script, '-r', bad_coding_path) self.assertEqual(out, b'') self.assertNotEqual(err, b'') diff --git a/Lib/test/test_unicode_identifiers.py b/Lib/test/test_unicode_identifiers.py index 5b9ced5d1cb837..63c6c055824b20 100644 --- a/Lib/test/test_unicode_identifiers.py +++ b/Lib/test/test_unicode_identifiers.py @@ -19,7 +19,7 @@ def test_non_bmp_normalized(self): def test_invalid(self): try: - from test import badsyntax_3131 + from test.tokenizedata import badsyntax_3131 except SyntaxError as err: self.assertEqual(str(err), "invalid character '€' (U+20AC) (badsyntax_3131.py, line 2)") diff --git a/Lib/test/tokenizedata/__init__.py b/Lib/test/tokenizedata/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/Lib/test/bad_coding.py b/Lib/test/tokenizedata/bad_coding.py similarity index 100% rename from Lib/test/bad_coding.py rename to Lib/test/tokenizedata/bad_coding.py diff --git a/Lib/test/bad_coding2.py b/Lib/test/tokenizedata/bad_coding2.py similarity index 100% rename from Lib/test/bad_coding2.py rename to Lib/test/tokenizedata/bad_coding2.py diff --git a/Lib/test/badsyntax_3131.py b/Lib/test/tokenizedata/badsyntax_3131.py similarity index 100% rename from Lib/test/badsyntax_3131.py rename to Lib/test/tokenizedata/badsyntax_3131.py diff --git a/Lib/test/coding20731.py b/Lib/test/tokenizedata/coding20731.py similarity index 100% rename from Lib/test/coding20731.py rename to Lib/test/tokenizedata/coding20731.py diff --git a/Lib/test/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt b/Lib/test/tokenizedata/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt similarity index 100% rename from Lib/test/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt rename to Lib/test/tokenizedata/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt diff --git a/Lib/test/tokenize_tests-no-coding-cookie-and-utf8-bom-sig-only.txt b/Lib/test/tokenizedata/tokenize_tests-no-coding-cookie-and-utf8-bom-sig-only.txt similarity index 100% rename from Lib/test/tokenize_tests-no-coding-cookie-and-utf8-bom-sig-only.txt rename to Lib/test/tokenizedata/tokenize_tests-no-coding-cookie-and-utf8-bom-sig-only.txt diff --git a/Lib/test/tokenize_tests-utf8-coding-cookie-and-no-utf8-bom-sig.txt b/Lib/test/tokenizedata/tokenize_tests-utf8-coding-cookie-and-no-utf8-bom-sig.txt similarity index 100% rename from Lib/test/tokenize_tests-utf8-coding-cookie-and-no-utf8-bom-sig.txt rename to Lib/test/tokenizedata/tokenize_tests-utf8-coding-cookie-and-no-utf8-bom-sig.txt diff --git a/Lib/test/tokenize_tests-utf8-coding-cookie-and-utf8-bom-sig.txt b/Lib/test/tokenizedata/tokenize_tests-utf8-coding-cookie-and-utf8-bom-sig.txt similarity index 100% rename from Lib/test/tokenize_tests-utf8-coding-cookie-and-utf8-bom-sig.txt rename to Lib/test/tokenizedata/tokenize_tests-utf8-coding-cookie-and-utf8-bom-sig.txt diff --git a/Lib/test/tokenize_tests.txt b/Lib/test/tokenizedata/tokenize_tests.txt similarity index 100% rename from Lib/test/tokenize_tests.txt rename to Lib/test/tokenizedata/tokenize_tests.txt diff --git a/Makefile.pre.in b/Makefile.pre.in index cf054c19de6cf2..7418ddf1500dc9 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2226,6 +2226,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_zipfile/_path \ test/test_zoneinfo \ test/test_zoneinfo/data \ + test/tokenizedata \ test/tracedmodules \ test/typinganndata \ test/xmltestdata \ From 5baa8af8daa65a819b41974391efbe5f9a572fa6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:12:54 +0200 Subject: [PATCH 0867/1206] [3.12] gh-108303: Move `test_future` into its own test_future_stmt subdir (#109368) (#109679) gh-108303: Move `test_future` into its own test_future_stmt subdir (#109368) (cherry picked from commit 82505dc351b2f7e37aa395218709b432d83292cd) Co-authored-by: Nikita Sobolev --- Lib/test/libregrtest/runtest.py | 1 + Lib/test/test_future_stmt/__init__.py | 6 +++ .../badsyntax_future10.py | 0 .../badsyntax_future3.py | 0 .../badsyntax_future4.py | 0 .../badsyntax_future5.py | 0 .../badsyntax_future6.py | 0 .../badsyntax_future7.py | 0 .../badsyntax_future8.py | 0 .../badsyntax_future9.py | 0 .../{ => test_future_stmt}/future_test1.py | 0 .../{ => test_future_stmt}/future_test2.py | 0 .../{ => test_future_stmt}/test_future.py | 48 +++++++++++-------- .../test_future_flags.py} | 0 .../test_future_multiple_features.py} | 0 .../test_future_multiple_imports.py} | 0 .../test_future_single_import.py} | 0 Makefile.pre.in | 1 + 18 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 Lib/test/test_future_stmt/__init__.py rename Lib/test/{ => test_future_stmt}/badsyntax_future10.py (100%) rename Lib/test/{ => test_future_stmt}/badsyntax_future3.py (100%) rename Lib/test/{ => test_future_stmt}/badsyntax_future4.py (100%) rename Lib/test/{ => test_future_stmt}/badsyntax_future5.py (100%) rename Lib/test/{ => test_future_stmt}/badsyntax_future6.py (100%) rename Lib/test/{ => test_future_stmt}/badsyntax_future7.py (100%) rename Lib/test/{ => test_future_stmt}/badsyntax_future8.py (100%) rename Lib/test/{ => test_future_stmt}/badsyntax_future9.py (100%) rename Lib/test/{ => test_future_stmt}/future_test1.py (100%) rename Lib/test/{ => test_future_stmt}/future_test2.py (100%) rename Lib/test/{ => test_future_stmt}/test_future.py (91%) rename Lib/test/{test___future__.py => test_future_stmt/test_future_flags.py} (100%) rename Lib/test/{test_future5.py => test_future_stmt/test_future_multiple_features.py} (100%) rename Lib/test/{test_future4.py => test_future_stmt/test_future_multiple_imports.py} (100%) rename Lib/test/{test_future3.py => test_future_stmt/test_future_single_import.py} (100%) diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index 16ae04191da768..8acce564e61a57 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -232,6 +232,7 @@ def iter_tests(self): SPLITTESTDIRS = { "test_asyncio", "test_concurrent_futures", + "test_future_stmt", "test_multiprocessing_fork", "test_multiprocessing_forkserver", "test_multiprocessing_spawn", diff --git a/Lib/test/test_future_stmt/__init__.py b/Lib/test/test_future_stmt/__init__.py new file mode 100644 index 00000000000000..f2a39a3fe29c7f --- /dev/null +++ b/Lib/test/test_future_stmt/__init__.py @@ -0,0 +1,6 @@ +import os +from test import support + + +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/badsyntax_future10.py b/Lib/test/test_future_stmt/badsyntax_future10.py similarity index 100% rename from Lib/test/badsyntax_future10.py rename to Lib/test/test_future_stmt/badsyntax_future10.py diff --git a/Lib/test/badsyntax_future3.py b/Lib/test/test_future_stmt/badsyntax_future3.py similarity index 100% rename from Lib/test/badsyntax_future3.py rename to Lib/test/test_future_stmt/badsyntax_future3.py diff --git a/Lib/test/badsyntax_future4.py b/Lib/test/test_future_stmt/badsyntax_future4.py similarity index 100% rename from Lib/test/badsyntax_future4.py rename to Lib/test/test_future_stmt/badsyntax_future4.py diff --git a/Lib/test/badsyntax_future5.py b/Lib/test/test_future_stmt/badsyntax_future5.py similarity index 100% rename from Lib/test/badsyntax_future5.py rename to Lib/test/test_future_stmt/badsyntax_future5.py diff --git a/Lib/test/badsyntax_future6.py b/Lib/test/test_future_stmt/badsyntax_future6.py similarity index 100% rename from Lib/test/badsyntax_future6.py rename to Lib/test/test_future_stmt/badsyntax_future6.py diff --git a/Lib/test/badsyntax_future7.py b/Lib/test/test_future_stmt/badsyntax_future7.py similarity index 100% rename from Lib/test/badsyntax_future7.py rename to Lib/test/test_future_stmt/badsyntax_future7.py diff --git a/Lib/test/badsyntax_future8.py b/Lib/test/test_future_stmt/badsyntax_future8.py similarity index 100% rename from Lib/test/badsyntax_future8.py rename to Lib/test/test_future_stmt/badsyntax_future8.py diff --git a/Lib/test/badsyntax_future9.py b/Lib/test/test_future_stmt/badsyntax_future9.py similarity index 100% rename from Lib/test/badsyntax_future9.py rename to Lib/test/test_future_stmt/badsyntax_future9.py diff --git a/Lib/test/future_test1.py b/Lib/test/test_future_stmt/future_test1.py similarity index 100% rename from Lib/test/future_test1.py rename to Lib/test/test_future_stmt/future_test1.py diff --git a/Lib/test/future_test2.py b/Lib/test/test_future_stmt/future_test2.py similarity index 100% rename from Lib/test/future_test2.py rename to Lib/test/test_future_stmt/future_test2.py diff --git a/Lib/test/test_future.py b/Lib/test/test_future_stmt/test_future.py similarity index 91% rename from Lib/test/test_future.py rename to Lib/test/test_future_stmt/test_future.py index 4730bfafbd9cfe..8e67bcd72c91c5 100644 --- a/Lib/test/test_future.py +++ b/Lib/test/test_future_stmt/test_future.py @@ -25,57 +25,71 @@ def check_syntax_error(self, err, basename, lineno, offset=1): self.assertEqual(err.offset, offset) def test_future1(self): - with import_helper.CleanImport('future_test1'): - from test import future_test1 + with import_helper.CleanImport('test.test_future_stmt.future_test1'): + from test.test_future_stmt import future_test1 self.assertEqual(future_test1.result, 6) def test_future2(self): - with import_helper.CleanImport('future_test2'): - from test import future_test2 + with import_helper.CleanImport('test.test_future_stmt.future_test2'): + from test.test_future_stmt import future_test2 self.assertEqual(future_test2.result, 6) - def test_future3(self): - with import_helper.CleanImport('test_future3'): - from test import test_future3 + def test_future_single_import(self): + with import_helper.CleanImport( + 'test.test_future_stmt.test_future_single_import', + ): + from test.test_future_stmt import test_future_single_import + + def test_future_multiple_imports(self): + with import_helper.CleanImport( + 'test.test_future_stmt.test_future_multiple_imports', + ): + from test.test_future_stmt import test_future_multiple_imports + + def test_future_multiple_features(self): + with import_helper.CleanImport( + "test.test_future_stmt.test_future_multiple_features", + ): + from test.test_future_stmt import test_future_multiple_features def test_badfuture3(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future3 + from test.test_future_stmt import badsyntax_future3 self.check_syntax_error(cm.exception, "badsyntax_future3", 3) def test_badfuture4(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future4 + from test.test_future_stmt import badsyntax_future4 self.check_syntax_error(cm.exception, "badsyntax_future4", 3) def test_badfuture5(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future5 + from test.test_future_stmt import badsyntax_future5 self.check_syntax_error(cm.exception, "badsyntax_future5", 4) def test_badfuture6(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future6 + from test.test_future_stmt import badsyntax_future6 self.check_syntax_error(cm.exception, "badsyntax_future6", 3) def test_badfuture7(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future7 + from test.test_future_stmt import badsyntax_future7 self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 54) def test_badfuture8(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future8 + from test.test_future_stmt import badsyntax_future8 self.check_syntax_error(cm.exception, "badsyntax_future8", 3) def test_badfuture9(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future9 + from test.test_future_stmt import badsyntax_future9 self.check_syntax_error(cm.exception, "badsyntax_future9", 3) def test_badfuture10(self): with self.assertRaises(SyntaxError) as cm: - from test import badsyntax_future10 + from test.test_future_stmt import badsyntax_future10 self.check_syntax_error(cm.exception, "badsyntax_future10", 3) def test_ensure_flags_dont_clash(self): @@ -113,10 +127,6 @@ def test_parserhack(self): else: self.fail("syntax error didn't occur") - def test_multiple_features(self): - with import_helper.CleanImport("test.test_future5"): - from test import test_future5 - def test_unicode_literals_exec(self): scope = {} exec("from __future__ import unicode_literals; x = ''", {}, scope) diff --git a/Lib/test/test___future__.py b/Lib/test/test_future_stmt/test_future_flags.py similarity index 100% rename from Lib/test/test___future__.py rename to Lib/test/test_future_stmt/test_future_flags.py diff --git a/Lib/test/test_future5.py b/Lib/test/test_future_stmt/test_future_multiple_features.py similarity index 100% rename from Lib/test/test_future5.py rename to Lib/test/test_future_stmt/test_future_multiple_features.py diff --git a/Lib/test/test_future4.py b/Lib/test/test_future_stmt/test_future_multiple_imports.py similarity index 100% rename from Lib/test/test_future4.py rename to Lib/test/test_future_stmt/test_future_multiple_imports.py diff --git a/Lib/test/test_future3.py b/Lib/test/test_future_stmt/test_future_single_import.py similarity index 100% rename from Lib/test/test_future3.py rename to Lib/test/test_future_stmt/test_future_single_import.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 7418ddf1500dc9..2599d20a111868 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2137,6 +2137,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_dataclasses \ test/test_email \ test/test_email/data \ + test/test_future_stmt \ test/test_import \ test/test_import/data \ test/test_import/data/circular_imports \ From 05b139b599bbe2125bd81eb7ac3e55743c01d974 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:14:30 -0700 Subject: [PATCH 0868/1206] [3.12] gh-109582: test_fork_signal_handling should wait for event (GH-109605) (#109695) gh-109582: test_fork_signal_handling should wait for event (GH-109605) Sometimes the child_handled event was missing because either the child quits before it gets a chance to handle the signal, or the parent asserts before the event notification is delivered via IPC. Synchronize explicitly to avoid this. (cherry picked from commit 608c1f3083ea1e06d383ef1a9878a9758903de4b) Co-authored-by: Davide Rizzo --- Lib/test/test_asyncio/test_unix_events.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index cdf3eaac68af15..7322be597ae2d2 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -11,9 +11,11 @@ import stat import sys import threading +import time import unittest from unittest import mock import warnings +from test import support from test.support import os_helper from test.support import socket_helper from test.support import wait_process @@ -1911,8 +1913,14 @@ def test_fork_signal_handling(self): parent_handled = manager.Event() def child_main(): - signal.signal(signal.SIGTERM, lambda *args: child_handled.set()) + def on_sigterm(*args): + child_handled.set() + sys.exit() + + signal.signal(signal.SIGTERM, on_sigterm) child_started.set() + while True: + time.sleep(1) async def main(): loop = asyncio.get_running_loop() @@ -1922,7 +1930,7 @@ async def main(): process.start() child_started.wait() os.kill(process.pid, signal.SIGTERM) - process.join() + process.join(timeout=support.SHORT_TIMEOUT) async def func(): await asyncio.sleep(0.1) @@ -1933,6 +1941,7 @@ async def func(): asyncio.run(main()) + child_handled.wait(timeout=support.SHORT_TIMEOUT) self.assertFalse(parent_handled.is_set()) self.assertTrue(child_handled.is_set()) From 84ef145d854832f8521ea38468071ad210b6365c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:16:25 +0200 Subject: [PATCH 0869/1206] [3.12] gh-108948: Skip test_tarfile.test_modes() on EFTYPE error (#109697) (#109698) gh-108948: Skip test_tarfile.test_modes() on EFTYPE error (#109697) On FreeBSD, regular users cannot set the sticky bit. Skip the test if chmod() fails with EFTYPE error. (cherry picked from commit 26e06ad617bb416201c769fea91cd33d544c6a1c) --- Lib/test/test_tarfile.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 5d9714eb287e10..c5fc76dc0207d4 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1,3 +1,4 @@ +import errno import sys import os import io @@ -3798,9 +3799,21 @@ def test_modes(self): tmp_filename = os.path.join(TEMPDIR, "tmp.file") with open(tmp_filename, 'w'): pass - os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) - have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) - os.unlink(tmp_filename) + try: + try: + os.chmod(tmp_filename, + os.stat(tmp_filename).st_mode | stat.S_ISVTX) + except OSError as exc: + if exc.errno == getattr(errno, "EFTYPE", 0): + # gh-108948: On FreeBSD, regular users cannot set + # the sticky bit. + self.skipTest("chmod() failed with EFTYPE: " + "regular users cannot set sticky bit") + else: + raise + have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + finally: + os.unlink(tmp_filename) os.mkdir(tmp_filename) os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) From 551aa6ab9419109a80ad53900ad930e9b7f2e40d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:18:41 -0700 Subject: [PATCH 0870/1206] [3.12] gh-106584: Fix exit code for unittest in Python 3.12 (GH-106588) (#109725) gh-106584: Fix exit code for unittest in Python 3.12 (GH-106588) (cherry picked from commit 8fc071345b50dd3de61ebeeaa287ccef21d061b2) Co-authored-by: EliseevEgor Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> Co-authored-by: Nikita Sobolev --- Lib/test/test_unittest/test_discovery.py | 2 +- Lib/test/test_unittest/test_skipping.py | 12 ++++++------ Lib/unittest/case.py | 4 +++- Lib/unittest/result.py | 10 ++++++---- .../2023-07-11-08-56-40.gh-issue-106584.g-SBtC.rst | 2 ++ 5 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-11-08-56-40.gh-issue-106584.g-SBtC.rst diff --git a/Lib/test/test_unittest/test_discovery.py b/Lib/test/test_unittest/test_discovery.py index 004898ed431834..dcb72d73efceab 100644 --- a/Lib/test/test_unittest/test_discovery.py +++ b/Lib/test/test_unittest/test_discovery.py @@ -571,7 +571,7 @@ def _get_module_from_name(name): result = unittest.TestResult() suite.run(result) self.assertEqual(len(result.skipped), 1) - self.assertEqual(result.testsRun, 1) + self.assertEqual(result.testsRun, 0) self.assertEqual(import_calls, ['my_package']) # Check picklability diff --git a/Lib/test/test_unittest/test_skipping.py b/Lib/test/test_unittest/test_skipping.py index f146dcac18ecc0..1a6af06d32b433 100644 --- a/Lib/test/test_unittest/test_skipping.py +++ b/Lib/test/test_unittest/test_skipping.py @@ -103,16 +103,16 @@ def test_dont_skip(self): pass result = LoggingResult(events) self.assertIs(suite.run(result), result) self.assertEqual(len(result.skipped), 1) - expected = ['startTest', 'addSkip', 'stopTest', - 'startTest', 'addSuccess', 'stopTest'] + expected = ['addSkip', 'stopTest', 'startTest', + 'addSuccess', 'stopTest'] self.assertEqual(events, expected) - self.assertEqual(result.testsRun, 2) + self.assertEqual(result.testsRun, 1) self.assertEqual(result.skipped, [(test_do_skip, "testing")]) self.assertTrue(result.wasSuccessful()) events = [] result = test_do_skip.run() - self.assertEqual(events, ['startTestRun', 'startTest', 'addSkip', + self.assertEqual(events, ['startTestRun', 'addSkip', 'stopTest', 'stopTestRun']) self.assertEqual(result.skipped, [(test_do_skip, "testing")]) @@ -135,13 +135,13 @@ def test_1(self): test = Foo("test_1") suite = unittest.TestSuite([test]) self.assertIs(suite.run(result), result) - self.assertEqual(events, ['startTest', 'addSkip', 'stopTest']) + self.assertEqual(events, ['addSkip', 'stopTest']) self.assertEqual(result.skipped, [(test, "testing")]) self.assertEqual(record, []) events = [] result = test.run() - self.assertEqual(events, ['startTestRun', 'startTest', 'addSkip', + self.assertEqual(events, ['startTestRun', 'addSkip', 'stopTest', 'stopTestRun']) self.assertEqual(result.skipped, [(test, "testing")]) self.assertEqual(record, []) diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index 001b640dc43ad6..811557498bb30e 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -606,7 +606,6 @@ def run(self, result=None): else: stopTestRun = None - result.startTest(self) try: testMethod = getattr(self, self._testMethodName) if (getattr(self.__class__, "__unittest_skip__", False) or @@ -617,6 +616,9 @@ def run(self, result=None): _addSkip(result, self, skip_why) return result + # Increase the number of tests only if it hasn't been skipped + result.startTest(self) + expecting_failure = ( getattr(self, "__unittest_expecting_failure__", False) or getattr(testMethod, "__unittest_expecting_failure__", False) diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py index 3ace0a5b7bf2ef..9e56f658027f4d 100644 --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -97,10 +97,12 @@ def _restoreStdout(self): sys.stdout = self._original_stdout sys.stderr = self._original_stderr - self._stdout_buffer.seek(0) - self._stdout_buffer.truncate() - self._stderr_buffer.seek(0) - self._stderr_buffer.truncate() + if self._stdout_buffer is not None: + self._stdout_buffer.seek(0) + self._stdout_buffer.truncate() + if self._stderr_buffer is not None: + self._stderr_buffer.seek(0) + self._stderr_buffer.truncate() def stopTestRun(self): """Called once after all tests are executed. diff --git a/Misc/NEWS.d/next/Library/2023-07-11-08-56-40.gh-issue-106584.g-SBtC.rst b/Misc/NEWS.d/next/Library/2023-07-11-08-56-40.gh-issue-106584.g-SBtC.rst new file mode 100644 index 00000000000000..a13b61bf1c121b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-11-08-56-40.gh-issue-106584.g-SBtC.rst @@ -0,0 +1,2 @@ +Fix exit code for ``unittest`` if all tests are skipped. +Patch by Egor Eliseev. From c7cbd82e62d22b6b1c6d4e95dbbd1db16c321533 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:21:51 -0700 Subject: [PATCH 0871/1206] [3.12] gh-109709: Fix asyncio test_stdin_broken_pipe() (GH-109710) (#109731) gh-109709: Fix asyncio test_stdin_broken_pipe() (GH-109710) Replace harcoded sleep of 500 ms with synchronization using a pipe. Fix also Process._feed_stdin(): catch also BrokenPipeError on stdin.write(input), not only on stdin.drain(). (cherry picked from commit cbbdf2c1440c804adcfc32ea0470865b3b3b8eb2) Co-authored-by: Victor Stinner --- Lib/asyncio/subprocess.py | 14 ++++--- Lib/test/test_asyncio/test_subprocess.py | 52 +++++++++++++++++++----- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/Lib/asyncio/subprocess.py b/Lib/asyncio/subprocess.py index c4e5ba2061cffc..043359bbd03f8a 100644 --- a/Lib/asyncio/subprocess.py +++ b/Lib/asyncio/subprocess.py @@ -147,15 +147,17 @@ def kill(self): async def _feed_stdin(self, input): debug = self._loop.get_debug() - if input is not None: - self.stdin.write(input) - if debug: - logger.debug( - '%r communicate: feed stdin (%s bytes)', self, len(input)) try: + if input is not None: + self.stdin.write(input) + if debug: + logger.debug( + '%r communicate: feed stdin (%s bytes)', self, len(input)) + await self.stdin.drain() except (BrokenPipeError, ConnectionResetError) as exc: - # communicate() ignores BrokenPipeError and ConnectionResetError + # communicate() ignores BrokenPipeError and ConnectionResetError. + # write() and drain() can raise these exceptions. if debug: logger.debug('%r communicate: stdin got %r', self, exc) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 429ef16fdb0e05..dc5a48d500e8d5 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -1,6 +1,7 @@ import os import signal import sys +import textwrap import unittest import warnings from unittest import mock @@ -12,9 +13,14 @@ from test import support from test.support import os_helper -if sys.platform != 'win32': + +MS_WINDOWS = (sys.platform == 'win32') +if MS_WINDOWS: + import msvcrt +else: from asyncio import unix_events + if support.check_sanitizer(address=True): raise unittest.SkipTest("Exposes ASAN flakiness in GitHub CI") @@ -270,26 +276,43 @@ async def send_signal(proc): finally: signal.signal(signal.SIGHUP, old_handler) - def prepare_broken_pipe_test(self): + def test_stdin_broken_pipe(self): # buffer large enough to feed the whole pipe buffer large_data = b'x' * support.PIPE_MAX_SIZE + rfd, wfd = os.pipe() + self.addCleanup(os.close, rfd) + self.addCleanup(os.close, wfd) + if MS_WINDOWS: + handle = msvcrt.get_osfhandle(rfd) + os.set_handle_inheritable(handle, True) + code = textwrap.dedent(f''' + import os, msvcrt + handle = {handle} + fd = msvcrt.open_osfhandle(handle, os.O_RDONLY) + os.read(fd, 1) + ''') + from subprocess import STARTUPINFO + startupinfo = STARTUPINFO() + startupinfo.lpAttributeList = {"handle_list": [handle]} + kwargs = dict(startupinfo=startupinfo) + else: + code = f'import os; fd = {rfd}; os.read(fd, 1)' + kwargs = dict(pass_fds=(rfd,)) + # the program ends before the stdin can be fed proc = self.loop.run_until_complete( asyncio.create_subprocess_exec( - sys.executable, '-c', 'pass', + sys.executable, '-c', code, stdin=subprocess.PIPE, + **kwargs ) ) - return (proc, large_data) - - def test_stdin_broken_pipe(self): - proc, large_data = self.prepare_broken_pipe_test() - async def write_stdin(proc, data): - await asyncio.sleep(0.5) proc.stdin.write(data) + # Only exit the child process once the write buffer is filled + os.write(wfd, b'go') await proc.stdin.drain() coro = write_stdin(proc, large_data) @@ -300,7 +323,16 @@ async def write_stdin(proc, data): self.loop.run_until_complete(proc.wait()) def test_communicate_ignore_broken_pipe(self): - proc, large_data = self.prepare_broken_pipe_test() + # buffer large enough to feed the whole pipe buffer + large_data = b'x' * support.PIPE_MAX_SIZE + + # the program ends before the stdin can be fed + proc = self.loop.run_until_complete( + asyncio.create_subprocess_exec( + sys.executable, '-c', 'pass', + stdin=subprocess.PIPE, + ) + ) # communicate() must ignore BrokenPipeError when feeding stdin self.loop.set_exception_handler(lambda loop, msg: None) From f6cb2e48152fc7b44d55583ad8b80b653085bae2 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Mon, 2 Oct 2023 16:22:07 +0100 Subject: [PATCH 0872/1206] [3.12] gh-109596: Ensure repeated rules in the grammar are not allowed and fix incorrect soft keywords (GH-109606). (#109752) (cherry picked from commit b28ffaa193efc66f46ab90d383279174a11a11d7) --- Grammar/python.gram | 11 +- Include/compile.h | 3 - Lib/test/test_peg_generator/test_pegen.py | 9 + ...-09-20-13-18-08.gh-issue-109596.RG0K2G.rst | 3 + Parser/parser.c | 2362 ++++++++--------- Parser/pegen_errors.c | 26 - Tools/peg_generator/pegen/grammar.py | 8 +- 7 files changed, 1203 insertions(+), 1219 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-20-13-18-08.gh-issue-109596.RG0K2G.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index f88dc2bdd92327..ed0b326fa58642 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -19,8 +19,6 @@ _PyPegen_parse(Parser *p) result = eval_rule(p); } else if (p->start_rule == Py_func_type_input) { result = func_type_rule(p); - } else if (p->start_rule == Py_fstring_input) { - result = fstring_rule(p); } return result; @@ -89,7 +87,6 @@ file[mod_ty]: a=[statements] ENDMARKER { _PyPegen_make_module(p, a) } interactive[mod_ty]: a=statement_newline { _PyAST_Interactive(a, p->arena) } eval[mod_ty]: a=expressions NEWLINE* ENDMARKER { _PyAST_Expression(a, p->arena) } func_type[mod_ty]: '(' a=[type_expressions] ')' '->' b=expression NEWLINE* ENDMARKER { _PyAST_FunctionType(a, b, p->arena) } -fstring[expr_ty]: star_expressions # GENERAL STATEMENTS # ================== @@ -647,20 +644,20 @@ type_param_seq[asdl_type_param_seq*]: a[asdl_type_param_seq*]=','.type_param+ [' type_param[type_param_ty] (memo): | a=NAME b=[type_param_bound] { _PyAST_TypeVar(a->v.Name.id, b, EXTRA) } - | '*' a=NAME colon=":" e=expression { + | '*' a=NAME colon=':' e=expression { RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind ? "cannot use constraints with TypeVarTuple" : "cannot use bound with TypeVarTuple") } | '*' a=NAME { _PyAST_TypeVarTuple(a->v.Name.id, EXTRA) } - | '**' a=NAME colon=":" e=expression { + | '**' a=NAME colon=':' e=expression { RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind ? "cannot use constraints with ParamSpec" : "cannot use bound with ParamSpec") } | '**' a=NAME { _PyAST_ParamSpec(a->v.Name.id, EXTRA) } -type_param_bound[expr_ty]: ":" e=expression { e } +type_param_bound[expr_ty]: ':' e=expression { e } # EXPRESSIONS # ----------- @@ -915,7 +912,7 @@ fstring_middle[expr_ty]: | fstring_replacement_field | t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) } fstring_replacement_field[expr_ty]: - | '{' a=(yield_expr | star_expressions) debug_expr="="? conversion=[fstring_conversion] format=[fstring_full_format_spec] rbrace='}' { + | '{' a=(yield_expr | star_expressions) debug_expr='='? conversion=[fstring_conversion] format=[fstring_full_format_spec] rbrace='}' { _PyPegen_formatted_value(p, a, debug_expr, conversion, format, rbrace, EXTRA) } | invalid_replacement_field fstring_conversion[ResultTokenWithMetadata*]: diff --git a/Include/compile.h b/Include/compile.h index 3c5acd7209f763..52d0bc76c9fca4 100644 --- a/Include/compile.h +++ b/Include/compile.h @@ -10,9 +10,6 @@ extern "C" { #define Py_eval_input 258 #define Py_func_type_input 345 -/* This doesn't need to match anything */ -#define Py_fstring_input 800 - #ifndef Py_LIMITED_API # define Py_CPYTHON_COMPILE_H # include "cpython/compile.h" diff --git a/Lib/test/test_peg_generator/test_pegen.py b/Lib/test/test_peg_generator/test_pegen.py index d92da7b29bff98..ec61199d6e35e3 100644 --- a/Lib/test/test_peg_generator/test_pegen.py +++ b/Lib/test/test_peg_generator/test_pegen.py @@ -42,6 +42,15 @@ def test_parse_grammar(self) -> None: ) self.assertEqual(repr(rules["term"]), expected_repr) + def test_repeated_rules(self) -> None: + grammar_source = """ + start: the_rule NEWLINE + the_rule: 'b' NEWLINE + the_rule: 'a' NEWLINE + """ + with self.assertRaisesRegex(GrammarError, "Repeated rule 'the_rule'"): + parse_string(grammar_source, GrammarParser) + def test_long_rule_str(self) -> None: grammar_source = """ start: zero | one | one zero | one one | one zero zero | one zero one | one one zero | one one one diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-20-13-18-08.gh-issue-109596.RG0K2G.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-20-13-18-08.gh-issue-109596.RG0K2G.rst new file mode 100644 index 00000000000000..23ef73d578651d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-20-13-18-08.gh-issue-109596.RG0K2G.rst @@ -0,0 +1,3 @@ +Fix some tokens in the grammar that were incorrectly marked as soft +keywords. Also fix some repeated rule names and ensure that repeated rules +are not allowed. Patch by Pablo Galindo diff --git a/Parser/parser.c b/Parser/parser.c index 5d2adf7417b2ec..f7229cb91681aa 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -82,159 +82,159 @@ static char *soft_keywords[] = { #define interactive_type 1001 #define eval_type 1002 #define func_type_type 1003 -#define fstring_type 1004 -#define statements_type 1005 -#define statement_type 1006 -#define statement_newline_type 1007 -#define simple_stmts_type 1008 -#define simple_stmt_type 1009 -#define compound_stmt_type 1010 -#define assignment_type 1011 -#define annotated_rhs_type 1012 -#define augassign_type 1013 -#define return_stmt_type 1014 -#define raise_stmt_type 1015 -#define global_stmt_type 1016 -#define nonlocal_stmt_type 1017 -#define del_stmt_type 1018 -#define yield_stmt_type 1019 -#define assert_stmt_type 1020 -#define import_stmt_type 1021 -#define import_name_type 1022 -#define import_from_type 1023 -#define import_from_targets_type 1024 -#define import_from_as_names_type 1025 -#define import_from_as_name_type 1026 -#define dotted_as_names_type 1027 -#define dotted_as_name_type 1028 -#define dotted_name_type 1029 // Left-recursive -#define block_type 1030 -#define decorators_type 1031 -#define class_def_type 1032 -#define class_def_raw_type 1033 -#define function_def_type 1034 -#define function_def_raw_type 1035 -#define params_type 1036 -#define parameters_type 1037 -#define slash_no_default_type 1038 -#define slash_with_default_type 1039 -#define star_etc_type 1040 -#define kwds_type 1041 -#define param_no_default_type 1042 -#define param_no_default_star_annotation_type 1043 -#define param_with_default_type 1044 -#define param_maybe_default_type 1045 -#define param_type 1046 -#define param_star_annotation_type 1047 -#define annotation_type 1048 -#define star_annotation_type 1049 -#define default_type 1050 -#define if_stmt_type 1051 -#define elif_stmt_type 1052 -#define else_block_type 1053 -#define while_stmt_type 1054 -#define for_stmt_type 1055 -#define with_stmt_type 1056 -#define with_item_type 1057 -#define try_stmt_type 1058 -#define except_block_type 1059 -#define except_star_block_type 1060 -#define finally_block_type 1061 -#define match_stmt_type 1062 -#define subject_expr_type 1063 -#define case_block_type 1064 -#define guard_type 1065 -#define patterns_type 1066 -#define pattern_type 1067 -#define as_pattern_type 1068 -#define or_pattern_type 1069 -#define closed_pattern_type 1070 -#define literal_pattern_type 1071 -#define literal_expr_type 1072 -#define complex_number_type 1073 -#define signed_number_type 1074 -#define signed_real_number_type 1075 -#define real_number_type 1076 -#define imaginary_number_type 1077 -#define capture_pattern_type 1078 -#define pattern_capture_target_type 1079 -#define wildcard_pattern_type 1080 -#define value_pattern_type 1081 -#define attr_type 1082 // Left-recursive -#define name_or_attr_type 1083 // Left-recursive -#define group_pattern_type 1084 -#define sequence_pattern_type 1085 -#define open_sequence_pattern_type 1086 -#define maybe_sequence_pattern_type 1087 -#define maybe_star_pattern_type 1088 -#define star_pattern_type 1089 -#define mapping_pattern_type 1090 -#define items_pattern_type 1091 -#define key_value_pattern_type 1092 -#define double_star_pattern_type 1093 -#define class_pattern_type 1094 -#define positional_patterns_type 1095 -#define keyword_patterns_type 1096 -#define keyword_pattern_type 1097 -#define type_alias_type 1098 -#define type_params_type 1099 -#define type_param_seq_type 1100 -#define type_param_type 1101 -#define type_param_bound_type 1102 -#define expressions_type 1103 -#define expression_type 1104 -#define yield_expr_type 1105 -#define star_expressions_type 1106 -#define star_expression_type 1107 -#define star_named_expressions_type 1108 -#define star_named_expression_type 1109 -#define assignment_expression_type 1110 -#define named_expression_type 1111 -#define disjunction_type 1112 -#define conjunction_type 1113 -#define inversion_type 1114 -#define comparison_type 1115 -#define compare_op_bitwise_or_pair_type 1116 -#define eq_bitwise_or_type 1117 -#define noteq_bitwise_or_type 1118 -#define lte_bitwise_or_type 1119 -#define lt_bitwise_or_type 1120 -#define gte_bitwise_or_type 1121 -#define gt_bitwise_or_type 1122 -#define notin_bitwise_or_type 1123 -#define in_bitwise_or_type 1124 -#define isnot_bitwise_or_type 1125 -#define is_bitwise_or_type 1126 -#define bitwise_or_type 1127 // Left-recursive -#define bitwise_xor_type 1128 // Left-recursive -#define bitwise_and_type 1129 // Left-recursive -#define shift_expr_type 1130 // Left-recursive -#define sum_type 1131 // Left-recursive -#define term_type 1132 // Left-recursive -#define factor_type 1133 -#define power_type 1134 -#define await_primary_type 1135 -#define primary_type 1136 // Left-recursive -#define slices_type 1137 -#define slice_type 1138 -#define atom_type 1139 -#define group_type 1140 -#define lambdef_type 1141 -#define lambda_params_type 1142 -#define lambda_parameters_type 1143 -#define lambda_slash_no_default_type 1144 -#define lambda_slash_with_default_type 1145 -#define lambda_star_etc_type 1146 -#define lambda_kwds_type 1147 -#define lambda_param_no_default_type 1148 -#define lambda_param_with_default_type 1149 -#define lambda_param_maybe_default_type 1150 -#define lambda_param_type 1151 -#define fstring_middle_type 1152 -#define fstring_replacement_field_type 1153 -#define fstring_conversion_type 1154 -#define fstring_full_format_spec_type 1155 -#define fstring_format_spec_type 1156 +#define statements_type 1004 +#define statement_type 1005 +#define statement_newline_type 1006 +#define simple_stmts_type 1007 +#define simple_stmt_type 1008 +#define compound_stmt_type 1009 +#define assignment_type 1010 +#define annotated_rhs_type 1011 +#define augassign_type 1012 +#define return_stmt_type 1013 +#define raise_stmt_type 1014 +#define global_stmt_type 1015 +#define nonlocal_stmt_type 1016 +#define del_stmt_type 1017 +#define yield_stmt_type 1018 +#define assert_stmt_type 1019 +#define import_stmt_type 1020 +#define import_name_type 1021 +#define import_from_type 1022 +#define import_from_targets_type 1023 +#define import_from_as_names_type 1024 +#define import_from_as_name_type 1025 +#define dotted_as_names_type 1026 +#define dotted_as_name_type 1027 +#define dotted_name_type 1028 // Left-recursive +#define block_type 1029 +#define decorators_type 1030 +#define class_def_type 1031 +#define class_def_raw_type 1032 +#define function_def_type 1033 +#define function_def_raw_type 1034 +#define params_type 1035 +#define parameters_type 1036 +#define slash_no_default_type 1037 +#define slash_with_default_type 1038 +#define star_etc_type 1039 +#define kwds_type 1040 +#define param_no_default_type 1041 +#define param_no_default_star_annotation_type 1042 +#define param_with_default_type 1043 +#define param_maybe_default_type 1044 +#define param_type 1045 +#define param_star_annotation_type 1046 +#define annotation_type 1047 +#define star_annotation_type 1048 +#define default_type 1049 +#define if_stmt_type 1050 +#define elif_stmt_type 1051 +#define else_block_type 1052 +#define while_stmt_type 1053 +#define for_stmt_type 1054 +#define with_stmt_type 1055 +#define with_item_type 1056 +#define try_stmt_type 1057 +#define except_block_type 1058 +#define except_star_block_type 1059 +#define finally_block_type 1060 +#define match_stmt_type 1061 +#define subject_expr_type 1062 +#define case_block_type 1063 +#define guard_type 1064 +#define patterns_type 1065 +#define pattern_type 1066 +#define as_pattern_type 1067 +#define or_pattern_type 1068 +#define closed_pattern_type 1069 +#define literal_pattern_type 1070 +#define literal_expr_type 1071 +#define complex_number_type 1072 +#define signed_number_type 1073 +#define signed_real_number_type 1074 +#define real_number_type 1075 +#define imaginary_number_type 1076 +#define capture_pattern_type 1077 +#define pattern_capture_target_type 1078 +#define wildcard_pattern_type 1079 +#define value_pattern_type 1080 +#define attr_type 1081 // Left-recursive +#define name_or_attr_type 1082 // Left-recursive +#define group_pattern_type 1083 +#define sequence_pattern_type 1084 +#define open_sequence_pattern_type 1085 +#define maybe_sequence_pattern_type 1086 +#define maybe_star_pattern_type 1087 +#define star_pattern_type 1088 +#define mapping_pattern_type 1089 +#define items_pattern_type 1090 +#define key_value_pattern_type 1091 +#define double_star_pattern_type 1092 +#define class_pattern_type 1093 +#define positional_patterns_type 1094 +#define keyword_patterns_type 1095 +#define keyword_pattern_type 1096 +#define type_alias_type 1097 +#define type_params_type 1098 +#define type_param_seq_type 1099 +#define type_param_type 1100 +#define type_param_bound_type 1101 +#define expressions_type 1102 +#define expression_type 1103 +#define yield_expr_type 1104 +#define star_expressions_type 1105 +#define star_expression_type 1106 +#define star_named_expressions_type 1107 +#define star_named_expression_type 1108 +#define assignment_expression_type 1109 +#define named_expression_type 1110 +#define disjunction_type 1111 +#define conjunction_type 1112 +#define inversion_type 1113 +#define comparison_type 1114 +#define compare_op_bitwise_or_pair_type 1115 +#define eq_bitwise_or_type 1116 +#define noteq_bitwise_or_type 1117 +#define lte_bitwise_or_type 1118 +#define lt_bitwise_or_type 1119 +#define gte_bitwise_or_type 1120 +#define gt_bitwise_or_type 1121 +#define notin_bitwise_or_type 1122 +#define in_bitwise_or_type 1123 +#define isnot_bitwise_or_type 1124 +#define is_bitwise_or_type 1125 +#define bitwise_or_type 1126 // Left-recursive +#define bitwise_xor_type 1127 // Left-recursive +#define bitwise_and_type 1128 // Left-recursive +#define shift_expr_type 1129 // Left-recursive +#define sum_type 1130 // Left-recursive +#define term_type 1131 // Left-recursive +#define factor_type 1132 +#define power_type 1133 +#define await_primary_type 1134 +#define primary_type 1135 // Left-recursive +#define slices_type 1136 +#define slice_type 1137 +#define atom_type 1138 +#define group_type 1139 +#define lambdef_type 1140 +#define lambda_params_type 1141 +#define lambda_parameters_type 1142 +#define lambda_slash_no_default_type 1143 +#define lambda_slash_with_default_type 1144 +#define lambda_star_etc_type 1145 +#define lambda_kwds_type 1146 +#define lambda_param_no_default_type 1147 +#define lambda_param_with_default_type 1148 +#define lambda_param_maybe_default_type 1149 +#define lambda_param_type 1150 +#define fstring_middle_type 1151 +#define fstring_replacement_field_type 1152 +#define fstring_conversion_type 1153 +#define fstring_full_format_spec_type 1154 +#define fstring_format_spec_type 1155 +#define fstring_type 1156 #define string_type 1157 #define strings_type 1158 #define list_type 1159 @@ -324,10 +324,10 @@ static char *soft_keywords[] = { #define invalid_conversion_character_type 1243 #define _loop0_1_type 1244 #define _loop0_2_type 1245 -#define _loop0_3_type 1246 -#define _loop1_4_type 1247 -#define _loop0_6_type 1248 -#define _gather_5_type 1249 +#define _loop1_3_type 1246 +#define _loop0_5_type 1247 +#define _gather_4_type 1248 +#define _tmp_6_type 1249 #define _tmp_7_type 1250 #define _tmp_8_type 1251 #define _tmp_9_type 1252 @@ -335,106 +335,106 @@ static char *soft_keywords[] = { #define _tmp_11_type 1254 #define _tmp_12_type 1255 #define _tmp_13_type 1256 -#define _tmp_14_type 1257 -#define _loop1_15_type 1258 +#define _loop1_14_type 1257 +#define _tmp_15_type 1258 #define _tmp_16_type 1259 #define _tmp_17_type 1260 -#define _tmp_18_type 1261 -#define _loop0_20_type 1262 -#define _gather_19_type 1263 -#define _loop0_22_type 1264 -#define _gather_21_type 1265 +#define _loop0_19_type 1261 +#define _gather_18_type 1262 +#define _loop0_21_type 1263 +#define _gather_20_type 1264 +#define _tmp_22_type 1265 #define _tmp_23_type 1266 -#define _tmp_24_type 1267 -#define _loop0_25_type 1268 -#define _loop1_26_type 1269 -#define _loop0_28_type 1270 -#define _gather_27_type 1271 -#define _tmp_29_type 1272 -#define _loop0_31_type 1273 -#define _gather_30_type 1274 -#define _tmp_32_type 1275 -#define _loop1_33_type 1276 +#define _loop0_24_type 1267 +#define _loop1_25_type 1268 +#define _loop0_27_type 1269 +#define _gather_26_type 1270 +#define _tmp_28_type 1271 +#define _loop0_30_type 1272 +#define _gather_29_type 1273 +#define _tmp_31_type 1274 +#define _loop1_32_type 1275 +#define _tmp_33_type 1276 #define _tmp_34_type 1277 #define _tmp_35_type 1278 -#define _tmp_36_type 1279 +#define _loop0_36_type 1279 #define _loop0_37_type 1280 #define _loop0_38_type 1281 -#define _loop0_39_type 1282 -#define _loop1_40_type 1283 -#define _loop0_41_type 1284 +#define _loop1_39_type 1282 +#define _loop0_40_type 1283 +#define _loop1_41_type 1284 #define _loop1_42_type 1285 #define _loop1_43_type 1286 -#define _loop1_44_type 1287 -#define _loop0_45_type 1288 -#define _loop1_46_type 1289 -#define _loop0_47_type 1290 -#define _loop1_48_type 1291 +#define _loop0_44_type 1287 +#define _loop1_45_type 1288 +#define _loop0_46_type 1289 +#define _loop1_47_type 1290 +#define _loop0_48_type 1291 #define _loop0_49_type 1292 -#define _loop0_50_type 1293 -#define _loop1_51_type 1294 -#define _loop0_53_type 1295 -#define _gather_52_type 1296 -#define _loop0_55_type 1297 -#define _gather_54_type 1298 -#define _loop0_57_type 1299 -#define _gather_56_type 1300 -#define _loop0_59_type 1301 -#define _gather_58_type 1302 -#define _tmp_60_type 1303 +#define _loop1_50_type 1293 +#define _loop0_52_type 1294 +#define _gather_51_type 1295 +#define _loop0_54_type 1296 +#define _gather_53_type 1297 +#define _loop0_56_type 1298 +#define _gather_55_type 1299 +#define _loop0_58_type 1300 +#define _gather_57_type 1301 +#define _tmp_59_type 1302 +#define _loop1_60_type 1303 #define _loop1_61_type 1304 -#define _loop1_62_type 1305 +#define _tmp_62_type 1305 #define _tmp_63_type 1306 -#define _tmp_64_type 1307 -#define _loop1_65_type 1308 -#define _loop0_67_type 1309 -#define _gather_66_type 1310 +#define _loop1_64_type 1307 +#define _loop0_66_type 1308 +#define _gather_65_type 1309 +#define _tmp_67_type 1310 #define _tmp_68_type 1311 #define _tmp_69_type 1312 #define _tmp_70_type 1313 -#define _tmp_71_type 1314 -#define _loop0_73_type 1315 -#define _gather_72_type 1316 -#define _loop0_75_type 1317 -#define _gather_74_type 1318 -#define _tmp_76_type 1319 -#define _loop0_78_type 1320 -#define _gather_77_type 1321 -#define _loop0_80_type 1322 -#define _gather_79_type 1323 -#define _loop0_82_type 1324 -#define _gather_81_type 1325 +#define _loop0_72_type 1314 +#define _gather_71_type 1315 +#define _loop0_74_type 1316 +#define _gather_73_type 1317 +#define _tmp_75_type 1318 +#define _loop0_77_type 1319 +#define _gather_76_type 1320 +#define _loop0_79_type 1321 +#define _gather_78_type 1322 +#define _loop0_81_type 1323 +#define _gather_80_type 1324 +#define _loop1_82_type 1325 #define _loop1_83_type 1326 -#define _loop1_84_type 1327 -#define _loop0_86_type 1328 -#define _gather_85_type 1329 +#define _loop0_85_type 1327 +#define _gather_84_type 1328 +#define _loop1_86_type 1329 #define _loop1_87_type 1330 #define _loop1_88_type 1331 -#define _loop1_89_type 1332 -#define _tmp_90_type 1333 -#define _loop0_92_type 1334 -#define _gather_91_type 1335 +#define _tmp_89_type 1332 +#define _loop0_91_type 1333 +#define _gather_90_type 1334 +#define _tmp_92_type 1335 #define _tmp_93_type 1336 #define _tmp_94_type 1337 #define _tmp_95_type 1338 #define _tmp_96_type 1339 #define _tmp_97_type 1340 -#define _tmp_98_type 1341 +#define _loop0_98_type 1341 #define _loop0_99_type 1342 #define _loop0_100_type 1343 -#define _loop0_101_type 1344 -#define _loop1_102_type 1345 -#define _loop0_103_type 1346 +#define _loop1_101_type 1344 +#define _loop0_102_type 1345 +#define _loop1_103_type 1346 #define _loop1_104_type 1347 #define _loop1_105_type 1348 -#define _loop1_106_type 1349 -#define _loop0_107_type 1350 -#define _loop1_108_type 1351 -#define _loop0_109_type 1352 -#define _loop1_110_type 1353 -#define _loop0_111_type 1354 -#define _loop1_112_type 1355 -#define _tmp_113_type 1356 +#define _loop0_106_type 1349 +#define _loop1_107_type 1350 +#define _loop0_108_type 1351 +#define _loop1_109_type 1352 +#define _loop0_110_type 1353 +#define _loop1_111_type 1354 +#define _tmp_112_type 1355 +#define _loop0_113_type 1356 #define _loop0_114_type 1357 #define _loop1_115_type 1358 #define _tmp_116_type 1359 @@ -602,7 +602,6 @@ static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); static mod_ty eval_rule(Parser *p); static mod_ty func_type_rule(Parser *p); -static expr_ty fstring_rule(Parser *p); static asdl_stmt_seq* statements_rule(Parser *p); static asdl_stmt_seq* statement_rule(Parser *p); static asdl_stmt_seq* statement_newline_rule(Parser *p); @@ -755,6 +754,7 @@ static expr_ty fstring_replacement_field_rule(Parser *p); static ResultTokenWithMetadata* fstring_conversion_rule(Parser *p); static ResultTokenWithMetadata* fstring_full_format_spec_rule(Parser *p); static expr_ty fstring_format_spec_rule(Parser *p); +static expr_ty fstring_rule(Parser *p); static expr_ty string_rule(Parser *p); static expr_ty strings_rule(Parser *p); static expr_ty list_rule(Parser *p); @@ -844,10 +844,10 @@ static void *invalid_replacement_field_rule(Parser *p); static void *invalid_conversion_character_rule(Parser *p); static asdl_seq *_loop0_1_rule(Parser *p); static asdl_seq *_loop0_2_rule(Parser *p); -static asdl_seq *_loop0_3_rule(Parser *p); -static asdl_seq *_loop1_4_rule(Parser *p); -static asdl_seq *_loop0_6_rule(Parser *p); -static asdl_seq *_gather_5_rule(Parser *p); +static asdl_seq *_loop1_3_rule(Parser *p); +static asdl_seq *_loop0_5_rule(Parser *p); +static asdl_seq *_gather_4_rule(Parser *p); +static void *_tmp_6_rule(Parser *p); static void *_tmp_7_rule(Parser *p); static void *_tmp_8_rule(Parser *p); static void *_tmp_9_rule(Parser *p); @@ -855,106 +855,106 @@ static void *_tmp_10_rule(Parser *p); static void *_tmp_11_rule(Parser *p); static void *_tmp_12_rule(Parser *p); static void *_tmp_13_rule(Parser *p); -static void *_tmp_14_rule(Parser *p); -static asdl_seq *_loop1_15_rule(Parser *p); +static asdl_seq *_loop1_14_rule(Parser *p); +static void *_tmp_15_rule(Parser *p); static void *_tmp_16_rule(Parser *p); static void *_tmp_17_rule(Parser *p); -static void *_tmp_18_rule(Parser *p); -static asdl_seq *_loop0_20_rule(Parser *p); -static asdl_seq *_gather_19_rule(Parser *p); -static asdl_seq *_loop0_22_rule(Parser *p); -static asdl_seq *_gather_21_rule(Parser *p); +static asdl_seq *_loop0_19_rule(Parser *p); +static asdl_seq *_gather_18_rule(Parser *p); +static asdl_seq *_loop0_21_rule(Parser *p); +static asdl_seq *_gather_20_rule(Parser *p); +static void *_tmp_22_rule(Parser *p); static void *_tmp_23_rule(Parser *p); -static void *_tmp_24_rule(Parser *p); -static asdl_seq *_loop0_25_rule(Parser *p); -static asdl_seq *_loop1_26_rule(Parser *p); -static asdl_seq *_loop0_28_rule(Parser *p); -static asdl_seq *_gather_27_rule(Parser *p); -static void *_tmp_29_rule(Parser *p); -static asdl_seq *_loop0_31_rule(Parser *p); -static asdl_seq *_gather_30_rule(Parser *p); -static void *_tmp_32_rule(Parser *p); -static asdl_seq *_loop1_33_rule(Parser *p); +static asdl_seq *_loop0_24_rule(Parser *p); +static asdl_seq *_loop1_25_rule(Parser *p); +static asdl_seq *_loop0_27_rule(Parser *p); +static asdl_seq *_gather_26_rule(Parser *p); +static void *_tmp_28_rule(Parser *p); +static asdl_seq *_loop0_30_rule(Parser *p); +static asdl_seq *_gather_29_rule(Parser *p); +static void *_tmp_31_rule(Parser *p); +static asdl_seq *_loop1_32_rule(Parser *p); +static void *_tmp_33_rule(Parser *p); static void *_tmp_34_rule(Parser *p); static void *_tmp_35_rule(Parser *p); -static void *_tmp_36_rule(Parser *p); +static asdl_seq *_loop0_36_rule(Parser *p); static asdl_seq *_loop0_37_rule(Parser *p); static asdl_seq *_loop0_38_rule(Parser *p); -static asdl_seq *_loop0_39_rule(Parser *p); -static asdl_seq *_loop1_40_rule(Parser *p); -static asdl_seq *_loop0_41_rule(Parser *p); +static asdl_seq *_loop1_39_rule(Parser *p); +static asdl_seq *_loop0_40_rule(Parser *p); +static asdl_seq *_loop1_41_rule(Parser *p); static asdl_seq *_loop1_42_rule(Parser *p); static asdl_seq *_loop1_43_rule(Parser *p); -static asdl_seq *_loop1_44_rule(Parser *p); -static asdl_seq *_loop0_45_rule(Parser *p); -static asdl_seq *_loop1_46_rule(Parser *p); -static asdl_seq *_loop0_47_rule(Parser *p); -static asdl_seq *_loop1_48_rule(Parser *p); +static asdl_seq *_loop0_44_rule(Parser *p); +static asdl_seq *_loop1_45_rule(Parser *p); +static asdl_seq *_loop0_46_rule(Parser *p); +static asdl_seq *_loop1_47_rule(Parser *p); +static asdl_seq *_loop0_48_rule(Parser *p); static asdl_seq *_loop0_49_rule(Parser *p); -static asdl_seq *_loop0_50_rule(Parser *p); -static asdl_seq *_loop1_51_rule(Parser *p); -static asdl_seq *_loop0_53_rule(Parser *p); -static asdl_seq *_gather_52_rule(Parser *p); -static asdl_seq *_loop0_55_rule(Parser *p); -static asdl_seq *_gather_54_rule(Parser *p); -static asdl_seq *_loop0_57_rule(Parser *p); -static asdl_seq *_gather_56_rule(Parser *p); -static asdl_seq *_loop0_59_rule(Parser *p); -static asdl_seq *_gather_58_rule(Parser *p); -static void *_tmp_60_rule(Parser *p); +static asdl_seq *_loop1_50_rule(Parser *p); +static asdl_seq *_loop0_52_rule(Parser *p); +static asdl_seq *_gather_51_rule(Parser *p); +static asdl_seq *_loop0_54_rule(Parser *p); +static asdl_seq *_gather_53_rule(Parser *p); +static asdl_seq *_loop0_56_rule(Parser *p); +static asdl_seq *_gather_55_rule(Parser *p); +static asdl_seq *_loop0_58_rule(Parser *p); +static asdl_seq *_gather_57_rule(Parser *p); +static void *_tmp_59_rule(Parser *p); +static asdl_seq *_loop1_60_rule(Parser *p); static asdl_seq *_loop1_61_rule(Parser *p); -static asdl_seq *_loop1_62_rule(Parser *p); +static void *_tmp_62_rule(Parser *p); static void *_tmp_63_rule(Parser *p); -static void *_tmp_64_rule(Parser *p); -static asdl_seq *_loop1_65_rule(Parser *p); -static asdl_seq *_loop0_67_rule(Parser *p); -static asdl_seq *_gather_66_rule(Parser *p); +static asdl_seq *_loop1_64_rule(Parser *p); +static asdl_seq *_loop0_66_rule(Parser *p); +static asdl_seq *_gather_65_rule(Parser *p); +static void *_tmp_67_rule(Parser *p); static void *_tmp_68_rule(Parser *p); static void *_tmp_69_rule(Parser *p); static void *_tmp_70_rule(Parser *p); -static void *_tmp_71_rule(Parser *p); -static asdl_seq *_loop0_73_rule(Parser *p); -static asdl_seq *_gather_72_rule(Parser *p); -static asdl_seq *_loop0_75_rule(Parser *p); -static asdl_seq *_gather_74_rule(Parser *p); -static void *_tmp_76_rule(Parser *p); -static asdl_seq *_loop0_78_rule(Parser *p); -static asdl_seq *_gather_77_rule(Parser *p); -static asdl_seq *_loop0_80_rule(Parser *p); -static asdl_seq *_gather_79_rule(Parser *p); -static asdl_seq *_loop0_82_rule(Parser *p); -static asdl_seq *_gather_81_rule(Parser *p); +static asdl_seq *_loop0_72_rule(Parser *p); +static asdl_seq *_gather_71_rule(Parser *p); +static asdl_seq *_loop0_74_rule(Parser *p); +static asdl_seq *_gather_73_rule(Parser *p); +static void *_tmp_75_rule(Parser *p); +static asdl_seq *_loop0_77_rule(Parser *p); +static asdl_seq *_gather_76_rule(Parser *p); +static asdl_seq *_loop0_79_rule(Parser *p); +static asdl_seq *_gather_78_rule(Parser *p); +static asdl_seq *_loop0_81_rule(Parser *p); +static asdl_seq *_gather_80_rule(Parser *p); +static asdl_seq *_loop1_82_rule(Parser *p); static asdl_seq *_loop1_83_rule(Parser *p); -static asdl_seq *_loop1_84_rule(Parser *p); -static asdl_seq *_loop0_86_rule(Parser *p); -static asdl_seq *_gather_85_rule(Parser *p); +static asdl_seq *_loop0_85_rule(Parser *p); +static asdl_seq *_gather_84_rule(Parser *p); +static asdl_seq *_loop1_86_rule(Parser *p); static asdl_seq *_loop1_87_rule(Parser *p); static asdl_seq *_loop1_88_rule(Parser *p); -static asdl_seq *_loop1_89_rule(Parser *p); -static void *_tmp_90_rule(Parser *p); -static asdl_seq *_loop0_92_rule(Parser *p); -static asdl_seq *_gather_91_rule(Parser *p); +static void *_tmp_89_rule(Parser *p); +static asdl_seq *_loop0_91_rule(Parser *p); +static asdl_seq *_gather_90_rule(Parser *p); +static void *_tmp_92_rule(Parser *p); static void *_tmp_93_rule(Parser *p); static void *_tmp_94_rule(Parser *p); static void *_tmp_95_rule(Parser *p); static void *_tmp_96_rule(Parser *p); static void *_tmp_97_rule(Parser *p); -static void *_tmp_98_rule(Parser *p); +static asdl_seq *_loop0_98_rule(Parser *p); static asdl_seq *_loop0_99_rule(Parser *p); static asdl_seq *_loop0_100_rule(Parser *p); -static asdl_seq *_loop0_101_rule(Parser *p); -static asdl_seq *_loop1_102_rule(Parser *p); -static asdl_seq *_loop0_103_rule(Parser *p); +static asdl_seq *_loop1_101_rule(Parser *p); +static asdl_seq *_loop0_102_rule(Parser *p); +static asdl_seq *_loop1_103_rule(Parser *p); static asdl_seq *_loop1_104_rule(Parser *p); static asdl_seq *_loop1_105_rule(Parser *p); -static asdl_seq *_loop1_106_rule(Parser *p); -static asdl_seq *_loop0_107_rule(Parser *p); -static asdl_seq *_loop1_108_rule(Parser *p); -static asdl_seq *_loop0_109_rule(Parser *p); -static asdl_seq *_loop1_110_rule(Parser *p); -static asdl_seq *_loop0_111_rule(Parser *p); -static asdl_seq *_loop1_112_rule(Parser *p); -static void *_tmp_113_rule(Parser *p); +static asdl_seq *_loop0_106_rule(Parser *p); +static asdl_seq *_loop1_107_rule(Parser *p); +static asdl_seq *_loop0_108_rule(Parser *p); +static asdl_seq *_loop1_109_rule(Parser *p); +static asdl_seq *_loop0_110_rule(Parser *p); +static asdl_seq *_loop1_111_rule(Parser *p); +static void *_tmp_112_rule(Parser *p); +static asdl_seq *_loop0_113_rule(Parser *p); static asdl_seq *_loop0_114_rule(Parser *p); static asdl_seq *_loop1_115_rule(Parser *p); static void *_tmp_116_rule(Parser *p); @@ -1318,55 +1318,6 @@ func_type_rule(Parser *p) return _res; } -// fstring: FSTRING_START fstring_middle* FSTRING_END -static expr_ty -fstring_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - expr_ty _res = NULL; - int _mark = p->mark; - { // FSTRING_START fstring_middle* FSTRING_END - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> fstring[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); - Token * a; - asdl_seq * b; - Token * c; - if ( - (a = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' - && - (b = _loop0_3_rule(p)) // fstring_middle* - && - (c = _PyPegen_expect_token(p, FSTRING_END)) // token='FSTRING_END' - ) - { - D(fprintf(stderr, "%*c+ fstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); - _res = _PyPegen_joined_str ( p , a , ( asdl_expr_seq* ) b , c ); - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - p->level--; - return NULL; - } - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s fstring[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); - } - _res = NULL; - done: - p->level--; - return _res; -} - // statements: statement+ static asdl_stmt_seq* statements_rule(Parser *p) @@ -1388,7 +1339,7 @@ statements_rule(Parser *p) D(fprintf(stderr, "%*c> statements[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement+")); asdl_seq * a; if ( - (a = _loop1_4_rule(p)) // statement+ + (a = _loop1_3_rule(p)) // statement+ ) { D(fprintf(stderr, "%*c+ statements[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "statement+")); @@ -1661,7 +1612,7 @@ simple_stmts_rule(Parser *p) asdl_stmt_seq* a; Token * newline_var; if ( - (a = (asdl_stmt_seq*)_gather_5_rule(p)) // ';'.simple_stmt+ + (a = (asdl_stmt_seq*)_gather_4_rule(p)) // ';'.simple_stmt+ && (_opt_var = _PyPegen_expect_token(p, 13), !p->error_indicator) // ';'? && @@ -1829,7 +1780,7 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('import' | 'from') import_stmt")); stmt_ty import_stmt_var; if ( - _PyPegen_lookahead(1, _tmp_7_rule, p) + _PyPegen_lookahead(1, _tmp_6_rule, p) && (import_stmt_var = import_stmt_rule(p)) // import_stmt ) @@ -2103,7 +2054,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('def' | '@' | ASYNC) function_def")); stmt_ty function_def_var; if ( - _PyPegen_lookahead(1, _tmp_8_rule, p) + _PyPegen_lookahead(1, _tmp_7_rule, p) && (function_def_var = function_def_rule(p)) // function_def ) @@ -2145,7 +2096,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('class' | '@') class_def")); stmt_ty class_def_var; if ( - _PyPegen_lookahead(1, _tmp_9_rule, p) + _PyPegen_lookahead(1, _tmp_8_rule, p) && (class_def_var = class_def_rule(p)) // class_def ) @@ -2166,7 +2117,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('with' | ASYNC) with_stmt")); stmt_ty with_stmt_var; if ( - _PyPegen_lookahead(1, _tmp_10_rule, p) + _PyPegen_lookahead(1, _tmp_9_rule, p) && (with_stmt_var = with_stmt_rule(p)) // with_stmt ) @@ -2187,7 +2138,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('for' | ASYNC) for_stmt")); stmt_ty for_stmt_var; if ( - _PyPegen_lookahead(1, _tmp_11_rule, p) + _PyPegen_lookahead(1, _tmp_10_rule, p) && (for_stmt_var = for_stmt_rule(p)) // for_stmt ) @@ -2311,7 +2262,7 @@ assignment_rule(Parser *p) && (b = expression_rule(p)) // expression && - (c = _tmp_12_rule(p), !p->error_indicator) // ['=' annotated_rhs] + (c = _tmp_11_rule(p), !p->error_indicator) // ['=' annotated_rhs] ) { D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME ':' expression ['=' annotated_rhs]")); @@ -2347,13 +2298,13 @@ assignment_rule(Parser *p) expr_ty b; void *c; if ( - (a = _tmp_13_rule(p)) // '(' single_target ')' | single_subscript_attribute_target + (a = _tmp_12_rule(p)) // '(' single_target ')' | single_subscript_attribute_target && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (b = expression_rule(p)) // expression && - (c = _tmp_14_rule(p), !p->error_indicator) // ['=' annotated_rhs] + (c = _tmp_13_rule(p), !p->error_indicator) // ['=' annotated_rhs] ) { D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs]")); @@ -2388,9 +2339,9 @@ assignment_rule(Parser *p) void *b; void *tc; if ( - (a = (asdl_expr_seq*)_loop1_15_rule(p)) // ((star_targets '='))+ + (a = (asdl_expr_seq*)_loop1_14_rule(p)) // ((star_targets '='))+ && - (b = _tmp_16_rule(p)) // yield_expr | star_expressions + (b = _tmp_15_rule(p)) // yield_expr | star_expressions && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' && @@ -2436,7 +2387,7 @@ assignment_rule(Parser *p) && (_cut_var = 1) && - (c = _tmp_17_rule(p)) // yield_expr | star_expressions + (c = _tmp_16_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_target augassign ~ (yield_expr | star_expressions)")); @@ -2991,7 +2942,7 @@ raise_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (b = _tmp_18_rule(p), !p->error_indicator) // ['from' expression] + (b = _tmp_17_rule(p), !p->error_indicator) // ['from' expression] ) { D(fprintf(stderr, "%*c+ raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression ['from' expression]")); @@ -3088,7 +3039,7 @@ global_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 523)) // token='global' && - (a = (asdl_expr_seq*)_gather_19_rule(p)) // ','.NAME+ + (a = (asdl_expr_seq*)_gather_18_rule(p)) // ','.NAME+ ) { D(fprintf(stderr, "%*c+ global_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'global' ','.NAME+")); @@ -3152,7 +3103,7 @@ nonlocal_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 524)) // token='nonlocal' && - (a = (asdl_expr_seq*)_gather_21_rule(p)) // ','.NAME+ + (a = (asdl_expr_seq*)_gather_20_rule(p)) // ','.NAME+ ) { D(fprintf(stderr, "%*c+ nonlocal_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'nonlocal' ','.NAME+")); @@ -3218,7 +3169,7 @@ del_stmt_rule(Parser *p) && (a = del_targets_rule(p)) // del_targets && - _PyPegen_lookahead(1, _tmp_23_rule, p) + _PyPegen_lookahead(1, _tmp_22_rule, p) ) { D(fprintf(stderr, "%*c+ del_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'del' del_targets &(';' | NEWLINE)")); @@ -3365,7 +3316,7 @@ assert_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (b = _tmp_24_rule(p), !p->error_indicator) // [',' expression] + (b = _tmp_23_rule(p), !p->error_indicator) // [',' expression] ) { D(fprintf(stderr, "%*c+ assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression [',' expression]")); @@ -3574,7 +3525,7 @@ import_from_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && - (a = _loop0_25_rule(p)) // (('.' | '...'))* + (a = _loop0_24_rule(p)) // (('.' | '...'))* && (b = dotted_name_rule(p)) // dotted_name && @@ -3618,7 +3569,7 @@ import_from_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && - (a = _loop1_26_rule(p)) // (('.' | '...'))+ + (a = _loop1_25_rule(p)) // (('.' | '...'))+ && (_keyword_1 = _PyPegen_expect_token(p, 607)) // token='import' && @@ -3813,7 +3764,7 @@ import_from_as_names_rule(Parser *p) D(fprintf(stderr, "%*c> import_from_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+")); asdl_alias_seq* a; if ( - (a = (asdl_alias_seq*)_gather_27_rule(p)) // ','.import_from_as_name+ + (a = (asdl_alias_seq*)_gather_26_rule(p)) // ','.import_from_as_name+ ) { D(fprintf(stderr, "%*c+ import_from_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+")); @@ -3868,7 +3819,7 @@ import_from_as_name_rule(Parser *p) if ( (a = _PyPegen_name_token(p)) // NAME && - (b = _tmp_29_rule(p), !p->error_indicator) // ['as' NAME] + (b = _tmp_28_rule(p), !p->error_indicator) // ['as' NAME] ) { D(fprintf(stderr, "%*c+ import_from_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME ['as' NAME]")); @@ -3920,7 +3871,7 @@ dotted_as_names_rule(Parser *p) D(fprintf(stderr, "%*c> dotted_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+")); asdl_alias_seq* a; if ( - (a = (asdl_alias_seq*)_gather_30_rule(p)) // ','.dotted_as_name+ + (a = (asdl_alias_seq*)_gather_29_rule(p)) // ','.dotted_as_name+ ) { D(fprintf(stderr, "%*c+ dotted_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+")); @@ -3975,7 +3926,7 @@ dotted_as_name_rule(Parser *p) if ( (a = dotted_name_rule(p)) // dotted_name && - (b = _tmp_32_rule(p), !p->error_indicator) // ['as' NAME] + (b = _tmp_31_rule(p), !p->error_indicator) // ['as' NAME] ) { D(fprintf(stderr, "%*c+ dotted_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name ['as' NAME]")); @@ -4226,7 +4177,7 @@ decorators_rule(Parser *p) D(fprintf(stderr, "%*c> decorators[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_33_rule(p)) // (('@' named_expression NEWLINE))+ + (a = (asdl_expr_seq*)_loop1_32_rule(p)) // (('@' named_expression NEWLINE))+ ) { D(fprintf(stderr, "%*c+ decorators[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+")); @@ -4375,7 +4326,7 @@ class_def_raw_rule(Parser *p) && (t = type_params_rule(p), !p->error_indicator) // type_params? && - (b = _tmp_34_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (b = _tmp_33_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -4548,7 +4499,7 @@ function_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (a = _tmp_35_rule(p), !p->error_indicator) // ['->' expression] + (a = _tmp_34_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -4611,7 +4562,7 @@ function_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (a = _tmp_36_rule(p), !p->error_indicator) // ['->' expression] + (a = _tmp_35_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -4736,9 +4687,9 @@ parameters_rule(Parser *p) if ( (a = slash_no_default_rule(p)) // slash_no_default && - (b = (asdl_arg_seq*)_loop0_37_rule(p)) // param_no_default* + (b = (asdl_arg_seq*)_loop0_36_rule(p)) // param_no_default* && - (c = _loop0_38_rule(p)) // param_with_default* + (c = _loop0_37_rule(p)) // param_with_default* && (d = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4768,7 +4719,7 @@ parameters_rule(Parser *p) if ( (a = slash_with_default_rule(p)) // slash_with_default && - (b = _loop0_39_rule(p)) // param_with_default* + (b = _loop0_38_rule(p)) // param_with_default* && (c = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4796,9 +4747,9 @@ parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_40_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_39_rule(p)) // param_no_default+ && - (b = _loop0_41_rule(p)) // param_with_default* + (b = _loop0_40_rule(p)) // param_with_default* && (c = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4825,7 +4776,7 @@ parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_42_rule(p)) // param_with_default+ + (a = _loop1_41_rule(p)) // param_with_default+ && (b = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4896,7 +4847,7 @@ slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_43_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_42_rule(p)) // param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4925,7 +4876,7 @@ slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_44_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_43_rule(p)) // param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4977,9 +4928,9 @@ slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_45_rule(p)) // param_no_default* + (a = _loop0_44_rule(p)) // param_no_default* && - (b = _loop1_46_rule(p)) // param_with_default+ + (b = _loop1_45_rule(p)) // param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -5009,9 +4960,9 @@ slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_47_rule(p)) // param_no_default* + (a = _loop0_46_rule(p)) // param_no_default* && - (b = _loop1_48_rule(p)) // param_with_default+ + (b = _loop1_47_rule(p)) // param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -5089,7 +5040,7 @@ star_etc_rule(Parser *p) && (a = param_no_default_rule(p)) // param_no_default && - (b = _loop0_49_rule(p)) // param_maybe_default* + (b = _loop0_48_rule(p)) // param_maybe_default* && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -5122,7 +5073,7 @@ star_etc_rule(Parser *p) && (a = param_no_default_star_annotation_rule(p)) // param_no_default_star_annotation && - (b = _loop0_50_rule(p)) // param_maybe_default* + (b = _loop0_49_rule(p)) // param_maybe_default* && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -5155,7 +5106,7 @@ star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_51_rule(p)) // param_maybe_default+ + (b = _loop1_50_rule(p)) // param_maybe_default+ && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -6582,7 +6533,7 @@ with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = (asdl_withitem_seq*)_gather_52_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_51_rule(p)) // ','.with_item+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -6629,7 +6580,7 @@ with_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (a = (asdl_withitem_seq*)_gather_54_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_53_rule(p)) // ','.with_item+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -6682,7 +6633,7 @@ with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = (asdl_withitem_seq*)_gather_56_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_55_rule(p)) // ','.with_item+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -6732,7 +6683,7 @@ with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (a = (asdl_withitem_seq*)_gather_58_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_57_rule(p)) // ','.with_item+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -6820,7 +6771,7 @@ with_item_rule(Parser *p) && (t = star_target_rule(p)) // star_target && - _PyPegen_lookahead(1, _tmp_60_rule, p) + _PyPegen_lookahead(1, _tmp_59_rule, p) ) { D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')")); @@ -6991,7 +6942,7 @@ try_stmt_rule(Parser *p) && (b = block_rule(p)) // block && - (ex = (asdl_excepthandler_seq*)_loop1_61_rule(p)) // except_block+ + (ex = (asdl_excepthandler_seq*)_loop1_60_rule(p)) // except_block+ && (el = else_block_rule(p), !p->error_indicator) // else_block? && @@ -7039,7 +6990,7 @@ try_stmt_rule(Parser *p) && (b = block_rule(p)) // block && - (ex = (asdl_excepthandler_seq*)_loop1_62_rule(p)) // except_star_block+ + (ex = (asdl_excepthandler_seq*)_loop1_61_rule(p)) // except_star_block+ && (el = else_block_rule(p), !p->error_indicator) // else_block? && @@ -7135,7 +7086,7 @@ except_block_rule(Parser *p) && (e = expression_rule(p)) // expression && - (t = _tmp_63_rule(p), !p->error_indicator) // ['as' NAME] + (t = _tmp_62_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7291,7 +7242,7 @@ except_star_block_rule(Parser *p) && (e = expression_rule(p)) // expression && - (t = _tmp_64_rule(p), !p->error_indicator) // ['as' NAME] + (t = _tmp_63_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7461,7 +7412,7 @@ match_stmt_rule(Parser *p) && (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' && - (cases = (asdl_match_case_seq*)_loop1_65_rule(p)) // case_block+ + (cases = (asdl_match_case_seq*)_loop1_64_rule(p)) // case_block+ && (dedent_var = _PyPegen_expect_token(p, DEDENT)) // token='DEDENT' ) @@ -7972,7 +7923,7 @@ or_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> or_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); asdl_pattern_seq* patterns; if ( - (patterns = (asdl_pattern_seq*)_gather_66_rule(p)) // '|'.closed_pattern+ + (patterns = (asdl_pattern_seq*)_gather_65_rule(p)) // '|'.closed_pattern+ ) { D(fprintf(stderr, "%*c+ or_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); @@ -8225,7 +8176,7 @@ literal_pattern_rule(Parser *p) if ( (value = signed_number_rule(p)) // signed_number && - _PyPegen_lookahead(0, _tmp_68_rule, p) + _PyPegen_lookahead(0, _tmp_67_rule, p) ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); @@ -8459,7 +8410,7 @@ literal_expr_rule(Parser *p) if ( (signed_number_var = signed_number_rule(p)) // signed_number && - _PyPegen_lookahead(0, _tmp_69_rule, p) + _PyPegen_lookahead(0, _tmp_68_rule, p) ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); @@ -9059,7 +9010,7 @@ pattern_capture_target_rule(Parser *p) && (name = _PyPegen_name_token(p)) // NAME && - _PyPegen_lookahead(0, _tmp_70_rule, p) + _PyPegen_lookahead(0, _tmp_69_rule, p) ) { D(fprintf(stderr, "%*c+ pattern_capture_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); @@ -9174,7 +9125,7 @@ value_pattern_rule(Parser *p) if ( (attr = attr_rule(p)) // attr && - _PyPegen_lookahead(0, _tmp_71_rule, p) + _PyPegen_lookahead(0, _tmp_70_rule, p) ) { D(fprintf(stderr, "%*c+ value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr !('.' | '(' | '=')")); @@ -9593,7 +9544,7 @@ maybe_sequence_pattern_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * patterns; if ( - (patterns = _gather_72_rule(p)) // ','.maybe_star_pattern+ + (patterns = _gather_71_rule(p)) // ','.maybe_star_pattern+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -10001,13 +9952,13 @@ items_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> items_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); - asdl_seq * _gather_74_var; + asdl_seq * _gather_73_var; if ( - (_gather_74_var = _gather_74_rule(p)) // ','.key_value_pattern+ + (_gather_73_var = _gather_73_rule(p)) // ','.key_value_pattern+ ) { D(fprintf(stderr, "%*c+ items_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); - _res = _gather_74_var; + _res = _gather_73_var; goto done; } p->mark = _mark; @@ -10043,7 +9994,7 @@ key_value_pattern_rule(Parser *p) void *key; pattern_ty pattern; if ( - (key = _tmp_76_rule(p)) // literal_expr | attr + (key = _tmp_75_rule(p)) // literal_expr | attr && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -10371,7 +10322,7 @@ positional_patterns_rule(Parser *p) D(fprintf(stderr, "%*c> positional_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.pattern+")); asdl_pattern_seq* args; if ( - (args = (asdl_pattern_seq*)_gather_77_rule(p)) // ','.pattern+ + (args = (asdl_pattern_seq*)_gather_76_rule(p)) // ','.pattern+ ) { D(fprintf(stderr, "%*c+ positional_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.pattern+")); @@ -10412,13 +10363,13 @@ keyword_patterns_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> keyword_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); - asdl_seq * _gather_79_var; + asdl_seq * _gather_78_var; if ( - (_gather_79_var = _gather_79_rule(p)) // ','.keyword_pattern+ + (_gather_78_var = _gather_78_rule(p)) // ','.keyword_pattern+ ) { D(fprintf(stderr, "%*c+ keyword_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); - _res = _gather_79_var; + _res = _gather_78_var; goto done; } p->mark = _mark; @@ -10625,7 +10576,7 @@ type_param_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_type_param_seq* a; if ( - (a = (asdl_type_param_seq*)_gather_81_rule(p)) // ','.type_param+ + (a = (asdl_type_param_seq*)_gather_80_rule(p)) // ','.type_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -10651,9 +10602,9 @@ type_param_seq_rule(Parser *p) // type_param: // | NAME type_param_bound? -// | '*' NAME ":" expression +// | '*' NAME ':' expression // | '*' NAME -// | '**' NAME ":" expression +// | '**' NAME ':' expression // | '**' NAME static type_param_ty type_param_rule(Parser *p) @@ -10716,12 +10667,12 @@ type_param_rule(Parser *p) D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME type_param_bound?")); } - { // '*' NAME ":" expression + { // '*' NAME ':' expression if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' NAME \":\" expression")); + D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' NAME ':' expression")); Token * _literal; expr_ty a; Token * colon; @@ -10736,7 +10687,7 @@ type_param_rule(Parser *p) (e = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' NAME \":\" expression")); + D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' NAME ':' expression")); _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( colon , e -> kind == Tuple_kind ? "cannot use constraints with TypeVarTuple" : "cannot use bound with TypeVarTuple" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -10747,7 +10698,7 @@ type_param_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' NAME \":\" expression")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' NAME ':' expression")); } { // '*' NAME if (p->error_indicator) { @@ -10785,12 +10736,12 @@ type_param_rule(Parser *p) D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' NAME")); } - { // '**' NAME ":" expression + { // '**' NAME ':' expression if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' NAME \":\" expression")); + D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' NAME ':' expression")); Token * _literal; expr_ty a; Token * colon; @@ -10805,7 +10756,7 @@ type_param_rule(Parser *p) (e = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' NAME \":\" expression")); + D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' NAME ':' expression")); _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( colon , e -> kind == Tuple_kind ? "cannot use constraints with ParamSpec" : "cannot use bound with ParamSpec" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -10816,7 +10767,7 @@ type_param_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' NAME \":\" expression")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' NAME ':' expression")); } { // '**' NAME if (p->error_indicator) { @@ -10861,7 +10812,7 @@ type_param_rule(Parser *p) return _res; } -// type_param_bound: ":" expression +// type_param_bound: ':' expression static expr_ty type_param_bound_rule(Parser *p) { @@ -10874,12 +10825,12 @@ type_param_bound_rule(Parser *p) } expr_ty _res = NULL; int _mark = p->mark; - { // ":" expression + { // ':' expression if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> type_param_bound[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "\":\" expression")); + D(fprintf(stderr, "%*c> type_param_bound[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression")); Token * _literal; expr_ty e; if ( @@ -10888,7 +10839,7 @@ type_param_bound_rule(Parser *p) (e = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ type_param_bound[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "\":\" expression")); + D(fprintf(stderr, "%*c+ type_param_bound[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression")); _res = e; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -10899,7 +10850,7 @@ type_param_bound_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s type_param_bound[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "\":\" expression")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' expression")); } _res = NULL; done: @@ -10942,7 +10893,7 @@ expressions_rule(Parser *p) if ( (a = expression_rule(p)) // expression && - (b = _loop1_83_rule(p)) // ((',' expression))+ + (b = _loop1_82_rule(p)) // ((',' expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11330,7 +11281,7 @@ star_expressions_rule(Parser *p) if ( (a = star_expression_rule(p)) // star_expression && - (b = _loop1_84_rule(p)) // ((',' star_expression))+ + (b = _loop1_83_rule(p)) // ((',' star_expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11529,7 +11480,7 @@ star_named_expressions_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_85_rule(p)) // ','.star_named_expression+ + (a = (asdl_expr_seq*)_gather_84_rule(p)) // ','.star_named_expression+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11825,7 +11776,7 @@ disjunction_rule(Parser *p) if ( (a = conjunction_rule(p)) // conjunction && - (b = _loop1_87_rule(p)) // (('or' conjunction))+ + (b = _loop1_86_rule(p)) // (('or' conjunction))+ ) { D(fprintf(stderr, "%*c+ disjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "conjunction (('or' conjunction))+")); @@ -11913,7 +11864,7 @@ conjunction_rule(Parser *p) if ( (a = inversion_rule(p)) // inversion && - (b = _loop1_88_rule(p)) // (('and' inversion))+ + (b = _loop1_87_rule(p)) // (('and' inversion))+ ) { D(fprintf(stderr, "%*c+ conjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "inversion (('and' inversion))+")); @@ -12085,7 +12036,7 @@ comparison_rule(Parser *p) if ( (a = bitwise_or_rule(p)) // bitwise_or && - (b = _loop1_89_rule(p)) // compare_op_bitwise_or_pair+ + (b = _loop1_88_rule(p)) // compare_op_bitwise_or_pair+ ) { D(fprintf(stderr, "%*c+ comparison[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or compare_op_bitwise_or_pair+")); @@ -12419,10 +12370,10 @@ noteq_bitwise_or_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> noteq_bitwise_or[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('!=') bitwise_or")); - void *_tmp_90_var; + void *_tmp_89_var; expr_ty a; if ( - (_tmp_90_var = _tmp_90_rule(p)) // '!=' + (_tmp_89_var = _tmp_89_rule(p)) // '!=' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -14431,7 +14382,7 @@ slices_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_91_rule(p)) // ','.(slice | starred_expression)+ + (a = (asdl_expr_seq*)_gather_90_rule(p)) // ','.(slice | starred_expression)+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -14503,7 +14454,7 @@ slice_rule(Parser *p) && (b = expression_rule(p), !p->error_indicator) // expression? && - (c = _tmp_93_rule(p), !p->error_indicator) // [':' expression?] + (c = _tmp_92_rule(p), !p->error_indicator) // [':' expression?] ) { D(fprintf(stderr, "%*c+ slice[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression? ':' expression? [':' expression?]")); @@ -14716,7 +14667,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); expr_ty strings_var; if ( - _PyPegen_lookahead(1, _tmp_94_rule, p) + _PyPegen_lookahead(1, _tmp_93_rule, p) && (strings_var = strings_rule(p)) // strings ) @@ -14754,15 +14705,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - void *_tmp_95_var; + void *_tmp_94_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 7) // token='(' && - (_tmp_95_var = _tmp_95_rule(p)) // tuple | group | genexp + (_tmp_94_var = _tmp_94_rule(p)) // tuple | group | genexp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - _res = _tmp_95_var; + _res = _tmp_94_var; goto done; } p->mark = _mark; @@ -14775,15 +14726,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - void *_tmp_96_var; + void *_tmp_95_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='[' && - (_tmp_96_var = _tmp_96_rule(p)) // list | listcomp + (_tmp_95_var = _tmp_95_rule(p)) // list | listcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - _res = _tmp_96_var; + _res = _tmp_95_var; goto done; } p->mark = _mark; @@ -14796,15 +14747,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - void *_tmp_97_var; + void *_tmp_96_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{' && - (_tmp_97_var = _tmp_97_rule(p)) // dict | set | dictcomp | setcomp + (_tmp_96_var = _tmp_96_rule(p)) // dict | set | dictcomp | setcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - _res = _tmp_97_var; + _res = _tmp_96_var; goto done; } p->mark = _mark; @@ -14875,7 +14826,7 @@ group_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_98_rule(p)) // yield_expr | named_expression + (a = _tmp_97_rule(p)) // yield_expr | named_expression && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -15076,9 +15027,9 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_no_default_rule(p)) // lambda_slash_no_default && - (b = (asdl_arg_seq*)_loop0_99_rule(p)) // lambda_param_no_default* + (b = (asdl_arg_seq*)_loop0_98_rule(p)) // lambda_param_no_default* && - (c = _loop0_100_rule(p)) // lambda_param_with_default* + (c = _loop0_99_rule(p)) // lambda_param_with_default* && (d = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15108,7 +15059,7 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_with_default_rule(p)) // lambda_slash_with_default && - (b = _loop0_101_rule(p)) // lambda_param_with_default* + (b = _loop0_100_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15136,9 +15087,9 @@ lambda_parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_102_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_101_rule(p)) // lambda_param_no_default+ && - (b = _loop0_103_rule(p)) // lambda_param_with_default* + (b = _loop0_102_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15165,7 +15116,7 @@ lambda_parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_104_rule(p)) // lambda_param_with_default+ + (a = _loop1_103_rule(p)) // lambda_param_with_default+ && (b = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15238,7 +15189,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_105_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_104_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15267,7 +15218,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_106_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_105_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15319,9 +15270,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_107_rule(p)) // lambda_param_no_default* + (a = _loop0_106_rule(p)) // lambda_param_no_default* && - (b = _loop1_108_rule(p)) // lambda_param_with_default+ + (b = _loop1_107_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15351,9 +15302,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_109_rule(p)) // lambda_param_no_default* + (a = _loop0_108_rule(p)) // lambda_param_no_default* && - (b = _loop1_110_rule(p)) // lambda_param_with_default+ + (b = _loop1_109_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15430,7 +15381,7 @@ lambda_star_etc_rule(Parser *p) && (a = lambda_param_no_default_rule(p)) // lambda_param_no_default && - (b = _loop0_111_rule(p)) // lambda_param_maybe_default* + (b = _loop0_110_rule(p)) // lambda_param_maybe_default* && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15463,7 +15414,7 @@ lambda_star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_112_rule(p)) // lambda_param_maybe_default+ + (b = _loop1_111_rule(p)) // lambda_param_maybe_default+ && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15928,7 +15879,7 @@ fstring_middle_rule(Parser *p) } // fstring_replacement_field: -// | '{' (yield_expr | star_expressions) "="? fstring_conversion? fstring_full_format_spec? '}' +// | '{' (yield_expr | star_expressions) '='? fstring_conversion? fstring_full_format_spec? '}' // | invalid_replacement_field static expr_ty fstring_replacement_field_rule(Parser *p) @@ -15951,12 +15902,12 @@ fstring_replacement_field_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '{' (yield_expr | star_expressions) "="? fstring_conversion? fstring_full_format_spec? '}' + { // '{' (yield_expr | star_expressions) '='? fstring_conversion? fstring_full_format_spec? '}' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> fstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'")); + D(fprintf(stderr, "%*c> fstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? fstring_conversion? fstring_full_format_spec? '}'")); Token * _literal; void *a; void *conversion; @@ -15966,9 +15917,9 @@ fstring_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (a = _tmp_113_rule(p)) // yield_expr | star_expressions + (a = _tmp_112_rule(p)) // yield_expr | star_expressions && - (debug_expr = _PyPegen_expect_token(p, 22), !p->error_indicator) // "="? + (debug_expr = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && (conversion = fstring_conversion_rule(p), !p->error_indicator) // fstring_conversion? && @@ -15977,7 +15928,7 @@ fstring_replacement_field_rule(Parser *p) (rbrace = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'")); + D(fprintf(stderr, "%*c+ fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? fstring_conversion? fstring_full_format_spec? '}'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -15997,7 +15948,7 @@ fstring_replacement_field_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s fstring_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? fstring_conversion? fstring_full_format_spec? '}'")); } if (p->call_invalid_rules) { // invalid_replacement_field if (p->error_indicator) { @@ -16103,7 +16054,7 @@ fstring_full_format_spec_rule(Parser *p) if ( (colon = _PyPegen_expect_token(p, 11)) // token=':' && - (spec = _loop0_114_rule(p)) // fstring_format_spec* + (spec = _loop0_113_rule(p)) // fstring_format_spec* ) { D(fprintf(stderr, "%*c+ fstring_full_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' fstring_format_spec*")); @@ -16196,6 +16147,55 @@ fstring_format_spec_rule(Parser *p) return _res; } +// fstring: FSTRING_START fstring_middle* FSTRING_END +static expr_ty +fstring_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + { // FSTRING_START fstring_middle* FSTRING_END + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); + Token * a; + asdl_seq * b; + Token * c; + if ( + (a = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' + && + (b = _loop0_114_rule(p)) // fstring_middle* + && + (c = _PyPegen_expect_token(p, FSTRING_END)) // token='FSTRING_END' + ) + { + D(fprintf(stderr, "%*c+ fstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); + _res = _PyPegen_joined_str ( p , a , ( asdl_expr_seq* ) b , c ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // string: STRING static expr_ty string_rule(Parser *p) @@ -25070,76 +25070,9 @@ _loop0_2_rule(Parser *p) return _seq; } -// _loop0_3: fstring_middle -static asdl_seq * -_loop0_3_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // fstring_middle - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_3[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); - expr_ty fstring_middle_var; - while ( - (fstring_middle_var = fstring_middle_rule(p)) // fstring_middle - ) - { - _res = fstring_middle_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_3[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_middle")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop1_4: statement +// _loop1_3: statement static asdl_seq * -_loop1_4_rule(Parser *p) +_loop1_3_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25164,7 +25097,7 @@ _loop1_4_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_4[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement")); + D(fprintf(stderr, "%*c> _loop1_3[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement")); asdl_stmt_seq* statement_var; while ( (statement_var = statement_rule(p)) // statement @@ -25187,7 +25120,7 @@ _loop1_4_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_4[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_3[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "statement")); } if (_n == 0 || p->error_indicator) { @@ -25209,9 +25142,9 @@ _loop1_4_rule(Parser *p) return _seq; } -// _loop0_6: ';' simple_stmt +// _loop0_5: ';' simple_stmt static asdl_seq * -_loop0_6_rule(Parser *p) +_loop0_5_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25236,7 +25169,7 @@ _loop0_6_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';' simple_stmt")); + D(fprintf(stderr, "%*c> _loop0_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';' simple_stmt")); Token * _literal; stmt_ty elem; while ( @@ -25268,7 +25201,7 @@ _loop0_6_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_6[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_5[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';' simple_stmt")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -25285,9 +25218,9 @@ _loop0_6_rule(Parser *p) return _seq; } -// _gather_5: simple_stmt _loop0_6 +// _gather_4: simple_stmt _loop0_5 static asdl_seq * -_gather_5_rule(Parser *p) +_gather_4_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25298,27 +25231,27 @@ _gather_5_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // simple_stmt _loop0_6 + { // simple_stmt _loop0_5 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_6")); + D(fprintf(stderr, "%*c> _gather_4[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_5")); stmt_ty elem; asdl_seq * seq; if ( (elem = simple_stmt_rule(p)) // simple_stmt && - (seq = _loop0_6_rule(p)) // _loop0_6 + (seq = _loop0_5_rule(p)) // _loop0_5 ) { - D(fprintf(stderr, "%*c+ _gather_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_6")); + D(fprintf(stderr, "%*c+ _gather_4[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_5")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_5[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "simple_stmt _loop0_6")); + D(fprintf(stderr, "%*c%s _gather_4[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "simple_stmt _loop0_5")); } _res = NULL; done: @@ -25326,9 +25259,9 @@ _gather_5_rule(Parser *p) return _res; } -// _tmp_7: 'import' | 'from' +// _tmp_6: 'import' | 'from' static void * -_tmp_7_rule(Parser *p) +_tmp_6_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25344,18 +25277,18 @@ _tmp_7_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); + D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 607)) // token='import' ) { - D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); + D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_6[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'import'")); } { // 'from' @@ -25363,18 +25296,18 @@ _tmp_7_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); + D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 608)) // token='from' ) { - D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); + D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_6[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from'")); } _res = NULL; @@ -25383,9 +25316,9 @@ _tmp_7_rule(Parser *p) return _res; } -// _tmp_8: 'def' | '@' | ASYNC +// _tmp_7: 'def' | '@' | ASYNC static void * -_tmp_8_rule(Parser *p) +_tmp_7_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25401,18 +25334,18 @@ _tmp_8_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); + D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 652)) // token='def' ) { - D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); + D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'def'")); } { // '@' @@ -25420,18 +25353,18 @@ _tmp_8_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 49)) // token='@' ) { - D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); } { // ASYNC @@ -25439,18 +25372,18 @@ _tmp_8_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); Token * async_var; if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' ) { - D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); _res = async_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC")); } _res = NULL; @@ -25459,9 +25392,9 @@ _tmp_8_rule(Parser *p) return _res; } -// _tmp_9: 'class' | '@' +// _tmp_8: 'class' | '@' static void * -_tmp_9_rule(Parser *p) +_tmp_8_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25477,18 +25410,18 @@ _tmp_9_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); + D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 654)) // token='class' ) { - D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); + D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class'")); } { // '@' @@ -25496,18 +25429,18 @@ _tmp_9_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 49)) // token='@' ) { - D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); } _res = NULL; @@ -25516,9 +25449,9 @@ _tmp_9_rule(Parser *p) return _res; } -// _tmp_10: 'with' | ASYNC +// _tmp_9: 'with' | ASYNC static void * -_tmp_10_rule(Parser *p) +_tmp_9_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25534,18 +25467,18 @@ _tmp_10_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); + D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 615)) // token='with' ) { - D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); + D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'with'")); } { // ASYNC @@ -25553,18 +25486,18 @@ _tmp_10_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); Token * async_var; if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' ) { - D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); _res = async_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC")); } _res = NULL; @@ -25573,9 +25506,9 @@ _tmp_10_rule(Parser *p) return _res; } -// _tmp_11: 'for' | ASYNC +// _tmp_10: 'for' | ASYNC static void * -_tmp_11_rule(Parser *p) +_tmp_10_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25591,18 +25524,18 @@ _tmp_11_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); + D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 650)) // token='for' ) { - D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); + D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'for'")); } { // ASYNC @@ -25610,18 +25543,18 @@ _tmp_11_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); Token * async_var; if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' ) { - D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); _res = async_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC")); } _res = NULL; @@ -25630,9 +25563,9 @@ _tmp_11_rule(Parser *p) return _res; } -// _tmp_12: '=' annotated_rhs +// _tmp_11: '=' annotated_rhs static void * -_tmp_12_rule(Parser *p) +_tmp_11_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25648,7 +25581,7 @@ _tmp_12_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); Token * _literal; expr_ty d; if ( @@ -25657,7 +25590,7 @@ _tmp_12_rule(Parser *p) (d = annotated_rhs_rule(p)) // annotated_rhs ) { - D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25667,7 +25600,7 @@ _tmp_12_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'=' annotated_rhs")); } _res = NULL; @@ -25676,9 +25609,9 @@ _tmp_12_rule(Parser *p) return _res; } -// _tmp_13: '(' single_target ')' | single_subscript_attribute_target +// _tmp_12: '(' single_target ')' | single_subscript_attribute_target static void * -_tmp_13_rule(Parser *p) +_tmp_12_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25694,7 +25627,7 @@ _tmp_13_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); + D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); Token * _literal; Token * _literal_1; expr_ty b; @@ -25706,7 +25639,7 @@ _tmp_13_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); + D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); _res = b; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25716,7 +25649,7 @@ _tmp_13_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' single_target ')'")); } { // single_subscript_attribute_target @@ -25724,18 +25657,18 @@ _tmp_13_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); + D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); expr_ty single_subscript_attribute_target_var; if ( (single_subscript_attribute_target_var = single_subscript_attribute_target_rule(p)) // single_subscript_attribute_target ) { - D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); + D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); _res = single_subscript_attribute_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "single_subscript_attribute_target")); } _res = NULL; @@ -25744,9 +25677,9 @@ _tmp_13_rule(Parser *p) return _res; } -// _tmp_14: '=' annotated_rhs +// _tmp_13: '=' annotated_rhs static void * -_tmp_14_rule(Parser *p) +_tmp_13_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25762,7 +25695,7 @@ _tmp_14_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); Token * _literal; expr_ty d; if ( @@ -25771,7 +25704,7 @@ _tmp_14_rule(Parser *p) (d = annotated_rhs_rule(p)) // annotated_rhs ) { - D(fprintf(stderr, "%*c+ _tmp_14[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25781,7 +25714,7 @@ _tmp_14_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_14[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'=' annotated_rhs")); } _res = NULL; @@ -25790,9 +25723,9 @@ _tmp_14_rule(Parser *p) return _res; } -// _loop1_15: (star_targets '=') +// _loop1_14: (star_targets '=') static asdl_seq * -_loop1_15_rule(Parser *p) +_loop1_14_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25817,7 +25750,7 @@ _loop1_15_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + D(fprintf(stderr, "%*c> _loop1_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); void *_tmp_247_var; while ( (_tmp_247_var = _tmp_247_rule(p)) // star_targets '=' @@ -25840,7 +25773,7 @@ _loop1_15_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_15[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_14[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } if (_n == 0 || p->error_indicator) { @@ -25862,9 +25795,9 @@ _loop1_15_rule(Parser *p) return _seq; } -// _tmp_16: yield_expr | star_expressions +// _tmp_15: yield_expr | star_expressions static void * -_tmp_16_rule(Parser *p) +_tmp_15_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25880,18 +25813,18 @@ _tmp_16_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_15[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_15[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -25899,18 +25832,18 @@ _tmp_16_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_15[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_15[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -25919,9 +25852,9 @@ _tmp_16_rule(Parser *p) return _res; } -// _tmp_17: yield_expr | star_expressions +// _tmp_16: yield_expr | star_expressions static void * -_tmp_17_rule(Parser *p) +_tmp_16_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25937,18 +25870,18 @@ _tmp_17_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -25956,18 +25889,18 @@ _tmp_17_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -25976,9 +25909,9 @@ _tmp_17_rule(Parser *p) return _res; } -// _tmp_18: 'from' expression +// _tmp_17: 'from' expression static void * -_tmp_18_rule(Parser *p) +_tmp_17_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -25994,7 +25927,7 @@ _tmp_18_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression")); + D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression")); Token * _keyword; expr_ty z; if ( @@ -26003,7 +25936,7 @@ _tmp_18_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_18[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression")); + D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26013,7 +25946,7 @@ _tmp_18_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_18[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from' expression")); } _res = NULL; @@ -26022,9 +25955,9 @@ _tmp_18_rule(Parser *p) return _res; } -// _loop0_20: ',' NAME +// _loop0_19: ',' NAME static asdl_seq * -_loop0_20_rule(Parser *p) +_loop0_19_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26049,7 +25982,7 @@ _loop0_20_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); + D(fprintf(stderr, "%*c> _loop0_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); Token * _literal; expr_ty elem; while ( @@ -26081,7 +26014,7 @@ _loop0_20_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_20[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_19[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' NAME")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26098,9 +26031,9 @@ _loop0_20_rule(Parser *p) return _seq; } -// _gather_19: NAME _loop0_20 +// _gather_18: NAME _loop0_19 static asdl_seq * -_gather_19_rule(Parser *p) +_gather_18_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26111,27 +26044,27 @@ _gather_19_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // NAME _loop0_20 + { // NAME _loop0_19 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_20")); + D(fprintf(stderr, "%*c> _gather_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_19")); expr_ty elem; asdl_seq * seq; if ( (elem = _PyPegen_name_token(p)) // NAME && - (seq = _loop0_20_rule(p)) // _loop0_20 + (seq = _loop0_19_rule(p)) // _loop0_19 ) { - D(fprintf(stderr, "%*c+ _gather_19[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_20")); + D(fprintf(stderr, "%*c+ _gather_18[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_19")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_19[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_20")); + D(fprintf(stderr, "%*c%s _gather_18[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_19")); } _res = NULL; done: @@ -26139,9 +26072,9 @@ _gather_19_rule(Parser *p) return _res; } -// _loop0_22: ',' NAME +// _loop0_21: ',' NAME static asdl_seq * -_loop0_22_rule(Parser *p) +_loop0_21_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26166,7 +26099,7 @@ _loop0_22_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); + D(fprintf(stderr, "%*c> _loop0_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); Token * _literal; expr_ty elem; while ( @@ -26198,7 +26131,7 @@ _loop0_22_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_22[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_21[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' NAME")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26215,9 +26148,9 @@ _loop0_22_rule(Parser *p) return _seq; } -// _gather_21: NAME _loop0_22 +// _gather_20: NAME _loop0_21 static asdl_seq * -_gather_21_rule(Parser *p) +_gather_20_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26228,27 +26161,27 @@ _gather_21_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // NAME _loop0_22 + { // NAME _loop0_21 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_22")); + D(fprintf(stderr, "%*c> _gather_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_21")); expr_ty elem; asdl_seq * seq; if ( (elem = _PyPegen_name_token(p)) // NAME && - (seq = _loop0_22_rule(p)) // _loop0_22 + (seq = _loop0_21_rule(p)) // _loop0_21 ) { - D(fprintf(stderr, "%*c+ _gather_21[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_22")); + D(fprintf(stderr, "%*c+ _gather_20[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_21")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_21[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_22")); + D(fprintf(stderr, "%*c%s _gather_20[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_21")); } _res = NULL; done: @@ -26256,9 +26189,9 @@ _gather_21_rule(Parser *p) return _res; } -// _tmp_23: ';' | NEWLINE +// _tmp_22: ';' | NEWLINE static void * -_tmp_23_rule(Parser *p) +_tmp_22_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26274,18 +26207,18 @@ _tmp_23_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c> _tmp_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 13)) // token=';' ) { - D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c+ _tmp_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_22[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';'")); } { // NEWLINE @@ -26293,18 +26226,18 @@ _tmp_23_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_22[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } _res = NULL; @@ -26313,9 +26246,9 @@ _tmp_23_rule(Parser *p) return _res; } -// _tmp_24: ',' expression +// _tmp_23: ',' expression static void * -_tmp_24_rule(Parser *p) +_tmp_23_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26331,7 +26264,7 @@ _tmp_24_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty z; if ( @@ -26340,7 +26273,7 @@ _tmp_24_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_24[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26350,7 +26283,7 @@ _tmp_24_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_24[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -26359,9 +26292,9 @@ _tmp_24_rule(Parser *p) return _res; } -// _loop0_25: ('.' | '...') +// _loop0_24: ('.' | '...') static asdl_seq * -_loop0_25_rule(Parser *p) +_loop0_24_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26386,7 +26319,7 @@ _loop0_25_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); + D(fprintf(stderr, "%*c> _loop0_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); void *_tmp_248_var; while ( (_tmp_248_var = _tmp_248_rule(p)) // '.' | '...' @@ -26409,7 +26342,7 @@ _loop0_25_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_25[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_24[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26426,9 +26359,9 @@ _loop0_25_rule(Parser *p) return _seq; } -// _loop1_26: ('.' | '...') +// _loop1_25: ('.' | '...') static asdl_seq * -_loop1_26_rule(Parser *p) +_loop1_25_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26453,7 +26386,7 @@ _loop1_26_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); + D(fprintf(stderr, "%*c> _loop1_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); void *_tmp_249_var; while ( (_tmp_249_var = _tmp_249_rule(p)) // '.' | '...' @@ -26476,7 +26409,7 @@ _loop1_26_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_26[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_25[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')")); } if (_n == 0 || p->error_indicator) { @@ -26498,9 +26431,9 @@ _loop1_26_rule(Parser *p) return _seq; } -// _loop0_28: ',' import_from_as_name +// _loop0_27: ',' import_from_as_name static asdl_seq * -_loop0_28_rule(Parser *p) +_loop0_27_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26525,7 +26458,7 @@ _loop0_28_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name")); + D(fprintf(stderr, "%*c> _loop0_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name")); Token * _literal; alias_ty elem; while ( @@ -26557,7 +26490,7 @@ _loop0_28_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_28[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_27[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' import_from_as_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26574,9 +26507,9 @@ _loop0_28_rule(Parser *p) return _seq; } -// _gather_27: import_from_as_name _loop0_28 +// _gather_26: import_from_as_name _loop0_27 static asdl_seq * -_gather_27_rule(Parser *p) +_gather_26_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26587,27 +26520,27 @@ _gather_27_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // import_from_as_name _loop0_28 + { // import_from_as_name _loop0_27 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_28")); + D(fprintf(stderr, "%*c> _gather_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_27")); alias_ty elem; asdl_seq * seq; if ( (elem = import_from_as_name_rule(p)) // import_from_as_name && - (seq = _loop0_28_rule(p)) // _loop0_28 + (seq = _loop0_27_rule(p)) // _loop0_27 ) { - D(fprintf(stderr, "%*c+ _gather_27[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_28")); + D(fprintf(stderr, "%*c+ _gather_26[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_27")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_27[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_28")); + D(fprintf(stderr, "%*c%s _gather_26[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_27")); } _res = NULL; done: @@ -26615,9 +26548,9 @@ _gather_27_rule(Parser *p) return _res; } -// _tmp_29: 'as' NAME +// _tmp_28: 'as' NAME static void * -_tmp_29_rule(Parser *p) +_tmp_28_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26633,7 +26566,7 @@ _tmp_29_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( @@ -26642,7 +26575,7 @@ _tmp_29_rule(Parser *p) (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_29[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_28[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26652,7 +26585,7 @@ _tmp_29_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_29[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_28[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -26661,9 +26594,9 @@ _tmp_29_rule(Parser *p) return _res; } -// _loop0_31: ',' dotted_as_name +// _loop0_30: ',' dotted_as_name static asdl_seq * -_loop0_31_rule(Parser *p) +_loop0_30_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26688,7 +26621,7 @@ _loop0_31_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name")); + D(fprintf(stderr, "%*c> _loop0_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name")); Token * _literal; alias_ty elem; while ( @@ -26720,7 +26653,7 @@ _loop0_31_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_31[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_30[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_as_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26737,9 +26670,9 @@ _loop0_31_rule(Parser *p) return _seq; } -// _gather_30: dotted_as_name _loop0_31 +// _gather_29: dotted_as_name _loop0_30 static asdl_seq * -_gather_30_rule(Parser *p) +_gather_29_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26750,27 +26683,27 @@ _gather_30_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // dotted_as_name _loop0_31 + { // dotted_as_name _loop0_30 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_31")); + D(fprintf(stderr, "%*c> _gather_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_30")); alias_ty elem; asdl_seq * seq; if ( (elem = dotted_as_name_rule(p)) // dotted_as_name && - (seq = _loop0_31_rule(p)) // _loop0_31 + (seq = _loop0_30_rule(p)) // _loop0_30 ) { - D(fprintf(stderr, "%*c+ _gather_30[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_31")); + D(fprintf(stderr, "%*c+ _gather_29[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_30")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_30[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_31")); + D(fprintf(stderr, "%*c%s _gather_29[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_30")); } _res = NULL; done: @@ -26778,9 +26711,9 @@ _gather_30_rule(Parser *p) return _res; } -// _tmp_32: 'as' NAME +// _tmp_31: 'as' NAME static void * -_tmp_32_rule(Parser *p) +_tmp_31_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26796,7 +26729,7 @@ _tmp_32_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( @@ -26805,7 +26738,7 @@ _tmp_32_rule(Parser *p) (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_32[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_31[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26815,7 +26748,7 @@ _tmp_32_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_32[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_31[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -26824,9 +26757,9 @@ _tmp_32_rule(Parser *p) return _res; } -// _loop1_33: ('@' named_expression NEWLINE) +// _loop1_32: ('@' named_expression NEWLINE) static asdl_seq * -_loop1_33_rule(Parser *p) +_loop1_32_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26851,7 +26784,7 @@ _loop1_33_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); + D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); void *_tmp_250_var; while ( (_tmp_250_var = _tmp_250_rule(p)) // '@' named_expression NEWLINE @@ -26874,7 +26807,7 @@ _loop1_33_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_33[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_32[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('@' named_expression NEWLINE)")); } if (_n == 0 || p->error_indicator) { @@ -26896,9 +26829,9 @@ _loop1_33_rule(Parser *p) return _seq; } -// _tmp_34: '(' arguments? ')' +// _tmp_33: '(' arguments? ')' static void * -_tmp_34_rule(Parser *p) +_tmp_33_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26914,7 +26847,7 @@ _tmp_34_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *z; @@ -26926,7 +26859,7 @@ _tmp_34_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_34[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_33[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26936,7 +26869,7 @@ _tmp_34_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_34[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_33[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -26945,9 +26878,9 @@ _tmp_34_rule(Parser *p) return _res; } -// _tmp_35: '->' expression +// _tmp_34: '->' expression static void * -_tmp_35_rule(Parser *p) +_tmp_34_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -26963,7 +26896,7 @@ _tmp_35_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty z; if ( @@ -26972,7 +26905,7 @@ _tmp_35_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_35[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_34[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -26982,7 +26915,7 @@ _tmp_35_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_35[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_34[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -26991,9 +26924,9 @@ _tmp_35_rule(Parser *p) return _res; } -// _tmp_36: '->' expression +// _tmp_35: '->' expression static void * -_tmp_36_rule(Parser *p) +_tmp_35_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27009,7 +26942,7 @@ _tmp_36_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty z; if ( @@ -27018,7 +26951,7 @@ _tmp_36_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_36[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_35[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -27028,7 +26961,7 @@ _tmp_36_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_36[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_35[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -27037,9 +26970,9 @@ _tmp_36_rule(Parser *p) return _res; } -// _loop0_37: param_no_default +// _loop0_36: param_no_default static asdl_seq * -_loop0_37_rule(Parser *p) +_loop0_36_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27064,7 +26997,7 @@ _loop0_37_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -27087,7 +27020,7 @@ _loop0_37_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_37[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_36[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27104,9 +27037,9 @@ _loop0_37_rule(Parser *p) return _seq; } -// _loop0_38: param_with_default +// _loop0_37: param_with_default static asdl_seq * -_loop0_38_rule(Parser *p) +_loop0_37_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27131,7 +27064,7 @@ _loop0_38_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop0_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -27154,7 +27087,7 @@ _loop0_38_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_38[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_37[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27171,9 +27104,9 @@ _loop0_38_rule(Parser *p) return _seq; } -// _loop0_39: param_with_default +// _loop0_38: param_with_default static asdl_seq * -_loop0_39_rule(Parser *p) +_loop0_38_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27198,7 +27131,7 @@ _loop0_39_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop0_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -27221,7 +27154,7 @@ _loop0_39_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_39[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_38[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27238,9 +27171,9 @@ _loop0_39_rule(Parser *p) return _seq; } -// _loop1_40: param_no_default +// _loop1_39: param_no_default static asdl_seq * -_loop1_40_rule(Parser *p) +_loop1_39_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27265,7 +27198,7 @@ _loop1_40_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -27288,7 +27221,7 @@ _loop1_40_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_40[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_39[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -27310,9 +27243,9 @@ _loop1_40_rule(Parser *p) return _seq; } -// _loop0_41: param_with_default +// _loop0_40: param_with_default static asdl_seq * -_loop0_41_rule(Parser *p) +_loop0_40_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27337,7 +27270,7 @@ _loop0_41_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop0_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -27360,7 +27293,7 @@ _loop0_41_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_41[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_40[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27377,9 +27310,9 @@ _loop0_41_rule(Parser *p) return _seq; } -// _loop1_42: param_with_default +// _loop1_41: param_with_default static asdl_seq * -_loop1_42_rule(Parser *p) +_loop1_41_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27404,7 +27337,7 @@ _loop1_42_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -27427,7 +27360,7 @@ _loop1_42_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_42[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_41[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -27449,9 +27382,9 @@ _loop1_42_rule(Parser *p) return _seq; } -// _loop1_43: param_no_default +// _loop1_42: param_no_default static asdl_seq * -_loop1_43_rule(Parser *p) +_loop1_42_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27476,7 +27409,7 @@ _loop1_43_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -27499,7 +27432,7 @@ _loop1_43_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_43[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_42[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -27521,9 +27454,9 @@ _loop1_43_rule(Parser *p) return _seq; } -// _loop1_44: param_no_default +// _loop1_43: param_no_default static asdl_seq * -_loop1_44_rule(Parser *p) +_loop1_43_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27548,7 +27481,7 @@ _loop1_44_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -27571,7 +27504,7 @@ _loop1_44_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_44[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_43[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -27593,9 +27526,9 @@ _loop1_44_rule(Parser *p) return _seq; } -// _loop0_45: param_no_default +// _loop0_44: param_no_default static asdl_seq * -_loop0_45_rule(Parser *p) +_loop0_44_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27620,7 +27553,7 @@ _loop0_45_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -27643,7 +27576,7 @@ _loop0_45_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_45[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_44[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27660,9 +27593,9 @@ _loop0_45_rule(Parser *p) return _seq; } -// _loop1_46: param_with_default +// _loop1_45: param_with_default static asdl_seq * -_loop1_46_rule(Parser *p) +_loop1_45_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27687,7 +27620,7 @@ _loop1_46_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -27710,7 +27643,7 @@ _loop1_46_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_46[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_45[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -27732,9 +27665,9 @@ _loop1_46_rule(Parser *p) return _seq; } -// _loop0_47: param_no_default +// _loop0_46: param_no_default static asdl_seq * -_loop0_47_rule(Parser *p) +_loop0_46_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27759,7 +27692,7 @@ _loop0_47_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -27782,7 +27715,7 @@ _loop0_47_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_47[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_46[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27799,9 +27732,9 @@ _loop0_47_rule(Parser *p) return _seq; } -// _loop1_48: param_with_default +// _loop1_47: param_with_default static asdl_seq * -_loop1_48_rule(Parser *p) +_loop1_47_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27826,7 +27759,7 @@ _loop1_48_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -27849,7 +27782,7 @@ _loop1_48_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_48[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_47[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -27871,9 +27804,9 @@ _loop1_48_rule(Parser *p) return _seq; } -// _loop0_49: param_maybe_default +// _loop0_48: param_maybe_default static asdl_seq * -_loop0_49_rule(Parser *p) +_loop0_48_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27898,7 +27831,7 @@ _loop0_49_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -27921,7 +27854,7 @@ _loop0_49_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_49[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_48[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27938,9 +27871,9 @@ _loop0_49_rule(Parser *p) return _seq; } -// _loop0_50: param_maybe_default +// _loop0_49: param_maybe_default static asdl_seq * -_loop0_50_rule(Parser *p) +_loop0_49_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -27965,7 +27898,7 @@ _loop0_50_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -27988,7 +27921,7 @@ _loop0_50_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_50[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_49[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28005,9 +27938,9 @@ _loop0_50_rule(Parser *p) return _seq; } -// _loop1_51: param_maybe_default +// _loop1_50: param_maybe_default static asdl_seq * -_loop1_51_rule(Parser *p) +_loop1_50_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28032,7 +27965,7 @@ _loop1_51_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -28055,7 +27988,7 @@ _loop1_51_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_51[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_50[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -28077,9 +28010,9 @@ _loop1_51_rule(Parser *p) return _seq; } -// _loop0_53: ',' with_item +// _loop0_52: ',' with_item static asdl_seq * -_loop0_53_rule(Parser *p) +_loop0_52_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28104,7 +28037,7 @@ _loop0_53_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -28136,7 +28069,7 @@ _loop0_53_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_53[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_52[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28153,9 +28086,9 @@ _loop0_53_rule(Parser *p) return _seq; } -// _gather_52: with_item _loop0_53 +// _gather_51: with_item _loop0_52 static asdl_seq * -_gather_52_rule(Parser *p) +_gather_51_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28166,27 +28099,27 @@ _gather_52_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_53 + { // with_item _loop0_52 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_53")); + D(fprintf(stderr, "%*c> _gather_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_52")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_53_rule(p)) // _loop0_53 + (seq = _loop0_52_rule(p)) // _loop0_52 ) { - D(fprintf(stderr, "%*c+ _gather_52[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_53")); + D(fprintf(stderr, "%*c+ _gather_51[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_52")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_52[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_53")); + D(fprintf(stderr, "%*c%s _gather_51[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_52")); } _res = NULL; done: @@ -28194,9 +28127,9 @@ _gather_52_rule(Parser *p) return _res; } -// _loop0_55: ',' with_item +// _loop0_54: ',' with_item static asdl_seq * -_loop0_55_rule(Parser *p) +_loop0_54_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28221,7 +28154,7 @@ _loop0_55_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -28253,7 +28186,7 @@ _loop0_55_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_55[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_54[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28270,9 +28203,9 @@ _loop0_55_rule(Parser *p) return _seq; } -// _gather_54: with_item _loop0_55 +// _gather_53: with_item _loop0_54 static asdl_seq * -_gather_54_rule(Parser *p) +_gather_53_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28283,27 +28216,27 @@ _gather_54_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_55 + { // with_item _loop0_54 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_55")); + D(fprintf(stderr, "%*c> _gather_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_54")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_55_rule(p)) // _loop0_55 + (seq = _loop0_54_rule(p)) // _loop0_54 ) { - D(fprintf(stderr, "%*c+ _gather_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_55")); + D(fprintf(stderr, "%*c+ _gather_53[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_54")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_54[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_55")); + D(fprintf(stderr, "%*c%s _gather_53[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_54")); } _res = NULL; done: @@ -28311,9 +28244,9 @@ _gather_54_rule(Parser *p) return _res; } -// _loop0_57: ',' with_item +// _loop0_56: ',' with_item static asdl_seq * -_loop0_57_rule(Parser *p) +_loop0_56_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28338,7 +28271,7 @@ _loop0_57_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -28370,7 +28303,7 @@ _loop0_57_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_57[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_56[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28387,9 +28320,9 @@ _loop0_57_rule(Parser *p) return _seq; } -// _gather_56: with_item _loop0_57 +// _gather_55: with_item _loop0_56 static asdl_seq * -_gather_56_rule(Parser *p) +_gather_55_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28400,27 +28333,27 @@ _gather_56_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_57 + { // with_item _loop0_56 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_57")); + D(fprintf(stderr, "%*c> _gather_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_56")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_57_rule(p)) // _loop0_57 + (seq = _loop0_56_rule(p)) // _loop0_56 ) { - D(fprintf(stderr, "%*c+ _gather_56[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_57")); + D(fprintf(stderr, "%*c+ _gather_55[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_56")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_56[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_57")); + D(fprintf(stderr, "%*c%s _gather_55[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_56")); } _res = NULL; done: @@ -28428,9 +28361,9 @@ _gather_56_rule(Parser *p) return _res; } -// _loop0_59: ',' with_item +// _loop0_58: ',' with_item static asdl_seq * -_loop0_59_rule(Parser *p) +_loop0_58_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28455,7 +28388,7 @@ _loop0_59_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -28487,7 +28420,7 @@ _loop0_59_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_59[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_58[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28504,9 +28437,9 @@ _loop0_59_rule(Parser *p) return _seq; } -// _gather_58: with_item _loop0_59 +// _gather_57: with_item _loop0_58 static asdl_seq * -_gather_58_rule(Parser *p) +_gather_57_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28517,27 +28450,27 @@ _gather_58_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_59 + { // with_item _loop0_58 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_59")); + D(fprintf(stderr, "%*c> _gather_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_58")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_59_rule(p)) // _loop0_59 + (seq = _loop0_58_rule(p)) // _loop0_58 ) { - D(fprintf(stderr, "%*c+ _gather_58[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_59")); + D(fprintf(stderr, "%*c+ _gather_57[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_58")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_58[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_59")); + D(fprintf(stderr, "%*c%s _gather_57[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_58")); } _res = NULL; done: @@ -28545,9 +28478,9 @@ _gather_58_rule(Parser *p) return _res; } -// _tmp_60: ',' | ')' | ':' +// _tmp_59: ',' | ')' | ':' static void * -_tmp_60_rule(Parser *p) +_tmp_59_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28563,18 +28496,18 @@ _tmp_60_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -28582,18 +28515,18 @@ _tmp_60_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -28601,18 +28534,18 @@ _tmp_60_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -28621,9 +28554,9 @@ _tmp_60_rule(Parser *p) return _res; } -// _loop1_61: except_block +// _loop1_60: except_block static asdl_seq * -_loop1_61_rule(Parser *p) +_loop1_60_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28648,7 +28581,7 @@ _loop1_61_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); excepthandler_ty except_block_var; while ( (except_block_var = except_block_rule(p)) // except_block @@ -28671,7 +28604,7 @@ _loop1_61_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_60[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -28693,9 +28626,9 @@ _loop1_61_rule(Parser *p) return _seq; } -// _loop1_62: except_star_block +// _loop1_61: except_star_block static asdl_seq * -_loop1_62_rule(Parser *p) +_loop1_61_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28720,7 +28653,7 @@ _loop1_62_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); excepthandler_ty except_star_block_var; while ( (except_star_block_var = except_star_block_rule(p)) // except_star_block @@ -28743,7 +28676,7 @@ _loop1_62_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_62[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -28765,9 +28698,9 @@ _loop1_62_rule(Parser *p) return _seq; } -// _tmp_63: 'as' NAME +// _tmp_62: 'as' NAME static void * -_tmp_63_rule(Parser *p) +_tmp_62_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28783,7 +28716,7 @@ _tmp_63_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( @@ -28792,7 +28725,7 @@ _tmp_63_rule(Parser *p) (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_63[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_62[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -28802,7 +28735,7 @@ _tmp_63_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_63[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_62[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -28811,9 +28744,9 @@ _tmp_63_rule(Parser *p) return _res; } -// _tmp_64: 'as' NAME +// _tmp_63: 'as' NAME static void * -_tmp_64_rule(Parser *p) +_tmp_63_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28829,7 +28762,7 @@ _tmp_64_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( @@ -28838,7 +28771,7 @@ _tmp_64_rule(Parser *p) (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_64[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_63[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -28848,7 +28781,7 @@ _tmp_64_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_64[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_63[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -28857,9 +28790,9 @@ _tmp_64_rule(Parser *p) return _res; } -// _loop1_65: case_block +// _loop1_64: case_block static asdl_seq * -_loop1_65_rule(Parser *p) +_loop1_64_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28884,7 +28817,7 @@ _loop1_65_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block")); + D(fprintf(stderr, "%*c> _loop1_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block")); match_case_ty case_block_var; while ( (case_block_var = case_block_rule(p)) // case_block @@ -28907,7 +28840,7 @@ _loop1_65_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_65[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_64[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "case_block")); } if (_n == 0 || p->error_indicator) { @@ -28929,9 +28862,9 @@ _loop1_65_rule(Parser *p) return _seq; } -// _loop0_67: '|' closed_pattern +// _loop0_66: '|' closed_pattern static asdl_seq * -_loop0_67_rule(Parser *p) +_loop0_66_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -28956,7 +28889,7 @@ _loop0_67_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern")); + D(fprintf(stderr, "%*c> _loop0_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern")); Token * _literal; pattern_ty elem; while ( @@ -28988,7 +28921,7 @@ _loop0_67_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_67[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_66[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'|' closed_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29005,9 +28938,9 @@ _loop0_67_rule(Parser *p) return _seq; } -// _gather_66: closed_pattern _loop0_67 +// _gather_65: closed_pattern _loop0_66 static asdl_seq * -_gather_66_rule(Parser *p) +_gather_65_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29018,27 +28951,27 @@ _gather_66_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // closed_pattern _loop0_67 + { // closed_pattern _loop0_66 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_67")); + D(fprintf(stderr, "%*c> _gather_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_66")); pattern_ty elem; asdl_seq * seq; if ( (elem = closed_pattern_rule(p)) // closed_pattern && - (seq = _loop0_67_rule(p)) // _loop0_67 + (seq = _loop0_66_rule(p)) // _loop0_66 ) { - D(fprintf(stderr, "%*c+ _gather_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_67")); + D(fprintf(stderr, "%*c+ _gather_65[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_66")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_66[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_67")); + D(fprintf(stderr, "%*c%s _gather_65[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_66")); } _res = NULL; done: @@ -29046,9 +28979,9 @@ _gather_66_rule(Parser *p) return _res; } -// _tmp_68: '+' | '-' +// _tmp_67: '+' | '-' static void * -_tmp_68_rule(Parser *p) +_tmp_67_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29064,18 +28997,18 @@ _tmp_68_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } { // '-' @@ -29083,18 +29016,18 @@ _tmp_68_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } _res = NULL; @@ -29103,9 +29036,9 @@ _tmp_68_rule(Parser *p) return _res; } -// _tmp_69: '+' | '-' +// _tmp_68: '+' | '-' static void * -_tmp_69_rule(Parser *p) +_tmp_68_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29121,18 +29054,18 @@ _tmp_69_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } { // '-' @@ -29140,18 +29073,18 @@ _tmp_69_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } _res = NULL; @@ -29160,9 +29093,9 @@ _tmp_69_rule(Parser *p) return _res; } -// _tmp_70: '.' | '(' | '=' +// _tmp_69: '.' | '(' | '=' static void * -_tmp_70_rule(Parser *p) +_tmp_69_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29178,18 +29111,18 @@ _tmp_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '(' @@ -29197,18 +29130,18 @@ _tmp_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '=' @@ -29216,18 +29149,18 @@ _tmp_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } _res = NULL; @@ -29236,9 +29169,9 @@ _tmp_70_rule(Parser *p) return _res; } -// _tmp_71: '.' | '(' | '=' +// _tmp_70: '.' | '(' | '=' static void * -_tmp_71_rule(Parser *p) +_tmp_70_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29254,18 +29187,18 @@ _tmp_71_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '(' @@ -29273,18 +29206,18 @@ _tmp_71_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '=' @@ -29292,18 +29225,18 @@ _tmp_71_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } _res = NULL; @@ -29312,9 +29245,9 @@ _tmp_71_rule(Parser *p) return _res; } -// _loop0_73: ',' maybe_star_pattern +// _loop0_72: ',' maybe_star_pattern static asdl_seq * -_loop0_73_rule(Parser *p) +_loop0_72_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29339,7 +29272,7 @@ _loop0_73_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); + D(fprintf(stderr, "%*c> _loop0_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); Token * _literal; pattern_ty elem; while ( @@ -29371,7 +29304,7 @@ _loop0_73_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_73[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_72[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' maybe_star_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29388,9 +29321,9 @@ _loop0_73_rule(Parser *p) return _seq; } -// _gather_72: maybe_star_pattern _loop0_73 +// _gather_71: maybe_star_pattern _loop0_72 static asdl_seq * -_gather_72_rule(Parser *p) +_gather_71_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29401,27 +29334,27 @@ _gather_72_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // maybe_star_pattern _loop0_73 + { // maybe_star_pattern _loop0_72 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_73")); + D(fprintf(stderr, "%*c> _gather_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_72")); pattern_ty elem; asdl_seq * seq; if ( (elem = maybe_star_pattern_rule(p)) // maybe_star_pattern && - (seq = _loop0_73_rule(p)) // _loop0_73 + (seq = _loop0_72_rule(p)) // _loop0_72 ) { - D(fprintf(stderr, "%*c+ _gather_72[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_73")); + D(fprintf(stderr, "%*c+ _gather_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_72")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_72[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_73")); + D(fprintf(stderr, "%*c%s _gather_71[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_72")); } _res = NULL; done: @@ -29429,9 +29362,9 @@ _gather_72_rule(Parser *p) return _res; } -// _loop0_75: ',' key_value_pattern +// _loop0_74: ',' key_value_pattern static asdl_seq * -_loop0_75_rule(Parser *p) +_loop0_74_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29456,7 +29389,7 @@ _loop0_75_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern")); + D(fprintf(stderr, "%*c> _loop0_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern")); Token * _literal; KeyPatternPair* elem; while ( @@ -29488,7 +29421,7 @@ _loop0_75_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_75[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_74[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' key_value_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29505,9 +29438,9 @@ _loop0_75_rule(Parser *p) return _seq; } -// _gather_74: key_value_pattern _loop0_75 +// _gather_73: key_value_pattern _loop0_74 static asdl_seq * -_gather_74_rule(Parser *p) +_gather_73_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29518,27 +29451,27 @@ _gather_74_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // key_value_pattern _loop0_75 + { // key_value_pattern _loop0_74 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_75")); + D(fprintf(stderr, "%*c> _gather_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_74")); KeyPatternPair* elem; asdl_seq * seq; if ( (elem = key_value_pattern_rule(p)) // key_value_pattern && - (seq = _loop0_75_rule(p)) // _loop0_75 + (seq = _loop0_74_rule(p)) // _loop0_74 ) { - D(fprintf(stderr, "%*c+ _gather_74[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_75")); + D(fprintf(stderr, "%*c+ _gather_73[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_74")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_74[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_75")); + D(fprintf(stderr, "%*c%s _gather_73[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_74")); } _res = NULL; done: @@ -29546,9 +29479,9 @@ _gather_74_rule(Parser *p) return _res; } -// _tmp_76: literal_expr | attr +// _tmp_75: literal_expr | attr static void * -_tmp_76_rule(Parser *p) +_tmp_75_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29564,18 +29497,18 @@ _tmp_76_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr")); + D(fprintf(stderr, "%*c> _tmp_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr")); expr_ty literal_expr_var; if ( (literal_expr_var = literal_expr_rule(p)) // literal_expr ) { - D(fprintf(stderr, "%*c+ _tmp_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr")); + D(fprintf(stderr, "%*c+ _tmp_75[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr")); _res = literal_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_76[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_75[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "literal_expr")); } { // attr @@ -29583,18 +29516,18 @@ _tmp_76_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr")); + D(fprintf(stderr, "%*c> _tmp_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr")); expr_ty attr_var; if ( (attr_var = attr_rule(p)) // attr ) { - D(fprintf(stderr, "%*c+ _tmp_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr")); + D(fprintf(stderr, "%*c+ _tmp_75[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr")); _res = attr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_76[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_75[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "attr")); } _res = NULL; @@ -29603,9 +29536,9 @@ _tmp_76_rule(Parser *p) return _res; } -// _loop0_78: ',' pattern +// _loop0_77: ',' pattern static asdl_seq * -_loop0_78_rule(Parser *p) +_loop0_77_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29630,7 +29563,7 @@ _loop0_78_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern")); + D(fprintf(stderr, "%*c> _loop0_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern")); Token * _literal; pattern_ty elem; while ( @@ -29662,7 +29595,7 @@ _loop0_78_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_77[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29679,9 +29612,9 @@ _loop0_78_rule(Parser *p) return _seq; } -// _gather_77: pattern _loop0_78 +// _gather_76: pattern _loop0_77 static asdl_seq * -_gather_77_rule(Parser *p) +_gather_76_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29692,27 +29625,27 @@ _gather_77_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // pattern _loop0_78 + { // pattern _loop0_77 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78")); + D(fprintf(stderr, "%*c> _gather_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_77")); pattern_ty elem; asdl_seq * seq; if ( (elem = pattern_rule(p)) // pattern && - (seq = _loop0_78_rule(p)) // _loop0_78 + (seq = _loop0_77_rule(p)) // _loop0_77 ) { - D(fprintf(stderr, "%*c+ _gather_77[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78")); + D(fprintf(stderr, "%*c+ _gather_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_77")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_77[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_78")); + D(fprintf(stderr, "%*c%s _gather_76[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_77")); } _res = NULL; done: @@ -29720,9 +29653,9 @@ _gather_77_rule(Parser *p) return _res; } -// _loop0_80: ',' keyword_pattern +// _loop0_79: ',' keyword_pattern static asdl_seq * -_loop0_80_rule(Parser *p) +_loop0_79_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29747,7 +29680,7 @@ _loop0_80_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); + D(fprintf(stderr, "%*c> _loop0_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); Token * _literal; KeyPatternPair* elem; while ( @@ -29779,7 +29712,7 @@ _loop0_80_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_80[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_79[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' keyword_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29796,9 +29729,9 @@ _loop0_80_rule(Parser *p) return _seq; } -// _gather_79: keyword_pattern _loop0_80 +// _gather_78: keyword_pattern _loop0_79 static asdl_seq * -_gather_79_rule(Parser *p) +_gather_78_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29809,27 +29742,27 @@ _gather_79_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // keyword_pattern _loop0_80 + { // keyword_pattern _loop0_79 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80")); + D(fprintf(stderr, "%*c> _gather_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_79")); KeyPatternPair* elem; asdl_seq * seq; if ( (elem = keyword_pattern_rule(p)) // keyword_pattern && - (seq = _loop0_80_rule(p)) // _loop0_80 + (seq = _loop0_79_rule(p)) // _loop0_79 ) { - D(fprintf(stderr, "%*c+ _gather_79[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80")); + D(fprintf(stderr, "%*c+ _gather_78[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_79")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_79[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_80")); + D(fprintf(stderr, "%*c%s _gather_78[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_79")); } _res = NULL; done: @@ -29837,9 +29770,9 @@ _gather_79_rule(Parser *p) return _res; } -// _loop0_82: ',' type_param +// _loop0_81: ',' type_param static asdl_seq * -_loop0_82_rule(Parser *p) +_loop0_81_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29864,7 +29797,7 @@ _loop0_82_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param")); + D(fprintf(stderr, "%*c> _loop0_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param")); Token * _literal; type_param_ty elem; while ( @@ -29896,7 +29829,7 @@ _loop0_82_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_82[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_81[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' type_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29913,9 +29846,9 @@ _loop0_82_rule(Parser *p) return _seq; } -// _gather_81: type_param _loop0_82 +// _gather_80: type_param _loop0_81 static asdl_seq * -_gather_81_rule(Parser *p) +_gather_80_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29926,27 +29859,27 @@ _gather_81_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // type_param _loop0_82 + { // type_param _loop0_81 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_82")); + D(fprintf(stderr, "%*c> _gather_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_81")); type_param_ty elem; asdl_seq * seq; if ( (elem = type_param_rule(p)) // type_param && - (seq = _loop0_82_rule(p)) // _loop0_82 + (seq = _loop0_81_rule(p)) // _loop0_81 ) { - D(fprintf(stderr, "%*c+ _gather_81[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "type_param _loop0_82")); + D(fprintf(stderr, "%*c+ _gather_80[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "type_param _loop0_81")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_81[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "type_param _loop0_82")); + D(fprintf(stderr, "%*c%s _gather_80[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "type_param _loop0_81")); } _res = NULL; done: @@ -29954,9 +29887,9 @@ _gather_81_rule(Parser *p) return _res; } -// _loop1_83: (',' expression) +// _loop1_82: (',' expression) static asdl_seq * -_loop1_83_rule(Parser *p) +_loop1_82_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -29981,7 +29914,7 @@ _loop1_83_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); + D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); void *_tmp_251_var; while ( (_tmp_251_var = _tmp_251_rule(p)) // ',' expression @@ -30004,7 +29937,7 @@ _loop1_83_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_82[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' expression)")); } if (_n == 0 || p->error_indicator) { @@ -30026,9 +29959,9 @@ _loop1_83_rule(Parser *p) return _seq; } -// _loop1_84: (',' star_expression) +// _loop1_83: (',' star_expression) static asdl_seq * -_loop1_84_rule(Parser *p) +_loop1_83_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30053,7 +29986,7 @@ _loop1_84_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); + D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); void *_tmp_252_var; while ( (_tmp_252_var = _tmp_252_rule(p)) // ',' star_expression @@ -30076,7 +30009,7 @@ _loop1_84_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_84[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)")); } if (_n == 0 || p->error_indicator) { @@ -30098,9 +30031,9 @@ _loop1_84_rule(Parser *p) return _seq; } -// _loop0_86: ',' star_named_expression +// _loop0_85: ',' star_named_expression static asdl_seq * -_loop0_86_rule(Parser *p) +_loop0_85_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30125,7 +30058,7 @@ _loop0_86_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); + D(fprintf(stderr, "%*c> _loop0_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); Token * _literal; expr_ty elem; while ( @@ -30157,7 +30090,7 @@ _loop0_86_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_85[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30174,9 +30107,9 @@ _loop0_86_rule(Parser *p) return _seq; } -// _gather_85: star_named_expression _loop0_86 +// _gather_84: star_named_expression _loop0_85 static asdl_seq * -_gather_85_rule(Parser *p) +_gather_84_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30187,27 +30120,27 @@ _gather_85_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_named_expression _loop0_86 + { // star_named_expression _loop0_85 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); + D(fprintf(stderr, "%*c> _gather_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_85")); expr_ty elem; asdl_seq * seq; if ( (elem = star_named_expression_rule(p)) // star_named_expression && - (seq = _loop0_86_rule(p)) // _loop0_86 + (seq = _loop0_85_rule(p)) // _loop0_85 ) { - D(fprintf(stderr, "%*c+ _gather_85[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); + D(fprintf(stderr, "%*c+ _gather_84[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_85")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_85[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_86")); + D(fprintf(stderr, "%*c%s _gather_84[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_85")); } _res = NULL; done: @@ -30215,9 +30148,9 @@ _gather_85_rule(Parser *p) return _res; } -// _loop1_87: ('or' conjunction) +// _loop1_86: ('or' conjunction) static asdl_seq * -_loop1_87_rule(Parser *p) +_loop1_86_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30242,7 +30175,7 @@ _loop1_87_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); + D(fprintf(stderr, "%*c> _loop1_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); void *_tmp_253_var; while ( (_tmp_253_var = _tmp_253_rule(p)) // 'or' conjunction @@ -30265,7 +30198,7 @@ _loop1_87_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_86[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)")); } if (_n == 0 || p->error_indicator) { @@ -30287,9 +30220,9 @@ _loop1_87_rule(Parser *p) return _seq; } -// _loop1_88: ('and' inversion) +// _loop1_87: ('and' inversion) static asdl_seq * -_loop1_88_rule(Parser *p) +_loop1_87_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30314,7 +30247,7 @@ _loop1_88_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); + D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); void *_tmp_254_var; while ( (_tmp_254_var = _tmp_254_rule(p)) // 'and' inversion @@ -30337,7 +30270,7 @@ _loop1_88_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_88[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('and' inversion)")); } if (_n == 0 || p->error_indicator) { @@ -30359,9 +30292,9 @@ _loop1_88_rule(Parser *p) return _seq; } -// _loop1_89: compare_op_bitwise_or_pair +// _loop1_88: compare_op_bitwise_or_pair static asdl_seq * -_loop1_89_rule(Parser *p) +_loop1_88_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30386,7 +30319,7 @@ _loop1_89_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); + D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); CmpopExprPair* compare_op_bitwise_or_pair_var; while ( (compare_op_bitwise_or_pair_var = compare_op_bitwise_or_pair_rule(p)) // compare_op_bitwise_or_pair @@ -30409,7 +30342,7 @@ _loop1_89_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_89[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_88[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compare_op_bitwise_or_pair")); } if (_n == 0 || p->error_indicator) { @@ -30431,9 +30364,9 @@ _loop1_89_rule(Parser *p) return _seq; } -// _tmp_90: '!=' +// _tmp_89: '!=' static void * -_tmp_90_rule(Parser *p) +_tmp_89_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30449,13 +30382,13 @@ _tmp_90_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c> _tmp_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); Token * tok; if ( (tok = _PyPegen_expect_token(p, 28)) // token='!=' ) { - D(fprintf(stderr, "%*c+ _tmp_90[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c+ _tmp_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); _res = _PyPegen_check_barry_as_flufl ( p , tok ) ? NULL : tok; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -30465,7 +30398,7 @@ _tmp_90_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_90[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_89[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!='")); } _res = NULL; @@ -30474,9 +30407,9 @@ _tmp_90_rule(Parser *p) return _res; } -// _loop0_92: ',' (slice | starred_expression) +// _loop0_91: ',' (slice | starred_expression) static asdl_seq * -_loop0_92_rule(Parser *p) +_loop0_91_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30501,7 +30434,7 @@ _loop0_92_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); + D(fprintf(stderr, "%*c> _loop0_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); Token * _literal; void *elem; while ( @@ -30533,7 +30466,7 @@ _loop0_92_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_92[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_91[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (slice | starred_expression)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -30550,9 +30483,9 @@ _loop0_92_rule(Parser *p) return _seq; } -// _gather_91: (slice | starred_expression) _loop0_92 +// _gather_90: (slice | starred_expression) _loop0_91 static asdl_seq * -_gather_91_rule(Parser *p) +_gather_90_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30563,27 +30496,27 @@ _gather_91_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (slice | starred_expression) _loop0_92 + { // (slice | starred_expression) _loop0_91 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_92")); + D(fprintf(stderr, "%*c> _gather_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_91")); void *elem; asdl_seq * seq; if ( (elem = _tmp_255_rule(p)) // slice | starred_expression && - (seq = _loop0_92_rule(p)) // _loop0_92 + (seq = _loop0_91_rule(p)) // _loop0_91 ) { - D(fprintf(stderr, "%*c+ _gather_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_92")); + D(fprintf(stderr, "%*c+ _gather_90[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_91")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_91[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_92")); + D(fprintf(stderr, "%*c%s _gather_90[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_91")); } _res = NULL; done: @@ -30591,9 +30524,9 @@ _gather_91_rule(Parser *p) return _res; } -// _tmp_93: ':' expression? +// _tmp_92: ':' expression? static void * -_tmp_93_rule(Parser *p) +_tmp_92_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30609,7 +30542,7 @@ _tmp_93_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); Token * _literal; void *d; if ( @@ -30618,7 +30551,7 @@ _tmp_93_rule(Parser *p) (d = expression_rule(p), !p->error_indicator) // expression? ) { - D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -30628,7 +30561,7 @@ _tmp_93_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' expression?")); } _res = NULL; @@ -30637,9 +30570,9 @@ _tmp_93_rule(Parser *p) return _res; } -// _tmp_94: STRING | FSTRING_START +// _tmp_93: STRING | FSTRING_START static void * -_tmp_94_rule(Parser *p) +_tmp_93_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30655,18 +30588,18 @@ _tmp_94_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); + D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); expr_ty string_var; if ( (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING")); + D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING")); } { // FSTRING_START @@ -30674,18 +30607,18 @@ _tmp_94_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); + D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); Token * fstring_start_var; if ( (fstring_start_var = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' ) { - D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); + D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); _res = fstring_start_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START")); } _res = NULL; @@ -30694,9 +30627,9 @@ _tmp_94_rule(Parser *p) return _res; } -// _tmp_95: tuple | group | genexp +// _tmp_94: tuple | group | genexp static void * -_tmp_95_rule(Parser *p) +_tmp_94_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30712,18 +30645,18 @@ _tmp_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // group @@ -30731,18 +30664,18 @@ _tmp_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); expr_ty group_var; if ( (group_var = group_rule(p)) // group ) { - D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); _res = group_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "group")); } { // genexp @@ -30750,18 +30683,18 @@ _tmp_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } _res = NULL; @@ -30770,9 +30703,9 @@ _tmp_95_rule(Parser *p) return _res; } -// _tmp_96: list | listcomp +// _tmp_95: list | listcomp static void * -_tmp_96_rule(Parser *p) +_tmp_95_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30788,18 +30721,18 @@ _tmp_96_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // listcomp @@ -30807,18 +30740,18 @@ _tmp_96_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); expr_ty listcomp_var; if ( (listcomp_var = listcomp_rule(p)) // listcomp ) { - D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); _res = listcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "listcomp")); } _res = NULL; @@ -30827,9 +30760,9 @@ _tmp_96_rule(Parser *p) return _res; } -// _tmp_97: dict | set | dictcomp | setcomp +// _tmp_96: dict | set | dictcomp | setcomp static void * -_tmp_97_rule(Parser *p) +_tmp_96_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30845,18 +30778,18 @@ _tmp_97_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); expr_ty dict_var; if ( (dict_var = dict_rule(p)) // dict ) { - D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); _res = dict_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict")); } { // set @@ -30864,18 +30797,18 @@ _tmp_97_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); expr_ty set_var; if ( (set_var = set_rule(p)) // set ) { - D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); _res = set_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set")); } { // dictcomp @@ -30883,18 +30816,18 @@ _tmp_97_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); expr_ty dictcomp_var; if ( (dictcomp_var = dictcomp_rule(p)) // dictcomp ) { - D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); _res = dictcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp")); } { // setcomp @@ -30902,18 +30835,18 @@ _tmp_97_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); expr_ty setcomp_var; if ( (setcomp_var = setcomp_rule(p)) // setcomp ) { - D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); _res = setcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp")); } _res = NULL; @@ -30922,9 +30855,9 @@ _tmp_97_rule(Parser *p) return _res; } -// _tmp_98: yield_expr | named_expression +// _tmp_97: yield_expr | named_expression static void * -_tmp_98_rule(Parser *p) +_tmp_97_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -30940,18 +30873,18 @@ _tmp_98_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_98[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // named_expression @@ -30959,18 +30892,18 @@ _tmp_98_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); expr_ty named_expression_var; if ( (named_expression_var = named_expression_rule(p)) // named_expression ) { - D(fprintf(stderr, "%*c+ _tmp_98[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); _res = named_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression")); } _res = NULL; @@ -30979,9 +30912,9 @@ _tmp_98_rule(Parser *p) return _res; } -// _loop0_99: lambda_param_no_default +// _loop0_98: lambda_param_no_default static asdl_seq * -_loop0_99_rule(Parser *p) +_loop0_98_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31006,7 +30939,7 @@ _loop0_99_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -31029,7 +30962,7 @@ _loop0_99_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_99[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_98[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31046,9 +30979,9 @@ _loop0_99_rule(Parser *p) return _seq; } -// _loop0_100: lambda_param_with_default +// _loop0_99: lambda_param_with_default static asdl_seq * -_loop0_100_rule(Parser *p) +_loop0_99_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31073,7 +31006,7 @@ _loop0_100_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31096,7 +31029,7 @@ _loop0_100_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_100[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_99[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31113,9 +31046,9 @@ _loop0_100_rule(Parser *p) return _seq; } -// _loop0_101: lambda_param_with_default +// _loop0_100: lambda_param_with_default static asdl_seq * -_loop0_101_rule(Parser *p) +_loop0_100_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31140,7 +31073,7 @@ _loop0_101_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31163,7 +31096,7 @@ _loop0_101_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_101[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_100[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31180,9 +31113,9 @@ _loop0_101_rule(Parser *p) return _seq; } -// _loop1_102: lambda_param_no_default +// _loop1_101: lambda_param_no_default static asdl_seq * -_loop1_102_rule(Parser *p) +_loop1_101_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31207,7 +31140,7 @@ _loop1_102_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -31230,7 +31163,7 @@ _loop1_102_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_102[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_101[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -31252,9 +31185,9 @@ _loop1_102_rule(Parser *p) return _seq; } -// _loop0_103: lambda_param_with_default +// _loop0_102: lambda_param_with_default static asdl_seq * -_loop0_103_rule(Parser *p) +_loop0_102_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31279,7 +31212,7 @@ _loop0_103_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31302,7 +31235,7 @@ _loop0_103_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_103[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_102[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31319,9 +31252,9 @@ _loop0_103_rule(Parser *p) return _seq; } -// _loop1_104: lambda_param_with_default +// _loop1_103: lambda_param_with_default static asdl_seq * -_loop1_104_rule(Parser *p) +_loop1_103_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31346,7 +31279,7 @@ _loop1_104_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31369,7 +31302,7 @@ _loop1_104_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_104[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_103[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -31391,9 +31324,9 @@ _loop1_104_rule(Parser *p) return _seq; } -// _loop1_105: lambda_param_no_default +// _loop1_104: lambda_param_no_default static asdl_seq * -_loop1_105_rule(Parser *p) +_loop1_104_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31418,7 +31351,7 @@ _loop1_105_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -31441,7 +31374,7 @@ _loop1_105_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_105[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_104[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -31463,9 +31396,9 @@ _loop1_105_rule(Parser *p) return _seq; } -// _loop1_106: lambda_param_no_default +// _loop1_105: lambda_param_no_default static asdl_seq * -_loop1_106_rule(Parser *p) +_loop1_105_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31490,7 +31423,7 @@ _loop1_106_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -31513,7 +31446,7 @@ _loop1_106_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_106[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_105[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -31535,9 +31468,9 @@ _loop1_106_rule(Parser *p) return _seq; } -// _loop0_107: lambda_param_no_default +// _loop0_106: lambda_param_no_default static asdl_seq * -_loop0_107_rule(Parser *p) +_loop0_106_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31562,7 +31495,7 @@ _loop0_107_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -31585,7 +31518,7 @@ _loop0_107_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_107[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_106[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31602,9 +31535,9 @@ _loop0_107_rule(Parser *p) return _seq; } -// _loop1_108: lambda_param_with_default +// _loop1_107: lambda_param_with_default static asdl_seq * -_loop1_108_rule(Parser *p) +_loop1_107_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31629,7 +31562,7 @@ _loop1_108_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31652,7 +31585,7 @@ _loop1_108_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_108[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_107[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -31674,9 +31607,9 @@ _loop1_108_rule(Parser *p) return _seq; } -// _loop0_109: lambda_param_no_default +// _loop0_108: lambda_param_no_default static asdl_seq * -_loop0_109_rule(Parser *p) +_loop0_108_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31701,7 +31634,7 @@ _loop0_109_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -31724,7 +31657,7 @@ _loop0_109_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_109[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_108[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31741,9 +31674,9 @@ _loop0_109_rule(Parser *p) return _seq; } -// _loop1_110: lambda_param_with_default +// _loop1_109: lambda_param_with_default static asdl_seq * -_loop1_110_rule(Parser *p) +_loop1_109_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31768,7 +31701,7 @@ _loop1_110_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31791,7 +31724,7 @@ _loop1_110_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_109[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -31813,9 +31746,9 @@ _loop1_110_rule(Parser *p) return _seq; } -// _loop0_111: lambda_param_maybe_default +// _loop0_110: lambda_param_maybe_default static asdl_seq * -_loop0_111_rule(Parser *p) +_loop0_110_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31840,7 +31773,7 @@ _loop0_111_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -31863,7 +31796,7 @@ _loop0_111_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_111[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_110[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31880,9 +31813,9 @@ _loop0_111_rule(Parser *p) return _seq; } -// _loop1_112: lambda_param_maybe_default +// _loop1_111: lambda_param_maybe_default static asdl_seq * -_loop1_112_rule(Parser *p) +_loop1_111_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31907,7 +31840,7 @@ _loop1_112_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -31930,7 +31863,7 @@ _loop1_112_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_112[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_111[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -31952,9 +31885,9 @@ _loop1_112_rule(Parser *p) return _seq; } -// _tmp_113: yield_expr | star_expressions +// _tmp_112: yield_expr | star_expressions static void * -_tmp_113_rule(Parser *p) +_tmp_112_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -31970,18 +31903,18 @@ _tmp_113_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -31989,18 +31922,18 @@ _tmp_113_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -32009,9 +31942,9 @@ _tmp_113_rule(Parser *p) return _res; } -// _loop0_114: fstring_format_spec +// _loop0_113: fstring_format_spec static asdl_seq * -_loop0_114_rule(Parser *p) +_loop0_113_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -32036,7 +31969,7 @@ _loop0_114_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -32059,7 +31992,7 @@ _loop0_114_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32076,6 +32009,73 @@ _loop0_114_rule(Parser *p) return _seq; } +// _loop0_114: fstring_middle +static asdl_seq * +_loop0_114_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // fstring_middle + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); + expr_ty fstring_middle_var; + while ( + (fstring_middle_var = fstring_middle_rule(p)) // fstring_middle + ) + { + _res = fstring_middle_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_114[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_middle")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + // _loop1_115: (fstring | string) static asdl_seq * _loop1_115_rule(Parser *p) @@ -41373,8 +41373,6 @@ _PyPegen_parse(Parser *p) result = eval_rule(p); } else if (p->start_rule == Py_func_type_input) { result = func_type_rule(p); - } else if (p->start_rule == Py_fstring_input) { - result = fstring_rule(p); } return result; diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index b2fca019f6819c..cbeb9da04d92d8 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -309,21 +309,6 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype, end_col_offset = p->tok->cur - p->tok->line_start; } - if (p->start_rule == Py_fstring_input) { - const char *fstring_msg = "f-string: "; - Py_ssize_t len = strlen(fstring_msg) + strlen(errmsg); - - char *new_errmsg = PyMem_Malloc(len + 1); // Lengths of both strings plus NULL character - if (!new_errmsg) { - return (void *) PyErr_NoMemory(); - } - - // Copy both strings into new buffer - memcpy(new_errmsg, fstring_msg, strlen(fstring_msg)); - memcpy(new_errmsg + strlen(fstring_msg), errmsg, strlen(errmsg)); - new_errmsg[len] = 0; - errmsg = new_errmsg; - } errstr = PyUnicode_FromFormatV(errmsg, va); if (!errstr) { goto error; @@ -362,11 +347,6 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype, } } - if (p->start_rule == Py_fstring_input) { - col_offset -= p->starting_col_offset; - end_col_offset -= p->starting_col_offset; - } - Py_ssize_t col_number = col_offset; Py_ssize_t end_col_number = end_col_offset; @@ -397,17 +377,11 @@ _PyPegen_raise_error_known_location(Parser *p, PyObject *errtype, Py_DECREF(errstr); Py_DECREF(value); - if (p->start_rule == Py_fstring_input) { - PyMem_Free((void *)errmsg); - } return NULL; error: Py_XDECREF(errstr); Py_XDECREF(error_line); - if (p->start_rule == Py_fstring_input) { - PyMem_Free((void *)errmsg); - } return NULL; } diff --git a/Tools/peg_generator/pegen/grammar.py b/Tools/peg_generator/pegen/grammar.py index 03d60d01026f85..a6c19bc7b84565 100644 --- a/Tools/peg_generator/pegen/grammar.py +++ b/Tools/peg_generator/pegen/grammar.py @@ -35,7 +35,13 @@ def generic_visit(self, node: Iterable[Any], *args: Any, **kwargs: Any) -> Any: class Grammar: def __init__(self, rules: Iterable[Rule], metas: Iterable[Tuple[str, Optional[str]]]): - self.rules = {rule.name: rule for rule in rules} + # Check if there are repeated rules in "rules" + all_rules = {} + for rule in rules: + if rule.name in all_rules: + raise GrammarError(f"Repeated rule {rule.name!r}") + all_rules[rule.name] = rule + self.rules = all_rules self.metas = dict(metas) def __str__(self) -> str: From 6a6bea3ee8bbe52e4307c4da1ed4a7b9c78cbe45 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:22:16 -0700 Subject: [PATCH 0873/1206] [3.12] gh-109706: Fix multiprocessing test_nested_startmethod() (GH-109707) (#109762) gh-109706: Fix multiprocessing test_nested_startmethod() (GH-109707) Don't check order, queue items can be written in any order. (cherry picked from commit b03a791497ff4b3c42805e06c73d08ac34087402) Co-authored-by: Victor Stinner --- Lib/test/_test_multiprocessing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 044bfc97b8c666..bf5d541af896ca 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -5434,7 +5434,9 @@ def test_nested_startmethod(self): while not queue.empty(): results.append(queue.get()) - self.assertEqual(results, [2, 1]) + # gh-109706: queue.put(1) can write into the queue before queue.put(2), + # there is no synchronization in the test. + self.assertSetEqual(set(results), set([2, 1])) @unittest.skipIf(sys.platform == "win32", From 5e6e99646e46d485e018429f6000661609e4f1b5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:22:40 -0700 Subject: [PATCH 0874/1206] [3.12] gh-109521: Fix obscure cases handling in PyImport_GetImporter() (GH-109522) (#109777) gh-109521: Fix obscure cases handling in PyImport_GetImporter() (GH-109522) PyImport_GetImporter() now sets RuntimeError if it fails to get sys.path_hooks or sys.path_importer_cache or they are not list and dict correspondingly. Previously it could return NULL without setting error in obscure cases, crash or raise SystemError if these attributes have wrong type. (cherry picked from commit 62c7015e89cbdedb5218d4fedd45f971885f67a8) Co-authored-by: Serhiy Storchaka --- ...-09-17-21-47-31.gh-issue-109521.JDF6i9.rst | 5 ++++ Python/import.c | 26 +++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-09-17-21-47-31.gh-issue-109521.JDF6i9.rst diff --git a/Misc/NEWS.d/next/C API/2023-09-17-21-47-31.gh-issue-109521.JDF6i9.rst b/Misc/NEWS.d/next/C API/2023-09-17-21-47-31.gh-issue-109521.JDF6i9.rst new file mode 100644 index 00000000000000..338650c9246686 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-09-17-21-47-31.gh-issue-109521.JDF6i9.rst @@ -0,0 +1,5 @@ +:c:func:`PyImport_GetImporter` now sets RuntimeError if it fails to get +:data:`sys.path_hooks` or :data:`sys.path_importer_cache` or they are not +list and dict correspondingly. Previously it could return NULL without +setting error in obscure cases, crash or raise SystemError if these +attributes have wrong type. diff --git a/Python/import.c b/Python/import.c index 3f3f2a2b681351..54232a130082f0 100644 --- a/Python/import.c +++ b/Python/import.c @@ -2380,9 +2380,14 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache, PyObject *importer; Py_ssize_t j, nhooks; - /* These conditions are the caller's responsibility: */ - assert(PyList_Check(path_hooks)); - assert(PyDict_Check(path_importer_cache)); + if (!PyList_Check(path_hooks)) { + PyErr_SetString(PyExc_RuntimeError, "sys.path_hooks is not a list"); + return NULL; + } + if (!PyDict_Check(path_importer_cache)) { + PyErr_SetString(PyExc_RuntimeError, "sys.path_importer_cache is not a dict"); + return NULL; + } nhooks = PyList_Size(path_hooks); if (nhooks < 0) @@ -2425,11 +2430,22 @@ PyImport_GetImporter(PyObject *path) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *path_importer_cache = PySys_GetObject("path_importer_cache"); + if (path_importer_cache == NULL) { + PyErr_SetString(PyExc_RuntimeError, "lost sys.path_importer_cache"); + return NULL; + } + Py_INCREF(path_importer_cache); PyObject *path_hooks = PySys_GetObject("path_hooks"); - if (path_importer_cache == NULL || path_hooks == NULL) { + if (path_hooks == NULL) { + PyErr_SetString(PyExc_RuntimeError, "lost sys.path_hooks"); + Py_DECREF(path_importer_cache); return NULL; } - return get_path_importer(tstate, path_importer_cache, path_hooks, path); + Py_INCREF(path_hooks); + PyObject *importer = get_path_importer(tstate, path_importer_cache, path_hooks, path); + Py_DECREF(path_hooks); + Py_DECREF(path_importer_cache); + return importer; } From c2cadb0ec2d192c78d9e01c3c0c1cae12ea57392 Mon Sep 17 00:00:00 2001 From: elfstrom Date: Mon, 2 Oct 2023 17:24:19 +0200 Subject: [PATCH 0875/1206] [3.12] gh-105829: Fix concurrent.futures.ProcessPoolExecutor deadlock (GH-108513) (#109784) This fixes issue GH-105829, https://github.com/python/cpython/issues/105829 (cherry picked from commit 405b06375a8a4cdb08ff53afade09a8b66ec23d5) --- Lib/concurrent/futures/process.py | 18 ++++- .../test_concurrent_futures/test_deadlock.py | 72 ++++++++++++++++++- ...-08-26-12-35-39.gh-issue-105829.kyYhWI.rst | 1 + 3 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-26-12-35-39.gh-issue-105829.kyYhWI.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index a8dab1302aabb1..33df65a3081fa7 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -71,6 +71,11 @@ def __init__(self): self._reader, self._writer = mp.Pipe(duplex=False) def close(self): + # Please note that we do not take the shutdown lock when + # calling clear() (to avoid deadlocking) so this method can + # only be called safely from the same thread as all calls to + # clear() even if you hold the shutdown lock. Otherwise we + # might try to read from the closed pipe. if not self._closed: self._closed = True self._writer.close() @@ -426,8 +431,12 @@ def wait_result_broken_or_wakeup(self): elif wakeup_reader in ready: is_broken = False - with self.shutdown_lock: - self.thread_wakeup.clear() + # No need to hold the _shutdown_lock here because: + # 1. we're the only thread to use the wakeup reader + # 2. we're also the only thread to call thread_wakeup.close() + # 3. we want to avoid a possible deadlock when both reader and writer + # would block (gh-105829) + self.thread_wakeup.clear() return result_item, is_broken, cause @@ -710,7 +719,10 @@ def __init__(self, max_workers=None, mp_context=None, # as it could result in a deadlock if a worker process dies with the # _result_queue write lock still acquired. # - # _shutdown_lock must be locked to access _ThreadWakeup. + # _shutdown_lock must be locked to access _ThreadWakeup.close() and + # .wakeup(). Care must also be taken to not call clear or close from + # more than one thread since _ThreadWakeup.clear() is not protected by + # the _shutdown_lock self._executor_manager_thread_wakeup = _ThreadWakeup() # Create communication channels for the executor diff --git a/Lib/test/test_concurrent_futures/test_deadlock.py b/Lib/test/test_concurrent_futures/test_deadlock.py index 6b78b360d15627..6be16777568030 100644 --- a/Lib/test/test_concurrent_futures/test_deadlock.py +++ b/Lib/test/test_concurrent_futures/test_deadlock.py @@ -1,10 +1,13 @@ import contextlib +import queue +import signal import sys import time import unittest +import unittest.mock from pickle import PicklingError from concurrent import futures -from concurrent.futures.process import BrokenProcessPool +from concurrent.futures.process import BrokenProcessPool, _ThreadWakeup from test import support @@ -239,6 +242,73 @@ def test_crash_big_data(self): with self.assertRaises(BrokenProcessPool): list(executor.map(_crash_with_data, [data] * 10)) + def test_gh105829_should_not_deadlock_if_wakeup_pipe_full(self): + # Issue #105829: The _ExecutorManagerThread wakeup pipe could + # fill up and block. See: https://github.com/python/cpython/issues/105829 + + # Lots of cargo culting while writing this test, apologies if + # something is really stupid... + + self.executor.shutdown(wait=True) + + if not hasattr(signal, 'alarm'): + raise unittest.SkipTest( + "Tested platform does not support the alarm signal") + + def timeout(_signum, _frame): + import faulthandler + faulthandler.dump_traceback() + + raise RuntimeError("timed out while submitting jobs?") + + thread_run = futures.process._ExecutorManagerThread.run + def mock_run(self): + # Delay thread startup so the wakeup pipe can fill up and block + time.sleep(3) + thread_run(self) + + class MockWakeup(_ThreadWakeup): + """Mock wakeup object to force the wakeup to block""" + def __init__(self): + super().__init__() + self._dummy_queue = queue.Queue(maxsize=1) + + def wakeup(self): + self._dummy_queue.put(None, block=True) + super().wakeup() + + def clear(self): + try: + while True: + self._dummy_queue.get_nowait() + except queue.Empty: + super().clear() + + with (unittest.mock.patch.object(futures.process._ExecutorManagerThread, + 'run', mock_run), + unittest.mock.patch('concurrent.futures.process._ThreadWakeup', + MockWakeup)): + with self.executor_type(max_workers=2, + mp_context=self.get_context()) as executor: + self.executor = executor # Allow clean up in fail_on_deadlock + + job_num = 100 + job_data = range(job_num) + + # Need to use sigalarm for timeout detection because + # Executor.submit is not guarded by any timeout (both + # self._work_ids.put(self._queue_count) and + # self._executor_manager_thread_wakeup.wakeup() might + # timeout, maybe more?). In this specific case it was + # the wakeup call that deadlocked on a blocking pipe. + old_handler = signal.signal(signal.SIGALRM, timeout) + try: + signal.alarm(int(self.TIMEOUT)) + self.assertEqual(job_num, len(list(executor.map(int, job_data)))) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, old_handler) + create_executor_tests(globals(), ExecutorDeadlockTest, executor_mixins=(ProcessPoolForkMixin, diff --git a/Misc/NEWS.d/next/Library/2023-08-26-12-35-39.gh-issue-105829.kyYhWI.rst b/Misc/NEWS.d/next/Library/2023-08-26-12-35-39.gh-issue-105829.kyYhWI.rst new file mode 100644 index 00000000000000..eaa2a5a4330e28 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-26-12-35-39.gh-issue-105829.kyYhWI.rst @@ -0,0 +1 @@ +Fix concurrent.futures.ProcessPoolExecutor deadlock From 150bd302bb78ad3ed0524447cfa25805b1e22763 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:24:51 -0700 Subject: [PATCH 0876/1206] [3.12] gh-109833: Fix asyncio test_wait_for() (GH-109834) (#109837) gh-109833: Fix asyncio test_wait_for() (GH-109834) Expect the test to be "short" but don't measure the exact performance of the CI. SHORT_TIMEOUT is about 30 seconds whereas the cancelled coroutine takes around 1 hour. (cherry picked from commit f29bc9c9a0a6794c6b8a9e84a7ba9237b427a10a) Co-authored-by: Victor Stinner --- Lib/test/test_asyncio/test_waitfor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_waitfor.py b/Lib/test/test_asyncio/test_waitfor.py index d5c02ba4a01df9..e714b154c5cadf 100644 --- a/Lib/test/test_asyncio/test_waitfor.py +++ b/Lib/test/test_asyncio/test_waitfor.py @@ -1,6 +1,7 @@ import asyncio import unittest import time +from test import support def tearDownModule(): @@ -130,7 +131,7 @@ async def foo(): nonlocal foo_running foo_running = True try: - await asyncio.sleep(10) + await asyncio.sleep(support.LONG_TIMEOUT) finally: foo_running = False return 'done' @@ -144,7 +145,7 @@ async def foo(): self.assertTrue(fut.done()) # it should have been cancelled due to the timeout self.assertTrue(fut.cancelled()) - self.assertLess(t1 - t0, 0.5) + self.assertLess(t1 - t0, support.SHORT_TIMEOUT) self.assertEqual(foo_running, False) async def test_wait_for_blocking(self): From 8c5fd2105c3d592883b682b5788355aed3f785d7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:35:03 -0700 Subject: [PATCH 0877/1206] [3.12] gh-109625: Move _ready_to_import() from test_import to support.import_helper (GH-109626) (#109640) gh-109625: Move _ready_to_import() from test_import to support.import_helper (GH-109626) (cherry picked from commit 115c49ad5a5ccfb628fef3ae06a566f7a0197f97) Co-authored-by: Nikita Sobolev --- Lib/test/support/import_helper.py | 25 +++++++++++++++++++- Lib/test/test_import/__init__.py | 38 ++++++++----------------------- Lib/test/test_inspect.py | 6 ++--- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/Lib/test/support/import_helper.py b/Lib/test/support/import_helper.py index 67f18e530edc4b..3d804f2b590108 100644 --- a/Lib/test/support/import_helper.py +++ b/Lib/test/support/import_helper.py @@ -8,7 +8,7 @@ import unittest import warnings -from .os_helper import unlink +from .os_helper import unlink, temp_dir @contextlib.contextmanager @@ -274,3 +274,26 @@ def mock_register_at_fork(func): # memory. from unittest import mock return mock.patch('os.register_at_fork', create=True)(func) + + +@contextlib.contextmanager +def ready_to_import(name=None, source=""): + from test.support import script_helper + + # 1. Sets up a temporary directory and removes it afterwards + # 2. Creates the module file + # 3. Temporarily clears the module from sys.modules (if any) + # 4. Reverts or removes the module when cleaning up + name = name or "spam" + with temp_dir() as tempdir: + path = script_helper.make_script(tempdir, name, source) + old_module = sys.modules.pop(name, None) + try: + sys.path.insert(0, tempdir) + yield name, path + sys.path.remove(tempdir) + finally: + if old_module is not None: + sys.modules[name] = old_module + else: + sys.modules.pop(name, None) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 62585b23a7398f..8994f146b0155f 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -30,9 +30,10 @@ STDLIB_DIR, swap_attr, swap_item, cpython_only, is_emscripten, is_wasi, run_in_subinterp, run_in_subinterp_with_config) from test.support.import_helper import ( - forget, make_legacy_pyc, unlink, unload, DirsOnSysPath, CleanImport) + forget, make_legacy_pyc, unlink, unload, ready_to_import, + DirsOnSysPath, CleanImport) from test.support.os_helper import ( - TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE, temp_dir) + TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE) from test.support import script_helper from test.support import threading_helper from test.test_importlib.util import uncache @@ -125,27 +126,6 @@ def wrapper(self): return deco -@contextlib.contextmanager -def _ready_to_import(name=None, source=""): - # sets up a temporary directory and removes it - # creates the module file - # temporarily clears the module from sys.modules (if any) - # reverts or removes the module when cleaning up - name = name or "spam" - with temp_dir() as tempdir: - path = script_helper.make_script(tempdir, name, source) - old_module = sys.modules.pop(name, None) - try: - sys.path.insert(0, tempdir) - yield name, path - sys.path.remove(tempdir) - finally: - if old_module is not None: - sys.modules[name] = old_module - elif name in sys.modules: - del sys.modules[name] - - if _testsinglephase is not None: def restore__testsinglephase(*, _orig=_testsinglephase): # We started with the module imported and want to restore @@ -401,7 +381,7 @@ def test_from_import_missing_attr_path_is_canonical(self): def test_from_import_star_invalid_type(self): import re - with _ready_to_import() as (name, path): + with ready_to_import() as (name, path): with open(path, 'w', encoding='utf-8') as f: f.write("__all__ = [b'invalid_type']") globals = {} @@ -410,7 +390,7 @@ def test_from_import_star_invalid_type(self): ): exec(f"from {name} import *", globals) self.assertNotIn(b"invalid_type", globals) - with _ready_to_import() as (name, path): + with ready_to_import() as (name, path): with open(path, 'w', encoding='utf-8') as f: f.write("globals()[b'invalid_type'] = object()") globals = {} @@ -818,7 +798,7 @@ class FilePermissionTests(unittest.TestCase): ) def test_creation_mode(self): mask = 0o022 - with temp_umask(mask), _ready_to_import() as (name, path): + with temp_umask(mask), ready_to_import() as (name, path): cached_path = importlib.util.cache_from_source(path) module = __import__(name) if not os.path.exists(cached_path): @@ -837,7 +817,7 @@ def test_creation_mode(self): def test_cached_mode_issue_2051(self): # permissions of .pyc should match those of .py, regardless of mask mode = 0o600 - with temp_umask(0o022), _ready_to_import() as (name, path): + with temp_umask(0o022), ready_to_import() as (name, path): cached_path = importlib.util.cache_from_source(path) os.chmod(path, mode) __import__(name) @@ -853,7 +833,7 @@ def test_cached_mode_issue_2051(self): @os_helper.skip_unless_working_chmod def test_cached_readonly(self): mode = 0o400 - with temp_umask(0o022), _ready_to_import() as (name, path): + with temp_umask(0o022), ready_to_import() as (name, path): cached_path = importlib.util.cache_from_source(path) os.chmod(path, mode) __import__(name) @@ -868,7 +848,7 @@ def test_cached_readonly(self): def test_pyc_always_writable(self): # Initially read-only .pyc files on Windows used to cause problems # with later updates, see issue #6074 for details - with _ready_to_import() as (name, path): + with ready_to_import() as (name, path): # Write a Python file, make it read-only and import it with open(path, 'w', encoding='utf-8') as f: f.write("x = 'original'\n") diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index f0ee83187c96bf..6f260c9a71782c 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -28,7 +28,7 @@ from test.support import cpython_only from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ -from test.support.import_helper import DirsOnSysPath +from test.support.import_helper import DirsOnSysPath, ready_to_import from test.support.os_helper import TESTFN from test.support.script_helper import assert_python_ok, assert_python_failure from test import inspect_fodder as mod @@ -38,8 +38,6 @@ from test import inspect_stringized_annotations from test import inspect_stringized_annotations_2 -from test.test_import import _ready_to_import - # Functions tested in this suite: # ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode, @@ -4739,7 +4737,7 @@ def assertInspectEqual(self, path, source): def test_getsource_reload(self): # see issue 1218234 - with _ready_to_import('reload_bug', self.src_before) as (name, path): + with ready_to_import('reload_bug', self.src_before) as (name, path): module = importlib.import_module(name) self.assertInspectEqual(path, module) with open(path, 'w', encoding='utf-8') as src: From e25bc38ebb5927e2e7a3b0a201f4d1af8b4e546a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:35:36 -0700 Subject: [PATCH 0878/1206] [3.12] gh-109702: Increase concurrent_futures deadlock timeout (GH-109703) (#109705) gh-109702: Increase concurrent_futures deadlock timeout (GH-109703) Replace SHORT_TIMEOUT with LONG_TIMEOUT in test_deadlock of test_concurrent_futures. (cherry picked from commit 1eb1b45183c3b8aeefe3d5d27694155741e82bbc) Co-authored-by: Victor Stinner --- Lib/test/test_concurrent_futures/test_deadlock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_concurrent_futures/test_deadlock.py b/Lib/test/test_concurrent_futures/test_deadlock.py index 6be16777568030..2f08bf84698885 100644 --- a/Lib/test/test_concurrent_futures/test_deadlock.py +++ b/Lib/test/test_concurrent_futures/test_deadlock.py @@ -91,7 +91,7 @@ def __reduce__(self): class ExecutorDeadlockTest: - TIMEOUT = support.SHORT_TIMEOUT + TIMEOUT = support.LONG_TIMEOUT def _fail_on_deadlock(self, executor): # If we did not recover before TIMEOUT seconds, consider that the From d09a3145b596810078d0b24e1a9cbebc117f804d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:36:04 -0700 Subject: [PATCH 0879/1206] [3.12] gh-89363: Skip threading test_is_alive_after_fork() if ASAN (GH-109835) (#109855) gh-89363: Skip threading test_is_alive_after_fork() if ASAN (GH-109835) Skip test_is_alive_after_fork() of test_threading if Python is built with Address Sanitizer (ASAN). (cherry picked from commit bc06743533b5fea2d5ecdad6dd3caa372c67439f) Co-authored-by: Victor Stinner --- Lib/test/_test_multiprocessing.py | 2 +- Lib/test/test_threading.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index bf5d541af896ca..ca8fcab09af6da 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -79,7 +79,7 @@ if support.check_sanitizer(address=True): - # bpo-45200: Skip multiprocessing tests if Python is built with ASAN to + # gh-89363: Skip multiprocessing tests if Python is built with ASAN to # work around a libasan race condition: dead lock in pthread_create(). raise unittest.SkipTest("libasan has a pthread_create() dead lock") diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 9e4972ecb640df..1b8019f0931f4f 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -564,6 +564,10 @@ def background_thread(evt): self.assertEqual(err, b'') @support.requires_fork() + # gh-89363: Skip multiprocessing tests if Python is built with ASAN to + # work around a libasan race condition: dead lock in pthread_create(). + @support.skip_if_sanitizer("libasan has a pthread_create() dead lock", + address=True) def test_is_alive_after_fork(self): # Try hard to trigger #18418: is_alive() could sometimes be True on # threads that vanished after a fork. From 65c845e065d6ff7abc1abdc9c24bc7612a665161 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:36:29 -0700 Subject: [PATCH 0880/1206] [3.12] gh-109631: Allow interruption of short repeated regex matches (GH-109867) (#109886) gh-109631: Allow interruption of short repeated regex matches (GH-109867) Counting for signal checking now continues in new match from the point where it ended in the previous match instead of starting from 0. (cherry picked from commit 8ac2085b80eca4d9b2a1093d0a7da020fd12e11a) Co-authored-by: Serhiy Storchaka --- .../Library/2023-09-25-23-00-37.gh-issue-109631.eWSqpO.rst | 3 +++ Modules/_sre/sre.h | 1 + Modules/_sre/sre_lib.h | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-25-23-00-37.gh-issue-109631.eWSqpO.rst diff --git a/Misc/NEWS.d/next/Library/2023-09-25-23-00-37.gh-issue-109631.eWSqpO.rst b/Misc/NEWS.d/next/Library/2023-09-25-23-00-37.gh-issue-109631.eWSqpO.rst new file mode 100644 index 00000000000000..58af2e57068267 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-25-23-00-37.gh-issue-109631.eWSqpO.rst @@ -0,0 +1,3 @@ +:mod:`re` functions such as :func:`re.findall`, :func:`re.split`, +:func:`re.search` and :func:`re.sub` which perform short repeated matches +can now be interrupted by user. diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h index d967d9ea04ba7a..a0f235606e290e 100644 --- a/Modules/_sre/sre.h +++ b/Modules/_sre/sre.h @@ -94,6 +94,7 @@ typedef struct { size_t data_stack_base; /* current repeat context */ SRE_REPEAT *repeat; + unsigned int sigcount; } SRE_STATE; typedef struct { diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h index e83149825e2cdb..f8d556b2db85c0 100644 --- a/Modules/_sre/sre_lib.h +++ b/Modules/_sre/sre_lib.h @@ -563,7 +563,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) Py_ssize_t alloc_pos, ctx_pos = -1; Py_ssize_t ret = 0; int jump; - unsigned int sigcount=0; + unsigned int sigcount = state->sigcount; SRE(match_context)* ctx; SRE(match_context)* nextctx; @@ -1565,8 +1565,10 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) ctx_pos = ctx->last_ctx_pos; jump = ctx->jump; DATA_POP_DISCARD(ctx); - if (ctx_pos == -1) + if (ctx_pos == -1) { + state->sigcount = sigcount; return ret; + } DATA_LOOKUP_AT(SRE(match_context), ctx, ctx_pos); switch (jump) { From 84f9da9ab52e476224baac8786ab104e80ff77ba Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:37:25 -0700 Subject: [PATCH 0881/1206] [3.12] gh-109832: concurrent.futures test_deadlock restores sys.stderr (GH-109887) (#109892) gh-109832: concurrent.futures test_deadlock restores sys.stderr (GH-109887) test_error_at_task_unpickle() and test_error_during_result_unpickle_in_result_handler() now restore sys.stderr which is overriden by _raise_error_ignore_stderr(). (cherry picked from commit 2897142d2ec0930a8991af964c798b68fb6dcadd) Co-authored-by: Victor Stinner --- Lib/test/test_concurrent_futures/test_deadlock.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/test_concurrent_futures/test_deadlock.py b/Lib/test/test_concurrent_futures/test_deadlock.py index 2f08bf84698885..7ede95d5ed3422 100644 --- a/Lib/test/test_concurrent_futures/test_deadlock.py +++ b/Lib/test/test_concurrent_futures/test_deadlock.py @@ -145,6 +145,9 @@ def test_exit_at_task_unpickle(self): self._check_crash(BrokenProcessPool, id, ExitAtUnpickle()) def test_error_at_task_unpickle(self): + # gh-109832: Restore stderr overriden by _raise_error_ignore_stderr() + self.addCleanup(setattr, sys, 'stderr', sys.stderr) + # Check problem occurring while unpickling a task on workers self._check_crash(BrokenProcessPool, id, ErrorAtUnpickle()) @@ -180,6 +183,9 @@ def test_error_during_result_pickle_on_worker(self): self._check_crash(PicklingError, _return_instance, ErrorAtPickle) def test_error_during_result_unpickle_in_result_handler(self): + # gh-109832: Restore stderr overriden by _raise_error_ignore_stderr() + self.addCleanup(setattr, sys, 'stderr', sys.stderr) + # Check problem occurring while unpickling a task in # the result_handler thread self._check_crash(BrokenProcessPool, From b723b8a13d6b74b0fa1bf89149f314e26a93be9d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:37:40 -0700 Subject: [PATCH 0882/1206] [3.12] gh-109593: Fix reentrancy issue in multiprocessing resource_tracker (GH-109629) (#109898) gh-109593: Fix reentrancy issue in multiprocessing resource_tracker (GH-109629) --------- (cherry picked from commit 0eb98837b60bc58e57ad3e2b35c6b0e9ab634678) Co-authored-by: Antoine Pitrou Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- Lib/multiprocessing/resource_tracker.py | 34 ++++++++++++++++-- Lib/test/lock_tests.py | 36 +++++++++++++++++++ Lib/test/test_importlib/test_locks.py | 2 ++ Lib/test/test_threading.py | 3 ++ Lib/threading.py | 7 ++++ ...-09-22-20-16-44.gh-issue-109593.LboaNM.rst | 1 + Modules/_threadmodule.c | 14 ++++++++ 7 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-22-20-16-44.gh-issue-109593.LboaNM.rst diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py index ea369507297f86..79e96ecf3245f4 100644 --- a/Lib/multiprocessing/resource_tracker.py +++ b/Lib/multiprocessing/resource_tracker.py @@ -51,15 +51,31 @@ }) +class ReentrantCallError(RuntimeError): + pass + + class ResourceTracker(object): def __init__(self): - self._lock = threading.Lock() + self._lock = threading.RLock() self._fd = None self._pid = None + def _reentrant_call_error(self): + # gh-109629: this happens if an explicit call to the ResourceTracker + # gets interrupted by a garbage collection, invoking a finalizer (*) + # that itself calls back into ResourceTracker. + # (*) for example the SemLock finalizer + raise ReentrantCallError( + "Reentrant call into the multiprocessing resource tracker") + def _stop(self): with self._lock: + # This should not happen (_stop() isn't called by a finalizer) + # but we check for it anyway. + if self._lock._recursion_count() > 1: + return self._reentrant_call_error() if self._fd is None: # not running return @@ -81,6 +97,9 @@ def ensure_running(self): This can be run from any process. Usually a child process will use the resource created by its parent.''' with self._lock: + if self._lock._recursion_count() > 1: + # The code below is certainly not reentrant-safe, so bail out + return self._reentrant_call_error() if self._fd is not None: # resource tracker was launched before, is it still running? if self._check_alive(): @@ -159,7 +178,17 @@ def unregister(self, name, rtype): self._send('UNREGISTER', name, rtype) def _send(self, cmd, name, rtype): - self.ensure_running() + try: + self.ensure_running() + except ReentrantCallError: + # The code below might or might not work, depending on whether + # the resource tracker was already running and still alive. + # Better warn the user. + # (XXX is warnings.warn itself reentrant-safe? :-) + warnings.warn( + f"ResourceTracker called reentrantly for resource cleanup, " + f"which is unsupported. " + f"The {rtype} object {name!r} might leak.") msg = '{0}:{1}:{2}\n'.format(cmd, name, rtype).encode('ascii') if len(msg) > 512: # posix guarantees that writes to a pipe of less than PIPE_BUF @@ -176,6 +205,7 @@ def _send(self, cmd, name, rtype): unregister = _resource_tracker.unregister getfd = _resource_tracker.getfd + def main(fd): '''Run resource tracker.''' # protect the process from ^C and "killall python" etc diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py index a4f52cb20ad301..238e607d20a2b2 100644 --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -330,6 +330,42 @@ def test_release_save_unacquired(self): lock.release() self.assertRaises(RuntimeError, lock._release_save) + def test_recursion_count(self): + lock = self.locktype() + self.assertEqual(0, lock._recursion_count()) + lock.acquire() + self.assertEqual(1, lock._recursion_count()) + lock.acquire() + lock.acquire() + self.assertEqual(3, lock._recursion_count()) + lock.release() + self.assertEqual(2, lock._recursion_count()) + lock.release() + lock.release() + self.assertEqual(0, lock._recursion_count()) + + phase = [] + + def f(): + lock.acquire() + phase.append(None) + while len(phase) == 1: + _wait() + lock.release() + phase.append(None) + + with threading_helper.wait_threads_exit(): + start_new_thread(f, ()) + while len(phase) == 0: + _wait() + self.assertEqual(len(phase), 1) + self.assertEqual(0, lock._recursion_count()) + phase.append(None) + while len(phase) == 2: + _wait() + self.assertEqual(len(phase), 3) + self.assertEqual(0, lock._recursion_count()) + def test_different_thread(self): # Cannot release from a different thread lock = self.locktype() diff --git a/Lib/test/test_importlib/test_locks.py b/Lib/test/test_importlib/test_locks.py index ba9cf51c261d52..7091c36aaaf761 100644 --- a/Lib/test/test_importlib/test_locks.py +++ b/Lib/test/test_importlib/test_locks.py @@ -29,6 +29,8 @@ class ModuleLockAsRLockTests: test_timeout = None # _release_save() unsupported test_release_save_unacquired = None + # _recursion_count() unsupported + test_recursion_count = None # lock status in repr unsupported test_repr = None test_locked_repr = None diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 1b8019f0931f4f..f3532fb2010c63 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1751,6 +1751,9 @@ class ConditionAsRLockTests(lock_tests.RLockTests): # Condition uses an RLock by default and exports its API. locktype = staticmethod(threading.Condition) + def test_recursion_count(self): + self.skipTest("Condition does not expose _recursion_count()") + class ConditionTests(lock_tests.ConditionTests): condtype = staticmethod(threading.Condition) diff --git a/Lib/threading.py b/Lib/threading.py index df273870fa4273..a746dee5708124 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -238,6 +238,13 @@ def _release_save(self): def _is_owned(self): return self._owner == get_ident() + # Internal method used for reentrancy checks + + def _recursion_count(self): + if self._owner != get_ident(): + return 0 + return self._count + _PyRLock = _RLock diff --git a/Misc/NEWS.d/next/Library/2023-09-22-20-16-44.gh-issue-109593.LboaNM.rst b/Misc/NEWS.d/next/Library/2023-09-22-20-16-44.gh-issue-109593.LboaNM.rst new file mode 100644 index 00000000000000..292aea0be24dfb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-22-20-16-44.gh-issue-109593.LboaNM.rst @@ -0,0 +1 @@ +Avoid deadlocking on a reentrant call to the multiprocessing resource tracker. Such a reentrant call, though unlikely, can happen if a GC pass invokes the finalizer for a multiprocessing object such as SemLock. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 4514dfd3fc85eb..18fd65ac9f420f 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -486,6 +486,18 @@ PyDoc_STRVAR(rlock_release_save_doc, \n\ For internal use by `threading.Condition`."); +static PyObject * +rlock_recursion_count(rlockobject *self, PyObject *Py_UNUSED(ignored)) +{ + unsigned long tid = PyThread_get_thread_ident(); + return PyLong_FromUnsignedLong( + self->rlock_owner == tid ? self->rlock_count : 0UL); +} + +PyDoc_STRVAR(rlock_recursion_count_doc, +"_recursion_count() -> int\n\ +\n\ +For internal use by reentrancy checks."); static PyObject * rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored)) @@ -561,6 +573,8 @@ static PyMethodDef rlock_methods[] = { METH_VARARGS, rlock_acquire_restore_doc}, {"_release_save", (PyCFunction)rlock_release_save, METH_NOARGS, rlock_release_save_doc}, + {"_recursion_count", (PyCFunction)rlock_recursion_count, + METH_NOARGS, rlock_recursion_count_doc}, {"__enter__", _PyCFunction_CAST(rlock_acquire), METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, {"__exit__", (PyCFunction)rlock_release, From b0e377f694c2b86a0155784386a9f1ccf57af97e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:37:56 -0700 Subject: [PATCH 0883/1206] [3.12] More informative docstrings in the random module (gh-109745) (#109905) More informative docstrings in the random module (gh-109745) (cherry picked from commit 19bf3986958fc8269a1eb6d741bb60c91d6b5e58) Co-authored-by: Raymond Hettinger --- Lib/random.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Lib/random.py b/Lib/random.py index 84bbfc5df1bf23..1d789b107904fb 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -492,7 +492,14 @@ def choices(self, population, weights=None, *, cum_weights=None, k=1): ## -------------------- real-valued distributions ------------------- def uniform(self, a, b): - "Get a random number in the range [a, b) or [a, b] depending on rounding." + """Get a random number in the range [a, b) or [a, b] depending on rounding. + + The mean (expected value) and variance of the random variable are: + + E[X] = (a + b) / 2 + Var[X] = (b - a) ** 2 / 12 + + """ return a + (b - a) * self.random() def triangular(self, low=0.0, high=1.0, mode=None): @@ -503,6 +510,11 @@ def triangular(self, low=0.0, high=1.0, mode=None): http://en.wikipedia.org/wiki/Triangular_distribution + The mean (expected value) and variance of the random variable are: + + E[X] = (low + high + mode) / 3 + Var[X] = (low**2 + high**2 + mode**2 - low*high - low*mode - high*mode) / 18 + """ u = self.random() try: @@ -593,12 +605,15 @@ def expovariate(self, lambd=1.0): positive infinity if lambd is positive, and from negative infinity to 0 if lambd is negative. - """ - # lambd: rate lambd = 1/mean - # ('lambda' is a Python reserved word) + The mean (expected value) and variance of the random variable are: + + E[X] = 1 / lambd + Var[X] = 1 / lambd ** 2 + """ # we use 1-random() instead of random() to preclude the # possibility of taking the log of zero. + return -_log(1.0 - self.random()) / lambd def vonmisesvariate(self, mu, kappa): @@ -654,8 +669,12 @@ def gammavariate(self, alpha, beta): pdf(x) = -------------------------------------- math.gamma(alpha) * beta ** alpha + The mean (expected value) and variance of the random variable are: + + E[X] = alpha * beta + Var[X] = alpha * beta ** 2 + """ - # alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2 # Warning: a few older sources define the gamma distribution in terms # of alpha > -1.0 @@ -714,6 +733,11 @@ def betavariate(self, alpha, beta): Conditions on the parameters are alpha > 0 and beta > 0. Returned values range between 0 and 1. + The mean (expected value) and variance of the random variable are: + + E[X] = alpha / (alpha + beta) + Var[X] = alpha * beta / ((alpha + beta)**2 * (alpha + beta + 1)) + """ ## See ## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html @@ -766,6 +790,11 @@ def binomialvariate(self, n=1, p=0.5): Returns an integer in the range: 0 <= X <= n + The mean (expected value) and variance of the random variable are: + + E[X] = n * p + Var[x] = n * p * (1 - p) + """ # Error check inputs and handle edge cases if n < 0: From 1f622004c533aaf6eace434e73ac353d90fce9b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:38:07 -0700 Subject: [PATCH 0884/1206] [3.12] gh-109845: Make test_ftplib more stable under load (GH-109912) (#109919) gh-109845: Make test_ftplib more stable under load (GH-109912) recv() can return partial data cut in the middle of a multibyte character. Test raw binary data instead of data incorrectly decoded by parts. (cherry picked from commit 2ef2fffe3be953b91852585c75188d5475b09474) Co-authored-by: Serhiy Storchaka --- Lib/test/test_ftplib.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py index 544228e3bab47b..1ca94393d8569f 100644 --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -32,7 +32,7 @@ DEFAULT_ENCODING = 'utf-8' # the dummy data returned by server over the data channel when # RETR, LIST, NLST, MLSD commands are issued -RETR_DATA = 'abcde12345\r\n' * 1000 + 'non-ascii char \xAE\r\n' +RETR_DATA = 'abcde\xB9\xB2\xB3\xA4\xA6\r\n' * 1000 LIST_DATA = 'foo\r\nbar\r\n non-ascii char \xAE\r\n' NLST_DATA = 'foo\r\nbar\r\n non-ascii char \xAE\r\n' MLSD_DATA = ("type=cdir;perm=el;unique==keVO1+ZF4; test\r\n" @@ -67,11 +67,11 @@ class DummyDTPHandler(asynchat.async_chat): def __init__(self, conn, baseclass): asynchat.async_chat.__init__(self, conn) self.baseclass = baseclass - self.baseclass.last_received_data = '' + self.baseclass.last_received_data = bytearray() self.encoding = baseclass.encoding def handle_read(self): - new_data = self.recv(1024).decode(self.encoding, 'replace') + new_data = self.recv(1024) self.baseclass.last_received_data += new_data def handle_close(self): @@ -107,7 +107,7 @@ def __init__(self, conn, encoding=DEFAULT_ENCODING): self.in_buffer = [] self.dtp = None self.last_received_cmd = None - self.last_received_data = '' + self.last_received_data = bytearray() self.next_response = '' self.next_data = None self.rest = None @@ -590,19 +590,17 @@ def test_abort(self): self.client.abort() def test_retrbinary(self): - def callback(data): - received.append(data.decode(self.client.encoding)) received = [] - self.client.retrbinary('retr', callback) - self.check_data(''.join(received), RETR_DATA) + self.client.retrbinary('retr', received.append) + self.check_data(b''.join(received), + RETR_DATA.encode(self.client.encoding)) def test_retrbinary_rest(self): - def callback(data): - received.append(data.decode(self.client.encoding)) for rest in (0, 10, 20): received = [] - self.client.retrbinary('retr', callback, rest=rest) - self.check_data(''.join(received), RETR_DATA[rest:]) + self.client.retrbinary('retr', received.append, rest=rest) + self.check_data(b''.join(received), + RETR_DATA[rest:].encode(self.client.encoding)) def test_retrlines(self): received = [] @@ -612,7 +610,8 @@ def test_retrlines(self): def test_storbinary(self): f = io.BytesIO(RETR_DATA.encode(self.client.encoding)) self.client.storbinary('stor', f) - self.check_data(self.server.handler_instance.last_received_data, RETR_DATA) + self.check_data(self.server.handler_instance.last_received_data, + RETR_DATA.encode(self.server.encoding)) # test new callback arg flag = [] f.seek(0) @@ -631,7 +630,8 @@ def test_storlines(self): data = RETR_DATA.replace('\r\n', '\n').encode(self.client.encoding) f = io.BytesIO(data) self.client.storlines('stor', f) - self.check_data(self.server.handler_instance.last_received_data, RETR_DATA) + self.check_data(self.server.handler_instance.last_received_data, + RETR_DATA.encode(self.server.encoding)) # test new callback arg flag = [] f.seek(0) @@ -649,7 +649,7 @@ def test_nlst(self): def test_dir(self): l = [] - self.client.dir(lambda x: l.append(x)) + self.client.dir(l.append) self.assertEqual(''.join(l), LIST_DATA.replace('\r\n', '')) def test_mlsd(self): @@ -889,12 +889,10 @@ def test_makepasv(self): def test_transfer(self): def retr(): - def callback(data): - received.append(data.decode(self.client.encoding)) received = [] - self.client.retrbinary('retr', callback) - self.assertEqual(len(''.join(received)), len(RETR_DATA)) - self.assertEqual(''.join(received), RETR_DATA) + self.client.retrbinary('retr', received.append) + self.assertEqual(b''.join(received), + RETR_DATA.encode(self.client.encoding)) self.client.set_pasv(True) retr() self.client.set_pasv(False) From 95fd4edc6313a23bf74cb055aa430b0784a14112 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:39:07 -0700 Subject: [PATCH 0885/1206] [3.12] gh-109098: Fuzz re module instead of internal sre (GH-109911) (#109932) gh-109098: Fuzz re module instead of internal sre (GH-109911) * gh-109098: Fuzz re module instead of internal sre * Fix c-analyzer globals test failure * Put globals exception in ignored.tsv (cherry picked from commit a829356f86d597e4dfe92e236a6d711c8a464f16) Co-authored-by: Ammar Askar --- Modules/_xxtestfuzz/fuzzer.c | 45 +++++++++++----------------- Tools/c-analyzer/cpython/ignored.tsv | 6 ++-- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index 37d402824853f0..cd97206d181d62 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -188,37 +188,33 @@ static int fuzz_json_loads(const char* data, size_t size) { #define MAX_RE_TEST_SIZE 0x10000 -PyObject* sre_compile_method = NULL; -PyObject* sre_error_exception = NULL; -int SRE_FLAG_DEBUG = 0; +PyObject* re_compile_method = NULL; +PyObject* re_error_exception = NULL; +int RE_FLAG_DEBUG = 0; /* Called by LLVMFuzzerTestOneInput for initialization */ static int init_sre_compile(void) { /* Import sre_compile.compile and sre.error */ - PyObject* sre_compile_module = PyImport_ImportModule("sre_compile"); - if (sre_compile_module == NULL) { + PyObject* re_module = PyImport_ImportModule("re"); + if (re_module == NULL) { return 0; } - sre_compile_method = PyObject_GetAttrString(sre_compile_module, "compile"); - if (sre_compile_method == NULL) { + re_compile_method = PyObject_GetAttrString(re_module, "compile"); + if (re_compile_method == NULL) { return 0; } - PyObject* sre_constants = PyImport_ImportModule("sre_constants"); - if (sre_constants == NULL) { + re_error_exception = PyObject_GetAttrString(re_module, "error"); + if (re_error_exception == NULL) { return 0; } - sre_error_exception = PyObject_GetAttrString(sre_constants, "error"); - if (sre_error_exception == NULL) { - return 0; - } - PyObject* debug_flag = PyObject_GetAttrString(sre_constants, "SRE_FLAG_DEBUG"); + PyObject* debug_flag = PyObject_GetAttrString(re_module, "DEBUG"); if (debug_flag == NULL) { return 0; } - SRE_FLAG_DEBUG = PyLong_AsLong(debug_flag); + RE_FLAG_DEBUG = PyLong_AsLong(debug_flag); return 1; } -/* Fuzz _sre.compile(x) */ +/* Fuzz re.compile(x) */ static int fuzz_sre_compile(const char* data, size_t size) { /* Ignore really long regex patterns that will timeout the fuzzer */ if (size > MAX_RE_TEST_SIZE) { @@ -231,7 +227,7 @@ static int fuzz_sre_compile(const char* data, size_t size) { uint16_t flags = ((uint16_t*) data)[0]; /* We remove the SRE_FLAG_DEBUG if present. This is because it prints to stdout which greatly decreases fuzzing speed */ - flags &= ~SRE_FLAG_DEBUG; + flags &= ~RE_FLAG_DEBUG; /* Pull the pattern from the remaining bytes */ PyObject* pattern_bytes = PyBytes_FromStringAndSize(data + 2, size - 2); @@ -244,9 +240,9 @@ static int fuzz_sre_compile(const char* data, size_t size) { return 0; } - /* compiled = _sre.compile(data[2:], data[0:2] */ + /* compiled = re.compile(data[2:], data[0:2] */ PyObject* compiled = PyObject_CallFunctionObjArgs( - sre_compile_method, pattern_bytes, flags_obj, NULL); + re_compile_method, pattern_bytes, flags_obj, NULL); /* Ignore ValueError as the fuzzer will more than likely generate some invalid combination of flags */ if (compiled == NULL && PyErr_ExceptionMatches(PyExc_ValueError)) { @@ -262,7 +258,7 @@ static int fuzz_sre_compile(const char* data, size_t size) { PyErr_Clear(); } /* Ignore re.error */ - if (compiled == NULL && PyErr_ExceptionMatches(sre_error_exception)) { + if (compiled == NULL && PyErr_ExceptionMatches(re_error_exception)) { PyErr_Clear(); } @@ -526,13 +522,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { #if !defined(_Py_FUZZ_ONE) || defined(_Py_FUZZ_fuzz_sre_compile) static int SRE_COMPILE_INITIALIZED = 0; if (!SRE_COMPILE_INITIALIZED && !init_sre_compile()) { - if (!PyErr_ExceptionMatches(PyExc_DeprecationWarning)) { - PyErr_Print(); - abort(); - } - else { - PyErr_Clear(); - } + PyErr_Print(); + abort(); } else { SRE_COMPILE_INITIALIZED = 1; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 6a7c14ebb220a8..629a9a10ae59bb 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -572,15 +572,15 @@ Modules/_testmultiphase.c - uninitialized_def - Modules/_testsinglephase.c - global_state - Modules/_xxtestfuzz/_xxtestfuzz.c - _fuzzmodule - Modules/_xxtestfuzz/_xxtestfuzz.c - module_methods - -Modules/_xxtestfuzz/fuzzer.c - SRE_FLAG_DEBUG - +Modules/_xxtestfuzz/fuzzer.c - RE_FLAG_DEBUG - Modules/_xxtestfuzz/fuzzer.c - ast_literal_eval_method - Modules/_xxtestfuzz/fuzzer.c - compiled_patterns - Modules/_xxtestfuzz/fuzzer.c - csv_error - Modules/_xxtestfuzz/fuzzer.c - csv_module - Modules/_xxtestfuzz/fuzzer.c - json_loads_method - Modules/_xxtestfuzz/fuzzer.c - regex_patterns - -Modules/_xxtestfuzz/fuzzer.c - sre_compile_method - -Modules/_xxtestfuzz/fuzzer.c - sre_error_exception - +Modules/_xxtestfuzz/fuzzer.c - re_compile_method - +Modules/_xxtestfuzz/fuzzer.c - re_error_exception - Modules/_xxtestfuzz/fuzzer.c - struct_error - Modules/_xxtestfuzz/fuzzer.c - struct_unpack_method - Modules/_xxtestfuzz/fuzzer.c LLVMFuzzerTestOneInput CSV_READER_INITIALIZED - From 3ab9fdaedb9c6b77c75cb036851332f4d9215748 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:39:34 -0700 Subject: [PATCH 0886/1206] [3.12] Remove loop from docstring for asyncio.streams.open_connection (GH-108528) (#109941) Remove loop from docstring for asyncio.streams.open_connection (GH-108528) (cherry picked from commit e721f7a95186452339dc9e57630d639d549b2521) Co-authored-by: Tom Gillespie --- Lib/asyncio/streams.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index 14861dffce3a84..aff081a1e0d02c 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -66,9 +66,8 @@ async def start_server(client_connected_cb, host=None, port=None, *, positional host and port, with various optional keyword arguments following. The return value is the same as loop.create_server(). - Additional optional keyword arguments are loop (to set the event loop - instance to use) and limit (to set the buffer limit passed to the - StreamReader). + Additional optional keyword argument is limit (to set the buffer + limit passed to the StreamReader). The return value is the same as loop.create_server(), i.e. a Server object which can be used to stop the service. From 1fc25a389cf126b580ca6fdb65acdd6e42281e38 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:40:02 +0200 Subject: [PATCH 0887/1206] [3.12] gh-109615: Fix test_tools.test_freeze SRCDIR (#109935) (#109950) gh-109615: Fix test_tools.test_freeze SRCDIR (#109935) Fix copy_source_tree() function of test_tools.test_freeze: * Don't copy SRC_DIR/build/ anymore. This directory is modified by other tests running in parallel. * Add test.support.copy_python_src_ignore(). * Use sysconfig to get the source directory. * Use sysconfig.get_config_var() to get CONFIG_ARGS variable. (cherry picked from commit 1512d6c6ee2a770afb339bbb74c1b990116f7f89) --- Lib/test/libregrtest/main.py | 2 +- Lib/test/support/__init__.py | 26 +++++++++++++++++ Lib/test/test_support.py | 22 +++++++++++++++ Lib/test/test_venv.py | 6 ++-- Tools/freeze/test/freeze.py | 54 +++++------------------------------- 5 files changed, 60 insertions(+), 50 deletions(-) diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index ab03647ca5802f..7cfea548ee2180 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -747,7 +747,7 @@ def set_temp_dir(self): if sysconfig.is_python_build(): self.tmp_dir = sysconfig.get_config_var('abs_builddir') if self.tmp_dir is None: - # bpo-30284: On Windows, only srcdir is available. Using + # gh-74470: On Windows, only srcdir is available. Using # abs_builddir mostly matters on UNIX when building Python # out of the source tree, especially when the source tree # is read only. diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 389d39c83bc006..fa26ce8c1a7bd8 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2554,3 +2554,29 @@ def adjust_int_max_str_digits(max_digits): #Windows doesn't have os.uname() but it doesn't support s390x. skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x', 'skipped on s390x') + +_BASE_COPY_SRC_DIR_IGNORED_NAMES = frozenset({ + # SRC_DIR/.git + '.git', + # ignore all __pycache__/ sub-directories + '__pycache__', +}) + +# Ignore function for shutil.copytree() to copy the Python source code. +def copy_python_src_ignore(path, names): + ignored = _BASE_COPY_SRC_DIR_IGNORED_NAMES + if os.path.basename(path) == 'Doc': + ignored |= { + # SRC_DIR/Doc/build/ + 'build', + # SRC_DIR/Doc/venv/ + 'venv', + } + + # check if we are at the root of the source code + elif 'Modules' in names: + ignored |= { + # SRC_DIR/build/ + 'build', + } + return ignored diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 4047e0bd0164a5..d3b2922d9b0ad1 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -7,6 +7,7 @@ import stat import subprocess import sys +import sysconfig import tempfile import textwrap import unittest @@ -765,6 +766,27 @@ def recursive_function(depth): #self.assertEqual(available, 2) + def test_copy_python_src_ignore(self): + src_dir = sysconfig.get_config_var('srcdir') + src_dir = os.path.abspath(src_dir) + + ignored = {'.git', '__pycache__'} + + # Source code directory + names = os.listdir(src_dir) + self.assertEqual(support.copy_python_src_ignore(src_dir, names), + ignored | {'build'}) + + # Doc/ directory + path = os.path.join(src_dir, 'Doc') + self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)), + ignored | {'build', 'venv'}) + + # An other directory + path = os.path.join(src_dir, 'Objects') + self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)), + ignored) + # XXX -follows a list of untested API # make_legacy_pyc # is_resource_enabled diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index aa6a8fbf8cfd17..6942bf246b61d1 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -21,7 +21,7 @@ skip_if_broken_multiprocessing_synchronize, verbose, requires_subprocess, is_emscripten, is_wasi, requires_venv_with_pip, TEST_HOME_DIR, - requires_resource) + requires_resource, copy_python_src_ignore) from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) import unittest import venv @@ -561,6 +561,7 @@ def test_zippath_from_non_installed_posix(self): platlibdir, stdlib_zip) additional_pythonpath_for_non_installed = [] + # Copy stdlib files to the non-installed python so venv can # correctly calculate the prefix. for eachpath in sys.path: @@ -577,7 +578,8 @@ def test_zippath_from_non_installed_posix(self): if os.path.isfile(fn): shutil.copy(fn, libdir) elif os.path.isdir(fn): - shutil.copytree(fn, os.path.join(libdir, name)) + shutil.copytree(fn, os.path.join(libdir, name), + ignore=copy_python_src_ignore) else: additional_pythonpath_for_non_installed.append( eachpath) diff --git a/Tools/freeze/test/freeze.py b/Tools/freeze/test/freeze.py index 92e97cb261719c..bb15941464e3d1 100644 --- a/Tools/freeze/test/freeze.py +++ b/Tools/freeze/test/freeze.py @@ -1,14 +1,15 @@ import os import os.path -import re import shlex import shutil import subprocess +import sysconfig +from test import support TESTS_DIR = os.path.dirname(__file__) TOOL_ROOT = os.path.dirname(TESTS_DIR) -SRCDIR = os.path.dirname(os.path.dirname(TOOL_ROOT)) +SRCDIR = os.path.abspath(sysconfig.get_config_var('srcdir')) MAKE = shutil.which('make') FREEZE = os.path.join(TOOL_ROOT, 'freeze.py') @@ -75,56 +76,17 @@ def ensure_opt(args, name, value): def copy_source_tree(newroot, oldroot): - print(f'copying the source tree into {newroot}...') + print(f'copying the source tree from {oldroot} to {newroot}...') if os.path.exists(newroot): if newroot == SRCDIR: raise Exception('this probably isn\'t what you wanted') shutil.rmtree(newroot) - def ignore_non_src(src, names): - """Turns what could be a 1000M copy into a 100M copy.""" - # Don't copy the ~600M+ of needless git repo metadata. - # source only, ignore cached .pyc files. - subdirs_to_skip = {'.git', '__pycache__'} - if os.path.basename(src) == 'Doc': - # Another potential ~250M+ of non test related data. - subdirs_to_skip.add('build') - subdirs_to_skip.add('venv') - return subdirs_to_skip - - shutil.copytree(oldroot, newroot, ignore=ignore_non_src) + shutil.copytree(oldroot, newroot, ignore=support.copy_python_src_ignore) if os.path.exists(os.path.join(newroot, 'Makefile')): _run_quiet([MAKE, 'clean'], newroot) -def get_makefile_var(builddir, name): - regex = re.compile(rf'^{name} *=\s*(.*?)\s*$') - filename = os.path.join(builddir, 'Makefile') - try: - infile = open(filename, encoding='utf-8') - except FileNotFoundError: - return None - with infile: - for line in infile: - m = regex.match(line) - if m: - value, = m.groups() - return value or '' - return None - - -def get_config_var(builddir, name): - python = os.path.join(builddir, 'python') - if os.path.isfile(python): - cmd = [python, '-c', - f'import sysconfig; print(sysconfig.get_config_var("{name}"))'] - try: - return _run_stdout(cmd) - except subprocess.CalledProcessError: - pass - return get_makefile_var(builddir, name) - - ################################## # freezing @@ -151,10 +113,8 @@ def prepare(script=None, outdir=None): # Run configure. print(f'configuring python in {builddir}...') - cmd = [ - os.path.join(srcdir, 'configure'), - *shlex.split(get_config_var(SRCDIR, 'CONFIG_ARGS') or ''), - ] + config_args = shlex.split(sysconfig.get_config_var('CONFIG_ARGS') or '') + cmd = [os.path.join(srcdir, 'configure'), *config_args] ensure_opt(cmd, 'cache-file', os.path.join(outdir, 'python-config.cache')) prefix = os.path.join(outdir, 'python-installation') ensure_opt(cmd, 'prefix', prefix) From 73ec1e7c219ea116521bd1024d23b352625966f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:40:16 -0700 Subject: [PATCH 0888/1206] [3.12] gh-109565: Fix concurrent.futures test_future_times_out() (GH-109949) (#109952) gh-109565: Fix concurrent.futures test_future_times_out() (GH-109949) as_completed() uses a timeout of 100 ms instead of 10 ms. Windows monotonic clock resolution is around 15.6 ms. (cherry picked from commit b1aebf1e6576680d606068d17e2208259573e061) Co-authored-by: Victor Stinner --- Lib/test/test_concurrent_futures/test_as_completed.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_concurrent_futures/test_as_completed.py b/Lib/test/test_concurrent_futures/test_as_completed.py index 2b3bec8cafbcb0..c90b0021d85fc7 100644 --- a/Lib/test/test_concurrent_futures/test_as_completed.py +++ b/Lib/test/test_concurrent_futures/test_as_completed.py @@ -42,11 +42,14 @@ def test_future_times_out(self): EXCEPTION_FUTURE, SUCCESSFUL_FUTURE} - for timeout in (0, 0.01): + # Windows clock resolution is around 15.6 ms + short_timeout = 0.100 + for timeout in (0, short_timeout): with self.subTest(timeout): - future = self.executor.submit(time.sleep, 0.1) completed_futures = set() + future = self.executor.submit(time.sleep, short_timeout * 10) + try: for f in futures.as_completed( already_completed | {future}, From dd67e59bb195cac4a4d9fdc05eca217cd1918f96 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:41:12 -0700 Subject: [PATCH 0889/1206] [3.12] gh-109955 : Update state transition comments for asyncio.Task (GH-109910) (#109992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-109955 : Update state transition comments for asyncio.Task (GH-109910) (cherry picked from commit 45cf5b0c69bb5c51f33fc681d90c45147e311ddf) Co-authored-by: Kristján Valur Jónsson Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Lib/asyncio/tasks.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 152c9f8afcc062..65f2a6ef800482 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -86,15 +86,25 @@ class Task(futures._PyFuture): # Inherit Python Task implementation """A coroutine wrapped in a Future.""" # An important invariant maintained while a Task not done: + # _fut_waiter is either None or a Future. The Future + # can be either done() or not done(). + # The task can be in any of 3 states: # - # - Either _fut_waiter is None, and _step() is scheduled; - # - or _fut_waiter is some Future, and _step() is *not* scheduled. + # - 1: _fut_waiter is not None and not _fut_waiter.done(): + # __step() is *not* scheduled and the Task is waiting for _fut_waiter. + # - 2: (_fut_waiter is None or _fut_waiter.done()) and __step() is scheduled: + # the Task is waiting for __step() to be executed. + # - 3: _fut_waiter is None and __step() is *not* scheduled: + # the Task is currently executing (in __step()). # - # The only transition from the latter to the former is through - # _wakeup(). When _fut_waiter is not None, one of its callbacks - # must be _wakeup(). - - # If False, don't log a message if the task is destroyed whereas its + # * In state 1, one of the callbacks of __fut_waiter must be __wakeup(). + # * The transition from 1 to 2 happens when _fut_waiter becomes done(), + # as it schedules __wakeup() to be called (which calls __step() so + # we way that __step() is scheduled). + # * It transitions from 2 to 3 when __step() is executed, and it clears + # _fut_waiter to None. + + # If False, don't log a message if the task is destroyed while its # status is still pending _log_destroy_pending = True From 9be6a111993c5e75574b0e858b57969c245c5866 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 2 Oct 2023 08:41:26 -0700 Subject: [PATCH 0890/1206] =?UTF-8?q?[3.12]=20gh-109818:=20`reprlib.recurs?= =?UTF-8?q?ive=5Frepr`=20copies=20`=5F=5Ftype=5Fparams=5F=5F`=20(=E2=80=A6?= =?UTF-8?q?=20(#109999)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [3.12] gh-109818: `reprlib.recursive_repr` copies `__type_params__` (GH-109819). (cherry picked from commit f65f9e80fe741c894582a3e413d4e3318c1ed626) Co-authored-by: Nikita Sobolev --- Lib/reprlib.py | 1 + Lib/test/test_reprlib.py | 11 +++++++++++ .../2023-09-25-09-59-59.gh-issue-109818.dLRtT-.rst | 2 ++ 3 files changed, 14 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-09-25-09-59-59.gh-issue-109818.dLRtT-.rst diff --git a/Lib/reprlib.py b/Lib/reprlib.py index a92b3e3dbb613a..a7b37630a4edb9 100644 --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -29,6 +29,7 @@ def wrapper(self): wrapper.__name__ = getattr(user_function, '__name__') wrapper.__qualname__ = getattr(user_function, '__qualname__') wrapper.__annotations__ = getattr(user_function, '__annotations__', {}) + wrapper.__type_params__ = getattr(user_function, '__type_params__', ()) return wrapper return decorating_function diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index e7216d427200c1..4a896db2002047 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -765,5 +765,16 @@ def test_assigned_attributes(self): for name in assigned: self.assertIs(getattr(wrapper, name), getattr(wrapped, name)) + def test__type_params__(self): + class My: + @recursive_repr() + def __repr__[T: str](self, default: T = '') -> str: + return default + + type_params = My().__repr__.__type_params__ + self.assertEqual(len(type_params), 1) + self.assertEqual(type_params[0].__name__, 'T') + self.assertEqual(type_params[0].__bound__, str) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-09-25-09-59-59.gh-issue-109818.dLRtT-.rst b/Misc/NEWS.d/next/Library/2023-09-25-09-59-59.gh-issue-109818.dLRtT-.rst new file mode 100644 index 00000000000000..184086af2585ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-25-09-59-59.gh-issue-109818.dLRtT-.rst @@ -0,0 +1,2 @@ +Fix :func:`reprlib.recursive_repr` not copying ``__type_params__`` from +decorated function. From 9cf6d89165ac5543c5c2a3112f303f32778c2548 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:42:03 -0700 Subject: [PATCH 0891/1206] [3.12] gh-109594: Fix concurrent.futures test_timeout() (GH-110018) (#110021) gh-109594: Fix concurrent.futures test_timeout() (GH-110018) Fix test_timeout() of test_concurrent_futures.test_wait. Remove the future which may or may not complete depending if it takes longer than the timeout ot not. Keep the second future which does not complete before wait(). Make also the test faster: 0.5 second instead of 6 seconds, so remove @support.requires_resource('walltime') decorator. (cherry picked from commit 9be283e5e15d5d5685b78a38eb132501f7f3febb) Co-authored-by: Victor Stinner --- Lib/test/test_concurrent_futures/test_wait.py | 17 +++++++++-------- ...23-09-28-14-47-14.gh-issue-109594.DB5KPP.rst | 4 ++++ 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-28-14-47-14.gh-issue-109594.DB5KPP.rst diff --git a/Lib/test/test_concurrent_futures/test_wait.py b/Lib/test/test_concurrent_futures/test_wait.py index 3f64ca173c02f6..ff486202092c81 100644 --- a/Lib/test/test_concurrent_futures/test_wait.py +++ b/Lib/test/test_concurrent_futures/test_wait.py @@ -112,24 +112,25 @@ def test_all_completed(self): future2]), finished) self.assertEqual(set(), pending) - @support.requires_resource('walltime') def test_timeout(self): - future1 = self.executor.submit(mul, 6, 7) - future2 = self.executor.submit(time.sleep, 6) + short_timeout = 0.050 + long_timeout = short_timeout * 10 + + future = self.executor.submit(time.sleep, long_timeout) finished, pending = futures.wait( [CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, SUCCESSFUL_FUTURE, - future1, future2], - timeout=5, + future], + timeout=short_timeout, return_when=futures.ALL_COMPLETED) self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1]), finished) - self.assertEqual(set([future2]), pending) + SUCCESSFUL_FUTURE]), + finished) + self.assertEqual(set([future]), pending) class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests, BaseTestCase): diff --git a/Misc/NEWS.d/next/Tests/2023-09-28-14-47-14.gh-issue-109594.DB5KPP.rst b/Misc/NEWS.d/next/Tests/2023-09-28-14-47-14.gh-issue-109594.DB5KPP.rst new file mode 100644 index 00000000000000..5a4ae2b0837df6 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-28-14-47-14.gh-issue-109594.DB5KPP.rst @@ -0,0 +1,4 @@ +Fix test_timeout() of test_concurrent_futures.test_wait. Remove the future +which may or may not complete depending if it takes longer than the timeout +ot not. Keep the second future which does not complete before wait() +timeout. Patch by Victor Stinner. From 4bdcb99469ed4d9e4ab2ef3586985a081a18b2bb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:42:40 -0700 Subject: [PATCH 0892/1206] [3.12] gh-110033: Fix signal test_interprocess_signal() (GH-110035) (#110040) gh-110033: Fix signal test_interprocess_signal() (GH-110035) Fix test_interprocess_signal() of test_signal. Make sure that the subprocess.Popen object is deleted before the test raising an exception in a signal handler. Otherwise, Popen.__del__() can get the exception which is logged as "Exception ignored in: ...." and the test fails. (cherry picked from commit 7e0fbf5175fcf21dae390ba68b7f49706d62aa49) Co-authored-by: Victor Stinner --- Lib/test/signalinterproctester.py | 8 ++++++++ .../Tests/2023-09-28-18-14-52.gh-issue-110033.2yHMx0.rst | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-28-18-14-52.gh-issue-110033.2yHMx0.rst diff --git a/Lib/test/signalinterproctester.py b/Lib/test/signalinterproctester.py index cdcd92a8baace6..073c078f45f6d7 100644 --- a/Lib/test/signalinterproctester.py +++ b/Lib/test/signalinterproctester.py @@ -1,3 +1,4 @@ +import gc import os import signal import subprocess @@ -59,6 +60,13 @@ def test_interprocess_signal(self): self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 0, 'SIGALRM': 0}) + # gh-110033: Make sure that the subprocess.Popen is deleted before + # the next test which raises an exception. Otherwise, the exception + # may be raised when Popen.__del__() is executed and so be logged + # as "Exception ignored in: ". + child = None + gc.collect() + with self.assertRaises(SIGUSR1Exception): with self.subprocess_send_signal(pid, "SIGUSR1") as child: self.wait_signal(child, 'SIGUSR1') diff --git a/Misc/NEWS.d/next/Tests/2023-09-28-18-14-52.gh-issue-110033.2yHMx0.rst b/Misc/NEWS.d/next/Tests/2023-09-28-18-14-52.gh-issue-110033.2yHMx0.rst new file mode 100644 index 00000000000000..fb6089377083bf --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-28-18-14-52.gh-issue-110033.2yHMx0.rst @@ -0,0 +1,5 @@ +Fix ``test_interprocess_signal()`` of ``test_signal``. Make sure that the +``subprocess.Popen`` object is deleted before the test raising an exception +in a signal handler. Otherwise, ``Popen.__del__()`` can get the exception +which is logged as ``Exception ignored in: ...`` and the test fails. Patch by +Victor Stinner. From c7941034171cd608a0235731832b7784200dec70 Mon Sep 17 00:00:00 2001 From: Davide Rizzo Date: Mon, 2 Oct 2023 17:42:55 +0200 Subject: [PATCH 0893/1206] [3.12] gh-110038: KqueueSelector must count all read/write events (GH-110039) (#110043) [3.12] gh-110038: KqueueSelector must count all read/write events (GH-110039). (cherry picked from commit b14f0ab51cb4851b25935279617e388456dcf716) --- Lib/selectors.py | 7 ++++- Lib/test/test_selectors.py | 29 +++++++++++++++++++ ...-09-28-18-50-33.gh-issue-110038.nx_gCu.rst | 3 ++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-28-18-50-33.gh-issue-110038.nx_gCu.rst diff --git a/Lib/selectors.py b/Lib/selectors.py index af6a4f94b5008a..c3b065b52264aa 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -509,6 +509,7 @@ class KqueueSelector(_BaseSelectorImpl): def __init__(self): super().__init__() self._selector = select.kqueue() + self._max_events = 0 def fileno(self): return self._selector.fileno() @@ -520,10 +521,12 @@ def register(self, fileobj, events, data=None): kev = select.kevent(key.fd, select.KQ_FILTER_READ, select.KQ_EV_ADD) self._selector.control([kev], 0, 0) + self._max_events += 1 if events & EVENT_WRITE: kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD) self._selector.control([kev], 0, 0) + self._max_events += 1 except: super().unregister(fileobj) raise @@ -534,6 +537,7 @@ def unregister(self, fileobj): if key.events & EVENT_READ: kev = select.kevent(key.fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE) + self._max_events -= 1 try: self._selector.control([kev], 0, 0) except OSError: @@ -543,6 +547,7 @@ def unregister(self, fileobj): if key.events & EVENT_WRITE: kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE) + self._max_events -= 1 try: self._selector.control([kev], 0, 0) except OSError: @@ -555,7 +560,7 @@ def select(self, timeout=None): # If max_ev is 0, kqueue will ignore the timeout. For consistent # behavior with the other selector classes, we prevent that here # (using max). See https://bugs.python.org/issue29255 - max_ev = max(len(self._fd_to_key), 1) + max_ev = self._max_events or 1 ready = [] try: kev_list = self._selector.control(None, max_ev, timeout) diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py index 12ecc50d550c4f..31757205ca37c5 100644 --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -279,6 +279,35 @@ def test_select(self): self.assertEqual([(wr_key, selectors.EVENT_WRITE)], result) + def test_select_read_write(self): + # gh-110038: when a file descriptor is registered for both read and + # write, the two events must be seen on a single call to select(). + s = self.SELECTOR() + self.addCleanup(s.close) + + sock1, sock2 = self.make_socketpair() + sock2.send(b"foo") + my_key = s.register(sock1, selectors.EVENT_READ | selectors.EVENT_WRITE) + + seen_read, seen_write = False, False + result = s.select() + # We get the read and write either in the same result entry or in two + # distinct entries with the same key. + self.assertLessEqual(len(result), 2) + for key, events in result: + self.assertTrue(isinstance(key, selectors.SelectorKey)) + self.assertEqual(key, my_key) + self.assertFalse(events & ~(selectors.EVENT_READ | + selectors.EVENT_WRITE)) + if events & selectors.EVENT_READ: + self.assertFalse(seen_read) + seen_read = True + if events & selectors.EVENT_WRITE: + self.assertFalse(seen_write) + seen_write = True + self.assertTrue(seen_read) + self.assertTrue(seen_write) + def test_context_manager(self): s = self.SELECTOR() self.addCleanup(s.close) diff --git a/Misc/NEWS.d/next/Library/2023-09-28-18-50-33.gh-issue-110038.nx_gCu.rst b/Misc/NEWS.d/next/Library/2023-09-28-18-50-33.gh-issue-110038.nx_gCu.rst new file mode 100644 index 00000000000000..6b2abd802fccdc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-28-18-50-33.gh-issue-110038.nx_gCu.rst @@ -0,0 +1,3 @@ +Fixed an issue that caused :meth:`KqueueSelector.select` to not return all +the ready events in some cases when a file descriptor is registered for both +read and write. From 2b96102f29d2634a69b04cc782236cb12d8e3e56 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:43:16 -0700 Subject: [PATCH 0894/1206] [3.12] gh-109889: fix compiler's redundant NOP detection to look past NOPs with no lineno when looking for the next instruction's lineno (GH-109987) (#110048) gh-109889: fix compiler's redundant NOP detection to look past NOPs with no lineno when looking for the next instruction's lineno (GH-109987) (cherry picked from commit f580edcc6a4c528020afe46c753db713474acad6) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/test/test_compile.py | 5 +++++ .../2023-09-27-21-35-49.gh-issue-109889.t5hIRT.rst | 2 ++ Python/flowgraph.c | 12 +++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-27-21-35-49.gh-issue-109889.t5hIRT.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index b75d1c59591e91..42df670fe00e0a 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1269,6 +1269,11 @@ def f(x): while x: 0 if 1 else 0 + def test_remove_redundant_nop_edge_case(self): + # See gh-109889 + def f(): + a if (1 if b else c) else d + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): # Ensure that compiled code snippets have correct line and column numbers diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-27-21-35-49.gh-issue-109889.t5hIRT.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-27-21-35-49.gh-issue-109889.t5hIRT.rst new file mode 100644 index 00000000000000..8be373f0f6b6cd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-27-21-35-49.gh-issue-109889.t5hIRT.rst @@ -0,0 +1,2 @@ +Fix the compiler's redundant NOP detection algorithm to skip over NOPs with +no line number when looking for the next instruction's lineno. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index f860631a6c21dd..afcae317403ef2 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -981,7 +981,17 @@ remove_redundant_nops(basicblock *bb) { } /* or if last instruction in BB and next BB has same line number */ if (next) { - if (lineno == next->b_instr[0].i_loc.lineno) { + location next_loc = NO_LOCATION; + for (int next_i=0; next_i < next->b_iused; next_i++) { + cfg_instr *instr = &next->b_instr[next_i]; + if (instr->i_opcode == NOP && instr->i_loc.lineno == NO_LOCATION.lineno) { + /* Skip over NOPs without location, they will be removed */ + continue; + } + next_loc = instr->i_loc; + break; + } + if (lineno == next_loc.lineno) { continue; } } From aaa8bf18c6e569abb178896a68786ad3857663e9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:43:38 -0700 Subject: [PATCH 0895/1206] [3.12] gh-109960: Remove test_pty timeout of 10 seconds (GH-110058) (#110060) gh-109960: Remove test_pty timeout of 10 seconds (GH-110058) In 2003, test_pty got a hardcoded timeout of 10 seconds to prevent hanging on AIX & HPUX "if run after test_openpty": commit 7d8145268ee282f14d6adce9305dc3c1c7ffec14. Since 2003, test_pty was no longer reported to hang on AIX. But today, the test can fail simply because a CI is busy running other tests in parallel. The timeout of 10 seconds is no longer needed, just remove it. Moreover, regrtest now has multiple built-in generic timeout mecanisms. (cherry picked from commit 5fdcea744024c8a19ddb57057bf5ec2889546c98) Co-authored-by: Victor Stinner --- Lib/test/test_pty.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index c9c2b42861c6f4..a971f6b0250efb 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -80,17 +80,9 @@ def expectedFailureIfStdinIsTTY(fun): # because pty code is not too portable. class PtyTest(unittest.TestCase): def setUp(self): - old_alarm = signal.signal(signal.SIGALRM, self.handle_sig) - self.addCleanup(signal.signal, signal.SIGALRM, old_alarm) - old_sighup = signal.signal(signal.SIGHUP, self.handle_sighup) self.addCleanup(signal.signal, signal.SIGHUP, old_sighup) - # isatty() and close() can hang on some platforms. Set an alarm - # before running the test to make sure we don't hang forever. - self.addCleanup(signal.alarm, 0) - signal.alarm(10) - # Save original stdin window size. self.stdin_dim = None if _HAVE_WINSZ: @@ -101,9 +93,6 @@ def setUp(self): except tty.error: pass - def handle_sig(self, sig, frame): - self.fail("isatty hung") - @staticmethod def handle_sighup(signum, frame): pass From a2074911baaa75216a6a3bc78487ee2254f031d5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:44:26 -0700 Subject: [PATCH 0896/1206] [3.12] gh-110036: multiprocessing Popen.terminate() catches PermissionError (GH-110037) (#110064) gh-110036: multiprocessing Popen.terminate() catches PermissionError (GH-110037) On Windows, multiprocessing Popen.terminate() now catchs PermissionError and get the process exit code. If the process is still running, raise again the PermissionError. Otherwise, the process terminated as expected: store its exit code. (cherry picked from commit bd4518c60c9df356cf5e05b81305e3644ebb5e70) Co-authored-by: Victor Stinner --- Lib/multiprocessing/popen_spawn_win32.py | 11 +++++++++-- Lib/test/_test_multiprocessing.py | 5 +++-- .../2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst | 5 +++++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst diff --git a/Lib/multiprocessing/popen_spawn_win32.py b/Lib/multiprocessing/popen_spawn_win32.py index 4d60ffc030bea6..af044305709e56 100644 --- a/Lib/multiprocessing/popen_spawn_win32.py +++ b/Lib/multiprocessing/popen_spawn_win32.py @@ -14,6 +14,7 @@ # # +# Exit code used by Popen.terminate() TERMINATE = 0x10000 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") @@ -122,9 +123,15 @@ def terminate(self): if self.returncode is None: try: _winapi.TerminateProcess(int(self._handle), TERMINATE) - except OSError: - if self.wait(timeout=1.0) is None: + except PermissionError: + # ERROR_ACCESS_DENIED (winerror 5) is received when the + # process already died. + code = _winapi.GetExitCodeProcess(int(self._handle)) + if code == _winapi.STILL_ACTIVE: raise + self.returncode = code + else: + self.returncode = -signal.SIGTERM kill = terminate diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index ca8fcab09af6da..34027b004f5602 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -557,13 +557,14 @@ def handler(*args): def test_terminate(self): exitcode = self._kill_process(multiprocessing.Process.terminate) - if os.name != 'nt': - self.assertEqual(exitcode, -signal.SIGTERM) + self.assertEqual(exitcode, -signal.SIGTERM) def test_kill(self): exitcode = self._kill_process(multiprocessing.Process.kill) if os.name != 'nt': self.assertEqual(exitcode, -signal.SIGKILL) + else: + self.assertEqual(exitcode, -signal.SIGTERM) def test_cpu_count(self): try: diff --git a/Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst b/Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst new file mode 100644 index 00000000000000..ddb11b5c3546a1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst @@ -0,0 +1,5 @@ +On Windows, multiprocessing ``Popen.terminate()`` now catchs +:exc:`PermissionError` and get the process exit code. If the process is +still running, raise again the :exc:`PermissionError`. Otherwise, the +process terminated as expected: store its exit code. Patch by Victor +Stinner. From d0641ab676ac117bcf71fb8b0fd531a82bff6501 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:44:51 +0200 Subject: [PATCH 0897/1206] [3.12] gh-110052: Fix faulthandler for freed tstate (#110069) (#110071) gh-110052: Fix faulthandler for freed tstate (#110069) faulthandler now detected freed interp and freed tstate, and no longer dereference them. (cherry picked from commit 2e37a38bcbfbe1357436e030538290e7d00b668d) --- Modules/faulthandler.c | 3 +-- Python/traceback.c | 47 +++++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 3d360cb4368cca..be77bb01f3fae1 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -176,7 +176,6 @@ faulthandler_dump_traceback(int fd, int all_threads, PyInterpreterState *interp) { static volatile int reentrant = 0; - PyThreadState *tstate; if (reentrant) return; @@ -191,7 +190,7 @@ faulthandler_dump_traceback(int fd, int all_threads, fault if the thread released the GIL, and so this function cannot be used. Read the thread specific storage (TSS) instead: call PyGILState_GetThisThreadState(). */ - tstate = PyGILState_GetThisThreadState(); + PyThreadState *tstate = PyGILState_GetThisThreadState(); if (all_threads) { (void)_Py_DumpTracebackThreads(fd, NULL, tstate); diff --git a/Python/traceback.c b/Python/traceback.c index dc258703a8c49a..0070f1591a5275 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -1218,23 +1218,45 @@ dump_frame(int fd, _PyInterpreterFrame *frame) PUTS(fd, "\n"); } +static int +tstate_is_freed(PyThreadState *tstate) +{ + if (_PyMem_IsPtrFreed(tstate)) { + return 1; + } + if (_PyMem_IsPtrFreed(tstate->interp)) { + return 1; + } + return 0; +} + + +static int +interp_is_freed(PyInterpreterState *interp) +{ + return _PyMem_IsPtrFreed(interp); +} + + static void dump_traceback(int fd, PyThreadState *tstate, int write_header) { - _PyInterpreterFrame *frame; - unsigned int depth; - if (write_header) { PUTS(fd, "Stack (most recent call first):\n"); } - frame = tstate->cframe->current_frame; + if (tstate_is_freed(tstate)) { + PUTS(fd, " \n"); + return; + } + + _PyInterpreterFrame *frame = tstate->cframe->current_frame; if (frame == NULL) { PUTS(fd, " \n"); return; } - depth = 0; + unsigned int depth = 0; while (1) { if (MAX_FRAME_DEPTH <= depth) { PUTS(fd, " ...\n"); @@ -1298,9 +1320,6 @@ const char* _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, PyThreadState *current_tstate) { - PyThreadState *tstate; - unsigned int nthreads; - if (current_tstate == NULL) { /* _Py_DumpTracebackThreads() is called from signal handlers by faulthandler. @@ -1316,6 +1335,10 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, current_tstate = PyGILState_GetThisThreadState(); } + if (current_tstate != NULL && tstate_is_freed(current_tstate)) { + return "tstate is freed"; + } + if (interp == NULL) { if (current_tstate == NULL) { interp = _PyGILState_GetInterpreterStateUnsafe(); @@ -1330,14 +1353,18 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, } assert(interp != NULL); + if (interp_is_freed(interp)) { + return "interp is freed"; + } + /* Get the current interpreter from the current thread */ - tstate = PyInterpreterState_ThreadHead(interp); + PyThreadState *tstate = PyInterpreterState_ThreadHead(interp); if (tstate == NULL) return "unable to get the thread head state"; /* Dump the traceback of each thread */ tstate = PyInterpreterState_ThreadHead(interp); - nthreads = 0; + unsigned int nthreads = 0; _Py_BEGIN_SUPPRESS_IPH do { From 41eb0c728653d2dfc0f9b4529557288069b6047a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:46:45 -0700 Subject: [PATCH 0898/1206] [3.12] gh-109592: test_eintr tolerates 20 ms when comparing timings (GH-110102) (#110106) gh-109592: test_eintr tolerates 20 ms when comparing timings (GH-110102) (cherry picked from commit 9c73a9acec095c05a178e7dff638f7d9769318f3) Co-authored-by: Victor Stinner --- Lib/test/_test_eintr.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Lib/test/_test_eintr.py b/Lib/test/_test_eintr.py index 006581f7cc6a9a..15586f15dfab30 100644 --- a/Lib/test/_test_eintr.py +++ b/Lib/test/_test_eintr.py @@ -25,6 +25,12 @@ from test.support import os_helper from test.support import socket_helper + +# gh-109592: Tolerate a difference of 20 ms when comparing timings +# (clock resolution) +CLOCK_RES = 0.020 + + @contextlib.contextmanager def kill_on_error(proc): """Context manager killing the subprocess if a Python exception is raised.""" @@ -75,6 +81,9 @@ def subprocess(self, *args, **kw): cmd_args = (sys.executable, '-c') + args return subprocess.Popen(cmd_args, **kw) + def check_elapsed_time(self, elapsed): + self.assertGreaterEqual(elapsed, self.sleep_time - CLOCK_RES) + @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") class OSEINTRTest(EINTRBaseTest): @@ -373,7 +382,7 @@ def test_sleep(self): time.sleep(self.sleep_time) self.stop_alarm() dt = time.monotonic() - t0 - self.assertGreaterEqual(dt, self.sleep_time) + self.check_elapsed_time(dt) @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") @@ -435,7 +444,7 @@ def test_select(self): select.select([], [], [], self.sleep_time) dt = time.monotonic() - t0 self.stop_alarm() - self.assertGreaterEqual(dt, self.sleep_time) + self.check_elapsed_time(dt) @unittest.skipIf(sys.platform == "darwin", "poll may fail on macOS; see issue #28087") @@ -447,7 +456,7 @@ def test_poll(self): poller.poll(self.sleep_time * 1e3) dt = time.monotonic() - t0 self.stop_alarm() - self.assertGreaterEqual(dt, self.sleep_time) + self.check_elapsed_time(dt) @unittest.skipUnless(hasattr(select, 'epoll'), 'need select.epoll') def test_epoll(self): @@ -458,7 +467,7 @@ def test_epoll(self): poller.poll(self.sleep_time) dt = time.monotonic() - t0 self.stop_alarm() - self.assertGreaterEqual(dt, self.sleep_time) + self.check_elapsed_time(dt) @unittest.skipUnless(hasattr(select, 'kqueue'), 'need select.kqueue') def test_kqueue(self): @@ -469,7 +478,7 @@ def test_kqueue(self): kqueue.control(None, 1, self.sleep_time) dt = time.monotonic() - t0 self.stop_alarm() - self.assertGreaterEqual(dt, self.sleep_time) + self.check_elapsed_time(dt) @unittest.skipUnless(hasattr(select, 'devpoll'), 'need select.devpoll') def test_devpoll(self): @@ -480,7 +489,7 @@ def test_devpoll(self): poller.poll(self.sleep_time * 1e3) dt = time.monotonic() - t0 self.stop_alarm() - self.assertGreaterEqual(dt, self.sleep_time) + self.check_elapsed_time(dt) class FNTLEINTRTest(EINTRBaseTest): @@ -512,8 +521,8 @@ def _lock(self, lock_func, lock_name): # potential context switch delay lock_func(f, fcntl.LOCK_EX) dt = time.monotonic() - start_time - self.assertGreaterEqual(dt, self.sleep_time) self.stop_alarm() + self.check_elapsed_time(dt) proc.wait() # Issue 35633: See https://bugs.python.org/issue35633#msg333662 From 356de021d7dc02d4803627c0807c0950f7453754 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:47:10 +0200 Subject: [PATCH 0899/1206] [3.12] gh-109047: concurrent.futures catches RuntimeError (#109810) (#110126) gh-109047: concurrent.futures catches PythonFinalizationError (#109810) concurrent.futures: The *executor manager thread* now catches exceptions when adding an item to the *call queue*. During Python finalization, creating a new thread can now raise RuntimeError. Catch the exception and call terminate_broken() in this case. Add test_python_finalization_error() to test_concurrent_futures. concurrent.futures._ExecutorManagerThread changes: * terminate_broken() no longer calls shutdown_workers() since the call queue is no longer working anymore (read and write ends of the queue pipe are closed). * terminate_broken() now terminates child processes, not only wait until they complete. * _ExecutorManagerThread.terminate_broken() now holds shutdown_lock to prevent race conditons with ProcessPoolExecutor.submit(). multiprocessing.Queue changes: * Add _terminate_broken() method. * _start_thread() sets _thread to None on exception to prevent leaking "dangling threads" even if the thread was not started yet. (cherry picked from commit 635184212179b0511768ea1cd57256e134ba2d75) --- Lib/concurrent/futures/process.py | 49 ++++++++++++++----- Lib/multiprocessing/queues.py | 25 ++++++++-- .../test_process_pool.py | 29 +++++++++++ ...-09-25-02-11-14.gh-issue-109047.b1TrqG.rst | 4 ++ 4 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-25-02-11-14.gh-issue-109047.b1TrqG.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 33df65a3081fa7..8359a4fce6520d 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -341,7 +341,14 @@ def run(self): # Main loop for the executor manager thread. while True: - self.add_call_item_to_queue() + # gh-109047: During Python finalization, self.call_queue.put() + # creation of a thread can fail with RuntimeError. + try: + self.add_call_item_to_queue() + except BaseException as exc: + cause = format_exception(exc) + self.terminate_broken(cause) + return result_item, is_broken, cause = self.wait_result_broken_or_wakeup() @@ -425,8 +432,8 @@ def wait_result_broken_or_wakeup(self): try: result_item = result_reader.recv() is_broken = False - except BaseException as e: - cause = format_exception(type(e), e, e.__traceback__) + except BaseException as exc: + cause = format_exception(exc) elif wakeup_reader in ready: is_broken = False @@ -473,7 +480,7 @@ def is_shutting_down(self): return (_global_shutdown or executor is None or executor._shutdown_thread) - def terminate_broken(self, cause): + def _terminate_broken(self, cause): # Terminate the executor because it is in a broken state. The cause # argument can be used to display more information on the error that # lead the executor into becoming broken. @@ -498,7 +505,14 @@ def terminate_broken(self, cause): # Mark pending tasks as failed. for work_id, work_item in self.pending_work_items.items(): - work_item.future.set_exception(bpe) + try: + work_item.future.set_exception(bpe) + except _base.InvalidStateError: + # set_exception() fails if the future is cancelled: ignore it. + # Trying to check if the future is cancelled before calling + # set_exception() would leave a race condition if the future is + # cancelled between the check and set_exception(). + pass # Delete references to object. See issue16284 del work_item self.pending_work_items.clear() @@ -508,16 +522,18 @@ def terminate_broken(self, cause): for p in self.processes.values(): p.terminate() - # Prevent queue writing to a pipe which is no longer read. - # https://github.com/python/cpython/issues/94777 - self.call_queue._reader.close() + self.call_queue._terminate_broken() # gh-107219: Close the connection writer which can unblock # Queue._feed() if it was stuck in send_bytes(). self.call_queue._writer.close() # clean up resources - self.join_executor_internals() + self._join_executor_internals(broken=True) + + def terminate_broken(self, cause): + with self.shutdown_lock: + self._terminate_broken(cause) def flag_executor_shutting_down(self): # Flag the executor as shutting down and cancel remaining tasks if @@ -560,15 +576,24 @@ def shutdown_workers(self): break def join_executor_internals(self): - self.shutdown_workers() + with self.shutdown_lock: + self._join_executor_internals() + + def _join_executor_internals(self, broken=False): + # If broken, call_queue was closed and so can no longer be used. + if not broken: + self.shutdown_workers() + # Release the queue's resources as soon as possible. self.call_queue.close() self.call_queue.join_thread() - with self.shutdown_lock: - self.thread_wakeup.close() + self.thread_wakeup.close() + # If .join() is not called on the created processes then # some ctx.Queue methods may deadlock on Mac OS X. for p in self.processes.values(): + if broken: + p.terminate() p.join() def get_n_children_alive(self): diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py index daf9ee94a19431..d36de75749f4ed 100644 --- a/Lib/multiprocessing/queues.py +++ b/Lib/multiprocessing/queues.py @@ -158,6 +158,15 @@ def cancel_join_thread(self): except AttributeError: pass + def _terminate_broken(self): + # Close a Queue on error. + + # gh-94777: Prevent queue writing to a pipe which is no longer read. + self._reader.close() + + self.close() + self.join_thread() + def _start_thread(self): debug('Queue._start_thread()') @@ -169,13 +178,19 @@ def _start_thread(self): self._wlock, self._reader.close, self._writer.close, self._ignore_epipe, self._on_queue_feeder_error, self._sem), - name='QueueFeederThread' + name='QueueFeederThread', + daemon=True, ) - self._thread.daemon = True - debug('doing self._thread.start()') - self._thread.start() - debug('... done self._thread.start()') + try: + debug('doing self._thread.start()') + self._thread.start() + debug('... done self._thread.start()') + except: + # gh-109047: During Python finalization, creating a thread + # can fail with RuntimeError. + self._thread = None + raise if not self._joincancelled: self._jointhread = Finalize( diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index 7763a4946f110c..c73c2da1a01088 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -1,5 +1,6 @@ import os import sys +import threading import time import unittest from concurrent import futures @@ -187,6 +188,34 @@ def test_max_tasks_early_shutdown(self): for i, future in enumerate(futures): self.assertEqual(future.result(), mul(i, i)) + def test_python_finalization_error(self): + # gh-109047: Catch RuntimeError on thread creation + # during Python finalization. + + context = self.get_context() + + # gh-109047: Mock the threading.start_new_thread() function to inject + # RuntimeError: simulate the error raised during Python finalization. + # Block the second creation: create _ExecutorManagerThread, but block + # QueueFeederThread. + orig_start_new_thread = threading._start_new_thread + nthread = 0 + def mock_start_new_thread(func, *args): + nonlocal nthread + if nthread >= 1: + raise RuntimeError("can't create new thread at " + "interpreter shutdown") + nthread += 1 + return orig_start_new_thread(func, *args) + + with support.swap_attr(threading, '_start_new_thread', + mock_start_new_thread): + executor = self.executor_type(max_workers=2, mp_context=context) + with executor: + with self.assertRaises(BrokenProcessPool): + list(executor.map(mul, [(2, 3)] * 10)) + executor.shutdown() + create_executor_tests(globals(), ProcessPoolExecutorTest, executor_mixins=(ProcessPoolForkMixin, diff --git a/Misc/NEWS.d/next/Library/2023-09-25-02-11-14.gh-issue-109047.b1TrqG.rst b/Misc/NEWS.d/next/Library/2023-09-25-02-11-14.gh-issue-109047.b1TrqG.rst new file mode 100644 index 00000000000000..71cb5a80847d0a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-25-02-11-14.gh-issue-109047.b1TrqG.rst @@ -0,0 +1,4 @@ +:mod:`concurrent.futures`: The *executor manager thread* now catches exceptions +when adding an item to the *call queue*. During Python finalization, creating a +new thread can now raise :exc:`RuntimeError`. Catch the exception and call +``terminate_broken()`` in this case. Patch by Victor Stinner. From b8a30a4365d243604d5853ce524075c7e7ed0951 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:47:28 -0700 Subject: [PATCH 0900/1206] [3.12] Add example for linear_regression() with proportional=True. (gh-110133) (#110134) Add example for linear_regression() with proportional=True. (gh-110133) (cherry picked from commit 613c0d4e866341e15a66704643a6392ce49058ba) Co-authored-by: Raymond Hettinger --- Doc/library/statistics.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index 6e6ca7cef3391f..318e5d74611426 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -14,6 +14,7 @@ .. testsetup:: * from statistics import * + import math __name__ = '' -------------- @@ -741,6 +742,24 @@ However, for reading convenience, most of the examples show sorted sequences. *y = slope \* x + noise* + Continuing the example from :func:`correlation`, we look to see + how well a model based on major planets can predict the orbital + distances for dwarf planets: + + .. doctest:: + + >>> model = linear_regression(period_squared, dist_cubed, proportional=True) + >>> slope = model.slope + + >>> # Dwarf planets: Pluto, Eris, Makemake, Haumea, Ceres + >>> orbital_periods = [90_560, 204_199, 111_845, 103_410, 1_680] # days + >>> predicted_dist = [math.cbrt(slope * (p * p)) for p in orbital_periods] + >>> list(map(round, predicted_dist)) + [5912, 10166, 6806, 6459, 414] + + >>> [5_906, 10_152, 6_796, 6_450, 414] # actual distance in million km + [5906, 10152, 6796, 6450, 414] + .. versionadded:: 3.10 .. versionchanged:: 3.11 From ce332aa8c5c2d3a086cabb3f21d2da3a96e78680 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:47:41 -0700 Subject: [PATCH 0901/1206] [3.12] gh-110088: Fix asyncio test_prompt_cancellation() (GH-110157) (#110158) gh-110088: Fix asyncio test_prompt_cancellation() (GH-110157) Don't measure the CI performance: don't test the maximum elapsed time. The check failed on a slow CI. (cherry picked from commit c62b49ecc8da13fa9522865ef6fe0aec194fd0d8) Co-authored-by: Victor Stinner --- Lib/test/test_asyncio/test_events.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 1647d2308c4e35..8839d5b0995d68 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1693,12 +1693,9 @@ async def main(): self.loop.stop() return res - start = time.monotonic() t = self.loop.create_task(main()) self.loop.run_forever() - elapsed = time.monotonic() - start - self.assertLess(elapsed, 0.1) self.assertEqual(t.result(), 'cancelled') self.assertRaises(asyncio.CancelledError, f.result) if ov is not None: From 5245b97e132ae071e2b574224e0788cab62fdcc9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:47:57 +0200 Subject: [PATCH 0902/1206] [3.12] gh-109649: Enhance os.cpu_count() documentation (#110169) * gh-109649: Enhance os.cpu_count() documentation * Doc: Specify that os.cpu_count() counts *logicial* CPUs. * Doc: Specify that os.sched_getaffinity(0) is related to the calling thread. * Fix test_posix.test_sched_getaffinity(): restore the old CPU mask when the test completes! * Restore removed text --- Doc/library/os.rst | 16 +++++++++------- Lib/test/test_posix.py | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 4ffd520f9ecd8b..0c36c244ab53db 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -5141,8 +5141,10 @@ operating system. .. function:: sched_getaffinity(pid, /) - Return the set of CPUs the process with PID *pid* (or the current process - if zero) is restricted to. + Return the set of CPUs the process with PID *pid* is restricted to. + + If *pid* is zero, return the set of CPUs the calling thread of the current + process is restricted to. .. _os-path: @@ -5183,12 +5185,12 @@ Miscellaneous System Information .. function:: cpu_count() - Return the number of CPUs in the system. Returns ``None`` if undetermined. - - This number is not equivalent to the number of CPUs the current process can - use. The number of usable CPUs can be obtained with - ``len(os.sched_getaffinity(0))`` + Return the number of logical CPUs in the system. Returns ``None`` if + undetermined. + This number is not equivalent to the number of logical CPUs the current + process can use. ``len(os.sched_getaffinity(0))`` gets the number of logical + CPUs the calling thread of the current process is restricted to .. versionadded:: 3.4 diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 444f8abe4607b7..9d72dba159c6be 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1205,6 +1205,7 @@ def test_sched_getaffinity(self): @requires_sched_affinity def test_sched_setaffinity(self): mask = posix.sched_getaffinity(0) + self.addCleanup(posix.sched_setaffinity, 0, list(mask)) if len(mask) > 1: # Empty masks are forbidden mask.pop() From 10af2242f436ba5996c2c866108de803e7f4ca62 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:48:17 -0700 Subject: [PATCH 0903/1206] [3.12] gh-110160: Fix flaky `test_find_periodic_pattern` in `string_tests` (GH-110170) (#110182) gh-110160: Fix flaky `test_find_periodic_pattern` in `string_tests` (GH-110170) (cherry picked from commit 06faa9a39bd93c5e7999d52b52043ecdd0774dac) Co-authored-by: Nikita Sobolev --- Lib/test/string_tests.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 709cac7a27a449..408b19338b55b5 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -327,11 +327,12 @@ def reference_find(p, s): for i in range(len(s)): if s.startswith(p, i): return i + if p == '' and s == '': + return 0 return -1 - rr = random.randrange - choices = random.choices - for _ in range(1000): + def check_pattern(rr): + choices = random.choices p0 = ''.join(choices('abcde', k=rr(10))) * rr(10, 20) p = p0[:len(p0) - rr(10)] # pop off some characters left = ''.join(choices('abcdef', k=rr(2000))) @@ -341,6 +342,13 @@ def reference_find(p, s): self.checkequal(reference_find(p, text), text, 'find', p) + rr = random.randrange + for _ in range(1000): + check_pattern(rr) + + # Test that empty string always work: + check_pattern(lambda *args: 0) + def test_find_many_lengths(self): haystack_repeats = [a * 10**e for e in range(6) for a in (1,2,5)] haystacks = [(n, self.fixtype("abcab"*n + "da")) for n in haystack_repeats] From b61a4da459b65c7c925d395944aaa9b4be1254a5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:48:30 -0700 Subject: [PATCH 0904/1206] [3.12] gh-109590: Update shutil.which on Windows to prefer a PATHEXT extension on executable files (GH-109995) (#110202) gh-109590: Update shutil.which on Windows to prefer a PATHEXT extension on executable files (GH-109995) The default arguments for shutil.which() request an executable file, but extensionless files are not executable on Windows and should be ignored. (cherry picked from commit 29b875bb93099171aeb7a60cd18d4e1f4ea3c1db) Co-authored-by: Charles Machalow --- Doc/library/shutil.rst | 6 ++ Lib/shutil.py | 12 ++- Lib/test/test_shutil.py | 82 ++++++++++++++++--- ...-09-24-06-04-14.gh-issue-109590.9EMofC.rst | 3 + 4 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-24-06-04-14.gh-issue-109590.9EMofC.rst diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 4390a8e22306fa..d1949d698f5614 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -476,6 +476,12 @@ Directory and files operations or ends with an extension that is in ``PATHEXT``; and filenames that have no extension can now be found. + .. versionchanged:: 3.12.1 + On Windows, if *mode* includes ``os.X_OK``, executables with an + extension in ``PATHEXT`` will be preferred over executables without a + matching extension. + This brings behavior closer to that of Python 3.11. + .. exception:: Error This exception collects exceptions that are raised during a multi-file diff --git a/Lib/shutil.py b/Lib/shutil.py index b37bd082eee0c6..5bcfa563fea9af 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1554,8 +1554,16 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): if use_bytes: pathext = [os.fsencode(ext) for ext in pathext] - # Always try checking the originally given cmd, if it doesn't match, try pathext - files = [cmd] + [cmd + ext for ext in pathext] + files = ([cmd] + [cmd + ext for ext in pathext]) + + # gh-109590. If we are looking for an executable, we need to look + # for a PATHEXT match. The first cmd is the direct match + # (e.g. python.exe instead of python) + # Check that direct match first if and only if the extension is in PATHEXT + # Otherwise check it last + suffix = os.path.splitext(files[0])[1].upper() + if mode & os.X_OK and not any(suffix == ext.upper() for ext in pathext): + files.append(files.pop(0)) else: # On other platforms you don't have things like PATHEXT to tell you # what file suffixes are executable, so just pass on cmd as-is. diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index cd1c3d8cfbc388..e96a5313b438ce 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2068,6 +2068,14 @@ def setUp(self): self.curdir = os.curdir self.ext = ".EXE" + def to_text_type(self, s): + ''' + In this class we're testing with str, so convert s to a str + ''' + if isinstance(s, bytes): + return s.decode() + return s + def test_basic(self): # Given an EXE in a directory, it should be returned. rv = shutil.which(self.file, path=self.dir) @@ -2255,9 +2263,9 @@ def test_empty_path_no_PATH(self): @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') def test_pathext(self): - ext = ".xyz" + ext = self.to_text_type(".xyz") temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir, - prefix="Tmp2", suffix=ext) + prefix=self.to_text_type("Tmp2"), suffix=ext) os.chmod(temp_filexyz.name, stat.S_IXUSR) self.addCleanup(temp_filexyz.close) @@ -2266,16 +2274,16 @@ def test_pathext(self): program = os.path.splitext(program)[0] with os_helper.EnvironmentVarGuard() as env: - env['PATHEXT'] = ext + env['PATHEXT'] = ext if isinstance(ext, str) else ext.decode() rv = shutil.which(program, path=self.temp_dir) self.assertEqual(rv, temp_filexyz.name) # Issue 40592: See https://bugs.python.org/issue40592 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') def test_pathext_with_empty_str(self): - ext = ".xyz" + ext = self.to_text_type(".xyz") temp_filexyz = tempfile.NamedTemporaryFile(dir=self.temp_dir, - prefix="Tmp2", suffix=ext) + prefix=self.to_text_type("Tmp2"), suffix=ext) self.addCleanup(temp_filexyz.close) # strip path and extension @@ -2283,7 +2291,7 @@ def test_pathext_with_empty_str(self): program = os.path.splitext(program)[0] with os_helper.EnvironmentVarGuard() as env: - env['PATHEXT'] = f"{ext};" # note the ; + env['PATHEXT'] = f"{ext if isinstance(ext, str) else ext.decode()};" # note the ; rv = shutil.which(program, path=self.temp_dir) self.assertEqual(rv, temp_filexyz.name) @@ -2291,13 +2299,14 @@ def test_pathext_with_empty_str(self): @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') def test_pathext_applied_on_files_in_path(self): with os_helper.EnvironmentVarGuard() as env: - env["PATH"] = self.temp_dir + env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode() env["PATHEXT"] = ".test" - test_path = pathlib.Path(self.temp_dir) / "test_program.test" - test_path.touch(mode=0o755) + test_path = os.path.join(self.temp_dir, self.to_text_type("test_program.test")) + open(test_path, 'w').close() + os.chmod(test_path, 0o755) - self.assertEqual(shutil.which("test_program"), str(test_path)) + self.assertEqual(shutil.which(self.to_text_type("test_program")), test_path) # See GH-75586 @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') @@ -2313,6 +2322,50 @@ def test_win_path_needs_curdir(self): self.assertFalse(shutil._win_path_needs_curdir('dontcare', os.X_OK)) need_curdir_mock.assert_called_once_with('dontcare') + # See GH-109590 + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_preferred_for_execute(self): + with os_helper.EnvironmentVarGuard() as env: + env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode() + env["PATHEXT"] = ".test" + + exe = os.path.join(self.temp_dir, self.to_text_type("test.exe")) + open(exe, 'w').close() + os.chmod(exe, 0o755) + + # default behavior allows a direct match if nothing in PATHEXT matches + self.assertEqual(shutil.which(self.to_text_type("test.exe")), exe) + + dot_test = os.path.join(self.temp_dir, self.to_text_type("test.exe.test")) + open(dot_test, 'w').close() + os.chmod(dot_test, 0o755) + + # now we have a PATHEXT match, so it take precedence + self.assertEqual(shutil.which(self.to_text_type("test.exe")), dot_test) + + # but if we don't use os.X_OK we don't change the order based off PATHEXT + # and therefore get the direct match. + self.assertEqual(shutil.which(self.to_text_type("test.exe"), mode=os.F_OK), exe) + + # See GH-109590 + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_given_extension_preferred(self): + with os_helper.EnvironmentVarGuard() as env: + env["PATH"] = self.temp_dir if isinstance(self.temp_dir, str) else self.temp_dir.decode() + env["PATHEXT"] = ".exe2;.exe" + + exe = os.path.join(self.temp_dir, self.to_text_type("test.exe")) + open(exe, 'w').close() + os.chmod(exe, 0o755) + + exe2 = os.path.join(self.temp_dir, self.to_text_type("test.exe2")) + open(exe2, 'w').close() + os.chmod(exe2, 0o755) + + # even though .exe2 is preferred in PATHEXT, we matched directly to test.exe + self.assertEqual(shutil.which(self.to_text_type("test.exe")), exe) + self.assertEqual(shutil.which(self.to_text_type("test")), exe2) + class TestWhichBytes(TestWhich): def setUp(self): @@ -2320,9 +2373,18 @@ def setUp(self): self.dir = os.fsencode(self.dir) self.file = os.fsencode(self.file) self.temp_file.name = os.fsencode(self.temp_file.name) + self.temp_dir = os.fsencode(self.temp_dir) self.curdir = os.fsencode(self.curdir) self.ext = os.fsencode(self.ext) + def to_text_type(self, s): + ''' + In this class we're testing with bytes, so convert s to a bytes + ''' + if isinstance(s, str): + return s.encode() + return s + class TestMove(BaseTest, unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-09-24-06-04-14.gh-issue-109590.9EMofC.rst b/Misc/NEWS.d/next/Library/2023-09-24-06-04-14.gh-issue-109590.9EMofC.rst new file mode 100644 index 00000000000000..647e84e71b42d2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-24-06-04-14.gh-issue-109590.9EMofC.rst @@ -0,0 +1,3 @@ +:func:`shutil.which` will prefer files with an extension in ``PATHEXT`` if the given mode includes ``os.X_OK`` on win32. +If no ``PATHEXT`` match is found, a file without an extension in ``PATHEXT`` can be returned. +This change will have :func:`shutil.which` act more similarly to previous behavior in Python 3.11. From f911d7ecd99c4f0b67131b24b286a569c54c9655 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 17:48:42 +0200 Subject: [PATCH 0905/1206] =?UTF-8?q?[3.12]=20gh-108963:=20using=20random?= =?UTF-8?q?=20to=20generate=20unique=20string=20in=20sys.intern=20test=20?= =?UTF-8?q?=E2=80=A6=20(#110216)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-108963: using random to generate unique string in sys.intern test (#109491) (cherry picked from commit 44b1e4ea4842c6cdc1bedba7aaeb93f236b3ec08) Co-authored-by: AN Long --- Lib/test/test_sys.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index c3e9f9c406815f..0b8529a9b6abd0 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -4,6 +4,7 @@ import locale import operator import os +import random import struct import subprocess import sys @@ -19,10 +20,6 @@ import warnings -# count the number of test runs, used to create unique -# strings to intern in test_intern() -INTERN_NUMRUNS = 0 - DICT_KEY_STRUCT_FORMAT = 'n2BI2n' class DisplayHookTest(unittest.TestCase): @@ -685,10 +682,8 @@ def test_43581(self): self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding) def test_intern(self): - global INTERN_NUMRUNS - INTERN_NUMRUNS += 1 self.assertRaises(TypeError, sys.intern) - s = "never interned before" + str(INTERN_NUMRUNS) + s = "never interned before" + str(random.randrange(0, 10**9)) self.assertTrue(sys.intern(s) is s) s2 = s.swapcase().swapcase() self.assertTrue(sys.intern(s2) is s) From 8296b53027b15e688f028f4d7c44f3d76d283416 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 08:48:57 -0700 Subject: [PATCH 0906/1206] [3.12] 3.12 What's New: Remove duplicate "up to" (GH-110219) (#110220) 3.12 What's New: Remove duplicate "up to" (GH-110219) (cherry picked from commit 8d92b6eff3bac45e7d4871c46c4511218b9b685a) Co-authored-by: numbermaniac <5206120+numbermaniac@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index fad94d6d78616a..f63664d1239b62 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -121,7 +121,7 @@ Significant improvements in the standard library: * A :ref:`command-line interface ` has been added to the :mod:`uuid` module * Due to the changes in :ref:`PEP 701 `, - producing tokens via the :mod:`tokenize` module is up to up to 64% faster. + producing tokens via the :mod:`tokenize` module is up to 64% faster. Security improvements: From 46e69576a96e200ed8e6c94c43864b3dc17f30a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 10:15:30 -0700 Subject: [PATCH 0907/1206] [3.12] gh-110178: Use fewer weakrefs in test_typing.py (GH-110194) (#110224) gh-110178: Use fewer weakrefs in test_typing.py (GH-110194) Confirmed that without the C changes from GH-108517, this test still segfaults with only 10 weakrefs. (cherry picked from commit 732ad44cec971be5255b1accbac6555d3615c2bf) Co-authored-by: Jelle Zijlstra --- Lib/test/test_typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index eb7617737b8c1d..83f25402d8793b 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -550,7 +550,7 @@ def test_many_weakrefs(self): with self.subTest(cls=cls): vals = weakref.WeakValueDictionary() - for x in range(100000): + for x in range(10): vals[x] = cls(str(x)) del vals From 196738fc8693f3e1059c7872fbbc5578adc33f65 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 10:31:34 -0700 Subject: [PATCH 0908/1206] [3.12] Code: Update Donghee Na's name (GH-109744) (#110225) Co-authored-by: Hugo van Kemenade --- Tools/unicode/genmap_japanese.py | 2 +- Tools/unicode/genmap_korean.py | 2 +- Tools/unicode/genmap_schinese.py | 2 +- Tools/unicode/genmap_support.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tools/unicode/genmap_japanese.py b/Tools/unicode/genmap_japanese.py index 21de37b62bced0..838317fa54175e 100644 --- a/Tools/unicode/genmap_japanese.py +++ b/Tools/unicode/genmap_japanese.py @@ -2,7 +2,7 @@ # genmap_ja_codecs.py: Japanese Codecs Map Generator # # Original Author: Hye-Shik Chang -# Modified Author: Dong-hee Na +# Modified Author: Donghee Na # import os diff --git a/Tools/unicode/genmap_korean.py b/Tools/unicode/genmap_korean.py index 4b94a6c43e5382..4432a3601b7e3b 100644 --- a/Tools/unicode/genmap_korean.py +++ b/Tools/unicode/genmap_korean.py @@ -2,7 +2,7 @@ # genmap_korean.py: Korean Codecs Map Generator # # Original Author: Hye-Shik Chang -# Modified Author: Dong-hee Na +# Modified Author: Donghee Na # import os diff --git a/Tools/unicode/genmap_schinese.py b/Tools/unicode/genmap_schinese.py index 647c0333ed2728..862f1def71d122 100644 --- a/Tools/unicode/genmap_schinese.py +++ b/Tools/unicode/genmap_schinese.py @@ -2,7 +2,7 @@ # genmap_schinese.py: Simplified Chinese Codecs Map Generator # # Original Author: Hye-Shik Chang -# Modified Author: Dong-hee Na +# Modified Author: Donghee Na # import os import re diff --git a/Tools/unicode/genmap_support.py b/Tools/unicode/genmap_support.py index 5e1d9ee77b0002..4649bc3b7125fe 100644 --- a/Tools/unicode/genmap_support.py +++ b/Tools/unicode/genmap_support.py @@ -2,7 +2,7 @@ # genmap_support.py: Multibyte Codec Map Generator # # Original Author: Hye-Shik Chang -# Modified Author: Dong-hee Na +# Modified Author: Donghee Na # From 25bf0564c4317ac69df40e7fc360568c526dbc6d Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 2 Oct 2023 18:34:49 +0100 Subject: [PATCH 0909/1206] [3.12] Fix typos in docs and comments (#109619) (#109621) Fix typos in docs and comments (#109619) Co-authored-by: Heinz-Alexander Fuetterer <35225576+afuetterer@users.noreply.github.com> --- Doc/c-api/exceptions.rst | 2 +- Doc/library/typing.rst | 2 +- Doc/whatsnew/3.12.rst | 2 +- Doc/whatsnew/3.5.rst | 2 +- Lib/test/test_descr.py | 2 +- Lib/test/test_dynamic.py | 2 +- Lib/test/test_frame.py | 2 +- Lib/test/test_unpack.py | 2 +- Objects/object_layout.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 6e2ac0a40a5f1b..2139da051e0193 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -786,7 +786,7 @@ Exception Objects Implement part of the interpreter's implementation of :keyword:`!except*`. *orig* is the original exception that was caught, and *excs* is the list of - the exceptions that need to be raised. This list contains the the unhandled + the exceptions that need to be raised. This list contains the unhandled part of *orig*, if any, as well as the exceptions that were raised from the :keyword:`!except*` clauses (so they have a different traceback from *orig*) and those that were reraised (and have the same traceback as *orig*). diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index f36dc76c3232f7..eb14d11604ae1d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1291,7 +1291,7 @@ These can be used as types in annotations. They all support subscription using completely disables typechecking for a function or class. The responsibility of how to interpret the metadata - lies with the the tool or library encountering an + lies with the tool or library encountering an ``Annotated`` annotation. A tool or library encountering an ``Annotated`` type can scan through the metadata elements to determine if they are of interest (e.g., using :func:`isinstance`). diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f63664d1239b62..f9cc94514f2cad 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -354,7 +354,7 @@ create an interpreter with its own GIL:: if (PyStatus_Exception(status)) { return -1; } - /* The new interpeter is now active in the current thread. */ + /* The new interpreter is now active in the current thread. */ For further examples how to use the C-API for sub-interpreters with a per-interpreter GIL, see :source:`Modules/_xxsubinterpretersmodule.c`. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 3c0d8d665c3949..108e5293bc4b1c 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -921,7 +921,7 @@ and improves their substitutability for lists. Docstrings produced by :func:`~collections.namedtuple` can now be updated:: Point = namedtuple('Point', ['x', 'y']) - Point.__doc__ += ': Cartesian coodinate' + Point.__doc__ += ': Cartesian coordinate' Point.x.__doc__ = 'abscissa' Point.y.__doc__ = 'ordinate' diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 9d8b1497330f0a..bf4b8f9572df4c 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1989,7 +1989,7 @@ def __getattr__(self, attr): ns = {} exec(code, ns) number_attrs = ns["number_attrs"] - # Warm up the the function for quickening (PEP 659) + # Warm up the function for quickening (PEP 659) for _ in range(30): self.assertEqual(number_attrs(Numbers()), list(range(280))) diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py index 7e12d428e0fde2..0aa3be6a1bde6a 100644 --- a/Lib/test/test_dynamic.py +++ b/Lib/test/test_dynamic.py @@ -145,7 +145,7 @@ def __missing__(self, key): code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables)) sum_func = eval(code, MyGlobals()) expected = sum(range(variables)) - # Warm up the the function for quickening (PEP 659) + # Warm up the function for quickening (PEP 659) for _ in range(30): self.assertEqual(sum_func(), expected) diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index 6bb0144e9b1ed7..9491c7facdf077 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -322,7 +322,7 @@ def f(): sneaky_frame_object = None gc.enable() next(g) - # g.gi_frame should be the the frame object from the callback (the + # g.gi_frame should be the frame object from the callback (the # one that was *requested* second, but *created* first): self.assertIs(g.gi_frame, sneaky_frame_object) finally: diff --git a/Lib/test/test_unpack.py b/Lib/test/test_unpack.py index f5ca1d455b5c6f..515ec128a08a9c 100644 --- a/Lib/test/test_unpack.py +++ b/Lib/test/test_unpack.py @@ -162,7 +162,7 @@ def test_extended_oparg_not_ignored(self): ns = {} exec(code, ns) unpack_400 = ns["unpack_400"] - # Warm up the the function for quickening (PEP 659) + # Warm up the function for quickening (PEP 659) for _ in range(30): y = unpack_400(range(400)) self.assertEqual(y, 399) diff --git a/Objects/object_layout.md b/Objects/object_layout.md index 9380b57938c8e3..82483022a01442 100644 --- a/Objects/object_layout.md +++ b/Objects/object_layout.md @@ -36,7 +36,7 @@ and the ``dict`` field points to the dictionary. ## 3.12 pre-header -In 3.12 the the pointer to the list of weak references is added to the +In 3.12 the pointer to the list of weak references is added to the pre-header. In order to make space for it, the ``dict`` and ``values`` pointers are combined into a single tagged pointer: From 221c8d64e672ff50affbb10cacc81d0586752eef Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Mon, 2 Oct 2023 14:19:46 -0500 Subject: [PATCH 0910/1206] [3.12] Sync factor() recipe with main branch (gh-110231) --- Doc/library/itertools.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 8a1c83aa3a2804..5846d784c88ccc 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1119,9 +1119,7 @@ The following recipes have a more mathematical flavor: # factor(1_000_000_000_000_007) --> 47 59 360620266859 # factor(1_000_000_000_000_403) --> 1000000000000403 for prime in sieve(math.isqrt(n) + 1): - while True: - if n % prime: - break + while not n % prime: yield prime n //= prime if n == 1: From da75bd6c31ca8fbbee494a9a4fc320d8b6db0552 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 2 Oct 2023 20:25:06 +0100 Subject: [PATCH 0911/1206] [3.12] gh-109782: Ensure `os.path.isdir` has the same signature on all platforms (GH-109790) (#110233) gh-109782: Ensure `os.path.isdir` has the same signature on all platforms (GH-109790) Co-authored-by: Amin Alaee --- ...023-09-24-16-43-33.gh-issue-109782.gMC_7z.rst | 2 ++ Modules/clinic/posixmodule.c.h | 16 ++++++++-------- Modules/posixmodule.c | 10 +++++----- 3 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-24-16-43-33.gh-issue-109782.gMC_7z.rst diff --git a/Misc/NEWS.d/next/Library/2023-09-24-16-43-33.gh-issue-109782.gMC_7z.rst b/Misc/NEWS.d/next/Library/2023-09-24-16-43-33.gh-issue-109782.gMC_7z.rst new file mode 100644 index 00000000000000..7612e59dc45412 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-24-16-43-33.gh-issue-109782.gMC_7z.rst @@ -0,0 +1,2 @@ +Ensure the signature of :func:`os.path.isdir` is identical on all platforms. +Patch by Amin Alaee. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 5924c4ab03943a..fb01c8dbc8d81c 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1975,7 +1975,7 @@ os__path_splitroot(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #if defined(MS_WINDOWS) PyDoc_STRVAR(os__path_isdir__doc__, -"_path_isdir($module, /, path)\n" +"_path_isdir($module, /, s)\n" "--\n" "\n" "Return true if the pathname refers to an existing directory."); @@ -1984,7 +1984,7 @@ PyDoc_STRVAR(os__path_isdir__doc__, {"_path_isdir", _PyCFunction_CAST(os__path_isdir), METH_FASTCALL|METH_KEYWORDS, os__path_isdir__doc__}, static PyObject * -os__path_isdir_impl(PyObject *module, PyObject *path); +os__path_isdir_impl(PyObject *module, PyObject *s); static PyObject * os__path_isdir(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -1999,7 +1999,7 @@ os__path_isdir(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(path), }, + .ob_item = { &_Py_ID(s), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2008,7 +2008,7 @@ os__path_isdir(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"path", NULL}; + static const char * const _keywords[] = {"s", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "_path_isdir", @@ -2016,14 +2016,14 @@ os__path_isdir(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *path; + PyObject *s; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } - path = args[0]; - return_value = os__path_isdir_impl(module, path); + s = args[0]; + return_value = os__path_isdir_impl(module, s); exit: return return_value; @@ -11999,4 +11999,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=6646be70849f971f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ce77253f8879f36e input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 816601da488d62..b33293992f0d8e 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4901,25 +4901,25 @@ os__path_splitroot_impl(PyObject *module, path_t *path) /*[clinic input] os._path_isdir - path: 'O' + s: 'O' Return true if the pathname refers to an existing directory. [clinic start generated code]*/ static PyObject * -os__path_isdir_impl(PyObject *module, PyObject *path) -/*[clinic end generated code: output=00faea0af309669d input=b1d2571cf7291aaf]*/ +os__path_isdir_impl(PyObject *module, PyObject *s) +/*[clinic end generated code: output=9d87ab3c8b8a4e61 input=c17f7ef21d22d64e]*/ { HANDLE hfile; BOOL close_file = TRUE; FILE_BASIC_INFO info; - path_t _path = PATH_T_INITIALIZE("isdir", "path", 0, 1); + path_t _path = PATH_T_INITIALIZE("isdir", "s", 0, 1); int result; BOOL slow_path = TRUE; FILE_STAT_BASIC_INFORMATION statInfo; - if (!path_converter(path, &_path)) { + if (!path_converter(s, &_path)) { path_cleanup(&_path); if (PyErr_ExceptionMatches(PyExc_ValueError)) { PyErr_Clear(); From c188a13c8ed3605e57caf6aa1783833f386e1c76 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 21:31:12 +0200 Subject: [PATCH 0912/1206] [3.12] gh-110031: Skip test_threading fork tests if ASAN (#110100) (#110103) gh-110031: Skip test_threading fork tests if ASAN (#110100) Skip test_threading tests using thread+fork if Python is built with Address Sanitizer (ASAN). (cherry picked from commit 86e76ab8af9a5018acbcdcbb6285678175b1bd8a) --- Lib/test/test_threading.py | 41 +++++++++++-------- ...-09-29-14-11-30.gh-issue-110031.fQnFnc.rst | 2 + 2 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-29-14-11-30.gh-issue-110031.fQnFnc.rst diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index f3532fb2010c63..6c486bf84e0de0 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -35,6 +35,23 @@ platforms_to_skip = ('netbsd5', 'hp-ux11') +# gh-89363: Skip fork() test if Python is built with Address Sanitizer (ASAN) +# to work around a libasan race condition, dead lock in pthread_create(). +skip_if_asan_fork = support.skip_if_sanitizer( + "libasan has a pthread_create() dead lock", + address=True) + + +def skip_unless_reliable_fork(test): + if not support.has_fork_support: + return unittest.skip("requires working os.fork()")(test) + if sys.platform in platforms_to_skip: + return unittest.skip("due to known OS bug related to thread+fork")(test) + if support.check_sanitizer(address=True): + return unittest.skip("libasan has a pthread_create() dead lock related to thread+fork")(test) + return test + + def restore_default_excepthook(testcase): testcase.addCleanup(setattr, threading, 'excepthook', threading.excepthook) threading.excepthook = threading.__excepthook__ @@ -531,7 +548,7 @@ def test_daemon_param(self): t = threading.Thread(daemon=True) self.assertTrue(t.daemon) - @support.requires_fork() + @skip_unless_reliable_fork def test_dummy_thread_after_fork(self): # Issue #14308: a dummy thread in the active list doesn't mess up # the after-fork mechanism. @@ -563,11 +580,7 @@ def background_thread(evt): self.assertEqual(out, b'') self.assertEqual(err, b'') - @support.requires_fork() - # gh-89363: Skip multiprocessing tests if Python is built with ASAN to - # work around a libasan race condition: dead lock in pthread_create(). - @support.skip_if_sanitizer("libasan has a pthread_create() dead lock", - address=True) + @skip_unless_reliable_fork def test_is_alive_after_fork(self): # Try hard to trigger #18418: is_alive() could sometimes be True on # threads that vanished after a fork. @@ -603,7 +616,7 @@ def f(): th.start() th.join() - @support.requires_fork() + @skip_unless_reliable_fork @unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()") def test_main_thread_after_fork(self): code = """if 1: @@ -624,8 +637,7 @@ def test_main_thread_after_fork(self): self.assertEqual(err, b"") self.assertEqual(data, "MainThread\nTrue\nTrue\n") - @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") - @support.requires_fork() + @skip_unless_reliable_fork @unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()") def test_main_thread_after_fork_from_nonmain_thread(self): code = """if 1: @@ -1072,8 +1084,7 @@ def test_1_join_on_shutdown(self): """ self._run_and_join(script) - @support.requires_fork() - @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") + @skip_unless_reliable_fork def test_2_join_in_forked_process(self): # Like the test above, but from a forked interpreter script = """if 1: @@ -1093,8 +1104,7 @@ def test_2_join_in_forked_process(self): """ self._run_and_join(script) - @support.requires_fork() - @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") + @skip_unless_reliable_fork def test_3_join_in_forked_from_thread(self): # Like the test above, but fork() was called from a worker thread # In the forked process, the main Thread object must be marked as stopped. @@ -1164,8 +1174,7 @@ def main(): rc, out, err = assert_python_ok('-c', script) self.assertFalse(err) - @support.requires_fork() - @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") + @skip_unless_reliable_fork def test_reinit_tls_after_fork(self): # Issue #13817: fork() would deadlock in a multithreaded program with # the ad-hoc TLS implementation. @@ -1191,7 +1200,7 @@ def do_fork_and_wait(): for t in threads: t.join() - @support.requires_fork() + @skip_unless_reliable_fork def test_clear_threads_states_after_fork(self): # Issue #17094: check that threads states are cleared after fork() diff --git a/Misc/NEWS.d/next/Tests/2023-09-29-14-11-30.gh-issue-110031.fQnFnc.rst b/Misc/NEWS.d/next/Tests/2023-09-29-14-11-30.gh-issue-110031.fQnFnc.rst new file mode 100644 index 00000000000000..a8a163c567d2b3 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-29-14-11-30.gh-issue-110031.fQnFnc.rst @@ -0,0 +1,2 @@ +Skip test_threading tests using thread+fork if Python is built with Address +Sanitizer (ASAN). Patch by Victor Stinner. From 0745ab88e502b56ca9a87cb6dd9cd1a23b53658a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 Oct 2023 21:35:29 +0200 Subject: [PATCH 0913/1206] [3.12] gh-110088, gh-109878: Fix test_asyncio timeouts (#110092) (#110098) gh-110088, gh-109878: Fix test_asyncio timeouts (#110092) Fix test_asyncio timeouts: don't measure the maximum duration, a test should not measure a CI performance. Only measure the minimum duration when a task has a timeout or delay. Add CLOCK_RES to test_asyncio.utils. (cherry picked from commit db0a258e796703e12befea9d6dec04e349ca2f5b) --- Lib/test/test_asyncio/test_base_events.py | 7 ++----- Lib/test/test_asyncio/test_events.py | 8 ++++---- Lib/test/test_asyncio/test_timeouts.py | 20 ------------------- Lib/test/test_asyncio/test_waitfor.py | 15 -------------- Lib/test/test_asyncio/test_windows_events.py | 13 +++--------- Lib/test/test_asyncio/utils.py | 6 ++++++ ...-09-29-12-48-42.gh-issue-110088.qUhRga.rst | 4 ++++ 7 files changed, 19 insertions(+), 54 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 3b4026cb73869a..abcb6f55c4b04e 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -273,7 +273,7 @@ def cb(): self.loop.stop() self.loop._process_events = mock.Mock() - delay = 0.1 + delay = 0.100 when = self.loop.time() + delay self.loop.call_at(when, cb) @@ -282,10 +282,7 @@ def cb(): dt = self.loop.time() - t0 # 50 ms: maximum granularity of the event loop - self.assertGreaterEqual(dt, delay - 0.050, dt) - # tolerate a difference of +800 ms because some Python buildbots - # are really slow - self.assertLessEqual(dt, 0.9, dt) + self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES) with self.assertRaises(TypeError, msg="when cannot be None"): self.loop.call_at(None, cb) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 8839d5b0995d68..ddc45fd99b1300 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -294,10 +294,11 @@ async def coro2(): # 15.6 msec, we use fairly long sleep times here (~100 msec). def test_run_until_complete(self): + delay = 0.100 t0 = self.loop.time() - self.loop.run_until_complete(asyncio.sleep(0.1)) - t1 = self.loop.time() - self.assertTrue(0.08 <= t1-t0 <= 0.8, t1-t0) + self.loop.run_until_complete(asyncio.sleep(delay)) + dt = self.loop.time() - t0 + self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES) def test_run_until_complete_stopped(self): @@ -1715,7 +1716,6 @@ def _run_once(): self.loop._run_once = _run_once async def wait(): - loop = self.loop await asyncio.sleep(1e-2) await asyncio.sleep(1e-4) await asyncio.sleep(1e-6) diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py index 8b6b9a1fea0be8..e9b59b953518b3 100644 --- a/Lib/test/test_asyncio/test_timeouts.py +++ b/Lib/test/test_asyncio/test_timeouts.py @@ -46,7 +46,6 @@ async def test_nested_timeouts(self): self.assertTrue(cm2.expired()) async def test_waiter_cancelled(self): - loop = asyncio.get_running_loop() cancelled = False with self.assertRaises(TimeoutError): async with asyncio.timeout(0.01): @@ -59,39 +58,26 @@ async def test_waiter_cancelled(self): async def test_timeout_not_called(self): loop = asyncio.get_running_loop() - t0 = loop.time() async with asyncio.timeout(10) as cm: await asyncio.sleep(0.01) t1 = loop.time() self.assertFalse(cm.expired()) - # 2 sec for slow CI boxes - self.assertLess(t1-t0, 2) self.assertGreater(cm.when(), t1) async def test_timeout_disabled(self): - loop = asyncio.get_running_loop() - t0 = loop.time() async with asyncio.timeout(None) as cm: await asyncio.sleep(0.01) - t1 = loop.time() self.assertFalse(cm.expired()) self.assertIsNone(cm.when()) - # 2 sec for slow CI boxes - self.assertLess(t1-t0, 2) async def test_timeout_at_disabled(self): - loop = asyncio.get_running_loop() - t0 = loop.time() async with asyncio.timeout_at(None) as cm: await asyncio.sleep(0.01) - t1 = loop.time() self.assertFalse(cm.expired()) self.assertIsNone(cm.when()) - # 2 sec for slow CI boxes - self.assertLess(t1-t0, 2) async def test_timeout_zero(self): loop = asyncio.get_running_loop() @@ -101,8 +87,6 @@ async def test_timeout_zero(self): await asyncio.sleep(10) t1 = loop.time() self.assertTrue(cm.expired()) - # 2 sec for slow CI boxes - self.assertLess(t1-t0, 2) self.assertTrue(t0 <= cm.when() <= t1) async def test_timeout_zero_sleep_zero(self): @@ -113,8 +97,6 @@ async def test_timeout_zero_sleep_zero(self): await asyncio.sleep(0) t1 = loop.time() self.assertTrue(cm.expired()) - # 2 sec for slow CI boxes - self.assertLess(t1-t0, 2) self.assertTrue(t0 <= cm.when() <= t1) async def test_timeout_in_the_past_sleep_zero(self): @@ -125,8 +107,6 @@ async def test_timeout_in_the_past_sleep_zero(self): await asyncio.sleep(0) t1 = loop.time() self.assertTrue(cm.expired()) - # 2 sec for slow CI boxes - self.assertLess(t1-t0, 2) self.assertTrue(t0 >= cm.when() <= t1) async def test_foreign_exception_passed(self): diff --git a/Lib/test/test_asyncio/test_waitfor.py b/Lib/test/test_asyncio/test_waitfor.py index e714b154c5cadf..d52f32534a0cfe 100644 --- a/Lib/test/test_asyncio/test_waitfor.py +++ b/Lib/test/test_asyncio/test_waitfor.py @@ -66,17 +66,12 @@ async def test_wait_for_timeout_less_then_0_or_0_future_done(self): fut = loop.create_future() fut.set_result('done') - t0 = loop.time() ret = await asyncio.wait_for(fut, 0) - t1 = loop.time() self.assertEqual(ret, 'done') self.assertTrue(fut.done()) - self.assertLess(t1 - t0, 0.1) async def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self): - loop = asyncio.get_running_loop() - foo_started = False async def foo(): @@ -84,12 +79,9 @@ async def foo(): foo_started = True with self.assertRaises(asyncio.TimeoutError): - t0 = loop.time() await asyncio.wait_for(foo(), 0) - t1 = loop.time() self.assertEqual(foo_started, False) - self.assertLess(t1 - t0, 0.1) async def test_wait_for_timeout_less_then_0_or_0(self): loop = asyncio.get_running_loop() @@ -113,18 +105,14 @@ async def foo(): await started with self.assertRaises(asyncio.TimeoutError): - t0 = loop.time() await asyncio.wait_for(fut, timeout) - t1 = loop.time() self.assertTrue(fut.done()) # it should have been cancelled due to the timeout self.assertTrue(fut.cancelled()) self.assertEqual(foo_running, False) - self.assertLess(t1 - t0, 0.1) async def test_wait_for(self): - loop = asyncio.get_running_loop() foo_running = None async def foo(): @@ -139,13 +127,10 @@ async def foo(): fut = asyncio.create_task(foo()) with self.assertRaises(asyncio.TimeoutError): - t0 = loop.time() await asyncio.wait_for(fut, 0.1) - t1 = loop.time() self.assertTrue(fut.done()) # it should have been cancelled due to the timeout self.assertTrue(fut.cancelled()) - self.assertLess(t1 - t0, support.SHORT_TIMEOUT) self.assertEqual(foo_running, False) async def test_wait_for_blocking(self): diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py index a36119a8004f9d..6e6c90a247b291 100644 --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -163,29 +163,25 @@ def test_wait_for_handle(self): # Wait for unset event with 0.5s timeout; # result should be False at timeout - fut = self.loop._proactor.wait_for_handle(event, 0.5) + timeout = 0.5 + fut = self.loop._proactor.wait_for_handle(event, timeout) start = self.loop.time() done = self.loop.run_until_complete(fut) elapsed = self.loop.time() - start self.assertEqual(done, False) self.assertFalse(fut.result()) - # bpo-31008: Tolerate only 450 ms (at least 500 ms expected), - # because of bad clock resolution on Windows - self.assertTrue(0.45 <= elapsed <= 0.9, elapsed) + self.assertGreaterEqual(elapsed, timeout - test_utils.CLOCK_RES) _overlapped.SetEvent(event) # Wait for set event; # result should be True immediately fut = self.loop._proactor.wait_for_handle(event, 10) - start = self.loop.time() done = self.loop.run_until_complete(fut) - elapsed = self.loop.time() - start self.assertEqual(done, True) self.assertTrue(fut.result()) - self.assertTrue(0 <= elapsed < 0.3, elapsed) # asyncio issue #195: cancelling a done _WaitHandleFuture # must not crash @@ -199,11 +195,8 @@ def test_wait_for_handle_cancel(self): # CancelledError should be raised immediately fut = self.loop._proactor.wait_for_handle(event, 10) fut.cancel() - start = self.loop.time() with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(fut) - elapsed = self.loop.time() - start - self.assertTrue(0 <= elapsed < 0.1, elapsed) # asyncio issue #195: cancelling a _WaitHandleFuture twice # must not crash diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 6dee5bb33b2560..870f6fcfc02d30 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -36,6 +36,12 @@ from test.support import threading_helper +# Use the maximum known clock resolution (gh-75191, gh-110088): Windows +# GetTickCount64() has a resolution of 15.6 ms. Use 20 ms to tolerate rounding +# issues. +CLOCK_RES = 0.020 + + def data_file(filename): if hasattr(support, 'TEST_HOME_DIR'): fullname = os.path.join(support.TEST_HOME_DIR, filename) diff --git a/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst b/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst new file mode 100644 index 00000000000000..cf44a123c2c925 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst @@ -0,0 +1,4 @@ +Fix test_asyncio timeouts: don't measure the maximum duration, a test should +not measure a CI performance. Only measure the minimum duration when a task has +a timeout or delay. Add ``CLOCK_RES`` to ``test_asyncio.utils``. Patch by +Victor Stinner. From 74d0b608116b269fdc47566638f79d70e3fab174 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:48:31 -0700 Subject: [PATCH 0914/1206] [3.12] gh-108494: Document how to add a project in PCbuild/readme.txt (GH-110077) (#110230) gh-108494: Document how to add a project in PCbuild/readme.txt (GH-110077) (cherry picked from commit 6387b5313c60c1403785b2245db33372476ac304) Co-authored-by: Victor Stinner --- PCbuild/readme.txt | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 5c682a28260882..cfc1979fab095f 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -293,3 +293,31 @@ project, with some projects overriding certain specific values. The GUI doesn't always reflect the correct settings and may confuse the user with false information, especially for settings that automatically adapt for different configurations. + +Add a new project +----------------- + +For example, add a new _testclinic_limited project to build a new +_testclinic_limited extension, the file Modules/_testclinic_limited.c: + +* In PCbuild/, copy _testclinic.vcxproj to _testclinic_limited.vcxproj, + replace RootNamespace value with `_testclinic_limited`, replace + `_asyncio.c` with `_testclinic_limited.c`. +* Open Visual Studio, open PCbuild\pcbuild.sln solution, add the + PCbuild\_testclinic_limited.vcxproj project to the solution ("add existing + project). +* Add a dependency on the python project to the new _testclinic_limited + project. +* Save and exit Visual Studio. +* Add `;_testclinic_limited` to `` in + PCbuild\pcbuild.proj. +* Update "exts" in Tools\msi\lib\lib_files.wxs file or in + Tools\msi\test\test_files.wxs file (for tests). +* PC\layout\main.py needs updating if you add a test-only extension whose name + doesn't start with "_test". +* Add the extension to PCbuild\readme.txt (this file). +* Build Python from scratch (clean the solution) to check that the new project + is built successfully. +* Ensure the new .vcxproj and .vcxproj.filters files are added to your commit, + as well as the changes to pcbuild.sln, pcbuild.proj and any other modified + files. From 892b1942a70cf2eb68a7582c7a9f3f91a3aeda1d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:38:25 -0700 Subject: [PATCH 0915/1206] [3.12] gh-110241: Add missing error check to `record_eval` in `_testinternalcapi` (GH-110242) (#110244) gh-110241: Add missing error check to `record_eval` in `_testinternalcapi` (GH-110242) (cherry picked from commit 4596c76d1a7650fd4650c814dc1d40d664cd8fb4) Co-authored-by: Nikita Sobolev --- Modules/_testinternalcapi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 4e063a86152931..22d156725f545c 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -683,7 +683,11 @@ record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc) assert(module != NULL); module_state *state = get_module_state(module); Py_DECREF(module); - PyList_Append(state->record_list, ((PyFunctionObject *)f->f_funcobj)->func_name); + int res = PyList_Append(state->record_list, + ((PyFunctionObject *)f->f_funcobj)->func_name); + if (res < 0) { + return NULL; + } } return _PyEval_EvalFrameDefault(tstate, f, exc); } From 41e8e1553f7e4fa97265b02e18fdc2a22b6a6611 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:31:55 -0700 Subject: [PATCH 0916/1206] [3.12] gh-109653: Reduce the import time of `random` by 60% (GH-110221) (#110247) gh-109653: Fix regression in the import time of `random` in Python 3.12 (GH-110221) (cherry picked from commit 21a6263020db17020b2886f996bc23aa8cb7fbdf) Co-authored-by: Alex Waygood --- Lib/random.py | 2 +- .../next/Library/2023-10-02-15-40-10.gh-issue-109653.iB0peK.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-02-15-40-10.gh-issue-109653.iB0peK.rst diff --git a/Lib/random.py b/Lib/random.py index 1d789b107904fb..1cfc2ba2f025b5 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -65,7 +65,7 @@ try: # hashlib is pretty heavy to load, try lean internal module first - from _sha512 import sha512 as _sha512 + from _sha2 import sha512 as _sha512 except ImportError: # fallback to official implementation from hashlib import sha512 as _sha512 diff --git a/Misc/NEWS.d/next/Library/2023-10-02-15-40-10.gh-issue-109653.iB0peK.rst b/Misc/NEWS.d/next/Library/2023-10-02-15-40-10.gh-issue-109653.iB0peK.rst new file mode 100644 index 00000000000000..54330976d71dc1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-02-15-40-10.gh-issue-109653.iB0peK.rst @@ -0,0 +1,2 @@ +Fix a Python 3.12 regression in the import time of :mod:`random`. Patch by Alex +Waygood. From b0b9b91f789047bde267b625954cf395e6043a93 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 22:36:30 -0700 Subject: [PATCH 0917/1206] [3.12] Remove unused Misc/requirements-test.txt (GH-110240) (#110253) Co-authored-by: Hugo van Kemenade --- Misc/requirements-test.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/requirements-test.txt diff --git a/Misc/requirements-test.txt b/Misc/requirements-test.txt deleted file mode 100644 index 60e7ed20a3d510..00000000000000 --- a/Misc/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -tzdata==2020.3 From 64afbf6f2815d03ea8a94b64e6e45d5990413876 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:20:20 -0700 Subject: [PATCH 0918/1206] [3.12] Fix typo in py312 whatsnew: add missing closing paren (GH-110255) (#110257) Fix typo in py312 whatsnew: add missing closing paren (GH-110255) (cherry picked from commit 8c071373f12f325c54591fe990ec026184e48f8f) Co-authored-by: Lele Gaifax --- Doc/whatsnew/3.12.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f9cc94514f2cad..9080908c5c96c0 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -303,7 +303,7 @@ Let's cover these in detail: See :pep:`701` for more details. As a positive side-effect of how this feature has been implemented (by parsing f-strings -with :pep:`the PEG parser <617>`, now error messages for f-strings are more precise +with :pep:`the PEG parser <617>`), now error messages for f-strings are more precise and include the exact location of the error. For example, in Python 3.11, the following f-string raises a :exc:`SyntaxError`: From bd56c51f1c2800d1e7167cdd65a8a28c8bfff16f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 3 Oct 2023 06:18:09 -0700 Subject: [PATCH 0919/1206] [3.12] Bump various dependencies in `Doc/requirements-oldest-sphinx.txt` (GH-110278) (#110280) Bump various dependencies in `Doc/requirements-oldest-sphinx.txt` (GH-110278) This resolves a Dependabot security alert on the repository for urllib3==2.0.4. (cherry picked from commit f1663a492e14c80c30cb9741fdc36fa221d5e30a) Co-authored-by: Alex Waygood --- Doc/requirements-oldest-sphinx.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/requirements-oldest-sphinx.txt b/Doc/requirements-oldest-sphinx.txt index d3ef5bc17650ae..5de739fc10b085 100644 --- a/Doc/requirements-oldest-sphinx.txt +++ b/Doc/requirements-oldest-sphinx.txt @@ -13,16 +13,16 @@ python-docs-theme>=2022.1 # Sphinx 4.2 comes from ``needs_sphinx = '4.2'`` in ``Doc/conf.py``. alabaster==0.7.13 -Babel==2.12.1 +Babel==2.13.0 certifi==2023.7.22 -charset-normalizer==3.2.0 +charset-normalizer==3.3.0 colorama==0.4.6 -docutils==0.16 +docutils==0.17.1 idna==3.4 imagesize==1.4.1 -Jinja2==2.11.3 -MarkupSafe==1.1.1 -packaging==23.1 +Jinja2==3.1.2 +MarkupSafe==2.1.3 +packaging==23.2 Pygments==2.16.1 requests==2.31.0 snowballstemmer==2.2.0 @@ -33,4 +33,4 @@ sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 -urllib3==2.0.4 +urllib3==2.0.6 From 4dac406f662d99ac494cae6fa7319ad623269a61 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 3 Oct 2023 16:13:22 +0100 Subject: [PATCH 0920/1206] [3.12] Enable ruff on `Lib/test/test_typing.py` (#110179) (#110288) Enable ruff on `Lib/test/test_typing.py` (#110179) --- .pre-commit-config.yaml | 2 +- Lib/test/.ruff.toml | 1 - Lib/test/test_typing.py | 104 ++++++++++++++++++++-------------------- 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c1fd20ea921b8..a5d32a04fc2d7d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.288 + rev: v0.0.292 hooks: - id: ruff name: Run Ruff on Lib/test/ diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml index 2d9c9eeae6c0c6..98da981c7be1a2 100644 --- a/Lib/test/.ruff.toml +++ b/Lib/test/.ruff.toml @@ -34,7 +34,6 @@ extend-exclude = [ "test_pkg.py", "test_subclassinit.py", "test_tokenize.py", - "test_typing.py", "test_yield_from.py", "time_hashlib.py", # Pending https://github.com/python/cpython/pull/109139 diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 83f25402d8793b..03f03fea3b04d4 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -185,7 +185,7 @@ def test_cannot_subclass(self): class A(self.bottom_type): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class A(type(self.bottom_type)): + class B(type(self.bottom_type)): pass def test_cannot_instantiate(self): @@ -282,7 +282,7 @@ class C(type(Self)): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Self'): - class C(Self): + class D(Self): pass def test_cannot_init(self): @@ -339,7 +339,7 @@ class C(type(LiteralString)): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.LiteralString'): - class C(LiteralString): + class D(LiteralString): pass def test_cannot_init(self): @@ -483,7 +483,7 @@ class V(TypeVar): pass T = TypeVar("T") with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_INSTANCE % 'TypeVar'): - class V(T): pass + class W(T): pass def test_cannot_instantiate_vars(self): with self.assertRaises(TypeError): @@ -1244,20 +1244,20 @@ class C(TypeVarTuple): pass Ts = TypeVarTuple('Ts') with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_INSTANCE % 'TypeVarTuple'): - class C(Ts): pass + class D(Ts): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(Unpack)): pass + class E(type(Unpack)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(*Ts)): pass + class F(type(*Ts)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(Unpack[Ts])): pass + class G(type(Unpack[Ts])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Unpack'): - class C(Unpack): pass + class H(Unpack): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing.Unpack\[Ts\]'): - class C(*Ts): pass + class I(*Ts): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing.Unpack\[Ts\]'): - class C(Unpack[Ts]): pass + class J(Unpack[Ts]): pass def test_variadic_class_args_are_correct(self): T = TypeVar('T') @@ -1431,12 +1431,12 @@ def test_variadic_class_with_duplicate_typevartuples_fails(self): with self.assertRaises(TypeError): class C(Generic[*Ts1, *Ts1]): pass with self.assertRaises(TypeError): - class C(Generic[Unpack[Ts1], Unpack[Ts1]]): pass + class D(Generic[Unpack[Ts1], Unpack[Ts1]]): pass with self.assertRaises(TypeError): - class C(Generic[*Ts1, *Ts2, *Ts1]): pass + class E(Generic[*Ts1, *Ts2, *Ts1]): pass with self.assertRaises(TypeError): - class C(Generic[Unpack[Ts1], Unpack[Ts2], Unpack[Ts1]]): pass + class F(Generic[Unpack[Ts1], Unpack[Ts2], Unpack[Ts1]]): pass def test_type_concatenation_in_variadic_class_argument_list_succeeds(self): Ts = TypeVarTuple('Ts') @@ -1804,11 +1804,11 @@ def test_cannot_subclass(self): class C(Union): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(Union)): + class D(type(Union)): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Union\[int, str\]'): - class C(Union[int, str]): + class E(Union[int, str]): pass def test_cannot_instantiate(self): @@ -2557,10 +2557,10 @@ class BP(Protocol): pass class P(C, Protocol): pass with self.assertRaises(TypeError): - class P(Protocol, C): + class Q(Protocol, C): pass with self.assertRaises(TypeError): - class P(BP, C, Protocol): + class R(BP, C, Protocol): pass class D(BP, C): pass @@ -2836,7 +2836,7 @@ class NotAProtocolButAnImplicitSubclass3: meth: Callable[[], None] meth2: Callable[[int, str], bool] def meth(self): pass - def meth(self, x, y): return True + def meth2(self, x, y): return True self.assertNotIsSubclass(AnnotatedButNotAProtocol, CallableMembersProto) self.assertIsSubclass(NotAProtocolButAnImplicitSubclass, CallableMembersProto) @@ -3646,11 +3646,11 @@ def test_protocols_bad_subscripts(self): with self.assertRaises(TypeError): class P(Protocol[T, T]): pass with self.assertRaises(TypeError): - class P(Protocol[int]): pass + class Q(Protocol[int]): pass with self.assertRaises(TypeError): - class P(Protocol[T], Protocol[S]): pass + class R(Protocol[T], Protocol[S]): pass with self.assertRaises(TypeError): - class P(typing.Mapping[T, S], Protocol[T]): pass + class S(typing.Mapping[T, S], Protocol[T]): pass def test_generic_protocols_repr(self): T = TypeVar('T') @@ -4029,12 +4029,12 @@ class NewGeneric(Generic): ... with self.assertRaises(TypeError): class MyGeneric(Generic[T], Generic[S]): ... with self.assertRaises(TypeError): - class MyGeneric(List[T], Generic[S]): ... + class MyGeneric2(List[T], Generic[S]): ... with self.assertRaises(TypeError): Generic[()] - class C(Generic[T]): pass + class D(Generic[T]): pass with self.assertRaises(TypeError): - C[()] + D[()] def test_init(self): T = TypeVar('T') @@ -4755,7 +4755,7 @@ class Test(Generic[T], Final): class Subclass(Test): pass with self.assertRaises(FinalException): - class Subclass(Test[int]): + class Subclass2(Test[int]): pass def test_nested(self): @@ -4993,15 +4993,15 @@ def test_cannot_subclass(self): class C(type(ClassVar)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(ClassVar[int])): + class D(type(ClassVar[int])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.ClassVar'): - class C(ClassVar): + class E(ClassVar): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.ClassVar\[int\]'): - class C(ClassVar[int]): + class F(ClassVar[int]): pass def test_cannot_init(self): @@ -5043,15 +5043,15 @@ def test_cannot_subclass(self): class C(type(Final)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(Final[int])): + class D(type(Final[int])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Final'): - class C(Final): + class E(Final): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Final\[int\]'): - class C(Final[int]): + class F(Final[int]): pass def test_cannot_init(self): @@ -7180,15 +7180,15 @@ class A: class X(NamedTuple, A): x: int with self.assertRaises(TypeError): - class X(NamedTuple, tuple): + class Y(NamedTuple, tuple): x: int with self.assertRaises(TypeError): - class X(NamedTuple, NamedTuple): + class Z(NamedTuple, NamedTuple): x: int - class A(NamedTuple): + class B(NamedTuple): x: int with self.assertRaises(TypeError): - class X(NamedTuple, A): + class C(NamedTuple, B): y: str def test_generic(self): @@ -7869,15 +7869,15 @@ def test_cannot_subclass(self): class C(type(Required)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(Required[int])): + class D(type(Required[int])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Required'): - class C(Required): + class E(Required): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Required\[int\]'): - class C(Required[int]): + class F(Required[int]): pass def test_cannot_init(self): @@ -7917,15 +7917,15 @@ def test_cannot_subclass(self): class C(type(NotRequired)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(NotRequired[int])): + class D(type(NotRequired[int])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.NotRequired'): - class C(NotRequired): + class E(NotRequired): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.NotRequired\[int\]'): - class C(NotRequired[int]): + class F(NotRequired[int]): pass def test_cannot_init(self): @@ -8045,7 +8045,7 @@ class A(typing.Match): TypeError, r"type 're\.Pattern' is not an acceptable base type", ): - class A(typing.Pattern): + class B(typing.Pattern): pass @@ -8393,7 +8393,7 @@ class C(TypeAlias): pass with self.assertRaises(TypeError): - class C(type(TypeAlias)): + class D(type(TypeAlias)): pass def test_repr(self): @@ -8783,19 +8783,19 @@ def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpec'): class C(ParamSpec): pass with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpecArgs'): - class C(ParamSpecArgs): pass + class D(ParamSpecArgs): pass with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpecKwargs'): - class C(ParamSpecKwargs): pass + class E(ParamSpecKwargs): pass P = ParamSpec('P') with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_INSTANCE % 'ParamSpec'): - class C(P): pass + class F(P): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_INSTANCE % 'ParamSpecArgs'): - class C(P.args): pass + class G(P.args): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_INSTANCE % 'ParamSpecKwargs'): - class C(P.kwargs): pass + class H(P.kwargs): pass class ConcatenateTests(BaseTestCase): @@ -8876,15 +8876,15 @@ def test_cannot_subclass(self): class C(type(TypeGuard)): pass with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): - class C(type(TypeGuard[int])): + class D(type(TypeGuard[int])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.TypeGuard'): - class C(TypeGuard): + class E(TypeGuard): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.TypeGuard\[int\]'): - class C(TypeGuard[int]): + class F(TypeGuard[int]): pass def test_cannot_init(self): From 90dea557bb0b171efd62ad4eef5b1939d5b248fd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:02:44 -0700 Subject: [PATCH 0921/1206] [3.12] gh-109234: Hint to contextlib.closing in sqlite3 context manager docs (GH-109322) (#110294) (cherry picked from commit 4227bfa8b273207a2b882f7d69c8ac49c3d2b57d) Co-authored-by: Lincoln <71312724+Lincoln-developer@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- Doc/library/sqlite3.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index d5afaa1c4c9557..43921c34232924 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -2406,9 +2406,9 @@ or if :attr:`~Connection.autocommit` is ``True``, the context manager does nothing. .. note:: - The context manager neither implicitly opens a new transaction - nor closes the connection. + nor closes the connection. If you need a closing context manager, consider + using :meth:`contextlib.closing`. .. testcode:: From 4c0f42bbc6fb9d2d0b46ecff07b995655a43c4ce Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 3 Oct 2023 18:55:29 +0100 Subject: [PATCH 0922/1206] [3.12] Docs: Avoid the deprecated ``.. cmdoption::`` directive (GH-110292) (#110302) [3.12] Docs: Avoid the deprecated ``.. cmdoption::`` directive (GH-110292). (cherry picked from commit 77e9aae3837d9f0cf87461d023896f2c4aeb282f) --- Doc/library/ast.rst | 14 ++--- Doc/library/compileall.rst | 34 +++++----- Doc/library/gzip.rst | 10 +-- Doc/library/inspect.rst | 2 +- Doc/library/json.rst | 14 ++--- Doc/library/pickletools.rst | 10 +-- Doc/library/py_compile.rst | 6 +- Doc/library/site.rst | 4 +- Doc/library/tarfile.rst | 20 +++--- Doc/library/timeit.rst | 14 ++--- Doc/library/tokenize.rst | 4 +- Doc/library/trace.rst | 30 ++++----- Doc/library/unittest.rst | 20 +++--- Doc/library/uuid.rst | 14 ++--- Doc/library/zipapp.rst | 12 ++-- Doc/library/zipfile.rst | 18 +++--- Doc/using/cmdline.rst | 60 +++++++++--------- Doc/using/configure.rst | 120 ++++++++++++++++++------------------ 18 files changed, 203 insertions(+), 203 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index a7fa8074493dec..274d831f4dda0c 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -2477,26 +2477,26 @@ The following options are accepted: .. program:: ast -.. cmdoption:: -h, --help +.. option:: -h, --help Show the help message and exit. -.. cmdoption:: -m - --mode +.. option:: -m + --mode Specify what kind of code must be compiled, like the *mode* argument in :func:`parse`. -.. cmdoption:: --no-type-comments +.. option:: --no-type-comments Don't parse type comments. -.. cmdoption:: -a, --include-attributes +.. option:: -a, --include-attributes Include attributes such as line numbers and column offsets. -.. cmdoption:: -i - --indent +.. option:: -i + --indent Indentation of nodes in AST (number of spaces). diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst index 75b97d6ff4588e..a1482c9eb889e8 100644 --- a/Doc/library/compileall.rst +++ b/Doc/library/compileall.rst @@ -24,28 +24,28 @@ compile Python sources. .. program:: compileall -.. cmdoption:: directory ... - file ... +.. option:: directory ... + file ... Positional arguments are files to compile or directories that contain source files, traversed recursively. If no argument is given, behave as if the command line was :samp:`-l {}`. -.. cmdoption:: -l +.. option:: -l Do not recurse into subdirectories, only compile source code files directly contained in the named or implied directories. -.. cmdoption:: -f +.. option:: -f Force rebuild even if timestamps are up-to-date. -.. cmdoption:: -q +.. option:: -q Do not print the list of files compiled. If passed once, error messages will still be printed. If passed twice (``-qq``), all output is suppressed. -.. cmdoption:: -d destdir +.. option:: -d destdir Directory prepended to the path to each file being compiled. This will appear in compilation time tracebacks, and is also compiled in to the @@ -53,45 +53,45 @@ compile Python sources. cases where the source file does not exist at the time the byte-code file is executed. -.. cmdoption:: -s strip_prefix -.. cmdoption:: -p prepend_prefix +.. option:: -s strip_prefix +.. option:: -p prepend_prefix Remove (``-s``) or append (``-p``) the given prefix of paths recorded in the ``.pyc`` files. Cannot be combined with ``-d``. -.. cmdoption:: -x regex +.. option:: -x regex regex is used to search the full path to each file considered for compilation, and if the regex produces a match, the file is skipped. -.. cmdoption:: -i list +.. option:: -i list Read the file ``list`` and add each line that it contains to the list of files and directories to compile. If ``list`` is ``-``, read lines from ``stdin``. -.. cmdoption:: -b +.. option:: -b Write the byte-code files to their legacy locations and names, which may overwrite byte-code files created by another version of Python. The default is to write files to their :pep:`3147` locations and names, which allows byte-code files from multiple versions of Python to coexist. -.. cmdoption:: -r +.. option:: -r Control the maximum recursion level for subdirectories. If this is given, then ``-l`` option will not be taken into account. :program:`python -m compileall -r 0` is equivalent to :program:`python -m compileall -l`. -.. cmdoption:: -j N +.. option:: -j N Use *N* workers to compile the files within the given directory. If ``0`` is used, then the result of :func:`os.cpu_count()` will be used. -.. cmdoption:: --invalidation-mode [timestamp|checked-hash|unchecked-hash] +.. option:: --invalidation-mode [timestamp|checked-hash|unchecked-hash] Control how the generated byte-code files are invalidated at runtime. The ``timestamp`` value, means that ``.pyc`` files with the source timestamp @@ -104,17 +104,17 @@ compile Python sources. variable is not set, and ``checked-hash`` if the ``SOURCE_DATE_EPOCH`` environment variable is set. -.. cmdoption:: -o level +.. option:: -o level Compile with the given optimization level. May be used multiple times to compile for multiple levels at a time (for example, ``compileall -o 1 -o 2``). -.. cmdoption:: -e dir +.. option:: -e dir Ignore symlinks pointing outside the given directory. -.. cmdoption:: --hardlink-dupes +.. option:: --hardlink-dupes If two ``.pyc`` files with different optimization level have the same content, use hard links to consolidate duplicate files. diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 60236a1190e423..7c871048b43948 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -266,23 +266,23 @@ Once executed the :mod:`gzip` module keeps the input file(s). Command line options ^^^^^^^^^^^^^^^^^^^^ -.. cmdoption:: file +.. option:: file If *file* is not specified, read from :data:`sys.stdin`. -.. cmdoption:: --fast +.. option:: --fast Indicates the fastest compression method (less compression). -.. cmdoption:: --best +.. option:: --best Indicates the slowest compression method (best compression). -.. cmdoption:: -d, --decompress +.. option:: -d, --decompress Decompress the given file. -.. cmdoption:: -h, --help +.. option:: -h, --help Show the help message. diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 603ac3263bb9ec..556cc3b5cd40c0 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1650,6 +1650,6 @@ By default, accepts the name of a module and prints the source of that module. A class or function within the module can be printed instead by appended a colon and the qualified name of the target object. -.. cmdoption:: --details +.. option:: --details Print information about the specified object rather than the source code diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 6c3059381776c9..e234fe92bc9995 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -703,7 +703,7 @@ specified, :data:`sys.stdin` and :data:`sys.stdout` will be used respectively: Command line options ^^^^^^^^^^^^^^^^^^^^ -.. cmdoption:: infile +.. option:: infile The JSON file to be validated or pretty-printed: @@ -723,36 +723,36 @@ Command line options If *infile* is not specified, read from :data:`sys.stdin`. -.. cmdoption:: outfile +.. option:: outfile Write the output of the *infile* to the given *outfile*. Otherwise, write it to :data:`sys.stdout`. -.. cmdoption:: --sort-keys +.. option:: --sort-keys Sort the output of dictionaries alphabetically by key. .. versionadded:: 3.5 -.. cmdoption:: --no-ensure-ascii +.. option:: --no-ensure-ascii Disable escaping of non-ascii characters, see :func:`json.dumps` for more information. .. versionadded:: 3.9 -.. cmdoption:: --json-lines +.. option:: --json-lines Parse every input line as separate JSON object. .. versionadded:: 3.8 -.. cmdoption:: --indent, --tab, --no-indent, --compact +.. option:: --indent, --tab, --no-indent, --compact Mutually exclusive options for whitespace control. .. versionadded:: 3.9 -.. cmdoption:: -h, --help +.. option:: -h, --help Show the help message. diff --git a/Doc/library/pickletools.rst b/Doc/library/pickletools.rst index 480f4a6d320815..c6ff4e6ed3d3b5 100644 --- a/Doc/library/pickletools.rst +++ b/Doc/library/pickletools.rst @@ -51,24 +51,24 @@ Command line options .. program:: pickletools -.. cmdoption:: -a, --annotate +.. option:: -a, --annotate Annotate each line with a short opcode description. -.. cmdoption:: -o, --output= +.. option:: -o, --output= Name of a file where the output should be written. -.. cmdoption:: -l, --indentlevel= +.. option:: -l, --indentlevel= The number of blanks by which to indent a new MARK level. -.. cmdoption:: -m, --memo +.. option:: -m, --memo When multiple objects are disassembled, preserve memo between disassemblies. -.. cmdoption:: -p, --preamble= +.. option:: -p, --preamble= When more than one pickle file are specified, print given preamble before each disassembly. diff --git a/Doc/library/py_compile.rst b/Doc/library/py_compile.rst index 69b93a3bdfcb26..7272f36d9a5568 100644 --- a/Doc/library/py_compile.rst +++ b/Doc/library/py_compile.rst @@ -138,13 +138,13 @@ not be compiled. .. program:: python -m py_compile -.. cmdoption:: ... - - +.. option:: ... + - Positional arguments are files to compile. If ``-`` is the only parameter, the list of files is taken from standard input. -.. cmdoption:: -q, --quiet +.. option:: -q, --quiet Suppress errors output. diff --git a/Doc/library/site.rst b/Doc/library/site.rst index 02880c56416615..2dc9fb09d727e2 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -266,11 +266,11 @@ If it is called without arguments, it will print the contents of :data:`USER_BASE` and whether the directory exists, then the same thing for :data:`USER_SITE`, and finally the value of :data:`ENABLE_USER_SITE`. -.. cmdoption:: --user-base +.. option:: --user-base Print the path to the user base directory. -.. cmdoption:: --user-site +.. option:: --user-site Print the path to the user site-packages directory. diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 574ea337e71b79..68b2091aa24ce4 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -1151,31 +1151,31 @@ For a list of the files in a tar archive, use the :option:`-l` option: Command-line options ~~~~~~~~~~~~~~~~~~~~ -.. cmdoption:: -l - --list +.. option:: -l + --list List files in a tarfile. -.. cmdoption:: -c ... - --create ... +.. option:: -c ... + --create ... Create tarfile from source files. -.. cmdoption:: -e [] - --extract [] +.. option:: -e [] + --extract [] Extract tarfile into the current directory if *output_dir* is not specified. -.. cmdoption:: -t - --test +.. option:: -t + --test Test whether the tarfile is valid or not. -.. cmdoption:: -v, --verbose +.. option:: -v, --verbose Verbose output. -.. cmdoption:: --filter +.. option:: --filter Specifies the *filter* for ``--extract``. See :ref:`tarfile-extraction-filter` for details. diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst index b3d2a1b9e0600f..60ec135873c414 100644 --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -214,36 +214,36 @@ Where the following options are understood: .. program:: timeit -.. cmdoption:: -n N, --number=N +.. option:: -n N, --number=N how many times to execute 'statement' -.. cmdoption:: -r N, --repeat=N +.. option:: -r N, --repeat=N how many times to repeat the timer (default 5) -.. cmdoption:: -s S, --setup=S +.. option:: -s S, --setup=S statement to be executed once initially (default ``pass``) -.. cmdoption:: -p, --process +.. option:: -p, --process measure process time, not wallclock time, using :func:`time.process_time` instead of :func:`time.perf_counter`, which is the default .. versionadded:: 3.3 -.. cmdoption:: -u, --unit=U +.. option:: -u, --unit=U specify a time unit for timer output; can select ``nsec``, ``usec``, ``msec``, or ``sec`` .. versionadded:: 3.5 -.. cmdoption:: -v, --verbose +.. option:: -v, --verbose print raw timing results; repeat for more digits precision -.. cmdoption:: -h, --help +.. option:: -h, --help print a short usage message and exit diff --git a/Doc/library/tokenize.rst b/Doc/library/tokenize.rst index bffe93006edc7b..92bdb052267a68 100644 --- a/Doc/library/tokenize.rst +++ b/Doc/library/tokenize.rst @@ -166,11 +166,11 @@ The following options are accepted: .. program:: tokenize -.. cmdoption:: -h, --help +.. option:: -h, --help show this help message and exit -.. cmdoption:: -e, --exact +.. option:: -e, --exact display token names using the exact type diff --git a/Doc/library/trace.rst b/Doc/library/trace.rst index 40cf198f1287d7..e9b59a6d186ba2 100644 --- a/Doc/library/trace.rst +++ b/Doc/library/trace.rst @@ -34,11 +34,11 @@ all Python modules imported during the execution into the current directory. .. program:: trace -.. cmdoption:: --help +.. option:: --help Display usage and exit. -.. cmdoption:: --version +.. option:: --version Display the version of the module and exit. @@ -56,28 +56,28 @@ the :option:`--trace <-t>` and :option:`--count <-c>` options. When .. program:: trace -.. cmdoption:: -c, --count +.. option:: -c, --count Produce a set of annotated listing files upon program completion that shows how many times each statement was executed. See also :option:`--coverdir <-C>`, :option:`--file <-f>` and :option:`--no-report <-R>` below. -.. cmdoption:: -t, --trace +.. option:: -t, --trace Display lines as they are executed. -.. cmdoption:: -l, --listfuncs +.. option:: -l, --listfuncs Display the functions executed by running the program. -.. cmdoption:: -r, --report +.. option:: -r, --report Produce an annotated list from an earlier program run that used the :option:`--count <-c>` and :option:`--file <-f>` option. This does not execute any code. -.. cmdoption:: -T, --trackcalls +.. option:: -T, --trackcalls Display the calling relationships exposed by running the program. @@ -86,33 +86,33 @@ Modifiers .. program:: trace -.. cmdoption:: -f, --file= +.. option:: -f, --file= Name of a file to accumulate counts over several tracing runs. Should be used with the :option:`--count <-c>` option. -.. cmdoption:: -C, --coverdir= +.. option:: -C, --coverdir= Directory where the report files go. The coverage report for ``package.module`` is written to file :file:`{dir}/{package}/{module}.cover`. -.. cmdoption:: -m, --missing +.. option:: -m, --missing When generating annotated listings, mark lines which were not executed with ``>>>>>>``. -.. cmdoption:: -s, --summary +.. option:: -s, --summary When using :option:`--count <-c>` or :option:`--report <-r>`, write a brief summary to stdout for each file processed. -.. cmdoption:: -R, --no-report +.. option:: -R, --no-report Do not generate annotated listings. This is useful if you intend to make several runs with :option:`--count <-c>`, and then produce a single set of annotated listings at the end. -.. cmdoption:: -g, --timing +.. option:: -g, --timing Prefix each line with the time since the program started. Only used while tracing. @@ -124,12 +124,12 @@ These options may be repeated multiple times. .. program:: trace -.. cmdoption:: --ignore-module= +.. option:: --ignore-module= Ignore each of the given module names and its submodules (if it is a package). The argument can be a list of names separated by a comma. -.. cmdoption:: --ignore-dir= +.. option:: --ignore-dir= Ignore all modules and packages in the named directory and subdirectories. The argument can be a list of directories separated by :data:`os.pathsep`. diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 4c28e8fae8b088..21abc583f853a7 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -206,13 +206,13 @@ Command-line options .. program:: unittest -.. cmdoption:: -b, --buffer +.. option:: -b, --buffer The standard output and standard error streams are buffered during the test run. Output during a passing test is discarded. Output is echoed normally on test fail or error and is added to the failure messages. -.. cmdoption:: -c, --catch +.. option:: -c, --catch :kbd:`Control-C` during the test run waits for the current test to end and then reports all the results so far. A second :kbd:`Control-C` raises the normal @@ -220,11 +220,11 @@ Command-line options See `Signal Handling`_ for the functions that provide this functionality. -.. cmdoption:: -f, --failfast +.. option:: -f, --failfast Stop the test run on the first error or failure. -.. cmdoption:: -k +.. option:: -k Only run test methods and classes that match the pattern or substring. This option may be used multiple times, in which case all test cases that @@ -240,11 +240,11 @@ Command-line options For example, ``-k foo`` matches ``foo_tests.SomeTest.test_something``, ``bar_tests.SomeTest.test_foo``, but not ``bar_tests.FooTest.test_something``. -.. cmdoption:: --locals +.. option:: --locals Show local variables in tracebacks. -.. cmdoption:: --durations N +.. option:: --durations N Show the N slowest test cases (N=0 for all). @@ -292,19 +292,19 @@ The ``discover`` sub-command has the following options: .. program:: unittest discover -.. cmdoption:: -v, --verbose +.. option:: -v, --verbose Verbose output -.. cmdoption:: -s, --start-directory directory +.. option:: -s, --start-directory directory Directory to start discovery (``.`` default) -.. cmdoption:: -p, --pattern pattern +.. option:: -p, --pattern pattern Pattern to match test files (``test*.py`` default) -.. cmdoption:: -t, --top-level-directory directory +.. option:: -t, --top-level-directory directory Top level directory of project (defaults to start directory) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index adf01770656754..e2d231da38fd9a 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -289,25 +289,25 @@ The following options are accepted: .. program:: uuid -.. cmdoption:: -h, --help +.. option:: -h, --help Show the help message and exit. -.. cmdoption:: -u - --uuid +.. option:: -u + --uuid Specify the function name to use to generate the uuid. By default :func:`uuid4` is used. -.. cmdoption:: -n - --namespace +.. option:: -n + --namespace The namespace is a ``UUID``, or ``@ns`` where ``ns`` is a well-known predefined UUID addressed by namespace name. Such as ``@dns``, ``@url``, ``@oid``, and ``@x500``. Only required for :func:`uuid3` / :func:`uuid5` functions. -.. cmdoption:: -N - --name +.. option:: -N + --name The name used as part of generating the uuid. Only required for :func:`uuid3` / :func:`uuid5` functions. diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index 7c01fc102fca07..104afca23a20b4 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -54,7 +54,7 @@ The following options are understood: .. program:: zipapp -.. cmdoption:: -o , --output= +.. option:: -o , --output= Write the output to a file named *output*. If this option is not specified, the output filename will be the same as the input *source*, with the @@ -64,13 +64,13 @@ The following options are understood: An output filename must be specified if the *source* is an archive (and in that case, *output* must not be the same as *source*). -.. cmdoption:: -p , --python= +.. option:: -p , --python= Add a ``#!`` line to the archive specifying *interpreter* as the command to run. Also, on POSIX, make the archive executable. The default is to write no ``#!`` line, and not make the file executable. -.. cmdoption:: -m , --main= +.. option:: -m , --main= Write a ``__main__.py`` file to the archive that executes *mainfn*. The *mainfn* argument should have the form "pkg.mod:fn", where "pkg.mod" is a @@ -79,7 +79,7 @@ The following options are understood: :option:`--main` cannot be specified when copying an archive. -.. cmdoption:: -c, --compress +.. option:: -c, --compress Compress files with the deflate method, reducing the size of the output file. By default, files are stored uncompressed in the archive. @@ -88,13 +88,13 @@ The following options are understood: .. versionadded:: 3.7 -.. cmdoption:: --info +.. option:: --info Display the interpreter embedded in the archive, for diagnostic purposes. In this case, any other options are ignored and SOURCE must be an archive, not a directory. -.. cmdoption:: -h, --help +.. option:: -h, --help Print a short usage message and exit. diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 45f3d340bd82d3..c011656d9ef90c 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -905,27 +905,27 @@ For a list of the files in a ZIP archive, use the :option:`-l` option: Command-line options ~~~~~~~~~~~~~~~~~~~~ -.. cmdoption:: -l - --list +.. option:: -l + --list List files in a zipfile. -.. cmdoption:: -c ... - --create ... +.. option:: -c ... + --create ... Create zipfile from source files. -.. cmdoption:: -e - --extract +.. option:: -e + --extract Extract zipfile into target directory. -.. cmdoption:: -t - --test +.. option:: -t + --test Test whether the zipfile is valid or not. -.. cmdoption:: --metadata-encoding +.. option:: --metadata-encoding Specify encoding of member names for :option:`-l`, :option:`-e` and :option:`-t`. diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index bade3ca6650e62..f68a2251f06d4a 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -59,7 +59,7 @@ all consecutive arguments will end up in :data:`sys.argv` -- note that the first element, subscript zero (``sys.argv[0]``), is a string reflecting the program's source. -.. cmdoption:: -c +.. option:: -c Execute the Python code in *command*. *command* can be one or more statements separated by newlines, with significant leading whitespace as in @@ -72,7 +72,7 @@ source. .. audit-event:: cpython.run_command command cmdoption-c -.. cmdoption:: -m +.. option:: -m Search :data:`sys.path` for the named module and execute its contents as the :mod:`__main__` module. @@ -188,35 +188,35 @@ automatically enabled, if available on your platform (see Generic options ~~~~~~~~~~~~~~~ -.. cmdoption:: -? - -h - --help +.. option:: -? + -h + --help Print a short description of all command line options and corresponding environment variables and exit. -.. cmdoption:: --help-env +.. option:: --help-env Print a short description of Python-specific environment variables and exit. .. versionadded:: 3.11 -.. cmdoption:: --help-xoptions +.. option:: --help-xoptions Print a description of implementation-specific :option:`-X` options and exit. .. versionadded:: 3.11 -.. cmdoption:: --help-all +.. option:: --help-all Print complete usage information and exit. .. versionadded:: 3.11 -.. cmdoption:: -V - --version +.. option:: -V + --version Print the Python version number and exit. Example output could be: @@ -240,7 +240,7 @@ Generic options Miscellaneous options ~~~~~~~~~~~~~~~~~~~~~ -.. cmdoption:: -b +.. option:: -b Issue a warning when comparing :class:`bytes` or :class:`bytearray` with :class:`str` or :class:`bytes` with :class:`int`. Issue an error when the @@ -249,13 +249,13 @@ Miscellaneous options .. versionchanged:: 3.5 Affects comparisons of :class:`bytes` with :class:`int`. -.. cmdoption:: -B +.. option:: -B If given, Python won't try to write ``.pyc`` files on the import of source modules. See also :envvar:`PYTHONDONTWRITEBYTECODE`. -.. cmdoption:: --check-hash-based-pycs default|always|never +.. option:: --check-hash-based-pycs default|always|never Control the validation behavior of hash-based ``.pyc`` files. See :ref:`pyc-invalidation`. When set to ``default``, checked and unchecked @@ -269,7 +269,7 @@ Miscellaneous options option. -.. cmdoption:: -d +.. option:: -d Turn on parser debugging output (for expert only). See also the :envvar:`PYTHONDEBUG` environment variable. @@ -278,7 +278,7 @@ Miscellaneous options it's ignored. -.. cmdoption:: -E +.. option:: -E Ignore all :envvar:`PYTHON*` environment variables, e.g. :envvar:`PYTHONPATH` and :envvar:`PYTHONHOME`, that might be set. @@ -286,7 +286,7 @@ Miscellaneous options See also the :option:`-P` and :option:`-I` (isolated) options. -.. cmdoption:: -i +.. option:: -i When a script is passed as first argument or the :option:`-c` option is used, enter interactive mode after executing the script or the command, even when @@ -297,7 +297,7 @@ Miscellaneous options raises an exception. See also :envvar:`PYTHONINSPECT`. -.. cmdoption:: -I +.. option:: -I Run Python in isolated mode. This also implies :option:`-E`, :option:`-P` and :option:`-s` options. @@ -310,7 +310,7 @@ Miscellaneous options .. versionadded:: 3.4 -.. cmdoption:: -O +.. option:: -O Remove assert statements and any code conditional on the value of :const:`__debug__`. Augment the filename for compiled @@ -321,7 +321,7 @@ Miscellaneous options Modify ``.pyc`` filenames according to :pep:`488`. -.. cmdoption:: -OO +.. option:: -OO Do :option:`-O` and also discard docstrings. Augment the filename for compiled (:term:`bytecode`) files by adding ``.opt-2`` before the @@ -331,7 +331,7 @@ Miscellaneous options Modify ``.pyc`` filenames according to :pep:`488`. -.. cmdoption:: -P +.. option:: -P Don't prepend a potentially unsafe path to :data:`sys.path`: @@ -348,14 +348,14 @@ Miscellaneous options .. versionadded:: 3.11 -.. cmdoption:: -q +.. option:: -q Don't display the copyright and version messages even in interactive mode. .. versionadded:: 3.2 -.. cmdoption:: -R +.. option:: -R Turn on hash randomization. This option only has an effect if the :envvar:`PYTHONHASHSEED` environment variable is set to ``0``, since hash @@ -381,7 +381,7 @@ Miscellaneous options .. versionadded:: 3.2.3 -.. cmdoption:: -s +.. option:: -s Don't add the :data:`user site-packages directory ` to :data:`sys.path`. @@ -391,7 +391,7 @@ Miscellaneous options :pep:`370` -- Per user site-packages directory -.. cmdoption:: -S +.. option:: -S Disable the import of the module :mod:`site` and the site-dependent manipulations of :data:`sys.path` that it entails. Also disable these @@ -399,7 +399,7 @@ Miscellaneous options :func:`site.main` if you want them to be triggered). -.. cmdoption:: -u +.. option:: -u Force the stdout and stderr streams to be unbuffered. This option has no effect on the stdin stream. @@ -410,7 +410,7 @@ Miscellaneous options The text layer of the stdout and stderr streams now is unbuffered. -.. cmdoption:: -v +.. option:: -v Print a message each time a module is initialized, showing the place (filename or built-in module) from which it is loaded. When given twice @@ -425,7 +425,7 @@ Miscellaneous options .. _using-on-warnings: -.. cmdoption:: -W arg +.. option:: -W arg Warning control. Python's warning machinery by default prints warning messages to :data:`sys.stderr`. @@ -484,13 +484,13 @@ Miscellaneous options details. -.. cmdoption:: -x +.. option:: -x Skip the first line of the source, allowing use of non-Unix forms of ``#!cmd``. This is intended for a DOS specific hack only. -.. cmdoption:: -X +.. option:: -X Reserved for various implementation-specific options. CPython currently defines the following possible values: @@ -597,7 +597,7 @@ Miscellaneous options Options you shouldn't use ~~~~~~~~~~~~~~~~~~~~~~~~~ -.. cmdoption:: -J +.. option:: -J Reserved for use by Jython_. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 3fe2a63587111c..11b6b53f8bb269 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -80,7 +80,7 @@ See also the :file:`Misc/SpecialBuilds.txt` in the Python source distribution. General Options --------------- -.. cmdoption:: --enable-loadable-sqlite-extensions +.. option:: --enable-loadable-sqlite-extensions Support loadable extensions in the :mod:`!_sqlite` extension module (default is no) of the :mod:`sqlite3` module. @@ -90,12 +90,12 @@ General Options .. versionadded:: 3.6 -.. cmdoption:: --disable-ipv6 +.. option:: --disable-ipv6 Disable IPv6 support (enabled by default if supported), see the :mod:`socket` module. -.. cmdoption:: --enable-big-digits=[15|30] +.. option:: --enable-big-digits=[15|30] Define the size in bits of Python :class:`int` digits: 15 or 30 bits. @@ -105,7 +105,7 @@ General Options See :data:`sys.int_info.bits_per_digit `. -.. cmdoption:: --with-suffix=SUFFIX +.. option:: --with-suffix=SUFFIX Set the Python executable suffix to *SUFFIX*. @@ -118,7 +118,7 @@ General Options The default suffix on WASM platform is one of ``.js``, ``.html`` or ``.wasm``. -.. cmdoption:: --with-tzpath= +.. option:: --with-tzpath= Select the default time zone search path for :const:`zoneinfo.TZPATH`. See the :ref:`Compile-time configuration @@ -130,7 +130,7 @@ General Options .. versionadded:: 3.9 -.. cmdoption:: --without-decimal-contextvar +.. option:: --without-decimal-contextvar Build the ``_decimal`` extension module using a thread-local context rather than a coroutine-local context (default), see the :mod:`decimal` module. @@ -139,7 +139,7 @@ General Options .. versionadded:: 3.9 -.. cmdoption:: --with-dbmliborder= +.. option:: --with-dbmliborder= Override order to check db backends for the :mod:`dbm` module @@ -149,7 +149,7 @@ General Options * ``gdbm``; * ``bdb``. -.. cmdoption:: --without-c-locale-coercion +.. option:: --without-c-locale-coercion Disable C locale coercion to a UTF-8 based locale (enabled by default). @@ -157,13 +157,13 @@ General Options See :envvar:`PYTHONCOERCECLOCALE` and the :pep:`538`. -.. cmdoption:: --without-freelists +.. option:: --without-freelists Disable all freelists except the empty tuple singleton. .. versionadded:: 3.11 -.. cmdoption:: --with-platlibdir=DIRNAME +.. option:: --with-platlibdir=DIRNAME Python library directory name (default is ``lib``). @@ -173,7 +173,7 @@ General Options .. versionadded:: 3.9 -.. cmdoption:: --with-wheel-pkg-dir=PATH +.. option:: --with-wheel-pkg-dir=PATH Directory of wheel packages used by the :mod:`ensurepip` module (none by default). @@ -185,7 +185,7 @@ General Options .. versionadded:: 3.10 -.. cmdoption:: --with-pkg-config=[check|yes|no] +.. option:: --with-pkg-config=[check|yes|no] Whether configure should use :program:`pkg-config` to detect build dependencies. @@ -196,7 +196,7 @@ General Options .. versionadded:: 3.11 -.. cmdoption:: --enable-pystats +.. option:: --enable-pystats Turn on internal statistics gathering. @@ -211,7 +211,7 @@ General Options WebAssembly Options ------------------- -.. cmdoption:: --with-emscripten-target=[browser|node] +.. option:: --with-emscripten-target=[browser|node] Set build flavor for ``wasm32-emscripten``. @@ -220,7 +220,7 @@ WebAssembly Options .. versionadded:: 3.11 -.. cmdoption:: --enable-wasm-dynamic-linking +.. option:: --enable-wasm-dynamic-linking Turn on dynamic linking support for WASM. @@ -229,7 +229,7 @@ WebAssembly Options .. versionadded:: 3.11 -.. cmdoption:: --enable-wasm-pthreads +.. option:: --enable-wasm-pthreads Turn on pthreads support for WASM. @@ -239,7 +239,7 @@ WebAssembly Options Install Options --------------- -.. cmdoption:: --prefix=PREFIX +.. option:: --prefix=PREFIX Install architecture-independent files in PREFIX. On Unix, it defaults to :file:`/usr/local`. @@ -249,20 +249,20 @@ Install Options As an example, one can use ``--prefix="$HOME/.local/"`` to install a Python in its home directory. -.. cmdoption:: --exec-prefix=EPREFIX +.. option:: --exec-prefix=EPREFIX Install architecture-dependent files in EPREFIX, defaults to :option:`--prefix`. This value can be retrieved at runtime using :data:`sys.exec_prefix`. -.. cmdoption:: --disable-test-modules +.. option:: --disable-test-modules Don't build nor install test modules, like the :mod:`test` package or the :mod:`!_testcapi` extension module (built and installed by default). .. versionadded:: 3.10 -.. cmdoption:: --with-ensurepip=[upgrade|install|no] +.. option:: --with-ensurepip=[upgrade|install|no] Select the :mod:`ensurepip` command run on Python installation: @@ -281,7 +281,7 @@ Configuring Python using ``--enable-optimizations --with-lto`` (PGO + LTO) is recommended for best performance. The experimental ``--enable-bolt`` flag can also be used to improve performance. -.. cmdoption:: --enable-optimizations +.. option:: --enable-optimizations Enable Profile Guided Optimization (PGO) using :envvar:`PROFILE_TASK` (disabled by default). @@ -307,7 +307,7 @@ also be used to improve performance. .. versionadded:: 3.8 -.. cmdoption:: --with-lto=[full|thin|no|yes] +.. option:: --with-lto=[full|thin|no|yes] Enable Link Time Optimization (LTO) in any build (disabled by default). @@ -322,7 +322,7 @@ also be used to improve performance. .. versionchanged:: 3.12 Use ThinLTO as the default optimization policy on Clang if the compiler accepts the flag. -.. cmdoption:: --enable-bolt +.. option:: --enable-bolt Enable usage of the `BOLT post-link binary optimizer `_ (disabled by @@ -347,19 +347,19 @@ also be used to improve performance. .. versionadded:: 3.12 -.. cmdoption:: --with-computed-gotos +.. option:: --with-computed-gotos Enable computed gotos in evaluation loop (enabled by default on supported compilers). -.. cmdoption:: --without-pymalloc +.. option:: --without-pymalloc Disable the specialized Python memory allocator :ref:`pymalloc ` (enabled by default). See also :envvar:`PYTHONMALLOC` environment variable. -.. cmdoption:: --without-doc-strings +.. option:: --without-doc-strings Disable static documentation strings to reduce the memory footprint (enabled by default). Documentation strings defined in Python are not affected. @@ -368,11 +368,11 @@ also be used to improve performance. See the ``PyDoc_STRVAR()`` macro. -.. cmdoption:: --enable-profiling +.. option:: --enable-profiling Enable C-level code profiling with ``gprof`` (disabled by default). -.. cmdoption:: --with-strict-overflow +.. option:: --with-strict-overflow Add ``-fstrict-overflow`` to the C compiler flags (by default we add ``-fno-strict-overflow`` instead). @@ -429,12 +429,12 @@ See also the :ref:`Python Development Mode ` and the Debug options ------------- -.. cmdoption:: --with-pydebug +.. option:: --with-pydebug :ref:`Build Python in debug mode `: define the ``Py_DEBUG`` macro (disabled by default). -.. cmdoption:: --with-trace-refs +.. option:: --with-trace-refs Enable tracing references for debugging purpose (disabled by default). @@ -449,7 +449,7 @@ Debug options .. versionadded:: 3.8 -.. cmdoption:: --with-assertions +.. option:: --with-assertions Build with C assertions enabled (default is no): ``assert(...);`` and ``_PyObject_ASSERT(...);``. @@ -462,11 +462,11 @@ Debug options .. versionadded:: 3.6 -.. cmdoption:: --with-valgrind +.. option:: --with-valgrind Enable Valgrind support (default is no). -.. cmdoption:: --with-dtrace +.. option:: --with-dtrace Enable DTrace support (default is no). @@ -475,19 +475,19 @@ Debug options .. versionadded:: 3.6 -.. cmdoption:: --with-address-sanitizer +.. option:: --with-address-sanitizer Enable AddressSanitizer memory error detector, ``asan`` (default is no). .. versionadded:: 3.6 -.. cmdoption:: --with-memory-sanitizer +.. option:: --with-memory-sanitizer Enable MemorySanitizer allocation error detector, ``msan`` (default is no). .. versionadded:: 3.6 -.. cmdoption:: --with-undefined-behavior-sanitizer +.. option:: --with-undefined-behavior-sanitizer Enable UndefinedBehaviorSanitizer undefined behaviour detector, ``ubsan`` (default is no). @@ -498,11 +498,11 @@ Debug options Linker options -------------- -.. cmdoption:: --enable-shared +.. option:: --enable-shared Enable building a shared Python library: ``libpython`` (default is no). -.. cmdoption:: --without-static-libpython +.. option:: --without-static-libpython Do not build ``libpythonMAJOR.MINOR.a`` and do not install ``python.o`` (built and enabled by default). @@ -513,23 +513,23 @@ Linker options Libraries options ----------------- -.. cmdoption:: --with-libs='lib1 ...' +.. option:: --with-libs='lib1 ...' Link against additional libraries (default is no). -.. cmdoption:: --with-system-expat +.. option:: --with-system-expat Build the :mod:`!pyexpat` module using an installed ``expat`` library (default is no). -.. cmdoption:: --with-system-libmpdec +.. option:: --with-system-libmpdec Build the ``_decimal`` extension module using an installed ``mpdec`` library, see the :mod:`decimal` module (default is no). .. versionadded:: 3.3 -.. cmdoption:: --with-readline=editline +.. option:: --with-readline=editline Use ``editline`` library for backend of the :mod:`readline` module. @@ -537,7 +537,7 @@ Libraries options .. versionadded:: 3.10 -.. cmdoption:: --without-readline +.. option:: --without-readline Don't build the :mod:`readline` module (built by default). @@ -545,21 +545,21 @@ Libraries options .. versionadded:: 3.10 -.. cmdoption:: --with-libm=STRING +.. option:: --with-libm=STRING Override ``libm`` math library to *STRING* (default is system-dependent). -.. cmdoption:: --with-libc=STRING +.. option:: --with-libc=STRING Override ``libc`` C library to *STRING* (default is system-dependent). -.. cmdoption:: --with-openssl=DIR +.. option:: --with-openssl=DIR Root of the OpenSSL directory. .. versionadded:: 3.7 -.. cmdoption:: --with-openssl-rpath=[no|auto|DIR] +.. option:: --with-openssl-rpath=[no|auto|DIR] Set runtime library directory (rpath) for OpenSSL libraries: @@ -574,7 +574,7 @@ Libraries options Security Options ---------------- -.. cmdoption:: --with-hash-algorithm=[fnv|siphash13|siphash24] +.. option:: --with-hash-algorithm=[fnv|siphash13|siphash24] Select hash algorithm for use in ``Python/pyhash.c``: @@ -587,7 +587,7 @@ Security Options .. versionadded:: 3.11 ``siphash13`` is added and it is the new default. -.. cmdoption:: --with-builtin-hashlib-hashes=md5,sha1,sha256,sha512,sha3,blake2 +.. option:: --with-builtin-hashlib-hashes=md5,sha1,sha256,sha512,sha3,blake2 Built-in hash modules: @@ -600,7 +600,7 @@ Security Options .. versionadded:: 3.9 -.. cmdoption:: --with-ssl-default-suites=[python|openssl|STRING] +.. option:: --with-ssl-default-suites=[python|openssl|STRING] Override the OpenSSL default cipher suites string: @@ -622,19 +622,19 @@ macOS Options See ``Mac/README.rst``. -.. cmdoption:: --enable-universalsdk -.. cmdoption:: --enable-universalsdk=SDKDIR +.. option:: --enable-universalsdk +.. option:: --enable-universalsdk=SDKDIR Create a universal binary build. *SDKDIR* specifies which macOS SDK should be used to perform the build (default is no). -.. cmdoption:: --enable-framework -.. cmdoption:: --enable-framework=INSTALLDIR +.. option:: --enable-framework +.. option:: --enable-framework=INSTALLDIR Create a Python.framework rather than a traditional Unix install. Optional *INSTALLDIR* specifies the installation path (default is no). -.. cmdoption:: --with-universal-archs=ARCH +.. option:: --with-universal-archs=ARCH Specify the kind of universal binary that should be created. This option is only valid when :option:`--enable-universalsdk` is set. @@ -650,7 +650,7 @@ See ``Mac/README.rst``. * ``intel-64``; * ``all``. -.. cmdoption:: --with-framework-name=FRAMEWORK +.. option:: --with-framework-name=FRAMEWORK Specify the name for the python framework on macOS only valid when :option:`--enable-framework` is set (default: ``Python``). @@ -664,21 +664,21 @@ for another CPU architecture or platform. Cross compiling requires a Python interpreter for the build platform. The version of the build Python must match the version of the cross compiled host Python. -.. cmdoption:: --build=BUILD +.. option:: --build=BUILD configure for building on BUILD, usually guessed by :program:`config.guess`. -.. cmdoption:: --host=HOST +.. option:: --host=HOST cross-compile to build programs to run on HOST (target platform) -.. cmdoption:: --with-build-python=path/to/python +.. option:: --with-build-python=path/to/python path to build ``python`` binary for cross compiling .. versionadded:: 3.11 -.. cmdoption:: CONFIG_SITE=file +.. option:: CONFIG_SITE=file An environment variable that points to a file with configure overrides. From 414f5620812584906eed8a19405f148641b248d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:28:13 -0700 Subject: [PATCH 0923/1206] [3.12] gh-109917: Fix test instability in test_concurrent_futures (GH-110306) (#110315) gh-109917: Fix test instability in test_concurrent_futures (GH-110306) The test had an instability issue due to the ordering of the dummy queue operation and the real wakeup pipe operations. Both primitives are thread safe but not done atomically as a single update and may interleave arbitrarily. With the old order of operations this can lead to an incorrect state where the dummy queue is full but the wakeup pipe is empty. By swapping the order in clear() I think this can no longer happen in any possible operation interleaving (famous last words). (cherry picked from commit a376a72bd92cd7c9930467dd1aba40045fb75e3b) Co-authored-by: elfstrom --- Lib/test/test_concurrent_futures/test_deadlock.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_concurrent_futures/test_deadlock.py b/Lib/test/test_concurrent_futures/test_deadlock.py index 7ede95d5ed3422..1db4cd009926b9 100644 --- a/Lib/test/test_concurrent_futures/test_deadlock.py +++ b/Lib/test/test_concurrent_futures/test_deadlock.py @@ -284,11 +284,12 @@ def wakeup(self): super().wakeup() def clear(self): + super().clear() try: while True: self._dummy_queue.get_nowait() except queue.Empty: - super().clear() + pass with (unittest.mock.patch.object(futures.process._ExecutorManagerThread, 'run', mock_run), From 35feda5bc93ab1e756f3f2739985fd36caae6920 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 02:01:03 -0700 Subject: [PATCH 0924/1206] [3.12] gh-110267: Add tests for pickling and copying PyStructSequence objects (GH-110272) (GH-110285) (cherry picked from commit 2d4865d775123e8889c7a79fc49b4bf627176c4b) Co-authored-by: Xuehai Pan --- Lib/test/test_structseq.py | 75 ++++++++++++++++++- ...-10-03-10-54-09.gh-issue-110267.O-c47G.rst | 2 + 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-03-10-54-09.gh-issue-110267.O-c47G.rst diff --git a/Lib/test/test_structseq.py b/Lib/test/test_structseq.py index a9fe193028ebe4..c6c0afaf077acc 100644 --- a/Lib/test/test_structseq.py +++ b/Lib/test/test_structseq.py @@ -1,4 +1,6 @@ +import copy import os +import pickle import time import unittest @@ -106,9 +108,78 @@ def __len__(self): self.assertRaises(Exc, time.struct_time, C()) - def test_reduce(self): + def test_pickling(self): t = time.gmtime() - x = t.__reduce__() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + p = pickle.dumps(t, proto) + t2 = pickle.loads(p) + self.assertEqual(t2.__class__, t.__class__) + self.assertEqual(t2, t) + self.assertEqual(t2.tm_year, t.tm_year) + self.assertEqual(t2.tm_zone, t.tm_zone) + + def test_pickling_with_unnamed_fields(self): + assert os.stat_result.n_unnamed_fields > 0 + + r = os.stat_result(range(os.stat_result.n_sequence_fields), + {'st_atime': 1.0, 'st_atime_ns': 2.0}) + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + p = pickle.dumps(r, proto) + r2 = pickle.loads(p) + self.assertEqual(r2.__class__, r.__class__) + self.assertEqual(r2, r) + self.assertEqual(r2.st_mode, r.st_mode) + self.assertEqual(r2.st_atime, r.st_atime) + self.assertEqual(r2.st_atime_ns, r.st_atime_ns) + + def test_copying(self): + n_fields = time.struct_time.n_fields + t = time.struct_time([[i] for i in range(n_fields)]) + + t2 = copy.copy(t) + self.assertEqual(t2.__class__, t.__class__) + self.assertEqual(t2, t) + self.assertEqual(t2.tm_year, t.tm_year) + self.assertEqual(t2.tm_zone, t.tm_zone) + self.assertIs(t2[0], t[0]) + self.assertIs(t2.tm_year, t.tm_year) + + t3 = copy.deepcopy(t) + self.assertEqual(t3.__class__, t.__class__) + self.assertEqual(t3, t) + self.assertEqual(t3.tm_year, t.tm_year) + self.assertEqual(t3.tm_zone, t.tm_zone) + self.assertIsNot(t3[0], t[0]) + self.assertIsNot(t3.tm_year, t.tm_year) + + def test_copying_with_unnamed_fields(self): + assert os.stat_result.n_unnamed_fields > 0 + + n_sequence_fields = os.stat_result.n_sequence_fields + r = os.stat_result([[i] for i in range(n_sequence_fields)], + {'st_atime': [1.0], 'st_atime_ns': [2.0]}) + + r2 = copy.copy(r) + self.assertEqual(r2.__class__, r.__class__) + self.assertEqual(r2, r) + self.assertEqual(r2.st_mode, r.st_mode) + self.assertEqual(r2.st_atime, r.st_atime) + self.assertEqual(r2.st_atime_ns, r.st_atime_ns) + self.assertIs(r2[0], r[0]) + self.assertIs(r2.st_mode, r.st_mode) + self.assertIs(r2.st_atime, r.st_atime) + self.assertIs(r2.st_atime_ns, r.st_atime_ns) + + r3 = copy.deepcopy(r) + self.assertEqual(r3.__class__, r.__class__) + self.assertEqual(r3, r) + self.assertEqual(r3.st_mode, r.st_mode) + self.assertEqual(r3.st_atime, r.st_atime) + self.assertEqual(r3.st_atime_ns, r.st_atime_ns) + self.assertIsNot(r3[0], r[0]) + self.assertIsNot(r3.st_mode, r.st_mode) + self.assertIsNot(r3.st_atime, r.st_atime) + self.assertIsNot(r3.st_atime_ns, r.st_atime_ns) def test_extended_getslice(self): # Test extended slicing by comparing with list slicing. diff --git a/Misc/NEWS.d/next/Tests/2023-10-03-10-54-09.gh-issue-110267.O-c47G.rst b/Misc/NEWS.d/next/Tests/2023-10-03-10-54-09.gh-issue-110267.O-c47G.rst new file mode 100644 index 00000000000000..2bae7715cc3d5b --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-03-10-54-09.gh-issue-110267.O-c47G.rst @@ -0,0 +1,2 @@ +Add tests for pickling and copying PyStructSequence objects. +Patched by Xuehai Pan. From e7a61d34b7897ac6cff53add2ec03309a5ff8350 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Oct 2023 12:26:24 +0200 Subject: [PATCH 0925/1206] [3.12] gh-109972: Split test_gdb.py into test_gdb package (#109977) (#110339) gh-109972: Split test_gdb.py into test_gdb package (#109977) Split test_gdb.py file into a test_gdb package made of multiple tests, so tests can now be run in parallel. * Create Lib/test/test_gdb/ directory. * Split test_gdb.py into multiple files in Lib/test/test_gdb/ directory. * Move Lib/test/gdb_sample.py to Lib/test/test_gdb/ directory. Update get_sample_script(): use __file__ to locate gdb_sample.py. * Move gdb_has_frame_select() and HAS_PYUP_PYDOWN to test_misc.py. * Explicitly skip test_gdb on Windows. Previously, test_gdb was skipped even if gdb was available because of gdb_has_frame_select(). (cherry picked from commit 8f324b7ecd2df3036fab098c4c8ac185ac07b277) --- Lib/test/libregrtest/runtest.py | 1 + Lib/test/test_gdb.py | 1066 ----------------- Lib/test/test_gdb/__init__.py | 10 + Lib/test/{ => test_gdb}/gdb_sample.py | 2 +- Lib/test/test_gdb/test_backtrace.py | 134 +++ Lib/test/test_gdb/test_cfunction.py | 83 ++ Lib/test/test_gdb/test_misc.py | 188 +++ Lib/test/test_gdb/test_pretty_print.py | 400 +++++++ Lib/test/test_gdb/util.py | 304 +++++ Makefile.pre.in | 1 + ...-09-28-12-25-19.gh-issue-109972.GYnwIP.rst | 2 + 11 files changed, 1124 insertions(+), 1067 deletions(-) delete mode 100644 Lib/test/test_gdb.py create mode 100644 Lib/test/test_gdb/__init__.py rename Lib/test/{ => test_gdb}/gdb_sample.py (75%) create mode 100644 Lib/test/test_gdb/test_backtrace.py create mode 100644 Lib/test/test_gdb/test_cfunction.py create mode 100644 Lib/test/test_gdb/test_misc.py create mode 100644 Lib/test/test_gdb/test_pretty_print.py create mode 100644 Lib/test/test_gdb/util.py create mode 100644 Misc/NEWS.d/next/Tests/2023-09-28-12-25-19.gh-issue-109972.GYnwIP.rst diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py index 8acce564e61a57..8b7844cb4b3bae 100644 --- a/Lib/test/libregrtest/runtest.py +++ b/Lib/test/libregrtest/runtest.py @@ -233,6 +233,7 @@ def iter_tests(self): "test_asyncio", "test_concurrent_futures", "test_future_stmt", + "test_gdb", "test_multiprocessing_fork", "test_multiprocessing_forkserver", "test_multiprocessing_spawn", diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py deleted file mode 100644 index b99e0abaa5b151..00000000000000 --- a/Lib/test/test_gdb.py +++ /dev/null @@ -1,1066 +0,0 @@ -# Verify that gdb can pretty-print the various PyObject* types -# -# The code for testing gdb was adapted from similar work in Unladen Swallow's -# Lib/test/test_jit_gdb.py - -import os -import platform -import re -import subprocess -import sys -import sysconfig -import textwrap -import unittest - -from test import support -from test.support import findfile, python_is_optimized - -def get_gdb_version(): - try: - cmd = ["gdb", "-nx", "--version"] - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True) - with proc: - version, stderr = proc.communicate() - - if proc.returncode: - raise Exception(f"Command {' '.join(cmd)!r} failed " - f"with exit code {proc.returncode}: " - f"stdout={version!r} stderr={stderr!r}") - except OSError: - # This is what "no gdb" looks like. There may, however, be other - # errors that manifest this way too. - raise unittest.SkipTest("Couldn't find gdb on the path") - - # Regex to parse: - # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7 - # 'GNU gdb (GDB) Fedora 7.9.1-17.fc22\n' -> 7.9 - # 'GNU gdb 6.1.1 [FreeBSD]\n' -> 6.1 - # 'GNU gdb (GDB) Fedora (7.5.1-37.fc18)\n' -> 7.5 - # 'HP gdb 6.7 for HP Itanium (32 or 64 bit) and target HP-UX 11iv2 and 11iv3.\n' -> 6.7 - match = re.search(r"^(?:GNU|HP) gdb.*?\b(\d+)\.(\d+)", version) - if match is None: - raise Exception("unable to parse GDB version: %r" % version) - return (version, int(match.group(1)), int(match.group(2))) - -gdb_version, gdb_major_version, gdb_minor_version = get_gdb_version() -if gdb_major_version < 7: - raise unittest.SkipTest("gdb versions before 7.0 didn't support python " - "embedding. Saw %s.%s:\n%s" - % (gdb_major_version, gdb_minor_version, - gdb_version)) - -if not sysconfig.is_python_build(): - raise unittest.SkipTest("test_gdb only works on source builds at the moment.") - -if ((sysconfig.get_config_var('PGO_PROF_USE_FLAG') or 'xxx') in - (sysconfig.get_config_var('PY_CORE_CFLAGS') or '')): - raise unittest.SkipTest("test_gdb is not reliable on PGO builds") - -# Location of custom hooks file in a repository checkout. -checkout_hook_path = os.path.join(os.path.dirname(sys.executable), - 'python-gdb.py') - -PYTHONHASHSEED = '123' - - -def cet_protection(): - cflags = sysconfig.get_config_var('CFLAGS') - if not cflags: - return False - flags = cflags.split() - # True if "-mcet -fcf-protection" options are found, but false - # if "-fcf-protection=none" or "-fcf-protection=return" is found. - return (('-mcet' in flags) - and any((flag.startswith('-fcf-protection') - and not flag.endswith(("=none", "=return"))) - for flag in flags)) - -# Control-flow enforcement technology -CET_PROTECTION = cet_protection() - - -def run_gdb(*args, **env_vars): - """Runs gdb in --batch mode with the additional arguments given by *args. - - Returns its (stdout, stderr) decoded from utf-8 using the replace handler. - """ - if env_vars: - env = os.environ.copy() - env.update(env_vars) - else: - env = None - # -nx: Do not execute commands from any .gdbinit initialization files - # (issue #22188) - base_cmd = ('gdb', '--batch', '-nx') - if (gdb_major_version, gdb_minor_version) >= (7, 4): - base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path) - proc = subprocess.Popen(base_cmd + args, - # Redirect stdin to prevent GDB from messing with - # the terminal settings - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=env) - with proc: - out, err = proc.communicate() - return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') - -# Verify that "gdb" was built with the embedded python support enabled: -gdbpy_version, _ = run_gdb("--eval-command=python import sys; print(sys.version_info)") -if not gdbpy_version: - raise unittest.SkipTest("gdb not built with embedded python support") - -if "major=2" in gdbpy_version: - raise unittest.SkipTest("gdb built with Python 2") - -# Verify that "gdb" can load our custom hooks, as OS security settings may -# disallow this without a customized .gdbinit. -_, gdbpy_errors = run_gdb('--args', sys.executable) -if "auto-loading has been declined" in gdbpy_errors: - msg = "gdb security settings prevent use of custom hooks: " - raise unittest.SkipTest(msg + gdbpy_errors.rstrip()) - -def gdb_has_frame_select(): - # Does this build of gdb have gdb.Frame.select ? - stdout, _ = run_gdb("--eval-command=python print(dir(gdb.Frame))") - m = re.match(r'.*\[(.*)\].*', stdout) - if not m: - raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test") - gdb_frame_dir = m.group(1).split(', ') - return "'select'" in gdb_frame_dir - -HAS_PYUP_PYDOWN = gdb_has_frame_select() - -BREAKPOINT_FN='builtin_id' - -@unittest.skipIf(support.PGO, "not useful for PGO") -class DebuggerTests(unittest.TestCase): - - """Test that the debugger can debug Python.""" - - def get_stack_trace(self, source=None, script=None, - breakpoint=BREAKPOINT_FN, - cmds_after_breakpoint=None, - import_site=False, - ignore_stderr=False): - ''' - Run 'python -c SOURCE' under gdb with a breakpoint. - - Support injecting commands after the breakpoint is reached - - Returns the stdout from gdb - - cmds_after_breakpoint: if provided, a list of strings: gdb commands - ''' - # We use "set breakpoint pending yes" to avoid blocking with a: - # Function "foo" not defined. - # Make breakpoint pending on future shared library load? (y or [n]) - # error, which typically happens python is dynamically linked (the - # breakpoints of interest are to be found in the shared library) - # When this happens, we still get: - # Function "textiowrapper_write" not defined. - # emitted to stderr each time, alas. - - # Initially I had "--eval-command=continue" here, but removed it to - # avoid repeated print breakpoints when traversing hierarchical data - # structures - - # Generate a list of commands in gdb's language: - commands = ['set breakpoint pending yes', - 'break %s' % breakpoint, - - # The tests assume that the first frame of printed - # backtrace will not contain program counter, - # that is however not guaranteed by gdb - # therefore we need to use 'set print address off' to - # make sure the counter is not there. For example: - # #0 in PyObject_Print ... - # is assumed, but sometimes this can be e.g. - # #0 0x00003fffb7dd1798 in PyObject_Print ... - 'set print address off', - - 'run'] - - # GDB as of 7.4 onwards can distinguish between the - # value of a variable at entry vs current value: - # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html - # which leads to the selftests failing with errors like this: - # AssertionError: 'v@entry=()' != '()' - # Disable this: - if (gdb_major_version, gdb_minor_version) >= (7, 4): - commands += ['set print entry-values no'] - - if cmds_after_breakpoint: - if CET_PROTECTION: - # bpo-32962: When Python is compiled with -mcet - # -fcf-protection, function arguments are unusable before - # running the first instruction of the function entry point. - # The 'next' command makes the required first step. - commands += ['next'] - commands += cmds_after_breakpoint - else: - commands += ['backtrace'] - - # print commands - - # Use "commands" to generate the arguments with which to invoke "gdb": - args = ['--eval-command=%s' % cmd for cmd in commands] - args += ["--args", - sys.executable] - args.extend(subprocess._args_from_interpreter_flags()) - - if not import_site: - # -S suppresses the default 'import site' - args += ["-S"] - - if source: - args += ["-c", source] - elif script: - args += [script] - - # Use "args" to invoke gdb, capturing stdout, stderr: - out, err = run_gdb(*args, PYTHONHASHSEED=PYTHONHASHSEED) - - if not ignore_stderr: - for line in err.splitlines(): - print(line, file=sys.stderr) - - # bpo-34007: Sometimes some versions of the shared libraries that - # are part of the traceback are compiled in optimised mode and the - # Program Counter (PC) is not present, not allowing gdb to walk the - # frames back. When this happens, the Python bindings of gdb raise - # an exception, making the test impossible to succeed. - if "PC not saved" in err: - raise unittest.SkipTest("gdb cannot walk the frame object" - " because the Program Counter is" - " not present") - - # bpo-40019: Skip the test if gdb failed to read debug information - # because the Python binary is optimized. - for pattern in ( - '(frame information optimized out)', - 'Unable to read information on python frame', - # gh-91960: On Python built with "clang -Og", gdb gets - # "frame=" for _PyEval_EvalFrameDefault() parameter - '(unable to read python frame information)', - # gh-104736: On Python built with "clang -Og" on ppc64le, - # "py-bt" displays a truncated or not traceback, but "where" - # logs this error message: - 'Backtrace stopped: frame did not save the PC', - # gh-104736: When "bt" command displays something like: - # "#1 0x0000000000000000 in ?? ()", the traceback is likely - # truncated or wrong. - ' ?? ()', - ): - if pattern in out: - raise unittest.SkipTest(f"{pattern!r} found in gdb output") - - return out - - def get_gdb_repr(self, source, - cmds_after_breakpoint=None, - import_site=False): - # Given an input python source representation of data, - # run "python -c'id(DATA)'" under gdb with a breakpoint on - # builtin_id and scrape out gdb's representation of the "op" - # parameter, and verify that the gdb displays the same string - # - # Verify that the gdb displays the expected string - # - # For a nested structure, the first time we hit the breakpoint will - # give us the top-level structure - - # NOTE: avoid decoding too much of the traceback as some - # undecodable characters may lurk there in optimized mode - # (issue #19743). - cmds_after_breakpoint = cmds_after_breakpoint or ["backtrace 1"] - gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN, - cmds_after_breakpoint=cmds_after_breakpoint, - import_site=import_site) - # gdb can insert additional '\n' and space characters in various places - # in its output, depending on the width of the terminal it's connected - # to (using its "wrap_here" function) - m = re.search( - # Match '#0 builtin_id(self=..., v=...)' - r'#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)?\)' - # Match ' at Python/bltinmodule.c'. - # bpo-38239: builtin_id() is defined in Python/bltinmodule.c, - # but accept any "Directory\file.c" to support Link Time - # Optimization (LTO). - r'\s+at\s+\S*[A-Za-z]+/[A-Za-z0-9_-]+\.c', - gdb_output, re.DOTALL) - if not m: - self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output)) - return m.group(1), gdb_output - - def assertEndsWith(self, actual, exp_end): - '''Ensure that the given "actual" string ends with "exp_end"''' - self.assertTrue(actual.endswith(exp_end), - msg='%r did not end with %r' % (actual, exp_end)) - - def assertMultilineMatches(self, actual, pattern): - m = re.match(pattern, actual, re.DOTALL) - if not m: - self.fail(msg='%r did not match %r' % (actual, pattern)) - - def get_sample_script(self): - return findfile('gdb_sample.py') - -class PrettyPrintTests(DebuggerTests): - def test_getting_backtrace(self): - gdb_output = self.get_stack_trace('id(42)') - self.assertTrue(BREAKPOINT_FN in gdb_output) - - def assertGdbRepr(self, val, exp_repr=None): - # Ensure that gdb's rendering of the value in a debugged process - # matches repr(value) in this process: - gdb_repr, gdb_output = self.get_gdb_repr('id(' + ascii(val) + ')') - if not exp_repr: - exp_repr = repr(val) - self.assertEqual(gdb_repr, exp_repr, - ('%r did not equal expected %r; full output was:\n%s' - % (gdb_repr, exp_repr, gdb_output))) - - @support.requires_resource('cpu') - def test_int(self): - 'Verify the pretty-printing of various int values' - self.assertGdbRepr(42) - self.assertGdbRepr(0) - self.assertGdbRepr(-7) - self.assertGdbRepr(1000000000000) - self.assertGdbRepr(-1000000000000000) - - def test_singletons(self): - 'Verify the pretty-printing of True, False and None' - self.assertGdbRepr(True) - self.assertGdbRepr(False) - self.assertGdbRepr(None) - - def test_dicts(self): - 'Verify the pretty-printing of dictionaries' - self.assertGdbRepr({}) - self.assertGdbRepr({'foo': 'bar'}, "{'foo': 'bar'}") - # Python preserves insertion order since 3.6 - self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, "{'foo': 'bar', 'douglas': 42}") - - def test_lists(self): - 'Verify the pretty-printing of lists' - self.assertGdbRepr([]) - self.assertGdbRepr(list(range(5))) - - @support.requires_resource('cpu') - def test_bytes(self): - 'Verify the pretty-printing of bytes' - self.assertGdbRepr(b'') - self.assertGdbRepr(b'And now for something hopefully the same') - self.assertGdbRepr(b'string with embedded NUL here \0 and then some more text') - self.assertGdbRepr(b'this is a tab:\t' - b' this is a slash-N:\n' - b' this is a slash-R:\r' - ) - - self.assertGdbRepr(b'this is byte 255:\xff and byte 128:\x80') - - self.assertGdbRepr(bytes([b for b in range(255)])) - - @support.requires_resource('cpu') - def test_strings(self): - 'Verify the pretty-printing of unicode strings' - # We cannot simply call locale.getpreferredencoding() here, - # as GDB might have been linked against a different version - # of Python with a different encoding and coercion policy - # with respect to PEP 538 and PEP 540. - out, err = run_gdb( - '--eval-command', - 'python import locale; print(locale.getpreferredencoding())') - - encoding = out.rstrip() - if err or not encoding: - raise RuntimeError( - f'unable to determine the preferred encoding ' - f'of embedded Python in GDB: {err}') - - def check_repr(text): - try: - text.encode(encoding) - except UnicodeEncodeError: - self.assertGdbRepr(text, ascii(text)) - else: - self.assertGdbRepr(text) - - self.assertGdbRepr('') - self.assertGdbRepr('And now for something hopefully the same') - self.assertGdbRepr('string with embedded NUL here \0 and then some more text') - - # Test printing a single character: - # U+2620 SKULL AND CROSSBONES - check_repr('\u2620') - - # Test printing a Japanese unicode string - # (I believe this reads "mojibake", using 3 characters from the CJK - # Unified Ideographs area, followed by U+3051 HIRAGANA LETTER KE) - check_repr('\u6587\u5b57\u5316\u3051') - - # Test a character outside the BMP: - # U+1D121 MUSICAL SYMBOL C CLEF - # This is: - # UTF-8: 0xF0 0x9D 0x84 0xA1 - # UTF-16: 0xD834 0xDD21 - check_repr(chr(0x1D121)) - - def test_tuples(self): - 'Verify the pretty-printing of tuples' - self.assertGdbRepr(tuple(), '()') - self.assertGdbRepr((1,), '(1,)') - self.assertGdbRepr(('foo', 'bar', 'baz')) - - @support.requires_resource('cpu') - def test_sets(self): - 'Verify the pretty-printing of sets' - if (gdb_major_version, gdb_minor_version) < (7, 3): - self.skipTest("pretty-printing of sets needs gdb 7.3 or later") - self.assertGdbRepr(set(), "set()") - self.assertGdbRepr(set(['a']), "{'a'}") - # PYTHONHASHSEED is need to get the exact frozenset item order - if not sys.flags.ignore_environment: - self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}") - self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}") - - # Ensure that we handle sets containing the "dummy" key value, - # which happens on deletion: - gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b']) -s.remove('a') -id(s)''') - self.assertEqual(gdb_repr, "{'b'}") - - @support.requires_resource('cpu') - def test_frozensets(self): - 'Verify the pretty-printing of frozensets' - if (gdb_major_version, gdb_minor_version) < (7, 3): - self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later") - self.assertGdbRepr(frozenset(), "frozenset()") - self.assertGdbRepr(frozenset(['a']), "frozenset({'a'})") - # PYTHONHASHSEED is need to get the exact frozenset item order - if not sys.flags.ignore_environment: - self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})") - self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})") - - def test_exceptions(self): - # Test a RuntimeError - gdb_repr, gdb_output = self.get_gdb_repr(''' -try: - raise RuntimeError("I am an error") -except RuntimeError as e: - id(e) -''') - self.assertEqual(gdb_repr, - "RuntimeError('I am an error',)") - - - # Test division by zero: - gdb_repr, gdb_output = self.get_gdb_repr(''' -try: - a = 1 / 0 -except ZeroDivisionError as e: - id(e) -''') - self.assertEqual(gdb_repr, - "ZeroDivisionError('division by zero',)") - - def test_modern_class(self): - 'Verify the pretty-printing of new-style class instances' - gdb_repr, gdb_output = self.get_gdb_repr(''' -class Foo: - pass -foo = Foo() -foo.an_int = 42 -id(foo)''') - m = re.match(r'', gdb_repr) - self.assertTrue(m, - msg='Unexpected new-style class rendering %r' % gdb_repr) - - def test_subclassing_list(self): - 'Verify the pretty-printing of an instance of a list subclass' - gdb_repr, gdb_output = self.get_gdb_repr(''' -class Foo(list): - pass -foo = Foo() -foo += [1, 2, 3] -foo.an_int = 42 -id(foo)''') - m = re.match(r'', gdb_repr) - - self.assertTrue(m, - msg='Unexpected new-style class rendering %r' % gdb_repr) - - def test_subclassing_tuple(self): - 'Verify the pretty-printing of an instance of a tuple subclass' - # This should exercise the negative tp_dictoffset code in the - # new-style class support - gdb_repr, gdb_output = self.get_gdb_repr(''' -class Foo(tuple): - pass -foo = Foo((1, 2, 3)) -foo.an_int = 42 -id(foo)''') - m = re.match(r'', gdb_repr) - - self.assertTrue(m, - msg='Unexpected new-style class rendering %r' % gdb_repr) - - def assertSane(self, source, corruption, exprepr=None): - '''Run Python under gdb, corrupting variables in the inferior process - immediately before taking a backtrace. - - Verify that the variable's representation is the expected failsafe - representation''' - if corruption: - cmds_after_breakpoint=[corruption, 'backtrace'] - else: - cmds_after_breakpoint=['backtrace'] - - gdb_repr, gdb_output = \ - self.get_gdb_repr(source, - cmds_after_breakpoint=cmds_after_breakpoint) - if exprepr: - if gdb_repr == exprepr: - # gdb managed to print the value in spite of the corruption; - # this is good (see http://bugs.python.org/issue8330) - return - - # Match anything for the type name; 0xDEADBEEF could point to - # something arbitrary (see http://bugs.python.org/issue8330) - pattern = '<.* at remote 0x-?[0-9a-f]+>' - - m = re.match(pattern, gdb_repr) - if not m: - self.fail('Unexpected gdb representation: %r\n%s' % \ - (gdb_repr, gdb_output)) - - def test_NULL_ptr(self): - 'Ensure that a NULL PyObject* is handled gracefully' - gdb_repr, gdb_output = ( - self.get_gdb_repr('id(42)', - cmds_after_breakpoint=['set variable v=0', - 'backtrace']) - ) - - self.assertEqual(gdb_repr, '0x0') - - def test_NULL_ob_type(self): - 'Ensure that a PyObject* with NULL ob_type is handled gracefully' - self.assertSane('id(42)', - 'set v->ob_type=0') - - def test_corrupt_ob_type(self): - 'Ensure that a PyObject* with a corrupt ob_type is handled gracefully' - self.assertSane('id(42)', - 'set v->ob_type=0xDEADBEEF', - exprepr='42') - - def test_corrupt_tp_flags(self): - 'Ensure that a PyObject* with a type with corrupt tp_flags is handled' - self.assertSane('id(42)', - 'set v->ob_type->tp_flags=0x0', - exprepr='42') - - def test_corrupt_tp_name(self): - 'Ensure that a PyObject* with a type with corrupt tp_name is handled' - self.assertSane('id(42)', - 'set v->ob_type->tp_name=0xDEADBEEF', - exprepr='42') - - def test_builtins_help(self): - 'Ensure that the new-style class _Helper in site.py can be handled' - - if sys.flags.no_site: - self.skipTest("need site module, but -S option was used") - - # (this was the issue causing tracebacks in - # http://bugs.python.org/issue8032#msg100537 ) - gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True) - - m = re.match(r'<_Helper\(\) at remote 0x-?[0-9a-f]+>', gdb_repr) - self.assertTrue(m, - msg='Unexpected rendering %r' % gdb_repr) - - def test_selfreferential_list(self): - '''Ensure that a reference loop involving a list doesn't lead proxyval - into an infinite loop:''' - gdb_repr, gdb_output = \ - self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; id(a)") - self.assertEqual(gdb_repr, '[3, 4, 5, [...]]') - - gdb_repr, gdb_output = \ - self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; id(a)") - self.assertEqual(gdb_repr, '[3, 4, 5, [[...]]]') - - def test_selfreferential_dict(self): - '''Ensure that a reference loop involving a dict doesn't lead proxyval - into an infinite loop:''' - gdb_repr, gdb_output = \ - self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; id(a)") - - self.assertEqual(gdb_repr, "{'foo': {'bar': {...}}}") - - def test_selfreferential_old_style_instance(self): - gdb_repr, gdb_output = \ - self.get_gdb_repr(''' -class Foo: - pass -foo = Foo() -foo.an_attr = foo -id(foo)''') - self.assertTrue(re.match(r'\) at remote 0x-?[0-9a-f]+>', - gdb_repr), - 'Unexpected gdb representation: %r\n%s' % \ - (gdb_repr, gdb_output)) - - def test_selfreferential_new_style_instance(self): - gdb_repr, gdb_output = \ - self.get_gdb_repr(''' -class Foo(object): - pass -foo = Foo() -foo.an_attr = foo -id(foo)''') - self.assertTrue(re.match(r'\) at remote 0x-?[0-9a-f]+>', - gdb_repr), - 'Unexpected gdb representation: %r\n%s' % \ - (gdb_repr, gdb_output)) - - gdb_repr, gdb_output = \ - self.get_gdb_repr(''' -class Foo(object): - pass -a = Foo() -b = Foo() -a.an_attr = b -b.an_attr = a -id(a)''') - self.assertTrue(re.match(r'\) at remote 0x-?[0-9a-f]+>\) at remote 0x-?[0-9a-f]+>', - gdb_repr), - 'Unexpected gdb representation: %r\n%s' % \ - (gdb_repr, gdb_output)) - - def test_truncation(self): - 'Verify that very long output is truncated' - gdb_repr, gdb_output = self.get_gdb_repr('id(list(range(1000)))') - self.assertEqual(gdb_repr, - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, " - "14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, " - "27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, " - "40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, " - "53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, " - "66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, " - "79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, " - "92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, " - "104, 105, 106, 107, 108, 109, 110, 111, 112, 113, " - "114, 115, 116, 117, 118, 119, 120, 121, 122, 123, " - "124, 125, 126, 127, 128, 129, 130, 131, 132, 133, " - "134, 135, 136, 137, 138, 139, 140, 141, 142, 143, " - "144, 145, 146, 147, 148, 149, 150, 151, 152, 153, " - "154, 155, 156, 157, 158, 159, 160, 161, 162, 163, " - "164, 165, 166, 167, 168, 169, 170, 171, 172, 173, " - "174, 175, 176, 177, 178, 179, 180, 181, 182, 183, " - "184, 185, 186, 187, 188, 189, 190, 191, 192, 193, " - "194, 195, 196, 197, 198, 199, 200, 201, 202, 203, " - "204, 205, 206, 207, 208, 209, 210, 211, 212, 213, " - "214, 215, 216, 217, 218, 219, 220, 221, 222, 223, " - "224, 225, 226...(truncated)") - self.assertEqual(len(gdb_repr), - 1024 + len('...(truncated)')) - - def test_builtin_method(self): - gdb_repr, gdb_output = self.get_gdb_repr('import sys; id(sys.stdout.readlines)') - self.assertTrue(re.match(r'', - gdb_repr), - 'Unexpected gdb representation: %r\n%s' % \ - (gdb_repr, gdb_output)) - - def test_frames(self): - gdb_output = self.get_stack_trace(''' -import sys -def foo(a, b, c): - return sys._getframe(0) - -f = foo(3, 4, 5) -id(f)''', - breakpoint='builtin_id', - cmds_after_breakpoint=['print (PyFrameObject*)v'] - ) - self.assertTrue(re.match(r'.*\s+\$1 =\s+Frame 0x-?[0-9a-f]+, for file , line 4, in foo \(a=3.*', - gdb_output, - re.DOTALL), - 'Unexpected gdb representation: %r\n%s' % (gdb_output, gdb_output)) - -@unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") -class PyListTests(DebuggerTests): - def assertListing(self, expected, actual): - self.assertEndsWith(actual, expected) - - def test_basic_command(self): - 'Verify that the "py-list" command works' - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-list']) - - self.assertListing(' 5 \n' - ' 6 def bar(a, b, c):\n' - ' 7 baz(a, b, c)\n' - ' 8 \n' - ' 9 def baz(*args):\n' - ' >10 id(42)\n' - ' 11 \n' - ' 12 foo(1, 2, 3)\n', - bt) - - def test_one_abs_arg(self): - 'Verify the "py-list" command with one absolute argument' - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-list 9']) - - self.assertListing(' 9 def baz(*args):\n' - ' >10 id(42)\n' - ' 11 \n' - ' 12 foo(1, 2, 3)\n', - bt) - - def test_two_abs_args(self): - 'Verify the "py-list" command with two absolute arguments' - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-list 1,3']) - - self.assertListing(' 1 # Sample script for use by test_gdb.py\n' - ' 2 \n' - ' 3 def foo(a, b, c):\n', - bt) - -SAMPLE_WITH_C_CALL = """ - -from _testcapi import pyobject_fastcall - -def foo(a, b, c): - bar(a, b, c) - -def bar(a, b, c): - pyobject_fastcall(baz, (a, b, c)) - -def baz(*args): - id(42) - -foo(1, 2, 3) - -""" - - -class StackNavigationTests(DebuggerTests): - @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - def test_pyup_command(self): - 'Verify that the "py-up" command works' - bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, - cmds_after_breakpoint=['py-up', 'py-up']) - self.assertMultilineMatches(bt, - r'''^.* -#[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) -#[0-9]+ -$''') - - @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") - def test_down_at_bottom(self): - 'Verify handling of "py-down" at the bottom of the stack' - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-down']) - self.assertEndsWith(bt, - 'Unable to find a newer python frame\n') - - @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") - def test_up_at_top(self): - 'Verify handling of "py-up" at the top of the stack' - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-up'] * 5) - self.assertEndsWith(bt, - 'Unable to find an older python frame\n') - - @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - def test_up_then_down(self): - 'Verify "py-up" followed by "py-down"' - bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, - cmds_after_breakpoint=['py-up', 'py-up', 'py-down']) - self.assertMultilineMatches(bt, - r'''^.* -#[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) -#[0-9]+ -#[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) -$''') - -class PyBtTests(DebuggerTests): - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - def test_bt(self): - 'Verify that the "py-bt" command works' - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-bt']) - self.assertMultilineMatches(bt, - r'''^.* -Traceback \(most recent call first\): - - File ".*gdb_sample.py", line 10, in baz - id\(42\) - File ".*gdb_sample.py", line 7, in bar - baz\(a, b, c\) - File ".*gdb_sample.py", line 4, in foo - bar\(a=a, b=b, c=c\) - File ".*gdb_sample.py", line 12, in - foo\(1, 2, 3\) -''') - - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - def test_bt_full(self): - 'Verify that the "py-bt-full" command works' - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-bt-full']) - self.assertMultilineMatches(bt, - r'''^.* -#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) - baz\(a, b, c\) -#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) - bar\(a=a, b=b, c=c\) -#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in \(\) - foo\(1, 2, 3\) -''') - - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - @support.requires_resource('cpu') - def test_threads(self): - 'Verify that "py-bt" indicates threads that are waiting for the GIL' - cmd = ''' -from threading import Thread - -class TestThread(Thread): - # These threads would run forever, but we'll interrupt things with the - # debugger - def run(self): - i = 0 - while 1: - i += 1 - -t = {} -for i in range(4): - t[i] = TestThread() - t[i].start() - -# Trigger a breakpoint on the main thread -id(42) - -''' - # Verify with "py-bt": - gdb_output = self.get_stack_trace(cmd, - cmds_after_breakpoint=['thread apply all py-bt']) - self.assertIn('Waiting for the GIL', gdb_output) - - # Verify with "py-bt-full": - gdb_output = self.get_stack_trace(cmd, - cmds_after_breakpoint=['thread apply all py-bt-full']) - self.assertIn('Waiting for the GIL', gdb_output) - - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - # Some older versions of gdb will fail with - # "Cannot find new threads: generic error" - # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround - def test_gc(self): - 'Verify that "py-bt" indicates if a thread is garbage-collecting' - cmd = ('from gc import collect\n' - 'id(42)\n' - 'def foo():\n' - ' collect()\n' - 'def bar():\n' - ' foo()\n' - 'bar()\n') - # Verify with "py-bt": - gdb_output = self.get_stack_trace(cmd, - cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'], - ) - self.assertIn('Garbage-collecting', gdb_output) - - # Verify with "py-bt-full": - gdb_output = self.get_stack_trace(cmd, - cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'], - ) - self.assertIn('Garbage-collecting', gdb_output) - - - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - @support.requires_resource('cpu') - # Some older versions of gdb will fail with - # "Cannot find new threads: generic error" - # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround - # - # gdb will also generate many erroneous errors such as: - # Function "meth_varargs" not defined. - # This is because we are calling functions from an "external" module - # (_testcapimodule) rather than compiled-in functions. It seems difficult - # to suppress these. See also the comment in DebuggerTests.get_stack_trace - def test_pycfunction(self): - 'Verify that "py-bt" displays invocations of PyCFunction instances' - # bpo-46600: If the compiler inlines _null_to_none() in meth_varargs() - # (ex: clang -Og), _null_to_none() is the frame #1. Otherwise, - # meth_varargs() is the frame #1. - expected_frame = r'#(1|2)' - # Various optimizations multiply the code paths by which these are - # called, so test a variety of calling conventions. - for func_name, args in ( - ('meth_varargs', ''), - ('meth_varargs_keywords', ''), - ('meth_o', '[]'), - ('meth_noargs', ''), - ('meth_fastcall', ''), - ('meth_fastcall_keywords', ''), - ): - for obj in ( - '_testcapi', - '_testcapi.MethClass', - '_testcapi.MethClass()', - '_testcapi.MethStatic()', - - # XXX: bound methods don't yet give nice tracebacks - # '_testcapi.MethInstance()', - ): - with self.subTest(f'{obj}.{func_name}'): - cmd = textwrap.dedent(f''' - import _testcapi - def foo(): - {obj}.{func_name}({args}) - def bar(): - foo() - bar() - ''') - # Verify with "py-bt": - gdb_output = self.get_stack_trace( - cmd, - breakpoint=func_name, - cmds_after_breakpoint=['bt', 'py-bt'], - # bpo-45207: Ignore 'Function "meth_varargs" not - # defined.' message in stderr. - ignore_stderr=True, - ) - self.assertIn(f'\n.*") - -class PyLocalsTests(DebuggerTests): - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - def test_basic_command(self): - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-up', 'py-locals']) - self.assertMultilineMatches(bt, - r".*\nargs = \(1, 2, 3\)\n.*") - - @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") - @unittest.skipIf(python_is_optimized(), - "Python was compiled with optimizations") - def test_locals_after_up(self): - bt = self.get_stack_trace(script=self.get_sample_script(), - cmds_after_breakpoint=['py-up', 'py-up', 'py-locals']) - self.assertMultilineMatches(bt, - r'''^.* -Locals for foo -a = 1 -b = 2 -c = 3 -Locals for -.*$''') - - -def setUpModule(): - if support.verbose: - print("GDB version %s.%s:" % (gdb_major_version, gdb_minor_version)) - for line in gdb_version.splitlines(): - print(" " * 4 + line) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_gdb/__init__.py b/Lib/test/test_gdb/__init__.py new file mode 100644 index 00000000000000..0261f59adf54bd --- /dev/null +++ b/Lib/test/test_gdb/__init__.py @@ -0,0 +1,10 @@ +# Verify that gdb can pretty-print the various PyObject* types +# +# The code for testing gdb was adapted from similar work in Unladen Swallow's +# Lib/test/test_jit_gdb.py + +import os +from test.support import load_package_tests + +def load_tests(*args): + return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/gdb_sample.py b/Lib/test/test_gdb/gdb_sample.py similarity index 75% rename from Lib/test/gdb_sample.py rename to Lib/test/test_gdb/gdb_sample.py index 4188f50136fb97..a7f23db73ea6e6 100644 --- a/Lib/test/gdb_sample.py +++ b/Lib/test/test_gdb/gdb_sample.py @@ -1,4 +1,4 @@ -# Sample script for use by test_gdb.py +# Sample script for use by test_gdb def foo(a, b, c): bar(a=a, b=b, c=c) diff --git a/Lib/test/test_gdb/test_backtrace.py b/Lib/test/test_gdb/test_backtrace.py new file mode 100644 index 00000000000000..15cbcf169ab9e3 --- /dev/null +++ b/Lib/test/test_gdb/test_backtrace.py @@ -0,0 +1,134 @@ +import textwrap +import unittest +from test import support +from test.support import python_is_optimized + +from .util import setup_module, DebuggerTests, CET_PROTECTION + + +def setUpModule(): + setup_module() + + +class PyBtTests(DebuggerTests): + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_bt(self): + 'Verify that the "py-bt" command works' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-bt']) + self.assertMultilineMatches(bt, + r'''^.* +Traceback \(most recent call first\): + + File ".*gdb_sample.py", line 10, in baz + id\(42\) + File ".*gdb_sample.py", line 7, in bar + baz\(a, b, c\) + File ".*gdb_sample.py", line 4, in foo + bar\(a=a, b=b, c=c\) + File ".*gdb_sample.py", line 12, in + foo\(1, 2, 3\) +''') + + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_bt_full(self): + 'Verify that the "py-bt-full" command works' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-bt-full']) + self.assertMultilineMatches(bt, + r'''^.* +#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) + baz\(a, b, c\) +#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) + bar\(a=a, b=b, c=c\) +#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in \(\) + foo\(1, 2, 3\) +''') + + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + @support.requires_resource('cpu') + def test_threads(self): + 'Verify that "py-bt" indicates threads that are waiting for the GIL' + cmd = ''' +from threading import Thread + +class TestThread(Thread): + # These threads would run forever, but we'll interrupt things with the + # debugger + def run(self): + i = 0 + while 1: + i += 1 + +t = {} +for i in range(4): + t[i] = TestThread() + t[i].start() + +# Trigger a breakpoint on the main thread +id(42) + +''' + # Verify with "py-bt": + gdb_output = self.get_stack_trace(cmd, + cmds_after_breakpoint=['thread apply all py-bt']) + self.assertIn('Waiting for the GIL', gdb_output) + + # Verify with "py-bt-full": + gdb_output = self.get_stack_trace(cmd, + cmds_after_breakpoint=['thread apply all py-bt-full']) + self.assertIn('Waiting for the GIL', gdb_output) + + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + # Some older versions of gdb will fail with + # "Cannot find new threads: generic error" + # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround + def test_gc(self): + 'Verify that "py-bt" indicates if a thread is garbage-collecting' + cmd = ('from gc import collect\n' + 'id(42)\n' + 'def foo():\n' + ' collect()\n' + 'def bar():\n' + ' foo()\n' + 'bar()\n') + # Verify with "py-bt": + gdb_output = self.get_stack_trace(cmd, + cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'], + ) + self.assertIn('Garbage-collecting', gdb_output) + + # Verify with "py-bt-full": + gdb_output = self.get_stack_trace(cmd, + cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'], + ) + self.assertIn('Garbage-collecting', gdb_output) + + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_wrapper_call(self): + cmd = textwrap.dedent(''' + class MyList(list): + def __init__(self): + super(*[]).__init__() # wrapper_call() + + id("first break point") + l = MyList() + ''') + cmds_after_breakpoint = ['break wrapper_call', 'continue'] + if CET_PROTECTION: + # bpo-32962: same case as in get_stack_trace(): + # we need an additional 'next' command in order to read + # arguments of the innermost function of the call stack. + cmds_after_breakpoint.append('next') + cmds_after_breakpoint.append('py-bt') + + # Verify with "py-bt": + gdb_output = self.get_stack_trace(cmd, + cmds_after_breakpoint=cmds_after_breakpoint) + self.assertRegex(gdb_output, + r"10 id(42)\n' + ' 11 \n' + ' 12 foo(1, 2, 3)\n', + bt) + + def test_one_abs_arg(self): + 'Verify the "py-list" command with one absolute argument' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-list 9']) + + self.assertListing(' 9 def baz(*args):\n' + ' >10 id(42)\n' + ' 11 \n' + ' 12 foo(1, 2, 3)\n', + bt) + + def test_two_abs_args(self): + 'Verify the "py-list" command with two absolute arguments' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-list 1,3']) + + self.assertListing(' 1 # Sample script for use by test_gdb\n' + ' 2 \n' + ' 3 def foo(a, b, c):\n', + bt) + +SAMPLE_WITH_C_CALL = """ + +from _testcapi import pyobject_vectorcall + +def foo(a, b, c): + bar(a, b, c) + +def bar(a, b, c): + pyobject_vectorcall(baz, (a, b, c), None) + +def baz(*args): + id(42) + +foo(1, 2, 3) + +""" + + +class StackNavigationTests(DebuggerTests): + @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_pyup_command(self): + 'Verify that the "py-up" command works' + bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, + cmds_after_breakpoint=['py-up', 'py-up']) + self.assertMultilineMatches(bt, + r'''^.* +#[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) +#[0-9]+ +$''') + + @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") + def test_down_at_bottom(self): + 'Verify handling of "py-down" at the bottom of the stack' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-down']) + self.assertEndsWith(bt, + 'Unable to find a newer python frame\n') + + @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") + def test_up_at_top(self): + 'Verify handling of "py-up" at the top of the stack' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-up'] * 5) + self.assertEndsWith(bt, + 'Unable to find an older python frame\n') + + @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_up_then_down(self): + 'Verify "py-up" followed by "py-down"' + bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, + cmds_after_breakpoint=['py-up', 'py-up', 'py-down']) + self.assertMultilineMatches(bt, + r'''^.* +#[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) +#[0-9]+ +#[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) +$''') + +class PyPrintTests(DebuggerTests): + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_basic_command(self): + 'Verify that the "py-print" command works' + bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, + cmds_after_breakpoint=['py-up', 'py-print args']) + self.assertMultilineMatches(bt, + r".*\nlocal 'args' = \(1, 2, 3\)\n.*") + + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") + def test_print_after_up(self): + bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, + cmds_after_breakpoint=['py-up', 'py-up', 'py-print c', 'py-print b', 'py-print a']) + self.assertMultilineMatches(bt, + r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*") + + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_printing_global(self): + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-up', 'py-print __name__']) + self.assertMultilineMatches(bt, + r".*\nglobal '__name__' = '__main__'\n.*") + + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_printing_builtin(self): + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-up', 'py-print len']) + self.assertMultilineMatches(bt, + r".*\nbuiltin 'len' = \n.*") + +class PyLocalsTests(DebuggerTests): + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_basic_command(self): + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-up', 'py-locals']) + self.assertMultilineMatches(bt, + r".*\nargs = \(1, 2, 3\)\n.*") + + @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") + @unittest.skipIf(python_is_optimized(), + "Python was compiled with optimizations") + def test_locals_after_up(self): + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-up', 'py-up', 'py-locals']) + self.assertMultilineMatches(bt, + r'''^.* +Locals for foo +a = 1 +b = 2 +c = 3 +Locals for +.*$''') diff --git a/Lib/test/test_gdb/test_pretty_print.py b/Lib/test/test_gdb/test_pretty_print.py new file mode 100644 index 00000000000000..e31dc66f29684a --- /dev/null +++ b/Lib/test/test_gdb/test_pretty_print.py @@ -0,0 +1,400 @@ +import re +import sys +from test import support + +from .util import ( + BREAKPOINT_FN, gdb_major_version, gdb_minor_version, + run_gdb, setup_module, DebuggerTests) + + +def setUpModule(): + setup_module() + + +class PrettyPrintTests(DebuggerTests): + def test_getting_backtrace(self): + gdb_output = self.get_stack_trace('id(42)') + self.assertTrue(BREAKPOINT_FN in gdb_output) + + def assertGdbRepr(self, val, exp_repr=None): + # Ensure that gdb's rendering of the value in a debugged process + # matches repr(value) in this process: + gdb_repr, gdb_output = self.get_gdb_repr('id(' + ascii(val) + ')') + if not exp_repr: + exp_repr = repr(val) + self.assertEqual(gdb_repr, exp_repr, + ('%r did not equal expected %r; full output was:\n%s' + % (gdb_repr, exp_repr, gdb_output))) + + @support.requires_resource('cpu') + def test_int(self): + 'Verify the pretty-printing of various int values' + self.assertGdbRepr(42) + self.assertGdbRepr(0) + self.assertGdbRepr(-7) + self.assertGdbRepr(1000000000000) + self.assertGdbRepr(-1000000000000000) + + def test_singletons(self): + 'Verify the pretty-printing of True, False and None' + self.assertGdbRepr(True) + self.assertGdbRepr(False) + self.assertGdbRepr(None) + + def test_dicts(self): + 'Verify the pretty-printing of dictionaries' + self.assertGdbRepr({}) + self.assertGdbRepr({'foo': 'bar'}, "{'foo': 'bar'}") + # Python preserves insertion order since 3.6 + self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, "{'foo': 'bar', 'douglas': 42}") + + def test_lists(self): + 'Verify the pretty-printing of lists' + self.assertGdbRepr([]) + self.assertGdbRepr(list(range(5))) + + @support.requires_resource('cpu') + def test_bytes(self): + 'Verify the pretty-printing of bytes' + self.assertGdbRepr(b'') + self.assertGdbRepr(b'And now for something hopefully the same') + self.assertGdbRepr(b'string with embedded NUL here \0 and then some more text') + self.assertGdbRepr(b'this is a tab:\t' + b' this is a slash-N:\n' + b' this is a slash-R:\r' + ) + + self.assertGdbRepr(b'this is byte 255:\xff and byte 128:\x80') + + self.assertGdbRepr(bytes([b for b in range(255)])) + + @support.requires_resource('cpu') + def test_strings(self): + 'Verify the pretty-printing of unicode strings' + # We cannot simply call locale.getpreferredencoding() here, + # as GDB might have been linked against a different version + # of Python with a different encoding and coercion policy + # with respect to PEP 538 and PEP 540. + out, err = run_gdb( + '--eval-command', + 'python import locale; print(locale.getpreferredencoding())') + + encoding = out.rstrip() + if err or not encoding: + raise RuntimeError( + f'unable to determine the preferred encoding ' + f'of embedded Python in GDB: {err}') + + def check_repr(text): + try: + text.encode(encoding) + except UnicodeEncodeError: + self.assertGdbRepr(text, ascii(text)) + else: + self.assertGdbRepr(text) + + self.assertGdbRepr('') + self.assertGdbRepr('And now for something hopefully the same') + self.assertGdbRepr('string with embedded NUL here \0 and then some more text') + + # Test printing a single character: + # U+2620 SKULL AND CROSSBONES + check_repr('\u2620') + + # Test printing a Japanese unicode string + # (I believe this reads "mojibake", using 3 characters from the CJK + # Unified Ideographs area, followed by U+3051 HIRAGANA LETTER KE) + check_repr('\u6587\u5b57\u5316\u3051') + + # Test a character outside the BMP: + # U+1D121 MUSICAL SYMBOL C CLEF + # This is: + # UTF-8: 0xF0 0x9D 0x84 0xA1 + # UTF-16: 0xD834 0xDD21 + check_repr(chr(0x1D121)) + + def test_tuples(self): + 'Verify the pretty-printing of tuples' + self.assertGdbRepr(tuple(), '()') + self.assertGdbRepr((1,), '(1,)') + self.assertGdbRepr(('foo', 'bar', 'baz')) + + @support.requires_resource('cpu') + def test_sets(self): + 'Verify the pretty-printing of sets' + if (gdb_major_version, gdb_minor_version) < (7, 3): + self.skipTest("pretty-printing of sets needs gdb 7.3 or later") + self.assertGdbRepr(set(), "set()") + self.assertGdbRepr(set(['a']), "{'a'}") + # PYTHONHASHSEED is need to get the exact frozenset item order + if not sys.flags.ignore_environment: + self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}") + self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}") + + # Ensure that we handle sets containing the "dummy" key value, + # which happens on deletion: + gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b']) +s.remove('a') +id(s)''') + self.assertEqual(gdb_repr, "{'b'}") + + @support.requires_resource('cpu') + def test_frozensets(self): + 'Verify the pretty-printing of frozensets' + if (gdb_major_version, gdb_minor_version) < (7, 3): + self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later") + self.assertGdbRepr(frozenset(), "frozenset()") + self.assertGdbRepr(frozenset(['a']), "frozenset({'a'})") + # PYTHONHASHSEED is need to get the exact frozenset item order + if not sys.flags.ignore_environment: + self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})") + self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})") + + def test_exceptions(self): + # Test a RuntimeError + gdb_repr, gdb_output = self.get_gdb_repr(''' +try: + raise RuntimeError("I am an error") +except RuntimeError as e: + id(e) +''') + self.assertEqual(gdb_repr, + "RuntimeError('I am an error',)") + + + # Test division by zero: + gdb_repr, gdb_output = self.get_gdb_repr(''' +try: + a = 1 / 0 +except ZeroDivisionError as e: + id(e) +''') + self.assertEqual(gdb_repr, + "ZeroDivisionError('division by zero',)") + + def test_modern_class(self): + 'Verify the pretty-printing of new-style class instances' + gdb_repr, gdb_output = self.get_gdb_repr(''' +class Foo: + pass +foo = Foo() +foo.an_int = 42 +id(foo)''') + m = re.match(r'', gdb_repr) + self.assertTrue(m, + msg='Unexpected new-style class rendering %r' % gdb_repr) + + def test_subclassing_list(self): + 'Verify the pretty-printing of an instance of a list subclass' + gdb_repr, gdb_output = self.get_gdb_repr(''' +class Foo(list): + pass +foo = Foo() +foo += [1, 2, 3] +foo.an_int = 42 +id(foo)''') + m = re.match(r'', gdb_repr) + + self.assertTrue(m, + msg='Unexpected new-style class rendering %r' % gdb_repr) + + def test_subclassing_tuple(self): + 'Verify the pretty-printing of an instance of a tuple subclass' + # This should exercise the negative tp_dictoffset code in the + # new-style class support + gdb_repr, gdb_output = self.get_gdb_repr(''' +class Foo(tuple): + pass +foo = Foo((1, 2, 3)) +foo.an_int = 42 +id(foo)''') + m = re.match(r'', gdb_repr) + + self.assertTrue(m, + msg='Unexpected new-style class rendering %r' % gdb_repr) + + def assertSane(self, source, corruption, exprepr=None): + '''Run Python under gdb, corrupting variables in the inferior process + immediately before taking a backtrace. + + Verify that the variable's representation is the expected failsafe + representation''' + if corruption: + cmds_after_breakpoint=[corruption, 'backtrace'] + else: + cmds_after_breakpoint=['backtrace'] + + gdb_repr, gdb_output = \ + self.get_gdb_repr(source, + cmds_after_breakpoint=cmds_after_breakpoint) + if exprepr: + if gdb_repr == exprepr: + # gdb managed to print the value in spite of the corruption; + # this is good (see http://bugs.python.org/issue8330) + return + + # Match anything for the type name; 0xDEADBEEF could point to + # something arbitrary (see http://bugs.python.org/issue8330) + pattern = '<.* at remote 0x-?[0-9a-f]+>' + + m = re.match(pattern, gdb_repr) + if not m: + self.fail('Unexpected gdb representation: %r\n%s' % \ + (gdb_repr, gdb_output)) + + def test_NULL_ptr(self): + 'Ensure that a NULL PyObject* is handled gracefully' + gdb_repr, gdb_output = ( + self.get_gdb_repr('id(42)', + cmds_after_breakpoint=['set variable v=0', + 'backtrace']) + ) + + self.assertEqual(gdb_repr, '0x0') + + def test_NULL_ob_type(self): + 'Ensure that a PyObject* with NULL ob_type is handled gracefully' + self.assertSane('id(42)', + 'set v->ob_type=0') + + def test_corrupt_ob_type(self): + 'Ensure that a PyObject* with a corrupt ob_type is handled gracefully' + self.assertSane('id(42)', + 'set v->ob_type=0xDEADBEEF', + exprepr='42') + + def test_corrupt_tp_flags(self): + 'Ensure that a PyObject* with a type with corrupt tp_flags is handled' + self.assertSane('id(42)', + 'set v->ob_type->tp_flags=0x0', + exprepr='42') + + def test_corrupt_tp_name(self): + 'Ensure that a PyObject* with a type with corrupt tp_name is handled' + self.assertSane('id(42)', + 'set v->ob_type->tp_name=0xDEADBEEF', + exprepr='42') + + def test_builtins_help(self): + 'Ensure that the new-style class _Helper in site.py can be handled' + + if sys.flags.no_site: + self.skipTest("need site module, but -S option was used") + + # (this was the issue causing tracebacks in + # http://bugs.python.org/issue8032#msg100537 ) + gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True) + + m = re.match(r'<_Helper\(\) at remote 0x-?[0-9a-f]+>', gdb_repr) + self.assertTrue(m, + msg='Unexpected rendering %r' % gdb_repr) + + def test_selfreferential_list(self): + '''Ensure that a reference loop involving a list doesn't lead proxyval + into an infinite loop:''' + gdb_repr, gdb_output = \ + self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; id(a)") + self.assertEqual(gdb_repr, '[3, 4, 5, [...]]') + + gdb_repr, gdb_output = \ + self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; id(a)") + self.assertEqual(gdb_repr, '[3, 4, 5, [[...]]]') + + def test_selfreferential_dict(self): + '''Ensure that a reference loop involving a dict doesn't lead proxyval + into an infinite loop:''' + gdb_repr, gdb_output = \ + self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; id(a)") + + self.assertEqual(gdb_repr, "{'foo': {'bar': {...}}}") + + def test_selfreferential_old_style_instance(self): + gdb_repr, gdb_output = \ + self.get_gdb_repr(''' +class Foo: + pass +foo = Foo() +foo.an_attr = foo +id(foo)''') + self.assertTrue(re.match(r'\) at remote 0x-?[0-9a-f]+>', + gdb_repr), + 'Unexpected gdb representation: %r\n%s' % \ + (gdb_repr, gdb_output)) + + def test_selfreferential_new_style_instance(self): + gdb_repr, gdb_output = \ + self.get_gdb_repr(''' +class Foo(object): + pass +foo = Foo() +foo.an_attr = foo +id(foo)''') + self.assertTrue(re.match(r'\) at remote 0x-?[0-9a-f]+>', + gdb_repr), + 'Unexpected gdb representation: %r\n%s' % \ + (gdb_repr, gdb_output)) + + gdb_repr, gdb_output = \ + self.get_gdb_repr(''' +class Foo(object): + pass +a = Foo() +b = Foo() +a.an_attr = b +b.an_attr = a +id(a)''') + self.assertTrue(re.match(r'\) at remote 0x-?[0-9a-f]+>\) at remote 0x-?[0-9a-f]+>', + gdb_repr), + 'Unexpected gdb representation: %r\n%s' % \ + (gdb_repr, gdb_output)) + + def test_truncation(self): + 'Verify that very long output is truncated' + gdb_repr, gdb_output = self.get_gdb_repr('id(list(range(1000)))') + self.assertEqual(gdb_repr, + "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, " + "14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, " + "27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, " + "40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, " + "53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, " + "66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, " + "79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, " + "92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, " + "104, 105, 106, 107, 108, 109, 110, 111, 112, 113, " + "114, 115, 116, 117, 118, 119, 120, 121, 122, 123, " + "124, 125, 126, 127, 128, 129, 130, 131, 132, 133, " + "134, 135, 136, 137, 138, 139, 140, 141, 142, 143, " + "144, 145, 146, 147, 148, 149, 150, 151, 152, 153, " + "154, 155, 156, 157, 158, 159, 160, 161, 162, 163, " + "164, 165, 166, 167, 168, 169, 170, 171, 172, 173, " + "174, 175, 176, 177, 178, 179, 180, 181, 182, 183, " + "184, 185, 186, 187, 188, 189, 190, 191, 192, 193, " + "194, 195, 196, 197, 198, 199, 200, 201, 202, 203, " + "204, 205, 206, 207, 208, 209, 210, 211, 212, 213, " + "214, 215, 216, 217, 218, 219, 220, 221, 222, 223, " + "224, 225, 226...(truncated)") + self.assertEqual(len(gdb_repr), + 1024 + len('...(truncated)')) + + def test_builtin_method(self): + gdb_repr, gdb_output = self.get_gdb_repr('import sys; id(sys.stdout.readlines)') + self.assertTrue(re.match(r'', + gdb_repr), + 'Unexpected gdb representation: %r\n%s' % \ + (gdb_repr, gdb_output)) + + def test_frames(self): + gdb_output = self.get_stack_trace(''' +import sys +def foo(a, b, c): + return sys._getframe(0) + +f = foo(3, 4, 5) +id(f)''', + breakpoint='builtin_id', + cmds_after_breakpoint=['print (PyFrameObject*)v'] + ) + self.assertTrue(re.match(r'.*\s+\$1 =\s+Frame 0x-?[0-9a-f]+, for file , line 4, in foo \(a=3.*', + gdb_output, + re.DOTALL), + 'Unexpected gdb representation: %r\n%s' % (gdb_output, gdb_output)) diff --git a/Lib/test/test_gdb/util.py b/Lib/test/test_gdb/util.py new file mode 100644 index 00000000000000..30beb4e14285c7 --- /dev/null +++ b/Lib/test/test_gdb/util.py @@ -0,0 +1,304 @@ +import os +import re +import subprocess +import sys +import sysconfig +import unittest +from test import support + + +MS_WINDOWS = (sys.platform == 'win32') +if MS_WINDOWS: + raise unittest.SkipTest("test_gdb doesn't work on Windows") + + +def get_gdb_version(): + try: + cmd = ["gdb", "-nx", "--version"] + proc = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + with proc: + version, stderr = proc.communicate() + + if proc.returncode: + raise Exception(f"Command {' '.join(cmd)!r} failed " + f"with exit code {proc.returncode}: " + f"stdout={version!r} stderr={stderr!r}") + except OSError: + # This is what "no gdb" looks like. There may, however, be other + # errors that manifest this way too. + raise unittest.SkipTest("Couldn't find gdb on the path") + + # Regex to parse: + # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7 + # 'GNU gdb (GDB) Fedora 7.9.1-17.fc22\n' -> 7.9 + # 'GNU gdb 6.1.1 [FreeBSD]\n' -> 6.1 + # 'GNU gdb (GDB) Fedora (7.5.1-37.fc18)\n' -> 7.5 + # 'HP gdb 6.7 for HP Itanium (32 or 64 bit) and target HP-UX 11iv2 and 11iv3.\n' -> 6.7 + match = re.search(r"^(?:GNU|HP) gdb.*?\b(\d+)\.(\d+)", version) + if match is None: + raise Exception("unable to parse GDB version: %r" % version) + return (version, int(match.group(1)), int(match.group(2))) + +gdb_version, gdb_major_version, gdb_minor_version = get_gdb_version() +if gdb_major_version < 7: + raise unittest.SkipTest("gdb versions before 7.0 didn't support python " + "embedding. Saw %s.%s:\n%s" + % (gdb_major_version, gdb_minor_version, + gdb_version)) + +if not sysconfig.is_python_build(): + raise unittest.SkipTest("test_gdb only works on source builds at the moment.") + +if ((sysconfig.get_config_var('PGO_PROF_USE_FLAG') or 'xxx') in + (sysconfig.get_config_var('PY_CORE_CFLAGS') or '')): + raise unittest.SkipTest("test_gdb is not reliable on PGO builds") + +# Location of custom hooks file in a repository checkout. +checkout_hook_path = os.path.join(os.path.dirname(sys.executable), + 'python-gdb.py') + +PYTHONHASHSEED = '123' + + +def cet_protection(): + cflags = sysconfig.get_config_var('CFLAGS') + if not cflags: + return False + flags = cflags.split() + # True if "-mcet -fcf-protection" options are found, but false + # if "-fcf-protection=none" or "-fcf-protection=return" is found. + return (('-mcet' in flags) + and any((flag.startswith('-fcf-protection') + and not flag.endswith(("=none", "=return"))) + for flag in flags)) + +# Control-flow enforcement technology +CET_PROTECTION = cet_protection() + + +def run_gdb(*args, **env_vars): + """Runs gdb in --batch mode with the additional arguments given by *args. + + Returns its (stdout, stderr) decoded from utf-8 using the replace handler. + """ + if env_vars: + env = os.environ.copy() + env.update(env_vars) + else: + env = None + # -nx: Do not execute commands from any .gdbinit initialization files + # (issue #22188) + base_cmd = ('gdb', '--batch', '-nx') + if (gdb_major_version, gdb_minor_version) >= (7, 4): + base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path) + proc = subprocess.Popen(base_cmd + args, + # Redirect stdin to prevent GDB from messing with + # the terminal settings + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env) + with proc: + out, err = proc.communicate() + return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') + +# Verify that "gdb" was built with the embedded python support enabled: +gdbpy_version, _ = run_gdb("--eval-command=python import sys; print(sys.version_info)") +if not gdbpy_version: + raise unittest.SkipTest("gdb not built with embedded python support") + +if "major=2" in gdbpy_version: + raise unittest.SkipTest("gdb built with Python 2") + +# Verify that "gdb" can load our custom hooks, as OS security settings may +# disallow this without a customized .gdbinit. +_, gdbpy_errors = run_gdb('--args', sys.executable) +if "auto-loading has been declined" in gdbpy_errors: + msg = "gdb security settings prevent use of custom hooks: " + raise unittest.SkipTest(msg + gdbpy_errors.rstrip()) + +BREAKPOINT_FN='builtin_id' + + +def setup_module(): + if support.verbose: + print("GDB version %s.%s:" % (gdb_major_version, gdb_minor_version)) + for line in gdb_version.splitlines(): + print(" " * 4 + line) + + +@unittest.skipIf(support.PGO, "not useful for PGO") +class DebuggerTests(unittest.TestCase): + + """Test that the debugger can debug Python.""" + + def get_stack_trace(self, source=None, script=None, + breakpoint=BREAKPOINT_FN, + cmds_after_breakpoint=None, + import_site=False, + ignore_stderr=False): + ''' + Run 'python -c SOURCE' under gdb with a breakpoint. + + Support injecting commands after the breakpoint is reached + + Returns the stdout from gdb + + cmds_after_breakpoint: if provided, a list of strings: gdb commands + ''' + # We use "set breakpoint pending yes" to avoid blocking with a: + # Function "foo" not defined. + # Make breakpoint pending on future shared library load? (y or [n]) + # error, which typically happens python is dynamically linked (the + # breakpoints of interest are to be found in the shared library) + # When this happens, we still get: + # Function "textiowrapper_write" not defined. + # emitted to stderr each time, alas. + + # Initially I had "--eval-command=continue" here, but removed it to + # avoid repeated print breakpoints when traversing hierarchical data + # structures + + # Generate a list of commands in gdb's language: + commands = ['set breakpoint pending yes', + 'break %s' % breakpoint, + + # The tests assume that the first frame of printed + # backtrace will not contain program counter, + # that is however not guaranteed by gdb + # therefore we need to use 'set print address off' to + # make sure the counter is not there. For example: + # #0 in PyObject_Print ... + # is assumed, but sometimes this can be e.g. + # #0 0x00003fffb7dd1798 in PyObject_Print ... + 'set print address off', + + 'run'] + + # GDB as of 7.4 onwards can distinguish between the + # value of a variable at entry vs current value: + # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html + # which leads to the selftests failing with errors like this: + # AssertionError: 'v@entry=()' != '()' + # Disable this: + if (gdb_major_version, gdb_minor_version) >= (7, 4): + commands += ['set print entry-values no'] + + if cmds_after_breakpoint: + if CET_PROTECTION: + # bpo-32962: When Python is compiled with -mcet + # -fcf-protection, function arguments are unusable before + # running the first instruction of the function entry point. + # The 'next' command makes the required first step. + commands += ['next'] + commands += cmds_after_breakpoint + else: + commands += ['backtrace'] + + # print commands + + # Use "commands" to generate the arguments with which to invoke "gdb": + args = ['--eval-command=%s' % cmd for cmd in commands] + args += ["--args", + sys.executable] + args.extend(subprocess._args_from_interpreter_flags()) + + if not import_site: + # -S suppresses the default 'import site' + args += ["-S"] + + if source: + args += ["-c", source] + elif script: + args += [script] + + # Use "args" to invoke gdb, capturing stdout, stderr: + out, err = run_gdb(*args, PYTHONHASHSEED=PYTHONHASHSEED) + + if not ignore_stderr: + for line in err.splitlines(): + print(line, file=sys.stderr) + + # bpo-34007: Sometimes some versions of the shared libraries that + # are part of the traceback are compiled in optimised mode and the + # Program Counter (PC) is not present, not allowing gdb to walk the + # frames back. When this happens, the Python bindings of gdb raise + # an exception, making the test impossible to succeed. + if "PC not saved" in err: + raise unittest.SkipTest("gdb cannot walk the frame object" + " because the Program Counter is" + " not present") + + # bpo-40019: Skip the test if gdb failed to read debug information + # because the Python binary is optimized. + for pattern in ( + '(frame information optimized out)', + 'Unable to read information on python frame', + # gh-91960: On Python built with "clang -Og", gdb gets + # "frame=" for _PyEval_EvalFrameDefault() parameter + '(unable to read python frame information)', + # gh-104736: On Python built with "clang -Og" on ppc64le, + # "py-bt" displays a truncated or not traceback, but "where" + # logs this error message: + 'Backtrace stopped: frame did not save the PC', + # gh-104736: When "bt" command displays something like: + # "#1 0x0000000000000000 in ?? ()", the traceback is likely + # truncated or wrong. + ' ?? ()', + ): + if pattern in out: + raise unittest.SkipTest(f"{pattern!r} found in gdb output") + + return out + + def get_gdb_repr(self, source, + cmds_after_breakpoint=None, + import_site=False): + # Given an input python source representation of data, + # run "python -c'id(DATA)'" under gdb with a breakpoint on + # builtin_id and scrape out gdb's representation of the "op" + # parameter, and verify that the gdb displays the same string + # + # Verify that the gdb displays the expected string + # + # For a nested structure, the first time we hit the breakpoint will + # give us the top-level structure + + # NOTE: avoid decoding too much of the traceback as some + # undecodable characters may lurk there in optimized mode + # (issue #19743). + cmds_after_breakpoint = cmds_after_breakpoint or ["backtrace 1"] + gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN, + cmds_after_breakpoint=cmds_after_breakpoint, + import_site=import_site) + # gdb can insert additional '\n' and space characters in various places + # in its output, depending on the width of the terminal it's connected + # to (using its "wrap_here" function) + m = re.search( + # Match '#0 builtin_id(self=..., v=...)' + r'#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)?\)' + # Match ' at Python/bltinmodule.c'. + # bpo-38239: builtin_id() is defined in Python/bltinmodule.c, + # but accept any "Directory\file.c" to support Link Time + # Optimization (LTO). + r'\s+at\s+\S*[A-Za-z]+/[A-Za-z0-9_-]+\.c', + gdb_output, re.DOTALL) + if not m: + self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output)) + return m.group(1), gdb_output + + def assertEndsWith(self, actual, exp_end): + '''Ensure that the given "actual" string ends with "exp_end"''' + self.assertTrue(actual.endswith(exp_end), + msg='%r did not end with %r' % (actual, exp_end)) + + def assertMultilineMatches(self, actual, pattern): + m = re.match(pattern, actual, re.DOTALL) + if not m: + self.fail(msg='%r did not match %r' % (actual, pattern)) + + def get_sample_script(self): + return os.path.join(os.path.dirname(__file__), 'gdb_sample.py') diff --git a/Makefile.pre.in b/Makefile.pre.in index 2599d20a111868..a2e8458b62c989 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2138,6 +2138,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_email \ test/test_email/data \ test/test_future_stmt \ + test/test_gdb \ test/test_import \ test/test_import/data \ test/test_import/data/circular_imports \ diff --git a/Misc/NEWS.d/next/Tests/2023-09-28-12-25-19.gh-issue-109972.GYnwIP.rst b/Misc/NEWS.d/next/Tests/2023-09-28-12-25-19.gh-issue-109972.GYnwIP.rst new file mode 100644 index 00000000000000..7b6007678388b1 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-28-12-25-19.gh-issue-109972.GYnwIP.rst @@ -0,0 +1,2 @@ +Split test_gdb.py file into a test_gdb package made of multiple tests, so tests +can now be run in parallel. Patch by Victor Stinner. From 8939221e91351f8e0a279f3019e2a3f65c3c95f9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Oct 2023 12:27:12 +0200 Subject: [PATCH 0926/1206] [3.12] gh-109615: Fix support test_copy_python_src_ignore() (#109958) (#110340) * gh-109615: Fix support test_copy_python_src_ignore() (#109958) Fix the test when run on an installed Python: use "abs_srcdir" of sysconfig, and skip the test if the Python source code cannot be found. * Tools/patchcheck/patchcheck.py, Tools/freeze/test/freeze.py and Lib/test/libregrtest/utils.py now first try to get "abs_srcdir" from sysconfig, before getting "srcdir" from sysconfig. * test.pythoninfo logs sysconfig "abs_srcdir". (cherry picked from commit b89ed9df39851348fbb1552294644f99f6b17d2c) * gh-109615: Fix support test_copy_python_src_ignore() on WASM (#109970) Not only check if src_dir exists, but look also for Lib/os.py landmark. (cherry picked from commit cc54bcf17b5b5f7681f52baf3acef75b995fa1fd) * gh-109615: Look for 'Modules' as landmark for test_copy_python_src_ignore (GH-110108) (cherry picked from commit 20bc5f7c28a6f8a2e156c4a748ffabb5efc7c761) * gh-109748: Fix again venv test_zippath_from_non_installed_posix() (#110149) Call also copy_python_src_ignore() on listdir() names. shutil.copytree(): replace set() with an empty tuple. An empty tuple becomes a constant in the compiler and checking if an item is in an empty tuple is cheap. (cherry picked from commit 0def8c712bb6f66f1081cab71deb3681566b846d) --------- Co-authored-by: Steve Dower --- Lib/shutil.py | 2 +- Lib/test/libregrtest/main.py | 12 +++++++----- Lib/test/pythoninfo.py | 2 ++ Lib/test/test_support.py | 21 ++++++++++++++++++--- Lib/test/test_venv.py | 6 +++++- Tools/freeze/test/freeze.py | 9 ++++++++- Tools/patchcheck/patchcheck.py | 9 ++++++++- 7 files changed, 49 insertions(+), 12 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py index 5bcfa563fea9af..a278b74fab2ddb 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -481,7 +481,7 @@ def _copytree(entries, src, dst, symlinks, ignore, copy_function, if ignore is not None: ignored_names = ignore(os.fspath(src), [x.name for x in entries]) else: - ignored_names = set() + ignored_names = () os.makedirs(dst, exist_ok=dirs_exist_ok) errors = [] diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 7cfea548ee2180..56d562d0b068dd 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -747,11 +747,13 @@ def set_temp_dir(self): if sysconfig.is_python_build(): self.tmp_dir = sysconfig.get_config_var('abs_builddir') if self.tmp_dir is None: - # gh-74470: On Windows, only srcdir is available. Using - # abs_builddir mostly matters on UNIX when building Python - # out of the source tree, especially when the source tree - # is read only. - self.tmp_dir = sysconfig.get_config_var('srcdir') + self.tmp_dir = sysconfig.get_config_var('abs_srcdir') + if not self.tmp_dir: + # gh-74470: On Windows, only srcdir is available. Using + # abs_builddir mostly matters on UNIX when building + # Python out of the source tree, especially when the + # source tree is read only. + self.tmp_dir = sysconfig.get_config_var('srcdir') self.tmp_dir = os.path.join(self.tmp_dir, 'build') else: self.tmp_dir = tempfile.gettempdir() diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 860c4cc4e0a818..1ec04de3c0c94f 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -516,6 +516,8 @@ def collect_sysconfig(info_add): 'Py_ENABLE_SHARED', 'SHELL', 'SOABI', + 'abs_builddir', + 'abs_srcdir', 'prefix', ): value = sysconfig.get_config_var(name) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index d3b2922d9b0ad1..b9b05fc4306a31 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -767,12 +767,27 @@ def recursive_function(depth): #self.assertEqual(available, 2) def test_copy_python_src_ignore(self): - src_dir = sysconfig.get_config_var('srcdir') + # Get source directory + src_dir = sysconfig.get_config_var('abs_srcdir') + if not src_dir: + src_dir = sysconfig.get_config_var('srcdir') src_dir = os.path.abspath(src_dir) - ignored = {'.git', '__pycache__'} + # Check that the source code is available + if not os.path.exists(src_dir): + self.skipTest(f"cannot access Python source code directory:" + f" {src_dir!r}") + # Check that the landmark copy_python_src_ignore() expects is available + # (Previously we looked for 'Lib\os.py', which is always present on Windows.) + landmark = os.path.join(src_dir, 'Modules') + if not os.path.exists(landmark): + self.skipTest(f"cannot access Python source code directory:" + f" {landmark!r} landmark is missing") + + # Test support.copy_python_src_ignore() # Source code directory + ignored = {'.git', '__pycache__'} names = os.listdir(src_dir) self.assertEqual(support.copy_python_src_ignore(src_dir, names), ignored | {'build'}) @@ -782,7 +797,7 @@ def test_copy_python_src_ignore(self): self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)), ignored | {'build', 'venv'}) - # An other directory + # Another directory path = os.path.join(src_dir, 'Objects') self.assertEqual(support.copy_python_src_ignore(path, os.listdir(path)), ignored) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 6942bf246b61d1..fea16568afebae 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -571,7 +571,11 @@ def test_zippath_from_non_installed_posix(self): eachpath, os.path.join(non_installed_dir, platlibdir)) elif os.path.isfile(os.path.join(eachpath, "os.py")): - for name in os.listdir(eachpath): + names = os.listdir(eachpath) + ignored_names = copy_python_src_ignore(eachpath, names) + for name in names: + if name in ignored_names: + continue if name == "site-packages": continue fn = os.path.join(eachpath, name) diff --git a/Tools/freeze/test/freeze.py b/Tools/freeze/test/freeze.py index bb15941464e3d1..cdf77c57bbb6ae 100644 --- a/Tools/freeze/test/freeze.py +++ b/Tools/freeze/test/freeze.py @@ -7,9 +7,16 @@ from test import support +def get_python_source_dir(): + src_dir = sysconfig.get_config_var('abs_srcdir') + if not src_dir: + src_dir = sysconfig.get_config_var('srcdir') + return os.path.abspath(src_dir) + + TESTS_DIR = os.path.dirname(__file__) TOOL_ROOT = os.path.dirname(TESTS_DIR) -SRCDIR = os.path.abspath(sysconfig.get_config_var('srcdir')) +SRCDIR = get_python_source_dir() MAKE = shutil.which('make') FREEZE = os.path.join(TOOL_ROOT, 'freeze.py') diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index fa3a43af6e6048..e3959ce428c7c5 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -11,6 +11,13 @@ import untabify +def get_python_source_dir(): + src_dir = sysconfig.get_config_var('abs_srcdir') + if not src_dir: + src_dir = sysconfig.get_config_var('srcdir') + return os.path.abspath(src_dir) + + # Excluded directories which are copies of external libraries: # don't check their coding style EXCLUDE_DIRS = [ @@ -18,7 +25,7 @@ os.path.join('Modules', 'expat'), os.path.join('Modules', 'zlib'), ] -SRCDIR = sysconfig.get_config_var('srcdir') +SRCDIR = get_python_source_dir() def n_files_str(count): From 1d87465005e8349323f6dad7e13f48ed5b52f6ad Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 03:33:14 -0700 Subject: [PATCH 0927/1206] [3.12] gh-110335: asyncio test_unix_events cleans multiprocessing (GH-110336) (#110338) gh-110335: asyncio test_unix_events cleans multiprocessing (GH-110336) test_unix_events tests using the multiprocessing module now call multiprocessing.util._cleanup_tests(). (cherry picked from commit 1337765225d7d593169205672e004f97e15237ec) Co-authored-by: Victor Stinner --- Lib/test/test_asyncio/test_unix_events.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 7322be597ae2d2..d2c8cba6acfa31 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -4,6 +4,7 @@ import errno import io import multiprocessing +from multiprocessing.util import _cleanup_tests as multiprocessing_cleanup_tests import os import pathlib import signal @@ -15,6 +16,7 @@ import unittest from unittest import mock import warnings + from test import support from test.support import os_helper from test.support import socket_helper @@ -1903,6 +1905,8 @@ async def test_fork_not_share_event_loop(self): @hashlib_helper.requires_hashdigest('md5') def test_fork_signal_handling(self): + self.addCleanup(multiprocessing_cleanup_tests) + # Sending signal to the forked process should not affect the parent # process ctx = multiprocessing.get_context('fork') @@ -1947,6 +1951,8 @@ async def func(): @hashlib_helper.requires_hashdigest('md5') def test_fork_asyncio_run(self): + self.addCleanup(multiprocessing_cleanup_tests) + ctx = multiprocessing.get_context('fork') manager = ctx.Manager() self.addCleanup(manager.shutdown) @@ -1964,6 +1970,8 @@ async def child_main(): @hashlib_helper.requires_hashdigest('md5') def test_fork_asyncio_subprocess(self): + self.addCleanup(multiprocessing_cleanup_tests) + ctx = multiprocessing.get_context('fork') manager = ctx.Manager() self.addCleanup(manager.shutdown) From 4936fa954125864ae3ae5d36863479094837e88a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Oct 2023 13:20:31 +0200 Subject: [PATCH 0928/1206] [3.12] gh-108987: Fix _thread.start_new_thread() race condition (#109135) (#110342) * gh-108987: Fix _thread.start_new_thread() race condition (#109135) Fix _thread.start_new_thread() race condition. If a thread is created during Python finalization, the newly spawned thread now exits immediately instead of trying to access freed memory and lead to a crash. thread_run() calls PyEval_AcquireThread() which checks if the thread must exit. The problem was that tstate was dereferenced earlier in _PyThreadState_Bind() which leads to a crash most of the time. Move _PyThreadState_CheckConsistency() from thread_run() to _PyThreadState_Bind(). (cherry picked from commit 517cd82ea7d01b344804413ef05610934a43a241) * gh-109795: `_thread.start_new_thread`: allocate thread bootstate using raw memory allocator (#109808) (cherry picked from commit 1b8f2366b38c87b0450d9c15bdfdd4c4a2fc3a01) --------- Co-authored-by: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> --- Include/internal/pycore_pystate.h | 2 + ...-09-08-12-09-55.gh-issue-108987.x5AIG8.rst | 4 ++ Modules/_threadmodule.c | 56 ++++++++++++------- Python/ceval_gil.c | 28 +--------- Python/pystate.c | 29 ++++++++++ 5 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-08-12-09-55.gh-issue-108987.x5AIG8.rst diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 218c3978e64dce..5be0ff6764c693 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -72,6 +72,8 @@ PyAPI_DATA(PyThreadState *) _PyThreadState_GetCurrent(void); extern int _PyThreadState_CheckConsistency(PyThreadState *tstate); #endif +extern int _PyThreadState_MustExit(PyThreadState *tstate); + /* Get the current Python thread state. This function is unsafe: it does not check for error and it can return NULL. diff --git a/Misc/NEWS.d/next/Library/2023-09-08-12-09-55.gh-issue-108987.x5AIG8.rst b/Misc/NEWS.d/next/Library/2023-09-08-12-09-55.gh-issue-108987.x5AIG8.rst new file mode 100644 index 00000000000000..16526ee748d869 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-08-12-09-55.gh-issue-108987.x5AIG8.rst @@ -0,0 +1,4 @@ +Fix :func:`_thread.start_new_thread` race condition. If a thread is created +during Python finalization, the newly spawned thread now exits immediately +instead of trying to access freed memory and lead to a crash. Patch by +Victor Stinner. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 18fd65ac9f420f..5edb6e9875d1ab 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1063,22 +1063,22 @@ _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) /* Module functions */ struct bootstate { - PyInterpreterState *interp; + PyThreadState *tstate; PyObject *func; PyObject *args; PyObject *kwargs; - PyThreadState *tstate; - _PyRuntimeState *runtime; }; static void -thread_bootstate_free(struct bootstate *boot) +thread_bootstate_free(struct bootstate *boot, int decref) { - Py_DECREF(boot->func); - Py_DECREF(boot->args); - Py_XDECREF(boot->kwargs); - PyMem_Free(boot); + if (decref) { + Py_DECREF(boot->func); + Py_DECREF(boot->args); + Py_XDECREF(boot->kwargs); + } + PyMem_RawFree(boot); } @@ -1088,9 +1088,24 @@ thread_run(void *boot_raw) struct bootstate *boot = (struct bootstate *) boot_raw; PyThreadState *tstate = boot->tstate; - // gh-104690: If Python is being finalized and PyInterpreterState_Delete() - // was called, tstate becomes a dangling pointer. - assert(_PyThreadState_CheckConsistency(tstate)); + // gh-108987: If _thread.start_new_thread() is called before or while + // Python is being finalized, thread_run() can called *after*. + // _PyRuntimeState_SetFinalizing() is called. At this point, all Python + // threads must exit, except of the thread calling Py_Finalize() whch holds + // the GIL and must not exit. + // + // At this stage, tstate can be a dangling pointer (point to freed memory), + // it's ok to call _PyThreadState_MustExit() with a dangling pointer. + if (_PyThreadState_MustExit(tstate)) { + // Don't call PyThreadState_Clear() nor _PyThreadState_DeleteCurrent(). + // These functions are called on tstate indirectly by Py_Finalize() + // which calls _PyInterpreterState_Clear(). + // + // Py_DECREF() cannot be called because the GIL is not held: leak + // references on purpose. Python is being finalized anyway. + thread_bootstate_free(boot, 0); + goto exit; + } _PyThreadState_Bind(tstate); PyEval_AcquireThread(tstate); @@ -1109,14 +1124,17 @@ thread_run(void *boot_raw) Py_DECREF(res); } - thread_bootstate_free(boot); + thread_bootstate_free(boot, 1); + tstate->interp->threads.count--; PyThreadState_Clear(tstate); _PyThreadState_DeleteCurrent(tstate); +exit: // bpo-44434: Don't call explicitly PyThread_exit_thread(). On Linux with // the glibc, pthread_exit() can abort the whole process if dlopen() fails // to open the libgcc_s.so library (ex: EMFILE error). + return; } static PyObject * @@ -1140,7 +1158,6 @@ and False otherwise.\n"); static PyObject * thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) { - _PyRuntimeState *runtime = &_PyRuntime; PyObject *func, *args, *kwargs = NULL; if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3, @@ -1179,20 +1196,21 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) return NULL; } - struct bootstate *boot = PyMem_NEW(struct bootstate, 1); + // gh-109795: Use PyMem_RawMalloc() instead of PyMem_Malloc(), + // because it should be possible to call thread_bootstate_free() + // without holding the GIL. + struct bootstate *boot = PyMem_RawMalloc(sizeof(struct bootstate)); if (boot == NULL) { return PyErr_NoMemory(); } - boot->interp = _PyInterpreterState_GET(); - boot->tstate = _PyThreadState_New(boot->interp); + boot->tstate = _PyThreadState_New(interp); if (boot->tstate == NULL) { - PyMem_Free(boot); + PyMem_RawFree(boot); if (!PyErr_Occurred()) { return PyErr_NoMemory(); } return NULL; } - boot->runtime = runtime; boot->func = Py_NewRef(func); boot->args = Py_NewRef(args); boot->kwargs = Py_XNewRef(kwargs); @@ -1201,7 +1219,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) if (ident == PYTHREAD_INVALID_THREAD_ID) { PyErr_SetString(ThreadError, "can't start new thread"); PyThreadState_Clear(boot->tstate); - thread_bootstate_free(boot); + thread_bootstate_free(boot, 1); return NULL; } return PyLong_FromUnsignedLong(ident); diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index b44cb0b9b6e09d..c1ab5883568e7d 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -328,28 +328,6 @@ drop_gil(struct _ceval_state *ceval, PyThreadState *tstate) } -/* Check if a Python thread must exit immediately, rather than taking the GIL - if Py_Finalize() has been called. - - When this function is called by a daemon thread after Py_Finalize() has been - called, the GIL does no longer exist. - - tstate must be non-NULL. */ -static inline int -tstate_must_exit(PyThreadState *tstate) -{ - /* bpo-39877: Access _PyRuntime directly rather than using - tstate->interp->runtime to support calls from Python daemon threads. - After Py_Finalize() has been called, tstate can be a dangling pointer: - point to PyThreadState freed memory. */ - PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime); - if (finalizing == NULL) { - finalizing = _PyInterpreterState_GetFinalizing(tstate->interp); - } - return (finalizing != NULL && finalizing != tstate); -} - - /* Take the GIL. The function saves errno at entry and restores its value at exit. @@ -365,7 +343,7 @@ take_gil(PyThreadState *tstate) // XXX It may be more correct to check tstate->_status.finalizing. // XXX assert(!tstate->_status.cleared); - if (tstate_must_exit(tstate)) { + if (_PyThreadState_MustExit(tstate)) { /* bpo-39877: If Py_Finalize() has been called and tstate is not the thread which called Py_Finalize(), exit immediately the thread. @@ -403,7 +381,7 @@ take_gil(PyThreadState *tstate) _Py_atomic_load_relaxed(&gil->locked) && gil->switch_number == saved_switchnum) { - if (tstate_must_exit(tstate)) { + if (_PyThreadState_MustExit(tstate)) { MUTEX_UNLOCK(gil->mutex); // gh-96387: If the loop requested a drop request in a previous // iteration, reset the request. Otherwise, drop_gil() can @@ -443,7 +421,7 @@ take_gil(PyThreadState *tstate) MUTEX_UNLOCK(gil->switch_mutex); #endif - if (tstate_must_exit(tstate)) { + if (_PyThreadState_MustExit(tstate)) { /* bpo-36475: If Py_Finalize() has been called and tstate is not the thread which called Py_Finalize(), exit immediately the thread. diff --git a/Python/pystate.c b/Python/pystate.c index 1fe88fdf5a8218..b77827ff8efa28 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1867,6 +1867,10 @@ PyThreadState_Swap(PyThreadState *newts) void _PyThreadState_Bind(PyThreadState *tstate) { + // gh-104690: If Python is being finalized and PyInterpreterState_Delete() + // was called, tstate becomes a dangling pointer. + assert(_PyThreadState_CheckConsistency(tstate)); + bind_tstate(tstate); // This makes sure there's a gilstate tstate bound // as soon as possible. @@ -2866,6 +2870,31 @@ _PyThreadState_CheckConsistency(PyThreadState *tstate) #endif +// Check if a Python thread must exit immediately, rather than taking the GIL +// if Py_Finalize() has been called. +// +// When this function is called by a daemon thread after Py_Finalize() has been +// called, the GIL does no longer exist. +// +// tstate can be a dangling pointer (point to freed memory): only tstate value +// is used, the pointer is not deferenced. +// +// tstate must be non-NULL. +int +_PyThreadState_MustExit(PyThreadState *tstate) +{ + /* bpo-39877: Access _PyRuntime directly rather than using + tstate->interp->runtime to support calls from Python daemon threads. + After Py_Finalize() has been called, tstate can be a dangling pointer: + point to PyThreadState freed memory. */ + PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime); + if (finalizing == NULL) { + finalizing = _PyInterpreterState_GetFinalizing(tstate->interp); + } + return (finalizing != NULL && finalizing != tstate); +} + + #ifdef __cplusplus } #endif From f53871e1e8bad0d7a8e58dd2cd4588331480d881 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 04:25:13 -0700 Subject: [PATCH 0929/1206] [3.12] gh-110332: Remove mentions of `random.WichmannHill` from `test_zlib` (GH-110334) (#110349) gh-110332: Remove mentions of `random.WichmannHill` from `test_zlib` (GH-110334) (cherry picked from commit e9f2352b7b7503519790ee6f51c2e298cf390e75) Co-authored-by: Nikita Sobolev --- Lib/test/test_zlib.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 55306c63cd4e16..cc6446c948b18d 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -513,18 +513,7 @@ def test_odd_flush(self): # Try 17K of data # generate random data stream - try: - # In 2.3 and later, WichmannHill is the RNG of the bug report - gen = random.WichmannHill() - except AttributeError: - try: - # 2.2 called it Random - gen = random.Random() - except AttributeError: - # others might simply have a single RNG - gen = random - gen.seed(1) - data = gen.randbytes(17 * 1024) + data = random.randbytes(17 * 1024) # compress, sync-flush, and decompress first = co.compress(data) From 1d032ea3d67e9725b63322f896d9aa727fd75521 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Oct 2023 13:26:45 +0200 Subject: [PATCH 0930/1206] [3.12] gh-109974: Fix threading lock_tests race conditions (#110057) (#110346) * gh-109974: Fix threading lock_tests race conditions (#110057) Fix race conditions in test_threading lock tests. Wait until a condition is met rather than using time.sleep() with a hardcoded number of seconds. * Replace sleeping loops with support.sleeping_retry() which raises an exception on timeout. * Add wait_threads_blocked(nthread) which computes a sleep depending on the number of threads. Remove _wait() function. * test_set_and_clear(): use a way longer Event.wait() timeout. * BarrierTests.test_repr(): wait until the 2 threads are waiting for the barrier. Use a way longer timeout for Barrier.wait() timeout. * test_thread_leak() no longer needs to count len(threading.enumerate()): Bunch uses threading_helper.wait_threads_exit() internally which does it in wait_for_finished(). * Add BaseLockTests.wait_phase() which implements a timeout. test_reacquire() and test_recursion_count() use wait_phase(). (cherry picked from commit 4e356ad183eeb567783f4a87fd092573da1e9252) * gh-109974: Fix more threading lock_tests race conditions (#110089) * Add context manager on Bunch class. * Bunch now catchs exceptions on executed functions and re-raise them at __exit__() as an ExceptionGroup. * Rewrite BarrierProxy.test_default_timeout(). Use a single thread. Only check that barrier.wait() blocks for at least default timeout seconds. * test_with(): inline _with() function. (cherry picked from commit 743e3572ee940a6cf88fd518e5f4a447905ba5eb) --- Lib/test/lock_tests.py | 621 +++++++++++------- Lib/test/test_importlib/test_locks.py | 3 +- ...-09-29-00-19-21.gh-issue-109974.Sh_g-r.rst | 3 + 3 files changed, 378 insertions(+), 249 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-09-29-00-19-21.gh-issue-109974.Sh_g-r.rst diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py index 238e607d20a2b2..024c6debcd4a54 100644 --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -19,54 +19,74 @@ "(no _at_fork_reinit method)") -def _wait(): - # A crude wait/yield function not relying on synchronization primitives. - time.sleep(0.01) +def wait_threads_blocked(nthread): + # Arbitrary sleep to wait until N threads are blocked, + # like waiting for a lock. + time.sleep(0.010 * nthread) + class Bunch(object): """ A bunch of threads. """ - def __init__(self, f, n, wait_before_exit=False): + def __init__(self, func, nthread, wait_before_exit=False): """ - Construct a bunch of `n` threads running the same function `f`. + Construct a bunch of `nthread` threads running the same function `func`. If `wait_before_exit` is True, the threads won't terminate until do_finish() is called. """ - self.f = f - self.n = n + self.func = func + self.nthread = nthread self.started = [] self.finished = [] + self.exceptions = [] self._can_exit = not wait_before_exit - self.wait_thread = threading_helper.wait_threads_exit() - self.wait_thread.__enter__() + self._wait_thread = None - def task(): - tid = threading.get_ident() - self.started.append(tid) - try: - f() - finally: - self.finished.append(tid) - while not self._can_exit: - _wait() + def task(self): + tid = threading.get_ident() + self.started.append(tid) + try: + self.func() + except BaseException as exc: + self.exceptions.append(exc) + finally: + self.finished.append(tid) + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if self._can_exit: + break + + def __enter__(self): + self._wait_thread = threading_helper.wait_threads_exit(support.SHORT_TIMEOUT) + self._wait_thread.__enter__() try: - for i in range(n): - start_new_thread(task, ()) + for _ in range(self.nthread): + start_new_thread(self.task, ()) except: self._can_exit = True raise - def wait_for_started(self): - while len(self.started) < self.n: - _wait() + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(self.started) >= self.nthread: + break + + return self + + def __exit__(self, exc_type, exc_value, traceback): + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(self.finished) >= self.nthread: + break - def wait_for_finished(self): - while len(self.finished) < self.n: - _wait() - # Wait for threads exit - self.wait_thread.__exit__(None, None, None) + # Wait until threads completely exit according to _thread._count() + self._wait_thread.__exit__(None, None, None) + + # Break reference cycle + exceptions = self.exceptions + self.exceptions = None + if exceptions: + raise ExceptionGroup(f"{self.func} threads raised exceptions", + exceptions) def do_finish(self): self._can_exit = True @@ -94,6 +114,12 @@ class BaseLockTests(BaseTestCase): Tests for both recursive and non-recursive locks. """ + def wait_phase(self, phase, expected): + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(phase) >= expected: + break + self.assertEqual(len(phase), expected) + def test_constructor(self): lock = self.locktype() del lock @@ -131,41 +157,57 @@ def test_try_acquire_contended(self): result = [] def f(): result.append(lock.acquire(False)) - Bunch(f, 1).wait_for_finished() + with Bunch(f, 1): + pass self.assertFalse(result[0]) lock.release() def test_acquire_contended(self): lock = self.locktype() lock.acquire() - N = 5 def f(): lock.acquire() lock.release() - b = Bunch(f, N) - b.wait_for_started() - _wait() - self.assertEqual(len(b.finished), 0) - lock.release() - b.wait_for_finished() - self.assertEqual(len(b.finished), N) + N = 5 + with Bunch(f, N) as bunch: + # Threads block on lock.acquire() + wait_threads_blocked(N) + self.assertEqual(len(bunch.finished), 0) + + # Threads unblocked + lock.release() + + self.assertEqual(len(bunch.finished), N) def test_with(self): lock = self.locktype() def f(): lock.acquire() lock.release() - def _with(err=None): + + def with_lock(err=None): with lock: if err is not None: raise err - _with() - # Check the lock is unacquired - Bunch(f, 1).wait_for_finished() - self.assertRaises(TypeError, _with, TypeError) - # Check the lock is unacquired - Bunch(f, 1).wait_for_finished() + + # Acquire the lock, do nothing, with releases the lock + with lock: + pass + + # Check that the lock is unacquired + with Bunch(f, 1): + pass + + # Acquire the lock, raise an exception, with releases the lock + with self.assertRaises(TypeError): + with lock: + raise TypeError + + # Check that the lock is unacquired even if after an exception + # was raised in the previous "with lock:" block + with Bunch(f, 1): + pass def test_thread_leak(self): # The lock shouldn't leak a Thread instance when used from a foreign @@ -174,17 +216,11 @@ def test_thread_leak(self): def f(): lock.acquire() lock.release() - n = len(threading.enumerate()) + # We run many threads in the hope that existing threads ids won't # be recycled. - Bunch(f, 15).wait_for_finished() - if len(threading.enumerate()) != n: - # There is a small window during which a Thread instance's - # target function has finished running, but the Thread is still - # alive and registered. Avoid spurious failures by waiting a - # bit more (seen on a buildbot). - time.sleep(0.4) - self.assertEqual(n, len(threading.enumerate())) + with Bunch(f, 15): + pass def test_timeout(self): lock = self.locktype() @@ -208,7 +244,8 @@ def f(): results.append(lock.acquire(timeout=0.5)) t2 = time.monotonic() results.append(t2 - t1) - Bunch(f, 1).wait_for_finished() + with Bunch(f, 1): + pass self.assertFalse(results[0]) self.assertTimeout(results[1], 0.5) @@ -242,15 +279,13 @@ def f(): phase.append(None) with threading_helper.wait_threads_exit(): + # Thread blocked on lock.acquire() start_new_thread(f, ()) - while len(phase) == 0: - _wait() - _wait() - self.assertEqual(len(phase), 1) + self.wait_phase(phase, 1) + + # Thread unblocked lock.release() - while len(phase) == 1: - _wait() - self.assertEqual(len(phase), 2) + self.wait_phase(phase, 2) def test_different_thread(self): # Lock can be released from a different thread. @@ -258,8 +293,8 @@ def test_different_thread(self): lock.acquire() def f(): lock.release() - b = Bunch(f, 1) - b.wait_for_finished() + with Bunch(f, 1): + pass lock.acquire() lock.release() @@ -349,21 +384,20 @@ def test_recursion_count(self): def f(): lock.acquire() phase.append(None) - while len(phase) == 1: - _wait() + + self.wait_phase(phase, 2) lock.release() phase.append(None) with threading_helper.wait_threads_exit(): + # Thread blocked on lock.acquire() start_new_thread(f, ()) - while len(phase) == 0: - _wait() - self.assertEqual(len(phase), 1) + self.wait_phase(phase, 1) self.assertEqual(0, lock._recursion_count()) + + # Thread unblocked phase.append(None) - while len(phase) == 2: - _wait() - self.assertEqual(len(phase), 3) + self.wait_phase(phase, 3) self.assertEqual(0, lock._recursion_count()) def test_different_thread(self): @@ -371,12 +405,12 @@ def test_different_thread(self): lock = self.locktype() def f(): lock.acquire() - b = Bunch(f, 1, True) - try: - self.assertRaises(RuntimeError, lock.release) - finally: - b.do_finish() - b.wait_for_finished() + + with Bunch(f, 1, True) as bunch: + try: + self.assertRaises(RuntimeError, lock.release) + finally: + bunch.do_finish() def test__is_owned(self): lock = self.locktype() @@ -388,7 +422,8 @@ def test__is_owned(self): result = [] def f(): result.append(lock._is_owned()) - Bunch(f, 1).wait_for_finished() + with Bunch(f, 1): + pass self.assertFalse(result[0]) lock.release() self.assertTrue(lock._is_owned()) @@ -421,12 +456,15 @@ def _check_notify(self, evt): def f(): results1.append(evt.wait()) results2.append(evt.wait()) - b = Bunch(f, N) - b.wait_for_started() - _wait() - self.assertEqual(len(results1), 0) - evt.set() - b.wait_for_finished() + + with Bunch(f, N): + # Threads blocked on first evt.wait() + wait_threads_blocked(N) + self.assertEqual(len(results1), 0) + + # Threads unblocked + evt.set() + self.assertEqual(results1, [True] * N) self.assertEqual(results2, [True] * N) @@ -449,35 +487,43 @@ def f(): r = evt.wait(0.5) t2 = time.monotonic() results2.append((r, t2 - t1)) - Bunch(f, N).wait_for_finished() + + with Bunch(f, N): + pass + self.assertEqual(results1, [False] * N) for r, dt in results2: self.assertFalse(r) self.assertTimeout(dt, 0.5) + # The event is set results1 = [] results2 = [] evt.set() - Bunch(f, N).wait_for_finished() + with Bunch(f, N): + pass + self.assertEqual(results1, [True] * N) for r, dt in results2: self.assertTrue(r) def test_set_and_clear(self): - # Issue #13502: check that wait() returns true even when the event is + # gh-57711: check that wait() returns true even when the event is # cleared before the waiting thread is woken up. - evt = self.eventtype() + event = self.eventtype() results = [] - timeout = 0.250 - N = 5 def f(): - results.append(evt.wait(timeout * 4)) - b = Bunch(f, N) - b.wait_for_started() - time.sleep(timeout) - evt.set() - evt.clear() - b.wait_for_finished() + results.append(event.wait(support.LONG_TIMEOUT)) + + N = 5 + with Bunch(f, N): + # Threads blocked on event.wait() + wait_threads_blocked(N) + + # Threads unblocked + event.set() + event.clear() + self.assertEqual(results, [True] * N) @requires_fork @@ -533,15 +579,14 @@ def _check_notify(self, cond): # Note that this test is sensitive to timing. If the worker threads # don't execute in a timely fashion, the main thread may think they # are further along then they are. The main thread therefore issues - # _wait() statements to try to make sure that it doesn't race ahead - # of the workers. + # wait_threads_blocked() statements to try to make sure that it doesn't + # race ahead of the workers. # Secondly, this test assumes that condition variables are not subject # to spurious wakeups. The absence of spurious wakeups is an implementation # detail of Condition Variables in current CPython, but in general, not # a guaranteed property of condition variables as a programming # construct. In particular, it is possible that this can no longer # be conveniently guaranteed should their implementation ever change. - N = 5 ready = [] results1 = [] results2 = [] @@ -550,58 +595,83 @@ def f(): cond.acquire() ready.append(phase_num) result = cond.wait() + cond.release() results1.append((result, phase_num)) + cond.acquire() ready.append(phase_num) + result = cond.wait() cond.release() results2.append((result, phase_num)) - b = Bunch(f, N) - b.wait_for_started() - # first wait, to ensure all workers settle into cond.wait() before - # we continue. See issues #8799 and #30727. - while len(ready) < 5: - _wait() - ready.clear() - self.assertEqual(results1, []) - # Notify 3 threads at first - cond.acquire() - cond.notify(3) - _wait() - phase_num = 1 - cond.release() - while len(results1) < 3: - _wait() - self.assertEqual(results1, [(True, 1)] * 3) - self.assertEqual(results2, []) - # make sure all awaken workers settle into cond.wait() - while len(ready) < 3: - _wait() - # Notify 5 threads: they might be in their first or second wait - cond.acquire() - cond.notify(5) - _wait() - phase_num = 2 - cond.release() - while len(results1) + len(results2) < 8: - _wait() - self.assertEqual(results1, [(True, 1)] * 3 + [(True, 2)] * 2) - self.assertEqual(results2, [(True, 2)] * 3) - # make sure all workers settle into cond.wait() - while len(ready) < 5: - _wait() - # Notify all threads: they are all in their second wait - cond.acquire() - cond.notify_all() - _wait() - phase_num = 3 - cond.release() - while len(results2) < 5: - _wait() - self.assertEqual(results1, [(True, 1)] * 3 + [(True,2)] * 2) - self.assertEqual(results2, [(True, 2)] * 3 + [(True, 3)] * 2) - b.wait_for_finished() + + N = 5 + with Bunch(f, N): + # first wait, to ensure all workers settle into cond.wait() before + # we continue. See issues #8799 and #30727. + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(ready) >= N: + break + + ready.clear() + self.assertEqual(results1, []) + + # Notify 3 threads at first + count1 = 3 + cond.acquire() + cond.notify(count1) + wait_threads_blocked(count1) + + # Phase 1 + phase_num = 1 + cond.release() + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(results1) >= count1: + break + + self.assertEqual(results1, [(True, 1)] * count1) + self.assertEqual(results2, []) + + # Wait until awaken workers are blocked on cond.wait() + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(ready) >= count1 : + break + + # Notify 5 threads: they might be in their first or second wait + cond.acquire() + cond.notify(5) + wait_threads_blocked(N) + + # Phase 2 + phase_num = 2 + cond.release() + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(results1) + len(results2) >= (N + count1): + break + + count2 = N - count1 + self.assertEqual(results1, [(True, 1)] * count1 + [(True, 2)] * count2) + self.assertEqual(results2, [(True, 2)] * count1) + + # Make sure all workers settle into cond.wait() + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(ready) >= N: + break + + # Notify all threads: they are all in their second wait + cond.acquire() + cond.notify_all() + wait_threads_blocked(N) + + # Phase 3 + phase_num = 3 + cond.release() + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(results2) >= N: + break + self.assertEqual(results1, [(True, 1)] * count1 + [(True, 2)] * count2) + self.assertEqual(results2, [(True, 2)] * count1 + [(True, 3)] * count2) def test_notify(self): cond = self.condtype() @@ -611,19 +681,23 @@ def test_notify(self): def test_timeout(self): cond = self.condtype() + timeout = 0.5 results = [] - N = 5 def f(): cond.acquire() t1 = time.monotonic() - result = cond.wait(0.5) + result = cond.wait(timeout) t2 = time.monotonic() cond.release() results.append((t2 - t1, result)) - Bunch(f, N).wait_for_finished() + + N = 5 + with Bunch(f, N): + pass self.assertEqual(len(results), N) + for dt, result in results: - self.assertTimeout(dt, 0.5) + self.assertTimeout(dt, timeout) # Note that conceptually (that"s the condition variable protocol) # a wait() may succeed even if no one notifies us and before any # timeout occurs. Spurious wakeups can occur. @@ -636,17 +710,16 @@ def test_waitfor(self): state = 0 def f(): with cond: - result = cond.wait_for(lambda : state==4) + result = cond.wait_for(lambda: state == 4) self.assertTrue(result) self.assertEqual(state, 4) - b = Bunch(f, 1) - b.wait_for_started() - for i in range(4): - time.sleep(0.01) - with cond: - state += 1 - cond.notify() - b.wait_for_finished() + + with Bunch(f, 1): + for i in range(4): + time.sleep(0.010) + with cond: + state += 1 + cond.notify() def test_waitfor_timeout(self): cond = self.condtype() @@ -660,15 +733,15 @@ def f(): self.assertFalse(result) self.assertTimeout(dt, 0.1) success.append(None) - b = Bunch(f, 1) - b.wait_for_started() - # Only increment 3 times, so state == 4 is never reached. - for i in range(3): - time.sleep(0.01) - with cond: - state += 1 - cond.notify() - b.wait_for_finished() + + with Bunch(f, 1): + # Only increment 3 times, so state == 4 is never reached. + for i in range(3): + time.sleep(0.010) + with cond: + state += 1 + cond.notify() + self.assertEqual(len(success), 1) @@ -697,73 +770,107 @@ def test_acquire_destroy(self): del sem def test_acquire_contended(self): - sem = self.semtype(7) + sem_value = 7 + sem = self.semtype(sem_value) sem.acquire() - N = 10 + sem_results = [] results1 = [] results2 = [] phase_num = 0 - def f(): + + def func(): sem_results.append(sem.acquire()) results1.append(phase_num) + sem_results.append(sem.acquire()) results2.append(phase_num) - b = Bunch(f, 10) - b.wait_for_started() - while len(results1) + len(results2) < 6: - _wait() - self.assertEqual(results1 + results2, [0] * 6) - phase_num = 1 - for i in range(7): - sem.release() - while len(results1) + len(results2) < 13: - _wait() - self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7) - phase_num = 2 - for i in range(6): + + def wait_count(count): + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(results1) + len(results2) >= count: + break + + N = 10 + with Bunch(func, N): + # Phase 0 + count1 = sem_value - 1 + wait_count(count1) + self.assertEqual(results1 + results2, [0] * count1) + + # Phase 1 + phase_num = 1 + for i in range(sem_value): + sem.release() + count2 = sem_value + wait_count(count1 + count2) + self.assertEqual(sorted(results1 + results2), + [0] * count1 + [1] * count2) + + # Phase 2 + phase_num = 2 + count3 = (sem_value - 1) + for i in range(count3): + sem.release() + wait_count(count1 + count2 + count3) + self.assertEqual(sorted(results1 + results2), + [0] * count1 + [1] * count2 + [2] * count3) + # The semaphore is still locked + self.assertFalse(sem.acquire(False)) + + # Final release, to let the last thread finish + count4 = 1 sem.release() - while len(results1) + len(results2) < 19: - _wait() - self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7 + [2] * 6) - # The semaphore is still locked - self.assertFalse(sem.acquire(False)) - # Final release, to let the last thread finish - sem.release() - b.wait_for_finished() - self.assertEqual(sem_results, [True] * (6 + 7 + 6 + 1)) + + self.assertEqual(sem_results, + [True] * (count1 + count2 + count3 + count4)) def test_multirelease(self): - sem = self.semtype(7) + sem_value = 7 + sem = self.semtype(sem_value) sem.acquire() + results1 = [] results2 = [] phase_num = 0 - def f(): + def func(): sem.acquire() results1.append(phase_num) + sem.acquire() results2.append(phase_num) - b = Bunch(f, 10) - b.wait_for_started() - while len(results1) + len(results2) < 6: - _wait() - self.assertEqual(results1 + results2, [0] * 6) - phase_num = 1 - sem.release(7) - while len(results1) + len(results2) < 13: - _wait() - self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7) - phase_num = 2 - sem.release(6) - while len(results1) + len(results2) < 19: - _wait() - self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7 + [2] * 6) - # The semaphore is still locked - self.assertFalse(sem.acquire(False)) - # Final release, to let the last thread finish - sem.release() - b.wait_for_finished() + + def wait_count(count): + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if len(results1) + len(results2) >= count: + break + + with Bunch(func, 10): + # Phase 0 + count1 = sem_value - 1 + wait_count(count1) + self.assertEqual(results1 + results2, [0] * count1) + + # Phase 1 + phase_num = 1 + count2 = sem_value + sem.release(count2) + wait_count(count1 + count2) + self.assertEqual(sorted(results1 + results2), + [0] * count1 + [1] * count2) + + # Phase 2 + phase_num = 2 + count3 = sem_value - 1 + sem.release(count3) + wait_count(count1 + count2 + count3) + self.assertEqual(sorted(results1 + results2), + [0] * count1 + [1] * count2 + [2] * count3) + # The semaphore is still locked + self.assertFalse(sem.acquire(False)) + + # Final release, to let the last thread finish + sem.release() def test_try_acquire(self): sem = self.semtype(2) @@ -780,7 +887,8 @@ def test_try_acquire_contended(self): def f(): results.append(sem.acquire(False)) results.append(sem.acquire(False)) - Bunch(f, 5).wait_for_finished() + with Bunch(f, 5): + pass # There can be a thread switch between acquiring the semaphore and # appending the result, therefore results will not necessarily be # ordered. @@ -806,12 +914,14 @@ def test_default_value(self): def f(): sem.acquire() sem.release() - b = Bunch(f, 1) - b.wait_for_started() - _wait() - self.assertFalse(b.finished) - sem.release() - b.wait_for_finished() + + with Bunch(f, 1) as bunch: + # Thread blocked on sem.acquire() + wait_threads_blocked(1) + self.assertFalse(bunch.finished) + + # Thread unblocked + sem.release() def test_with(self): sem = self.semtype(2) @@ -882,13 +992,13 @@ class BarrierTests(BaseTestCase): def setUp(self): self.barrier = self.barriertype(self.N, timeout=self.defaultTimeout) + def tearDown(self): self.barrier.abort() def run_threads(self, f): - b = Bunch(f, self.N-1) - f() - b.wait_for_finished() + with Bunch(f, self.N): + pass def multipass(self, results, n): m = self.barrier.parties @@ -979,8 +1089,9 @@ def f(): i = self.barrier.wait() if i == self.N//2: # Wait until the other threads are all in the barrier. - while self.barrier.n_waiting < self.N-1: - time.sleep(0.001) + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if self.barrier.n_waiting >= (self.N - 1): + break self.barrier.reset() else: try: @@ -1040,25 +1151,27 @@ def f(): i = self.barrier.wait() if i == self.N // 2: # One thread is late! - time.sleep(1.0) + time.sleep(self.defaultTimeout / 2) # Default timeout is 2.0, so this is shorter. self.assertRaises(threading.BrokenBarrierError, - self.barrier.wait, 0.5) + self.barrier.wait, self.defaultTimeout / 4) self.run_threads(f) def test_default_timeout(self): """ Test the barrier's default timeout """ - # create a barrier with a low default timeout - barrier = self.barriertype(self.N, timeout=0.3) + timeout = 0.100 + barrier = self.barriertype(2, timeout=timeout) def f(): - i = barrier.wait() - if i == self.N // 2: - # One thread is later than the default timeout of 0.3s. - time.sleep(1.0) - self.assertRaises(threading.BrokenBarrierError, barrier.wait) - self.run_threads(f) + self.assertRaises(threading.BrokenBarrierError, + barrier.wait) + + start_time = time.monotonic() + with Bunch(f, 1): + pass + dt = time.monotonic() - start_time + self.assertGreaterEqual(dt, timeout) def test_single_thread(self): b = self.barriertype(1) @@ -1066,16 +1179,28 @@ def test_single_thread(self): b.wait() def test_repr(self): - b = self.barriertype(3) - self.assertRegex(repr(b), r"<\w+\.Barrier at .*: waiters=0/3>") + barrier = self.barriertype(3) + timeout = support.LONG_TIMEOUT + self.assertRegex(repr(barrier), r"<\w+\.Barrier at .*: waiters=0/3>") def f(): - b.wait(3) - bunch = Bunch(f, 2) - bunch.wait_for_started() - time.sleep(0.2) - self.assertRegex(repr(b), r"<\w+\.Barrier at .*: waiters=2/3>") - b.wait(3) - bunch.wait_for_finished() - self.assertRegex(repr(b), r"<\w+\.Barrier at .*: waiters=0/3>") - b.abort() - self.assertRegex(repr(b), r"<\w+\.Barrier at .*: broken>") + barrier.wait(timeout) + + N = 2 + with Bunch(f, N): + # Threads blocked on barrier.wait() + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if barrier.n_waiting >= N: + break + self.assertRegex(repr(barrier), + r"<\w+\.Barrier at .*: waiters=2/3>") + + # Threads unblocked + barrier.wait(timeout) + + self.assertRegex(repr(barrier), + r"<\w+\.Barrier at .*: waiters=0/3>") + + # Abort the barrier + barrier.abort() + self.assertRegex(repr(barrier), + r"<\w+\.Barrier at .*: broken>") diff --git a/Lib/test/test_importlib/test_locks.py b/Lib/test/test_importlib/test_locks.py index 7091c36aaaf761..befac5d62b0abf 100644 --- a/Lib/test/test_importlib/test_locks.py +++ b/Lib/test/test_importlib/test_locks.py @@ -93,7 +93,8 @@ def f(): b.release() if ra: a.release() - lock_tests.Bunch(f, NTHREADS).wait_for_finished() + with lock_tests.Bunch(f, NTHREADS): + pass self.assertEqual(len(results), NTHREADS) return results diff --git a/Misc/NEWS.d/next/Tests/2023-09-29-00-19-21.gh-issue-109974.Sh_g-r.rst b/Misc/NEWS.d/next/Tests/2023-09-29-00-19-21.gh-issue-109974.Sh_g-r.rst new file mode 100644 index 00000000000000..a130cf690a57cb --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-29-00-19-21.gh-issue-109974.Sh_g-r.rst @@ -0,0 +1,3 @@ +Fix race conditions in test_threading lock tests. Wait until a condition is met +rather than using :func:`time.sleep` with a hardcoded number of seconds. Patch +by Victor Stinner. From bbce8bd05dd25c6e74487940fa1977485b52baf4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Oct 2023 13:34:28 +0200 Subject: [PATCH 0931/1206] [3.12] gh-109972: Enhance test_gdb (#110026) (#110351) * gh-109972: Enhance test_gdb (#110026) * Split test_pycfunction.py: add test_cfunction_full.py. Split the function into the following 6 functions. In verbose mode, these "pycfunction" tests now log each tested call. * test_pycfunction_noargs() * test_pycfunction_o() * test_pycfunction_varargs() * test_pycfunction_varargs_keywords() * test_pycfunction_fastcall() * test_pycfunction_fastcall_keywords() * Move get_gdb_repr() to PrettyPrintTests. * Replace DebuggerTests.get_sample_script() with SAMPLE_SCRIPT. * Rename checkout_hook_path to CHECKOUT_HOOK_PATH. * Rename gdb_version to GDB_VERSION_TEXT. * Replace (gdb_major_version, gdb_minor_version) with GDB_VERSION. * run_gdb() uses "backslashreplace" error handler instead of "replace". * Add check_gdb() function to util.py. * Enhance support.check_cflags_pgo(): check also for sysconfig PGO_PROF_USE_FLAG (if available) in compiler flags. * Move some SkipTest checks to test_gdb/__init__.py. * Elaborate why gdb cannot be tested on Windows: gdb doesn't support PDB debug symbol files. (cherry picked from commit 757cbd4f29c9e89b38b975e0463dc8ed331b2515) * gh-104736: Fix test_gdb tests on ppc64le with clang (#109360) Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora 38). Search patterns in gdb "bt" command output to detect when gdb fails to retrieve the traceback. For example, skip a test if "Backtrace stopped: frame did not save the PC" is found. (cherry picked from commit 44d9a71ea246e7c3fb478d9be62c16914be6c545) * gh-110166: Fix gdb CFunctionFullTests on ppc64le clang build (#110331) CFunctionFullTests now also runs "bt" command before "py-bt-full", similar to CFunctionTests which also runs "bt" command before "py-bt". So test_gdb can skip the test if patterns like "?? ()" are found in the gdb output. (cherry picked from commit 1de9406f9136e3952b849487f0151be3c669a3ea) --- Lib/test/support/__init__.py | 7 +- Lib/test/test_gdb/__init__.py | 24 +- Lib/test/test_gdb/test_backtrace.py | 6 +- Lib/test/test_gdb/test_cfunction.py | 114 ++++---- Lib/test/test_gdb/test_cfunction_full.py | 36 +++ Lib/test/test_gdb/test_misc.py | 20 +- Lib/test/test_gdb/test_pretty_print.py | 54 +++- Lib/test/test_gdb/util.py | 256 ++++++++---------- ...-09-13-05-58-09.gh-issue-104736.lA25Fu.rst | 4 + 9 files changed, 303 insertions(+), 218 deletions(-) create mode 100644 Lib/test/test_gdb/test_cfunction_full.py create mode 100644 Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index fa26ce8c1a7bd8..29ea944a3bfce9 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -785,14 +785,17 @@ def check_cflags_pgo(): # Check if Python was built with ./configure --enable-optimizations: # with Profile Guided Optimization (PGO). cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST') or '' - pgo_options = ( + pgo_options = [ # GCC '-fprofile-use', # clang: -fprofile-instr-use=code.profclangd '-fprofile-instr-use', # ICC "-prof-use", - ) + ] + PGO_PROF_USE_FLAG = sysconfig.get_config_var('PGO_PROF_USE_FLAG') + if PGO_PROF_USE_FLAG: + pgo_options.append(PGO_PROF_USE_FLAG) return any(option in cflags_nodist for option in pgo_options) diff --git a/Lib/test/test_gdb/__init__.py b/Lib/test/test_gdb/__init__.py index 0261f59adf54bd..d74075e456792d 100644 --- a/Lib/test/test_gdb/__init__.py +++ b/Lib/test/test_gdb/__init__.py @@ -4,7 +4,27 @@ # Lib/test/test_jit_gdb.py import os -from test.support import load_package_tests +import sysconfig +import unittest +from test import support + + +MS_WINDOWS = (os.name == 'nt') +if MS_WINDOWS: + # On Windows, Python is usually built by MSVC. Passing /p:DebugSymbols=true + # option to MSBuild produces PDB debug symbols, but gdb doesn't support PDB + # debug symbol files. + raise unittest.SkipTest("test_gdb doesn't work on Windows") + +if support.PGO: + raise unittest.SkipTest("test_gdb is not useful for PGO") + +if not sysconfig.is_python_build(): + raise unittest.SkipTest("test_gdb only works on source builds at the moment.") + +if support.check_cflags_pgo(): + raise unittest.SkipTest("test_gdb is not reliable on PGO builds") + def load_tests(*args): - return load_package_tests(os.path.dirname(__file__), *args) + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_gdb/test_backtrace.py b/Lib/test/test_gdb/test_backtrace.py index 15cbcf169ab9e3..c41e7cb7c210de 100644 --- a/Lib/test/test_gdb/test_backtrace.py +++ b/Lib/test/test_gdb/test_backtrace.py @@ -3,7 +3,7 @@ from test import support from test.support import python_is_optimized -from .util import setup_module, DebuggerTests, CET_PROTECTION +from .util import setup_module, DebuggerTests, CET_PROTECTION, SAMPLE_SCRIPT def setUpModule(): @@ -15,7 +15,7 @@ class PyBtTests(DebuggerTests): "Python was compiled with optimizations") def test_bt(self): 'Verify that the "py-bt" command works' - bt = self.get_stack_trace(script=self.get_sample_script(), + bt = self.get_stack_trace(script=SAMPLE_SCRIPT, cmds_after_breakpoint=['py-bt']) self.assertMultilineMatches(bt, r'''^.* @@ -35,7 +35,7 @@ def test_bt(self): "Python was compiled with optimizations") def test_bt_full(self): 'Verify that the "py-bt-full" command works' - bt = self.get_stack_trace(script=self.get_sample_script(), + bt = self.get_stack_trace(script=SAMPLE_SCRIPT, cmds_after_breakpoint=['py-bt-full']) self.assertMultilineMatches(bt, r'''^.* diff --git a/Lib/test/test_gdb/test_cfunction.py b/Lib/test/test_gdb/test_cfunction.py index 55796d021511e1..0a62014923e61f 100644 --- a/Lib/test/test_gdb/test_cfunction.py +++ b/Lib/test/test_gdb/test_cfunction.py @@ -1,8 +1,6 @@ -import re import textwrap import unittest from test import support -from test.support import python_is_optimized from .util import setup_module, DebuggerTests @@ -11,10 +9,22 @@ def setUpModule(): setup_module() -@unittest.skipIf(python_is_optimized(), +@unittest.skipIf(support.python_is_optimized(), "Python was compiled with optimizations") @support.requires_resource('cpu') class CFunctionTests(DebuggerTests): + def check(self, func_name, cmd): + # Verify with "py-bt": + gdb_output = self.get_stack_trace( + cmd, + breakpoint=func_name, + cmds_after_breakpoint=['bt', 'py-bt'], + # bpo-45207: Ignore 'Function "meth_varargs" not + # defined.' message in stderr. + ignore_stderr=True, + ) + self.assertIn(f'\n.*") @@ -167,7 +167,7 @@ class PyLocalsTests(DebuggerTests): @unittest.skipIf(python_is_optimized(), "Python was compiled with optimizations") def test_basic_command(self): - bt = self.get_stack_trace(script=self.get_sample_script(), + bt = self.get_stack_trace(script=SAMPLE_SCRIPT, cmds_after_breakpoint=['py-up', 'py-locals']) self.assertMultilineMatches(bt, r".*\nargs = \(1, 2, 3\)\n.*") @@ -176,7 +176,7 @@ def test_basic_command(self): @unittest.skipIf(python_is_optimized(), "Python was compiled with optimizations") def test_locals_after_up(self): - bt = self.get_stack_trace(script=self.get_sample_script(), + bt = self.get_stack_trace(script=SAMPLE_SCRIPT, cmds_after_breakpoint=['py-up', 'py-up', 'py-locals']) self.assertMultilineMatches(bt, r'''^.* diff --git a/Lib/test/test_gdb/test_pretty_print.py b/Lib/test/test_gdb/test_pretty_print.py index e31dc66f29684a..dfc77d65ab16a4 100644 --- a/Lib/test/test_gdb/test_pretty_print.py +++ b/Lib/test/test_gdb/test_pretty_print.py @@ -3,7 +3,7 @@ from test import support from .util import ( - BREAKPOINT_FN, gdb_major_version, gdb_minor_version, + BREAKPOINT_FN, GDB_VERSION, run_gdb, setup_module, DebuggerTests) @@ -12,6 +12,42 @@ def setUpModule(): class PrettyPrintTests(DebuggerTests): + def get_gdb_repr(self, source, + cmds_after_breakpoint=None, + import_site=False): + # Given an input python source representation of data, + # run "python -c'id(DATA)'" under gdb with a breakpoint on + # builtin_id and scrape out gdb's representation of the "op" + # parameter, and verify that the gdb displays the same string + # + # Verify that the gdb displays the expected string + # + # For a nested structure, the first time we hit the breakpoint will + # give us the top-level structure + + # NOTE: avoid decoding too much of the traceback as some + # undecodable characters may lurk there in optimized mode + # (issue #19743). + cmds_after_breakpoint = cmds_after_breakpoint or ["backtrace 1"] + gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN, + cmds_after_breakpoint=cmds_after_breakpoint, + import_site=import_site) + # gdb can insert additional '\n' and space characters in various places + # in its output, depending on the width of the terminal it's connected + # to (using its "wrap_here" function) + m = re.search( + # Match '#0 builtin_id(self=..., v=...)' + r'#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)?\)' + # Match ' at Python/bltinmodule.c'. + # bpo-38239: builtin_id() is defined in Python/bltinmodule.c, + # but accept any "Directory\file.c" to support Link Time + # Optimization (LTO). + r'\s+at\s+\S*[A-Za-z]+/[A-Za-z0-9_-]+\.c', + gdb_output, re.DOTALL) + if not m: + self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output)) + return m.group(1), gdb_output + def test_getting_backtrace(self): gdb_output = self.get_stack_trace('id(42)') self.assertTrue(BREAKPOINT_FN in gdb_output) @@ -75,15 +111,17 @@ def test_strings(self): # as GDB might have been linked against a different version # of Python with a different encoding and coercion policy # with respect to PEP 538 and PEP 540. - out, err = run_gdb( + stdout, stderr = run_gdb( '--eval-command', 'python import locale; print(locale.getpreferredencoding())') - encoding = out.rstrip() - if err or not encoding: + encoding = stdout + if stderr or not encoding: raise RuntimeError( - f'unable to determine the preferred encoding ' - f'of embedded Python in GDB: {err}') + f'unable to determine the Python locale preferred encoding ' + f'of embedded Python in GDB\n' + f'stdout={stdout!r}\n' + f'stderr={stderr!r}') def check_repr(text): try: @@ -122,7 +160,7 @@ def test_tuples(self): @support.requires_resource('cpu') def test_sets(self): 'Verify the pretty-printing of sets' - if (gdb_major_version, gdb_minor_version) < (7, 3): + if GDB_VERSION < (7, 3): self.skipTest("pretty-printing of sets needs gdb 7.3 or later") self.assertGdbRepr(set(), "set()") self.assertGdbRepr(set(['a']), "{'a'}") @@ -141,7 +179,7 @@ def test_sets(self): @support.requires_resource('cpu') def test_frozensets(self): 'Verify the pretty-printing of frozensets' - if (gdb_major_version, gdb_minor_version) < (7, 3): + if GDB_VERSION < (7, 3): self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later") self.assertGdbRepr(frozenset(), "frozenset()") self.assertGdbRepr(frozenset(['a']), "frozenset({'a'})") diff --git a/Lib/test/test_gdb/util.py b/Lib/test/test_gdb/util.py index 30beb4e14285c7..7f4e3cba3534bd 100644 --- a/Lib/test/test_gdb/util.py +++ b/Lib/test/test_gdb/util.py @@ -1,5 +1,6 @@ import os import re +import shlex import subprocess import sys import sysconfig @@ -7,29 +8,74 @@ from test import support -MS_WINDOWS = (sys.platform == 'win32') -if MS_WINDOWS: - raise unittest.SkipTest("test_gdb doesn't work on Windows") +# Location of custom hooks file in a repository checkout. +CHECKOUT_HOOK_PATH = os.path.join(os.path.dirname(sys.executable), + 'python-gdb.py') + +SAMPLE_SCRIPT = os.path.join(os.path.dirname(__file__), 'gdb_sample.py') +BREAKPOINT_FN = 'builtin_id' + +PYTHONHASHSEED = '123' + + +def clean_environment(): + # Remove PYTHON* environment variables such as PYTHONHOME + return {name: value for name, value in os.environ.items() + if not name.startswith('PYTHON')} + + +# Temporary value until it's initialized by get_gdb_version() below +GDB_VERSION = (0, 0) + +def run_gdb(*args, exitcode=0, **env_vars): + """Runs gdb in --batch mode with the additional arguments given by *args. + + Returns its (stdout, stderr) decoded from utf-8 using the replace handler. + """ + env = clean_environment() + if env_vars: + env.update(env_vars) + + cmd = ['gdb', + # Batch mode: Exit after processing all the command files + # specified with -x/--command + '--batch', + # -nx: Do not execute commands from any .gdbinit initialization + # files (gh-66384) + '-nx'] + if GDB_VERSION >= (7, 4): + cmd.extend(('--init-eval-command', + f'add-auto-load-safe-path {CHECKOUT_HOOK_PATH}')) + cmd.extend(args) + + proc = subprocess.run( + cmd, + # Redirect stdin to prevent gdb from messing with the terminal settings + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf8", errors="backslashreplace", + env=env) + + stdout = proc.stdout + stderr = proc.stderr + if proc.returncode != exitcode: + cmd_text = shlex.join(cmd) + raise Exception(f"{cmd_text} failed with exit code {proc.returncode}, " + f"expected exit code {exitcode}:\n" + f"stdout={stdout!r}\n" + f"stderr={stderr!r}") + + return (stdout, stderr) def get_gdb_version(): try: - cmd = ["gdb", "-nx", "--version"] - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True) - with proc: - version, stderr = proc.communicate() - - if proc.returncode: - raise Exception(f"Command {' '.join(cmd)!r} failed " - f"with exit code {proc.returncode}: " - f"stdout={version!r} stderr={stderr!r}") + stdout, stderr = run_gdb('--version') except OSError: # This is what "no gdb" looks like. There may, however, be other # errors that manifest this way too. - raise unittest.SkipTest("Couldn't find gdb on the path") + raise unittest.SkipTest("Couldn't find gdb program on the path") # Regex to parse: # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7 @@ -37,32 +83,48 @@ def get_gdb_version(): # 'GNU gdb 6.1.1 [FreeBSD]\n' -> 6.1 # 'GNU gdb (GDB) Fedora (7.5.1-37.fc18)\n' -> 7.5 # 'HP gdb 6.7 for HP Itanium (32 or 64 bit) and target HP-UX 11iv2 and 11iv3.\n' -> 6.7 - match = re.search(r"^(?:GNU|HP) gdb.*?\b(\d+)\.(\d+)", version) + match = re.search(r"^(?:GNU|HP) gdb.*?\b(\d+)\.(\d+)", stdout) if match is None: - raise Exception("unable to parse GDB version: %r" % version) - return (version, int(match.group(1)), int(match.group(2))) + raise Exception("unable to parse gdb version: %r" % stdout) + version_text = stdout + major = int(match.group(1)) + minor = int(match.group(2)) + version = (major, minor) + return (version_text, version) -gdb_version, gdb_major_version, gdb_minor_version = get_gdb_version() -if gdb_major_version < 7: - raise unittest.SkipTest("gdb versions before 7.0 didn't support python " - "embedding. Saw %s.%s:\n%s" - % (gdb_major_version, gdb_minor_version, - gdb_version)) +GDB_VERSION_TEXT, GDB_VERSION = get_gdb_version() +if GDB_VERSION < (7, 0): + raise unittest.SkipTest( + f"gdb versions before 7.0 didn't support python embedding. " + f"Saw gdb version {GDB_VERSION[0]}.{GDB_VERSION[1]}:\n" + f"{GDB_VERSION_TEXT}") -if not sysconfig.is_python_build(): - raise unittest.SkipTest("test_gdb only works on source builds at the moment.") -if ((sysconfig.get_config_var('PGO_PROF_USE_FLAG') or 'xxx') in - (sysconfig.get_config_var('PY_CORE_CFLAGS') or '')): - raise unittest.SkipTest("test_gdb is not reliable on PGO builds") +def check_usable_gdb(): + # Verify that "gdb" was built with the embedded Python support enabled and + # verify that "gdb" can load our custom hooks, as OS security settings may + # disallow this without a customized .gdbinit. + stdout, stderr = run_gdb( + '--eval-command=python import sys; print(sys.version_info)', + '--args', sys.executable) -# Location of custom hooks file in a repository checkout. -checkout_hook_path = os.path.join(os.path.dirname(sys.executable), - 'python-gdb.py') + if "auto-loading has been declined" in stderr: + raise unittest.SkipTest( + f"gdb security settings prevent use of custom hooks; " + f"stderr: {stderr!r}") -PYTHONHASHSEED = '123' + if not stdout: + raise unittest.SkipTest( + f"gdb not built with embedded python support; " + f"stderr: {stderr!r}") + + if "major=2" in stdout: + raise unittest.SkipTest("gdb built with Python 2") +check_usable_gdb() + +# Control-flow enforcement technology def cet_protection(): cflags = sysconfig.get_config_var('CFLAGS') if not cflags: @@ -74,63 +136,17 @@ def cet_protection(): and any((flag.startswith('-fcf-protection') and not flag.endswith(("=none", "=return"))) for flag in flags)) - -# Control-flow enforcement technology CET_PROTECTION = cet_protection() -def run_gdb(*args, **env_vars): - """Runs gdb in --batch mode with the additional arguments given by *args. - - Returns its (stdout, stderr) decoded from utf-8 using the replace handler. - """ - if env_vars: - env = os.environ.copy() - env.update(env_vars) - else: - env = None - # -nx: Do not execute commands from any .gdbinit initialization files - # (issue #22188) - base_cmd = ('gdb', '--batch', '-nx') - if (gdb_major_version, gdb_minor_version) >= (7, 4): - base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path) - proc = subprocess.Popen(base_cmd + args, - # Redirect stdin to prevent GDB from messing with - # the terminal settings - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=env) - with proc: - out, err = proc.communicate() - return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') - -# Verify that "gdb" was built with the embedded python support enabled: -gdbpy_version, _ = run_gdb("--eval-command=python import sys; print(sys.version_info)") -if not gdbpy_version: - raise unittest.SkipTest("gdb not built with embedded python support") - -if "major=2" in gdbpy_version: - raise unittest.SkipTest("gdb built with Python 2") - -# Verify that "gdb" can load our custom hooks, as OS security settings may -# disallow this without a customized .gdbinit. -_, gdbpy_errors = run_gdb('--args', sys.executable) -if "auto-loading has been declined" in gdbpy_errors: - msg = "gdb security settings prevent use of custom hooks: " - raise unittest.SkipTest(msg + gdbpy_errors.rstrip()) - -BREAKPOINT_FN='builtin_id' - - def setup_module(): if support.verbose: - print("GDB version %s.%s:" % (gdb_major_version, gdb_minor_version)) - for line in gdb_version.splitlines(): + print(f"gdb version {GDB_VERSION[0]}.{GDB_VERSION[1]}:") + for line in GDB_VERSION_TEXT.splitlines(): print(" " * 4 + line) + print() -@unittest.skipIf(support.PGO, "not useful for PGO") class DebuggerTests(unittest.TestCase): """Test that the debugger can debug Python.""" @@ -163,20 +179,22 @@ def get_stack_trace(self, source=None, script=None, # structures # Generate a list of commands in gdb's language: - commands = ['set breakpoint pending yes', - 'break %s' % breakpoint, - - # The tests assume that the first frame of printed - # backtrace will not contain program counter, - # that is however not guaranteed by gdb - # therefore we need to use 'set print address off' to - # make sure the counter is not there. For example: - # #0 in PyObject_Print ... - # is assumed, but sometimes this can be e.g. - # #0 0x00003fffb7dd1798 in PyObject_Print ... - 'set print address off', - - 'run'] + commands = [ + 'set breakpoint pending yes', + 'break %s' % breakpoint, + + # The tests assume that the first frame of printed + # backtrace will not contain program counter, + # that is however not guaranteed by gdb + # therefore we need to use 'set print address off' to + # make sure the counter is not there. For example: + # #0 in PyObject_Print ... + # is assumed, but sometimes this can be e.g. + # #0 0x00003fffb7dd1798 in PyObject_Print ... + 'set print address off', + + 'run', + ] # GDB as of 7.4 onwards can distinguish between the # value of a variable at entry vs current value: @@ -184,7 +202,7 @@ def get_stack_trace(self, source=None, script=None, # which leads to the selftests failing with errors like this: # AssertionError: 'v@entry=()' != '()' # Disable this: - if (gdb_major_version, gdb_minor_version) >= (7, 4): + if GDB_VERSION >= (7, 4): commands += ['set print entry-values no'] if cmds_after_breakpoint: @@ -237,13 +255,16 @@ def get_stack_trace(self, source=None, script=None, for pattern in ( '(frame information optimized out)', 'Unable to read information on python frame', + # gh-91960: On Python built with "clang -Og", gdb gets # "frame=" for _PyEval_EvalFrameDefault() parameter '(unable to read python frame information)', + # gh-104736: On Python built with "clang -Og" on ppc64le, # "py-bt" displays a truncated or not traceback, but "where" # logs this error message: 'Backtrace stopped: frame did not save the PC', + # gh-104736: When "bt" command displays something like: # "#1 0x0000000000000000 in ?? ()", the traceback is likely # truncated or wrong. @@ -254,42 +275,6 @@ def get_stack_trace(self, source=None, script=None, return out - def get_gdb_repr(self, source, - cmds_after_breakpoint=None, - import_site=False): - # Given an input python source representation of data, - # run "python -c'id(DATA)'" under gdb with a breakpoint on - # builtin_id and scrape out gdb's representation of the "op" - # parameter, and verify that the gdb displays the same string - # - # Verify that the gdb displays the expected string - # - # For a nested structure, the first time we hit the breakpoint will - # give us the top-level structure - - # NOTE: avoid decoding too much of the traceback as some - # undecodable characters may lurk there in optimized mode - # (issue #19743). - cmds_after_breakpoint = cmds_after_breakpoint or ["backtrace 1"] - gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN, - cmds_after_breakpoint=cmds_after_breakpoint, - import_site=import_site) - # gdb can insert additional '\n' and space characters in various places - # in its output, depending on the width of the terminal it's connected - # to (using its "wrap_here" function) - m = re.search( - # Match '#0 builtin_id(self=..., v=...)' - r'#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)?\)' - # Match ' at Python/bltinmodule.c'. - # bpo-38239: builtin_id() is defined in Python/bltinmodule.c, - # but accept any "Directory\file.c" to support Link Time - # Optimization (LTO). - r'\s+at\s+\S*[A-Za-z]+/[A-Za-z0-9_-]+\.c', - gdb_output, re.DOTALL) - if not m: - self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output)) - return m.group(1), gdb_output - def assertEndsWith(self, actual, exp_end): '''Ensure that the given "actual" string ends with "exp_end"''' self.assertTrue(actual.endswith(exp_end), @@ -299,6 +284,3 @@ def assertMultilineMatches(self, actual, pattern): m = re.match(pattern, actual, re.DOTALL) if not m: self.fail(msg='%r did not match %r' % (actual, pattern)) - - def get_sample_script(self): - return os.path.join(os.path.dirname(__file__), 'gdb_sample.py') diff --git a/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst b/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst new file mode 100644 index 00000000000000..85c370fc87ac41 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-13-05-58-09.gh-issue-104736.lA25Fu.rst @@ -0,0 +1,4 @@ +Fix test_gdb on Python built with LLVM clang 16 on Linux ppc64le (ex: Fedora +38). Search patterns in gdb "bt" command output to detect when gdb fails to +retrieve the traceback. For example, skip a test if ``Backtrace stopped: frame +did not save the PC`` is found. Patch by Victor Stinner. From ee2f2bdb306a9ea286a64308376adfe5329367f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 04:56:58 -0700 Subject: [PATCH 0932/1206] [3.12] Enhance TypedDict docs around required/optional keys (GH-109547) (#109982) Enhance TypedDict docs around required/optional keys (GH-109547) As discussed in comments to GH-109544, the semantics of this attribute are somewhat confusing. Add a note explaining its limitations and steering users towards __required_keys__ and __optional_keys__ instead. (cherry picked from commit f49958c886a2f2608f1008186d588efc2a98b445) Co-authored-by: Jelle Zijlstra --- Doc/library/typing.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index eb14d11604ae1d..3eae7797925d77 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2392,6 +2392,13 @@ types. >>> Point3D.__total__ True + This attribute reflects *only* the value of the ``total`` argument + to the current ``TypedDict`` class, not whether the class is semantically + total. For example, a ``TypedDict`` with ``__total__`` set to True may + have keys marked with :data:`NotRequired`, or it may inherit from another + ``TypedDict`` with ``total=False``. Therefore, it is generally better to use + :attr:`__required_keys__` and :attr:`__optional_keys__` for introspection. + .. attribute:: __required_keys__ .. versionadded:: 3.9 @@ -2427,6 +2434,14 @@ types. .. versionadded:: 3.9 + .. note:: + + If ``from __future__ import annotations`` is used or if annotations + are given as strings, annotations are not evaluated when the + ``TypedDict`` is defined. Therefore, the runtime introspection that + ``__required_keys__`` and ``__optional_keys__`` rely on may not work + properly, and the values of the attributes may be incorrect. + See :pep:`589` for more examples and detailed rules of using ``TypedDict``. .. versionadded:: 3.8 From 7ec34874e3778267028f4938b30c769b69c8a0b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 04:57:14 -0700 Subject: [PATCH 0933/1206] [3.12] gh-85984: Document change in return type of tty functions (GH-110028) (#110324) gh-85984: Document change in return type of tty functions (GH-110028) (cherry picked from commit f02f26e29366513b097578fbc6b25e02d0eba7c0) Co-authored-by: Jelle Zijlstra --- Doc/library/tty.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/library/tty.rst b/Doc/library/tty.rst index fc7f98c7931fa5..a4777772e1fc6c 100644 --- a/Doc/library/tty.rst +++ b/Doc/library/tty.rst @@ -43,6 +43,9 @@ The :mod:`tty` module defines the following functions: :func:`termios.tcsetattr`. The return value of :func:`termios.tcgetattr` is saved before setting *fd* to raw mode; this value is returned. + .. versionchanged:: 3.12 + The return value is now the original tty attributes, instead of None. + .. function:: setcbreak(fd, when=termios.TCSAFLUSH) @@ -51,6 +54,9 @@ The :mod:`tty` module defines the following functions: :func:`termios.tcsetattr`. The return value of :func:`termios.tcgetattr` is saved before setting *fd* to cbreak mode; this value is returned. + .. versionchanged:: 3.12 + The return value is now the original tty attributes, instead of None. + .. seealso:: From bc1fe3549b32896ef0cbae3d2220ebeaf111d9b8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 06:48:31 -0700 Subject: [PATCH 0934/1206] [3.12] gh-109151: Enable readline in the sqlite3 CLI (GH-109152) (#110352) gh-109151: Enable readline in the sqlite3 CLI (GH-109152) (cherry picked from commit 254e30c487908a52a7545cea205aeaef5fbfeea4) Co-authored-by: Serhiy Storchaka --- Lib/sqlite3/__main__.py | 4 ++++ .../Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst | 1 + 2 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index 3b59763375c147..b93b84384a0925 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -116,6 +116,10 @@ def main(*args): else: # No SQL provided; start the REPL. console = SqliteInteractiveConsole(con) + try: + import readline + except ImportError: + pass console.interact(banner, exitmsg="") finally: con.close() diff --git a/Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst b/Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst new file mode 100644 index 00000000000000..78b4e882baba96 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst @@ -0,0 +1 @@ +Enable ``readline`` editing features in the :ref:`sqlite3 command-line interface ` (``python -m sqlite3``). From e658413e552b4053014e8d52e3b9153895aebfb3 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 4 Oct 2023 08:31:03 -0600 Subject: [PATCH 0935/1206] [3.12] Lint: Remove files that no longer fail to parse (GH-110356) (#110360) Remove files that no longer fail to parse --- Lib/test/.ruff.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml index 98da981c7be1a2..99521dd0ec6574 100644 --- a/Lib/test/.ruff.toml +++ b/Lib/test/.ruff.toml @@ -9,8 +9,6 @@ extend-exclude = [ "encoded_modules/module_koi8_r.py", # Failed to parse "badsyntax_3131.py", - "support/socket_helper.py", - "test_fstring.py", "test_lib2to3/data/bom.py", "test_lib2to3/data/crlf.py", "test_lib2to3/data/different_encoding.py", From 36a7d6becd751357bb7a6b5f0401ac1519b5d2d0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 13:05:21 -0700 Subject: [PATCH 0936/1206] [3.12] Add back bltin-boolean-values ref tag (GH-110371) (#110372) Add back bltin-boolean-values ref tag (GH-110371) To avoid breaking downstream intersphinx via numpydoc (cherry picked from commit f7860295b16a402621e209871c8eaeeea16f464e) Co-authored-by: P. L. Lim <2090236+pllim@users.noreply.github.com> --- Doc/library/stdtypes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 50f56603911182..5e10f696173405 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -804,6 +804,7 @@ number, :class:`float`, or :class:`complex`:: hash_value = -2 return hash_value +.. _bltin-boolean-values: .. _typebool: Boolean Type - :class:`bool` From 4da8c1b61e654b9f2c66e8133f5bf7994e8e59b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 4 Oct 2023 21:26:44 -0700 Subject: [PATCH 0937/1206] [3.12] Remove duplicate word. (GH-110376) (GH-110377) Remove duplicate word. (GH-110376) (cherry picked from commit 313aa861ce23e83ca64284d97c1dac234c9def7c) Co-authored-by: Benjamin Peterson --- Doc/library/sys.monitoring.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 7b02b95fd766a7..5dcbdaf8e5d0e4 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -147,7 +147,7 @@ by another event: * C_RAISE * C_RETURN -The ``C_RETURN`` and ``C_RAISE`` events are are controlled by the ``CALL`` +The ``C_RETURN`` and ``C_RAISE`` events are controlled by the ``CALL`` event. ``C_RETURN`` and ``C_RAISE`` events will only be seen if the corresponding ``CALL`` event is being monitored. From 7bfcfcf6565dcf609854a82a7976faa7f7446fea Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 05:21:03 -0700 Subject: [PATCH 0938/1206] [3.12] gh-110365: Fix error overwrite in `termios.tcsetattr` (GH-110366) (#110389) (cherry picked from commit 2bbbab212fb10b3aeaded188fb5d6c001fb4bf74) Co-authored-by: Nikita Sobolev Co-authored-by: Erlend E. Aasland --- ...-10-04-18-56-29.gh-issue-110365.LCxiau.rst | 2 + Modules/termios.c | 39 ++++++++++++------- 2 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-04-18-56-29.gh-issue-110365.LCxiau.rst diff --git a/Misc/NEWS.d/next/Library/2023-10-04-18-56-29.gh-issue-110365.LCxiau.rst b/Misc/NEWS.d/next/Library/2023-10-04-18-56-29.gh-issue-110365.LCxiau.rst new file mode 100644 index 00000000000000..a1ac39b60296a3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-04-18-56-29.gh-issue-110365.LCxiau.rst @@ -0,0 +1,2 @@ +Fix :func:`termios.tcsetattr` bug that was overwritting existing errors +during parsing integers from ``term`` list. diff --git a/Modules/termios.c b/Modules/termios.c index 6dc8200572bc0c..c3d96cc5b2c00d 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -183,17 +183,25 @@ termios_tcsetattr_impl(PyObject *module, int fd, int when, PyObject *term) return PyErr_SetFromErrno(state->TermiosError); } - mode.c_iflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 0)); - mode.c_oflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 1)); - mode.c_cflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 2)); - mode.c_lflag = (tcflag_t) PyLong_AsLong(PyList_GetItem(term, 3)); - speed_t ispeed = (speed_t) PyLong_AsLong(PyList_GetItem(term, 4)); - speed_t ospeed = (speed_t) PyLong_AsLong(PyList_GetItem(term, 5)); - PyObject *cc = PyList_GetItem(term, 6); - if (PyErr_Occurred()) { - return NULL; - } - + speed_t ispeed, ospeed; +#define SET_FROM_LIST(TYPE, VAR, LIST, N) do { \ + PyObject *item = PyList_GET_ITEM(LIST, N); \ + long num = PyLong_AsLong(item); \ + if (num == -1 && PyErr_Occurred()) { \ + return NULL; \ + } \ + VAR = (TYPE)num; \ +} while (0) + + SET_FROM_LIST(tcflag_t, mode.c_iflag, term, 0); + SET_FROM_LIST(tcflag_t, mode.c_oflag, term, 1); + SET_FROM_LIST(tcflag_t, mode.c_cflag, term, 2); + SET_FROM_LIST(tcflag_t, mode.c_lflag, term, 3); + SET_FROM_LIST(speed_t, ispeed, term, 4); + SET_FROM_LIST(speed_t, ospeed, term, 5); +#undef SET_FROM_LIST + + PyObject *cc = PyList_GET_ITEM(term, 6); if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) { PyErr_Format(PyExc_TypeError, "tcsetattr: attributes[6] must be %d element list", @@ -208,8 +216,13 @@ termios_tcsetattr_impl(PyObject *module, int fd, int when, PyObject *term) if (PyBytes_Check(v) && PyBytes_Size(v) == 1) mode.c_cc[i] = (cc_t) * PyBytes_AsString(v); - else if (PyLong_Check(v)) - mode.c_cc[i] = (cc_t) PyLong_AsLong(v); + else if (PyLong_Check(v)) { + long num = PyLong_AsLong(v); + if (num == -1 && PyErr_Occurred()) { + return NULL; + } + mode.c_cc[i] = (cc_t)num; + } else { PyErr_SetString(PyExc_TypeError, "tcsetattr: elements of attributes must be characters or integers"); From 09ec8153c6480fd608ce6f981a050f515f1875c9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 07:07:25 -0700 Subject: [PATCH 0939/1206] [3.12] gh-110259: Fix f-strings with multiline expressions and format specs (GH-110271) (#110396) gh-110259: Fix f-strings with multiline expressions and format specs (GH-110271) (cherry picked from commit cc389ef627b2a486ab89d9a11245bef48224efb1) Signed-off-by: Pablo Galindo Co-authored-by: Pablo Galindo Salgado --- Lib/ast.py | 11 ++- Lib/test/test_tokenize.py | 97 +++++++++++++++++++ Lib/test/test_unparse.py | 3 +- ...-10-03-11-43-48.gh-issue-110259.ka93x5.rst | 3 + Parser/tokenizer.c | 24 +++-- 5 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-03-11-43-48.gh-issue-110259.ka93x5.rst diff --git a/Lib/ast.py b/Lib/ast.py index 07044706dc3608..de940d2e9c6549 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1268,13 +1268,15 @@ def visit_JoinedStr(self, node): quote_type = quote_types[0] self.write(f"{quote_type}{value}{quote_type}") - def _write_fstring_inner(self, node): + def _write_fstring_inner(self, node, scape_newlines=False): if isinstance(node, JoinedStr): # for both the f-string itself, and format_spec for value in node.values: - self._write_fstring_inner(value) + self._write_fstring_inner(value, scape_newlines=scape_newlines) elif isinstance(node, Constant) and isinstance(node.value, str): value = node.value.replace("{", "{{").replace("}", "}}") + if scape_newlines: + value = value.replace("\n", "\\n") self.write(value) elif isinstance(node, FormattedValue): self.visit_FormattedValue(node) @@ -1297,7 +1299,10 @@ def unparse_inner(inner): self.write(f"!{chr(node.conversion)}") if node.format_spec: self.write(":") - self._write_fstring_inner(node.format_spec) + self._write_fstring_inner( + node.format_spec, + scape_newlines=True + ) def visit_Name(self, node): self.write(node.id) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 40680f004723c5..b8d069a87843e4 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -571,6 +571,55 @@ def test_string(self): OP '=' (3, 0) (3, 1) OP '}' (3, 1) (3, 2) FSTRING_END "'''" (3, 2) (3, 5) + """) + self.check_tokenize("""\ +f'''__{ + x:a +}__'''""", """\ + FSTRING_START "f'''" (1, 0) (1, 4) + FSTRING_MIDDLE '__' (1, 4) (1, 6) + OP '{' (1, 6) (1, 7) + NL '\\n' (1, 7) (1, 8) + NAME 'x' (2, 4) (2, 5) + OP ':' (2, 5) (2, 6) + FSTRING_MIDDLE 'a\\n' (2, 6) (3, 0) + OP '}' (3, 0) (3, 1) + FSTRING_MIDDLE '__' (3, 1) (3, 3) + FSTRING_END "'''" (3, 3) (3, 6) + """) + self.check_tokenize("""\ +f'''__{ + x:a + b + c + d +}__'''""", """\ + FSTRING_START "f'''" (1, 0) (1, 4) + FSTRING_MIDDLE '__' (1, 4) (1, 6) + OP '{' (1, 6) (1, 7) + NL '\\n' (1, 7) (1, 8) + NAME 'x' (2, 4) (2, 5) + OP ':' (2, 5) (2, 6) + FSTRING_MIDDLE 'a\\n b\\n c\\n d\\n' (2, 6) (6, 0) + OP '}' (6, 0) (6, 1) + FSTRING_MIDDLE '__' (6, 1) (6, 3) + FSTRING_END "'''" (6, 3) (6, 6) + """) + self.check_tokenize("""\ +f'__{ + x:d +}__'""", """\ + FSTRING_START "f'" (1, 0) (1, 2) + FSTRING_MIDDLE '__' (1, 2) (1, 4) + OP '{' (1, 4) (1, 5) + NL '\\n' (1, 5) (1, 6) + NAME 'x' (2, 4) (2, 5) + OP ':' (2, 5) (2, 6) + FSTRING_MIDDLE 'd' (2, 6) (2, 7) + NL '\\n' (2, 7) (2, 8) + OP '}' (3, 0) (3, 1) + FSTRING_MIDDLE '__' (3, 1) (3, 3) + FSTRING_END "'" (3, 3) (3, 4) """) def test_function(self): @@ -2274,6 +2323,54 @@ def test_string(self): FSTRING_START \'f"\' (1, 0) (1, 2) FSTRING_MIDDLE 'hola\\\\\\\\\\\\r\\\\ndfgf' (1, 2) (1, 16) FSTRING_END \'"\' (1, 16) (1, 17) + """) + + self.check_tokenize("""\ +f'''__{ + x:a +}__'''""", """\ + FSTRING_START "f'''" (1, 0) (1, 4) + FSTRING_MIDDLE '__' (1, 4) (1, 6) + LBRACE '{' (1, 6) (1, 7) + NAME 'x' (2, 4) (2, 5) + COLON ':' (2, 5) (2, 6) + FSTRING_MIDDLE 'a\\n' (2, 6) (3, 0) + RBRACE '}' (3, 0) (3, 1) + FSTRING_MIDDLE '__' (3, 1) (3, 3) + FSTRING_END "'''" (3, 3) (3, 6) + """) + + self.check_tokenize("""\ +f'''__{ + x:a + b + c + d +}__'''""", """\ + FSTRING_START "f'''" (1, 0) (1, 4) + FSTRING_MIDDLE '__' (1, 4) (1, 6) + LBRACE '{' (1, 6) (1, 7) + NAME 'x' (2, 4) (2, 5) + COLON ':' (2, 5) (2, 6) + FSTRING_MIDDLE 'a\\n b\\n c\\n d\\n' (2, 6) (6, 0) + RBRACE '}' (6, 0) (6, 1) + FSTRING_MIDDLE '__' (6, 1) (6, 3) + FSTRING_END "'''" (6, 3) (6, 6) + """) + + self.check_tokenize("""\ +f'__{ + x:d +}__'""", """\ + FSTRING_START "f'" (1, 0) (1, 2) + FSTRING_MIDDLE '__' (1, 2) (1, 4) + LBRACE '{' (1, 4) (1, 5) + NAME 'x' (2, 4) (2, 5) + COLON ':' (2, 5) (2, 6) + FSTRING_MIDDLE 'd' (2, 6) (2, 7) + RBRACE '}' (3, 0) (3, 1) + FSTRING_MIDDLE '__' (3, 1) (3, 3) + FSTRING_END "'" (3, 3) (3, 4) """) def test_function(self): diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index bdf7b0588bee67..6f698a8d891815 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -730,7 +730,8 @@ class DirectoryTestCase(ASTTestCase): test_directories = (lib_dir, lib_dir / "test") run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py", "test_ast.py", "test_asdl_parser.py", "test_fstring.py", - "test_patma.py", "test_type_alias.py", "test_type_params.py"} + "test_patma.py", "test_type_alias.py", "test_type_params.py", + "test_tokenize.py"} _files_to_test = None diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-03-11-43-48.gh-issue-110259.ka93x5.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-03-11-43-48.gh-issue-110259.ka93x5.rst new file mode 100644 index 00000000000000..55c743d0e4917e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-03-11-43-48.gh-issue-110259.ka93x5.rst @@ -0,0 +1,3 @@ +Correctly identify the format spec in f-strings (with single or triple +quotes) that have multiple lines in the expression part and include a +formatting spec. Patch by Pablo Galindo diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 9911fa55d47c9f..a7786d0c17e9e3 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2768,11 +2768,28 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct if (tok->done == E_ERROR) { return MAKE_TOKEN(ERRORTOKEN); } - if (c == EOF || (current_tok->f_string_quote_size == 1 && c == '\n')) { + int in_format_spec = ( + current_tok->last_expr_end != -1 + && + INSIDE_FSTRING_EXPR(current_tok) + ); + + if (c == EOF || (current_tok->f_string_quote_size == 1 && c == '\n')) { if (tok->decoding_erred) { return MAKE_TOKEN(ERRORTOKEN); } + // If we are in a format spec and we found a newline, + // it means that the format spec ends here and we should + // return to the regular mode. + if (in_format_spec && c == '\n') { + tok_backup(tok, c); + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(FSTRING_MIDDLE); + } + assert(tok->multi_line_start != NULL); // shift the tok_state's location into // the start of string, and report the error @@ -2804,11 +2821,6 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct end_quote_size = 0; } - int in_format_spec = ( - current_tok->last_expr_end != -1 - && - INSIDE_FSTRING_EXPR(current_tok) - ); if (c == '{') { int peek = tok_nextc(tok); if (peek != '{' || in_format_spec) { From 4a87f927245a5eb4f007d9ba6cb0fbc96292e3a6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 10:01:59 -0700 Subject: [PATCH 0940/1206] [3.12] gh-110391: socket NetworkConnectionAttributesTest always declare cli (GH-110401) (#110405) gh-110391: socket NetworkConnectionAttributesTest always declare cli (GH-110401) NetworkConnectionAttributesTest of test_socket now always declare the 'cli' attribute, so clientTearDown() cannot fail with AttributeError. (cherry picked from commit e37d4557c3de0476e76ca4b8a1cc8d2566b86c79) Co-authored-by: Victor Stinner --- Lib/test/test_socket.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 99c4c5cbc4902d..09605f7e774dda 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5356,6 +5356,7 @@ def test_create_connection_timeout(self): class NetworkConnectionAttributesTest(SocketTCPTest, ThreadableTest): + cli = None def __init__(self, methodName='runTest'): SocketTCPTest.__init__(self, methodName=methodName) @@ -5365,7 +5366,8 @@ def clientSetUp(self): self.source_port = socket_helper.find_unused_port() def clientTearDown(self): - self.cli.close() + if self.cli is not None: + self.cli.close() self.cli = None ThreadableTest.clientTearDown(self) From 5635913125faec07deb31cc8b35d515cc5a80efa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 10:40:19 -0700 Subject: [PATCH 0941/1206] [3.12] Fix env var typo in perf profiling docs (GH-110404) (#110414) Fix env var typo in perf profiling docs (GH-110404) Fix typo in docs (cherry picked from commit a13620685f68957c965fca89343a0e91f95f1bab) Co-authored-by: Harmen Stoppels --- Doc/howto/perf_profiling.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst index 61812c19ae6ca9..af7b67d2042950 100644 --- a/Doc/howto/perf_profiling.rst +++ b/Doc/howto/perf_profiling.rst @@ -162,8 +162,7 @@ the :option:`!-X` option takes precedence over the environment variable. Example, using the environment variable:: - $ PYTHONPERFSUPPORT=1 - $ python script.py + $ PYTHONPERFSUPPORT=1 python script.py $ perf report -g -i perf.data Example, using the :option:`!-X` option:: From 5b66fe8304feaf39754e83c21cdfea110e688434 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 10:42:52 -0700 Subject: [PATCH 0942/1206] [3.12] gh-110383 TimeIt Docs Spelling Fix (GH-110407) (#110409) gh-110383 TimeIt Docs Spelling Fix (GH-110407) Make 0.2 second plural (cherry picked from commit a973bf0f97e55ace9eab100f9eb95d7eedcb28ac) Co-authored-by: Towster15 <105541074+Towster15@users.noreply.github.com> --- Doc/library/timeit.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst index 60ec135873c414..616f8365b80f6c 100644 --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -151,7 +151,7 @@ The module defines three convenience functions and a public class: so that the total time >= 0.2 second, returning the eventual (number of loops, time taken for that number of loops). It calls :meth:`.timeit` with increasing numbers from the sequence 1, 2, 5, - 10, 20, 50, ... until the time taken is at least 0.2 second. + 10, 20, 50, ... until the time taken is at least 0.2 seconds. If *callback* is given and is not ``None``, it will be called after each trial with two arguments: ``callback(number, time_taken)``. From 2ab41c8fbc6beafebe44f232227cb593cbe7a0bd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 12:24:26 -0700 Subject: [PATCH 0943/1206] [3.12] gh-110167: Fix test_socket deadlock in doCleanups() (GH-110416) (#110423) gh-110167: Fix test_socket deadlock in doCleanups() (GH-110416) Fix a deadlock in test_socket when server fails with a timeout but the client is still running in its thread. Don't hold a lock to call cleanup functions in doCleanups(). One of the cleanup function waits until the client completes, whereas the client could deadlock if it called addCleanup() in such situation. doCleanups() is called when the server completed, but the client can still be running in its thread especially if the server failed with a timeout. Don't put a lock on doCleanups() to prevent deadlock between addCleanup() called in the client and doCleanups() waiting for self.done.wait of ThreadableTest._setUp(). (cherry picked from commit 318f5df27109ff8d2519edefa771920a0ec62b92) Co-authored-by: Victor Stinner --- Lib/test/test_socket.py | 12 +++++++----- .../2023-10-05-19-33-49.gh-issue-110167.mIdj3v.rst | 5 +++++ 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-05-19-33-49.gh-issue-110167.mIdj3v.rst diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 09605f7e774dda..0d1c1867a25c40 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -218,8 +218,13 @@ def setUp(self): class ThreadSafeCleanupTestCase: """Subclass of unittest.TestCase with thread-safe cleanup methods. - This subclass protects the addCleanup() and doCleanups() methods - with a recursive lock. + This subclass protects the addCleanup() method with a recursive lock. + + doCleanups() is called when the server completed, but the client can still + be running in its thread especially if the server failed with a timeout. + Don't put a lock on doCleanups() to prevent deadlock between addCleanup() + called in the client and doCleanups() waiting for self.done.wait of + ThreadableTest._setUp() (gh-110167) """ def __init__(self, *args, **kwargs): @@ -230,9 +235,6 @@ def addCleanup(self, *args, **kwargs): with self._cleanup_lock: return super().addCleanup(*args, **kwargs) - def doCleanups(self, *args, **kwargs): - with self._cleanup_lock: - return super().doCleanups(*args, **kwargs) class SocketCANTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Tests/2023-10-05-19-33-49.gh-issue-110167.mIdj3v.rst b/Misc/NEWS.d/next/Tests/2023-10-05-19-33-49.gh-issue-110167.mIdj3v.rst new file mode 100644 index 00000000000000..d0cbbf9c3788bb --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-05-19-33-49.gh-issue-110167.mIdj3v.rst @@ -0,0 +1,5 @@ +Fix a deadlock in test_socket when server fails with a timeout but the +client is still running in its thread. Don't hold a lock to call cleanup +functions in doCleanups(). One of the cleanup function waits until the +client completes, whereas the client could deadlock if it called +addCleanup() in such situation. Patch by Victor Stinner. From 11137d38222f7874c8cbffe91bd656983288a9b0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:03:53 -0700 Subject: [PATCH 0944/1206] [3.12] gh-109840: Fix multiprocessing test_waitfor_timeout() (GH-110428) (#110430) gh-109840: Fix multiprocessing test_waitfor_timeout() (GH-110428) Don't measure the CI performance: don't fail if cond.wait_for() takes longer than 1 second on a slow CI. (cherry picked from commit 5eae8dc2cb832af6ae1ee340fb0194107fe3bd6e) Co-authored-by: Victor Stinner --- Lib/test/_test_multiprocessing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 34027b004f5602..80ebdbfc997bc2 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -1651,12 +1651,12 @@ def test_waitfor(self): def _test_waitfor_timeout_f(cls, cond, state, success, sem): sem.release() with cond: - expected = 0.1 + expected = 0.100 dt = time.monotonic() result = cond.wait_for(lambda : state.value==4, timeout=expected) dt = time.monotonic() - dt # borrow logic in assertTimeout() from test/lock_tests.py - if not result and expected * 0.6 < dt < expected * 10.0: + if not result and expected * 0.6 <= dt: success.value = True @unittest.skipUnless(HAS_SHAREDCTYPES, 'needs sharedctypes') @@ -1675,7 +1675,7 @@ def test_waitfor_timeout(self): # Only increment 3 times, so state == 4 is never reached. for i in range(3): - time.sleep(0.01) + time.sleep(0.010) with cond: state.value += 1 cond.notify() From 93279cc8b88ea9964fc5f82e30e754ee223d6453 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:14:22 -0700 Subject: [PATCH 0945/1206] [3.12] gh-110383: Swap 'the all' -> 'all the' in socket docs (GH-110434) (#110435) Co-authored-by: Bradley Reynolds --- Doc/library/socket.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 83957c87990440..7fb47ce2b84593 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -2100,7 +2100,7 @@ The next two examples are identical to the above two, but support both IPv4 and IPv6. The server side will listen to the first address family available (it should listen to both instead). On most of IPv6-ready systems, IPv6 will take precedence and the server may not accept IPv4 traffic. The client side will try -to connect to the all addresses returned as a result of the name resolution, and +to connect to all the addresses returned as a result of the name resolution, and sends traffic to the first one connected successfully. :: # Echo server program From 350d89b79588ebd140c3987cc05e3719ca17a973 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 5 Oct 2023 22:37:20 +0200 Subject: [PATCH 0946/1206] [3.12] gh-110167: Increase support.LOOPBACK_TIMEOUT to 10 seconds (#110413) (#110427) gh-110167: Increase support.LOOPBACK_TIMEOUT to 10 seconds (#110413) Increase support.LOOPBACK_TIMEOUT from 5 to 10 seconds. Also increase the timeout depending on the --timeout option. For example, for a test timeout of 40 minutes (ARM Raspbian 3.x), use LOOPBACK_TIMEOUT of 20 seconds instead of 5 seconds before. (cherry picked from commit 0db2f1475e6539e1954e1f8bd53e005c3ecd6a26) --- Lib/test/libregrtest/setup.py | 17 ++++++++++------- Lib/test/support/__init__.py | 8 +------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index b76bece7ca08b5..ec021668553fb4 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -88,16 +88,19 @@ def _test_audit_hook(name, args): setup_unraisable_hook() setup_threading_excepthook() - if ns.timeout is not None: + timeout = ns.timeout + if timeout is not None: # For a slow buildbot worker, increase SHORT_TIMEOUT and LONG_TIMEOUT - support.SHORT_TIMEOUT = max(support.SHORT_TIMEOUT, ns.timeout / 40) - support.LONG_TIMEOUT = max(support.LONG_TIMEOUT, ns.timeout / 4) + support.LOOPBACK_TIMEOUT = max(support.LOOPBACK_TIMEOUT, timeout / 120) + # don't increase INTERNET_TIMEOUT + support.SHORT_TIMEOUT = max(support.SHORT_TIMEOUT, timeout / 40) + support.LONG_TIMEOUT = max(support.LONG_TIMEOUT, timeout / 4) # If --timeout is short: reduce timeouts - support.LOOPBACK_TIMEOUT = min(support.LOOPBACK_TIMEOUT, ns.timeout) - support.INTERNET_TIMEOUT = min(support.INTERNET_TIMEOUT, ns.timeout) - support.SHORT_TIMEOUT = min(support.SHORT_TIMEOUT, ns.timeout) - support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, ns.timeout) + support.LOOPBACK_TIMEOUT = min(support.LOOPBACK_TIMEOUT, timeout) + support.INTERNET_TIMEOUT = min(support.INTERNET_TIMEOUT, timeout) + support.SHORT_TIMEOUT = min(support.SHORT_TIMEOUT, timeout) + support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, timeout) if ns.xmlpath: from test.support.testresult import RegressionTestResult diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 29ea944a3bfce9..fb69d9f7af018d 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -74,13 +74,7 @@ # # The timeout should be long enough for connect(), recv() and send() methods # of socket.socket. -LOOPBACK_TIMEOUT = 5.0 -if sys.platform == 'win32' and ' 32 bit (ARM)' in sys.version: - # bpo-37553: test_socket.SendfileUsingSendTest is taking longer than 2 - # seconds on Windows ARM32 buildbot - LOOPBACK_TIMEOUT = 10 -elif sys.platform == 'vxworks': - LOOPBACK_TIMEOUT = 10 +LOOPBACK_TIMEOUT = 10.0 # Timeout in seconds for network requests going to the internet. The timeout is # short enough to prevent a test to wait for too long if the internet request From 5a4e821b436710bc9814513965ec9ad097c4adac Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:54:47 -0700 Subject: [PATCH 0947/1206] [3.12] gh-110429: Fix race condition in "make regen-all" (GH-110433) (#110438) gh-110429: Fix race condition in "make regen-all" (GH-110433) "make regen-pegen" now creates a temporary file called "parser.c.new" instead of "parser.new.c". Previously, if "make clinic" was run in parallel with "make regen-all", clinic may try but fail to open "parser.new.c" if the temporay file was removed in the meanwhile. (cherry picked from commit fb6c4ed2bbb2a867d5f0b9a94656e4714be5d9c2) Co-authored-by: Victor Stinner --- Makefile.pre.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index a2e8458b62c989..d882c0cd672240 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1396,8 +1396,8 @@ regen-pegen: PYTHONPATH=$(srcdir)/Tools/peg_generator $(PYTHON_FOR_REGEN) -m pegen -q c \ $(srcdir)/Grammar/python.gram \ $(srcdir)/Grammar/Tokens \ - -o $(srcdir)/Parser/parser.new.c - $(UPDATE_FILE) $(srcdir)/Parser/parser.c $(srcdir)/Parser/parser.new.c + -o $(srcdir)/Parser/parser.c.new + $(UPDATE_FILE) $(srcdir)/Parser/parser.c $(srcdir)/Parser/parser.c.new .PHONY: regen-ast regen-ast: From 1b589850774e6386d7c04fd113a0879afa21f07c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:17:20 -0700 Subject: [PATCH 0948/1206] [3.12] gh-110393: Remove watchdog with hardcoded timeout (GH-110400) (#110445) gh-110393: Remove watchdog with hardcoded timeout (GH-110400) test_builtin and test_socketserver no longer use signal.alarm() to implement a watchdog with a hardcoded timeout (2 and 60 seconds). Python test runner regrtest has two watchdogs: faulthandler and timeout on running worker processes. Tests using short hardcoded timeout can fail on slowest buildbots just because the timeout is too short. (cherry picked from commit 1328fa31fe9c72748fc6fd11d017c82aafd48a49) Co-authored-by: Victor Stinner --- Lib/test/test_builtin.py | 2 -- Lib/test/test_socketserver.py | 7 ------- 2 files changed, 9 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index daac1008829b4c..78d5354f9cd180 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -2178,8 +2178,6 @@ def _run_child(self, child, terminal_input): if pid == 0: # Child try: - # Make sure we don't get stuck if there's a problem - signal.alarm(2) os.close(r) with open(w, "w") as wpipe: child(wpipe) diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py index c81d559cde315d..0f62f9eb200e42 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -32,11 +32,6 @@ HAVE_FORKING = test.support.has_fork_support requires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking') -def signal_alarm(n): - """Call signal.alarm when it exists (i.e. not on Windows).""" - if hasattr(signal, 'alarm'): - signal.alarm(n) - # Remember real select() to avoid interferences with mocking _real_select = select.select @@ -68,12 +63,10 @@ class SocketServerTest(unittest.TestCase): """Test all socket servers.""" def setUp(self): - signal_alarm(60) # Kill deadlocks after 60 seconds. self.port_seed = 0 self.test_files = [] def tearDown(self): - signal_alarm(0) # Didn't deadlock. reap_children() for fn in self.test_files: From 6af359b088cc5cecb98add1302e2788d57a83011 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:20:55 -0700 Subject: [PATCH 0949/1206] [3.12] gh-109888: Fix test_os _kill_with_event() on Windows (GH-110421) (#110442) gh-109888: Fix test_os _kill_with_event() on Windows (GH-110421) Replace os.kill() with proc.kill() which catchs PermissionError. Rewrite _kill_with_event(): * Use subprocess context manager ("with proc:"). * Use sleeping_retry() to wait until the child process is ready. * Replace SIGINT with proc.kill() on error. * Replace 10 seconds with SHORT_TIMEOUT to wait until the process is ready. * Replace 0.5 seconds with SHORT_TIMEOUT to wait for the process exit. (cherry picked from commit aaf297c048694cd9652790f8b74e69f7ddadfbde) Co-authored-by: Victor Stinner --- Lib/test/test_os.py | 50 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 3cc5a6aaafcf36..38464c60a84315 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2559,30 +2559,34 @@ def _kill_with_event(self, event, name): tagname = "test_os_%s" % uuid.uuid1() m = mmap.mmap(-1, 1, tagname) m[0] = 0 + # Run a script which has console control handling enabled. - proc = subprocess.Popen([sys.executable, - os.path.join(os.path.dirname(__file__), - "win_console_handler.py"), tagname], - creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) - # Let the interpreter startup before we send signals. See #3137. - count, max = 0, 100 - while count < max and proc.poll() is None: - if m[0] == 1: - break - time.sleep(0.1) - count += 1 - else: - # Forcefully kill the process if we weren't able to signal it. - os.kill(proc.pid, signal.SIGINT) - self.fail("Subprocess didn't finish initialization") - os.kill(proc.pid, event) - # proc.send_signal(event) could also be done here. - # Allow time for the signal to be passed and the process to exit. - time.sleep(0.5) - if not proc.poll(): - # Forcefully kill the process if we weren't able to signal it. - os.kill(proc.pid, signal.SIGINT) - self.fail("subprocess did not stop on {}".format(name)) + script = os.path.join(os.path.dirname(__file__), + "win_console_handler.py") + cmd = [sys.executable, script, tagname] + proc = subprocess.Popen(cmd, + creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) + + with proc: + # Let the interpreter startup before we send signals. See #3137. + for _ in support.sleeping_retry(support.SHORT_TIMEOUT): + if proc.poll() is None: + break + else: + # Forcefully kill the process if we weren't able to signal it. + proc.kill() + self.fail("Subprocess didn't finish initialization") + + os.kill(proc.pid, event) + + try: + # proc.send_signal(event) could also be done here. + # Allow time for the signal to be passed and the process to exit. + proc.wait(timeout=support.SHORT_TIMEOUT) + except subprocess.TimeoutExpired: + # Forcefully kill the process if we weren't able to signal it. + proc.kill() + self.fail("subprocess did not stop on {}".format(name)) @unittest.skip("subprocesses aren't inheriting Ctrl+C property") @support.requires_subprocess() From 67028f0c159d9d83528d1890d8e9543157efb8b7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 18:23:15 -0700 Subject: [PATCH 0950/1206] [3.12] gh-103053: Fix make check-clean-src: check "python" program (GH-110449) (#110453) gh-103053: Fix make check-clean-src: check "python" program (GH-110449) "make check-clean-src" now also checks if the "python" program is found in the source directory: fail with an error if it does exist. (cherry picked from commit a155f9f3427578ca5706d27e20bd0576f0395073) Co-authored-by: Victor Stinner --- Makefile.pre.in | 3 ++- .../next/Build/2023-10-06-02-15-23.gh-issue-103053.--7JUF.rst | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2023-10-06-02-15-23.gh-issue-103053.--7JUF.rst diff --git a/Makefile.pre.in b/Makefile.pre.in index d882c0cd672240..f3c2d8bf260de2 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -623,7 +623,8 @@ build_wasm: check-clean-src $(BUILDPYTHON) platform sharedmods \ .PHONY: check-clean-src check-clean-src: @if test -n "$(VPATH)" -a \( \ - -f "$(srcdir)/Programs/python.o" \ + -f "$(srcdir)/$(BUILDPYTHON)" \ + -o -f "$(srcdir)/Programs/python.o" \ -o -f "$(srcdir)\Python/frozen_modules/importlib._bootstrap.h" \ \); then \ echo "Error: The source directory ($(srcdir)) is not clean" ; \ diff --git a/Misc/NEWS.d/next/Build/2023-10-06-02-15-23.gh-issue-103053.--7JUF.rst b/Misc/NEWS.d/next/Build/2023-10-06-02-15-23.gh-issue-103053.--7JUF.rst new file mode 100644 index 00000000000000..81aa21357287c7 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-10-06-02-15-23.gh-issue-103053.--7JUF.rst @@ -0,0 +1,3 @@ +"make check-clean-src" now also checks if the "python" program is found in +the source directory: fail with an error if it does exist. Patch by Victor +Stinner. From e188534607761af1f8faba483ce0b1e8578c73e5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 6 Oct 2023 03:26:14 +0200 Subject: [PATCH 0951/1206] [3.12] Add support.MS_WINDOWS constant (#110446) (#110452) Add support.MS_WINDOWS constant (#110446) (cherry picked from commit e0c44377935de3491b2cbe1e5f87f8b336fdc922) --- Lib/test/_test_embed_set_config.py | 2 +- Lib/test/pythoninfo.py | 13 +++++++++++++ Lib/test/support/__init__.py | 4 +++- Lib/test/test_asyncio/test_subprocess.py | 5 ++--- Lib/test/test_cppext/__init__.py | 3 +-- Lib/test/test_cppext/setup.py | 6 ++---- Lib/test/test_embed.py | 7 ++----- Lib/test/test_faulthandler.py | 4 +--- Lib/test/test_gdb/__init__.py | 3 +-- Lib/test/test_utf8_mode.py | 3 +-- 10 files changed, 27 insertions(+), 23 deletions(-) diff --git a/Lib/test/_test_embed_set_config.py b/Lib/test/_test_embed_set_config.py index 0c016b5d75d734..a2ddd133cf47c8 100644 --- a/Lib/test/_test_embed_set_config.py +++ b/Lib/test/_test_embed_set_config.py @@ -9,9 +9,9 @@ import os import sys import unittest +from test.support import MS_WINDOWS -MS_WINDOWS = (os.name == 'nt') MAX_HASH_SEED = 4294967295 class SetConfigTests(unittest.TestCase): diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index 1ec04de3c0c94f..c0b21124499df0 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -704,6 +704,19 @@ def collect_test_support(info_add): attributes = ('IPV6_ENABLED',) copy_attributes(info_add, support, 'test_support.%s', attributes) + attributes = ( + 'MS_WINDOWS', + 'has_fork_support', + 'has_socket_support', + 'has_strftime_extensions', + 'has_subprocess_support', + 'is_android', + 'is_emscripten', + 'is_jython', + 'is_wasi', + ) + copy_attributes(info_add, support, 'support.%s', attributes) + call_func(info_add, 'test_support._is_gui_available', support, '_is_gui_available') call_func(info_add, 'test_support.python_is_optimized', support, 'python_is_optimized') diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index fb69d9f7af018d..22495748ddb097 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -46,7 +46,7 @@ "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", "requires_limited_api", "requires_specialization", # sys - "is_jython", "is_android", "is_emscripten", "is_wasi", + "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", "check_impl_detail", "unix_shell", "setswitchinterval", # os "get_pagesize", @@ -509,6 +509,8 @@ def requires_legacy_unicode_capi(): return unittest.skipUnless(unicode_legacy_string, 'requires legacy Unicode C API') +MS_WINDOWS = (sys.platform == 'win32') + # Is not actually used in tests, but is kept for compatibility. is_jython = sys.platform.startswith('java') diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index dc5a48d500e8d5..179c8cb8cc17cf 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -14,8 +14,7 @@ from test.support import os_helper -MS_WINDOWS = (sys.platform == 'win32') -if MS_WINDOWS: +if support.MS_WINDOWS: import msvcrt else: from asyncio import unix_events @@ -283,7 +282,7 @@ def test_stdin_broken_pipe(self): rfd, wfd = os.pipe() self.addCleanup(os.close, rfd) self.addCleanup(os.close, wfd) - if MS_WINDOWS: + if support.MS_WINDOWS: handle = msvcrt.get_osfhandle(rfd) os.set_handle_inheritable(handle, True) code = textwrap.dedent(f''' diff --git a/Lib/test/test_cppext/__init__.py b/Lib/test/test_cppext/__init__.py index a322f417a774f0..f02a823bd22176 100644 --- a/Lib/test/test_cppext/__init__.py +++ b/Lib/test/test_cppext/__init__.py @@ -10,7 +10,6 @@ from test.support import os_helper -MS_WINDOWS = (sys.platform == 'win32') SOURCE = os.path.join(os.path.dirname(__file__), 'extension.cpp') SETUP = os.path.join(os.path.dirname(__file__), 'setup.py') @@ -27,7 +26,7 @@ def test_build_cpp03(self): # With MSVC, the linker fails with: cannot open file 'python311.lib' # https://github.com/python/cpython/pull/32175#issuecomment-1111175897 - @unittest.skipIf(MS_WINDOWS, 'test fails on Windows') + @unittest.skipIf(support.MS_WINDOWS, 'test fails on Windows') # Building and running an extension in clang sanitizing mode is not # straightforward @unittest.skipIf( diff --git a/Lib/test/test_cppext/setup.py b/Lib/test/test_cppext/setup.py index 976633bc33889c..c7ba1efb4dd05a 100644 --- a/Lib/test/test_cppext/setup.py +++ b/Lib/test/test_cppext/setup.py @@ -4,15 +4,13 @@ import shlex import sys import sysconfig +from test import support from setuptools import setup, Extension -MS_WINDOWS = (sys.platform == 'win32') - - SOURCE = 'extension.cpp' -if not MS_WINDOWS: +if not support.MS_WINDOWS: # C++ compiler flags for GCC and clang CPPFLAGS = [ # gh-91321: The purpose of _testcppext extension is to check that building diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 582392ecddcb91..24617ab24c6958 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1,8 +1,6 @@ # Run the tests in Programs/_testembed.c (tests for the CPython embedding APIs) from test import support -from test.support import import_helper -from test.support import os_helper -from test.support import requires_specialization +from test.support import import_helper, os_helper, MS_WINDOWS import unittest from collections import namedtuple @@ -21,7 +19,6 @@ if not support.has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") -MS_WINDOWS = (os.name == 'nt') MACOS = (sys.platform == 'darwin') PYMEM_ALLOCATOR_NOT_SET = 0 PYMEM_ALLOCATOR_DEBUG = 2 @@ -347,7 +344,7 @@ def test_simple_initialization_api(self): out, err = self.run_embedded_interpreter("test_repeated_simple_init") self.assertEqual(out, 'Finalized\n' * INIT_LOOPS) - @requires_specialization + @support.requires_specialization def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self): # https://github.com/python/cpython/issues/92031 diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index cfc7ce5a86bab8..67ebc554cddb7c 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -7,8 +7,7 @@ import subprocess import sys from test import support -from test.support import os_helper -from test.support import script_helper, is_android +from test.support import os_helper, script_helper, is_android, MS_WINDOWS from test.support import skip_if_sanitizer import tempfile import unittest @@ -23,7 +22,6 @@ raise unittest.SkipTest("test module requires subprocess") TIMEOUT = 0.5 -MS_WINDOWS = (os.name == 'nt') def expected_traceback(lineno1, lineno2, header, min_count=1): diff --git a/Lib/test/test_gdb/__init__.py b/Lib/test/test_gdb/__init__.py index d74075e456792d..99557739af6748 100644 --- a/Lib/test/test_gdb/__init__.py +++ b/Lib/test/test_gdb/__init__.py @@ -9,8 +9,7 @@ from test import support -MS_WINDOWS = (os.name == 'nt') -if MS_WINDOWS: +if support.MS_WINDOWS: # On Windows, Python is usually built by MSVC. Passing /p:DebugSymbols=true # option to MSBuild produces PDB debug symbols, but gdb doesn't support PDB # debug symbol files. diff --git a/Lib/test/test_utf8_mode.py b/Lib/test/test_utf8_mode.py index ec29ba6d51b127..f66881044e16df 100644 --- a/Lib/test/test_utf8_mode.py +++ b/Lib/test/test_utf8_mode.py @@ -9,10 +9,9 @@ import unittest from test import support from test.support.script_helper import assert_python_ok, assert_python_failure -from test.support import os_helper +from test.support import os_helper, MS_WINDOWS -MS_WINDOWS = (sys.platform == 'win32') POSIX_LOCALES = ('C', 'POSIX') VXWORKS = (sys.platform == "vxworks") From eed92e4f7ec9e93a74f0e46e616c65902cc2f2a8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 5 Oct 2023 18:31:30 -0700 Subject: [PATCH 0952/1206] [3.12] gh-103053: Fix test_tools.test_freeze on FreeBSD (GH-110451) (#110456) gh-103053: Fix test_tools.test_freeze on FreeBSD (GH-110451) Fix test_tools.test_freeze on FreeBSD: run "make distclean" instead of "make clean" in the copied source directory to remove also the "python" program. Other test_freeze changes: * Log executed commands and directories, and the current directory. * No longer uses make -C option to change the directory, instead use subprocess cwd parameter. (cherry picked from commit a4baa9e8ac62cac3ea6363b15ea585b1998ea1f9) Co-authored-by: Victor Stinner --- ...-10-06-02-32-18.gh-issue-103053.VfxBLI.rst | 3 ++ Tools/freeze/test/freeze.py | 33 +++++++++++-------- 2 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-06-02-32-18.gh-issue-103053.VfxBLI.rst diff --git a/Misc/NEWS.d/next/Tests/2023-10-06-02-32-18.gh-issue-103053.VfxBLI.rst b/Misc/NEWS.d/next/Tests/2023-10-06-02-32-18.gh-issue-103053.VfxBLI.rst new file mode 100644 index 00000000000000..90a7ca512c97dd --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-06-02-32-18.gh-issue-103053.VfxBLI.rst @@ -0,0 +1,3 @@ +Fix test_tools.test_freeze on FreeBSD: run "make distclean" instead of "make +clean" in the copied source directory to remove also the "python" program. +Patch by Victor Stinner. diff --git a/Tools/freeze/test/freeze.py b/Tools/freeze/test/freeze.py index cdf77c57bbb6ae..d5f4d3d24c2bd6 100644 --- a/Tools/freeze/test/freeze.py +++ b/Tools/freeze/test/freeze.py @@ -27,8 +27,10 @@ class UnsupportedError(Exception): """The operation isn't supported.""" -def _run_quiet(cmd, cwd=None): - #print(f'# {" ".join(shlex.quote(a) for a in cmd)}') +def _run_quiet(cmd, *, cwd=None): + if cwd: + print('+', 'cd', cwd, flush=True) + print('+', shlex.join(cmd), flush=True) try: return subprocess.run( cmd, @@ -48,8 +50,8 @@ def _run_quiet(cmd, cwd=None): raise -def _run_stdout(cmd, cwd=None): - proc = _run_quiet(cmd, cwd) +def _run_stdout(cmd): + proc = _run_quiet(cmd) return proc.stdout.strip() @@ -91,13 +93,18 @@ def copy_source_tree(newroot, oldroot): shutil.copytree(oldroot, newroot, ignore=support.copy_python_src_ignore) if os.path.exists(os.path.join(newroot, 'Makefile')): - _run_quiet([MAKE, 'clean'], newroot) + # Out-of-tree builds require a clean srcdir. "make clean" keeps + # the "python" program, so use "make distclean" instead. + _run_quiet([MAKE, 'distclean'], cwd=newroot) ################################## # freezing def prepare(script=None, outdir=None): + print() + print("cwd:", os.getcwd()) + if not outdir: outdir = OUTDIR os.makedirs(outdir, exist_ok=True) @@ -125,7 +132,7 @@ def prepare(script=None, outdir=None): ensure_opt(cmd, 'cache-file', os.path.join(outdir, 'python-config.cache')) prefix = os.path.join(outdir, 'python-installation') ensure_opt(cmd, 'prefix', prefix) - _run_quiet(cmd, builddir) + _run_quiet(cmd, cwd=builddir) if not MAKE: raise UnsupportedError('make') @@ -135,20 +142,18 @@ def prepare(script=None, outdir=None): # this test is most often run as part of the whole suite with a lot # of other tests running in parallel, from 1-2 vCPU systems up to # people's NNN core beasts. Don't attempt to use it all. - parallel = f'-j{cores*2//3}' + jobs = cores * 2 // 3 + parallel = f'-j{jobs}' else: parallel = '-j2' # Build python. print(f'building python {parallel=} in {builddir}...') - if os.path.exists(os.path.join(srcdir, 'Makefile')): - # Out-of-tree builds require a clean srcdir. - _run_quiet([MAKE, '-C', srcdir, 'clean']) - _run_quiet([MAKE, '-C', builddir, parallel]) + _run_quiet([MAKE, parallel], cwd=builddir) # Install the build. print(f'installing python into {prefix}...') - _run_quiet([MAKE, '-C', builddir, 'install']) + _run_quiet([MAKE, 'install'], cwd=builddir) python = os.path.join(prefix, 'bin', 'python3') return outdir, scriptfile, python @@ -161,8 +166,8 @@ def freeze(python, scriptfile, outdir): print(f'freezing {scriptfile}...') os.makedirs(outdir, exist_ok=True) # Use -E to ignore PYTHONSAFEPATH - _run_quiet([python, '-E', FREEZE, '-o', outdir, scriptfile], outdir) - _run_quiet([MAKE, '-C', os.path.dirname(scriptfile)]) + _run_quiet([python, '-E', FREEZE, '-o', outdir, scriptfile], cwd=outdir) + _run_quiet([MAKE], cwd=os.path.dirname(scriptfile)) name = os.path.basename(scriptfile).rpartition('.')[0] executable = os.path.join(outdir, name) From 7e07eca008bbe04dc9139dfffd4ea82e13c6d518 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:09:29 -0700 Subject: [PATCH 0953/1206] [3.12] gh-110184: Fix subprocess test_pipesize_default() (GH-110465) (#110471) gh-110184: Fix subprocess test_pipesize_default() (GH-110465) For proc.stdin, get the size of the read end of the test pipe. Use subprocess context manager ("with proc:"). (cherry picked from commit d023d4166b255023dac448305270350030101481) Co-authored-by: Victor Stinner --- Lib/test/test_subprocess.py | 41 +++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index d95ef72b0da47a..a865df1082fba3 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -749,31 +749,36 @@ def test_pipesizes(self): @unittest.skipUnless(fcntl and hasattr(fcntl, 'F_GETPIPE_SZ'), 'fcntl.F_GETPIPE_SZ required for test.') def test_pipesize_default(self): - p = subprocess.Popen( + proc = subprocess.Popen( [sys.executable, "-c", 'import sys; sys.stdin.read(); sys.stdout.write("out"); ' 'sys.stderr.write("error!")'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, pipesize=-1) - try: - fp_r, fp_w = os.pipe() + + with proc: try: - default_pipesize = fcntl.fcntl(fp_w, fcntl.F_GETPIPE_SZ) - for fifo in [p.stdin, p.stdout, p.stderr]: - self.assertEqual( - fcntl.fcntl(fifo.fileno(), fcntl.F_GETPIPE_SZ), - default_pipesize) + fp_r, fp_w = os.pipe() + try: + default_read_pipesize = fcntl.fcntl(fp_r, fcntl.F_GETPIPE_SZ) + default_write_pipesize = fcntl.fcntl(fp_w, fcntl.F_GETPIPE_SZ) + finally: + os.close(fp_r) + os.close(fp_w) + + self.assertEqual( + fcntl.fcntl(proc.stdin.fileno(), fcntl.F_GETPIPE_SZ), + default_read_pipesize) + self.assertEqual( + fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETPIPE_SZ), + default_write_pipesize) + self.assertEqual( + fcntl.fcntl(proc.stderr.fileno(), fcntl.F_GETPIPE_SZ), + default_write_pipesize) + # On other platforms we cannot test the pipe size (yet). But above + # code using pipesize=-1 should not crash. finally: - os.close(fp_r) - os.close(fp_w) - # On other platforms we cannot test the pipe size (yet). But above - # code using pipesize=-1 should not crash. - p.stdin.close() - p.stdout.close() - p.stderr.close() - finally: - p.kill() - p.wait() + proc.kill() def test_env(self): newenv = os.environ.copy() From b77f5eea70b2f46d7b94c645645db3475e9d4c0e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:33:16 -0700 Subject: [PATCH 0954/1206] [3.12] Fix typo in Doc/library/textwrap.rst (GH-110328) (#110473) Co-authored-by: InSync <122007197+InSyncWithFoo@users.noreply.github.com> --- Doc/library/textwrap.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/textwrap.rst b/Doc/library/textwrap.rst index e2952ce3cc2ca3..7445410f91808c 100644 --- a/Doc/library/textwrap.rst +++ b/Doc/library/textwrap.rst @@ -238,7 +238,7 @@ hyphenated words; only then will long words be broken if necessary, unless However, the sentence detection algorithm is imperfect: it assumes that a sentence ending consists of a lowercase letter followed by one of ``'.'``, ``'!'``, or ``'?'``, possibly followed by one of ``'"'`` or ``"'"``, - followed by a space. One problem with this is algorithm is that it is + followed by a space. One problem with this algorithm is that it is unable to detect the difference between "Dr." in :: [...] Dr. Frankenstein's monster [...] From 2465fe00140fd902e7b5b61e12db4a6f7107e2fa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:48:48 -0700 Subject: [PATCH 0955/1206] [3.12] GH-110455: Guard `assert(tstate->thread_id > 0)` with `GH-ifndef HAVE_PTHREAD_STUBS` (GH-110487) (GH-110491) GH-110455: Guard `assert(tstate->thread_id > 0)` with `GH-ifndef HAVE_PTHREAD_STUBS` (GH-110487) (cherry picked from commit 5fd8821cf8eb1fe2e8575f8c7cc747cf78855a88) Co-authored-by: Brett Cannon --- .../2023-10-06-12-00-43.gh-issue-110455.8BjNGg.rst | 3 +++ Python/pystate.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-06-12-00-43.gh-issue-110455.8BjNGg.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-06-12-00-43.gh-issue-110455.8BjNGg.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-06-12-00-43.gh-issue-110455.8BjNGg.rst new file mode 100644 index 00000000000000..47bf17da757d12 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-06-12-00-43.gh-issue-110455.8BjNGg.rst @@ -0,0 +1,3 @@ +Guard ``assert(tstate->thread_id > 0)`` with ``#ifndef HAVE_PTHREAD_STUBS``. +This allows for for pydebug builds to work under WASI which (currently) +lacks thread support. diff --git a/Python/pystate.c b/Python/pystate.c index b77827ff8efa28..6f60c3dccce222 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -264,10 +264,10 @@ static void unbind_tstate(PyThreadState *tstate) { assert(tstate != NULL); - // XXX assert(tstate_is_alive(tstate)); assert(tstate_is_bound(tstate)); - // XXX assert(!tstate->_status.active); +#ifndef HAVE_PTHREAD_STUBS assert(tstate->thread_id > 0); +#endif #ifdef PY_HAVE_THREAD_NATIVE_ID assert(tstate->native_thread_id > 0); #endif From 6430ca53db8032011caac42fe85ecac745ca1ae9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 7 Oct 2023 06:28:59 -0700 Subject: [PATCH 0956/1206] [3.12] gh-109864: Make test_gettext tests order independent (GH-109866) (GH-110502) (cherry picked from commit 1aad4fc5dba993899621de86ae5955883448d6f6) Co-authored-by: Serhiy Storchaka --- Lib/test/test_gettext.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 8430fc234d00ee..2650ce501c309d 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -115,6 +115,12 @@ MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo') +def reset_gettext(): + gettext._localedirs.clear() + gettext._current_domain = 'messages' + gettext._translations.clear() + + class GettextBaseTest(unittest.TestCase): def setUp(self): self.addCleanup(os_helper.rmtree, os.path.split(LOCALEDIR)[0]) @@ -132,7 +138,8 @@ def setUp(self): fp.write(base64.decodebytes(MMO_DATA)) self.env = self.enterContext(os_helper.EnvironmentVarGuard()) self.env['LANGUAGE'] = 'xx' - gettext._translations.clear() + reset_gettext() + self.addCleanup(reset_gettext) GNU_MO_DATA_ISSUE_17898 = b'''\ @@ -312,6 +319,10 @@ def test_multiline_strings(self): class PluralFormsTestCase(GettextBaseTest): def setUp(self): GettextBaseTest.setUp(self) + self.localedir = os.curdir + # Set up the bindings + gettext.bindtextdomain('gettext', self.localedir) + gettext.textdomain('gettext') self.mofile = MOFILE def test_plural_forms1(self): @@ -355,7 +366,7 @@ def test_plural_context_forms2(self): x = t.npgettext('With context', 'There is %s file', 'There are %s files', 2) eq(x, 'Hay %s ficheros (context)') - x = gettext.pgettext('With context', 'There is %s file') + x = t.pgettext('With context', 'There is %s file') eq(x, 'Hay %s fichero (context)') # Examples from http://www.gnu.org/software/gettext/manual/gettext.html From 481aa7a40fdc43c18e1be210dbe21c6f227ee339 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 7 Oct 2023 06:39:19 -0700 Subject: [PATCH 0957/1206] [3.12] gh-109848: Make test_rot13_func in test_codecs independent (GH-109850) (GH-110504) (cherry picked from commit b987fdb19b981ef6e7f71b41790b5ed4e2064646) Co-authored-by: Serhiy Storchaka --- Lib/test/test_codecs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index b5e9271ac0c3cd..5dc5b1acf10f74 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -3567,9 +3567,10 @@ class Rot13UtilTest(unittest.TestCase): $ echo "Hello World" | python -m encodings.rot_13 """ def test_rot13_func(self): + from encodings.rot_13 import rot13 infile = io.StringIO('Gb or, be abg gb or, gung vf gur dhrfgvba') outfile = io.StringIO() - encodings.rot_13.rot13(infile, outfile) + rot13(infile, outfile) outfile.seek(0) plain_text = outfile.read() self.assertEqual( From 96e42d2f8d1fbc1c15ee02aab17ee209174d4b39 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 7 Oct 2023 17:18:39 -0700 Subject: [PATCH 0958/1206] [3.12] Update floatingpoint.rst (GH-110509) (#110513) Update floatingpoint.rst (GH-110509) This commit removes a ':'. I believe the extra colon causes a display error. What I believe to be an error: Above this expression `round(math.pi, ndigits=2) == round(22 / 7, ndigits=2)` the page displays `.. doctest::`. What I observed: After I remove the extra colon, the page does not display `.. doctest::` (cherry picked from commit 8e56d551ceef37a307280bcc5303bf69ccc9f9c1) Co-authored-by: zipperer <47086307+zipperer@users.noreply.github.com> --- Doc/tutorial/floatingpoint.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/floatingpoint.rst b/Doc/tutorial/floatingpoint.rst index b88055a41fd1ff..30f3dfb6b238b4 100644 --- a/Doc/tutorial/floatingpoint.rst +++ b/Doc/tutorial/floatingpoint.rst @@ -137,7 +137,7 @@ the :func:`math.isclose` function can be useful for comparing inexact values: True Alternatively, the :func:`round` function can be used to compare rough -approximations:: +approximations: .. doctest:: From ef4bd1b57ff2b0a908149d178b0b1fbdf9f7e247 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 7 Oct 2023 17:40:38 -0700 Subject: [PATCH 0959/1206] [3.12] gh-110237: Check `PyList_Append` for errors in `_PyEval_MatchClass` (GH-110238) (#110511) gh-110237: Check `PyList_Append` for errors in `_PyEval_MatchClass` (GH-110238) (cherry picked from commit dd9d781da30aa3740e54c063a40413c542d78c25) Co-authored-by: denballakh <47365157+denballakh@users.noreply.github.com> --- .../2023-10-02-23-17-08.gh-issue-110237._Xub0z.rst | 1 + Python/ceval.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-02-23-17-08.gh-issue-110237._Xub0z.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-02-23-17-08.gh-issue-110237._Xub0z.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-02-23-17-08.gh-issue-110237._Xub0z.rst new file mode 100644 index 00000000000000..67b95c52f7e4da --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-02-23-17-08.gh-issue-110237._Xub0z.rst @@ -0,0 +1 @@ +Fix missing error checks for calls to ``PyList_Append`` in ``_PyEval_MatchClass``. diff --git a/Python/ceval.c b/Python/ceval.c index fdb5b72e6c0f7b..4845ec04f08cc7 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -489,7 +489,9 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, } if (match_self) { // Easy. Copy the subject itself, and move on to kwargs. - PyList_Append(attrs, subject); + if (PyList_Append(attrs, subject) < 0) { + goto fail; + } } else { for (Py_ssize_t i = 0; i < nargs; i++) { @@ -505,7 +507,10 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, if (attr == NULL) { goto fail; } - PyList_Append(attrs, attr); + if (PyList_Append(attrs, attr) < 0) { + Py_DECREF(attr); + goto fail; + } Py_DECREF(attr); } } @@ -518,7 +523,10 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, if (attr == NULL) { goto fail; } - PyList_Append(attrs, attr); + if (PyList_Append(attrs, attr) < 0) { + Py_DECREF(attr); + goto fail; + } Py_DECREF(attr); } Py_SETREF(attrs, PyList_AsTuple(attrs)); From fb8c0415a26690df5b97e89ff1cc8e6d6b2473c3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 8 Oct 2023 21:52:36 -0700 Subject: [PATCH 0960/1206] [3.12] gh-110534 fix a URL redirect to wikipedia article on Fibonacci numbers (GH-110535) (#110536) gh-110534 fix a URL redirect to wikipedia article on Fibonacci numbers (GH-110535) (cherry picked from commit 892ee72b3622de30acd12576b59259fc69e2e40a) Co-authored-by: partev --- Doc/tutorial/introduction.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 0fc75c7d7532e2..172611dd0cfb41 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -480,7 +480,7 @@ First Steps Towards Programming Of course, we can use Python for more complicated tasks than adding two and two together. For instance, we can write an initial sub-sequence of the -`Fibonacci series `_ +`Fibonacci series `_ as follows:: >>> # Fibonacci series: From dae3db188329376134efe0433b1ded435a61f03a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:11:51 +0200 Subject: [PATCH 0961/1206] [3.12] gh-110514: Add PY_THROW to `sys.setprofile` events (GH-110524) (#110541) gh-110514: Add PY_THROW to `sys.setprofile` events (GH-110524) (cherry picked from commit dd4bb0529e44ac6f75a9ebbfcbf5d73dc251b7a7) Co-authored-by: Tian Gao --- Lib/test/test_sys_setprofile.py | 19 +++++++++++++++++++ ...-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst | 1 + Python/legacy_tracing.c | 8 +++++++- 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index 34c70d6c8de0c4..9e8936630de920 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -255,6 +255,25 @@ def g(p): (1, 'return', g_ident), ]) + def test_unfinished_generator(self): + def f(): + for i in range(2): + yield i + def g(p): + next(f()) + + f_ident = ident(f) + g_ident = ident(g) + self.check_events(g, [(1, 'call', g_ident), + (2, 'call', f_ident), + (2, 'return', f_ident), + # once more; the generator is being garbage collected + # and it will do a PY_THROW + (2, 'call', f_ident), + (2, 'return', f_ident), + (1, 'return', g_ident), + ]) + def test_stop_iteration(self): def f(): for i in range(2): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst new file mode 100644 index 00000000000000..96363c2b9d88be --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst @@ -0,0 +1 @@ +Add ``PY_THROW`` to :func:`sys.setprofile` events diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index b0136d2ebc7554..43fa5910ef6dd1 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -377,6 +377,11 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) { return -1; } + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_func3, PyTrace_CALL, + PY_MONITORING_EVENT_PY_THROW, -1)) { + return -1; + } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_func3, PyTrace_RETURN, PY_MONITORING_EVENT_PY_RETURN, PY_MONITORING_EVENT_PY_YIELD)) { @@ -417,7 +422,8 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) events = (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) | (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) | - (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND); + (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND) | + (1 << PY_MONITORING_EVENT_PY_THROW); } return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events); } From d1528233b875755c01d18d95784318041779aa70 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:12:15 +0200 Subject: [PATCH 0962/1206] [3.12] gh-109286: Update Windows installer to use SQLite 3.43.1 (GH-110403) (#110478) gh-109286: Update Windows installer to use SQLite 3.43.1 (GH-110403) (cherry picked from commit 201dc11aeb4699de3c5ebaea9798796c30087bcc) Co-authored-by: jtranquilli <76231120+jtranquilli@users.noreply.github.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- .../next/Windows/2023-10-05-15-23-23.gh-issue-109286.N8OzMg.rst | 1 + PCbuild/get_externals.bat | 2 +- PCbuild/python.props | 2 +- PCbuild/readme.txt | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-10-05-15-23-23.gh-issue-109286.N8OzMg.rst diff --git a/Misc/NEWS.d/next/Windows/2023-10-05-15-23-23.gh-issue-109286.N8OzMg.rst b/Misc/NEWS.d/next/Windows/2023-10-05-15-23-23.gh-issue-109286.N8OzMg.rst new file mode 100644 index 00000000000000..14a2aff70803ce --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-10-05-15-23-23.gh-issue-109286.N8OzMg.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.43.1. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 181ddfb60a3127..2656aa4c03f09f 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.11 -set libraries=%libraries% sqlite-3.42.0.0 +set libraries=%libraries% sqlite-3.43.1.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index 35c6e92be45dc9..496bc3dd4cf794 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -68,7 +68,7 @@ - $(ExternalsDir)sqlite-3.42.0.0\ + $(ExternalsDir)sqlite-3.43.1.0\ $(ExternalsDir)bzip2-1.0.8\ $(ExternalsDir)xz-5.2.5\ $(ExternalsDir)libffi-3.4.4\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index cfc1979fab095f..d8371df7615196 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -189,7 +189,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.42.0, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.43.1, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From 22474a1d62fef6b8223c5e33eae72fea78440d52 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 9 Oct 2023 12:13:16 +0300 Subject: [PATCH 0963/1206] [3.12] gh-109151: Revert readline support in the sqlite3 CLI (#110542) Revert "[3.12] gh-109151: Enable readline in the sqlite3 CLI (GH-109152) (#110352)" This reverts commit bc1fe3549b32896ef0cbae3d2220ebeaf111d9b8. --- Lib/sqlite3/__main__.py | 4 ---- .../Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst | 1 - 2 files changed, 5 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst diff --git a/Lib/sqlite3/__main__.py b/Lib/sqlite3/__main__.py index b93b84384a0925..3b59763375c147 100644 --- a/Lib/sqlite3/__main__.py +++ b/Lib/sqlite3/__main__.py @@ -116,10 +116,6 @@ def main(*args): else: # No SQL provided; start the REPL. console = SqliteInteractiveConsole(con) - try: - import readline - except ImportError: - pass console.interact(banner, exitmsg="") finally: con.close() diff --git a/Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst b/Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst deleted file mode 100644 index 78b4e882baba96..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-09-08-19-44-01.gh-issue-109151.GkzkQu.rst +++ /dev/null @@ -1 +0,0 @@ -Enable ``readline`` editing features in the :ref:`sqlite3 command-line interface ` (``python -m sqlite3``). From a7fe709fef75e056698b80b9861c34fc362dc5aa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:42:17 +0200 Subject: [PATCH 0964/1206] [3.12] gh-110497: Add note about `OSError` being an alias to `IOError` in docs (GH-110498) (#110546) gh-110497: Add note about `OSError` being an alias to `IOError` in docs (GH-110498) (cherry picked from commit 5e7edac7717bfe5f3c533d83ddd0f564db8de40b) Co-authored-by: Nikita Sobolev --- Doc/library/ctypes.rst | 8 +++++--- Doc/library/gettext.rst | 2 +- Doc/library/http.cookiejar.rst | 4 ++-- Doc/library/urllib.error.rst | 4 ++-- Doc/library/zipimport.rst | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 19cee10711fb89..98e6dbf0dd1830 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1403,7 +1403,8 @@ way is to instantiate one of the following classes: failure, an :class:`OSError` is automatically raised. .. versionchanged:: 3.3 - :exc:`WindowsError` used to be raised. + :exc:`WindowsError` used to be raised, + which is now an alias of :exc:`OSError`. .. versionchanged:: 3.12 @@ -2088,13 +2089,14 @@ Utility functions .. function:: WinError(code=None, descr=None) Windows only: this function is probably the worst-named thing in ctypes. It - creates an instance of OSError. If *code* is not specified, + creates an instance of :exc:`OSError`. If *code* is not specified, ``GetLastError`` is called to determine the error code. If *descr* is not specified, :func:`FormatError` is called to get a textual description of the error. .. versionchanged:: 3.3 - An instance of :exc:`WindowsError` used to be created. + An instance of :exc:`WindowsError` used to be created, which is now an + alias of :exc:`OSError`. .. function:: wstring_at(address, size=-1) diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index 7ebe91b372d35a..dc6cf5533fccbe 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -167,7 +167,7 @@ install themselves in the built-in namespace as the function :func:`!_`. :class:`NullTranslations` instance if *fallback* is true. .. versionchanged:: 3.3 - :exc:`IOError` used to be raised instead of :exc:`OSError`. + :exc:`IOError` used to be raised, it is now an alias of :exc:`OSError`. .. versionchanged:: 3.11 *codeset* parameter is removed. diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst index 87ef156a0bed57..12a6d768437ea5 100644 --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -44,8 +44,8 @@ The module defines the following exception: cookies from a file. :exc:`LoadError` is a subclass of :exc:`OSError`. .. versionchanged:: 3.3 - LoadError was made a subclass of :exc:`OSError` instead of - :exc:`IOError`. + :exc:`LoadError` used to be a subtype of :exc:`IOError`, which is now an + alias of :exc:`OSError`. The following classes are provided: diff --git a/Doc/library/urllib.error.rst b/Doc/library/urllib.error.rst index a5bcb5b1e643bf..facb11f42a40c5 100644 --- a/Doc/library/urllib.error.rst +++ b/Doc/library/urllib.error.rst @@ -27,8 +27,8 @@ The following exceptions are raised by :mod:`urllib.error` as appropriate: exception instance. .. versionchanged:: 3.3 - :exc:`URLError` has been made a subclass of :exc:`OSError` instead - of :exc:`IOError`. + :exc:`URLError` used to be a subtype of :exc:`IOError`, which is now an + alias of :exc:`OSError`. .. exception:: HTTPError(url, code, msg, hdrs, fp) diff --git a/Doc/library/zipimport.rst b/Doc/library/zipimport.rst index 11d19e8c863e9f..47c81f0e63603d 100644 --- a/Doc/library/zipimport.rst +++ b/Doc/library/zipimport.rst @@ -113,7 +113,7 @@ zipimporter Objects file wasn't found. .. versionchanged:: 3.3 - :exc:`IOError` used to be raised instead of :exc:`OSError`. + :exc:`IOError` used to be raised, it is now an alias of :exc:`OSError`. .. method:: get_filename(fullname) From 3ed5cb0de37a0bb9325265465a56427b90a29598 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Mon, 9 Oct 2023 13:04:09 +0300 Subject: [PATCH 0965/1206] [3.12] gh-110525: Add CAPI tests for set and frozenset objects (GH-110526). (GH-110547) (cherry picked from commit c49edd7d9c5395a6a6696a4846f56bc8b2b22792) --- Lib/test/test_capi/test_set.py | 215 +++++++++++++++++++++++++++++++++ Modules/Setup.stdlib.in | 2 +- Modules/_testcapi/parts.h | 1 + Modules/_testcapi/set.c | 162 +++++++++++++++++++++++++ Modules/_testcapimodule.c | 3 + PCbuild/_testcapi.vcxproj | 1 + 6 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_capi/test_set.py create mode 100644 Modules/_testcapi/set.c diff --git a/Lib/test/test_capi/test_set.py b/Lib/test/test_capi/test_set.py new file mode 100644 index 00000000000000..e9165e7e6806dd --- /dev/null +++ b/Lib/test/test_capi/test_set.py @@ -0,0 +1,215 @@ +import unittest + +from test.support import import_helper + +# Skip this test if the _testcapi module isn't available. +_testcapi = import_helper.import_module('_testcapi') + +class set_subclass(set): + pass + +class frozenset_subclass(frozenset): + pass + + +class TestSetCAPI(unittest.TestCase): + def assertImmutable(self, action, *args): + self.assertRaises(SystemError, action, frozenset(), *args) + self.assertRaises(SystemError, action, frozenset({1}), *args) + self.assertRaises(SystemError, action, frozenset_subclass(), *args) + self.assertRaises(SystemError, action, frozenset_subclass({1}), *args) + + def test_set_check(self): + check = _testcapi.set_check + self.assertTrue(check(set())) + self.assertTrue(check({1, 2})) + self.assertFalse(check(frozenset())) + self.assertTrue(check(set_subclass())) + self.assertFalse(check(frozenset_subclass())) + self.assertFalse(check(object())) + # CRASHES: check(NULL) + + def test_set_check_exact(self): + check = _testcapi.set_checkexact + self.assertTrue(check(set())) + self.assertTrue(check({1, 2})) + self.assertFalse(check(frozenset())) + self.assertFalse(check(set_subclass())) + self.assertFalse(check(frozenset_subclass())) + self.assertFalse(check(object())) + # CRASHES: check(NULL) + + def test_frozenset_check(self): + check = _testcapi.frozenset_check + self.assertFalse(check(set())) + self.assertTrue(check(frozenset())) + self.assertTrue(check(frozenset({1, 2}))) + self.assertFalse(check(set_subclass())) + self.assertTrue(check(frozenset_subclass())) + self.assertFalse(check(object())) + # CRASHES: check(NULL) + + def test_frozenset_check_exact(self): + check = _testcapi.frozenset_checkexact + self.assertFalse(check(set())) + self.assertTrue(check(frozenset())) + self.assertTrue(check(frozenset({1, 2}))) + self.assertFalse(check(set_subclass())) + self.assertFalse(check(frozenset_subclass())) + self.assertFalse(check(object())) + # CRASHES: check(NULL) + + def test_anyset_check(self): + check = _testcapi.anyset_check + self.assertTrue(check(set())) + self.assertTrue(check({1, 2})) + self.assertTrue(check(frozenset())) + self.assertTrue(check(frozenset({1, 2}))) + self.assertTrue(check(set_subclass())) + self.assertTrue(check(frozenset_subclass())) + self.assertFalse(check(object())) + # CRASHES: check(NULL) + + def test_anyset_check_exact(self): + check = _testcapi.anyset_checkexact + self.assertTrue(check(set())) + self.assertTrue(check({1, 2})) + self.assertTrue(check(frozenset())) + self.assertTrue(check(frozenset({1, 2}))) + self.assertFalse(check(set_subclass())) + self.assertFalse(check(frozenset_subclass())) + self.assertFalse(check(object())) + # CRASHES: check(NULL) + + def test_set_new(self): + set_new = _testcapi.set_new + self.assertEqual(set_new().__class__, set) + self.assertEqual(set_new(), set()) + self.assertEqual(set_new((1, 1, 2)), {1, 2}) + self.assertEqual(set_new([1, 1, 2]), {1, 2}) + with self.assertRaisesRegex(TypeError, 'object is not iterable'): + set_new(object()) + with self.assertRaisesRegex(TypeError, 'object is not iterable'): + set_new(1) + with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"): + set_new((1, {})) + + def test_frozenset_new(self): + frozenset_new = _testcapi.frozenset_new + self.assertEqual(frozenset_new().__class__, frozenset) + self.assertEqual(frozenset_new(), frozenset()) + self.assertEqual(frozenset_new((1, 1, 2)), frozenset({1, 2})) + self.assertEqual(frozenset_new([1, 1, 2]), frozenset({1, 2})) + with self.assertRaisesRegex(TypeError, 'object is not iterable'): + frozenset_new(object()) + with self.assertRaisesRegex(TypeError, 'object is not iterable'): + frozenset_new(1) + with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"): + frozenset_new((1, {})) + + def test_set_size(self): + get_size = _testcapi.set_size + self.assertEqual(get_size(set()), 0) + self.assertEqual(get_size(frozenset()), 0) + self.assertEqual(get_size({1, 1, 2}), 2) + self.assertEqual(get_size(frozenset({1, 1, 2})), 2) + self.assertEqual(get_size(set_subclass((1, 2, 3))), 3) + self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3) + with self.assertRaises(SystemError): + get_size(object()) + # CRASHES: get_size(NULL) + + def test_set_get_size(self): + get_size = _testcapi.set_get_size + self.assertEqual(get_size(set()), 0) + self.assertEqual(get_size(frozenset()), 0) + self.assertEqual(get_size({1, 1, 2}), 2) + self.assertEqual(get_size(frozenset({1, 1, 2})), 2) + self.assertEqual(get_size(set_subclass((1, 2, 3))), 3) + self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3) + # CRASHES: get_size(NULL) + # CRASHES: get_size(object()) + + def test_set_contains(self): + contains = _testcapi.set_contains + for cls in (set, frozenset, set_subclass, frozenset_subclass): + with self.subTest(cls=cls): + instance = cls((1, 2)) + self.assertTrue(contains(instance, 1)) + self.assertFalse(contains(instance, 'missing')) + with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"): + contains(instance, []) + # CRASHES: contains(instance, NULL) + # CRASHES: contains(NULL, object()) + # CRASHES: contains(NULL, NULL) + + def test_add(self): + add = _testcapi.set_add + for cls in (set, set_subclass): + with self.subTest(cls=cls): + instance = cls((1, 2)) + self.assertEqual(add(instance, 1), 0) + self.assertEqual(instance, {1, 2}) + self.assertEqual(add(instance, 3), 0) + self.assertEqual(instance, {1, 2, 3}) + with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"): + add(instance, []) + with self.assertRaises(SystemError): + add(object(), 1) + self.assertImmutable(add, 1) + # CRASHES: add(NULL, object()) + # CRASHES: add(instance, NULL) + # CRASHES: add(NULL, NULL) + + def test_discard(self): + discard = _testcapi.set_discard + for cls in (set, set_subclass): + with self.subTest(cls=cls): + instance = cls((1, 2)) + self.assertEqual(discard(instance, 3), 0) + self.assertEqual(instance, {1, 2}) + self.assertEqual(discard(instance, 1), 1) + self.assertEqual(instance, {2}) + self.assertEqual(discard(instance, 2), 1) + self.assertEqual(instance, set()) + self.assertEqual(discard(instance, 2), 0) + self.assertEqual(instance, set()) + with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"): + discard(instance, []) + with self.assertRaises(SystemError): + discard(object(), 1) + self.assertImmutable(discard, 1) + # CRASHES: discard(NULL, object()) + # CRASHES: discard(instance, NULL) + # CRASHES: discard(NULL, NULL) + + def test_pop(self): + pop = _testcapi.set_pop + orig = (1, 2) + for cls in (set, set_subclass): + with self.subTest(cls=cls): + instance = cls(orig) + self.assertIn(pop(instance), orig) + self.assertEqual(len(instance), 1) + self.assertIn(pop(instance), orig) + self.assertEqual(len(instance), 0) + with self.assertRaises(KeyError): + pop(instance) + with self.assertRaises(SystemError): + pop(object()) + self.assertImmutable(pop) + # CRASHES: pop(NULL) + + def test_clear(self): + clear = _testcapi.set_clear + for cls in (set, set_subclass): + with self.subTest(cls=cls): + instance = cls((1, 2)) + self.assertEqual(clear(instance), 0) + self.assertEqual(instance, set()) + self.assertEqual(clear(instance), 0) + self.assertEqual(instance, set()) + with self.assertRaises(SystemError): + clear(object()) + self.assertImmutable(clear) + # CRASHES: clear(NULL) diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 3e01e25056dfa8..140245d474cd41 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -168,7 +168,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index f37be9b67a3d78..9bbb54171b0a93 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -37,6 +37,7 @@ int _PyTestCapi_Init_Watchers(PyObject *module); int _PyTestCapi_Init_Long(PyObject *module); int _PyTestCapi_Init_Float(PyObject *module); int _PyTestCapi_Init_Dict(PyObject *module); +int _PyTestCapi_Init_Set(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); diff --git a/Modules/_testcapi/set.c b/Modules/_testcapi/set.c new file mode 100644 index 00000000000000..f68a1859698132 --- /dev/null +++ b/Modules/_testcapi/set.c @@ -0,0 +1,162 @@ +#include // ptrdiff_t + +#include "parts.h" +#include "util.h" + +static PyObject * +set_check(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PySet_Check(obj)); +} + +static PyObject * +set_checkexact(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PySet_CheckExact(obj)); +} + +static PyObject * +frozenset_check(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyFrozenSet_Check(obj)); +} + +static PyObject * +frozenset_checkexact(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyFrozenSet_CheckExact(obj)); +} + +static PyObject * +anyset_check(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyAnySet_Check(obj)); +} + +static PyObject * +anyset_checkexact(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyAnySet_CheckExact(obj)); +} + +static PyObject * +set_new(PyObject *self, PyObject *args) +{ + PyObject *iterable = NULL; + if (!PyArg_ParseTuple(args, "|O", &iterable)) { + return NULL; + } + return PySet_New(iterable); +} + +static PyObject * +frozenset_new(PyObject *self, PyObject *args) +{ + PyObject *iterable = NULL; + if (!PyArg_ParseTuple(args, "|O", &iterable)) { + return NULL; + } + return PyFrozenSet_New(iterable); +} + +static PyObject * +set_size(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PySet_Size(obj)); +} + +static PyObject * +set_get_size(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PySet_GET_SIZE(obj)); +} + +static PyObject * +set_contains(PyObject *self, PyObject *args) +{ + PyObject *obj, *item; + if (!PyArg_ParseTuple(args, "OO", &obj, &item)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(item); + RETURN_INT(PySet_Contains(obj, item)); +} + +static PyObject * +set_add(PyObject *self, PyObject *args) +{ + PyObject *obj, *item; + if (!PyArg_ParseTuple(args, "OO", &obj, &item)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(item); + RETURN_INT(PySet_Add(obj, item)); +} + +static PyObject * +set_discard(PyObject *self, PyObject *args) +{ + PyObject *obj, *item; + if (!PyArg_ParseTuple(args, "OO", &obj, &item)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(item); + RETURN_INT(PySet_Discard(obj, item)); +} + +static PyObject * +set_pop(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + return PySet_Pop(obj); +} + +static PyObject * +set_clear(PyObject *self, PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PySet_Clear(obj)); +} + +static PyMethodDef test_methods[] = { + {"set_check", set_check, METH_O}, + {"set_checkexact", set_checkexact, METH_O}, + {"frozenset_check", frozenset_check, METH_O}, + {"frozenset_checkexact", frozenset_checkexact, METH_O}, + {"anyset_check", anyset_check, METH_O}, + {"anyset_checkexact", anyset_checkexact, METH_O}, + + {"set_new", set_new, METH_VARARGS}, + {"frozenset_new", frozenset_new, METH_VARARGS}, + + {"set_size", set_size, METH_O}, + {"set_get_size", set_get_size, METH_O}, + {"set_contains", set_contains, METH_VARARGS}, + {"set_add", set_add, METH_VARARGS}, + {"set_discard", set_discard, METH_VARARGS}, + {"set_pop", set_pop, METH_O}, + {"set_clear", set_clear, METH_O}, + + {NULL}, +}; + +int +_PyTestCapi_Init_Set(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c73b297adaa76d..805a20733cdbfb 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4001,6 +4001,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Dict(m) < 0) { return NULL; } + if (_PyTestCapi_Init_Set(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Structmember(m) < 0) { return NULL; } diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 1843b58de9d151..8c0d7a502dd468 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -102,6 +102,7 @@ + From 23624462cb0df154346d932f0001997d935e30de Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:43:26 +0200 Subject: [PATCH 0966/1206] [3.12] gh-109286: Update macOS installer to use SQLite 3.43.1 (GH-110482) (#110550) (cherry picked from commit 48419a50b44a195ad7de958f479a924e7c2d3e1b) Co-authored-by: jtranquilli <76231120+jtranquilli@users.noreply.github.com> --- Mac/BuildScript/build-installer.py | 6 +++--- .../macOS/2023-10-04-23-38-24.gh-issue-109286.1ZLMaq.rst | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2023-10-04-23-38-24.gh-issue-109286.1ZLMaq.rst diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index c54de880c20360..a07d38aedcb5d6 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,9 +359,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.42.0", - url="https://sqlite.org/2023/sqlite-autoconf-3420000.tar.gz", - checksum="0c5a92bc51cf07cae45b4a1e94653dea", + name="SQLite 3.43.1", + url="https://sqlite.org/2023/sqlite-autoconf-3430100.tar.gz", + checksum="77e61befe9c3298da0504f87772a24b0", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2023-10-04-23-38-24.gh-issue-109286.1ZLMaq.rst b/Misc/NEWS.d/next/macOS/2023-10-04-23-38-24.gh-issue-109286.1ZLMaq.rst new file mode 100644 index 00000000000000..18ac9df73deb37 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-10-04-23-38-24.gh-issue-109286.1ZLMaq.rst @@ -0,0 +1 @@ +Update macOS installer to use SQLite 3.43.1. From b2419eff95fe2ca86d3036f0ee1d53bf10bf2620 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:40:53 +0200 Subject: [PATCH 0967/1206] [3.12] gh-110525: Cover PySet_Add corner case with frozenset objects (GH-110544) (GH-110554) (cherry picked from commit ea39c877c0a8e7a717f2e4bf7d92a3a8780e67c0) Co-authored-by: Nikita Sobolev --- Modules/_testcapi/set.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Modules/_testcapi/set.c b/Modules/_testcapi/set.c index f68a1859698132..3c58f185638c75 100644 --- a/Modules/_testcapi/set.c +++ b/Modules/_testcapi/set.c @@ -129,6 +129,41 @@ set_clear(PyObject *self, PyObject *obj) RETURN_INT(PySet_Clear(obj)); } +static PyObject * +test_frozenset_add_in_capi(PyObject *self, PyObject *Py_UNUSED(obj)) +{ + // Test that `frozenset` can be used with `PySet_Add`, + // when frozenset is just created in CAPI. + PyObject *fs = PyFrozenSet_New(NULL); + if (fs == NULL) { + return NULL; + } + PyObject *num = PyLong_FromLong(1); + if (num == NULL) { + goto error; + } + if (PySet_Add(fs, num) < 0) { + goto error; + } + int contains = PySet_Contains(fs, num); + if (contains < 0) { + goto error; + } + else if (contains == 0) { + goto unexpected; + } + Py_DECREF(fs); + Py_DECREF(num); + Py_RETURN_NONE; + +unexpected: + PyErr_SetString(PyExc_ValueError, "set does not contain expected value"); +error: + Py_DECREF(fs); + Py_XDECREF(num); + return NULL; +} + static PyMethodDef test_methods[] = { {"set_check", set_check, METH_O}, {"set_checkexact", set_checkexact, METH_O}, @@ -148,6 +183,8 @@ static PyMethodDef test_methods[] = { {"set_pop", set_pop, METH_O}, {"set_clear", set_clear, METH_O}, + {"test_frozenset_add_in_capi", test_frozenset_add_in_capi, METH_NOARGS}, + {NULL}, }; From 13ad1219c96d22543999bfe91d196e6d956bfd21 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:42:04 +0200 Subject: [PATCH 0968/1206] [3.12] gh-110437: Allow overriding VCRuntimeDLL with a semicolon separated list of DLLs to bundle (GH-110470) gh-110437: Allow overriding VCRuntimeDLL with a semicolon separated list of DLLs to bundle (GH-110470) (cherry picked from commit 12cc6792d0ca1d0b72712d77c6efcb0aa0c7e7ba) Co-authored-by: Steve Dower --- .../Windows/2023-10-06-14-20-14.gh-issue-110437.xpYy9q.rst | 2 ++ PCbuild/pyproject.props | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-10-06-14-20-14.gh-issue-110437.xpYy9q.rst diff --git a/Misc/NEWS.d/next/Windows/2023-10-06-14-20-14.gh-issue-110437.xpYy9q.rst b/Misc/NEWS.d/next/Windows/2023-10-06-14-20-14.gh-issue-110437.xpYy9q.rst new file mode 100644 index 00000000000000..777b4942e183f5 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-10-06-14-20-14.gh-issue-110437.xpYy9q.rst @@ -0,0 +1,2 @@ +Allows overriding the source of VC redistributables so that releases can be +guaranteed to never downgrade between updates. diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index fd928cafd77aaa..056ab2b3b6643a 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -232,7 +232,10 @@ public override bool Execute() { - + + + + From 5afac0cf8d50db62aa1edefebde8a0af5fed0cd4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 9 Oct 2023 14:43:35 +0300 Subject: [PATCH 0969/1206] [3.12] gh-110549: Remove unused includes of in _testcapi (GH-110552) (GH-110553) (cherry picked from commit 89df5b73d07872d554da60b455b46c98e01a022d) Co-authored-by: Nikita Sobolev --- Modules/_testcapi/abstract.c | 2 -- Modules/_testcapi/dict.c | 2 -- Modules/_testcapi/set.c | 2 -- 3 files changed, 6 deletions(-) diff --git a/Modules/_testcapi/abstract.c b/Modules/_testcapi/abstract.c index 38236aaf4f4353..1c4c45c6c93d3e 100644 --- a/Modules/_testcapi/abstract.c +++ b/Modules/_testcapi/abstract.c @@ -1,5 +1,3 @@ -#include // ptrdiff_t - #define PY_SSIZE_T_CLEAN #include "parts.h" #include "util.h" diff --git a/Modules/_testcapi/dict.c b/Modules/_testcapi/dict.c index 374464c40d582f..41c8dfde0dab0e 100644 --- a/Modules/_testcapi/dict.c +++ b/Modules/_testcapi/dict.c @@ -1,5 +1,3 @@ -#include // ptrdiff_t - #define PY_SSIZE_T_CLEAN #include "parts.h" #include "util.h" diff --git a/Modules/_testcapi/set.c b/Modules/_testcapi/set.c index 3c58f185638c75..2fbd0aeffcd9f9 100644 --- a/Modules/_testcapi/set.c +++ b/Modules/_testcapi/set.c @@ -1,5 +1,3 @@ -#include // ptrdiff_t - #include "parts.h" #include "util.h" From 53122bcf825681487226c041d47763e82e081530 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 16:01:00 +0200 Subject: [PATCH 0970/1206] [3.12] gh-109191: Fix build with newer editline (gh-110239) (gh-110562) gh-109191: Fix build with newer editline (gh-110239) (cherry picked from commit f4cb0d27cc08f490c42a22e646eb73cc7072d54a) Co-authored-by: Bo Anderson --- ...-10-05-11-46-20.gh-issue-109191.imUkVN.rst | 1 + Modules/readline.c | 2 +- configure | 19 +++++++++++++++++++ configure.ac | 7 +++++++ pyconfig.h.in | 3 +++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2023-10-05-11-46-20.gh-issue-109191.imUkVN.rst diff --git a/Misc/NEWS.d/next/Build/2023-10-05-11-46-20.gh-issue-109191.imUkVN.rst b/Misc/NEWS.d/next/Build/2023-10-05-11-46-20.gh-issue-109191.imUkVN.rst new file mode 100644 index 00000000000000..27e5df790bc0c6 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-10-05-11-46-20.gh-issue-109191.imUkVN.rst @@ -0,0 +1 @@ +Fix compile error when building with recent versions of libedit. diff --git a/Modules/readline.c b/Modules/readline.c index 2824105a187586..9823ebe71da3a5 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -442,7 +442,7 @@ readline_set_completion_display_matches_hook_impl(PyObject *module, default completion display. */ rl_completion_display_matches_hook = readlinestate_global->completion_display_matches_hook ? -#if defined(_RL_FUNCTION_TYPEDEF) +#if defined(HAVE_RL_COMPDISP_FUNC_T) (rl_compdisp_func_t *)on_completion_display_matches_hook : 0; #else (VFunction *)on_completion_display_matches_hook : 0; diff --git a/configure b/configure index b6f90bcd8c7300..985b3741349e8e 100755 --- a/configure +++ b/configure @@ -25345,6 +25345,25 @@ printf "%s\n" "#define HAVE_RL_APPEND_HISTORY 1" >>confdefs.h fi + # in readline as well as newer editline (April 2023) + ac_fn_c_check_type "$LINENO" "rl_compdisp_func_t" "ac_cv_type_rl_compdisp_func_t" " + #include /* Must be first for Gnu Readline */ + #ifdef WITH_EDITLINE + # include + #else + # include + # include + #endif + +" +if test "x$ac_cv_type_rl_compdisp_func_t" = xyes +then : + +printf "%s\n" "#define HAVE_RL_COMPDISP_FUNC_T 1" >>confdefs.h + +fi + + CFLAGS=$save_CFLAGS diff --git a/configure.ac b/configure.ac index ba768aea930714..2a7a91882640fd 100644 --- a/configure.ac +++ b/configure.ac @@ -6213,6 +6213,13 @@ AS_VAR_IF([with_readline], [no], [ AC_DEFINE([HAVE_RL_APPEND_HISTORY], [1], [Define if readline supports append_history]) ]) + # in readline as well as newer editline (April 2023) + AC_CHECK_TYPE([rl_compdisp_func_t], + [AC_DEFINE([HAVE_RL_COMPDISP_FUNC_T], [1], + [Define if readline supports rl_compdisp_func_t])], + [], + [readline_includes]) + m4_undefine([readline_includes]) ])dnl WITH_SAVE_ENV() ]) diff --git a/pyconfig.h.in b/pyconfig.h.in index ada9dccfef1084..9f858b2d3541d0 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -989,6 +989,9 @@ /* Define if you can turn off readline's signal handling. */ #undef HAVE_RL_CATCH_SIGNAL +/* Define if readline supports rl_compdisp_func_t */ +#undef HAVE_RL_COMPDISP_FUNC_T + /* Define if you have readline 2.2 */ #undef HAVE_RL_COMPLETION_APPEND_CHARACTER From 1f43bc2f3ba9500d70afa9f471cb328fa3f8f4ec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 9 Oct 2023 16:27:01 +0200 Subject: [PATCH 0971/1206] [3.12] gh-110519: Improve deprecation warning in the gettext module (GH-110520) (GH-110563) Deprecation warning about non-integer numbers in gettext now always refers to the line in the user code where gettext function or method is used. Previously, it could refer to a line in gettext code. Also, increase test coverage for NullTranslations and domain-aware functions like dngettext(). (cherry picked from commit 326c6c4e07137b43c49b74bd5528619360080469) Co-authored-by: Serhiy Storchaka --- Lib/gettext.py | 14 +- Lib/test/test_gettext.py | 178 +++++++++++++----- ...-10-08-18-15-02.gh-issue-110519.RDGe8-.rst | 3 + 3 files changed, 144 insertions(+), 51 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-08-18-15-02.gh-issue-110519.RDGe8-.rst diff --git a/Lib/gettext.py b/Lib/gettext.py index b72b15f82d4355..e84765bfdf0649 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -46,6 +46,7 @@ # find this format documented anywhere. +import operator import os import re import sys @@ -166,14 +167,21 @@ def _parse(tokens, priority=-1): def _as_int(n): try: - i = round(n) + round(n) except TypeError: raise TypeError('Plural value must be an integer, got %s' % (n.__class__.__name__,)) from None + import warnings + frame = sys._getframe(1) + stacklevel = 2 + while frame.f_back is not None and frame.f_globals.get('__name__') == __name__: + stacklevel += 1 + frame = frame.f_back warnings.warn('Plural value must be an integer, got %s' % (n.__class__.__name__,), - DeprecationWarning, 4) + DeprecationWarning, + stacklevel) return n @@ -200,7 +208,7 @@ def c2py(plural): elif c == ')': depth -= 1 - ns = {'_as_int': _as_int} + ns = {'_as_int': _as_int, '__name__': __name__} exec('''if True: def func(n): if not isinstance(n, int): diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 2650ce501c309d..dd33b9b88f6768 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -2,6 +2,7 @@ import base64 import gettext import unittest +from functools import partial from test import support from test.support import os_helper @@ -122,8 +123,9 @@ def reset_gettext(): class GettextBaseTest(unittest.TestCase): - def setUp(self): - self.addCleanup(os_helper.rmtree, os.path.split(LOCALEDIR)[0]) + @classmethod + def setUpClass(cls): + cls.addClassCleanup(os_helper.rmtree, os.path.split(LOCALEDIR)[0]) if not os.path.isdir(LOCALEDIR): os.makedirs(LOCALEDIR) with open(MOFILE, 'wb') as fp: @@ -136,6 +138,8 @@ def setUp(self): fp.write(base64.decodebytes(UMO_DATA)) with open(MMOFILE, 'wb') as fp: fp.write(base64.decodebytes(MMO_DATA)) + + def setUp(self): self.env = self.enterContext(os_helper.EnvironmentVarGuard()) self.env['LANGUAGE'] = 'xx' reset_gettext() @@ -316,59 +320,137 @@ def test_multiline_strings(self): trggrkg zrffntr pngnybt yvoenel.''') -class PluralFormsTestCase(GettextBaseTest): +class PluralFormsTests: + + def _test_plural_forms(self, ngettext, gettext, + singular, plural, tsingular, tplural, + numbers_only=True): + x = ngettext(singular, plural, 1) + self.assertEqual(x, tsingular) + x = ngettext(singular, plural, 2) + self.assertEqual(x, tplural) + x = gettext(singular) + self.assertEqual(x, tsingular) + + if numbers_only: + lineno = self._test_plural_forms.__code__.co_firstlineno + 9 + with self.assertWarns(DeprecationWarning) as cm: + x = ngettext(singular, plural, 1.0) + self.assertEqual(cm.filename, __file__) + self.assertEqual(cm.lineno, lineno + 4) + self.assertEqual(x, tsingular) + with self.assertWarns(DeprecationWarning) as cm: + x = ngettext(singular, plural, 1.1) + self.assertEqual(cm.filename, __file__) + self.assertEqual(cm.lineno, lineno + 9) + self.assertEqual(x, tplural) + with self.assertRaises(TypeError): + ngettext(singular, plural, None) + else: + x = ngettext(singular, plural, None) + self.assertEqual(x, tplural) + + def test_plural_forms(self): + self._test_plural_forms( + self.ngettext, self.gettext, + 'There is %s file', 'There are %s files', + 'Hay %s fichero', 'Hay %s ficheros') + self._test_plural_forms( + self.ngettext, self.gettext, + '%d file deleted', '%d files deleted', + '%d file deleted', '%d files deleted') + + def test_plural_context_forms(self): + ngettext = partial(self.npgettext, 'With context') + gettext = partial(self.pgettext, 'With context') + self._test_plural_forms( + ngettext, gettext, + 'There is %s file', 'There are %s files', + 'Hay %s fichero (context)', 'Hay %s ficheros (context)') + self._test_plural_forms( + ngettext, gettext, + '%d file deleted', '%d files deleted', + '%d file deleted', '%d files deleted') + + def test_plural_wrong_context_forms(self): + self._test_plural_forms( + partial(self.npgettext, 'Unknown context'), + partial(self.pgettext, 'Unknown context'), + 'There is %s file', 'There are %s files', + 'There is %s file', 'There are %s files') + + +class GNUTranslationsPluralFormsTestCase(PluralFormsTests, GettextBaseTest): def setUp(self): GettextBaseTest.setUp(self) - self.localedir = os.curdir # Set up the bindings - gettext.bindtextdomain('gettext', self.localedir) + gettext.bindtextdomain('gettext', os.curdir) gettext.textdomain('gettext') - self.mofile = MOFILE - def test_plural_forms1(self): - eq = self.assertEqual - x = gettext.ngettext('There is %s file', 'There are %s files', 1) - eq(x, 'Hay %s fichero') - x = gettext.ngettext('There is %s file', 'There are %s files', 2) - eq(x, 'Hay %s ficheros') - x = gettext.gettext('There is %s file') - eq(x, 'Hay %s fichero') - - def test_plural_context_forms1(self): - eq = self.assertEqual - x = gettext.npgettext('With context', - 'There is %s file', 'There are %s files', 1) - eq(x, 'Hay %s fichero (context)') - x = gettext.npgettext('With context', - 'There is %s file', 'There are %s files', 2) - eq(x, 'Hay %s ficheros (context)') - x = gettext.pgettext('With context', 'There is %s file') - eq(x, 'Hay %s fichero (context)') - - def test_plural_forms2(self): - eq = self.assertEqual - with open(self.mofile, 'rb') as fp: - t = gettext.GNUTranslations(fp) - x = t.ngettext('There is %s file', 'There are %s files', 1) - eq(x, 'Hay %s fichero') - x = t.ngettext('There is %s file', 'There are %s files', 2) - eq(x, 'Hay %s ficheros') - x = t.gettext('There is %s file') - eq(x, 'Hay %s fichero') - - def test_plural_context_forms2(self): - eq = self.assertEqual - with open(self.mofile, 'rb') as fp: + self.gettext = gettext.gettext + self.ngettext = gettext.ngettext + self.pgettext = gettext.pgettext + self.npgettext = gettext.npgettext + + +class GNUTranslationsWithDomainPluralFormsTestCase(PluralFormsTests, GettextBaseTest): + def setUp(self): + GettextBaseTest.setUp(self) + # Set up the bindings + gettext.bindtextdomain('gettext', os.curdir) + + self.gettext = partial(gettext.dgettext, 'gettext') + self.ngettext = partial(gettext.dngettext, 'gettext') + self.pgettext = partial(gettext.dpgettext, 'gettext') + self.npgettext = partial(gettext.dnpgettext, 'gettext') + + def test_plural_forms_wrong_domain(self): + self._test_plural_forms( + partial(gettext.dngettext, 'unknown'), + partial(gettext.dgettext, 'unknown'), + 'There is %s file', 'There are %s files', + 'There is %s file', 'There are %s files', + numbers_only=False) + + def test_plural_context_forms_wrong_domain(self): + self._test_plural_forms( + partial(gettext.dnpgettext, 'unknown', 'With context'), + partial(gettext.dpgettext, 'unknown', 'With context'), + 'There is %s file', 'There are %s files', + 'There is %s file', 'There are %s files', + numbers_only=False) + + +class GNUTranslationsClassPluralFormsTestCase(PluralFormsTests, GettextBaseTest): + def setUp(self): + GettextBaseTest.setUp(self) + with open(MOFILE, 'rb') as fp: t = gettext.GNUTranslations(fp) - x = t.npgettext('With context', - 'There is %s file', 'There are %s files', 1) - eq(x, 'Hay %s fichero (context)') - x = t.npgettext('With context', - 'There is %s file', 'There are %s files', 2) - eq(x, 'Hay %s ficheros (context)') - x = t.pgettext('With context', 'There is %s file') - eq(x, 'Hay %s fichero (context)') + self.gettext = t.gettext + self.ngettext = t.ngettext + self.pgettext = t.pgettext + self.npgettext = t.npgettext + + def test_plural_forms_null_translations(self): + t = gettext.NullTranslations() + self._test_plural_forms( + t.ngettext, t.gettext, + 'There is %s file', 'There are %s files', + 'There is %s file', 'There are %s files', + numbers_only=False) + + def test_plural_context_forms_null_translations(self): + t = gettext.NullTranslations() + self._test_plural_forms( + partial(t.npgettext, 'With context'), + partial(t.pgettext, 'With context'), + 'There is %s file', 'There are %s files', + 'There is %s file', 'There are %s files', + numbers_only=False) + + +class PluralFormsInternalTestCase: # Examples from http://www.gnu.org/software/gettext/manual/gettext.html def test_ja(self): diff --git a/Misc/NEWS.d/next/Library/2023-10-08-18-15-02.gh-issue-110519.RDGe8-.rst b/Misc/NEWS.d/next/Library/2023-10-08-18-15-02.gh-issue-110519.RDGe8-.rst new file mode 100644 index 00000000000000..8ff916736584dc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-08-18-15-02.gh-issue-110519.RDGe8-.rst @@ -0,0 +1,3 @@ +Deprecation warning about non-integer number in :mod:`gettext` now alwais +refers to the line in the user code where gettext function or method is +used. Previously it could refer to a line in ``gettext`` code. From c8bffd1667f4df4a6d2f31c1e9761f96940f8d6d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 03:14:00 +0200 Subject: [PATCH 0972/1206] [3.12] Remove unused `SPHINXLINT` var from `Doc/Makefile`. (GH-110570) (#110585) Remove unused `SPHINXLINT` var from `Doc/Makefile`. (GH-110570) Remove unused `SPHINXLINT` var. (cherry picked from commit bdbe43c7d0ad5ebda0232a4ab39689ea79a9733a) Co-authored-by: Ezio Melotti --- Doc/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Doc/Makefile b/Doc/Makefile index 22691895068fea..78ee4271e25f79 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -7,7 +7,6 @@ PYTHON = python3 VENVDIR = ./venv SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build -SPHINXLINT = PATH=$(VENVDIR)/bin:$$PATH sphinx-lint BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb JOBS = auto PAPER = From e73210c0233a727078b4f4ae02a1ed35693d51b7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:24:10 +0200 Subject: [PATCH 0973/1206] [3.12] Add some 'meta hooks' to our pre-commit config (GH-110587) (#110599) Add some 'meta hooks' to our pre-commit config (GH-110587) (cherry picked from commit d5ec77fafd352b4eb290b86d70e4d0b4673459eb) Co-authored-by: Alex Waygood --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a5d32a04fc2d7d..3e17bb6f0256a6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,3 +26,8 @@ repos: args: [--enable=default-role] files: ^Doc/|^Misc/NEWS.d/next/ types: [rst] + + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes From 0ffbde4e05a32eb16bd61bfd6a7158a5b0bd785f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:39:55 +0200 Subject: [PATCH 0974/1206] [3.12] gh-109408: Add the docs whitespace check from patchcheck to pre-commit (GH-109854) (#110594) gh-109408: Add the docs whitespace check from patchcheck to pre-commit (GH-109854) (cherry picked from commit 7426ed0347d66f7ef61ea7ae6c3163258b8fb128) Co-authored-by: Hugo van Kemenade Co-authored-by: Alex Waygood Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- Tools/patchcheck/patchcheck.py | 44 ++++++++++------------------------ 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e17bb6f0256a6..82863ad326f04d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: types: [python] exclude: Lib/test/tokenizedata/coding20731.py - id: trailing-whitespace - types_or: [c, python, rst] + types_or: [c, inc, python, rst] - repo: https://github.com/sphinx-contrib/sphinx-lint rev: v0.6.8 diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index e3959ce428c7c5..af1f0584bb5403 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -30,7 +30,8 @@ def get_python_source_dir(): def n_files_str(count): """Return 'N file(s)' with the proper plurality on 'file'.""" - return "{} file{}".format(count, "s" if count != 1 else "") + s = "s" if count != 1 else "" + return f"{count} file{s}" def status(message, modal=False, info=None): @@ -84,7 +85,7 @@ def get_git_remote_default_branch(remote_name): It is typically called 'main', but may differ """ - cmd = "git remote show {}".format(remote_name).split() + cmd = f"git remote show {remote_name}".split() env = os.environ.copy() env['LANG'] = 'C' try: @@ -171,9 +172,9 @@ def report_modified_files(file_paths): if count == 0: return n_files_str(count) else: - lines = ["{}:".format(n_files_str(count))] + lines = [f"{n_files_str(count)}:"] for path in file_paths: - lines.append(" {}".format(path)) + lines.append(f" {path}") return "\n".join(lines) @@ -212,27 +213,6 @@ def normalize_c_whitespace(file_paths): return fixed -ws_re = re.compile(br'\s+(\r?\n)$') - -@status("Fixing docs whitespace", info=report_modified_files) -def normalize_docs_whitespace(file_paths): - fixed = [] - for path in file_paths: - abspath = os.path.join(SRCDIR, path) - try: - with open(abspath, 'rb') as f: - lines = f.readlines() - new_lines = [ws_re.sub(br'\1', line) for line in lines] - if new_lines != lines: - shutil.copyfile(abspath, abspath + '.bak') - with open(abspath, 'wb') as f: - f.writelines(new_lines) - fixed.append(path) - except Exception as err: - print('Cannot fix %s: %s' % (path, err)) - return fixed - - @status("Docs modified", modal=True) def docs_modified(file_paths): """Report if any file in the Doc directory has been changed.""" @@ -251,6 +231,7 @@ def reported_news(file_paths): return any(p.startswith(os.path.join('Misc', 'NEWS.d', 'next')) for p in file_paths) + @status("configure regenerated", modal=True, info=str) def regenerated_configure(file_paths): """Check if configure has been regenerated.""" @@ -259,6 +240,7 @@ def regenerated_configure(file_paths): else: return "not needed" + @status("pyconfig.h.in regenerated", modal=True, info=str) def regenerated_pyconfig_h_in(file_paths): """Check if pyconfig.h.in has been regenerated.""" @@ -267,6 +249,7 @@ def regenerated_pyconfig_h_in(file_paths): else: return "not needed" + def ci(pull_request): if pull_request == 'false': print('Not a pull request; skipping') @@ -275,19 +258,18 @@ def ci(pull_request): file_paths = changed_files(base_branch) python_files = [fn for fn in file_paths if fn.endswith('.py')] c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] - doc_files = [fn for fn in file_paths if fn.startswith('Doc') and - fn.endswith(('.rst', '.inc'))] fixed = [] fixed.extend(normalize_whitespace(python_files)) fixed.extend(normalize_c_whitespace(c_files)) - fixed.extend(normalize_docs_whitespace(doc_files)) if not fixed: print('No whitespace issues found') else: - print(f'Please fix the {len(fixed)} file(s) with whitespace issues') - print('(on UNIX you can run `make patchcheck` to make the fixes)') + count = len(fixed) + print(f'Please fix the {n_files_str(count)} with whitespace issues') + print('(on Unix you can run `make patchcheck` to make the fixes)') sys.exit(1) + def main(): base_branch = get_base_branch() file_paths = changed_files(base_branch) @@ -300,8 +282,6 @@ def main(): normalize_whitespace(python_files) # C rules enforcement. normalize_c_whitespace(c_files) - # Doc whitespace enforcement. - normalize_docs_whitespace(doc_files) # Docs updated. docs_modified(doc_files) # Misc/ACKS changed. From 36886726a2fe9a2c8511cfb405704f39cf184d7c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 10 Oct 2023 10:58:56 +0200 Subject: [PATCH 0975/1206] [3.12] gh-110558: Run ruff on Argument Clinic in CI (#110559) (#110598) --- .github/workflows/lint.yml | 2 +- .pre-commit-config.yaml | 4 ++++ Lib/test/.ruff.toml | 2 ++ Lib/test/test_clinic.py | 2 -- Tools/clinic/.ruff.toml | 14 ++++++++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 Tools/clinic/.ruff.toml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 89f65816b6969d..6c1c29a58cf4fc 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,7 +7,7 @@ permissions: env: FORCE_COLOR: 1 - RUFF_FORMAT: github + RUFF_OUTPUT_FORMAT: github concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 82863ad326f04d..ffca103bb33e86 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,6 +6,10 @@ repos: name: Run Ruff on Lib/test/ args: [--exit-non-zero-on-fix] files: ^Lib/test/ + - id: ruff + name: Run Ruff on Tools/clinic/ + args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml] + files: ^Tools/clinic/|Lib/test/test_clinic.py - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml index 99521dd0ec6574..52a84f6a379427 100644 --- a/Lib/test/.ruff.toml +++ b/Lib/test/.ruff.toml @@ -3,6 +3,8 @@ select = [ "F811", # Redefinition of unused variable (useful for finding test methods with the same name) ] extend-exclude = [ + # Excluded (run with the other AC files in its own separate ruff job in pre-commit) + "test_clinic.py", # Failed to lint "badsyntax_pep3120.py", "encoded_modules/module_iso_8859_1.py", diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 520cc51302212d..23487958f45648 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -4,7 +4,6 @@ from test import support, test_tools from test.support import os_helper -from test.support import SHORT_TIMEOUT, requires_subprocess from test.support.os_helper import TESTFN, unlink from textwrap import dedent from unittest import TestCase @@ -600,7 +599,6 @@ def test_param_no_docstring(self): follow_symlinks: bool = True something_else: str = '' """) - p = function.parameters['follow_symlinks'] self.assertEqual(3, len(function.parameters)) conv = function.parameters['something_else'].converter self.assertIsInstance(conv, clinic.str_converter) diff --git a/Tools/clinic/.ruff.toml b/Tools/clinic/.ruff.toml new file mode 100644 index 00000000000000..3bc9d908ed3296 --- /dev/null +++ b/Tools/clinic/.ruff.toml @@ -0,0 +1,14 @@ +target-version = "py310" +fix = true +select = [ + "F", # Enable all pyflakes rules + "RUF100", # Ban unused `# noqa` comments + "PGH004", # Ban blanket `# noqa` comments (only ignore specific error codes) +] +unfixable = [ + # The autofixes sometimes do the wrong things for these; + # it's better to have to manually look at the code and see how it needs fixing + "F841", # Detects unused variables + "F601", # Detects dictionaries that have duplicate keys + "F602", # Also detects dictionaries that have duplicate keys +] From 2fc80814bf55445fb2cc56b25ec54d8e308e3408 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:12:28 +0200 Subject: [PATCH 0976/1206] [3.12] gh-110378: Close invalid generators in contextmanager and asynccontextmanager (GH-110499) (#110588) contextmanager and asynccontextmanager context managers now close an invalid underlying generator object that yields more then one value. (cherry picked from commit 96fed66a65097eac2dc528ce29c9ba676bb07689) Co-authored-by: Serhiy Storchaka --- Lib/contextlib.py | 20 ++++++++++++++---- Lib/test/test_contextlib.py | 21 ++++++++++++++++--- Lib/test/test_contextlib_async.py | 6 ++++++ ...-10-07-13-50-12.gh-issue-110378.Y4L8fl.rst | 3 +++ 4 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-07-13-50-12.gh-issue-110378.Y4L8fl.rst diff --git a/Lib/contextlib.py b/Lib/contextlib.py index b5acbcb9e6d77c..2efed2d9ec4742 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -145,7 +145,10 @@ def __exit__(self, typ, value, traceback): except StopIteration: return False else: - raise RuntimeError("generator didn't stop") + try: + raise RuntimeError("generator didn't stop") + finally: + self.gen.close() else: if value is None: # Need to force instantiation so we can reliably @@ -187,7 +190,10 @@ def __exit__(self, typ, value, traceback): raise exc.__traceback__ = traceback return False - raise RuntimeError("generator didn't stop after throw()") + try: + raise RuntimeError("generator didn't stop after throw()") + finally: + self.gen.close() class _AsyncGeneratorContextManager( _GeneratorContextManagerBase, @@ -212,7 +218,10 @@ async def __aexit__(self, typ, value, traceback): except StopAsyncIteration: return False else: - raise RuntimeError("generator didn't stop") + try: + raise RuntimeError("generator didn't stop") + finally: + await self.gen.aclose() else: if value is None: # Need to force instantiation so we can reliably @@ -254,7 +263,10 @@ async def __aexit__(self, typ, value, traceback): raise exc.__traceback__ = traceback return False - raise RuntimeError("generator didn't stop after athrow()") + try: + raise RuntimeError("generator didn't stop after athrow()") + finally: + await self.gen.aclose() def contextmanager(func): diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index 0f8351ab8108a6..b15829414e5dbb 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -157,9 +157,24 @@ def whoo(): yield ctx = whoo() ctx.__enter__() - self.assertRaises( - RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None - ) + with self.assertRaises(RuntimeError): + ctx.__exit__(TypeError, TypeError("foo"), None) + if support.check_impl_detail(cpython=True): + # The "gen" attribute is an implementation detail. + self.assertFalse(ctx.gen.gi_suspended) + + def test_contextmanager_trap_second_yield(self): + @contextmanager + def whoo(): + yield + yield + ctx = whoo() + ctx.__enter__() + with self.assertRaises(RuntimeError): + ctx.__exit__(None, None, None) + if support.check_impl_detail(cpython=True): + # The "gen" attribute is an implementation detail. + self.assertFalse(ctx.gen.gi_suspended) def test_contextmanager_except(self): state = [] diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py index 3d43ed0fcab168..e519dffee78b44 100644 --- a/Lib/test/test_contextlib_async.py +++ b/Lib/test/test_contextlib_async.py @@ -204,6 +204,9 @@ async def whoo(): await ctx.__aenter__() with self.assertRaises(RuntimeError): await ctx.__aexit__(TypeError, TypeError('foo'), None) + if support.check_impl_detail(cpython=True): + # The "gen" attribute is an implementation detail. + self.assertFalse(ctx.gen.ag_suspended) @_async_test async def test_contextmanager_trap_no_yield(self): @@ -225,6 +228,9 @@ async def whoo(): await ctx.__aenter__() with self.assertRaises(RuntimeError): await ctx.__aexit__(None, None, None) + if support.check_impl_detail(cpython=True): + # The "gen" attribute is an implementation detail. + self.assertFalse(ctx.gen.ag_suspended) @_async_test async def test_contextmanager_non_normalised(self): diff --git a/Misc/NEWS.d/next/Library/2023-10-07-13-50-12.gh-issue-110378.Y4L8fl.rst b/Misc/NEWS.d/next/Library/2023-10-07-13-50-12.gh-issue-110378.Y4L8fl.rst new file mode 100644 index 00000000000000..ef5395fc3c6420 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-07-13-50-12.gh-issue-110378.Y4L8fl.rst @@ -0,0 +1,3 @@ +:func:`~contextlib.contextmanager` and +:func:`~contextlib.asynccontextmanager` context managers now close an invalid +underlying generator object that yields more then one value. From 190660abe9168ef16370c2b8f346288ebda11fb3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:26:36 +0200 Subject: [PATCH 0977/1206] [3.12] gh-78469: Declare missing sethostname for Solaris 10 (GH-109447) (#110580) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add OS version specific macro for Solaris: Py_SUNOS_VERSION. (cherry picked from commit 3b1580af07c0ce90d1c2073ab087772283d7e3b9) Co-authored-by: Jakub Kulík --- Modules/socketmodule.c | 5 +++-- configure | 9 +++++++++ configure.ac | 8 ++++++++ pyconfig.h.in | 3 +++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 4ec68e22a9f8cd..62b0e67be15c49 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5655,8 +5655,9 @@ socket_sethostname(PyObject *self, PyObject *args) Py_buffer buf; int res, flag = 0; -#ifdef _AIX -/* issue #18259, not declared in any useful header file */ +#if defined(_AIX) || (defined(__sun) && defined(__SVR4) && Py_SUNOS_VERSION <= 510) +/* issue #18259, sethostname is not declared in any useful header file on AIX + * the same is true for Solaris 10 */ extern int sethostname(const char *, size_t); #endif diff --git a/configure b/configure index 985b3741349e8e..0240ff86dccbf9 100755 --- a/configure +++ b/configure @@ -4304,6 +4304,15 @@ then darwin*) MACHDEP="darwin";; '') MACHDEP="unknown";; esac + + if test "$ac_sys_system" = "SunOS"; then + # For Solaris, there isn't an OS version specific macro defined + # in most compilers, so we define one here. + SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'` + +printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h + + fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5 printf "%s\n" "\"$MACHDEP\"" >&6; } diff --git a/configure.ac b/configure.ac index 2a7a91882640fd..34e0653623dd6e 100644 --- a/configure.ac +++ b/configure.ac @@ -590,6 +590,14 @@ then darwin*) MACHDEP="darwin";; '') MACHDEP="unknown";; esac + + if test "$ac_sys_system" = "SunOS"; then + # For Solaris, there isn't an OS version specific macro defined + # in most compilers, so we define one here. + SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\([0-9]\)$!.0\1!g' | tr -d '.'` + AC_DEFINE_UNQUOTED([Py_SUNOS_VERSION], [$SUNOS_VERSION], + [The version of SunOS/Solaris as reported by `uname -r' without the dot.]) + fi fi AC_MSG_RESULT(["$MACHDEP"]) diff --git a/pyconfig.h.in b/pyconfig.h.in index 9f858b2d3541d0..6d370f6664c10c 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1621,6 +1621,9 @@ /* Define if you want to enable internal statistics gathering. */ #undef Py_STATS +/* The version of SunOS/Solaris as reported by `uname -r' without the dot. */ +#undef Py_SUNOS_VERSION + /* Define if you want to enable tracing references for debugging purpose */ #undef Py_TRACE_REFS From 55d607683f85367e503ee34b85bc3b9c1a782552 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 12:35:21 +0200 Subject: [PATCH 0978/1206] [3.12] gh-110558: Enable ruff's pyupgrade rules when running on Argument Clinic (GH-110603) (#110609) gh-110558: Enable ruff's pyupgrade rules when running on Argument Clinic (GH-110603) (cherry picked from commit fc811c8d205db9c19f42890e2c4193a0c2f87965) Co-authored-by: Alex Waygood --- .pre-commit-config.yaml | 2 +- Lib/test/test_clinic.py | 6 +++--- Tools/clinic/.ruff.toml | 15 +++++++++++++++ Tools/clinic/clinic.py | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ffca103bb33e86..8ad1f33d3a6050 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: args: [--exit-non-zero-on-fix] files: ^Lib/test/ - id: ruff - name: Run Ruff on Tools/clinic/ + name: Run Ruff on Argument Clinic args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml] files: ^Tools/clinic/|Lib/test/test_clinic.py diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 23487958f45648..05eea78a0ce4e5 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1394,7 +1394,7 @@ def expect_failure(self, *args): def test_external(self): CLINIC_TEST = 'clinic.test.c' source = support.findfile(CLINIC_TEST) - with open(source, 'r', encoding='utf-8') as f: + with open(source, encoding='utf-8') as f: orig_contents = f.read() # Run clinic CLI and verify that it does not complain. @@ -1402,7 +1402,7 @@ def test_external(self): out = self.expect_success("-f", "-o", TESTFN, source) self.assertEqual(out, "") - with open(TESTFN, 'r', encoding='utf-8') as f: + with open(TESTFN, encoding='utf-8') as f: new_contents = f.read() self.assertEqual(new_contents, orig_contents) @@ -1463,7 +1463,7 @@ def test_cli_force(self): "/*[clinic end generated code: " "output=2124c291eb067d76 input=9543a8d2da235301]*/\n" ) - with open(fn, 'r', encoding='utf-8') as f: + with open(fn, encoding='utf-8') as f: generated = f.read() self.assertTrue(generated.endswith(checksum)) diff --git a/Tools/clinic/.ruff.toml b/Tools/clinic/.ruff.toml index 3bc9d908ed3296..cbb3a9a8f3a8c2 100644 --- a/Tools/clinic/.ruff.toml +++ b/Tools/clinic/.ruff.toml @@ -2,9 +2,24 @@ target-version = "py310" fix = true select = [ "F", # Enable all pyflakes rules + "UP", # Enable all pyupgrade rules by default "RUF100", # Ban unused `# noqa` comments "PGH004", # Ban blanket `# noqa` comments (only ignore specific error codes) ] +ignore = [ + # Unnecessary parentheses to functools.lru_cache: just leads to unnecessary churn. + # https://github.com/python/cpython/pull/104684#discussion_r1199653347. + "UP011", + # Use format specifiers instead of %-style formatting. + # Doesn't always make code more readable. + "UP031", + # Use f-strings instead of format specifiers. + # Doesn't always make code more readable. + "UP032", + # Use PEP-604 unions rather than tuples for isinstance() checks. + # Makes code slower and more verbose. https://github.com/astral-sh/ruff/issues/7871. + "UP038", +] unfixable = [ # The autofixes sometimes do the wrong things for these; # it's better to have to manually look at the code and see how it needs fixing diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index fd394c92cad9c6..921b77bad51330 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1968,7 +1968,7 @@ def dump(self): def write_file(filename: str, new_contents: str) -> None: try: - with open(filename, 'r', encoding="utf-8") as fp: + with open(filename, encoding="utf-8") as fp: old_contents = fp.read() if old_contents == new_contents: From c1e8e90915e38604175e20e36a24fe45249cdc33 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 12:55:21 +0200 Subject: [PATCH 0979/1206] [3.12] gh-110590: Fix a bug where _sre.compile would overwrite exceptions (GH-110591) (#110613) TypeError would be overwritten by OverflowError if 'code' param contained non-ints. (cherry picked from commit 344d3a222a7864f8157773749bdd77d1c9dfc1e6) Co-authored-by: Nikita Sobolev --- Lib/test/test_re.py | 3 +++ .../Library/2023-10-10-10-46-55.gh-issue-110590.fatz-h.rst | 3 +++ Modules/_sre/sre.c | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-10-10-10-46-55.gh-issue-110590.fatz-h.rst diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 5a5de523eba052..382ef0b33cc05f 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2694,6 +2694,9 @@ def test_dealloc(self): _sre.compile("abc", 0, [long_overflow], 0, {}, ()) with self.assertRaises(TypeError): _sre.compile({}, 0, [], 0, [], []) + # gh-110590: `TypeError` was overwritten with `OverflowError`: + with self.assertRaises(TypeError): + _sre.compile('', 0, ['abc'], 0, {}, ()) @cpython_only def test_repeat_minmax_overflow_maxrepeat(self): diff --git a/Misc/NEWS.d/next/Library/2023-10-10-10-46-55.gh-issue-110590.fatz-h.rst b/Misc/NEWS.d/next/Library/2023-10-10-10-46-55.gh-issue-110590.fatz-h.rst new file mode 100644 index 00000000000000..20dc3fff205994 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-10-10-46-55.gh-issue-110590.fatz-h.rst @@ -0,0 +1,3 @@ +Fix a bug in :meth:`!_sre.compile` where :exc:`TypeError` +would be overwritten by :exc:`OverflowError` when +the *code* argument was a list of non-ints. diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 2f1c7324a0fa46..ace2e9bd7cc2f6 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -1462,6 +1462,9 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, for (i = 0; i < n; i++) { PyObject *o = PyList_GET_ITEM(code, i); unsigned long value = PyLong_AsUnsignedLong(o); + if (value == (unsigned long)-1 && PyErr_Occurred()) { + break; + } self->code[i] = (SRE_CODE) value; if ((unsigned long) self->code[i] != value) { PyErr_SetString(PyExc_OverflowError, From 26a3563caeed5dd77c8ef9c0dc4e0cc1edc064c4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:12:30 +0200 Subject: [PATCH 0980/1206] [3.12] gh-110378: Fix test_async_gen_propagates_generator_exit in test_contextlib_async (GH-110500) (#110610) It now fails if the original bug is not fixed, and no longer produce ResourceWarning with fixed code. (cherry picked from commit 5aa62a8de15212577a13966710b3aede46e93824) Co-authored-by: Serhiy Storchaka --- Lib/test/test_contextlib_async.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py index e519dffee78b44..02d3fe7f318608 100644 --- a/Lib/test/test_contextlib_async.py +++ b/Lib/test/test_contextlib_async.py @@ -49,15 +49,11 @@ async def gen(): async with ctx(): yield 11 - ret = [] - exc = ValueError(22) - with self.assertRaises(ValueError): - async with ctx(): - async for val in gen(): - ret.append(val) - raise exc - - self.assertEqual(ret, [11]) + g = gen() + async for val in g: + self.assertEqual(val, 11) + break + await g.aclose() def test_exit_is_abstract(self): class MissingAexit(AbstractAsyncContextManager): From 80e4abe0ce46f3ec5bca8d918a9772a7e8ef41a7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:10:22 +0200 Subject: [PATCH 0981/1206] [3.12] gh-101100: Fix sphinx warnings in `library/socketserver.rst` (GH-110207) (GH-110623) (cherry picked from commit 756062b296df6242ba324e4cdc8f3e38bfc83617) Co-authored-by: Nikita Sobolev --- Doc/library/socketserver.rst | 77 ++++++++++++++++++++++++------------ Doc/tools/.nitignore | 1 - 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst index d65e9fe81acf8b..5fd213fa613c8d 100644 --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -116,23 +116,28 @@ server is the address family. :class:`ForkingMixIn` and the Forking classes mentioned below are only available on POSIX platforms that support :func:`~os.fork`. - :meth:`socketserver.ForkingMixIn.server_close` waits until all child - processes complete, except if - :attr:`socketserver.ForkingMixIn.block_on_close` attribute is false. + .. attribute:: block_on_close - :meth:`socketserver.ThreadingMixIn.server_close` waits until all non-daemon - threads complete, except if - :attr:`socketserver.ThreadingMixIn.block_on_close` attribute is false. Use - daemonic threads by setting - :data:`ThreadingMixIn.daemon_threads` to ``True`` to not wait until threads - complete. + :meth:`ForkingMixIn.server_close ` + waits until all child processes complete, except if + :attr:`block_on_close` attribute is ``False``. + + :meth:`ThreadingMixIn.server_close ` + waits until all non-daemon threads complete, except if + :attr:`block_on_close` attribute is ``False``. + + .. attribute:: daemon_threads + + For :class:`ThreadingMixIn` use daemonic threads by setting + :data:`ThreadingMixIn.daemon_threads ` + to ``True`` to not wait until threads complete. .. versionchanged:: 3.7 - :meth:`socketserver.ForkingMixIn.server_close` and - :meth:`socketserver.ThreadingMixIn.server_close` now waits until all + :meth:`ForkingMixIn.server_close ` and + :meth:`ThreadingMixIn.server_close ` now waits until all child processes and non-daemonic threads complete. - Add a new :attr:`socketserver.ForkingMixIn.block_on_close` class + Add a new :attr:`ForkingMixIn.block_on_close ` class attribute to opt-in for the pre-3.7 behaviour. @@ -412,13 +417,13 @@ Request Handler Objects This function must do all the work required to service a request. The default implementation does nothing. Several instance attributes are - available to it; the request is available as :attr:`self.request`; the client - address as :attr:`self.client_address`; and the server instance as - :attr:`self.server`, in case it needs access to per-server information. + available to it; the request is available as :attr:`request`; the client + address as :attr:`client_address`; and the server instance as + :attr:`server`, in case it needs access to per-server information. - The type of :attr:`self.request` is different for datagram or stream - services. For stream services, :attr:`self.request` is a socket object; for - datagram services, :attr:`self.request` is a pair of string and socket. + The type of :attr:`request` is different for datagram or stream + services. For stream services, :attr:`request` is a socket object; for + datagram services, :attr:`request` is a pair of string and socket. .. method:: finish() @@ -428,20 +433,42 @@ Request Handler Objects raises an exception, this function will not be called. + .. attribute:: request + + The *new* :class:`socket.socket` object + to be used to communicate with the client. + + + .. attribute:: client_address + + Client address returned by :meth:`BaseServer.get_request`. + + + .. attribute:: server + + :class:`BaseServer` object used for handling the request. + + .. class:: StreamRequestHandler DatagramRequestHandler These :class:`BaseRequestHandler` subclasses override the :meth:`~BaseRequestHandler.setup` and :meth:`~BaseRequestHandler.finish` - methods, and provide :attr:`self.rfile` and :attr:`self.wfile` attributes. - The :attr:`self.rfile` and :attr:`self.wfile` attributes can be - read or written, respectively, to get the request data or return data - to the client. - The :attr:`!rfile` attributes support the :class:`io.BufferedIOBase` readable interface, - and :attr:`!wfile` attributes support the :class:`!io.BufferedIOBase` writable interface. + methods, and provide :attr:`rfile` and :attr:`wfile` attributes. + + .. attribute:: rfile + + A file object from which receives the request is read. + Support the :class:`io.BufferedIOBase` readable interface. + + .. attribute:: wfile + + A file object to which the reply is written. + Support the :class:`io.BufferedIOBase` writable interface + .. versionchanged:: 3.6 - :attr:`StreamRequestHandler.wfile` also supports the + :attr:`wfile` also supports the :class:`io.BufferedIOBase` writable interface. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 90a66ac8a282a0..5c3165c18e36a7 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -120,7 +120,6 @@ Doc/library/shelve.rst Doc/library/signal.rst Doc/library/smtplib.rst Doc/library/socket.rst -Doc/library/socketserver.rst Doc/library/ssl.rst Doc/library/stdtypes.rst Doc/library/string.rst From 555db6fd098fa26041e88eef83e8d7de05a54340 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:10:55 +0200 Subject: [PATCH 0982/1206] [3.12] gh-81002: Add tests for termios (GH-110386) (GH-110619) (cherry picked from commit 92a9e980245156bf75ede0869f8ba9512e04d2eb) Co-authored-by: Serhiy Storchaka --- Lib/test/test_termios.py | 220 ++++++++++++++++++ ...3-10-05-13-46-50.gh-issue-81002.bOcuV6.rst | 1 + 2 files changed, 221 insertions(+) create mode 100644 Lib/test/test_termios.py create mode 100644 Misc/NEWS.d/next/Tests/2023-10-05-13-46-50.gh-issue-81002.bOcuV6.rst diff --git a/Lib/test/test_termios.py b/Lib/test/test_termios.py new file mode 100644 index 00000000000000..58698ffac2d981 --- /dev/null +++ b/Lib/test/test_termios.py @@ -0,0 +1,220 @@ +import errno +import os +import sys +import tempfile +import unittest +from test.support.import_helper import import_module + +termios = import_module('termios') + + +@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()") +class TestFunctions(unittest.TestCase): + + def setUp(self): + master_fd, self.fd = os.openpty() + self.addCleanup(os.close, master_fd) + self.stream = self.enterContext(open(self.fd, 'wb', buffering=0)) + tmp = self.enterContext(tempfile.TemporaryFile(mode='wb', buffering=0)) + self.bad_fd = tmp.fileno() + + def assertRaisesTermiosError(self, errno, callable, *args): + with self.assertRaises(termios.error) as cm: + callable(*args) + self.assertEqual(cm.exception.args[0], errno) + + def test_tcgetattr(self): + attrs = termios.tcgetattr(self.fd) + self.assertIsInstance(attrs, list) + self.assertEqual(len(attrs), 7) + for i in range(6): + self.assertIsInstance(attrs[i], int) + iflag, oflag, cflag, lflag, ispeed, ospeed, cc = attrs + self.assertIsInstance(cc, list) + self.assertEqual(len(cc), termios.NCCS) + for i, x in enumerate(cc): + if ((lflag & termios.ICANON) == 0 and + (i == termios.VMIN or i == termios.VTIME)): + self.assertIsInstance(x, int) + else: + self.assertIsInstance(x, bytes) + self.assertEqual(len(x), 1) + self.assertEqual(termios.tcgetattr(self.stream), attrs) + + def test_tcgetattr_errors(self): + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcgetattr, self.bad_fd) + self.assertRaises(ValueError, termios.tcgetattr, -1) + self.assertRaises(OverflowError, termios.tcgetattr, 2**1000) + self.assertRaises(TypeError, termios.tcgetattr, object()) + self.assertRaises(TypeError, termios.tcgetattr) + + def test_tcsetattr(self): + attrs = termios.tcgetattr(self.fd) + termios.tcsetattr(self.fd, termios.TCSANOW, attrs) + termios.tcsetattr(self.fd, termios.TCSADRAIN, attrs) + termios.tcsetattr(self.fd, termios.TCSAFLUSH, attrs) + termios.tcsetattr(self.stream, termios.TCSANOW, attrs) + + def test_tcsetattr_errors(self): + attrs = termios.tcgetattr(self.fd) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, tuple(attrs)) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs[:-1]) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs + [0]) + for i in range(6): + attrs2 = attrs[:] + attrs2[i] = 2**1000 + self.assertRaises(OverflowError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs2) + attrs2[i] = object() + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs2) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs[:-1] + [attrs[-1][:-1]]) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs[:-1] + [attrs[-1] + [b'\0']]) + for i in range(len(attrs[-1])): + attrs2 = attrs[:] + attrs2[-1] = attrs2[-1][:] + attrs2[-1][i] = 2**1000 + self.assertRaises(OverflowError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs2) + attrs2[-1][i] = object() + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs2) + attrs2[-1][i] = b'' + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs2) + attrs2[-1][i] = b'\0\0' + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, attrs2) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW, object()) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW) + self.assertRaisesTermiosError(errno.EINVAL, termios.tcsetattr, self.fd, -1, attrs) + self.assertRaises(OverflowError, termios.tcsetattr, self.fd, 2**1000, attrs) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, object(), attrs) + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcsetattr, self.bad_fd, termios.TCSANOW, attrs) + self.assertRaises(ValueError, termios.tcsetattr, -1, termios.TCSANOW, attrs) + self.assertRaises(OverflowError, termios.tcsetattr, 2**1000, termios.TCSANOW, attrs) + self.assertRaises(TypeError, termios.tcsetattr, object(), termios.TCSANOW, attrs) + self.assertRaises(TypeError, termios.tcsetattr, self.fd, termios.TCSANOW) + + def test_tcsendbreak(self): + try: + termios.tcsendbreak(self.fd, 1) + except termios.error as exc: + if exc.args[0] == errno.ENOTTY and sys.platform.startswith('freebsd'): + self.skipTest('termios.tcsendbreak() is not supported ' + 'with pseudo-terminals (?) on this platform') + raise + termios.tcsendbreak(self.stream, 1) + + def test_tcsendbreak_errors(self): + self.assertRaises(OverflowError, termios.tcsendbreak, self.fd, 2**1000) + self.assertRaises(TypeError, termios.tcsendbreak, self.fd, 0.0) + self.assertRaises(TypeError, termios.tcsendbreak, self.fd, object()) + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcsendbreak, self.bad_fd, 0) + self.assertRaises(ValueError, termios.tcsendbreak, -1, 0) + self.assertRaises(OverflowError, termios.tcsendbreak, 2**1000, 0) + self.assertRaises(TypeError, termios.tcsendbreak, object(), 0) + self.assertRaises(TypeError, termios.tcsendbreak, self.fd) + + def test_tcdrain(self): + termios.tcdrain(self.fd) + termios.tcdrain(self.stream) + + def test_tcdrain_errors(self): + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcdrain, self.bad_fd) + self.assertRaises(ValueError, termios.tcdrain, -1) + self.assertRaises(OverflowError, termios.tcdrain, 2**1000) + self.assertRaises(TypeError, termios.tcdrain, object()) + self.assertRaises(TypeError, termios.tcdrain) + + def test_tcflush(self): + termios.tcflush(self.fd, termios.TCIFLUSH) + termios.tcflush(self.fd, termios.TCOFLUSH) + termios.tcflush(self.fd, termios.TCIOFLUSH) + + def test_tcflush_errors(self): + self.assertRaisesTermiosError(errno.EINVAL, termios.tcflush, self.fd, -1) + self.assertRaises(OverflowError, termios.tcflush, self.fd, 2**1000) + self.assertRaises(TypeError, termios.tcflush, self.fd, object()) + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcflush, self.bad_fd, termios.TCIFLUSH) + self.assertRaises(ValueError, termios.tcflush, -1, termios.TCIFLUSH) + self.assertRaises(OverflowError, termios.tcflush, 2**1000, termios.TCIFLUSH) + self.assertRaises(TypeError, termios.tcflush, object(), termios.TCIFLUSH) + self.assertRaises(TypeError, termios.tcflush, self.fd) + + def test_tcflow(self): + termios.tcflow(self.fd, termios.TCOOFF) + termios.tcflow(self.fd, termios.TCOON) + termios.tcflow(self.fd, termios.TCIOFF) + termios.tcflow(self.fd, termios.TCION) + + def test_tcflow_errors(self): + self.assertRaisesTermiosError(errno.EINVAL, termios.tcflow, self.fd, -1) + self.assertRaises(OverflowError, termios.tcflow, self.fd, 2**1000) + self.assertRaises(TypeError, termios.tcflow, self.fd, object()) + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcflow, self.bad_fd, termios.TCOON) + self.assertRaises(ValueError, termios.tcflow, -1, termios.TCOON) + self.assertRaises(OverflowError, termios.tcflow, 2**1000, termios.TCOON) + self.assertRaises(TypeError, termios.tcflow, object(), termios.TCOON) + self.assertRaises(TypeError, termios.tcflow, self.fd) + + def test_tcgetwinsize(self): + size = termios.tcgetwinsize(self.fd) + self.assertIsInstance(size, tuple) + self.assertEqual(len(size), 2) + self.assertIsInstance(size[0], int) + self.assertIsInstance(size[1], int) + self.assertEqual(termios.tcgetwinsize(self.stream), size) + + def test_tcgetwinsize_errors(self): + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcgetwinsize, self.bad_fd) + self.assertRaises(ValueError, termios.tcgetwinsize, -1) + self.assertRaises(OverflowError, termios.tcgetwinsize, 2**1000) + self.assertRaises(TypeError, termios.tcgetwinsize, object()) + self.assertRaises(TypeError, termios.tcgetwinsize) + + def test_tcsetwinsize(self): + size = termios.tcgetwinsize(self.fd) + termios.tcsetwinsize(self.fd, size) + termios.tcsetwinsize(self.fd, list(size)) + termios.tcsetwinsize(self.stream, size) + + def test_tcsetwinsize_errors(self): + size = termios.tcgetwinsize(self.fd) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, size[:-1]) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, size + (0,)) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, object()) + self.assertRaises(OverflowError, termios.tcsetwinsize, self.fd, (size[0], 2**1000)) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, (size[0], float(size[1]))) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, (size[0], object())) + self.assertRaises(OverflowError, termios.tcsetwinsize, self.fd, (2**1000, size[1])) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, (float(size[0]), size[1])) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd, (object(), size[1])) + self.assertRaisesTermiosError(errno.ENOTTY, termios.tcsetwinsize, self.bad_fd, size) + self.assertRaises(ValueError, termios.tcsetwinsize, -1, size) + self.assertRaises(OverflowError, termios.tcsetwinsize, 2**1000, size) + self.assertRaises(TypeError, termios.tcsetwinsize, object(), size) + self.assertRaises(TypeError, termios.tcsetwinsize, self.fd) + + +class TestModule(unittest.TestCase): + def test_constants(self): + self.assertIsInstance(termios.B0, int) + self.assertIsInstance(termios.B38400, int) + self.assertIsInstance(termios.TCSANOW, int) + self.assertIsInstance(termios.TCSADRAIN, int) + self.assertIsInstance(termios.TCSAFLUSH, int) + self.assertIsInstance(termios.TCIFLUSH, int) + self.assertIsInstance(termios.TCOFLUSH, int) + self.assertIsInstance(termios.TCIOFLUSH, int) + self.assertIsInstance(termios.TCOOFF, int) + self.assertIsInstance(termios.TCOON, int) + self.assertIsInstance(termios.TCIOFF, int) + self.assertIsInstance(termios.TCION, int) + self.assertIsInstance(termios.VTIME, int) + self.assertIsInstance(termios.VMIN, int) + self.assertIsInstance(termios.NCCS, int) + self.assertLess(termios.VTIME, termios.NCCS) + self.assertLess(termios.VMIN, termios.NCCS) + + def test_exception(self): + self.assertTrue(issubclass(termios.error, Exception)) + self.assertFalse(issubclass(termios.error, OSError)) + + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS.d/next/Tests/2023-10-05-13-46-50.gh-issue-81002.bOcuV6.rst b/Misc/NEWS.d/next/Tests/2023-10-05-13-46-50.gh-issue-81002.bOcuV6.rst new file mode 100644 index 00000000000000..d69f6746d9e9aa --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-05-13-46-50.gh-issue-81002.bOcuV6.rst @@ -0,0 +1 @@ +Add tests for :mod:`termios`. From 43641f58936ef219d9382cb83f6713b00a02bdfb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:55:23 +0200 Subject: [PATCH 0983/1206] [3.12] gh-110388: Add tests for tty (GH-110394) (#110621) cherry picked from commit 7f702b26dbbf24ab5ef2be5444ae652300733b5b) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tty.py | 80 +++++++++++++++++++ ...-10-05-14-22-48.gh-issue-110388.1-HQJO.rst | 1 + 2 files changed, 81 insertions(+) create mode 100644 Lib/test/test_tty.py create mode 100644 Misc/NEWS.d/next/Tests/2023-10-05-14-22-48.gh-issue-110388.1-HQJO.rst diff --git a/Lib/test/test_tty.py b/Lib/test/test_tty.py new file mode 100644 index 00000000000000..6993047492b5ec --- /dev/null +++ b/Lib/test/test_tty.py @@ -0,0 +1,80 @@ +import os +import unittest +from test.support.import_helper import import_module + +termios = import_module('termios') +tty = import_module('tty') + + +@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()") +class TestTty(unittest.TestCase): + + def setUp(self): + master_fd, self.fd = os.openpty() + self.addCleanup(os.close, master_fd) + self.stream = self.enterContext(open(self.fd, 'wb', buffering=0)) + self.fd = self.stream.fileno() + self.mode = termios.tcgetattr(self.fd) + self.addCleanup(termios.tcsetattr, self.fd, termios.TCSANOW, self.mode) + self.addCleanup(termios.tcsetattr, self.fd, termios.TCSAFLUSH, self.mode) + + def check_cbreak(self, mode): + self.assertEqual(mode[0] & termios.ICRNL, 0) + self.assertEqual(mode[3] & termios.ECHO, 0) + self.assertEqual(mode[3] & termios.ICANON, 0) + self.assertEqual(mode[6][termios.VMIN], 1) + self.assertEqual(mode[6][termios.VTIME], 0) + + def check_raw(self, mode): + self.check_cbreak(mode) + self.assertEqual(mode[0] & termios.ISTRIP, 0) + self.assertEqual(mode[0] & termios.ICRNL, 0) + self.assertEqual(mode[1] & termios.OPOST, 0) + self.assertEqual(mode[2] & termios.PARENB, termios.CS8 & termios.PARENB) + self.assertEqual(mode[2] & termios.CSIZE, termios.CS8 & termios.CSIZE) + self.assertEqual(mode[2] & termios.CS8, termios.CS8) + self.assertEqual(mode[3] & termios.ECHO, 0) + self.assertEqual(mode[3] & termios.ICANON, 0) + self.assertEqual(mode[3] & termios.ISIG, 0) + self.assertEqual(mode[6][termios.VMIN], 1) + self.assertEqual(mode[6][termios.VTIME], 0) + + def test_cfmakeraw(self): + mode = termios.tcgetattr(self.fd) + self.assertEqual(mode, self.mode) + tty.cfmakeraw(mode) + self.check_raw(mode) + self.assertEqual(mode[4], self.mode[4]) + self.assertEqual(mode[5], self.mode[5]) + + def test_cfmakecbreak(self): + mode = termios.tcgetattr(self.fd) + self.assertEqual(mode, self.mode) + tty.cfmakecbreak(mode) + self.check_cbreak(mode) + self.assertEqual(mode[1], self.mode[1]) + self.assertEqual(mode[2], self.mode[2]) + self.assertEqual(mode[4], self.mode[4]) + self.assertEqual(mode[5], self.mode[5]) + + def test_setraw(self): + mode = tty.setraw(self.fd) + mode2 = termios.tcgetattr(self.fd) + self.check_raw(mode2) + mode3 = tty.setraw(self.fd, termios.TCSANOW) + self.assertEqual(mode3, mode2) + tty.setraw(self.stream) + tty.setraw(fd=self.fd, when=termios.TCSANOW) + + def test_setcbreak(self): + mode = tty.setcbreak(self.fd) + mode2 = termios.tcgetattr(self.fd) + self.check_cbreak(mode2) + mode3 = tty.setcbreak(self.fd, termios.TCSANOW) + self.assertEqual(mode3, mode2) + tty.setcbreak(self.stream) + tty.setcbreak(fd=self.fd, when=termios.TCSANOW) + + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS.d/next/Tests/2023-10-05-14-22-48.gh-issue-110388.1-HQJO.rst b/Misc/NEWS.d/next/Tests/2023-10-05-14-22-48.gh-issue-110388.1-HQJO.rst new file mode 100644 index 00000000000000..caac41f81547de --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-05-14-22-48.gh-issue-110388.1-HQJO.rst @@ -0,0 +1 @@ +Add tests for :mod:`tty`. From 33450a9628d88103da6a430f534455375e6c77c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:58:06 +0200 Subject: [PATCH 0984/1206] [3.12] Don't doubly-parallelise sphinx-lint (GH-110617) (#110626) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8ad1f33d3a6050..5b362a7c9d4c8a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,6 +30,7 @@ repos: args: [--enable=default-role] files: ^Doc/|^Misc/NEWS.d/next/ types: [rst] + require_serial: true - repo: meta hooks: From 948576574f6567fb0e9de84a345f877cc42ed587 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:06:35 +0200 Subject: [PATCH 0985/1206] [3.12] GH-109408: Move the Python file whitespace check from patchcheck to pre-commit (GH-109891) (#110633) GH-109408: Move the Python file whitespace check from patchcheck to pre-commit (GH-109891) (cherry picked from commit 08ec4a1dbf66383303de9ce5cb55b2b437ef92c0) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- .pre-commit-config.yaml | 9 +++++++++ Tools/patchcheck/patchcheck.py | 32 +++++++------------------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5b362a7c9d4c8a..aabf1c535868a5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,6 +23,15 @@ repos: - id: trailing-whitespace types_or: [c, inc, python, rst] + - repo: local + hooks: + - id: python-file-whitespace + name: "Check Python file whitespace" + entry: 'python Tools/patchcheck/reindent.py --nobackup --newline LF' + language: 'system' + types: [python] + exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$' + - repo: https://github.com/sphinx-contrib/sphinx-lint rev: v0.6.8 hooks: diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index af1f0584bb5403..5f55e1bff457b9 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -7,7 +7,6 @@ import subprocess import sysconfig -import reindent import untabify @@ -184,21 +183,6 @@ def report_modified_files(file_paths): }) -@status("Fixing Python file whitespace", info=report_modified_files) -def normalize_whitespace(file_paths): - """Make sure that the whitespace for .py files have been normalized.""" - reindent.makebackup = False # No need to create backups. - fixed = [ - path for path in file_paths - if ( - path.endswith('.py') - and path not in _PYTHON_FILES_WITH_TABS - and reindent.check(os.path.join(SRCDIR, path)) - ) - ] - return fixed - - @status("Fixing C file whitespace", info=report_modified_files) def normalize_c_whitespace(file_paths): """Report if any C files """ @@ -256,10 +240,8 @@ def ci(pull_request): return base_branch = get_base_branch() file_paths = changed_files(base_branch) - python_files = [fn for fn in file_paths if fn.endswith('.py')] c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] fixed = [] - fixed.extend(normalize_whitespace(python_files)) fixed.extend(normalize_c_whitespace(c_files)) if not fixed: print('No whitespace issues found') @@ -273,13 +255,10 @@ def ci(pull_request): def main(): base_branch = get_base_branch() file_paths = changed_files(base_branch) - python_files = [fn for fn in file_paths if fn.endswith('.py')] c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] doc_files = [fn for fn in file_paths if fn.startswith('Doc') and fn.endswith(('.rst', '.inc'))] misc_files = {p for p in file_paths if p.startswith('Misc')} - # PEP 8 whitespace rules enforcement. - normalize_whitespace(python_files) # C rules enforcement. normalize_c_whitespace(c_files) # Docs updated. @@ -294,10 +273,13 @@ def main(): regenerated_pyconfig_h_in(file_paths) # Test suite run and passed. - if python_files or c_files: - end = " and check for refleaks?" if c_files else "?" - print() - print("Did you run the test suite" + end) + has_c_files = any(fn for fn in file_paths if fn.endswith(('.c', '.h'))) + has_python_files = any(fn for fn in file_paths if fn.endswith('.py')) + print() + if has_c_files: + print("Did you run the test suite and check for refleaks?") + elif has_python_files: + print("Did you run the test suite?") if __name__ == '__main__': From c9157feeec86dfeac6716bd1c946693ea076780b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:00:00 +0100 Subject: [PATCH 0986/1206] [3.12] GH-109408: Move the C file whitespace check from patchcheck to pre-commit (GH-109890) (#110636) (cherry picked from commit f5edb56328b46f262b74a53343b8098a3934f761) --- .pre-commit-config.yaml | 15 ++++++ Tools/patchcheck/patchcheck.py | 88 ++-------------------------------- Tools/patchcheck/untabify.py | 10 ++-- 3 files changed, 23 insertions(+), 90 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aabf1c535868a5..9a27d30fd4163e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,6 +32,21 @@ repos: types: [python] exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$' + - repo: local + hooks: + - id: c-file-whitespace + name: "Check C file whitespace" + entry: "python Tools/patchcheck/untabify.py" + language: "system" + types_or: ['c', 'c++'] + # Don't check the style of vendored libraries + exclude: | + (?x)^( + Modules/_decimal/.* + | Modules/libmpdec/.* + | Modules/expat/.* + )$ + - repo: https://github.com/sphinx-contrib/sphinx-lint rev: v0.6.8 hooks: diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index 5f55e1bff457b9..66328c8becc1f6 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -1,29 +1,15 @@ #!/usr/bin/env python3 """Check proposed changes for common issues.""" -import re import sys -import shutil import os.path import subprocess import sysconfig -import untabify - - def get_python_source_dir(): src_dir = sysconfig.get_config_var('abs_srcdir') if not src_dir: src_dir = sysconfig.get_config_var('srcdir') return os.path.abspath(src_dir) - - -# Excluded directories which are copies of external libraries: -# don't check their coding style -EXCLUDE_DIRS = [ - os.path.join('Modules', '_decimal', 'libmpdec'), - os.path.join('Modules', 'expat'), - os.path.join('Modules', 'zlib'), - ] SRCDIR = get_python_source_dir() @@ -154,47 +140,8 @@ def changed_files(base_branch=None): else: sys.exit('need a git checkout to get modified files') - filenames2 = [] - for filename in filenames: - # Normalize the path to be able to match using .startswith() - filename = os.path.normpath(filename) - if any(filename.startswith(path) for path in EXCLUDE_DIRS): - # Exclude the file - continue - filenames2.append(filename) - - return filenames2 - - -def report_modified_files(file_paths): - count = len(file_paths) - if count == 0: - return n_files_str(count) - else: - lines = [f"{n_files_str(count)}:"] - for path in file_paths: - lines.append(f" {path}") - return "\n".join(lines) - - -#: Python files that have tabs by design: -_PYTHON_FILES_WITH_TABS = frozenset({ - 'Tools/c-analyzer/cpython/_parser.py', -}) - - -@status("Fixing C file whitespace", info=report_modified_files) -def normalize_c_whitespace(file_paths): - """Report if any C files """ - fixed = [] - for path in file_paths: - abspath = os.path.join(SRCDIR, path) - with open(abspath, 'r') as f: - if '\t' not in f.read(): - continue - untabify.process(abspath, 8, verbose=False) - fixed.append(path) - return fixed + # Normalize the path to be able to match using str.startswith() + return list(map(os.path.normpath, filenames)) @status("Docs modified", modal=True) @@ -234,33 +181,12 @@ def regenerated_pyconfig_h_in(file_paths): return "not needed" -def ci(pull_request): - if pull_request == 'false': - print('Not a pull request; skipping') - return - base_branch = get_base_branch() - file_paths = changed_files(base_branch) - c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] - fixed = [] - fixed.extend(normalize_c_whitespace(c_files)) - if not fixed: - print('No whitespace issues found') - else: - count = len(fixed) - print(f'Please fix the {n_files_str(count)} with whitespace issues') - print('(on Unix you can run `make patchcheck` to make the fixes)') - sys.exit(1) - - def main(): base_branch = get_base_branch() file_paths = changed_files(base_branch) - c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] doc_files = [fn for fn in file_paths if fn.startswith('Doc') and fn.endswith(('.rst', '.inc'))] misc_files = {p for p in file_paths if p.startswith('Misc')} - # C rules enforcement. - normalize_c_whitespace(c_files) # Docs updated. docs_modified(doc_files) # Misc/ACKS changed. @@ -283,12 +209,4 @@ def main(): if __name__ == '__main__': - import argparse - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--ci', - help='Perform pass/fail checks') - args = parser.parse_args() - if args.ci: - ci(args.ci) - else: - main() + main() diff --git a/Tools/patchcheck/untabify.py b/Tools/patchcheck/untabify.py index 861c83ced90f24..5c9d1208540830 100755 --- a/Tools/patchcheck/untabify.py +++ b/Tools/patchcheck/untabify.py @@ -21,8 +21,7 @@ def main(): if optname == '-t': tabsize = int(optvalue) - for filename in args: - process(filename, tabsize) + return max(process(filename, tabsize) for filename in args) def process(filename, tabsize, verbose=True): @@ -32,10 +31,10 @@ def process(filename, tabsize, verbose=True): encoding = f.encoding except IOError as msg: print("%r: I/O error: %s" % (filename, msg)) - return + return 2 newtext = text.expandtabs(tabsize) if newtext == text: - return + return 0 backup = filename + "~" try: os.unlink(backup) @@ -49,7 +48,8 @@ def process(filename, tabsize, verbose=True): f.write(newtext) if verbose: print(filename) + return 1 if __name__ == '__main__': - main() + raise SystemExit(main()) From 5b168fdd6fd0846fe1dac8b23866aec834db8283 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 17:20:52 +0200 Subject: [PATCH 0987/1206] [3.12] gh-110631: Set three-space indents for reST in EditorConfig (GH-110635) (#110637) gh-110631: Set three-space indents for reST in EditorConfig (GH-110635) Set three-space indents in EditorConfig (cherry picked from commit 66a9b1082049855889854bfde617059499c26dd2) Co-authored-by: Hugo van Kemenade --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.editorconfig b/.editorconfig index 81445d2d79c739..0169eed951cd3f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,5 +8,8 @@ indent_style = space [*.{py,c,cpp,h}] indent_size = 4 +[*.rst] +indent_size = 3 + [*.yml] indent_size = 2 From c2d542b42cd109d81c0308f9c4437c38ac74d2e0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 10 Oct 2023 22:38:18 +0200 Subject: [PATCH 0988/1206] [3.12] gh-108303: Move all certificates to `Lib/test/certdata/` (GH-109489) (#109682) * gh-108303: Move all certificates to `Lib/test/certdata/` (GH-109489) (cherry picked from commit e57ecf6bbc59f999d27b125ea51b042c24a07bd9) Co-authored-by: Nikita Sobolev Python 3.12 backport: update also `test_nntplib`. Co-authored-by: Nikita Sobolev Co-authored-by: T. Wouters --- Lib/test/{ => certdata}/allsans.pem | 0 Lib/test/{ => certdata}/badcert.pem | 0 Lib/test/{ => certdata}/badkey.pem | 0 Lib/test/{ => certdata}/capath/4e1295a3.0 | 0 Lib/test/{ => certdata}/capath/5ed36f99.0 | 0 Lib/test/{ => certdata}/capath/6e88d7b8.0 | 0 Lib/test/{ => certdata}/capath/99d0fa06.0 | 0 Lib/test/{ => certdata}/capath/b1930218.0 | 0 Lib/test/{ => certdata}/capath/ceff1710.0 | 0 Lib/test/{ => certdata}/ffdh3072.pem | 0 Lib/test/{ => certdata}/idnsans.pem | 0 Lib/test/{ => certdata}/keycert.passwd.pem | 0 Lib/test/{ => certdata}/keycert.pem | 0 Lib/test/{ => certdata}/keycert2.pem | 0 Lib/test/{ => certdata}/keycert3.pem | 0 Lib/test/{ => certdata}/keycert4.pem | 0 Lib/test/{ => certdata}/keycertecc.pem | 0 Lib/test/{ => certdata}/make_ssl_certs.py | 0 Lib/test/{ => certdata}/nokia.pem | 0 Lib/test/{ => certdata}/nosan.pem | 0 Lib/test/{ => certdata}/nullbytecert.pem | 0 Lib/test/{ => certdata}/nullcert.pem | 0 Lib/test/{ => certdata}/pycacert.pem | 0 Lib/test/{ => certdata}/pycakey.pem | 0 Lib/test/{ => certdata}/revocation.crl | 0 Lib/test/{ => certdata}/secp384r1.pem | 0 .../selfsigned_pythontestdotnet.pem | 0 Lib/test/{ => certdata}/ssl_cert.pem | 0 Lib/test/{ => certdata}/ssl_key.passwd.pem | 0 Lib/test/{ => certdata}/ssl_key.pem | 0 Lib/test/{ => certdata}/talos-2019-0758.pem | 0 Lib/test/ssl_servers.py | 2 +- Lib/test/test_asyncio/utils.py | 16 ++++++++-------- Lib/test/test_ftplib.py | 4 ++-- Lib/test/test_httplib.py | 8 +++++--- Lib/test/test_imaplib.py | 4 ++-- Lib/test/test_logging.py | 2 +- Lib/test/test_nntplib.py | 2 +- Lib/test/test_poplib.py | 4 ++-- Lib/test/test_ssl.py | 12 ++++++------ Lib/test/test_urllib2_localnet.py | 4 ++-- Makefile.pre.in | 3 ++- 42 files changed, 32 insertions(+), 29 deletions(-) rename Lib/test/{ => certdata}/allsans.pem (100%) rename Lib/test/{ => certdata}/badcert.pem (100%) rename Lib/test/{ => certdata}/badkey.pem (100%) rename Lib/test/{ => certdata}/capath/4e1295a3.0 (100%) rename Lib/test/{ => certdata}/capath/5ed36f99.0 (100%) rename Lib/test/{ => certdata}/capath/6e88d7b8.0 (100%) rename Lib/test/{ => certdata}/capath/99d0fa06.0 (100%) rename Lib/test/{ => certdata}/capath/b1930218.0 (100%) rename Lib/test/{ => certdata}/capath/ceff1710.0 (100%) rename Lib/test/{ => certdata}/ffdh3072.pem (100%) rename Lib/test/{ => certdata}/idnsans.pem (100%) rename Lib/test/{ => certdata}/keycert.passwd.pem (100%) rename Lib/test/{ => certdata}/keycert.pem (100%) rename Lib/test/{ => certdata}/keycert2.pem (100%) rename Lib/test/{ => certdata}/keycert3.pem (100%) rename Lib/test/{ => certdata}/keycert4.pem (100%) rename Lib/test/{ => certdata}/keycertecc.pem (100%) rename Lib/test/{ => certdata}/make_ssl_certs.py (100%) rename Lib/test/{ => certdata}/nokia.pem (100%) rename Lib/test/{ => certdata}/nosan.pem (100%) rename Lib/test/{ => certdata}/nullbytecert.pem (100%) rename Lib/test/{ => certdata}/nullcert.pem (100%) rename Lib/test/{ => certdata}/pycacert.pem (100%) rename Lib/test/{ => certdata}/pycakey.pem (100%) rename Lib/test/{ => certdata}/revocation.crl (100%) rename Lib/test/{ => certdata}/secp384r1.pem (100%) rename Lib/test/{ => certdata}/selfsigned_pythontestdotnet.pem (100%) rename Lib/test/{ => certdata}/ssl_cert.pem (100%) rename Lib/test/{ => certdata}/ssl_key.passwd.pem (100%) rename Lib/test/{ => certdata}/ssl_key.pem (100%) rename Lib/test/{ => certdata}/talos-2019-0758.pem (100%) diff --git a/Lib/test/allsans.pem b/Lib/test/certdata/allsans.pem similarity index 100% rename from Lib/test/allsans.pem rename to Lib/test/certdata/allsans.pem diff --git a/Lib/test/badcert.pem b/Lib/test/certdata/badcert.pem similarity index 100% rename from Lib/test/badcert.pem rename to Lib/test/certdata/badcert.pem diff --git a/Lib/test/badkey.pem b/Lib/test/certdata/badkey.pem similarity index 100% rename from Lib/test/badkey.pem rename to Lib/test/certdata/badkey.pem diff --git a/Lib/test/capath/4e1295a3.0 b/Lib/test/certdata/capath/4e1295a3.0 similarity index 100% rename from Lib/test/capath/4e1295a3.0 rename to Lib/test/certdata/capath/4e1295a3.0 diff --git a/Lib/test/capath/5ed36f99.0 b/Lib/test/certdata/capath/5ed36f99.0 similarity index 100% rename from Lib/test/capath/5ed36f99.0 rename to Lib/test/certdata/capath/5ed36f99.0 diff --git a/Lib/test/capath/6e88d7b8.0 b/Lib/test/certdata/capath/6e88d7b8.0 similarity index 100% rename from Lib/test/capath/6e88d7b8.0 rename to Lib/test/certdata/capath/6e88d7b8.0 diff --git a/Lib/test/capath/99d0fa06.0 b/Lib/test/certdata/capath/99d0fa06.0 similarity index 100% rename from Lib/test/capath/99d0fa06.0 rename to Lib/test/certdata/capath/99d0fa06.0 diff --git a/Lib/test/capath/b1930218.0 b/Lib/test/certdata/capath/b1930218.0 similarity index 100% rename from Lib/test/capath/b1930218.0 rename to Lib/test/certdata/capath/b1930218.0 diff --git a/Lib/test/capath/ceff1710.0 b/Lib/test/certdata/capath/ceff1710.0 similarity index 100% rename from Lib/test/capath/ceff1710.0 rename to Lib/test/certdata/capath/ceff1710.0 diff --git a/Lib/test/ffdh3072.pem b/Lib/test/certdata/ffdh3072.pem similarity index 100% rename from Lib/test/ffdh3072.pem rename to Lib/test/certdata/ffdh3072.pem diff --git a/Lib/test/idnsans.pem b/Lib/test/certdata/idnsans.pem similarity index 100% rename from Lib/test/idnsans.pem rename to Lib/test/certdata/idnsans.pem diff --git a/Lib/test/keycert.passwd.pem b/Lib/test/certdata/keycert.passwd.pem similarity index 100% rename from Lib/test/keycert.passwd.pem rename to Lib/test/certdata/keycert.passwd.pem diff --git a/Lib/test/keycert.pem b/Lib/test/certdata/keycert.pem similarity index 100% rename from Lib/test/keycert.pem rename to Lib/test/certdata/keycert.pem diff --git a/Lib/test/keycert2.pem b/Lib/test/certdata/keycert2.pem similarity index 100% rename from Lib/test/keycert2.pem rename to Lib/test/certdata/keycert2.pem diff --git a/Lib/test/keycert3.pem b/Lib/test/certdata/keycert3.pem similarity index 100% rename from Lib/test/keycert3.pem rename to Lib/test/certdata/keycert3.pem diff --git a/Lib/test/keycert4.pem b/Lib/test/certdata/keycert4.pem similarity index 100% rename from Lib/test/keycert4.pem rename to Lib/test/certdata/keycert4.pem diff --git a/Lib/test/keycertecc.pem b/Lib/test/certdata/keycertecc.pem similarity index 100% rename from Lib/test/keycertecc.pem rename to Lib/test/certdata/keycertecc.pem diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/certdata/make_ssl_certs.py similarity index 100% rename from Lib/test/make_ssl_certs.py rename to Lib/test/certdata/make_ssl_certs.py diff --git a/Lib/test/nokia.pem b/Lib/test/certdata/nokia.pem similarity index 100% rename from Lib/test/nokia.pem rename to Lib/test/certdata/nokia.pem diff --git a/Lib/test/nosan.pem b/Lib/test/certdata/nosan.pem similarity index 100% rename from Lib/test/nosan.pem rename to Lib/test/certdata/nosan.pem diff --git a/Lib/test/nullbytecert.pem b/Lib/test/certdata/nullbytecert.pem similarity index 100% rename from Lib/test/nullbytecert.pem rename to Lib/test/certdata/nullbytecert.pem diff --git a/Lib/test/nullcert.pem b/Lib/test/certdata/nullcert.pem similarity index 100% rename from Lib/test/nullcert.pem rename to Lib/test/certdata/nullcert.pem diff --git a/Lib/test/pycacert.pem b/Lib/test/certdata/pycacert.pem similarity index 100% rename from Lib/test/pycacert.pem rename to Lib/test/certdata/pycacert.pem diff --git a/Lib/test/pycakey.pem b/Lib/test/certdata/pycakey.pem similarity index 100% rename from Lib/test/pycakey.pem rename to Lib/test/certdata/pycakey.pem diff --git a/Lib/test/revocation.crl b/Lib/test/certdata/revocation.crl similarity index 100% rename from Lib/test/revocation.crl rename to Lib/test/certdata/revocation.crl diff --git a/Lib/test/secp384r1.pem b/Lib/test/certdata/secp384r1.pem similarity index 100% rename from Lib/test/secp384r1.pem rename to Lib/test/certdata/secp384r1.pem diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/certdata/selfsigned_pythontestdotnet.pem similarity index 100% rename from Lib/test/selfsigned_pythontestdotnet.pem rename to Lib/test/certdata/selfsigned_pythontestdotnet.pem diff --git a/Lib/test/ssl_cert.pem b/Lib/test/certdata/ssl_cert.pem similarity index 100% rename from Lib/test/ssl_cert.pem rename to Lib/test/certdata/ssl_cert.pem diff --git a/Lib/test/ssl_key.passwd.pem b/Lib/test/certdata/ssl_key.passwd.pem similarity index 100% rename from Lib/test/ssl_key.passwd.pem rename to Lib/test/certdata/ssl_key.passwd.pem diff --git a/Lib/test/ssl_key.pem b/Lib/test/certdata/ssl_key.pem similarity index 100% rename from Lib/test/ssl_key.pem rename to Lib/test/certdata/ssl_key.pem diff --git a/Lib/test/talos-2019-0758.pem b/Lib/test/certdata/talos-2019-0758.pem similarity index 100% rename from Lib/test/talos-2019-0758.pem rename to Lib/test/certdata/talos-2019-0758.pem diff --git a/Lib/test/ssl_servers.py b/Lib/test/ssl_servers.py index a4bd7455d47e76..15b071e04dda1f 100644 --- a/Lib/test/ssl_servers.py +++ b/Lib/test/ssl_servers.py @@ -14,7 +14,7 @@ here = os.path.dirname(__file__) HOST = socket_helper.HOST -CERTFILE = os.path.join(here, 'keycert.pem') +CERTFILE = os.path.join(here, 'certdata', 'keycert.pem') # This one's based on HTTPServer, which is based on socketserver diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 870f6fcfc02d30..71391dd8603a66 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -42,21 +42,21 @@ CLOCK_RES = 0.020 -def data_file(filename): +def data_file(*filename): if hasattr(support, 'TEST_HOME_DIR'): - fullname = os.path.join(support.TEST_HOME_DIR, filename) + fullname = os.path.join(support.TEST_HOME_DIR, *filename) if os.path.isfile(fullname): return fullname - fullname = os.path.join(os.path.dirname(__file__), '..', filename) + fullname = os.path.join(os.path.dirname(__file__), '..', *filename) if os.path.isfile(fullname): return fullname - raise FileNotFoundError(filename) + raise FileNotFoundError(os.path.join(filename)) -ONLYCERT = data_file('ssl_cert.pem') -ONLYKEY = data_file('ssl_key.pem') -SIGNED_CERTFILE = data_file('keycert3.pem') -SIGNING_CA = data_file('pycacert.pem') +ONLYCERT = data_file('certdata', 'ssl_cert.pem') +ONLYKEY = data_file('certdata', 'ssl_key.pem') +SIGNED_CERTFILE = data_file('certdata', 'keycert3.pem') +SIGNING_CA = data_file('certdata', 'pycacert.pem') PEERCERT = { 'OCSP': ('http://testca.pythontest.net/testca/ocsp/',), 'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',), diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py index 1ca94393d8569f..2f191ea7a44c16 100644 --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -325,8 +325,8 @@ def handle_error(self): if ssl is not None: - CERTFILE = os.path.join(os.path.dirname(__file__), "keycert3.pem") - CAFILE = os.path.join(os.path.dirname(__file__), "pycacert.pem") + CERTFILE = os.path.join(os.path.dirname(__file__), "certdata", "keycert3.pem") + CAFILE = os.path.join(os.path.dirname(__file__), "certdata", "pycacert.pem") class SSLConnection(asyncore.dispatcher): """An asyncore.dispatcher subclass supporting TLS/SSL.""" diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 676725c46ec694..5d5832b62b2f94 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -21,11 +21,13 @@ here = os.path.dirname(__file__) # Self-signed cert file for 'localhost' -CERT_localhost = os.path.join(here, 'keycert.pem') +CERT_localhost = os.path.join(here, 'certdata', 'keycert.pem') # Self-signed cert file for 'fakehostname' -CERT_fakehostname = os.path.join(here, 'keycert2.pem') +CERT_fakehostname = os.path.join(here, 'certdata', 'keycert2.pem') # Self-signed cert file for self-signed.pythontest.net -CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') +CERT_selfsigned_pythontestdotnet = os.path.join( + here, 'certdata', 'selfsigned_pythontestdotnet.pem', +) # constants for testing chunked encoding chunked_start = ( diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 4b38355c37b329..def9f45d63789b 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -23,8 +23,8 @@ support.requires_working_socket(module=True) -CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem") -CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem") +CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "certdata", "keycert3.pem") +CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "certdata", "pycacert.pem") class TestImaplib(unittest.TestCase): diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index b7f4c6edf10614..d2daf93c523f8c 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2170,7 +2170,7 @@ def test_output(self): sslctx = None else: here = os.path.dirname(__file__) - localhost_cert = os.path.join(here, "keycert.pem") + localhost_cert = os.path.join(here, "certdata", "keycert.pem") sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) sslctx.load_cert_chain(localhost_cert) diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py index 31a02f86abb003..30ae557978308c 100644 --- a/Lib/test/test_nntplib.py +++ b/Lib/test/test_nntplib.py @@ -20,7 +20,7 @@ ssl = None -certfile = os.path.join(os.path.dirname(__file__), 'keycert3.pem') +certfile = os.path.join(os.path.dirname(__file__), 'certdata', 'keycert3.pem') if ssl is not None: SSLError = ssl.SSLError diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py index fa41ba0b6e4637..869f9431b928bb 100644 --- a/Lib/test/test_poplib.py +++ b/Lib/test/test_poplib.py @@ -29,8 +29,8 @@ import ssl SUPPORTS_SSL = True - CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem") - CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem") + CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "certdata", "keycert3.pem") + CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "certdata", "pycacert.pem") requires_ssl = skipUnless(SUPPORTS_SSL, 'SSL not supported') diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 2c32fec5104c23..06304dcb4ec7b8 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -60,10 +60,10 @@ PROTOCOL_TO_TLS_VERSION[proto] = ver def data_file(*name): - return os.path.join(os.path.dirname(__file__), *name) + return os.path.join(os.path.dirname(__file__), "certdata", *name) # The custom key and certificate files used in test_ssl are generated -# using Lib/test/make_ssl_certs.py. +# using Lib/test/certdata/make_ssl_certs.py. # Other certificates are simply fetched from the internet servers they # are meant to authenticate. @@ -641,7 +641,7 @@ def test_openssl111_deprecations(self): def bad_cert_test(self, certfile): """Check that trying to use the given client certificate fails""" certfile = os.path.join(os.path.dirname(__file__) or os.curdir, - certfile) + "certdata", certfile) sock = socket.socket() self.addCleanup(sock.close) with self.assertRaises(ssl.SSLError): @@ -3309,12 +3309,12 @@ def test_socketserver(self): # try to connect if support.verbose: sys.stdout.write('\n') - with open(CERTFILE, 'rb') as f: + # Get this test file itself: + with open(__file__, 'rb') as f: d1 = f.read() d2 = '' # now fetch the same data from the HTTPS server - url = 'https://localhost:%d/%s' % ( - server.port, os.path.split(CERTFILE)[1]) + url = f'https://localhost:{server.port}/test_ssl.py' context = ssl.create_default_context(cafile=SIGNING_CA) f = urllib.request.urlopen(url, context=context) try: diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py index f4729358557c95..96e43970d49fb9 100644 --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py @@ -22,9 +22,9 @@ here = os.path.dirname(__file__) # Self-signed cert file for 'localhost' -CERT_localhost = os.path.join(here, 'keycert.pem') +CERT_localhost = os.path.join(here, 'certdata', 'keycert.pem') # Self-signed cert file for 'fakehostname' -CERT_fakehostname = os.path.join(here, 'keycert2.pem') +CERT_fakehostname = os.path.join(here, 'certdata', 'keycert2.pem') # Loopback http server infrastructure diff --git a/Makefile.pre.in b/Makefile.pre.in index f3c2d8bf260de2..aa2ac012affc18 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2117,7 +2117,8 @@ LIBSUBDIRS= asyncio \ TESTSUBDIRS= idlelib/idle_test \ test \ test/audiodata \ - test/capath \ + test/certdata \ + test/certdata/capath \ test/cjkencodings \ test/crashers \ test/data \ From dcd47e506d48d1fa2fd6a2365559e77eecc48ab5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 02:26:48 +0200 Subject: [PATCH 0989/1206] [3.12] gh-110647: Fix signal test_stress_modifying_handlers() (GH-110650) (#110658) gh-110647: Fix signal test_stress_modifying_handlers() (GH-110650) * cycle_handlers() now waits until at least one signal is received. * num_received_signals can be equal to num_sent_signals. (cherry picked from commit e07c37cd5212c9d13749b4d02a1d68e1efcba6cf) Co-authored-by: Victor Stinner --- Lib/test/test_signal.py | 4 ++-- .../next/Tests/2023-10-10-23-20-13.gh-issue-110647.jKG3sY.rst | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-10-23-20-13.gh-issue-110647.jKG3sY.rst diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 2a1a1ee22f43da..f2ae28c38dd72d 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -1339,7 +1339,7 @@ def set_interrupts(): num_sent_signals += 1 def cycle_handlers(): - while num_sent_signals < 100: + while num_sent_signals < 100 or num_received_signals < 1: for i in range(20000): # Cycle between a Python-defined and a non-Python handler for handler in [custom_handler, signal.SIG_IGN]: @@ -1372,7 +1372,7 @@ def cycle_handlers(): if not ignored: # Sanity check that some signals were received, but not all self.assertGreater(num_received_signals, 0) - self.assertLess(num_received_signals, num_sent_signals) + self.assertLessEqual(num_received_signals, num_sent_signals) finally: do_stop = True t.join() diff --git a/Misc/NEWS.d/next/Tests/2023-10-10-23-20-13.gh-issue-110647.jKG3sY.rst b/Misc/NEWS.d/next/Tests/2023-10-10-23-20-13.gh-issue-110647.jKG3sY.rst new file mode 100644 index 00000000000000..00f38c844755ec --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-10-23-20-13.gh-issue-110647.jKG3sY.rst @@ -0,0 +1,2 @@ +Fix test_stress_modifying_handlers() of test_signal. Patch by Victor +Stinner. From 55448a5b14bb8cb345e3702384fea20eefe8b8ae Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 03:31:49 +0200 Subject: [PATCH 0990/1206] [3.12] gh-110656: Fix logging test_post_fork_child_no_deadlock() if ASAN (GH-110657) (#110664) gh-110656: Fix logging test_post_fork_child_no_deadlock() if ASAN (GH-110657) Skip test_post_fork_child_no_deadlock() if Python is built with ASAN. Add support.HAVE_ASAN_FORK_BUG. (cherry picked from commit f901f56313610389027cb4eae80d1d4b071aef69) Co-authored-by: Victor Stinner --- Lib/test/_test_multiprocessing.py | 4 ++-- Lib/test/support/__init__.py | 4 ++++ Lib/test/test_logging.py | 8 ++++++++ Lib/test/test_threading.py | 9 +-------- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 80ebdbfc997bc2..21e5a404f2f4aa 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -78,10 +78,10 @@ msvcrt = None -if support.check_sanitizer(address=True): +if support.HAVE_ASAN_FORK_BUG: # gh-89363: Skip multiprocessing tests if Python is built with ASAN to # work around a libasan race condition: dead lock in pthread_create(). - raise unittest.SkipTest("libasan has a pthread_create() dead lock") + raise unittest.SkipTest("libasan has a pthread_create() dead lock related to thread+fork") def latin(s): diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 22495748ddb097..9d69ade251dcae 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -428,6 +428,10 @@ def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False): skip = check_sanitizer(address=address, memory=memory, ub=ub) return unittest.skipIf(skip, reason) +# gh-89363: True if fork() can hang if Python is built with Address Sanitizer +# (ASAN): libasan race condition, dead lock in pthread_create(). +HAVE_ASAN_FORK_BUG = check_sanitizer(address=True) + def system_must_validate_cert(f): """Skip the test on TLS certificate validation failures.""" diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index d2daf93c523f8c..a2300daff9c735 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -76,6 +76,13 @@ pass +# gh-89363: Skip fork() test if Python is built with Address Sanitizer (ASAN) +# to work around a libasan race condition, dead lock in pthread_create(). +skip_if_asan_fork = unittest.skipIf( + support.HAVE_ASAN_FORK_BUG, + "libasan has a pthread_create() dead lock related to thread+fork") + + class BaseTest(unittest.TestCase): """Base class for logging tests.""" @@ -730,6 +737,7 @@ def remove_loop(fname, tries): # register_at_fork mechanism is also present and used. @support.requires_fork() @threading_helper.requires_working_threading() + @skip_if_asan_fork def test_post_fork_child_no_deadlock(self): """Ensure child logging locks are not held; bpo-6721 & bpo-36533.""" class _OurHandler(logging.Handler): diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 6c486bf84e0de0..f63e5c6184ef0b 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -35,19 +35,12 @@ platforms_to_skip = ('netbsd5', 'hp-ux11') -# gh-89363: Skip fork() test if Python is built with Address Sanitizer (ASAN) -# to work around a libasan race condition, dead lock in pthread_create(). -skip_if_asan_fork = support.skip_if_sanitizer( - "libasan has a pthread_create() dead lock", - address=True) - - def skip_unless_reliable_fork(test): if not support.has_fork_support: return unittest.skip("requires working os.fork()")(test) if sys.platform in platforms_to_skip: return unittest.skip("due to known OS bug related to thread+fork")(test) - if support.check_sanitizer(address=True): + if support.HAVE_ASAN_FORK_BUG: return unittest.skip("libasan has a pthread_create() dead lock related to thread+fork")(test) return test From 18458a527f36b6c00c1f41845eaac3ec4f26c69f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 04:13:01 +0200 Subject: [PATCH 0991/1206] [3.12] gh-110666: Fix multiprocessing test_terminate() elapsed (GH-110667) (#110668) gh-110666: Fix multiprocessing test_terminate() elapsed (GH-110667) multiprocessing test_terminate() and test_wait_socket_slow() no longer test the CI performance: no longer check maximum elapsed time. Add CLOCK_RES constant: tolerate a difference of 100 ms. (cherry picked from commit 1556f426da3f2fb5842689999933c8038b65c034) Co-authored-by: Victor Stinner --- Lib/test/_test_multiprocessing.py | 35 +++++++++++++------------------ 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 21e5a404f2f4aa..4c17088dd029c4 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -84,6 +84,11 @@ raise unittest.SkipTest("libasan has a pthread_create() dead lock related to thread+fork") +# gh-110666: Tolerate a difference of 100 ms when comparing timings +# (clock resolution) +CLOCK_RES = 0.100 + + def latin(s): return s.encode('latin') @@ -1655,8 +1660,7 @@ def _test_waitfor_timeout_f(cls, cond, state, success, sem): dt = time.monotonic() result = cond.wait_for(lambda : state.value==4, timeout=expected) dt = time.monotonic() - dt - # borrow logic in assertTimeout() from test/lock_tests.py - if not result and expected * 0.6 <= dt: + if not result and (expected - CLOCK_RES) <= dt: success.value = True @unittest.skipUnless(HAS_SHAREDCTYPES, 'needs sharedctypes') @@ -2678,14 +2682,11 @@ def test_make_pool(self): p.join() def test_terminate(self): - result = self.pool.map_async( - time.sleep, [0.1 for i in range(10000)], chunksize=1 - ) + # Simulate slow tasks which take "forever" to complete + args = [support.LONG_TIMEOUT for i in range(10_000)] + result = self.pool.map_async(time.sleep, args, chunksize=1) self.pool.terminate() - join = TimingWrapper(self.pool.join) - join() - # Sanity check the pool didn't wait for all tasks to finish - self.assertLess(join.elapsed, 2.0) + self.pool.join() def test_empty_iterable(self): # See Issue 12157 @@ -4870,7 +4871,7 @@ class TestWait(unittest.TestCase): def _child_test_wait(cls, w, slow): for i in range(10): if slow: - time.sleep(random.random()*0.1) + time.sleep(random.random() * 0.100) w.send((i, os.getpid())) w.close() @@ -4910,7 +4911,7 @@ def _child_test_wait_socket(cls, address, slow): s.connect(address) for i in range(10): if slow: - time.sleep(random.random()*0.1) + time.sleep(random.random() * 0.100) s.sendall(('%s\n' % i).encode('ascii')) s.close() @@ -4959,25 +4960,19 @@ def test_wait_socket_slow(self): def test_wait_timeout(self): from multiprocessing.connection import wait - expected = 5 + timeout = 5.0 # seconds a, b = multiprocessing.Pipe() start = time.monotonic() - res = wait([a, b], expected) + res = wait([a, b], timeout) delta = time.monotonic() - start self.assertEqual(res, []) - self.assertLess(delta, expected * 2) - self.assertGreater(delta, expected * 0.5) + self.assertGreater(delta, timeout - CLOCK_RES) b.send(None) - - start = time.monotonic() res = wait([a, b], 20) - delta = time.monotonic() - start - self.assertEqual(res, [a]) - self.assertLess(delta, 0.4) @classmethod def signal_and_sleep(cls, sem, period): From be381b5df5957197d5d534560315e9adcd35aa24 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 05:06:58 +0200 Subject: [PATCH 0992/1206] [3.12] gh-110662: multiprocessing test_async_timeout() increase timeout (GH-110663) (#110674) gh-110662: multiprocessing test_async_timeout() increase timeout (GH-110663) Increase timeout from 1 second to 30 seconds, if not longer. The important part is that apply_async() takes longer than TIMEOUT2. (cherry picked from commit 790ecf6302e47b84da5d1c3b14dbdf070bce615b) Co-authored-by: Victor Stinner --- Lib/test/_test_multiprocessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 4c17088dd029c4..83e9d165c411da 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -2578,7 +2578,7 @@ def test_async(self): self.assertTimingAlmostEqual(get.elapsed, TIMEOUT1) def test_async_timeout(self): - res = self.pool.apply_async(sqr, (6, TIMEOUT2 + 1.0)) + res = self.pool.apply_async(sqr, (6, TIMEOUT2 + support.SHORT_TIMEOUT)) get = TimingWrapper(res.get) self.assertRaises(multiprocessing.TimeoutError, get, timeout=TIMEOUT2) self.assertTimingAlmostEqual(get.elapsed, TIMEOUT2) From 9ffef4d797400de89fa9652fac99a4a171d05aed Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Wed, 11 Oct 2023 05:30:23 +0100 Subject: [PATCH 0993/1206] [3.12] GH-110488: Fix two small issues in `pathlib.PurePath.with_name()` (GH-110651) (#110678) Ensure that `PurePath('foo/a').with_name('.')` raises `ValueError` Ensure that `PureWindowsPath('foo/a').with_name('a:b')` does not raise `ValueError`. (cherry picked from commit b5f7777cb3ecae02d49e0b348968c1ff1ffe21f4) --- Lib/pathlib.py | 3 +-- Lib/test/test_pathlib.py | 14 ++++++++++---- .../2023-10-10-22-54-56.gh-issue-110488.2I7OiZ.rst | 4 ++++ 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-10-22-54-56.gh-issue-110488.2I7OiZ.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 65631b70396315..bd5a096f9e3609 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -630,8 +630,7 @@ def with_name(self, name): if not self.name: raise ValueError("%r has an empty name" % (self,)) f = self._flavour - drv, root, tail = f.splitroot(name) - if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail): + if not name or f.sep in name or (f.altsep and f.altsep in name) or name == '.': raise ValueError("Invalid name %r" % (name)) return self._from_parsed_parts(self.drive, self.root, self._tail[:-1] + [name]) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 012dacf10ea805..ec105ae1a069bd 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -546,6 +546,7 @@ def test_with_name_common(self): self.assertRaises(ValueError, P('.').with_name, 'd.xml') self.assertRaises(ValueError, P('/').with_name, 'd.xml') self.assertRaises(ValueError, P('a/b').with_name, '') + self.assertRaises(ValueError, P('a/b').with_name, '.') self.assertRaises(ValueError, P('a/b').with_name, '/c') self.assertRaises(ValueError, P('a/b').with_name, 'c/') self.assertRaises(ValueError, P('a/b').with_name, 'c/d') @@ -563,6 +564,7 @@ def test_with_stem_common(self): self.assertRaises(ValueError, P('.').with_stem, 'd') self.assertRaises(ValueError, P('/').with_stem, 'd') self.assertRaises(ValueError, P('a/b').with_stem, '') + self.assertRaises(ValueError, P('a/b').with_stem, '.') self.assertRaises(ValueError, P('a/b').with_stem, '/c') self.assertRaises(ValueError, P('a/b').with_stem, 'c/') self.assertRaises(ValueError, P('a/b').with_stem, 'c/d') @@ -1167,8 +1169,10 @@ def test_with_name(self): self.assertRaises(ValueError, P('c:').with_name, 'd.xml') self.assertRaises(ValueError, P('c:/').with_name, 'd.xml') self.assertRaises(ValueError, P('//My/Share').with_name, 'd.xml') - self.assertRaises(ValueError, P('c:a/b').with_name, 'd:') - self.assertRaises(ValueError, P('c:a/b').with_name, 'd:e') + self.assertEqual(str(P('a').with_name('d:')), '.\\d:') + self.assertEqual(str(P('a').with_name('d:e')), '.\\d:e') + self.assertEqual(P('c:a/b').with_name('d:'), P('c:a/d:')) + self.assertEqual(P('c:a/b').with_name('d:e'), P('c:a/d:e')) self.assertRaises(ValueError, P('c:a/b').with_name, 'd:/e') self.assertRaises(ValueError, P('c:a/b').with_name, '//My/Share') @@ -1181,8 +1185,10 @@ def test_with_stem(self): self.assertRaises(ValueError, P('c:').with_stem, 'd') self.assertRaises(ValueError, P('c:/').with_stem, 'd') self.assertRaises(ValueError, P('//My/Share').with_stem, 'd') - self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:') - self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:e') + self.assertEqual(str(P('a').with_stem('d:')), '.\\d:') + self.assertEqual(str(P('a').with_stem('d:e')), '.\\d:e') + self.assertEqual(P('c:a/b').with_stem('d:'), P('c:a/d:')) + self.assertEqual(P('c:a/b').with_stem('d:e'), P('c:a/d:e')) self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:/e') self.assertRaises(ValueError, P('c:a/b').with_stem, '//My/Share') diff --git a/Misc/NEWS.d/next/Library/2023-10-10-22-54-56.gh-issue-110488.2I7OiZ.rst b/Misc/NEWS.d/next/Library/2023-10-10-22-54-56.gh-issue-110488.2I7OiZ.rst new file mode 100644 index 00000000000000..aec9120d72e358 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-10-22-54-56.gh-issue-110488.2I7OiZ.rst @@ -0,0 +1,4 @@ +Fix a couple of issues in :meth:`pathlib.PurePath.with_name`: a single dot +was incorrectly considered a valid name, and in :class:`PureWindowsPath`, a +name with an NTFS alternate data stream, like ``a:b``, was incorrectly +considered invalid. From ca971d12eda3abdd6357e68b014a81db645da05a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 10:12:39 +0200 Subject: [PATCH 0994/1206] [3.12] gh-84489: C API: Add tests for Py_BuildValue() (GH-110596) (GH-110680) (cherry picked from commit 5c6e85480ad8365c1b05fdbd678c7867103f7d76) Co-authored-by: Serhiy Storchaka --- Lib/test/test_capi/test_misc.py | 80 +++++++++++++++++++++++++++++++++ Modules/_testcapimodule.c | 37 +++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 66d5ebed66d670..cf714e63cf95a5 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -298,6 +298,86 @@ def test_getitem_with_error(self): # test _Py_CheckFunctionResult() instead. self.assertIn('returned a result with an exception set', err) + def test_buildvalue(self): + # Test Py_BuildValue() with object arguments + buildvalue = _testcapi.py_buildvalue + self.assertEqual(buildvalue(''), None) + self.assertEqual(buildvalue('()'), ()) + self.assertEqual(buildvalue('[]'), []) + self.assertEqual(buildvalue('{}'), {}) + self.assertEqual(buildvalue('()[]{}'), ((), [], {})) + self.assertEqual(buildvalue('O', 1), 1) + self.assertEqual(buildvalue('(O)', 1), (1,)) + self.assertEqual(buildvalue('[O]', 1), [1]) + self.assertRaises(SystemError, buildvalue, '{O}', 1) + self.assertEqual(buildvalue('OO', 1, 2), (1, 2)) + self.assertEqual(buildvalue('(OO)', 1, 2), (1, 2)) + self.assertEqual(buildvalue('[OO]', 1, 2), [1, 2]) + self.assertEqual(buildvalue('{OO}', 1, 2), {1: 2}) + self.assertEqual(buildvalue('{OOOO}', 1, 2, 3, 4), {1: 2, 3: 4}) + self.assertEqual(buildvalue('((O))', 1), ((1,),)) + self.assertEqual(buildvalue('((OO))', 1, 2), ((1, 2),)) + + self.assertEqual(buildvalue(' \t,:'), None) + self.assertEqual(buildvalue(' O ', 1), 1) + self.assertEqual(buildvalue('\tO\t', 1), 1) + self.assertEqual(buildvalue('O,O', 1, 2), (1, 2)) + self.assertEqual(buildvalue('O, O', 1, 2), (1, 2)) + self.assertEqual(buildvalue('O,\tO', 1, 2), (1, 2)) + self.assertEqual(buildvalue('O O', 1, 2), (1, 2)) + self.assertEqual(buildvalue('O\tO', 1, 2), (1, 2)) + self.assertEqual(buildvalue('(O,O)', 1, 2), (1, 2)) + self.assertEqual(buildvalue('(O, O)', 1, 2), (1, 2)) + self.assertEqual(buildvalue(' ( O O) ', 1, 2), (1, 2)) + self.assertEqual(buildvalue('\t(\tO\tO)\t', 1, 2), (1, 2)) + self.assertEqual(buildvalue('[O,O]', 1, 2), [1, 2]) + self.assertEqual(buildvalue('[O, O]', 1, 2), [1, 2]) + self.assertEqual(buildvalue(' [ O O] ', 1, 2), [1, 2]) + self.assertEqual(buildvalue('{O:O}', 1, 2), {1: 2}) + self.assertEqual(buildvalue('{O:O,O:O}', 1, 2, 3, 4), {1: 2, 3: 4}) + self.assertEqual(buildvalue('{O: O, O: O}', 1, 2, 3, 4), {1: 2, 3: 4}) + self.assertEqual(buildvalue(' { O O O O} ', 1, 2, 3, 4), {1: 2, 3: 4}) + self.assertEqual(buildvalue('\t{\tO\tO\tO\tO}\t', 1, 2, 3, 4), {1: 2, 3: 4}) + + self.assertRaises(SystemError, buildvalue, 'O', NULL) + self.assertRaises(SystemError, buildvalue, '(O)', NULL) + self.assertRaises(SystemError, buildvalue, '[O]', NULL) + self.assertRaises(SystemError, buildvalue, '{O}', NULL) + self.assertRaises(SystemError, buildvalue, 'OO', 1, NULL) + self.assertRaises(SystemError, buildvalue, 'OO', NULL, 2) + self.assertRaises(SystemError, buildvalue, '(OO)', 1, NULL) + self.assertRaises(SystemError, buildvalue, '(OO)', NULL, 2) + self.assertRaises(SystemError, buildvalue, '[OO]', 1, NULL) + self.assertRaises(SystemError, buildvalue, '[OO]', NULL, 2) + self.assertRaises(SystemError, buildvalue, '{OO}', 1, NULL) + self.assertRaises(SystemError, buildvalue, '{OO}', NULL, 2) + + def test_buildvalue_ints(self): + # Test Py_BuildValue() with integer arguments + buildvalue = _testcapi.py_buildvalue_ints + from _testcapi import SHRT_MIN, SHRT_MAX, USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX + self.assertEqual(buildvalue('i', INT_MAX), INT_MAX) + self.assertEqual(buildvalue('i', INT_MIN), INT_MIN) + self.assertEqual(buildvalue('I', UINT_MAX), UINT_MAX) + + self.assertEqual(buildvalue('h', SHRT_MAX), SHRT_MAX) + self.assertEqual(buildvalue('h', SHRT_MIN), SHRT_MIN) + self.assertEqual(buildvalue('H', USHRT_MAX), USHRT_MAX) + + self.assertEqual(buildvalue('b', 127), 127) + self.assertEqual(buildvalue('b', -128), -128) + self.assertEqual(buildvalue('B', 255), 255) + + self.assertEqual(buildvalue('c', ord('A')), b'A') + self.assertEqual(buildvalue('c', 255), b'\xff') + self.assertEqual(buildvalue('c', 256), b'\x00') + self.assertEqual(buildvalue('c', -1), b'\xff') + + self.assertEqual(buildvalue('C', 255), chr(255)) + self.assertEqual(buildvalue('C', 256), chr(256)) + self.assertEqual(buildvalue('C', sys.maxunicode), chr(sys.maxunicode)) + self.assertRaises(ValueError, buildvalue, 'C', -1) + self.assertRaises(ValueError, buildvalue, 'C', sys.maxunicode+1) def test_buildvalue_N(self): _testcapi.test_buildvalue_N() diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 805a20733cdbfb..fd48984a7c45e7 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -423,6 +423,41 @@ raise_error(void *unused) return NULL; } +static PyObject * +py_buildvalue(PyObject *self, PyObject *args) +{ + const char *fmt; + PyObject *objs[10] = {NULL}; + if (!PyArg_ParseTuple(args, "s|OOOOOOOOOO", &fmt, + &objs[0], &objs[1], &objs[2], &objs[3], &objs[4], + &objs[5], &objs[6], &objs[7], &objs[8], &objs[9])) + { + return NULL; + } + for(int i = 0; i < 10; i++) { + NULLABLE(objs[i]); + } + return Py_BuildValue(fmt, + objs[0], objs[1], objs[2], objs[3], objs[4], + objs[5], objs[6], objs[7], objs[8], objs[9]); +} + +static PyObject * +py_buildvalue_ints(PyObject *self, PyObject *args) +{ + const char *fmt; + unsigned int values[10] = {0}; + if (!PyArg_ParseTuple(args, "s|IIIIIIIIII", &fmt, + &values[0], &values[1], &values[2], &values[3], &values[4], + &values[5], &values[6], &values[7], &values[8], &values[9])) + { + return NULL; + } + return Py_BuildValue(fmt, + values[0], values[1], values[2], values[3], values[4], + values[5], values[6], values[7], values[8], values[9]); +} + static int test_buildvalue_N_error(const char *fmt) { @@ -3267,6 +3302,8 @@ static PyMethodDef TestMethods[] = { #endif {"getbuffer_with_null_view", getbuffer_with_null_view, METH_O}, {"PyBuffer_SizeFromFormat", test_PyBuffer_SizeFromFormat, METH_VARARGS}, + {"py_buildvalue", py_buildvalue, METH_VARARGS}, + {"py_buildvalue_ints", py_buildvalue_ints, METH_VARARGS}, {"test_buildvalue_N", test_buildvalue_N, METH_NOARGS}, {"test_buildvalue_issue38913", test_buildvalue_issue38913, METH_NOARGS}, {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, From 1ea4cb1a66ee79a13eef4712159d41542d1218f4 Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Wed, 11 Oct 2023 11:53:17 +0200 Subject: [PATCH 0995/1206] [3.12] gh-110631: fix wrong indentation in the `Doc/whatsnew` dir (GH-110632) (#110690) fix wrong indentation in the `Doc/whatsnew` dir (#110632) --- Doc/whatsnew/2.6.rst | 20 ++--- Doc/whatsnew/2.7.rst | 2 +- Doc/whatsnew/3.10.rst | 200 +++++++++++++++++++++--------------------- Doc/whatsnew/3.12.rst | 18 ++-- Doc/whatsnew/3.3.rst | 128 +++++++++++++-------------- Doc/whatsnew/3.7.rst | 14 +-- 6 files changed, 191 insertions(+), 191 deletions(-) diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 96d9b792b3723a..759a0757ebefa7 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -875,11 +875,11 @@ The signature of the new function is:: The parameters are: - * *args*: positional arguments whose values will be printed out. - * *sep*: the separator, which will be printed between arguments. - * *end*: the ending text, which will be printed after all of the - arguments have been output. - * *file*: the file object to which the output will be sent. +* *args*: positional arguments whose values will be printed out. +* *sep*: the separator, which will be printed between arguments. +* *end*: the ending text, which will be printed after all of the + arguments have been output. +* *file*: the file object to which the output will be sent. .. seealso:: @@ -1138,13 +1138,13 @@ indicate that the external caller is done. The *flags* argument to :c:func:`PyObject_GetBuffer` specifies constraints upon the memory returned. Some examples are: - * :c:macro:`PyBUF_WRITABLE` indicates that the memory must be writable. +* :c:macro:`PyBUF_WRITABLE` indicates that the memory must be writable. - * :c:macro:`PyBUF_LOCK` requests a read-only or exclusive lock on the memory. +* :c:macro:`PyBUF_LOCK` requests a read-only or exclusive lock on the memory. - * :c:macro:`PyBUF_C_CONTIGUOUS` and :c:macro:`PyBUF_F_CONTIGUOUS` - requests a C-contiguous (last dimension varies the fastest) or - Fortran-contiguous (first dimension varies the fastest) array layout. +* :c:macro:`PyBUF_C_CONTIGUOUS` and :c:macro:`PyBUF_F_CONTIGUOUS` + requests a C-contiguous (last dimension varies the fastest) or + Fortran-contiguous (first dimension varies the fastest) array layout. Two new argument codes for :c:func:`PyArg_ParseTuple`, ``s*`` and ``z*``, return locked buffer objects for a parameter. diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index eda6c8be38ad08..7c81cc17f5c7d3 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2368,7 +2368,7 @@ Port-Specific Changes: Mac OS X installation and a user-installed copy of the same version. (Changed by Ronald Oussoren; :issue:`4865`.) - .. versionchanged:: 2.7.13 + .. versionchanged:: 2.7.13 As of 2.7.13, this change was removed. ``/Library/Python/2.7/site-packages``, the site-packages directory diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 42e54fbad2092f..e233db7e63d0a9 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -221,116 +221,116 @@ have been incorporated. Some of the most notable ones are as follows: * Missing ``:`` before blocks: - .. code-block:: python + .. code-block:: python - >>> if rocket.position > event_horizon - File "", line 1 - if rocket.position > event_horizon - ^ - SyntaxError: expected ':' + >>> if rocket.position > event_horizon + File "", line 1 + if rocket.position > event_horizon + ^ + SyntaxError: expected ':' - (Contributed by Pablo Galindo in :issue:`42997`.) + (Contributed by Pablo Galindo in :issue:`42997`.) * Unparenthesised tuples in comprehensions targets: - .. code-block:: python + .. code-block:: python - >>> {x,y for x,y in zip('abcd', '1234')} - File "", line 1 - {x,y for x,y in zip('abcd', '1234')} - ^ - SyntaxError: did you forget parentheses around the comprehension target? + >>> {x,y for x,y in zip('abcd', '1234')} + File "", line 1 + {x,y for x,y in zip('abcd', '1234')} + ^ + SyntaxError: did you forget parentheses around the comprehension target? - (Contributed by Pablo Galindo in :issue:`43017`.) + (Contributed by Pablo Galindo in :issue:`43017`.) * Missing commas in collection literals and between expressions: - .. code-block:: python + .. code-block:: python - >>> items = { - ... x: 1, - ... y: 2 - ... z: 3, - File "", line 3 - y: 2 - ^ - SyntaxError: invalid syntax. Perhaps you forgot a comma? + >>> items = { + ... x: 1, + ... y: 2 + ... z: 3, + File "", line 3 + y: 2 + ^ + SyntaxError: invalid syntax. Perhaps you forgot a comma? - (Contributed by Pablo Galindo in :issue:`43822`.) + (Contributed by Pablo Galindo in :issue:`43822`.) * Multiple Exception types without parentheses: - .. code-block:: python + .. code-block:: python - >>> try: - ... build_dyson_sphere() - ... except NotEnoughScienceError, NotEnoughResourcesError: - File "", line 3 - except NotEnoughScienceError, NotEnoughResourcesError: - ^ - SyntaxError: multiple exception types must be parenthesized + >>> try: + ... build_dyson_sphere() + ... except NotEnoughScienceError, NotEnoughResourcesError: + File "", line 3 + except NotEnoughScienceError, NotEnoughResourcesError: + ^ + SyntaxError: multiple exception types must be parenthesized - (Contributed by Pablo Galindo in :issue:`43149`.) + (Contributed by Pablo Galindo in :issue:`43149`.) * Missing ``:`` and values in dictionary literals: - .. code-block:: python + .. code-block:: python - >>> values = { - ... x: 1, - ... y: 2, - ... z: - ... } - File "", line 4 - z: - ^ - SyntaxError: expression expected after dictionary key and ':' + >>> values = { + ... x: 1, + ... y: 2, + ... z: + ... } + File "", line 4 + z: + ^ + SyntaxError: expression expected after dictionary key and ':' - >>> values = {x:1, y:2, z w:3} - File "", line 1 - values = {x:1, y:2, z w:3} - ^ - SyntaxError: ':' expected after dictionary key + >>> values = {x:1, y:2, z w:3} + File "", line 1 + values = {x:1, y:2, z w:3} + ^ + SyntaxError: ':' expected after dictionary key - (Contributed by Pablo Galindo in :issue:`43823`.) + (Contributed by Pablo Galindo in :issue:`43823`.) * ``try`` blocks without ``except`` or ``finally`` blocks: - .. code-block:: python + .. code-block:: python - >>> try: - ... x = 2 - ... something = 3 - File "", line 3 - something = 3 - ^^^^^^^^^ - SyntaxError: expected 'except' or 'finally' block + >>> try: + ... x = 2 + ... something = 3 + File "", line 3 + something = 3 + ^^^^^^^^^ + SyntaxError: expected 'except' or 'finally' block - (Contributed by Pablo Galindo in :issue:`44305`.) + (Contributed by Pablo Galindo in :issue:`44305`.) * Usage of ``=`` instead of ``==`` in comparisons: - .. code-block:: python + .. code-block:: python - >>> if rocket.position = event_horizon: - File "", line 1 - if rocket.position = event_horizon: - ^ - SyntaxError: cannot assign to attribute here. Maybe you meant '==' instead of '='? + >>> if rocket.position = event_horizon: + File "", line 1 + if rocket.position = event_horizon: + ^ + SyntaxError: cannot assign to attribute here. Maybe you meant '==' instead of '='? - (Contributed by Pablo Galindo in :issue:`43797`.) + (Contributed by Pablo Galindo in :issue:`43797`.) * Usage of ``*`` in f-strings: - .. code-block:: python + .. code-block:: python - >>> f"Black holes {*all_black_holes} and revelations" - File "", line 1 - (*all_black_holes) - ^ - SyntaxError: f-string: cannot use starred expression here + >>> f"Black holes {*all_black_holes} and revelations" + File "", line 1 + (*all_black_holes) + ^ + SyntaxError: f-string: cannot use starred expression here - (Contributed by Pablo Galindo in :issue:`41064`.) + (Contributed by Pablo Galindo in :issue:`41064`.) IndentationErrors ~~~~~~~~~~~~~~~~~ @@ -365,10 +365,10 @@ raised from: (Contributed by Pablo Galindo in :issue:`38530`.) - .. warning:: - Notice this won't work if :c:func:`PyErr_Display` is not called to display the error - which can happen if some other custom error display function is used. This is a common - scenario in some REPLs like IPython. +.. warning:: + Notice this won't work if :c:func:`PyErr_Display` is not called to display the error + which can happen if some other custom error display function is used. This is a common + scenario in some REPLs like IPython. NameErrors ~~~~~~~~~~ @@ -387,10 +387,10 @@ was raised from: (Contributed by Pablo Galindo in :issue:`38530`.) - .. warning:: - Notice this won't work if :c:func:`PyErr_Display` is not called to display the error, - which can happen if some other custom error display function is used. This is a common - scenario in some REPLs like IPython. +.. warning:: + Notice this won't work if :c:func:`PyErr_Display` is not called to display the error, + which can happen if some other custom error display function is used. This is a common + scenario in some REPLs like IPython. PEP 626: Precise line numbers for debugging and other tools @@ -433,16 +433,16 @@ A match statement takes an expression and compares its value to successive patterns given as one or more case blocks. Specifically, pattern matching operates by: - 1. using data with type and shape (the ``subject``) - 2. evaluating the ``subject`` in the ``match`` statement - 3. comparing the subject with each pattern in a ``case`` statement - from top to bottom until a match is confirmed. - 4. executing the action associated with the pattern of the confirmed - match - 5. If an exact match is not confirmed, the last case, a wildcard ``_``, - if provided, will be used as the matching case. If an exact match is - not confirmed and a wildcard case does not exist, the entire match - block is a no-op. +1. using data with type and shape (the ``subject``) +2. evaluating the ``subject`` in the ``match`` statement +3. comparing the subject with each pattern in a ``case`` statement + from top to bottom until a match is confirmed. +4. executing the action associated with the pattern of the confirmed + match +5. If an exact match is not confirmed, the last case, a wildcard ``_``, + if provided, will be used as the matching case. If an exact match is + not confirmed and a wildcard case does not exist, the entire match + block is a no-op. Declarative approach ~~~~~~~~~~~~~~~~~~~~ @@ -2211,16 +2211,16 @@ Removed * Removed ``Py_UNICODE_str*`` functions manipulating ``Py_UNICODE*`` strings. (Contributed by Inada Naoki in :issue:`41123`.) - * ``Py_UNICODE_strlen``: use :c:func:`PyUnicode_GetLength` or - :c:macro:`PyUnicode_GET_LENGTH` - * ``Py_UNICODE_strcat``: use :c:func:`PyUnicode_CopyCharacters` or - :c:func:`PyUnicode_FromFormat` - * ``Py_UNICODE_strcpy``, ``Py_UNICODE_strncpy``: use - :c:func:`PyUnicode_CopyCharacters` or :c:func:`PyUnicode_Substring` - * ``Py_UNICODE_strcmp``: use :c:func:`PyUnicode_Compare` - * ``Py_UNICODE_strncmp``: use :c:func:`PyUnicode_Tailmatch` - * ``Py_UNICODE_strchr``, ``Py_UNICODE_strrchr``: use - :c:func:`PyUnicode_FindChar` + * ``Py_UNICODE_strlen``: use :c:func:`PyUnicode_GetLength` or + :c:macro:`PyUnicode_GET_LENGTH` + * ``Py_UNICODE_strcat``: use :c:func:`PyUnicode_CopyCharacters` or + :c:func:`PyUnicode_FromFormat` + * ``Py_UNICODE_strcpy``, ``Py_UNICODE_strncpy``: use + :c:func:`PyUnicode_CopyCharacters` or :c:func:`PyUnicode_Substring` + * ``Py_UNICODE_strcmp``: use :c:func:`PyUnicode_Compare` + * ``Py_UNICODE_strncmp``: use :c:func:`PyUnicode_Tailmatch` + * ``Py_UNICODE_strchr``, ``Py_UNICODE_strrchr``: use + :c:func:`PyUnicode_FindChar` * Removed ``PyUnicode_GetMax()``. Please migrate to new (:pep:`393`) APIs. (Contributed by Inada Naoki in :issue:`41103`.) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 9080908c5c96c0..18fca00c9d5a7b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -2399,15 +2399,15 @@ Removed * Legacy Unicode APIs have been removed. See :pep:`623` for detail. - * :c:macro:`!PyUnicode_WCHAR_KIND` - * :c:func:`!PyUnicode_AS_UNICODE` - * :c:func:`!PyUnicode_AsUnicode` - * :c:func:`!PyUnicode_AsUnicodeAndSize` - * :c:func:`!PyUnicode_AS_DATA` - * :c:func:`!PyUnicode_FromUnicode` - * :c:func:`!PyUnicode_GET_SIZE` - * :c:func:`!PyUnicode_GetSize` - * :c:func:`!PyUnicode_GET_DATA_SIZE` + * :c:macro:`!PyUnicode_WCHAR_KIND` + * :c:func:`!PyUnicode_AS_UNICODE` + * :c:func:`!PyUnicode_AsUnicode` + * :c:func:`!PyUnicode_AsUnicodeAndSize` + * :c:func:`!PyUnicode_AS_DATA` + * :c:func:`!PyUnicode_FromUnicode` + * :c:func:`!PyUnicode_GET_SIZE` + * :c:func:`!PyUnicode_GetSize` + * :c:func:`!PyUnicode_GET_DATA_SIZE` * Remove the ``PyUnicode_InternImmortal()`` function macro. (Contributed by Victor Stinner in :gh:`85858`.) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 3361789ff6f35a..ed267f57276a23 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -917,12 +917,12 @@ abstract methods. The recommended approach to declaring abstract descriptors is now to provide :attr:`__isabstractmethod__` as a dynamically updated property. The built-in descriptors have been updated accordingly. - * :class:`abc.abstractproperty` has been deprecated, use :class:`property` - with :func:`abc.abstractmethod` instead. - * :class:`abc.abstractclassmethod` has been deprecated, use - :class:`classmethod` with :func:`abc.abstractmethod` instead. - * :class:`abc.abstractstaticmethod` has been deprecated, use - :class:`staticmethod` with :func:`abc.abstractmethod` instead. +* :class:`abc.abstractproperty` has been deprecated, use :class:`property` + with :func:`abc.abstractmethod` instead. +* :class:`abc.abstractclassmethod` has been deprecated, use + :class:`classmethod` with :func:`abc.abstractmethod` instead. +* :class:`abc.abstractstaticmethod` has been deprecated, use + :class:`staticmethod` with :func:`abc.abstractmethod` instead. (Contributed by Darren Dale in :issue:`11610`.) @@ -1060,32 +1060,32 @@ function to the :mod:`crypt` module. curses ------ - * If the :mod:`curses` module is linked to the ncursesw library, use Unicode - functions when Unicode strings or characters are passed (e.g. - :c:func:`waddwstr`), and bytes functions otherwise (e.g. :c:func:`waddstr`). - * Use the locale encoding instead of ``utf-8`` to encode Unicode strings. - * :class:`curses.window` has a new :attr:`curses.window.encoding` attribute. - * The :class:`curses.window` class has a new :meth:`~curses.window.get_wch` - method to get a wide character - * The :mod:`curses` module has a new :meth:`~curses.unget_wch` function to - push a wide character so the next :meth:`~curses.window.get_wch` will return - it +* If the :mod:`curses` module is linked to the ncursesw library, use Unicode + functions when Unicode strings or characters are passed (e.g. + :c:func:`waddwstr`), and bytes functions otherwise (e.g. :c:func:`waddstr`). +* Use the locale encoding instead of ``utf-8`` to encode Unicode strings. +* :class:`curses.window` has a new :attr:`curses.window.encoding` attribute. +* The :class:`curses.window` class has a new :meth:`~curses.window.get_wch` + method to get a wide character +* The :mod:`curses` module has a new :meth:`~curses.unget_wch` function to + push a wide character so the next :meth:`~curses.window.get_wch` will return + it (Contributed by Iñigo Serna in :issue:`6755`.) datetime -------- - * Equality comparisons between naive and aware :class:`~datetime.datetime` - instances now return :const:`False` instead of raising :exc:`TypeError` - (:issue:`15006`). - * New :meth:`datetime.datetime.timestamp` method: Return POSIX timestamp - corresponding to the :class:`~datetime.datetime` instance. - * The :meth:`datetime.datetime.strftime` method supports formatting years - older than 1000. - * The :meth:`datetime.datetime.astimezone` method can now be - called without arguments to convert datetime instance to the system - timezone. +* Equality comparisons between naive and aware :class:`~datetime.datetime` + instances now return :const:`False` instead of raising :exc:`TypeError` + (:issue:`15006`). +* New :meth:`datetime.datetime.timestamp` method: Return POSIX timestamp + corresponding to the :class:`~datetime.datetime` instance. +* The :meth:`datetime.datetime.strftime` method supports formatting years + older than 1000. +* The :meth:`datetime.datetime.astimezone` method can now be + called without arguments to convert datetime instance to the system + timezone. .. _new-decimal: @@ -1210,25 +1210,25 @@ the ``Message`` object it is serializing. The default policy is The minimum set of controls implemented by all ``policy`` objects are: - .. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L| - =============== ======================================================= - max_line_length The maximum length, excluding the linesep character(s), - individual lines may have when a ``Message`` is - serialized. Defaults to 78. +=============== ======================================================= +max_line_length The maximum length, excluding the linesep character(s), + individual lines may have when a ``Message`` is + serialized. Defaults to 78. - linesep The character used to separate individual lines when a - ``Message`` is serialized. Defaults to ``\n``. +linesep The character used to separate individual lines when a + ``Message`` is serialized. Defaults to ``\n``. - cte_type ``7bit`` or ``8bit``. ``8bit`` applies only to a - ``Bytes`` ``generator``, and means that non-ASCII may - be used where allowed by the protocol (or where it - exists in the original input). +cte_type ``7bit`` or ``8bit``. ``8bit`` applies only to a + ``Bytes`` ``generator``, and means that non-ASCII may + be used where allowed by the protocol (or where it + exists in the original input). - raise_on_defect Causes a ``parser`` to raise error when defects are - encountered instead of adding them to the ``Message`` - object's ``defects`` list. - =============== ======================================================= +raise_on_defect Causes a ``parser`` to raise error when defects are + encountered instead of adding them to the ``Message`` + object's ``defects`` list. +=============== ======================================================= A new policy instance, with new settings, is created using the :meth:`~email.policy.Policy.clone` method of policy objects. ``clone`` takes @@ -1263,21 +1263,21 @@ removal of the code) may occur if deemed necessary by the core developers. The new policies are instances of :class:`~email.policy.EmailPolicy`, and add the following additional controls: - .. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L| - =============== ======================================================= - refold_source Controls whether or not headers parsed by a - :mod:`~email.parser` are refolded by the - :mod:`~email.generator`. It can be ``none``, ``long``, - or ``all``. The default is ``long``, which means that - source headers with a line longer than - ``max_line_length`` get refolded. ``none`` means no - line get refolded, and ``all`` means that all lines - get refolded. +=============== ======================================================= +refold_source Controls whether or not headers parsed by a + :mod:`~email.parser` are refolded by the + :mod:`~email.generator`. It can be ``none``, ``long``, + or ``all``. The default is ``long``, which means that + source headers with a line longer than + ``max_line_length`` get refolded. ``none`` means no + line get refolded, and ``all`` means that all lines + get refolded. - header_factory A callable that take a ``name`` and ``value`` and - produces a custom header object. - =============== ======================================================= +header_factory A callable that take a ``name`` and ``value`` and + produces a custom header object. +=============== ======================================================= The ``header_factory`` is the key to the new features provided by the new policies. When one of the new policies is used, any header retrieved from @@ -1352,18 +1352,18 @@ API. New utility functions: - * :func:`~email.utils.format_datetime`: given a :class:`~datetime.datetime`, - produce a string formatted for use in an email header. +* :func:`~email.utils.format_datetime`: given a :class:`~datetime.datetime`, + produce a string formatted for use in an email header. - * :func:`~email.utils.parsedate_to_datetime`: given a date string from - an email header, convert it into an aware :class:`~datetime.datetime`, - or a naive :class:`~datetime.datetime` if the offset is ``-0000``. +* :func:`~email.utils.parsedate_to_datetime`: given a date string from + an email header, convert it into an aware :class:`~datetime.datetime`, + or a naive :class:`~datetime.datetime` if the offset is ``-0000``. - * :func:`~email.utils.localtime`: With no argument, returns the - current local time as an aware :class:`~datetime.datetime` using the local - :class:`~datetime.timezone`. Given an aware :class:`~datetime.datetime`, - converts it into an aware :class:`~datetime.datetime` using the - local :class:`~datetime.timezone`. +* :func:`~email.utils.localtime`: With no argument, returns the + current local time as an aware :class:`~datetime.datetime` using the local + :class:`~datetime.timezone`. Given an aware :class:`~datetime.datetime`, + converts it into an aware :class:`~datetime.datetime` using the + local :class:`~datetime.timezone`. ftplib diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index e82bb756b8485c..4ed53d04e1a916 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -1580,13 +1580,13 @@ The initialization of the default warnings filters has changed as follows: * warnings filters enabled via the command line or the environment now have the following order of precedence: - * the ``BytesWarning`` filter for :option:`-b` (or ``-bb``) - * any filters specified with the :option:`-W` option - * any filters specified with the :envvar:`PYTHONWARNINGS` environment - variable - * any other CPython specific filters (e.g. the ``default`` filter added - for the new ``-X dev`` mode) - * any implicit filters defined directly by the warnings machinery + * the ``BytesWarning`` filter for :option:`-b` (or ``-bb``) + * any filters specified with the :option:`-W` option + * any filters specified with the :envvar:`PYTHONWARNINGS` environment + variable + * any other CPython specific filters (e.g. the ``default`` filter added + for the new ``-X dev`` mode) + * any implicit filters defined directly by the warnings machinery * in :ref:`CPython debug builds `, all warnings are now displayed by default (the implicit filter list is empty) From bfb1f00926b4aa524c0028e440a3e9e2ef2fc5ad Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:15:44 +0200 Subject: [PATCH 0996/1206] [3.12] gh-76106: Remove the cleanup lock in test_socket (GH-110539) (GH-110699) It does not already work (because it locks only addCleanup(), not doCleanups()), and it is no longer needed since the clean up procedure waits for all test threads to join. (cherry picked from commit f27b83090701b9c215e0d65f1f924fb9330cb649) Co-authored-by: Serhiy Storchaka --- Lib/test/test_socket.py | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 0d1c1867a25c40..86701caf05399e 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -215,26 +215,6 @@ def setUp(self): self.serv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDPLITE) self.port = socket_helper.bind_port(self.serv) -class ThreadSafeCleanupTestCase: - """Subclass of unittest.TestCase with thread-safe cleanup methods. - - This subclass protects the addCleanup() method with a recursive lock. - - doCleanups() is called when the server completed, but the client can still - be running in its thread especially if the server failed with a timeout. - Don't put a lock on doCleanups() to prevent deadlock between addCleanup() - called in the client and doCleanups() waiting for self.done.wait of - ThreadableTest._setUp() (gh-110167) - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._cleanup_lock = threading.RLock() - - def addCleanup(self, *args, **kwargs): - with self._cleanup_lock: - return super().addCleanup(*args, **kwargs) - class SocketCANTest(unittest.TestCase): @@ -628,8 +608,7 @@ def setUp(self): self.serv.listen() -class ThreadedSocketTestMixin(ThreadSafeCleanupTestCase, SocketTestBase, - ThreadableTest): +class ThreadedSocketTestMixin(SocketTestBase, ThreadableTest): """Mixin to add client socket and allow client/server tests. Client socket is self.cli and its address is self.cli_addr. See @@ -2815,7 +2794,7 @@ def _testRecvFromNegative(self): # here assumes that datagram delivery on the local machine will be # reliable. -class SendrecvmsgBase(ThreadSafeCleanupTestCase): +class SendrecvmsgBase: # Base class for sendmsg()/recvmsg() tests. # Time in seconds to wait before considering a test failed, or @@ -4681,7 +4660,6 @@ def testInterruptedRecvmsgIntoTimeout(self): @unittest.skipUnless(hasattr(signal, "alarm") or hasattr(signal, "setitimer"), "Don't have signal.alarm or signal.setitimer") class InterruptedSendTimeoutTest(InterruptedTimeoutBase, - ThreadSafeCleanupTestCase, SocketListeningTestMixin, TCPTestBase): # Test interrupting the interruptible send*() methods with signals # when a timeout is set. From c06ac1b4cc76b78fa24058cbc82aa7be50ba4a69 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:37:41 +0200 Subject: [PATCH 0997/1206] [3.12] gh-109408: Revert pre-commit whitespace checks pending portable solution (GH-110726) (#110730) gh-109408: Revert pre-commit whitespace checks pending portable solution (GH-110726) (cherry picked from commit de956b263b98bb9928ce4377c42ca8271c4f2682) Co-authored-by: Hugo van Kemenade --- .pre-commit-config.yaml | 24 ------- Tools/patchcheck/patchcheck.py | 120 ++++++++++++++++++++++++++++++--- 2 files changed, 110 insertions(+), 34 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9a27d30fd4163e..5b362a7c9d4c8a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,30 +23,6 @@ repos: - id: trailing-whitespace types_or: [c, inc, python, rst] - - repo: local - hooks: - - id: python-file-whitespace - name: "Check Python file whitespace" - entry: 'python Tools/patchcheck/reindent.py --nobackup --newline LF' - language: 'system' - types: [python] - exclude: '^(Lib/test/tokenizedata/|Tools/c-analyzer/cpython/_parser).*$' - - - repo: local - hooks: - - id: c-file-whitespace - name: "Check C file whitespace" - entry: "python Tools/patchcheck/untabify.py" - language: "system" - types_or: ['c', 'c++'] - # Don't check the style of vendored libraries - exclude: | - (?x)^( - Modules/_decimal/.* - | Modules/libmpdec/.* - | Modules/expat/.* - )$ - - repo: https://github.com/sphinx-contrib/sphinx-lint rev: v0.6.8 hooks: diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index 66328c8becc1f6..af1f0584bb5403 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -1,15 +1,30 @@ #!/usr/bin/env python3 """Check proposed changes for common issues.""" +import re import sys +import shutil import os.path import subprocess import sysconfig +import reindent +import untabify + + def get_python_source_dir(): src_dir = sysconfig.get_config_var('abs_srcdir') if not src_dir: src_dir = sysconfig.get_config_var('srcdir') return os.path.abspath(src_dir) + + +# Excluded directories which are copies of external libraries: +# don't check their coding style +EXCLUDE_DIRS = [ + os.path.join('Modules', '_decimal', 'libmpdec'), + os.path.join('Modules', 'expat'), + os.path.join('Modules', 'zlib'), + ] SRCDIR = get_python_source_dir() @@ -140,8 +155,62 @@ def changed_files(base_branch=None): else: sys.exit('need a git checkout to get modified files') - # Normalize the path to be able to match using str.startswith() - return list(map(os.path.normpath, filenames)) + filenames2 = [] + for filename in filenames: + # Normalize the path to be able to match using .startswith() + filename = os.path.normpath(filename) + if any(filename.startswith(path) for path in EXCLUDE_DIRS): + # Exclude the file + continue + filenames2.append(filename) + + return filenames2 + + +def report_modified_files(file_paths): + count = len(file_paths) + if count == 0: + return n_files_str(count) + else: + lines = [f"{n_files_str(count)}:"] + for path in file_paths: + lines.append(f" {path}") + return "\n".join(lines) + + +#: Python files that have tabs by design: +_PYTHON_FILES_WITH_TABS = frozenset({ + 'Tools/c-analyzer/cpython/_parser.py', +}) + + +@status("Fixing Python file whitespace", info=report_modified_files) +def normalize_whitespace(file_paths): + """Make sure that the whitespace for .py files have been normalized.""" + reindent.makebackup = False # No need to create backups. + fixed = [ + path for path in file_paths + if ( + path.endswith('.py') + and path not in _PYTHON_FILES_WITH_TABS + and reindent.check(os.path.join(SRCDIR, path)) + ) + ] + return fixed + + +@status("Fixing C file whitespace", info=report_modified_files) +def normalize_c_whitespace(file_paths): + """Report if any C files """ + fixed = [] + for path in file_paths: + abspath = os.path.join(SRCDIR, path) + with open(abspath, 'r') as f: + if '\t' not in f.read(): + continue + untabify.process(abspath, 8, verbose=False) + fixed.append(path) + return fixed @status("Docs modified", modal=True) @@ -181,12 +250,38 @@ def regenerated_pyconfig_h_in(file_paths): return "not needed" +def ci(pull_request): + if pull_request == 'false': + print('Not a pull request; skipping') + return + base_branch = get_base_branch() + file_paths = changed_files(base_branch) + python_files = [fn for fn in file_paths if fn.endswith('.py')] + c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] + fixed = [] + fixed.extend(normalize_whitespace(python_files)) + fixed.extend(normalize_c_whitespace(c_files)) + if not fixed: + print('No whitespace issues found') + else: + count = len(fixed) + print(f'Please fix the {n_files_str(count)} with whitespace issues') + print('(on Unix you can run `make patchcheck` to make the fixes)') + sys.exit(1) + + def main(): base_branch = get_base_branch() file_paths = changed_files(base_branch) + python_files = [fn for fn in file_paths if fn.endswith('.py')] + c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))] doc_files = [fn for fn in file_paths if fn.startswith('Doc') and fn.endswith(('.rst', '.inc'))] misc_files = {p for p in file_paths if p.startswith('Misc')} + # PEP 8 whitespace rules enforcement. + normalize_whitespace(python_files) + # C rules enforcement. + normalize_c_whitespace(c_files) # Docs updated. docs_modified(doc_files) # Misc/ACKS changed. @@ -199,14 +294,19 @@ def main(): regenerated_pyconfig_h_in(file_paths) # Test suite run and passed. - has_c_files = any(fn for fn in file_paths if fn.endswith(('.c', '.h'))) - has_python_files = any(fn for fn in file_paths if fn.endswith('.py')) - print() - if has_c_files: - print("Did you run the test suite and check for refleaks?") - elif has_python_files: - print("Did you run the test suite?") + if python_files or c_files: + end = " and check for refleaks?" if c_files else "?" + print() + print("Did you run the test suite" + end) if __name__ == '__main__': - main() + import argparse + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--ci', + help='Perform pass/fail checks') + args = parser.parse_args() + if args.ci: + ci(args.ci) + else: + main() From 989aa447d79c010861b19053fad1204429aede38 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 20:59:11 +0200 Subject: [PATCH 0998/1206] [3.12] gh-65052: Prevent pdb from crashing when trying to display objects (GH-110578) (#110734) gh-65052: Prevent pdb from crashing when trying to display objects (GH-110578) (cherry picked from commit c523ce0f434582580a3721e15cb7dd6b56ad0236) Co-authored-by: Tian Gao --- Lib/pdb.py | 21 ++++++--- Lib/test/test_pdb.py | 47 +++++++++++++++++++ ...3-10-09-19-09-32.gh-issue-65052.C2mRlo.rst | 1 + 3 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-09-19-09-32.gh-issue-65052.C2mRlo.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 646695ccd1f4dd..df01829b48460e 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -410,8 +410,9 @@ def preloop(self): # fields are changed to be displayed if newvalue is not oldvalue and newvalue != oldvalue: displaying[expr] = newvalue - self.message('display %s: %r [old: %r]' % - (expr, newvalue, oldvalue)) + self.message('display %s: %s [old: %s]' % + (expr, self._safe_repr(newvalue, expr), + self._safe_repr(oldvalue, expr))) def interaction(self, frame, traceback): # Restore the previous signal handler at the Pdb prompt. @@ -1264,7 +1265,7 @@ def do_args(self, arg): for i in range(n): name = co.co_varnames[i] if name in dict: - self.message('%s = %r' % (name, dict[name])) + self.message('%s = %s' % (name, self._safe_repr(dict[name], name))) else: self.message('%s = *** undefined ***' % (name,)) do_a = do_args @@ -1275,7 +1276,7 @@ def do_retval(self, arg): Print the return value for the last return of a function. """ if '__return__' in self.curframe_locals: - self.message(repr(self.curframe_locals['__return__'])) + self.message(self._safe_repr(self.curframe_locals['__return__'], "retval")) else: self.error('Not yet returned!') do_rv = do_retval @@ -1310,6 +1311,12 @@ def _msg_val_func(self, arg, func): except: self._error_exc() + def _safe_repr(self, obj, expr): + try: + return repr(obj) + except Exception as e: + return _rstr(f"*** repr({expr}) failed: {self._format_exc(e)} ***") + def do_p(self, arg): """p expression @@ -1486,8 +1493,8 @@ def do_display(self, arg): if not arg: if self.displaying: self.message('Currently displaying:') - for item in self.displaying.get(self.curframe, {}).items(): - self.message('%s: %r' % item) + for key, val in self.displaying.get(self.curframe, {}).items(): + self.message('%s: %s' % (key, self._safe_repr(val, key))) else: self.message('No expression is being displayed') else: @@ -1496,7 +1503,7 @@ def do_display(self, arg): else: val = self._getval_except(arg) self.displaying.setdefault(self.curframe, {})[arg] = val - self.message('display %s: %r' % (arg, val)) + self.message('display %s: %s' % (arg, self._safe_repr(val, arg))) complete_display = _complete_expression diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index c0fb61253be5ad..46f9d6ef8a1d44 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1846,6 +1846,53 @@ def test_pdb_ambiguous_statements(): (Pdb) continue """ +def test_pdb_issue_gh_65052(): + """See GH-65052 + + args, retval and display should not crash if the object is not displayable + >>> class A: + ... def __new__(cls): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... return object.__new__(cls) + ... def __init__(self): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... self.a = 1 + ... def __repr__(self): + ... return self.a + + >>> def test_function(): + ... A() + >>> with PdbTestInput([ # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + ... 's', + ... 'retval', + ... 'continue', + ... 'args', + ... 'display self', + ... 'display', + ... 'continue', + ... ]): + ... test_function() + > (4)__new__() + -> return object.__new__(cls) + (Pdb) s + --Return-- + > (4)__new__()-> + -> return object.__new__(cls) + (Pdb) retval + *** repr(retval) failed: AttributeError: 'A' object has no attribute 'a' *** + (Pdb) continue + > (7)__init__() + -> self.a = 1 + (Pdb) args + self = *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' *** + (Pdb) display self + display self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' *** + (Pdb) display + Currently displaying: + self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' *** + (Pdb) continue + """ + @support.requires_subprocess() class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-10-09-19-09-32.gh-issue-65052.C2mRlo.rst b/Misc/NEWS.d/next/Library/2023-10-09-19-09-32.gh-issue-65052.C2mRlo.rst new file mode 100644 index 00000000000000..4739c63bb3cc9d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-09-19-09-32.gh-issue-65052.C2mRlo.rst @@ -0,0 +1 @@ +Prevent :mod:`pdb` from crashing when trying to display undisplayable objects From e6c53dd08535076fc60e9295bf46a2b7e615e2f3 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 11 Oct 2023 22:47:38 +0200 Subject: [PATCH 0999/1206] [3.12] gh-108826: Document `dis` module CLI and rename `_test` function to `main` (#108827) (#110681) Co-authored-by: Hugo van Kemenade Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> --- Doc/library/asyncio.rst | 2 + Doc/library/cmdline.rst | 57 +++++++++++++++++++ Doc/library/compileall.rst | 2 + Doc/library/dis.rst | 22 +++++++ Doc/library/gzip.rst | 2 + Doc/library/index.rst | 1 + Doc/library/pickletools.rst | 2 + Doc/library/profile.rst | 2 + Doc/library/py_compile.rst | 1 + Doc/library/sysconfig.rst | 1 + Lib/dis.py | 5 +- ...-09-03-13-43-49.gh-issue-108826.KG7abS.rst | 1 + 12 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 Doc/library/cmdline.rst create mode 100644 Misc/NEWS.d/next/Documentation/2023-09-03-13-43-49.gh-issue-108826.KG7abS.rst diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index c6a046f534e9a1..c75ab47404c1e4 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -56,6 +56,8 @@ Additionally, there are **low-level** APIs for * :ref:`bridge ` callback-based libraries and code with async/await syntax. +.. _asyncio-cli: + You can experiment with an ``asyncio`` concurrent context in the REPL: .. code-block:: pycon diff --git a/Doc/library/cmdline.rst b/Doc/library/cmdline.rst new file mode 100644 index 00000000000000..b2379befeffcba --- /dev/null +++ b/Doc/library/cmdline.rst @@ -0,0 +1,57 @@ +++++++++++++++++++++++++++++++++++++ +Modules command-line interface (CLI) +++++++++++++++++++++++++++++++++++++ + +The following modules have a command-line interface. + +* :ref:`ast ` +* :ref:`asyncio ` +* :mod:`base64` +* :ref:`calendar ` +* :mod:`code` +* :ref:`compileall ` +* :mod:`cProfile`: see :ref:`profile ` +* :ref:`difflib ` +* :ref:`dis ` +* :mod:`doctest` +* :mod:`!encodings.rot_13` +* :mod:`ensurepip` +* :mod:`filecmp` +* :mod:`fileinput` +* :mod:`ftplib` +* :ref:`gzip ` +* :ref:`http.server ` +* :mod:`!idlelib` +* :ref:`inspect ` +* :ref:`json.tool ` +* :mod:`mimetypes` +* :mod:`pdb` +* :mod:`pickle` +* :ref:`pickletools ` +* :mod:`platform` +* :mod:`poplib` +* :ref:`profile ` +* :mod:`pstats` +* :ref:`py_compile ` +* :mod:`pyclbr` +* :mod:`pydoc` +* :mod:`quopri` +* :mod:`runpy` +* :ref:`site ` +* :ref:`sqlite3 ` +* :ref:`sysconfig ` +* :mod:`tabnanny` +* :ref:`tarfile ` +* :mod:`!this` +* :ref:`timeit ` +* :ref:`tokenize ` +* :ref:`trace ` +* :mod:`turtledemo` +* :ref:`unittest ` +* :ref:`uuid ` +* :mod:`venv` +* :mod:`webbrowser` +* :ref:`zipapp ` +* :ref:`zipfile ` + +See also the :ref:`Python command-line interface `. diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst index a1482c9eb889e8..6d16734ddca21e 100644 --- a/Doc/library/compileall.rst +++ b/Doc/library/compileall.rst @@ -16,6 +16,8 @@ have write permission to the library directories. .. include:: ../includes/wasm-notavail.rst +.. _compileall-cli: + Command-line use ---------------- diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index b559b085aa728b..ef016c1fc00a5d 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -63,6 +63,28 @@ the following command can be used to display the disassembly of (The "2" is a line number). +.. _dis-cli: + +Command-line interface +---------------------- + +The :mod:`dis` module can be invoked as a script from the command line: + +.. code-block:: sh + + python -m dis [-h] [infile] + +The following options are accepted: + +.. program:: dis + +.. cmdoption:: -h, --help + + Display usage and exit. + +If :file:`infile` is specified, its disassembled code will be written to stdout. +Otherwise, disassembly is performed on compiled source code recieved from stdin. + Bytecode analysis ----------------- diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 7c871048b43948..f931d0e399c9f2 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -250,6 +250,8 @@ Example of how to GZIP compress a binary string:: .. program:: gzip +.. _gzip-cli: + Command Line Interface ---------------------- diff --git a/Doc/library/index.rst b/Doc/library/index.rst index d064b680f9aaa4..0b348ae6f5c8c0 100644 --- a/Doc/library/index.rst +++ b/Doc/library/index.rst @@ -73,5 +73,6 @@ the `Python Package Index `_. language.rst windows.rst unix.rst + cmdline.rst superseded.rst security_warnings.rst diff --git a/Doc/library/pickletools.rst b/Doc/library/pickletools.rst index c6ff4e6ed3d3b5..41930f8cbe8412 100644 --- a/Doc/library/pickletools.rst +++ b/Doc/library/pickletools.rst @@ -17,6 +17,8 @@ are useful for Python core developers who are working on the :mod:`pickle`; ordinary users of the :mod:`pickle` module probably won't find the :mod:`pickletools` module relevant. +.. _pickletools-cli: + Command line usage ------------------ diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index 723f927135a0f4..69274b0c354a25 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -121,6 +121,8 @@ results to a file by specifying a filename to the :func:`run` function:: The :class:`pstats.Stats` class reads profile results from a file and formats them in various ways. +.. _profile-cli: + The files :mod:`cProfile` and :mod:`profile` can also be invoked as a script to profile another script. For example:: diff --git a/Doc/library/py_compile.rst b/Doc/library/py_compile.rst index 7272f36d9a5568..38c416f9ad0305 100644 --- a/Doc/library/py_compile.rst +++ b/Doc/library/py_compile.rst @@ -125,6 +125,7 @@ byte-code cache files in the directory containing the source code. This option is useful when the ``.pycs`` are kept up to date by some system external to Python like a build system. +.. _py_compile-cli: Command-Line Interface ---------------------- diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index e5ed45b8529a57..905abc3a7c9f9b 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -427,6 +427,7 @@ Other functions Return the path of :file:`Makefile`. +.. _sysconfig-cli: Using :mod:`sysconfig` as a script ---------------------------------- diff --git a/Lib/dis.py b/Lib/dis.py index 3a8e6ac3bf5ace..320dec03d25b0c 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -790,8 +790,7 @@ def dis(self): return output.getvalue() -def _test(): - """Simple test program to disassemble a file.""" +def main(): import argparse parser = argparse.ArgumentParser() @@ -803,4 +802,4 @@ def _test(): dis(code) if __name__ == "__main__": - _test() + main() diff --git a/Misc/NEWS.d/next/Documentation/2023-09-03-13-43-49.gh-issue-108826.KG7abS.rst b/Misc/NEWS.d/next/Documentation/2023-09-03-13-43-49.gh-issue-108826.KG7abS.rst new file mode 100644 index 00000000000000..139b8f3457930c --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-09-03-13-43-49.gh-issue-108826.KG7abS.rst @@ -0,0 +1 @@ +:mod:`dis` module command-line interface is now mentioned in documentation. From cae968ba1708ce23760974e850a0fceee856d926 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 23:11:28 +0200 Subject: [PATCH 1000/1206] [3.12] gh-110631: Fix reST indentation in `Doc/library` (GH-110685) (#110736) gh-110631: Fix reST indentation in `Doc/library` (GH-110685) Fix wrong indentation in the Doc/library dir. (cherry picked from commit bb7923f556537a463c403dc1097726d8a8e1a6f2) Co-authored-by: Ezio Melotti --- Doc/library/__main__.rst | 46 +- Doc/library/_thread.rst | 2 +- Doc/library/binascii.rst | 9 +- Doc/library/collections.rst | 78 +-- Doc/library/concurrent.futures.rst | 270 +++++----- Doc/library/ctypes.rst | 84 +-- Doc/library/curses.rst | 6 +- Doc/library/dialog.rst | 12 +- Doc/library/email.contentmanager.rst | 50 +- Doc/library/email.policy.rst | 18 +- Doc/library/enum.rst | 28 +- Doc/library/functions.rst | 30 +- Doc/library/graphlib.rst | 16 +- Doc/library/idle.rst | 22 +- Doc/library/inspect.rst | 27 +- Doc/library/io.rst | 10 +- Doc/library/logging.config.rst | 16 +- Doc/library/lzma.rst | 51 +- Doc/library/multiprocessing.rst | 26 +- Doc/library/numbers.rst | 34 +- Doc/library/profile.rst | 8 +- Doc/library/re.rst | 2 +- Doc/library/shelve.rst | 6 +- Doc/library/socket.rst | 4 +- Doc/library/sqlite3.rst | 24 +- Doc/library/ssl.rst | 24 +- Doc/library/stdtypes.rst | 6 +- Doc/library/string.rst | 100 ++-- Doc/library/subprocess.rst | 28 +- Doc/library/tempfile.rst | 16 +- Doc/library/tkinter.rst | 36 +- Doc/library/tkinter.ttk.rst | 748 +++++++++++++-------------- Doc/library/unittest.mock.rst | 10 +- Doc/library/urllib.request.rst | 12 +- 34 files changed, 933 insertions(+), 926 deletions(-) diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index d378e40b3906c6..24a32b30bba673 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -54,45 +54,45 @@ The top-level code environment can be: * the scope of an interactive prompt:: - >>> __name__ - '__main__' + >>> __name__ + '__main__' * the Python module passed to the Python interpreter as a file argument: - .. code-block:: shell-session + .. code-block:: shell-session - $ python helloworld.py - Hello, world! + $ python helloworld.py + Hello, world! * the Python module or package passed to the Python interpreter with the :option:`-m` argument: - .. code-block:: shell-session + .. code-block:: shell-session - $ python -m tarfile - usage: tarfile.py [-h] [-v] (...) + $ python -m tarfile + usage: tarfile.py [-h] [-v] (...) * Python code read by the Python interpreter from standard input: - .. code-block:: shell-session + .. code-block:: shell-session - $ echo "import this" | python - The Zen of Python, by Tim Peters + $ echo "import this" | python + The Zen of Python, by Tim Peters - Beautiful is better than ugly. - Explicit is better than implicit. - ... + Beautiful is better than ugly. + Explicit is better than implicit. + ... * Python code passed to the Python interpreter with the :option:`-c` argument: - .. code-block:: shell-session + .. code-block:: shell-session - $ python -c "import this" - The Zen of Python, by Tim Peters + $ python -c "import this" + The Zen of Python, by Tim Peters - Beautiful is better than ugly. - Explicit is better than implicit. - ... + Beautiful is better than ugly. + Explicit is better than implicit. + ... In each of these situations, the top-level module's ``__name__`` is set to ``'__main__'``. @@ -102,9 +102,9 @@ top-level environment by checking its own ``__name__``, which allows a common idiom for conditionally executing code when the module is not initialized from an import statement:: - if __name__ == '__main__': - # Execute when the module is not initialized from an import statement. - ... + if __name__ == '__main__': + # Execute when the module is not initialized from an import statement. + ... .. seealso:: diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 0442c298c137ba..d7c61c3d7ef126 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -208,7 +208,7 @@ In addition to these methods, lock objects can also be used via the **Caveats:** - .. index:: pair: module; signal +.. index:: pair: module; signal * Threads interact strangely with interrupts: the :exc:`KeyboardInterrupt` exception will be received by an arbitrary thread. (When the :mod:`signal` diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index 21960cb7972e6e..d065fa3506da11 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -58,10 +58,11 @@ The :mod:`binascii` module defines the following functions: data will raise :exc:`binascii.Error`. Valid base64: - * Conforms to :rfc:`3548`. - * Contains only characters from the base64 alphabet. - * Contains no excess data after padding (including excess padding, newlines, etc.). - * Does not start with a padding. + + * Conforms to :rfc:`3548`. + * Contains only characters from the base64 alphabet. + * Contains no excess data after padding (including excess padding, newlines, etc.). + * Does not start with a padding. .. versionchanged:: 3.11 Added the *strict_mode* parameter. diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index bb46782c06e1c8..41896d70c92577 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -120,26 +120,26 @@ The class can be used to simulate nested scopes and is useful in templating. .. seealso:: - * The `MultiContext class - `_ - in the Enthought `CodeTools package - `_ has options to support - writing to any mapping in the chain. + * The `MultiContext class + `_ + in the Enthought `CodeTools package + `_ has options to support + writing to any mapping in the chain. - * Django's `Context class - `_ - for templating is a read-only chain of mappings. It also features - pushing and popping of contexts similar to the - :meth:`~collections.ChainMap.new_child` method and the - :attr:`~collections.ChainMap.parents` property. + * Django's `Context class + `_ + for templating is a read-only chain of mappings. It also features + pushing and popping of contexts similar to the + :meth:`~collections.ChainMap.new_child` method and the + :attr:`~collections.ChainMap.parents` property. - * The `Nested Contexts recipe - `_ has options to control - whether writes and other mutations apply only to the first mapping or to - any mapping in the chain. + * The `Nested Contexts recipe + `_ has options to control + whether writes and other mutations apply only to the first mapping or to + any mapping in the chain. - * A `greatly simplified read-only version of Chainmap - `_. + * A `greatly simplified read-only version of Chainmap + `_. :class:`ChainMap` Examples and Recipes @@ -429,22 +429,22 @@ or subtracting from an empty counter. .. seealso:: - * `Bag class `_ - in Smalltalk. + * `Bag class `_ + in Smalltalk. - * Wikipedia entry for `Multisets `_. + * Wikipedia entry for `Multisets `_. - * `C++ multisets `_ - tutorial with examples. + * `C++ multisets `_ + tutorial with examples. - * For mathematical operations on multisets and their use cases, see - *Knuth, Donald. The Art of Computer Programming Volume II, - Section 4.6.3, Exercise 19*. + * For mathematical operations on multisets and their use cases, see + *Knuth, Donald. The Art of Computer Programming Volume II, + Section 4.6.3, Exercise 19*. - * To enumerate all distinct multisets of a given size over a given set of - elements, see :func:`itertools.combinations_with_replacement`:: + * To enumerate all distinct multisets of a given size over a given set of + elements, see :func:`itertools.combinations_with_replacement`:: - map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC + map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC :class:`deque` objects @@ -1060,20 +1060,20 @@ fields: .. seealso:: - * See :class:`typing.NamedTuple` for a way to add type hints for named - tuples. It also provides an elegant notation using the :keyword:`class` - keyword:: + * See :class:`typing.NamedTuple` for a way to add type hints for named + tuples. It also provides an elegant notation using the :keyword:`class` + keyword:: - class Component(NamedTuple): - part_number: int - weight: float - description: Optional[str] = None + class Component(NamedTuple): + part_number: int + weight: float + description: Optional[str] = None - * See :meth:`types.SimpleNamespace` for a mutable namespace based on an - underlying dictionary instead of a tuple. + * See :meth:`types.SimpleNamespace` for a mutable namespace based on an + underlying dictionary instead of a tuple. - * The :mod:`dataclasses` module provides a decorator and functions for - automatically adding generated special methods to user-defined classes. + * The :mod:`dataclasses` module provides a decorator and functions for + automatically adding generated special methods to user-defined classes. :class:`OrderedDict` objects diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 6503d1fcf70a32..163f170927b719 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -29,83 +29,83 @@ Executor Objects An abstract class that provides methods to execute calls asynchronously. It should not be used directly, but through its concrete subclasses. - .. method:: submit(fn, /, *args, **kwargs) + .. method:: submit(fn, /, *args, **kwargs) - Schedules the callable, *fn*, to be executed as ``fn(*args, **kwargs)`` - and returns a :class:`Future` object representing the execution of the - callable. :: + Schedules the callable, *fn*, to be executed as ``fn(*args, **kwargs)`` + and returns a :class:`Future` object representing the execution of the + callable. :: - with ThreadPoolExecutor(max_workers=1) as executor: - future = executor.submit(pow, 323, 1235) - print(future.result()) + with ThreadPoolExecutor(max_workers=1) as executor: + future = executor.submit(pow, 323, 1235) + print(future.result()) - .. method:: map(func, *iterables, timeout=None, chunksize=1) + .. method:: map(func, *iterables, timeout=None, chunksize=1) - Similar to :func:`map(func, *iterables) ` except: + Similar to :func:`map(func, *iterables) ` except: - * the *iterables* are collected immediately rather than lazily; + * the *iterables* are collected immediately rather than lazily; - * *func* is executed asynchronously and several calls to - *func* may be made concurrently. + * *func* is executed asynchronously and several calls to + *func* may be made concurrently. - The returned iterator raises a :exc:`TimeoutError` - if :meth:`~iterator.__next__` is called and the result isn't available - after *timeout* seconds from the original call to :meth:`Executor.map`. - *timeout* can be an int or a float. If *timeout* is not specified or - ``None``, there is no limit to the wait time. + The returned iterator raises a :exc:`TimeoutError` + if :meth:`~iterator.__next__` is called and the result isn't available + after *timeout* seconds from the original call to :meth:`Executor.map`. + *timeout* can be an int or a float. If *timeout* is not specified or + ``None``, there is no limit to the wait time. - If a *func* call raises an exception, then that exception will be - raised when its value is retrieved from the iterator. + If a *func* call raises an exception, then that exception will be + raised when its value is retrieved from the iterator. - When using :class:`ProcessPoolExecutor`, this method chops *iterables* - into a number of chunks which it submits to the pool as separate - tasks. The (approximate) size of these chunks can be specified by - setting *chunksize* to a positive integer. For very long iterables, - using a large value for *chunksize* can significantly improve - performance compared to the default size of 1. With - :class:`ThreadPoolExecutor`, *chunksize* has no effect. + When using :class:`ProcessPoolExecutor`, this method chops *iterables* + into a number of chunks which it submits to the pool as separate + tasks. The (approximate) size of these chunks can be specified by + setting *chunksize* to a positive integer. For very long iterables, + using a large value for *chunksize* can significantly improve + performance compared to the default size of 1. With + :class:`ThreadPoolExecutor`, *chunksize* has no effect. - .. versionchanged:: 3.5 - Added the *chunksize* argument. + .. versionchanged:: 3.5 + Added the *chunksize* argument. - .. method:: shutdown(wait=True, *, cancel_futures=False) + .. method:: shutdown(wait=True, *, cancel_futures=False) - Signal the executor that it should free any resources that it is using - when the currently pending futures are done executing. Calls to - :meth:`Executor.submit` and :meth:`Executor.map` made after shutdown will - raise :exc:`RuntimeError`. + Signal the executor that it should free any resources that it is using + when the currently pending futures are done executing. Calls to + :meth:`Executor.submit` and :meth:`Executor.map` made after shutdown will + raise :exc:`RuntimeError`. - If *wait* is ``True`` then this method will not return until all the - pending futures are done executing and the resources associated with the - executor have been freed. If *wait* is ``False`` then this method will - return immediately and the resources associated with the executor will be - freed when all pending futures are done executing. Regardless of the - value of *wait*, the entire Python program will not exit until all - pending futures are done executing. + If *wait* is ``True`` then this method will not return until all the + pending futures are done executing and the resources associated with the + executor have been freed. If *wait* is ``False`` then this method will + return immediately and the resources associated with the executor will be + freed when all pending futures are done executing. Regardless of the + value of *wait*, the entire Python program will not exit until all + pending futures are done executing. - If *cancel_futures* is ``True``, this method will cancel all pending - futures that the executor has not started running. Any futures that - are completed or running won't be cancelled, regardless of the value - of *cancel_futures*. + If *cancel_futures* is ``True``, this method will cancel all pending + futures that the executor has not started running. Any futures that + are completed or running won't be cancelled, regardless of the value + of *cancel_futures*. - If both *cancel_futures* and *wait* are ``True``, all futures that the - executor has started running will be completed prior to this method - returning. The remaining futures are cancelled. + If both *cancel_futures* and *wait* are ``True``, all futures that the + executor has started running will be completed prior to this method + returning. The remaining futures are cancelled. - You can avoid having to call this method explicitly if you use the - :keyword:`with` statement, which will shutdown the :class:`Executor` - (waiting as if :meth:`Executor.shutdown` were called with *wait* set to - ``True``):: + You can avoid having to call this method explicitly if you use the + :keyword:`with` statement, which will shutdown the :class:`Executor` + (waiting as if :meth:`Executor.shutdown` were called with *wait* set to + ``True``):: - import shutil - with ThreadPoolExecutor(max_workers=4) as e: - e.submit(shutil.copy, 'src1.txt', 'dest1.txt') - e.submit(shutil.copy, 'src2.txt', 'dest2.txt') - e.submit(shutil.copy, 'src3.txt', 'dest3.txt') - e.submit(shutil.copy, 'src4.txt', 'dest4.txt') + import shutil + with ThreadPoolExecutor(max_workers=4) as e: + e.submit(shutil.copy, 'src1.txt', 'dest1.txt') + e.submit(shutil.copy, 'src2.txt', 'dest2.txt') + e.submit(shutil.copy, 'src3.txt', 'dest3.txt') + e.submit(shutil.copy, 'src4.txt', 'dest4.txt') - .. versionchanged:: 3.9 - Added *cancel_futures*. + .. versionchanged:: 3.9 + Added *cancel_futures*. ThreadPoolExecutor @@ -353,117 +353,117 @@ The :class:`Future` class encapsulates the asynchronous execution of a callable. instances are created by :meth:`Executor.submit` and should not be created directly except for testing. - .. method:: cancel() + .. method:: cancel() - Attempt to cancel the call. If the call is currently being executed or - finished running and cannot be cancelled then the method will return - ``False``, otherwise the call will be cancelled and the method will - return ``True``. + Attempt to cancel the call. If the call is currently being executed or + finished running and cannot be cancelled then the method will return + ``False``, otherwise the call will be cancelled and the method will + return ``True``. - .. method:: cancelled() + .. method:: cancelled() - Return ``True`` if the call was successfully cancelled. + Return ``True`` if the call was successfully cancelled. - .. method:: running() + .. method:: running() - Return ``True`` if the call is currently being executed and cannot be - cancelled. + Return ``True`` if the call is currently being executed and cannot be + cancelled. - .. method:: done() + .. method:: done() - Return ``True`` if the call was successfully cancelled or finished - running. + Return ``True`` if the call was successfully cancelled or finished + running. - .. method:: result(timeout=None) + .. method:: result(timeout=None) - Return the value returned by the call. If the call hasn't yet completed - then this method will wait up to *timeout* seconds. If the call hasn't - completed in *timeout* seconds, then a - :exc:`TimeoutError` will be raised. *timeout* can be - an int or float. If *timeout* is not specified or ``None``, there is no - limit to the wait time. + Return the value returned by the call. If the call hasn't yet completed + then this method will wait up to *timeout* seconds. If the call hasn't + completed in *timeout* seconds, then a + :exc:`TimeoutError` will be raised. *timeout* can be + an int or float. If *timeout* is not specified or ``None``, there is no + limit to the wait time. - If the future is cancelled before completing then :exc:`.CancelledError` - will be raised. + If the future is cancelled before completing then :exc:`.CancelledError` + will be raised. - If the call raised an exception, this method will raise the same exception. + If the call raised an exception, this method will raise the same exception. - .. method:: exception(timeout=None) + .. method:: exception(timeout=None) - Return the exception raised by the call. If the call hasn't yet - completed then this method will wait up to *timeout* seconds. If the - call hasn't completed in *timeout* seconds, then a - :exc:`TimeoutError` will be raised. *timeout* can be - an int or float. If *timeout* is not specified or ``None``, there is no - limit to the wait time. + Return the exception raised by the call. If the call hasn't yet + completed then this method will wait up to *timeout* seconds. If the + call hasn't completed in *timeout* seconds, then a + :exc:`TimeoutError` will be raised. *timeout* can be + an int or float. If *timeout* is not specified or ``None``, there is no + limit to the wait time. - If the future is cancelled before completing then :exc:`.CancelledError` - will be raised. + If the future is cancelled before completing then :exc:`.CancelledError` + will be raised. - If the call completed without raising, ``None`` is returned. + If the call completed without raising, ``None`` is returned. - .. method:: add_done_callback(fn) + .. method:: add_done_callback(fn) - Attaches the callable *fn* to the future. *fn* will be called, with the - future as its only argument, when the future is cancelled or finishes - running. + Attaches the callable *fn* to the future. *fn* will be called, with the + future as its only argument, when the future is cancelled or finishes + running. - Added callables are called in the order that they were added and are - always called in a thread belonging to the process that added them. If - the callable raises an :exc:`Exception` subclass, it will be logged and - ignored. If the callable raises a :exc:`BaseException` subclass, the - behavior is undefined. + Added callables are called in the order that they were added and are + always called in a thread belonging to the process that added them. If + the callable raises an :exc:`Exception` subclass, it will be logged and + ignored. If the callable raises a :exc:`BaseException` subclass, the + behavior is undefined. - If the future has already completed or been cancelled, *fn* will be - called immediately. + If the future has already completed or been cancelled, *fn* will be + called immediately. The following :class:`Future` methods are meant for use in unit tests and :class:`Executor` implementations. - .. method:: set_running_or_notify_cancel() + .. method:: set_running_or_notify_cancel() - This method should only be called by :class:`Executor` implementations - before executing the work associated with the :class:`Future` and by unit - tests. + This method should only be called by :class:`Executor` implementations + before executing the work associated with the :class:`Future` and by unit + tests. - If the method returns ``False`` then the :class:`Future` was cancelled, - i.e. :meth:`Future.cancel` was called and returned ``True``. Any threads - waiting on the :class:`Future` completing (i.e. through - :func:`as_completed` or :func:`wait`) will be woken up. + If the method returns ``False`` then the :class:`Future` was cancelled, + i.e. :meth:`Future.cancel` was called and returned ``True``. Any threads + waiting on the :class:`Future` completing (i.e. through + :func:`as_completed` or :func:`wait`) will be woken up. - If the method returns ``True`` then the :class:`Future` was not cancelled - and has been put in the running state, i.e. calls to - :meth:`Future.running` will return ``True``. + If the method returns ``True`` then the :class:`Future` was not cancelled + and has been put in the running state, i.e. calls to + :meth:`Future.running` will return ``True``. - This method can only be called once and cannot be called after - :meth:`Future.set_result` or :meth:`Future.set_exception` have been - called. + This method can only be called once and cannot be called after + :meth:`Future.set_result` or :meth:`Future.set_exception` have been + called. - .. method:: set_result(result) + .. method:: set_result(result) - Sets the result of the work associated with the :class:`Future` to - *result*. + Sets the result of the work associated with the :class:`Future` to + *result*. - This method should only be used by :class:`Executor` implementations and - unit tests. + This method should only be used by :class:`Executor` implementations and + unit tests. - .. versionchanged:: 3.8 - This method raises - :exc:`concurrent.futures.InvalidStateError` if the :class:`Future` is - already done. + .. versionchanged:: 3.8 + This method raises + :exc:`concurrent.futures.InvalidStateError` if the :class:`Future` is + already done. - .. method:: set_exception(exception) + .. method:: set_exception(exception) - Sets the result of the work associated with the :class:`Future` to the - :class:`Exception` *exception*. + Sets the result of the work associated with the :class:`Future` to the + :class:`Exception` *exception*. - This method should only be used by :class:`Executor` implementations and - unit tests. + This method should only be used by :class:`Executor` implementations and + unit tests. - .. versionchanged:: 3.8 - This method raises - :exc:`concurrent.futures.InvalidStateError` if the :class:`Future` is - already done. + .. versionchanged:: 3.8 + This method raises + :exc:`concurrent.futures.InvalidStateError` if the :class:`Future` is + already done. Module Functions ---------------- diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 98e6dbf0dd1830..f8c0a53e3dd7c1 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1738,70 +1738,70 @@ See :ref:`ctypes-callback-functions` for examples. Function prototypes created by these factory functions can be instantiated in different ways, depending on the type and number of the parameters in the call: +.. function:: prototype(address) + :noindex: + :module: - .. function:: prototype(address) - :noindex: - :module: + Returns a foreign function at the specified address which must be an integer. - Returns a foreign function at the specified address which must be an integer. +.. function:: prototype(callable) + :noindex: + :module: - .. function:: prototype(callable) - :noindex: - :module: + Create a C callable function (a callback function) from a Python *callable*. - Create a C callable function (a callback function) from a Python *callable*. +.. function:: prototype(func_spec[, paramflags]) + :noindex: + :module: - .. function:: prototype(func_spec[, paramflags]) - :noindex: - :module: + Returns a foreign function exported by a shared library. *func_spec* must + be a 2-tuple ``(name_or_ordinal, library)``. The first item is the name of + the exported function as string, or the ordinal of the exported function + as small integer. The second item is the shared library instance. - Returns a foreign function exported by a shared library. *func_spec* must - be a 2-tuple ``(name_or_ordinal, library)``. The first item is the name of - the exported function as string, or the ordinal of the exported function - as small integer. The second item is the shared library instance. +.. function:: prototype(vtbl_index, name[, paramflags[, iid]]) + :noindex: + :module: - .. function:: prototype(vtbl_index, name[, paramflags[, iid]]) - :noindex: - :module: + Returns a foreign function that will call a COM method. *vtbl_index* is + the index into the virtual function table, a small non-negative + integer. *name* is name of the COM method. *iid* is an optional pointer to + the interface identifier which is used in extended error reporting. - Returns a foreign function that will call a COM method. *vtbl_index* is - the index into the virtual function table, a small non-negative - integer. *name* is name of the COM method. *iid* is an optional pointer to - the interface identifier which is used in extended error reporting. + COM methods use a special calling convention: They require a pointer to + the COM interface as first argument, in addition to those parameters that + are specified in the :attr:`!argtypes` tuple. - COM methods use a special calling convention: They require a pointer to - the COM interface as first argument, in addition to those parameters that - are specified in the :attr:`!argtypes` tuple. +The optional *paramflags* parameter creates foreign function wrappers with much +more functionality than the features described above. - The optional *paramflags* parameter creates foreign function wrappers with much - more functionality than the features described above. +*paramflags* must be a tuple of the same length as :attr:`~_FuncPtr.argtypes`. - *paramflags* must be a tuple of the same length as :attr:`~_FuncPtr.argtypes`. +Each item in this tuple contains further information about a parameter, it must +be a tuple containing one, two, or three items. - Each item in this tuple contains further information about a parameter, it must - be a tuple containing one, two, or three items. +The first item is an integer containing a combination of direction +flags for the parameter: - The first item is an integer containing a combination of direction - flags for the parameter: + 1 + Specifies an input parameter to the function. - 1 - Specifies an input parameter to the function. + 2 + Output parameter. The foreign function fills in a value. - 2 - Output parameter. The foreign function fills in a value. + 4 + Input parameter which defaults to the integer zero. - 4 - Input parameter which defaults to the integer zero. +The optional second item is the parameter name as string. If this is specified, +the foreign function can be called with named parameters. - The optional second item is the parameter name as string. If this is specified, - the foreign function can be called with named parameters. +The optional third item is the default value for this parameter. - The optional third item is the default value for this parameter. -This example demonstrates how to wrap the Windows ``MessageBoxW`` function so +The following example demonstrates how to wrap the Windows ``MessageBoxW`` function so that it supports default parameters and named arguments. The C declaration from the windows header file is this:: diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 9ab67c21975394..9b8a98f05f7cbb 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1771,9 +1771,9 @@ The following table lists mouse button constants used by :meth:`getmouse`: | .. data:: BUTTON_ALT | Control was down during button state change | +----------------------------------+---------------------------------------------+ - .. versionchanged:: 3.10 - The ``BUTTON5_*`` constants are now exposed if they are provided by the - underlying curses library. +.. versionchanged:: 3.10 + The ``BUTTON5_*`` constants are now exposed if they are provided by the + underlying curses library. The following table lists the predefined colors: diff --git a/Doc/library/dialog.rst b/Doc/library/dialog.rst index 53f98c1018988f..191e0da12103fa 100644 --- a/Doc/library/dialog.rst +++ b/Doc/library/dialog.rst @@ -27,15 +27,15 @@ functions for creating simple modal dialogs to get a value from the user. The base class for custom dialogs. - .. method:: body(master) + .. method:: body(master) - Override to construct the dialog's interface and return the widget that - should have initial focus. + Override to construct the dialog's interface and return the widget that + should have initial focus. - .. method:: buttonbox() + .. method:: buttonbox() - Default behaviour adds OK and Cancel buttons. Override for custom button - layouts. + Default behaviour adds OK and Cancel buttons. Override for custom button + layouts. diff --git a/Doc/library/email.contentmanager.rst b/Doc/library/email.contentmanager.rst index 918fc55677e723..5b49339650f0e9 100644 --- a/Doc/library/email.contentmanager.rst +++ b/Doc/library/email.contentmanager.rst @@ -32,9 +32,9 @@ To find the handler, look for the following keys in the registry, stopping with the first one found: - * the string representing the full MIME type (``maintype/subtype``) - * the string representing the ``maintype`` - * the empty string + * the string representing the full MIME type (``maintype/subtype``) + * the string representing the ``maintype`` + * the empty string If none of these keys produce a handler, raise a :exc:`KeyError` for the full MIME type. @@ -55,11 +55,11 @@ look for the following keys in the registry, stopping with the first one found: - * the type itself (``typ``) - * the type's fully qualified name (``typ.__module__ + '.' + - typ.__qualname__``). - * the type's qualname (``typ.__qualname__``) - * the type's name (``typ.__name__``). + * the type itself (``typ``) + * the type's fully qualified name (``typ.__module__ + '.' + + typ.__qualname__``). + * the type's qualname (``typ.__qualname__``) + * the type's name (``typ.__name__``). If none of the above match, repeat all of the checks above for each of the types in the :term:`MRO` (``typ.__mro__``). Finally, if no other key @@ -132,15 +132,15 @@ Currently the email package provides only one concrete content manager, Add a :mailheader:`Content-Type` header with a ``maintype/subtype`` value. - * For ``str``, set the MIME ``maintype`` to ``text``, and set the - subtype to *subtype* if it is specified, or ``plain`` if it is not. - * For ``bytes``, use the specified *maintype* and *subtype*, or - raise a :exc:`TypeError` if they are not specified. - * For :class:`~email.message.EmailMessage` objects, set the maintype - to ``message``, and set the subtype to *subtype* if it is - specified or ``rfc822`` if it is not. If *subtype* is - ``partial``, raise an error (``bytes`` objects must be used to - construct ``message/partial`` parts). + * For ``str``, set the MIME ``maintype`` to ``text``, and set the + subtype to *subtype* if it is specified, or ``plain`` if it is not. + * For ``bytes``, use the specified *maintype* and *subtype*, or + raise a :exc:`TypeError` if they are not specified. + * For :class:`~email.message.EmailMessage` objects, set the maintype + to ``message``, and set the subtype to *subtype* if it is + specified or ``rfc822`` if it is not. If *subtype* is + ``partial``, raise an error (``bytes`` objects must be used to + construct ``message/partial`` parts). If *charset* is provided (which is valid only for ``str``), encode the string to bytes using the specified character set. The default is @@ -155,14 +155,14 @@ Currently the email package provides only one concrete content manager, ``7bit`` for an input that contains non-ASCII values), raise a :exc:`ValueError`. - * For ``str`` objects, if *cte* is not set use heuristics to - determine the most compact encoding. - * For :class:`~email.message.EmailMessage`, per :rfc:`2046`, raise - an error if a *cte* of ``quoted-printable`` or ``base64`` is - requested for *subtype* ``rfc822``, and for any *cte* other than - ``7bit`` for *subtype* ``external-body``. For - ``message/rfc822``, use ``8bit`` if *cte* is not specified. For - all other values of *subtype*, use ``7bit``. + * For ``str`` objects, if *cte* is not set use heuristics to + determine the most compact encoding. + * For :class:`~email.message.EmailMessage`, per :rfc:`2046`, raise + an error if a *cte* of ``quoted-printable`` or ``base64`` is + requested for *subtype* ``rfc822``, and for any *cte* other than + ``7bit`` for *subtype* ``external-body``. For + ``message/rfc822``, use ``8bit`` if *cte* is not specified. For + all other values of *subtype*, use ``7bit``. .. note:: A *cte* of ``binary`` does not actually work correctly yet. The ``EmailMessage`` object as modified by ``set_content`` is diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst index 2439dee676c9b0..fd47dd0dc5df36 100644 --- a/Doc/library/email.policy.rst +++ b/Doc/library/email.policy.rst @@ -557,17 +557,17 @@ more closely to the RFCs relevant to their domains. With all of these :class:`EmailPolicies <.EmailPolicy>`, the effective API of the email package is changed from the Python 3.2 API in the following ways: - * Setting a header on a :class:`~email.message.Message` results in that - header being parsed and a header object created. +* Setting a header on a :class:`~email.message.Message` results in that + header being parsed and a header object created. - * Fetching a header value from a :class:`~email.message.Message` results - in that header being parsed and a header object created and - returned. +* Fetching a header value from a :class:`~email.message.Message` results + in that header being parsed and a header object created and + returned. - * Any header object, or any header that is refolded due to the - policy settings, is folded using an algorithm that fully implements the - RFC folding algorithms, including knowing where encoded words are required - and allowed. +* Any header object, or any header that is refolded due to the + policy settings, is folded using an algorithm that fully implements the + RFC folding algorithms, including knowing where encoded words are required + and allowed. From the application view, this means that any header obtained through the :class:`~email.message.EmailMessage` is a header object with extra diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 7653865f0b9b36..487dace78c7288 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -597,8 +597,8 @@ Data Types If a *Flag* operation is performed with an *IntFlag* member and: - * the result is a valid *IntFlag*: an *IntFlag* is returned - * the result is not a valid *IntFlag*: the result depends on the *FlagBoundary* setting + * the result is a valid *IntFlag*: an *IntFlag* is returned + * the result is not a valid *IntFlag*: the result depends on the *FlagBoundary* setting The *repr()* of unnamed zero-valued flags has changed. It is now: @@ -625,8 +625,8 @@ Data Types :class:`!ReprEnum` uses the :meth:`repr() ` of :class:`Enum`, but the :class:`str() ` of the mixed-in data type: - * :meth:`!int.__str__` for :class:`IntEnum` and :class:`IntFlag` - * :meth:`!str.__str__` for :class:`StrEnum` + * :meth:`!int.__str__` for :class:`IntEnum` and :class:`IntFlag` + * :meth:`!str.__str__` for :class:`StrEnum` Inherit from :class:`!ReprEnum` to keep the :class:`str() ` / :func:`format` of the mixed-in data type instead of using the @@ -789,13 +789,13 @@ Supported ``_sunder_`` names - ``_generate_next_value_`` -- used to get an appropriate value for an enum member; may be overridden - .. note:: + .. note:: - For standard :class:`Enum` classes the next value chosen is the last value seen - incremented by one. + For standard :class:`Enum` classes the next value chosen is the last value seen + incremented by one. - For :class:`Flag` classes the next value chosen will be the next highest - power-of-two, regardless of the last value seen. + For :class:`Flag` classes the next value chosen will be the next highest + power-of-two, regardless of the last value seen. .. versionadded:: 3.6 ``_missing_``, ``_order_``, ``_generate_next_value_`` .. versionadded:: 3.7 ``_ignore_`` @@ -817,11 +817,11 @@ Utilities and Decorators *auto* instances are only resolved when at the top level of an assignment: - * ``FIRST = auto()`` will work (auto() is replaced with ``1``); - * ``SECOND = auto(), -2`` will work (auto is replaced with ``2``, so ``2, -2`` is - used to create the ``SECOND`` enum member; - * ``THREE = [auto(), -3]`` will *not* work (``, -3`` is used to - create the ``THREE`` enum member) + * ``FIRST = auto()`` will work (auto() is replaced with ``1``); + * ``SECOND = auto(), -2`` will work (auto is replaced with ``2``, so ``2, -2`` is + used to create the ``SECOND`` enum member; + * ``THREE = [auto(), -3]`` will *not* work (``, -3`` is used to + create the ``THREE`` enum member) .. versionchanged:: 3.11.1 diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 3cb70b7fda8d78..3277edd483b46b 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1158,8 +1158,8 @@ are always available. They are listed here in alphabetical order. See also :func:`format` for more information. - .. index:: - single: file object; open() built-in function +.. index:: + single: file object; open() built-in function .. function:: open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) @@ -1360,28 +1360,28 @@ are always available. They are listed here in alphabetical order. .. versionchanged:: 3.3 - * The *opener* parameter was added. - * The ``'x'`` mode was added. - * :exc:`IOError` used to be raised, it is now an alias of :exc:`OSError`. - * :exc:`FileExistsError` is now raised if the file opened in exclusive - creation mode (``'x'``) already exists. + * The *opener* parameter was added. + * The ``'x'`` mode was added. + * :exc:`IOError` used to be raised, it is now an alias of :exc:`OSError`. + * :exc:`FileExistsError` is now raised if the file opened in exclusive + creation mode (``'x'``) already exists. .. versionchanged:: 3.4 - * The file is now non-inheritable. + * The file is now non-inheritable. .. versionchanged:: 3.5 - * If the system call is interrupted and the signal handler does not raise an - exception, the function now retries the system call instead of raising an - :exc:`InterruptedError` exception (see :pep:`475` for the rationale). - * The ``'namereplace'`` error handler was added. + * If the system call is interrupted and the signal handler does not raise an + exception, the function now retries the system call instead of raising an + :exc:`InterruptedError` exception (see :pep:`475` for the rationale). + * The ``'namereplace'`` error handler was added. .. versionchanged:: 3.6 - * Support added to accept objects implementing :class:`os.PathLike`. - * On Windows, opening a console buffer may return a subclass of - :class:`io.RawIOBase` other than :class:`io.FileIO`. + * Support added to accept objects implementing :class:`os.PathLike`. + * On Windows, opening a console buffer may return a subclass of + :class:`io.RawIOBase` other than :class:`io.FileIO`. .. versionchanged:: 3.11 The ``'U'`` mode has been removed. diff --git a/Doc/library/graphlib.rst b/Doc/library/graphlib.rst index fdd8f39ef4e1c4..5414d6370b78ce 100644 --- a/Doc/library/graphlib.rst +++ b/Doc/library/graphlib.rst @@ -37,14 +37,14 @@ In the general case, the steps required to perform the sorting of a given graph are as follows: - * Create an instance of the :class:`TopologicalSorter` with an optional - initial graph. - * Add additional nodes to the graph. - * Call :meth:`~TopologicalSorter.prepare` on the graph. - * While :meth:`~TopologicalSorter.is_active` is ``True``, iterate over - the nodes returned by :meth:`~TopologicalSorter.get_ready` and - process them. Call :meth:`~TopologicalSorter.done` on each node as it - finishes processing. + * Create an instance of the :class:`TopologicalSorter` with an optional + initial graph. + * Add additional nodes to the graph. + * Call :meth:`~TopologicalSorter.prepare` on the graph. + * While :meth:`~TopologicalSorter.is_active` is ``True``, iterate over + the nodes returned by :meth:`~TopologicalSorter.get_ready` and + process them. Call :meth:`~TopologicalSorter.done` on each node as it + finishes processing. In case just an immediate sorting of the nodes in the graph is required and no parallelism is involved, the convenience method diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index 3211da50dc745c..e710d0bacf3fee 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -439,24 +439,24 @@ the :kbd:`Command` key on macOS. * Some useful Emacs bindings are inherited from Tcl/Tk: - * :kbd:`C-a` beginning of line + * :kbd:`C-a` beginning of line - * :kbd:`C-e` end of line + * :kbd:`C-e` end of line - * :kbd:`C-k` kill line (but doesn't put it in clipboard) + * :kbd:`C-k` kill line (but doesn't put it in clipboard) - * :kbd:`C-l` center window around the insertion point + * :kbd:`C-l` center window around the insertion point - * :kbd:`C-b` go backward one character without deleting (usually you can - also use the cursor key for this) + * :kbd:`C-b` go backward one character without deleting (usually you can + also use the cursor key for this) - * :kbd:`C-f` go forward one character without deleting (usually you can - also use the cursor key for this) + * :kbd:`C-f` go forward one character without deleting (usually you can + also use the cursor key for this) - * :kbd:`C-p` go up one line (usually you can also use the cursor key for - this) + * :kbd:`C-p` go up one line (usually you can also use the cursor key for + this) - * :kbd:`C-d` delete next character + * :kbd:`C-d` delete next character Standard keybindings (like :kbd:`C-c` to copy and :kbd:`C-v` to paste) may work. Keybindings are selected in the Configure IDLE dialog. diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 556cc3b5cd40c0..23dde26ea3ecd7 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1458,10 +1458,11 @@ generator to be determined easily. Get current state of a generator-iterator. Possible states are: - * GEN_CREATED: Waiting to start execution. - * GEN_RUNNING: Currently being executed by the interpreter. - * GEN_SUSPENDED: Currently suspended at a yield expression. - * GEN_CLOSED: Execution has completed. + + * GEN_CREATED: Waiting to start execution. + * GEN_RUNNING: Currently being executed by the interpreter. + * GEN_SUSPENDED: Currently suspended at a yield expression. + * GEN_CLOSED: Execution has completed. .. versionadded:: 3.2 @@ -1473,10 +1474,11 @@ generator to be determined easily. ``cr_frame`` attributes. Possible states are: - * CORO_CREATED: Waiting to start execution. - * CORO_RUNNING: Currently being executed by the interpreter. - * CORO_SUSPENDED: Currently suspended at an await expression. - * CORO_CLOSED: Execution has completed. + + * CORO_CREATED: Waiting to start execution. + * CORO_RUNNING: Currently being executed by the interpreter. + * CORO_SUSPENDED: Currently suspended at an await expression. + * CORO_CLOSED: Execution has completed. .. versionadded:: 3.5 @@ -1489,10 +1491,11 @@ generator to be determined easily. ``ag_running`` and ``ag_frame`` attributes. Possible states are: - * AGEN_CREATED: Waiting to start execution. - * AGEN_RUNNING: Currently being executed by the interpreter. - * AGEN_SUSPENDED: Currently suspended at a yield expression. - * AGEN_CLOSED: Execution has completed. + + * AGEN_CREATED: Waiting to start execution. + * AGEN_RUNNING: Currently being executed by the interpreter. + * AGEN_SUSPENDED: Currently suspended at a yield expression. + * AGEN_CLOSED: Execution has completed. .. versionadded:: 3.12 diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 01088879218cb4..6736aa9ee2b0ef 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -253,12 +253,12 @@ The implementation of I/O streams is organized as a hierarchy of classes. First specify the various categories of streams, then concrete classes providing the standard stream implementations. - .. note:: +.. note:: - The abstract base classes also provide default implementations of some - methods in order to help implementation of concrete stream classes. For - example, :class:`BufferedIOBase` provides unoptimized implementations of - :meth:`!readinto` and :meth:`!readline`. + The abstract base classes also provide default implementations of some + methods in order to help implementation of concrete stream classes. For + example, :class:`BufferedIOBase` provides unoptimized implementations of + :meth:`!readinto` and :meth:`!readline`. At the top of the I/O hierarchy is the abstract base class :class:`IOBase`. It defines the basic interface to a stream. Note, however, that there is no diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 448978f43b6d13..1c0ea22deac957 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -257,11 +257,11 @@ otherwise, the context is used to determine what to instantiate. which correspond to the arguments passed to create a :class:`~logging.Formatter` object: - * ``format`` - * ``datefmt`` - * ``style`` - * ``validate`` (since version >=3.8) - * ``defaults`` (since version >=3.12) + * ``format`` + * ``datefmt`` + * ``style`` + * ``validate`` (since version >=3.8) + * ``defaults`` (since version >=3.12) An optional ``class`` key indicates the name of the formatter's class (as a dotted module and class name). The instantiation @@ -544,9 +544,9 @@ valid keyword parameter name, and so will not clash with the names of the keyword arguments used in the call. The ``'()'`` also serves as a mnemonic that the corresponding value is a callable. - .. versionchanged:: 3.11 - The ``filters`` member of ``handlers`` and ``loggers`` can take - filter instances in addition to ids. +.. versionchanged:: 3.11 + The ``filters`` member of ``handlers`` and ``loggers`` can take + filter instances in addition to ids. You can also specify a special key ``'.'`` whose value is a dictionary is a mapping of attribute names to values. If found, the specified attributes will diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 434e7ac9061186..0d69c3bc01d1e2 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -333,19 +333,22 @@ the key ``"id"``, and may contain additional keys to specify filter-dependent options. Valid filter IDs are as follows: * Compression filters: - * :const:`FILTER_LZMA1` (for use with :const:`FORMAT_ALONE`) - * :const:`FILTER_LZMA2` (for use with :const:`FORMAT_XZ` and :const:`FORMAT_RAW`) + + * :const:`FILTER_LZMA1` (for use with :const:`FORMAT_ALONE`) + * :const:`FILTER_LZMA2` (for use with :const:`FORMAT_XZ` and :const:`FORMAT_RAW`) * Delta filter: - * :const:`FILTER_DELTA` + + * :const:`FILTER_DELTA` * Branch-Call-Jump (BCJ) filters: - * :const:`FILTER_X86` - * :const:`FILTER_IA64` - * :const:`FILTER_ARM` - * :const:`FILTER_ARMTHUMB` - * :const:`FILTER_POWERPC` - * :const:`FILTER_SPARC` + + * :const:`FILTER_X86` + * :const:`FILTER_IA64` + * :const:`FILTER_ARM` + * :const:`FILTER_ARMTHUMB` + * :const:`FILTER_POWERPC` + * :const:`FILTER_SPARC` A filter chain can consist of up to 4 filters, and cannot be empty. The last filter in the chain must be a compression filter, and any other filters must be @@ -354,21 +357,21 @@ delta or BCJ filters. Compression filters support the following options (specified as additional entries in the dictionary representing the filter): - * ``preset``: A compression preset to use as a source of default values for - options that are not specified explicitly. - * ``dict_size``: Dictionary size in bytes. This should be between 4 KiB and - 1.5 GiB (inclusive). - * ``lc``: Number of literal context bits. - * ``lp``: Number of literal position bits. The sum ``lc + lp`` must be at - most 4. - * ``pb``: Number of position bits; must be at most 4. - * ``mode``: :const:`MODE_FAST` or :const:`MODE_NORMAL`. - * ``nice_len``: What should be considered a "nice length" for a match. - This should be 273 or less. - * ``mf``: What match finder to use -- :const:`MF_HC3`, :const:`MF_HC4`, - :const:`MF_BT2`, :const:`MF_BT3`, or :const:`MF_BT4`. - * ``depth``: Maximum search depth used by match finder. 0 (default) means to - select automatically based on other filter options. +* ``preset``: A compression preset to use as a source of default values for + options that are not specified explicitly. +* ``dict_size``: Dictionary size in bytes. This should be between 4 KiB and + 1.5 GiB (inclusive). +* ``lc``: Number of literal context bits. +* ``lp``: Number of literal position bits. The sum ``lc + lp`` must be at + most 4. +* ``pb``: Number of position bits; must be at most 4. +* ``mode``: :const:`MODE_FAST` or :const:`MODE_NORMAL`. +* ``nice_len``: What should be considered a "nice length" for a match. + This should be 273 or less. +* ``mf``: What match finder to use -- :const:`MF_HC3`, :const:`MF_HC4`, + :const:`MF_BT2`, :const:`MF_BT3`, or :const:`MF_BT4`. +* ``depth``: Maximum search depth used by match finder. 0 (default) means to + select automatically based on other filter options. The delta filter stores the differences between bytes, producing more repetitive input for the compressor in certain circumstances. It supports one option, diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 2f0f1f800fdc94..773fca45c8e70a 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2782,20 +2782,20 @@ worker threads rather than worker processes. Unlike :class:`Pool`, *maxtasksperchild* and *context* cannot be provided. - .. note:: + .. note:: - A :class:`ThreadPool` shares the same interface as :class:`Pool`, which - is designed around a pool of processes and predates the introduction of - the :class:`concurrent.futures` module. As such, it inherits some - operations that don't make sense for a pool backed by threads, and it - has its own type for representing the status of asynchronous jobs, - :class:`AsyncResult`, that is not understood by any other libraries. - - Users should generally prefer to use - :class:`concurrent.futures.ThreadPoolExecutor`, which has a simpler - interface that was designed around threads from the start, and which - returns :class:`concurrent.futures.Future` instances that are - compatible with many other libraries, including :mod:`asyncio`. + A :class:`ThreadPool` shares the same interface as :class:`Pool`, which + is designed around a pool of processes and predates the introduction of + the :class:`concurrent.futures` module. As such, it inherits some + operations that don't make sense for a pool backed by threads, and it + has its own type for representing the status of asynchronous jobs, + :class:`AsyncResult`, that is not understood by any other libraries. + + Users should generally prefer to use + :class:`concurrent.futures.ThreadPoolExecutor`, which has a simpler + interface that was designed around threads from the start, and which + returns :class:`concurrent.futures.Future` instances that are + compatible with many other libraries, including :mod:`asyncio`. .. _multiprocessing-programming: diff --git a/Doc/library/numbers.rst b/Doc/library/numbers.rst index b3dce151aee289..2a05b56db051f9 100644 --- a/Doc/library/numbers.rst +++ b/Doc/library/numbers.rst @@ -160,23 +160,23 @@ refer to ``MyIntegral`` and ``OtherTypeIKnowAbout`` as of :class:`Complex` (``a : A <: Complex``), and ``b : B <: Complex``. I'll consider ``a + b``: - 1. If ``A`` defines an :meth:`__add__` which accepts ``b``, all is - well. - 2. If ``A`` falls back to the boilerplate code, and it were to - return a value from :meth:`__add__`, we'd miss the possibility - that ``B`` defines a more intelligent :meth:`__radd__`, so the - boilerplate should return :const:`NotImplemented` from - :meth:`__add__`. (Or ``A`` may not implement :meth:`__add__` at - all.) - 3. Then ``B``'s :meth:`__radd__` gets a chance. If it accepts - ``a``, all is well. - 4. If it falls back to the boilerplate, there are no more possible - methods to try, so this is where the default implementation - should live. - 5. If ``B <: A``, Python tries ``B.__radd__`` before - ``A.__add__``. This is ok, because it was implemented with - knowledge of ``A``, so it can handle those instances before - delegating to :class:`Complex`. +1. If ``A`` defines an :meth:`__add__` which accepts ``b``, all is + well. +2. If ``A`` falls back to the boilerplate code, and it were to + return a value from :meth:`__add__`, we'd miss the possibility + that ``B`` defines a more intelligent :meth:`__radd__`, so the + boilerplate should return :const:`NotImplemented` from + :meth:`__add__`. (Or ``A`` may not implement :meth:`__add__` at + all.) +3. Then ``B``'s :meth:`__radd__` gets a chance. If it accepts + ``a``, all is well. +4. If it falls back to the boilerplate, there are no more possible + methods to try, so this is where the default implementation + should live. +5. If ``B <: A``, Python tries ``B.__radd__`` before + ``A.__add__``. This is ok, because it was implemented with + knowledge of ``A``, so it can handle those instances before + delegating to :class:`Complex`. If ``A <: Complex`` and ``B <: Real`` without sharing any other knowledge, then the appropriate shared operation is the one involving the built diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index 69274b0c354a25..4c60a1e0d781b0 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -135,11 +135,11 @@ the output by. This only applies when ``-o`` is not supplied. ``-m`` specifies that a module is being profiled instead of a script. - .. versionadded:: 3.7 - Added the ``-m`` option to :mod:`cProfile`. +.. versionadded:: 3.7 + Added the ``-m`` option to :mod:`cProfile`. - .. versionadded:: 3.8 - Added the ``-m`` option to :mod:`profile`. +.. versionadded:: 3.8 + Added the ``-m`` option to :mod:`profile`. The :mod:`pstats` module's :class:`~pstats.Stats` class has a variety of methods for manipulating and printing the data saved into a profile results file:: diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 92aae10030f8a2..bb1c3132ba8230 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -176,7 +176,7 @@ The special characters are: ``x*+``, ``x++`` and ``x?+`` are equivalent to ``(?>x*)``, ``(?>x+)`` and ``(?>x?)`` correspondingly. - .. versionadded:: 3.11 + .. versionadded:: 3.11 .. index:: single: {} (curly brackets); in regular expressions diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index 01314f491f47a7..219219af6fd87f 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -94,9 +94,9 @@ Two additional methods are supported: Restrictions ------------ - .. index:: - pair: module; dbm.ndbm - pair: module; dbm.gnu +.. index:: + pair: module; dbm.ndbm + pair: module; dbm.gnu * The choice of which database package will be used (such as :mod:`dbm.ndbm` or :mod:`dbm.gnu`) depends on which interface is available. Therefore it is not diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 7fb47ce2b84593..c3cf48316b3248 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -207,14 +207,14 @@ created. Socket addresses are represented as follows: - *addr* - Optional bytes-like object specifying the hardware physical address, whose interpretation depends on the device. - .. availability:: Linux >= 2.2. + .. availability:: Linux >= 2.2. - :const:`AF_QIPCRTR` is a Linux-only socket based interface for communicating with services running on co-processors in Qualcomm platforms. The address family is represented as a ``(node, port)`` tuple where the *node* and *port* are non-negative integers. - .. availability:: Linux >= 4.7. + .. availability:: Linux >= 4.7. .. versionadded:: 3.8 diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 43921c34232924..87ea4658d16752 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -235,11 +235,11 @@ inserted data and retrieved values from it in multiple ways. * :ref:`sqlite3-howtos` for further reading: - * :ref:`sqlite3-placeholders` - * :ref:`sqlite3-adapters` - * :ref:`sqlite3-converters` - * :ref:`sqlite3-connection-context-manager` - * :ref:`sqlite3-howto-row-factory` + * :ref:`sqlite3-placeholders` + * :ref:`sqlite3-adapters` + * :ref:`sqlite3-converters` + * :ref:`sqlite3-connection-context-manager` + * :ref:`sqlite3-howto-row-factory` * :ref:`sqlite3-explanation` for in-depth background on transaction control. @@ -523,13 +523,13 @@ Module constants the default `threading mode `_ the underlying SQLite library is compiled with. The SQLite threading modes are: - 1. **Single-thread**: In this mode, all mutexes are disabled and SQLite is - unsafe to use in more than a single thread at once. - 2. **Multi-thread**: In this mode, SQLite can be safely used by multiple - threads provided that no single database connection is used - simultaneously in two or more threads. - 3. **Serialized**: In serialized mode, SQLite can be safely used by - multiple threads with no restriction. + 1. **Single-thread**: In this mode, all mutexes are disabled and SQLite is + unsafe to use in more than a single thread at once. + 2. **Multi-thread**: In this mode, SQLite can be safely used by multiple + threads provided that no single database connection is used + simultaneously in two or more threads. + 3. **Serialized**: In serialized mode, SQLite can be safely used by + multiple threads with no restriction. The mappings from SQLite threading modes to DB-API 2.0 threadsafety levels are as follows: diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 5d6bc829d68878..94d19507dab8e2 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1380,18 +1380,18 @@ to speed up repeated connections from the same clients. Here's a table showing which versions in a client (down the side) can connect to which versions in a server (along the top): - .. table:: - - ======================== ============ ============ ============= ========= =========== =========== - *client* / **server** **SSLv2** **SSLv3** **TLS** [3]_ **TLSv1** **TLSv1.1** **TLSv1.2** - ------------------------ ------------ ------------ ------------- --------- ----------- ----------- - *SSLv2* yes no no [1]_ no no no - *SSLv3* no yes no [2]_ no no no - *TLS* (*SSLv23*) [3]_ no [1]_ no [2]_ yes yes yes yes - *TLSv1* no no yes yes no no - *TLSv1.1* no no yes no yes no - *TLSv1.2* no no yes no no yes - ======================== ============ ============ ============= ========= =========== =========== + .. table:: + + ======================== ============ ============ ============= ========= =========== =========== + *client* / **server** **SSLv2** **SSLv3** **TLS** [3]_ **TLSv1** **TLSv1.1** **TLSv1.2** + ------------------------ ------------ ------------ ------------- --------- ----------- ----------- + *SSLv2* yes no no [1]_ no no no + *SSLv3* no yes no [2]_ no no no + *TLS* (*SSLv23*) [3]_ no [1]_ no [2]_ yes yes yes yes + *TLSv1* no no yes yes no no + *TLSv1.1* no no yes no yes no + *TLSv1.2* no no yes no no yes + ======================== ============ ============ ============= ========= =========== =========== .. rubric:: Footnotes .. [1] :class:`SSLContext` disables SSLv2 with :data:`OP_NO_SSLv2` by default. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 5e10f696173405..46ae60583df7d7 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -48,9 +48,9 @@ By default, an object is considered true unless its class defines either a returns zero, when called with the object. [1]_ Here are most of the built-in objects considered false: - .. index:: - single: None (Built-in object) - single: False (Built-in object) +.. index:: + single: None (Built-in object) + single: False (Built-in object) * constants defined to be false: ``None`` and ``False`` diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 9b28f99536a3ae..262b785bbcbfc1 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -206,15 +206,15 @@ literal text, it can be escaped by doubling: ``{{`` and ``}}``. The grammar for a replacement field is as follows: - .. productionlist:: format-string - replacement_field: "{" [`field_name`] ["!" `conversion`] [":" `format_spec`] "}" - field_name: arg_name ("." `attribute_name` | "[" `element_index` "]")* - arg_name: [`identifier` | `digit`+] - attribute_name: `identifier` - element_index: `digit`+ | `index_string` - index_string: + - conversion: "r" | "s" | "a" - format_spec: +.. productionlist:: format-string + replacement_field: "{" [`field_name`] ["!" `conversion`] [":" `format_spec`] "}" + field_name: arg_name ("." `attribute_name` | "[" `element_index` "]")* + arg_name: [`identifier` | `digit`+] + attribute_name: `identifier` + element_index: `digit`+ | `index_string` + index_string: + + conversion: "r" | "s" | "a" + format_spec: In less formal terms, the replacement field can start with a *field_name* that specifies the object whose value is to be formatted and inserted @@ -332,30 +332,30 @@ affect the :func:`format` function. The meaning of the various alignment options is as follows: - .. index:: - single: < (less); in string formatting - single: > (greater); in string formatting - single: = (equals); in string formatting - single: ^ (caret); in string formatting - - +---------+----------------------------------------------------------+ - | Option | Meaning | - +=========+==========================================================+ - | ``'<'`` | Forces the field to be left-aligned within the available | - | | space (this is the default for most objects). | - +---------+----------------------------------------------------------+ - | ``'>'`` | Forces the field to be right-aligned within the | - | | available space (this is the default for numbers). | - +---------+----------------------------------------------------------+ - | ``'='`` | Forces the padding to be placed after the sign (if any) | - | | but before the digits. This is used for printing fields | - | | in the form '+000000120'. This alignment option is only | - | | valid for numeric types. It becomes the default for | - | | numbers when '0' immediately precedes the field width. | - +---------+----------------------------------------------------------+ - | ``'^'`` | Forces the field to be centered within the available | - | | space. | - +---------+----------------------------------------------------------+ +.. index:: + single: < (less); in string formatting + single: > (greater); in string formatting + single: = (equals); in string formatting + single: ^ (caret); in string formatting + ++---------+----------------------------------------------------------+ +| Option | Meaning | ++=========+==========================================================+ +| ``'<'`` | Forces the field to be left-aligned within the available | +| | space (this is the default for most objects). | ++---------+----------------------------------------------------------+ +| ``'>'`` | Forces the field to be right-aligned within the | +| | available space (this is the default for numbers). | ++---------+----------------------------------------------------------+ +| ``'='`` | Forces the padding to be placed after the sign (if any) | +| | but before the digits. This is used for printing fields | +| | in the form '+000000120'. This alignment option is only | +| | valid for numeric types. It becomes the default for | +| | numbers when '0' immediately precedes the field width. | ++---------+----------------------------------------------------------+ +| ``'^'`` | Forces the field to be centered within the available | +| | space. | ++---------+----------------------------------------------------------+ Note that unless a minimum field width is defined, the field width will always be the same size as the data to fill it, so that the alignment option has no @@ -364,23 +364,23 @@ meaning in this case. The *sign* option is only valid for number types, and can be one of the following: - .. index:: - single: + (plus); in string formatting - single: - (minus); in string formatting - single: space; in string formatting - - +---------+----------------------------------------------------------+ - | Option | Meaning | - +=========+==========================================================+ - | ``'+'`` | indicates that a sign should be used for both | - | | positive as well as negative numbers. | - +---------+----------------------------------------------------------+ - | ``'-'`` | indicates that a sign should be used only for negative | - | | numbers (this is the default behavior). | - +---------+----------------------------------------------------------+ - | space | indicates that a leading space should be used on | - | | positive numbers, and a minus sign on negative numbers. | - +---------+----------------------------------------------------------+ +.. index:: + single: + (plus); in string formatting + single: - (minus); in string formatting + single: space; in string formatting + ++---------+----------------------------------------------------------+ +| Option | Meaning | ++=========+==========================================================+ +| ``'+'`` | indicates that a sign should be used for both | +| | positive as well as negative numbers. | ++---------+----------------------------------------------------------+ +| ``'-'`` | indicates that a sign should be used only for negative | +| | numbers (this is the default behavior). | ++---------+----------------------------------------------------------+ +| space | indicates that a leading space should be used on | +| | positive numbers, and a minus sign on negative numbers. | ++---------+----------------------------------------------------------+ .. index:: single: z; in string formatting diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 04340cca9e4a59..7f22a5d1852a89 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -666,18 +666,18 @@ functions. passed to the underlying ``CreateProcess`` function. *creationflags*, if given, can be one or more of the following flags: - * :data:`CREATE_NEW_CONSOLE` - * :data:`CREATE_NEW_PROCESS_GROUP` - * :data:`ABOVE_NORMAL_PRIORITY_CLASS` - * :data:`BELOW_NORMAL_PRIORITY_CLASS` - * :data:`HIGH_PRIORITY_CLASS` - * :data:`IDLE_PRIORITY_CLASS` - * :data:`NORMAL_PRIORITY_CLASS` - * :data:`REALTIME_PRIORITY_CLASS` - * :data:`CREATE_NO_WINDOW` - * :data:`DETACHED_PROCESS` - * :data:`CREATE_DEFAULT_ERROR_MODE` - * :data:`CREATE_BREAKAWAY_FROM_JOB` + * :data:`CREATE_NEW_CONSOLE` + * :data:`CREATE_NEW_PROCESS_GROUP` + * :data:`ABOVE_NORMAL_PRIORITY_CLASS` + * :data:`BELOW_NORMAL_PRIORITY_CLASS` + * :data:`HIGH_PRIORITY_CLASS` + * :data:`IDLE_PRIORITY_CLASS` + * :data:`NORMAL_PRIORITY_CLASS` + * :data:`REALTIME_PRIORITY_CLASS` + * :data:`CREATE_NO_WINDOW` + * :data:`DETACHED_PROCESS` + * :data:`CREATE_DEFAULT_ERROR_MODE` + * :data:`CREATE_BREAKAWAY_FROM_JOB` *pipesize* can be used to change the size of the pipe when :data:`PIPE` is used for *stdin*, *stdout* or *stderr*. The size of the pipe @@ -742,8 +742,8 @@ the timeout expires before the process exits. Exceptions defined in this module all inherit from :exc:`SubprocessError`. - .. versionadded:: 3.3 - The :exc:`SubprocessError` base class was added. +.. versionadded:: 3.3 + The :exc:`SubprocessError` base class was added. .. _subprocess-security: diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index 097f7087eccab9..42314648fec2bd 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -115,14 +115,14 @@ The module defines the following user-callable items: * On Windows, make sure that at least one of the following conditions are fulfilled: - * *delete* is false - * additional open shares delete access (e.g. by calling :func:`os.open` - with the flag ``O_TEMPORARY``) - * *delete* is true but *delete_on_close* is false. Note, that in this - case the additional opens that do not share delete access (e.g. - created via builtin :func:`open`) must be closed before exiting the - context manager, else the :func:`os.unlink` call on context manager - exit will fail with a :exc:`PermissionError`. + * *delete* is false + * additional open shares delete access (e.g. by calling :func:`os.open` + with the flag ``O_TEMPORARY``) + * *delete* is true but *delete_on_close* is false. Note, that in this + case the additional opens that do not share delete access (e.g. + created via builtin :func:`open`) must be closed before exiting the + context manager, else the :func:`os.unlink` call on context manager + exit will fail with a :exc:`PermissionError`. On Windows, if *delete_on_close* is false, and the file is created in a directory for which the user lacks delete access, then the :func:`os.unlink` diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 246abf374b0219..ee34f2659cf3d8 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -533,24 +533,24 @@ interpreter will fail. A number of special cases exist: - * Tcl/Tk libraries can be built so they are not thread-aware. In this case, - :mod:`tkinter` calls the library from the originating Python thread, even - if this is different than the thread that created the Tcl interpreter. A global - lock ensures only one call occurs at a time. - - * While :mod:`tkinter` allows you to create more than one instance of a :class:`Tk` - object (with its own interpreter), all interpreters that are part of the same - thread share a common event queue, which gets ugly fast. In practice, don't create - more than one instance of :class:`Tk` at a time. Otherwise, it's best to create - them in separate threads and ensure you're running a thread-aware Tcl/Tk build. - - * Blocking event handlers are not the only way to prevent the Tcl interpreter from - reentering the event loop. It is even possible to run multiple nested event loops - or abandon the event loop entirely. If you're doing anything tricky when it comes - to events or threads, be aware of these possibilities. - - * There are a few select :mod:`tkinter` functions that presently work only when - called from the thread that created the Tcl interpreter. +* Tcl/Tk libraries can be built so they are not thread-aware. In this case, + :mod:`tkinter` calls the library from the originating Python thread, even + if this is different than the thread that created the Tcl interpreter. A global + lock ensures only one call occurs at a time. + +* While :mod:`tkinter` allows you to create more than one instance of a :class:`Tk` + object (with its own interpreter), all interpreters that are part of the same + thread share a common event queue, which gets ugly fast. In practice, don't create + more than one instance of :class:`Tk` at a time. Otherwise, it's best to create + them in separate threads and ensure you're running a thread-aware Tcl/Tk build. + +* Blocking event handlers are not the only way to prevent the Tcl interpreter from + reentering the event loop. It is even possible to run multiple nested event loops + or abandon the event loop entirely. If you're doing anything tricky when it comes + to events or threads, be aware of these possibilities. + +* There are a few select :mod:`tkinter` functions that presently work only when + called from the thread that created the Tcl interpreter. Handy Reference diff --git a/Doc/library/tkinter.ttk.rst b/Doc/library/tkinter.ttk.rst index 9f2f9eb858afd4..dc31a1a4c1850a 100644 --- a/Doc/library/tkinter.ttk.rst +++ b/Doc/library/tkinter.ttk.rst @@ -104,33 +104,33 @@ Standard Options All the :mod:`ttk` Widgets accept the following options: - .. tabularcolumns:: |l|L| - - +-----------+--------------------------------------------------------------+ - | Option | Description | - +===========+==============================================================+ - | class | Specifies the window class. The class is used when querying | - | | the option database for the window's other options, to | - | | determine the default bindtags for the window, and to select | - | | the widget's default layout and style. This option is | - | | read-only, and may only be specified when the window is | - | | created. | - +-----------+--------------------------------------------------------------+ - | cursor | Specifies the mouse cursor to be used for the widget. If set | - | | to the empty string (the default), the cursor is inherited | - | | for the parent widget. | - +-----------+--------------------------------------------------------------+ - | takefocus | Determines whether the window accepts the focus during | - | | keyboard traversal. 0, 1 or an empty string is returned. | - | | If 0 is returned, it means that the window should be skipped | - | | entirely during keyboard traversal. If 1, it means that the | - | | window should receive the input focus as long as it is | - | | viewable. And an empty string means that the traversal | - | | scripts make the decision about whether or not to focus | - | | on the window. | - +-----------+--------------------------------------------------------------+ - | style | May be used to specify a custom widget style. | - +-----------+--------------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++-----------+--------------------------------------------------------------+ +| Option | Description | ++===========+==============================================================+ +| class | Specifies the window class. The class is used when querying | +| | the option database for the window's other options, to | +| | determine the default bindtags for the window, and to select | +| | the widget's default layout and style. This option is | +| | read-only, and may only be specified when the window is | +| | created. | ++-----------+--------------------------------------------------------------+ +| cursor | Specifies the mouse cursor to be used for the widget. If set | +| | to the empty string (the default), the cursor is inherited | +| | for the parent widget. | ++-----------+--------------------------------------------------------------+ +| takefocus | Determines whether the window accepts the focus during | +| | keyboard traversal. 0, 1 or an empty string is returned. | +| | If 0 is returned, it means that the window should be skipped | +| | entirely during keyboard traversal. If 1, it means that the | +| | window should receive the input focus as long as it is | +| | viewable. And an empty string means that the traversal | +| | scripts make the decision about whether or not to focus | +| | on the window. | ++-----------+--------------------------------------------------------------+ +| style | May be used to specify a custom widget style. | ++-----------+--------------------------------------------------------------+ Scrollable Widget Options @@ -139,24 +139,24 @@ Scrollable Widget Options The following options are supported by widgets that are controlled by a scrollbar. - .. tabularcolumns:: |l|L| - - +----------------+---------------------------------------------------------+ - | Option | Description | - +================+=========================================================+ - | xscrollcommand | Used to communicate with horizontal scrollbars. | - | | | - | | When the view in the widget's window change, the widget | - | | will generate a Tcl command based on the scrollcommand. | - | | | - | | Usually this option consists of the method | - | | :meth:`Scrollbar.set` of some scrollbar. This will cause| - | | the scrollbar to be updated whenever the view in the | - | | window changes. | - +----------------+---------------------------------------------------------+ - | yscrollcommand | Used to communicate with vertical scrollbars. | - | | For some more information, see above. | - +----------------+---------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++----------------+---------------------------------------------------------+ +| Option | Description | ++================+=========================================================+ +| xscrollcommand | Used to communicate with horizontal scrollbars. | +| | | +| | When the view in the widget's window change, the widget | +| | will generate a Tcl command based on the scrollcommand. | +| | | +| | Usually this option consists of the method | +| | :meth:`Scrollbar.set` of some scrollbar. This will cause| +| | the scrollbar to be updated whenever the view in the | +| | window changes. | ++----------------+---------------------------------------------------------+ +| yscrollcommand | Used to communicate with vertical scrollbars. | +| | For some more information, see above. | ++----------------+---------------------------------------------------------+ Label Options @@ -165,93 +165,93 @@ Label Options The following options are supported by labels, buttons and other button-like widgets. - .. tabularcolumns:: |l|p{0.7\linewidth}| - - +--------------+-----------------------------------------------------------+ - | Option | Description | - +==============+===========================================================+ - | text | Specifies a text string to be displayed inside the widget.| - +--------------+-----------------------------------------------------------+ - | textvariable | Specifies a name whose value will be used in place of the | - | | text option resource. | - +--------------+-----------------------------------------------------------+ - | underline | If set, specifies the index (0-based) of a character to | - | | underline in the text string. The underline character is | - | | used for mnemonic activation. | - +--------------+-----------------------------------------------------------+ - | image | Specifies an image to display. This is a list of 1 or more| - | | elements. The first element is the default image name. The| - | | rest of the list if a sequence of statespec/value pairs as| - | | defined by :meth:`Style.map`, specifying different images | - | | to use when the widget is in a particular state or a | - | | combination of states. All images in the list should have | - | | the same size. | - +--------------+-----------------------------------------------------------+ - | compound | Specifies how to display the image relative to the text, | - | | in the case both text and images options are present. | - | | Valid values are: | - | | | - | | * text: display text only | - | | * image: display image only | - | | * top, bottom, left, right: display image above, below, | - | | left of, or right of the text, respectively. | - | | * none: the default. display the image if present, | - | | otherwise the text. | - +--------------+-----------------------------------------------------------+ - | width | If greater than zero, specifies how much space, in | - | | character widths, to allocate for the text label, if less | - | | than zero, specifies a minimum width. If zero or | - | | unspecified, the natural width of the text label is used. | - +--------------+-----------------------------------------------------------+ +.. tabularcolumns:: |l|p{0.7\linewidth}| + ++--------------+-----------------------------------------------------------+ +| Option | Description | ++==============+===========================================================+ +| text | Specifies a text string to be displayed inside the widget.| ++--------------+-----------------------------------------------------------+ +| textvariable | Specifies a name whose value will be used in place of the | +| | text option resource. | ++--------------+-----------------------------------------------------------+ +| underline | If set, specifies the index (0-based) of a character to | +| | underline in the text string. The underline character is | +| | used for mnemonic activation. | ++--------------+-----------------------------------------------------------+ +| image | Specifies an image to display. This is a list of 1 or more| +| | elements. The first element is the default image name. The| +| | rest of the list if a sequence of statespec/value pairs as| +| | defined by :meth:`Style.map`, specifying different images | +| | to use when the widget is in a particular state or a | +| | combination of states. All images in the list should have | +| | the same size. | ++--------------+-----------------------------------------------------------+ +| compound | Specifies how to display the image relative to the text, | +| | in the case both text and images options are present. | +| | Valid values are: | +| | | +| | * text: display text only | +| | * image: display image only | +| | * top, bottom, left, right: display image above, below, | +| | left of, or right of the text, respectively. | +| | * none: the default. display the image if present, | +| | otherwise the text. | ++--------------+-----------------------------------------------------------+ +| width | If greater than zero, specifies how much space, in | +| | character widths, to allocate for the text label, if less | +| | than zero, specifies a minimum width. If zero or | +| | unspecified, the natural width of the text label is used. | ++--------------+-----------------------------------------------------------+ Compatibility Options ^^^^^^^^^^^^^^^^^^^^^ - .. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L| - +--------+----------------------------------------------------------------+ - | Option | Description | - +========+================================================================+ - | state | May be set to "normal" or "disabled" to control the "disabled" | - | | state bit. This is a write-only option: setting it changes the | - | | widget state, but the :meth:`Widget.state` method does not | - | | affect this option. | - +--------+----------------------------------------------------------------+ ++--------+----------------------------------------------------------------+ +| Option | Description | ++========+================================================================+ +| state | May be set to "normal" or "disabled" to control the "disabled" | +| | state bit. This is a write-only option: setting it changes the | +| | widget state, but the :meth:`Widget.state` method does not | +| | affect this option. | ++--------+----------------------------------------------------------------+ Widget States ^^^^^^^^^^^^^ The widget state is a bitmap of independent state flags. - .. tabularcolumns:: |l|L| - - +------------+-------------------------------------------------------------+ - | Flag | Description | - +============+=============================================================+ - | active | The mouse cursor is over the widget and pressing a mouse | - | | button will cause some action to occur | - +------------+-------------------------------------------------------------+ - | disabled | Widget is disabled under program control | - +------------+-------------------------------------------------------------+ - | focus | Widget has keyboard focus | - +------------+-------------------------------------------------------------+ - | pressed | Widget is being pressed | - +------------+-------------------------------------------------------------+ - | selected | "On", "true", or "current" for things like Checkbuttons and | - | | radiobuttons | - +------------+-------------------------------------------------------------+ - | background | Windows and Mac have a notion of an "active" or foreground | - | | window. The *background* state is set for widgets in a | - | | background window, and cleared for those in the foreground | - | | window | - +------------+-------------------------------------------------------------+ - | readonly | Widget should not allow user modification | - +------------+-------------------------------------------------------------+ - | alternate | A widget-specific alternate display format | - +------------+-------------------------------------------------------------+ - | invalid | The widget's value is invalid | - +------------+-------------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++------------+-------------------------------------------------------------+ +| Flag | Description | ++============+=============================================================+ +| active | The mouse cursor is over the widget and pressing a mouse | +| | button will cause some action to occur | ++------------+-------------------------------------------------------------+ +| disabled | Widget is disabled under program control | ++------------+-------------------------------------------------------------+ +| focus | Widget has keyboard focus | ++------------+-------------------------------------------------------------+ +| pressed | Widget is being pressed | ++------------+-------------------------------------------------------------+ +| selected | "On", "true", or "current" for things like Checkbuttons and | +| | radiobuttons | ++------------+-------------------------------------------------------------+ +| background | Windows and Mac have a notion of an "active" or foreground | +| | window. The *background* state is set for widgets in a | +| | background window, and cleared for those in the foreground | +| | window | ++------------+-------------------------------------------------------------+ +| readonly | Widget should not allow user modification | ++------------+-------------------------------------------------------------+ +| alternate | A widget-specific alternate display format | ++------------+-------------------------------------------------------------+ +| invalid | The widget's value is invalid | ++------------+-------------------------------------------------------------+ A state specification is a sequence of state names, optionally prefixed with an exclamation point indicating that the bit is off. @@ -311,43 +311,43 @@ Options This widget accepts the following specific options: - .. tabularcolumns:: |l|L| - - +-----------------+--------------------------------------------------------+ - | Option | Description | - +=================+========================================================+ - | exportselection | Boolean value. If set, the widget selection is linked | - | | to the Window Manager selection (which can be returned | - | | by invoking Misc.selection_get, for example). | - +-----------------+--------------------------------------------------------+ - | justify | Specifies how the text is aligned within the widget. | - | | One of "left", "center", or "right". | - +-----------------+--------------------------------------------------------+ - | height | Specifies the height of the pop-down listbox, in rows. | - +-----------------+--------------------------------------------------------+ - | postcommand | A script (possibly registered with Misc.register) that | - | | is called immediately before displaying the values. It | - | | may specify which values to display. | - +-----------------+--------------------------------------------------------+ - | state | One of "normal", "readonly", or "disabled". In the | - | | "readonly" state, the value may not be edited directly,| - | | and the user can only selection of the values from the | - | | dropdown list. In the "normal" state, the text field is| - | | directly editable. In the "disabled" state, no | - | | interaction is possible. | - +-----------------+--------------------------------------------------------+ - | textvariable | Specifies a name whose value is linked to the widget | - | | value. Whenever the value associated with that name | - | | changes, the widget value is updated, and vice versa. | - | | See :class:`tkinter.StringVar`. | - +-----------------+--------------------------------------------------------+ - | values | Specifies the list of values to display in the | - | | drop-down listbox. | - +-----------------+--------------------------------------------------------+ - | width | Specifies an integer value indicating the desired width| - | | of the entry window, in average-size characters of the | - | | widget's font. | - +-----------------+--------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++-----------------+--------------------------------------------------------+ +| Option | Description | ++=================+========================================================+ +| exportselection | Boolean value. If set, the widget selection is linked | +| | to the Window Manager selection (which can be returned | +| | by invoking Misc.selection_get, for example). | ++-----------------+--------------------------------------------------------+ +| justify | Specifies how the text is aligned within the widget. | +| | One of "left", "center", or "right". | ++-----------------+--------------------------------------------------------+ +| height | Specifies the height of the pop-down listbox, in rows. | ++-----------------+--------------------------------------------------------+ +| postcommand | A script (possibly registered with Misc.register) that | +| | is called immediately before displaying the values. It | +| | may specify which values to display. | ++-----------------+--------------------------------------------------------+ +| state | One of "normal", "readonly", or "disabled". In the | +| | "readonly" state, the value may not be edited directly,| +| | and the user can only selection of the values from the | +| | dropdown list. In the "normal" state, the text field is| +| | directly editable. In the "disabled" state, no | +| | interaction is possible. | ++-----------------+--------------------------------------------------------+ +| textvariable | Specifies a name whose value is linked to the widget | +| | value. Whenever the value associated with that name | +| | changes, the widget value is updated, and vice versa. | +| | See :class:`tkinter.StringVar`. | ++-----------------+--------------------------------------------------------+ +| values | Specifies the list of values to display in the | +| | drop-down listbox. | ++-----------------+--------------------------------------------------------+ +| width | Specifies an integer value indicating the desired width| +| | of the entry window, in average-size characters of the | +| | widget's font. | ++-----------------+--------------------------------------------------------+ Virtual events @@ -397,7 +397,7 @@ Options This widget accepts the following specific options: - .. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L| +----------------------+------------------------------------------------------+ | Option | Description | @@ -473,25 +473,25 @@ Options This widget accepts the following specific options: - .. tabularcolumns:: |l|L| - - +---------+----------------------------------------------------------------+ - | Option | Description | - +=========+================================================================+ - | height | If present and greater than zero, specifies the desired height | - | | of the pane area (not including internal padding or tabs). | - | | Otherwise, the maximum height of all panes is used. | - +---------+----------------------------------------------------------------+ - | padding | Specifies the amount of extra space to add around the outside | - | | of the notebook. The padding is a list up to four length | - | | specifications left top right bottom. If fewer than four | - | | elements are specified, bottom defaults to top, right defaults | - | | to left, and top defaults to left. | - +---------+----------------------------------------------------------------+ - | width | If present and greater than zero, specified the desired width | - | | of the pane area (not including internal padding). Otherwise, | - | | the maximum width of all panes is used. | - +---------+----------------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++---------+----------------------------------------------------------------+ +| Option | Description | ++=========+================================================================+ +| height | If present and greater than zero, specifies the desired height | +| | of the pane area (not including internal padding or tabs). | +| | Otherwise, the maximum height of all panes is used. | ++---------+----------------------------------------------------------------+ +| padding | Specifies the amount of extra space to add around the outside | +| | of the notebook. The padding is a list up to four length | +| | specifications left top right bottom. If fewer than four | +| | elements are specified, bottom defaults to top, right defaults | +| | to left, and top defaults to left. | ++---------+----------------------------------------------------------------+ +| width | If present and greater than zero, specified the desired width | +| | of the pane area (not including internal padding). Otherwise, | +| | the maximum width of all panes is used. | ++---------+----------------------------------------------------------------+ Tab Options @@ -499,39 +499,39 @@ Tab Options There are also specific options for tabs: - .. tabularcolumns:: |l|L| - - +-----------+--------------------------------------------------------------+ - | Option | Description | - +===========+==============================================================+ - | state | Either "normal", "disabled" or "hidden". If "disabled", then | - | | the tab is not selectable. If "hidden", then the tab is not | - | | shown. | - +-----------+--------------------------------------------------------------+ - | sticky | Specifies how the child window is positioned within the pane | - | | area. Value is a string containing zero or more of the | - | | characters "n", "s", "e" or "w". Each letter refers to a | - | | side (north, south, east or west) that the child window will | - | | stick to, as per the :meth:`grid` geometry manager. | - +-----------+--------------------------------------------------------------+ - | padding | Specifies the amount of extra space to add between the | - | | notebook and this pane. Syntax is the same as for the option | - | | padding used by this widget. | - +-----------+--------------------------------------------------------------+ - | text | Specifies a text to be displayed in the tab. | - +-----------+--------------------------------------------------------------+ - | image | Specifies an image to display in the tab. See the option | - | | image described in :class:`Widget`. | - +-----------+--------------------------------------------------------------+ - | compound | Specifies how to display the image relative to the text, in | - | | the case both options text and image are present. See | - | | `Label Options`_ for legal values. | - +-----------+--------------------------------------------------------------+ - | underline | Specifies the index (0-based) of a character to underline in | - | | the text string. The underlined character is used for | - | | mnemonic activation if :meth:`Notebook.enable_traversal` is | - | | called. | - +-----------+--------------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++-----------+--------------------------------------------------------------+ +| Option | Description | ++===========+==============================================================+ +| state | Either "normal", "disabled" or "hidden". If "disabled", then | +| | the tab is not selectable. If "hidden", then the tab is not | +| | shown. | ++-----------+--------------------------------------------------------------+ +| sticky | Specifies how the child window is positioned within the pane | +| | area. Value is a string containing zero or more of the | +| | characters "n", "s", "e" or "w". Each letter refers to a | +| | side (north, south, east or west) that the child window will | +| | stick to, as per the :meth:`grid` geometry manager. | ++-----------+--------------------------------------------------------------+ +| padding | Specifies the amount of extra space to add between the | +| | notebook and this pane. Syntax is the same as for the option | +| | padding used by this widget. | ++-----------+--------------------------------------------------------------+ +| text | Specifies a text to be displayed in the tab. | ++-----------+--------------------------------------------------------------+ +| image | Specifies an image to display in the tab. See the option | +| | image described in :class:`Widget`. | ++-----------+--------------------------------------------------------------+ +| compound | Specifies how to display the image relative to the text, in | +| | the case both options text and image are present. See | +| | `Label Options`_ for legal values. | ++-----------+--------------------------------------------------------------+ +| underline | Specifies the index (0-based) of a character to underline in | +| | the text string. The underlined character is used for | +| | mnemonic activation if :meth:`Notebook.enable_traversal` is | +| | called. | ++-----------+--------------------------------------------------------------+ Tab Identifiers @@ -663,36 +663,36 @@ Options This widget accepts the following specific options: - .. tabularcolumns:: |l|L| - - +----------+---------------------------------------------------------------+ - | Option | Description | - +==========+===============================================================+ - | orient | One of "horizontal" or "vertical". Specifies the orientation | - | | of the progress bar. | - +----------+---------------------------------------------------------------+ - | length | Specifies the length of the long axis of the progress bar | - | | (width if horizontal, height if vertical). | - +----------+---------------------------------------------------------------+ - | mode | One of "determinate" or "indeterminate". | - +----------+---------------------------------------------------------------+ - | maximum | A number specifying the maximum value. Defaults to 100. | - +----------+---------------------------------------------------------------+ - | value | The current value of the progress bar. In "determinate" mode, | - | | this represents the amount of work completed. In | - | | "indeterminate" mode, it is interpreted as modulo *maximum*; | - | | that is, the progress bar completes one "cycle" when its value| - | | increases by *maximum*. | - +----------+---------------------------------------------------------------+ - | variable | A name which is linked to the option value. If specified, the | - | | value of the progress bar is automatically set to the value of| - | | this name whenever the latter is modified. | - +----------+---------------------------------------------------------------+ - | phase | Read-only option. The widget periodically increments the value| - | | of this option whenever its value is greater than 0 and, in | - | | determinate mode, less than maximum. This option may be used | - | | by the current theme to provide additional animation effects. | - +----------+---------------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++----------+---------------------------------------------------------------+ +| Option | Description | ++==========+===============================================================+ +| orient | One of "horizontal" or "vertical". Specifies the orientation | +| | of the progress bar. | ++----------+---------------------------------------------------------------+ +| length | Specifies the length of the long axis of the progress bar | +| | (width if horizontal, height if vertical). | ++----------+---------------------------------------------------------------+ +| mode | One of "determinate" or "indeterminate". | ++----------+---------------------------------------------------------------+ +| maximum | A number specifying the maximum value. Defaults to 100. | ++----------+---------------------------------------------------------------+ +| value | The current value of the progress bar. In "determinate" mode, | +| | this represents the amount of work completed. In | +| | "indeterminate" mode, it is interpreted as modulo *maximum*; | +| | that is, the progress bar completes one "cycle" when its value| +| | increases by *maximum*. | ++----------+---------------------------------------------------------------+ +| variable | A name which is linked to the option value. If specified, the | +| | value of the progress bar is automatically set to the value of| +| | this name whenever the latter is modified. | ++----------+---------------------------------------------------------------+ +| phase | Read-only option. The widget periodically increments the value| +| | of this option whenever its value is greater than 0 and, in | +| | determinate mode, less than maximum. This option may be used | +| | by the current theme to provide additional animation effects. | ++----------+---------------------------------------------------------------+ ttk.Progressbar @@ -734,14 +734,14 @@ Options This widget accepts the following specific option: - .. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L| - +--------+----------------------------------------------------------------+ - | Option | Description | - +========+================================================================+ - | orient | One of "horizontal" or "vertical". Specifies the orientation of| - | | the separator. | - +--------+----------------------------------------------------------------+ ++--------+----------------------------------------------------------------+ +| Option | Description | ++========+================================================================+ +| orient | One of "horizontal" or "vertical". Specifies the orientation of| +| | the separator. | ++--------+----------------------------------------------------------------+ Sizegrip @@ -802,49 +802,49 @@ Options This widget accepts the following specific options: - .. tabularcolumns:: |l|p{0.7\linewidth}| - - +----------------+--------------------------------------------------------+ - | Option | Description | - +================+========================================================+ - | columns | A list of column identifiers, specifying the number of | - | | columns and their names. | - +----------------+--------------------------------------------------------+ - | displaycolumns | A list of column identifiers (either symbolic or | - | | integer indices) specifying which data columns are | - | | displayed and the order in which they appear, or the | - | | string "#all". | - +----------------+--------------------------------------------------------+ - | height | Specifies the number of rows which should be visible. | - | | Note: the requested width is determined from the sum | - | | of the column widths. | - +----------------+--------------------------------------------------------+ - | padding | Specifies the internal padding for the widget. The | - | | padding is a list of up to four length specifications. | - +----------------+--------------------------------------------------------+ - | selectmode | Controls how the built-in class bindings manage the | - | | selection. One of "extended", "browse" or "none". | - | | If set to "extended" (the default), multiple items may | - | | be selected. If "browse", only a single item will be | - | | selected at a time. If "none", the selection will not | - | | be changed. | - | | | - | | Note that the application code and tag bindings can set| - | | the selection however they wish, regardless of the | - | | value of this option. | - +----------------+--------------------------------------------------------+ - | show | A list containing zero or more of the following values,| - | | specifying which elements of the tree to display. | - | | | - | | * tree: display tree labels in column #0. | - | | * headings: display the heading row. | - | | | - | | The default is "tree headings", i.e., show all | - | | elements. | - | | | - | | **Note**: Column #0 always refers to the tree column, | - | | even if show="tree" is not specified. | - +----------------+--------------------------------------------------------+ +.. tabularcolumns:: |l|p{0.7\linewidth}| + ++----------------+--------------------------------------------------------+ +| Option | Description | ++================+========================================================+ +| columns | A list of column identifiers, specifying the number of | +| | columns and their names. | ++----------------+--------------------------------------------------------+ +| displaycolumns | A list of column identifiers (either symbolic or | +| | integer indices) specifying which data columns are | +| | displayed and the order in which they appear, or the | +| | string "#all". | ++----------------+--------------------------------------------------------+ +| height | Specifies the number of rows which should be visible. | +| | Note: the requested width is determined from the sum | +| | of the column widths. | ++----------------+--------------------------------------------------------+ +| padding | Specifies the internal padding for the widget. The | +| | padding is a list of up to four length specifications. | ++----------------+--------------------------------------------------------+ +| selectmode | Controls how the built-in class bindings manage the | +| | selection. One of "extended", "browse" or "none". | +| | If set to "extended" (the default), multiple items may | +| | be selected. If "browse", only a single item will be | +| | selected at a time. If "none", the selection will not | +| | be changed. | +| | | +| | Note that the application code and tag bindings can set| +| | the selection however they wish, regardless of the | +| | value of this option. | ++----------------+--------------------------------------------------------+ +| show | A list containing zero or more of the following values,| +| | specifying which elements of the tree to display. | +| | | +| | * tree: display tree labels in column #0. | +| | * headings: display the heading row. | +| | | +| | The default is "tree headings", i.e., show all | +| | elements. | +| | | +| | **Note**: Column #0 always refers to the tree column, | +| | even if show="tree" is not specified. | ++----------------+--------------------------------------------------------+ Item Options @@ -853,27 +853,27 @@ Item Options The following item options may be specified for items in the insert and item widget commands. - .. tabularcolumns:: |l|L| - - +--------+---------------------------------------------------------------+ - | Option | Description | - +========+===============================================================+ - | text | The textual label to display for the item. | - +--------+---------------------------------------------------------------+ - | image | A Tk Image, displayed to the left of the label. | - +--------+---------------------------------------------------------------+ - | values | The list of values associated with the item. | - | | | - | | Each item should have the same number of values as the widget | - | | option columns. If there are fewer values than columns, the | - | | remaining values are assumed empty. If there are more values | - | | than columns, the extra values are ignored. | - +--------+---------------------------------------------------------------+ - | open | ``True``/``False`` value indicating whether the item's | - | | children should be displayed or hidden. | - +--------+---------------------------------------------------------------+ - | tags | A list of tags associated with this item. | - +--------+---------------------------------------------------------------+ +.. tabularcolumns:: |l|L| + ++--------+---------------------------------------------------------------+ +| Option | Description | ++========+===============================================================+ +| text | The textual label to display for the item. | ++--------+---------------------------------------------------------------+ +| image | A Tk Image, displayed to the left of the label. | ++--------+---------------------------------------------------------------+ +| values | The list of values associated with the item. | +| | | +| | Each item should have the same number of values as the widget | +| | option columns. If there are fewer values than columns, the | +| | remaining values are assumed empty. If there are more values | +| | than columns, the extra values are ignored. | ++--------+---------------------------------------------------------------+ +| open | ``True``/``False`` value indicating whether the item's | +| | children should be displayed or hidden. | ++--------+---------------------------------------------------------------+ +| tags | A list of tags associated with this item. | ++--------+---------------------------------------------------------------+ Tag Options @@ -881,20 +881,20 @@ Tag Options The following options may be specified on tags: - .. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L| - +------------+-----------------------------------------------------------+ - | Option | Description | - +============+===========================================================+ - | foreground | Specifies the text foreground color. | - +------------+-----------------------------------------------------------+ - | background | Specifies the cell or item background color. | - +------------+-----------------------------------------------------------+ - | font | Specifies the font to use when drawing text. | - +------------+-----------------------------------------------------------+ - | image | Specifies the item image, in case the item's image option | - | | is empty. | - +------------+-----------------------------------------------------------+ ++------------+-----------------------------------------------------------+ +| Option | Description | ++============+===========================================================+ +| foreground | Specifies the text foreground color. | ++------------+-----------------------------------------------------------+ +| background | Specifies the cell or item background color. | ++------------+-----------------------------------------------------------+ +| font | Specifies the font to use when drawing text. | ++------------+-----------------------------------------------------------+ +| image | Specifies the item image, in case the item's image option | +| | is empty. | ++------------+-----------------------------------------------------------+ Column Identifiers @@ -926,19 +926,19 @@ Virtual Events The Treeview widget generates the following virtual events. - .. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L| - +--------------------+--------------------------------------------------+ - | Event | Description | - +====================+==================================================+ - | <> | Generated whenever the selection changes. | - +--------------------+--------------------------------------------------+ - | <> | Generated just before settings the focus item to | - | | open=True. | - +--------------------+--------------------------------------------------+ - | <> | Generated just after setting the focus item to | - | | open=False. | - +--------------------+--------------------------------------------------+ ++--------------------+--------------------------------------------------+ +| Event | Description | ++====================+==================================================+ +| <> | Generated whenever the selection changes. | ++--------------------+--------------------------------------------------+ +| <> | Generated just before settings the focus item to | +| | open=True. | ++--------------------+--------------------------------------------------+ +| <> | Generated just after setting the focus item to | +| | open=False. | ++--------------------+--------------------------------------------------+ The :meth:`Treeview.focus` and :meth:`Treeview.selection` methods can be used to determine the affected item or items. @@ -986,19 +986,19 @@ ttk.Treeview The valid options/values are: - * id + id Returns the column name. This is a read-only option. - * anchor: One of the standard Tk anchor values. + anchor: One of the standard Tk anchor values. Specifies how the text in this column should be aligned with respect to the cell. - * minwidth: width + minwidth: width The minimum width of the column in pixels. The treeview widget will not make the column any smaller than specified by this option when the widget is resized or the user drags a column. - * stretch: ``True``/``False`` + stretch: ``True``/``False`` Specifies whether the column's width should be adjusted when the widget is resized. - * width: width + width: width The width of the column in pixels. To configure the tree column, call this with column = "#0" @@ -1041,14 +1041,14 @@ ttk.Treeview The valid options/values are: - * text: text + text: text The text to display in the column heading. - * image: imageName + image: imageName Specifies an image to display to the right of the column heading. - * anchor: anchor + anchor: anchor Specifies how the heading text should be aligned. One of the standard Tk anchor values. - * command: callback + command: callback A callback to be invoked when the heading label is pressed. To configure the tree column heading, call this with column = "#0". @@ -1398,25 +1398,25 @@ option. If you don't know the class name of a widget, use the method by statespec/value pairs (this is the imagespec), and *kw* may have the following options: - * border=padding - padding is a list of up to four integers, specifying the left, top, - right, and bottom borders, respectively. + border=padding + padding is a list of up to four integers, specifying the left, top, + right, and bottom borders, respectively. - * height=height - Specifies a minimum height for the element. If less than zero, the - base image's height is used as a default. + height=height + Specifies a minimum height for the element. If less than zero, the + base image's height is used as a default. - * padding=padding - Specifies the element's interior padding. Defaults to border's value - if not specified. + padding=padding + Specifies the element's interior padding. Defaults to border's value + if not specified. - * sticky=spec - Specifies how the image is placed within the final parcel. spec - contains zero or more characters "n", "s", "w", or "e". + sticky=spec + Specifies how the image is placed within the final parcel. spec + contains zero or more characters "n", "s", "w", or "e". - * width=width - Specifies a minimum width for the element. If less than zero, the - base image's width is used as a default. + width=width + Specifies a minimum width for the element. If less than zero, the + base image's width is used as a default. If "from" is used as the value of *etype*, :meth:`element_create` will clone an existing @@ -1504,22 +1504,22 @@ uses a simplified version of the pack geometry manager: given an initial cavity, each element is allocated a parcel. Valid options/values are: - * side: whichside - Specifies which side of the cavity to place the element; one of - top, right, bottom or left. If omitted, the element occupies the - entire cavity. +side: whichside + Specifies which side of the cavity to place the element; one of + top, right, bottom or left. If omitted, the element occupies the + entire cavity. - * sticky: nswe - Specifies where the element is placed inside its allocated parcel. +sticky: nswe + Specifies where the element is placed inside its allocated parcel. - * unit: 0 or 1 - If set to 1, causes the element and all of its descendants to be treated as - a single element for the purposes of :meth:`Widget.identify` et al. It's - used for things like scrollbar thumbs with grips. +unit: 0 or 1 + If set to 1, causes the element and all of its descendants to be treated as + a single element for the purposes of :meth:`Widget.identify` et al. It's + used for things like scrollbar thumbs with grips. - * children: [sublayout... ] - Specifies a list of elements to place inside the element. Each - element is a tuple (or other sequence type) where the first item is - the layout name, and the other is a `Layout`_. +children: [sublayout... ] + Specifies a list of elements to place inside the element. Each + element is a tuple (or other sequence type) where the first item is + the layout name, and the other is a `Layout`_. .. _Layout: `Layouts`_ diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 13cd593f9549a2..3d8393c105ec32 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -814,8 +814,8 @@ This applies to :meth:`~Mock.assert_called_with`, :meth:`~Mock.assert_any_call`. When :ref:`auto-speccing`, it will also apply to method calls on the mock object. - .. versionchanged:: 3.4 - Added signature introspection on specced and autospecced mock objects. +.. versionchanged:: 3.4 + Added signature introspection on specced and autospecced mock objects. .. class:: PropertyMock(*args, **kwargs) @@ -1388,9 +1388,9 @@ patch .. note:: - .. versionchanged:: 3.5 - If you are patching builtins in a module then you don't - need to pass ``create=True``, it will be added by default. + .. versionchanged:: 3.5 + If you are patching builtins in a module then you don't + need to pass ``create=True``, it will be added by default. Patch can be used as a :class:`TestCase` class decorator. It works by decorating each test method in the class. This reduces the boilerplate diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 35b8f5b471dd96..002dab8a65195c 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -315,10 +315,10 @@ The following classes are provided: list of hostname suffixes, optionally with ``:port`` appended, for example ``cern.ch,ncsa.uiuc.edu,some.host:8080``. - .. note:: + .. note:: - ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set; - see the documentation on :func:`~urllib.request.getproxies`. + ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set; + see the documentation on :func:`~urllib.request.getproxies`. .. class:: HTTPPasswordMgr() @@ -1536,9 +1536,9 @@ some point in the future. :mod:`urllib.request` Restrictions ---------------------------------- - .. index:: - pair: HTTP; protocol - pair: FTP; protocol +.. index:: + pair: HTTP; protocol + pair: FTP; protocol * Currently, only the following protocols are supported: HTTP (versions 0.9 and 1.0), FTP, local files, and data URLs. From 7d5a9826095f4c1c8faec4a832fe4e8dfc00b224 Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Wed, 11 Oct 2023 23:12:36 +0200 Subject: [PATCH 1001/1206] [3.12] gh-110631: Fix reST indentation (GH-110724) (#110738) * Fix wrong indentation in the other dirs. * Fix more wrong indentation.. (cherry picked from commit 718391f475f2550d99dd794069ca76312f7f6aa6) --- Doc/c-api/memory.rst | 24 ++++++++++++------------ Doc/howto/enum.rst | 15 ++++++++------- Doc/howto/instrumentation.rst | 14 ++++++-------- Doc/library/csv.rst | 6 +++--- Doc/library/dataclasses.rst | 12 +++++------- Doc/library/decimal.rst | 8 ++++---- Doc/using/windows.rst | 25 +++++++++++++------------ 7 files changed, 51 insertions(+), 53 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 1df8c2b911ca8f..e98c178ac27a37 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -491,18 +491,18 @@ Customize Memory Allocators :c:func:`PyMem_SetAllocator` does have the following contract: - * It can be called after :c:func:`Py_PreInitialize` and before - :c:func:`Py_InitializeFromConfig` to install a custom memory - allocator. There are no restrictions over the installed allocator - other than the ones imposed by the domain (for instance, the Raw - Domain allows the allocator to be called without the GIL held). See - :ref:`the section on allocator domains ` for more - information. - - * If called after Python has finish initializing (after - :c:func:`Py_InitializeFromConfig` has been called) the allocator - **must** wrap the existing allocator. Substituting the current - allocator for some other arbitrary one is **not supported**. + * It can be called after :c:func:`Py_PreInitialize` and before + :c:func:`Py_InitializeFromConfig` to install a custom memory + allocator. There are no restrictions over the installed allocator + other than the ones imposed by the domain (for instance, the Raw + Domain allows the allocator to be called without the GIL held). See + :ref:`the section on allocator domains ` for more + information. + + * If called after Python has finish initializing (after + :c:func:`Py_InitializeFromConfig` has been called) the allocator + **must** wrap the existing allocator. Substituting the current + allocator for some other arbitrary one is **not supported**. .. versionchanged:: 3.12 All allocators must be thread-safe. diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 28749754a54dba..ebaa1cfe4c8b58 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -1156,13 +1156,14 @@ the following are true: There is a new boundary mechanism that controls how out-of-range / invalid bits are handled: ``STRICT``, ``CONFORM``, ``EJECT``, and ``KEEP``: - * STRICT --> raises an exception when presented with invalid values - * CONFORM --> discards any invalid bits - * EJECT --> lose Flag status and become a normal int with the given value - * KEEP --> keep the extra bits - - keeps Flag status and extra bits - - extra bits do not show up in iteration - - extra bits do show up in repr() and str() +* STRICT --> raises an exception when presented with invalid values +* CONFORM --> discards any invalid bits +* EJECT --> lose Flag status and become a normal int with the given value +* KEEP --> keep the extra bits + + - keeps Flag status and extra bits + - extra bits do not show up in iteration + - extra bits do show up in repr() and str() The default for Flag is ``STRICT``, the default for ``IntFlag`` is ``EJECT``, and the default for ``_convert_`` is ``KEEP`` (see ``ssl.Options`` for an diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst index 875f846aad0051..9c99fcecce1fcb 100644 --- a/Doc/howto/instrumentation.rst +++ b/Doc/howto/instrumentation.rst @@ -13,9 +13,9 @@ DTrace and SystemTap are monitoring tools, each providing a way to inspect what the processes on a computer system are doing. They both use domain-specific languages allowing a user to write scripts which: - - filter which processes are to be observed - - gather data from the processes of interest - - generate reports on the data +- filter which processes are to be observed +- gather data from the processes of interest +- generate reports on the data As of Python 3.6, CPython can be built with embedded "markers", also known as "probes", that can be observed by a DTrace or SystemTap script, @@ -246,11 +246,9 @@ The output looks like this: where the columns are: - - time in microseconds since start of script - - - name of executable - - - PID of process +- time in microseconds since start of script +- name of executable +- PID of process and the remainder indicates the call/return hierarchy as the script executes. diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index 64baa69be4af31..aba398b8ee1e54 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -288,9 +288,9 @@ The :mod:`csv` module defines the following classes: Inspecting each column, one of two key criteria will be considered to estimate if the sample contains a header: - - the second through n-th rows contain numeric values - - the second through n-th rows contain strings where at least one value's - length differs from that of the putative header of that column. + - the second through n-th rows contain numeric values + - the second through n-th rows contain strings where at least one value's + length differs from that of the putative header of that column. Twenty rows after the first row are sampled; if more than half of columns + rows meet the criteria, :const:`True` is returned. diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index d68748767c5e37..1b2f6d454dab65 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -319,13 +319,11 @@ Module contents module-level method (see below). Users should never instantiate a :class:`Field` object directly. Its documented attributes are: - - ``name``: The name of the field. - - - ``type``: The type of the field. - - - ``default``, ``default_factory``, ``init``, ``repr``, ``hash``, - ``compare``, ``metadata``, and ``kw_only`` have the identical - meaning and values as they do in the :func:`field` function. + - ``name``: The name of the field. + - ``type``: The type of the field. + - ``default``, ``default_factory``, ``init``, ``repr``, ``hash``, + ``compare``, ``metadata``, and ``kw_only`` have the identical + meaning and values as they do in the :func:`field` function. Other attributes may exist, but they are private and must not be inspected or relied on. diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 018ec1abf36406..08bbb7ff582f4f 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -1396,10 +1396,10 @@ In addition to the three supplied contexts, new contexts can be created with the With three arguments, compute ``(x**y) % modulo``. For the three argument form, the following restrictions on the arguments hold: - - all three arguments must be integral - - ``y`` must be nonnegative - - at least one of ``x`` or ``y`` must be nonzero - - ``modulo`` must be nonzero and have at most 'precision' digits + - all three arguments must be integral + - ``y`` must be nonnegative + - at least one of ``x`` or ``y`` must be nonzero + - ``modulo`` must be nonzero and have at most 'precision' digits The value resulting from ``Context.power(x, y, modulo)`` is equal to the value that would be obtained by computing ``(x**y) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 919b76f2816a80..e5843eeeb529b9 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -1187,21 +1187,22 @@ Otherwise, your users may experience problems using your application. Note that the first suggestion is the best, as the others may still be susceptible to non-standard paths in the registry and user site-packages. -.. versionchanged:: - 3.6 +.. versionchanged:: 3.6 + + Add ``._pth`` file support and removes ``applocal`` option from + ``pyvenv.cfg``. + +.. versionchanged:: 3.6 - * Adds ``._pth`` file support and removes ``applocal`` option from - ``pyvenv.cfg``. - * Adds :file:`python{XX}.zip` as a potential landmark when directly adjacent - to the executable. + Add :file:`python{XX}.zip` as a potential landmark when directly adjacent + to the executable. -.. deprecated:: - 3.6 +.. deprecated:: 3.6 - Modules specified in the registry under ``Modules`` (not ``PythonPath``) - may be imported by :class:`importlib.machinery.WindowsRegistryFinder`. - This finder is enabled on Windows in 3.6.0 and earlier, but may need to - be explicitly added to :data:`sys.meta_path` in the future. + Modules specified in the registry under ``Modules`` (not ``PythonPath``) + may be imported by :class:`importlib.machinery.WindowsRegistryFinder`. + This finder is enabled on Windows in 3.6.0 and earlier, but may need to + be explicitly added to :data:`sys.meta_path` in the future. Additional modules ================== From dbbe0eebf0a53fe5f9f9467b4bb85ec16989c0f0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 11 Oct 2023 23:13:21 +0200 Subject: [PATCH 1002/1206] [3.12] gh-110631: Fix reST indentation in `Doc/reference` (GH-110708) (#110740) gh-110631: Fix reST indentation in `Doc/reference` (GH-110708) Fix wrong indentation in the Doc/reference dir. (cherry picked from commit 41d8ec5a1bae1e5d4452da0a1a0649ace4ecb7b0) Co-authored-by: Ezio Melotti --- Doc/reference/compound_stmts.rst | 48 +++++++-------- Doc/reference/expressions.rst | 4 +- Doc/reference/import.rst | 94 +++++++++++++++--------------- Doc/reference/lexical_analysis.rst | 10 ++-- 4 files changed, 79 insertions(+), 77 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 12ad18d4119617..f79db828604b24 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -642,14 +642,14 @@ Here's an overview of the logical flow of a match statement: specified below. **Name bindings made during a successful pattern match outlive the executed block and can be used after the match statement**. - .. note:: + .. note:: - During failed pattern matches, some subpatterns may succeed. Do not - rely on bindings being made for a failed match. Conversely, do not - rely on variables remaining unchanged after a failed match. The exact - behavior is dependent on implementation and may vary. This is an - intentional decision made to allow different implementations to add - optimizations. + During failed pattern matches, some subpatterns may succeed. Do not + rely on bindings being made for a failed match. Conversely, do not + rely on variables remaining unchanged after a failed match. The exact + behavior is dependent on implementation and may vary. This is an + intentional decision made to allow different implementations to add + optimizations. #. If the pattern succeeds, the corresponding guard (if present) is evaluated. In this case all name bindings are guaranteed to have happened. @@ -1170,8 +1170,10 @@ In simple terms ``CLS(P1, attr=P2)`` matches only if the following happens: * ``isinstance(, CLS)`` * convert ``P1`` to a keyword pattern using ``CLS.__match_args__`` * For each keyword argument ``attr=P2``: - * ``hasattr(, "attr")`` - * ``P2`` matches ``.attr`` + + * ``hasattr(, "attr")`` + * ``P2`` matches ``.attr`` + * ... and so on for the corresponding keyword argument/pattern pair. .. seealso:: @@ -1838,29 +1840,29 @@ like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime. .. [#] In pattern matching, a sequence is defined as one of the following: - * a class that inherits from :class:`collections.abc.Sequence` - * a Python class that has been registered as :class:`collections.abc.Sequence` - * a builtin class that has its (CPython) :c:macro:`Py_TPFLAGS_SEQUENCE` bit set - * a class that inherits from any of the above + * a class that inherits from :class:`collections.abc.Sequence` + * a Python class that has been registered as :class:`collections.abc.Sequence` + * a builtin class that has its (CPython) :c:macro:`Py_TPFLAGS_SEQUENCE` bit set + * a class that inherits from any of the above The following standard library classes are sequences: - * :class:`array.array` - * :class:`collections.deque` - * :class:`list` - * :class:`memoryview` - * :class:`range` - * :class:`tuple` + * :class:`array.array` + * :class:`collections.deque` + * :class:`list` + * :class:`memoryview` + * :class:`range` + * :class:`tuple` .. note:: Subject values of type ``str``, ``bytes``, and ``bytearray`` do not match sequence patterns. .. [#] In pattern matching, a mapping is defined as one of the following: - * a class that inherits from :class:`collections.abc.Mapping` - * a Python class that has been registered as :class:`collections.abc.Mapping` - * a builtin class that has its (CPython) :c:macro:`Py_TPFLAGS_MAPPING` bit set - * a class that inherits from any of the above + * a class that inherits from :class:`collections.abc.Mapping` + * a Python class that has been registered as :class:`collections.abc.Mapping` + * a builtin class that has its (CPython) :c:macro:`Py_TPFLAGS_MAPPING` bit set + * a class that inherits from any of the above The standard library classes :class:`dict` and :class:`types.MappingProxyType` are mappings. diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 5d7a36aa8ff52b..26adc17e76ae08 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -499,8 +499,8 @@ the yield expression. It can be either set explicitly when raising :exc:`StopIteration`, or automatically when the subiterator is a generator (by returning a value from the subgenerator). - .. versionchanged:: 3.3 - Added ``yield from `` to delegate control flow to a subiterator. +.. versionchanged:: 3.3 + Added ``yield from `` to delegate control flow to a subiterator. The parentheses may be omitted when the yield expression is the sole expression on the right hand side of an assignment statement. diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 0f416a5c583f85..1a2677e7562b9c 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -375,32 +375,32 @@ of what happens during the loading portion of import:: Note the following details: - * If there is an existing module object with the given name in - :data:`sys.modules`, import will have already returned it. +* If there is an existing module object with the given name in + :data:`sys.modules`, import will have already returned it. - * The module will exist in :data:`sys.modules` before the loader - executes the module code. This is crucial because the module code may - (directly or indirectly) import itself; adding it to :data:`sys.modules` - beforehand prevents unbounded recursion in the worst case and multiple - loading in the best. +* The module will exist in :data:`sys.modules` before the loader + executes the module code. This is crucial because the module code may + (directly or indirectly) import itself; adding it to :data:`sys.modules` + beforehand prevents unbounded recursion in the worst case and multiple + loading in the best. - * If loading fails, the failing module -- and only the failing module -- - gets removed from :data:`sys.modules`. Any module already in the - :data:`sys.modules` cache, and any module that was successfully loaded - as a side-effect, must remain in the cache. This contrasts with - reloading where even the failing module is left in :data:`sys.modules`. +* If loading fails, the failing module -- and only the failing module -- + gets removed from :data:`sys.modules`. Any module already in the + :data:`sys.modules` cache, and any module that was successfully loaded + as a side-effect, must remain in the cache. This contrasts with + reloading where even the failing module is left in :data:`sys.modules`. - * After the module is created but before execution, the import machinery - sets the import-related module attributes ("_init_module_attrs" in - the pseudo-code example above), as summarized in a - :ref:`later section `. +* After the module is created but before execution, the import machinery + sets the import-related module attributes ("_init_module_attrs" in + the pseudo-code example above), as summarized in a + :ref:`later section `. - * Module execution is the key moment of loading in which the module's - namespace gets populated. Execution is entirely delegated to the - loader, which gets to decide what gets populated and how. +* Module execution is the key moment of loading in which the module's + namespace gets populated. Execution is entirely delegated to the + loader, which gets to decide what gets populated and how. - * The module created during loading and passed to exec_module() may - not be the one returned at the end of import [#fnlo]_. +* The module created during loading and passed to exec_module() may + not be the one returned at the end of import [#fnlo]_. .. versionchanged:: 3.4 The import system has taken over the boilerplate responsibilities of @@ -417,13 +417,13 @@ returned from :meth:`~importlib.abc.Loader.exec_module` is ignored. Loaders must satisfy the following requirements: - * If the module is a Python module (as opposed to a built-in module or a - dynamically loaded extension), the loader should execute the module's code - in the module's global name space (``module.__dict__``). +* If the module is a Python module (as opposed to a built-in module or a + dynamically loaded extension), the loader should execute the module's code + in the module's global name space (``module.__dict__``). - * If the loader cannot execute the module, it should raise an - :exc:`ImportError`, although any other exception raised during - :meth:`~importlib.abc.Loader.exec_module` will be propagated. +* If the loader cannot execute the module, it should raise an + :exc:`ImportError`, although any other exception raised during + :meth:`~importlib.abc.Loader.exec_module` will be propagated. In many cases, the finder and loader can be the same object; in such cases the :meth:`~importlib.abc.MetaPathFinder.find_spec` method would just return a @@ -453,20 +453,20 @@ import machinery will create the new module itself. functionality described above in addition to executing the module. All the same constraints apply, with some additional clarification: - * If there is an existing module object with the given name in - :data:`sys.modules`, the loader must use that existing module. - (Otherwise, :func:`importlib.reload` will not work correctly.) If the - named module does not exist in :data:`sys.modules`, the loader - must create a new module object and add it to :data:`sys.modules`. + * If there is an existing module object with the given name in + :data:`sys.modules`, the loader must use that existing module. + (Otherwise, :func:`importlib.reload` will not work correctly.) If the + named module does not exist in :data:`sys.modules`, the loader + must create a new module object and add it to :data:`sys.modules`. - * The module *must* exist in :data:`sys.modules` before the loader - executes the module code, to prevent unbounded recursion or multiple - loading. + * The module *must* exist in :data:`sys.modules` before the loader + executes the module code, to prevent unbounded recursion or multiple + loading. - * If loading fails, the loader must remove any modules it has inserted - into :data:`sys.modules`, but it must remove **only** the failing - module(s), and only if the loader itself has loaded the module(s) - explicitly. + * If loading fails, the loader must remove any modules it has inserted + into :data:`sys.modules`, but it must remove **only** the failing + module(s), and only if the loader itself has loaded the module(s) + explicitly. .. versionchanged:: 3.5 A :exc:`DeprecationWarning` is raised when ``exec_module()`` is defined but @@ -693,17 +693,17 @@ with defaults for whatever information is missing. Here are the exact rules used: - * If the module has a ``__spec__`` attribute, the information in the spec - is used to generate the repr. The "name", "loader", "origin", and - "has_location" attributes are consulted. +* If the module has a ``__spec__`` attribute, the information in the spec + is used to generate the repr. The "name", "loader", "origin", and + "has_location" attributes are consulted. - * If the module has a ``__file__`` attribute, this is used as part of the - module's repr. +* If the module has a ``__file__`` attribute, this is used as part of the + module's repr. - * If the module has no ``__file__`` but does have a ``__loader__`` that is not - ``None``, then the loader's repr is used as part of the module's repr. +* If the module has no ``__file__`` but does have a ``__loader__`` that is not + ``None``, then the loader's repr is used as part of the module's repr. - * Otherwise, just use the module's ``__name__`` in the repr. +* Otherwise, just use the module's ``__name__`` in the repr. .. versionchanged:: 3.12 Use of :meth:`!module_repr`, having been deprecated since Python 3.4, was diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 816de9b57536a7..55945e57befb92 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -657,12 +657,12 @@ is more easily recognized as broken.) It is also important to note that the escape sequences only recognized in string literals fall into the category of unrecognized escapes for bytes literals. - .. versionchanged:: 3.6 - Unrecognized escape sequences produce a :exc:`DeprecationWarning`. +.. versionchanged:: 3.6 + Unrecognized escape sequences produce a :exc:`DeprecationWarning`. - .. versionchanged:: 3.12 - Unrecognized escape sequences produce a :exc:`SyntaxWarning`. In a future - Python version they will be eventually a :exc:`SyntaxError`. +.. versionchanged:: 3.12 + Unrecognized escape sequences produce a :exc:`SyntaxWarning`. In a future + Python version they will be eventually a :exc:`SyntaxError`. Even in a raw literal, quotes can be escaped with a backslash, but the backslash remains in the result; for example, ``r"\""`` is a valid string From ea344e7a05b2564eb0657c1a46894f94ee0b6001 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:10:00 +0200 Subject: [PATCH 1003/1206] [3.12] gh-110673: test_pty raises on short write (GH-110677) (#110742) gh-110673: test_pty raises on short write (GH-110677) Add write_all() helper function to test_pty to raise an exception on short write: if os.writes() does not write all bytes. It should not happen for a PTY. (cherry picked from commit b4e8049766a46a9e6548b18d7e9a0c9f573cd122) Co-authored-by: Victor Stinner --- Lib/test/test_pty.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index a971f6b0250efb..f31a68c5d84e03 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -76,6 +76,15 @@ def expectedFailureIfStdinIsTTY(fun): pass return fun + +def write_all(fd, data): + written = os.write(fd, data) + if written != len(data): + # gh-73256, gh-110673: It should never happen, but check just in case + raise Exception(f"short write: os.write({fd}, {len(data)} bytes) " + f"wrote {written} bytes") + + # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing # because pty code is not too portable. class PtyTest(unittest.TestCase): @@ -170,14 +179,14 @@ def test_openpty(self): os.set_blocking(master_fd, blocking) debug("Writing to slave_fd") - os.write(slave_fd, TEST_STRING_1) + write_all(slave_fd, TEST_STRING_1) s1 = _readline(master_fd) self.assertEqual(b'I wish to buy a fish license.\n', normalize_output(s1)) debug("Writing chunked output") - os.write(slave_fd, TEST_STRING_2[:5]) - os.write(slave_fd, TEST_STRING_2[5:]) + write_all(slave_fd, TEST_STRING_2[:5]) + write_all(slave_fd, TEST_STRING_2[5:]) s2 = _readline(master_fd) self.assertEqual(b'For my pet fish, Eric.\n', normalize_output(s2)) @@ -360,8 +369,8 @@ def test__copy_to_each(self): masters = [s.fileno() for s in socketpair] # Feed data. Smaller than PIPEBUF. These writes will not block. - os.write(masters[1], b'from master') - os.write(write_to_stdin_fd, b'from stdin') + write_all(masters[1], b'from master') + write_all(write_to_stdin_fd, b'from stdin') # Expect three select calls, the last one will cause IndexError pty.select = self._mock_select From e8d04190c603f3b4ba7a0f2f5826906c77deca3b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 12 Oct 2023 11:37:37 +0200 Subject: [PATCH 1004/1206] [3.12] GH-107518: Remove the Argument Clinic How-To (#109900) (#110760) (cherry picked from commit d1f7fae424d51b0374c8204599583c4a26c1a992) * Remove the content of the Argument Clinic HOWTO * Update cross-references to the Argument Clinic * Add a note directing readers to the devguide Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/howto/clinic.rst | 1896 +----------------------------------------- Doc/howto/index.rst | 1 - Doc/whatsnew/3.8.rst | 2 +- 3 files changed, 6 insertions(+), 1893 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index e8e6aace350e0c..060977246149cf 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1,1900 +1,14 @@ -.. highlight:: c +:orphan: -.. _howto-clinic: +.. This page is retained solely for existing links to /howto/clinic.html. + Direct readers to the devguide. ********************** Argument Clinic How-To ********************** -:author: Larry Hastings - -**Source code:** :source:`Tools/clinic/clinic.py`. - -.. topic:: Abstract - - Argument Clinic is a preprocessor for CPython C files. - It was introduced in Python 3.4 with :pep:`436`, - in order to provide introspection signatures, - and to generate performant and tailor-made boilerplate code - for argument parsing in CPython builtins, - module level functions, and class methods. - This document is divided in four major sections: - - * :ref:`clinic-background` talks about the basic concepts and goals of - Argument Clinic. - * :ref:`clinic-reference` describes the command-line interface and Argument - Clinic terminology. - * :ref:`clinic-tutorial` guides you through all the steps required to - adapt an existing C function to Argument Clinic. - * :ref:`clinic-howtos` details how to handle specific tasks. - - -.. note:: - - Argument Clinic is considered internal-only - for CPython. Its use is not supported for files outside - CPython, and no guarantees are made regarding backwards - compatibility for future versions. In other words: if you - maintain an external C extension for CPython, you're welcome - to experiment with Argument Clinic in your own code. But the - version of Argument Clinic that ships with the next version - of CPython *could* be totally incompatible and break all your code. - - -.. _clinic-background: - -Background -========== - -Basic concepts --------------- - -When Argument Clinic is run on a file, either via the :ref:`clinic-cli` -or via ``make clinic``, it will scan over the input files looking for -:term:`start lines `: - -.. code-block:: none - - /*[clinic input] - -When it finds one, it reads everything up to the :term:`end line`: - -.. code-block:: none - - [clinic start generated code]*/ - -Everything in between these two lines is Argument Clinic :term:`input`. -When Argument Clinic parses input, it generates :term:`output`. -The output is rewritten into the C file immediately after the input, -followed by a :term:`checksum line`. -All of these lines, including the :term:`start line` and :term:`checksum line`, -are collectively called an Argument Clinic :term:`block`: - -.. code-block:: none - - /*[clinic input] - ... clinic input goes here ... - [clinic start generated code]*/ - ... clinic output goes here ... - /*[clinic end generated code: ...]*/ - -If you run Argument Clinic on the same file a second time, Argument Clinic -will discard the old :term:`output` and write out the new output with a fresh -:term:`checksum line`. -If the :term:`input` hasn't changed, the output won't change either. .. note:: - You should never modify the output of an Argument Clinic block, - as any change will be lost in future Argument Clinic runs; - Argument Clinic will detect an output checksum mismatch and regenerate the - correct output. - If you are not happy with the generated output, - you should instead change the input until it produces the output you want. - - -.. _clinic-reference: - -Reference -========= - - -.. _clinic-terminology: - -Terminology ------------ - -.. glossary:: - - start line - The line ``/*[clinic input]``. - This line marks the beginning of Argument Clinic input. - Note that the *start line* opens a C block comment. - - end line - The line ``[clinic start generated code]*/``. - The *end line* marks the _end_ of Argument Clinic :term:`input`, - but at the same time marks the _start_ of Argument Clinic :term:`output`, - thus the text *"clinic start start generated code"* - Note that the *end line* closes the C block comment opened - by the *start line*. - - checksum - A hash to distinguish unique :term:`inputs ` - and :term:`outputs `. - - checksum line - A line that looks like ``/*[clinic end generated code: ...]*/``. - The three dots will be replaced by a :term:`checksum` generated from the - :term:`input`, and a :term:`checksum` generated from the :term:`output`. - The checksum line marks the end of Argument Clinic generated code, - and is used by Argument Clinic to determine if it needs to regenerate - output. - - input - The text between the :term:`start line` and the :term:`end line`. - Note that the start and end lines open and close a C block comment; - the *input* is thus a part of that same C block comment. - - output - The text between the :term:`end line` and the :term:`checksum line`. - - block - All text from the :term:`start line` to the :term:`checksum line` inclusively. - - -.. _clinic-cli: - -Command-line interface ----------------------- - -The Argument Clinic :abbr:`CLI (Command-Line Interface)` is typically used to -process a single source file, like this: - -.. code-block:: shell-session - - $ python3 ./Tools/clinic/clinic.py foo.c - -The CLI supports the following options: - -.. program:: ./Tools/clinic/clinic.py [-h] [-f] [-o OUTPUT] [-v] \ - [--converters] [--make] [--srcdir SRCDIR] [FILE ...] - -.. option:: -h, --help - - Print CLI usage. - -.. option:: -f, --force - - Force output regeneration. - -.. option:: -o, --output OUTPUT - - Redirect file output to OUTPUT - -.. option:: -v, --verbose - - Enable verbose mode. - -.. option:: --converters - - Print a list of all supported converters and return converters. - -.. option:: --make - - Walk :option:`--srcdir` to run over all relevant files. - -.. option:: --srcdir SRCDIR - - The directory tree to walk in :option:`--make` mode. - -.. option:: FILE ... - - The list of files to process. - - -.. _clinic-classes: - -Classes for extending Argument Clinic -------------------------------------- - -.. module:: clinic - -.. class:: CConverter - - The base class for all converters. - See :ref:`clinic-howto-custom-converter` for how to subclass this class. - - .. attribute:: type - - The C type to use for this variable. - :attr:`!type` should be a Python string specifying the type, - e.g. ``'int'``. - If this is a pointer type, the type string should end with ``' *'``. - - .. attribute:: default - - The Python default value for this parameter, as a Python value. - Or the magic value ``unspecified`` if there is no default. - - .. attribute:: py_default - - :attr:`!default` as it should appear in Python code, - as a string. - Or ``None`` if there is no default. - - .. attribute:: c_default - - :attr:`!default` as it should appear in C code, - as a string. - Or ``None`` if there is no default. - - .. attribute:: c_ignored_default - - The default value used to initialize the C variable when - there is no default, but not specifying a default may - result in an "uninitialized variable" warning. This can - easily happen when using option groups—although - properly written code will never actually use this value, - the variable does get passed in to the impl, and the - C compiler will complain about the "use" of the - uninitialized value. This value should always be a - non-empty string. - - .. attribute:: converter - - The name of the C converter function, as a string. - - .. attribute:: impl_by_reference - - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into the impl function. - - .. attribute:: parse_by_reference - - A boolean value. If true, - Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into :c:func:`PyArg_ParseTuple`. - - -.. _clinic-tutorial: - -Tutorial -======== - -The best way to get a sense of how Argument Clinic works is to -convert a function to work with it. Here, then, are the bare -minimum steps you'd need to follow to convert a function to -work with Argument Clinic. Note that for code you plan to -check in to CPython, you really should take the conversion farther, -using some of the :ref:`advanced concepts ` -you'll see later on in the document, -like :ref:`clinic-howto-return-converters` -and :ref:`clinic-howto-self-converter`. -But we'll keep it simple for this walkthrough so you can learn. - -First, make sure you're working with a freshly updated checkout -of the CPython trunk. - -Next, find a Python builtin that calls either :c:func:`PyArg_ParseTuple` -or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted -to work with Argument Clinic yet. -For this tutorial, we'll be using -:py:meth:`_pickle.Pickler.dump `. - -If the call to the :c:func:`!PyArg_Parse*` function uses any of the -following format units...: - - .. code-block:: none - - O& - O! - es - es# - et - et# - -... or if it has multiple calls to :c:func:`PyArg_ParseTuple`, -you should choose a different function. -(See :ref:`clinic-howto-advanced-converters` for those scenarios.) - -Also, if the function has multiple calls to :c:func:`!PyArg_ParseTuple` -or :c:func:`PyArg_ParseTupleAndKeywords` where it supports different -types for the same argument, or if the function uses something besides -:c:func:`!PyArg_Parse*` functions to parse its arguments, it probably -isn't suitable for conversion to Argument Clinic. Argument Clinic -doesn't support generic functions or polymorphic parameters. - -Next, add the following boilerplate above the function, -creating our input block:: - - /*[clinic input] - [clinic start generated code]*/ - -Cut the docstring and paste it in between the ``[clinic]`` lines, -removing all the junk that makes it a properly quoted C string. -When you're done you should have just the text, based at the left -margin, with no line wider than 80 characters. -Argument Clinic will preserve indents inside the docstring. - -If the old docstring had a first line that looked like a function -signature, throw that line away; The docstring doesn't need it anymore --- -when you use :py:func:`help` on your builtin in the future, -the first line will be built automatically based on the function's signature. - -Example docstring summary line:: - - /*[clinic input] - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -If your docstring doesn't have a "summary" line, Argument Clinic will -complain, so let's make sure it has one. The "summary" line should -be a paragraph consisting of a single 80-column line -at the beginning of the docstring. -(See :pep:`257` regarding docstring conventions.) - -Our example docstring consists solely of a summary line, so the sample -code doesn't have to change for this step. - -Now, above the docstring, enter the name of the function, followed -by a blank line. This should be the Python name of the function, -and should be the full dotted path to the function --- -it should start with the name of the module, -include any sub-modules, and if the function is a method on -a class it should include the class name too. - -In our example, :mod:`!_pickle` is the module, :py:class:`!Pickler` is the class, -and :py:meth:`!dump` is the method, so the name becomes -:py:meth:`!_pickle.Pickler.dump`:: - - /*[clinic input] - _pickle.Pickler.dump - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -If this is the first time that module or class has been used with Argument -Clinic in this C file, -you must declare the module and/or class. Proper Argument Clinic hygiene -prefers declaring these in a separate block somewhere near the -top of the C file, in the same way that include files and statics go at -the top. -In our sample code we'll just show the two blocks next to each other. - -The name of the class and module should be the same as the one -seen by Python. Check the name defined in the :c:type:`PyModuleDef` -or :c:type:`PyTypeObject` as appropriate. - -When you declare a class, you must also specify two aspects of its type -in C: the type declaration you'd use for a pointer to an instance of -this class, and a pointer to the :c:type:`!PyTypeObject` for this class:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -Declare each of the parameters to the function. Each parameter -should get its own line. All the parameter lines should be -indented from the function name and the docstring. -The general form of these parameter lines is as follows: - -.. code-block:: none - - name_of_parameter: converter - -If the parameter has a default value, add that after the -converter: - -.. code-block:: none - - name_of_parameter: converter = default_value - -Argument Clinic's support for "default values" is quite sophisticated; -see :ref:`clinic-howto-default-values` for more information. - -Next, add a blank line below the parameters. - -What's a "converter"? -It establishes both the type of the variable used in C, -and the method to convert the Python value into a C value at runtime. -For now you're going to use what's called a "legacy converter" --- -a convenience syntax intended to make porting old code into Argument -Clinic easier. - -For each parameter, copy the "format unit" for that -parameter from the :c:func:`PyArg_Parse` format argument and -specify *that* as its converter, as a quoted string. -The "format unit" is the formal name for the one-to-three -character substring of the *format* parameter that tells -the argument parsing function what the type of the variable -is and how to convert it. -For more on format units please see :ref:`arg-parsing`. - -For multicharacter format units like ``z#``, -use the entire two-or-three character string. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -If your function has ``|`` in the format string, -meaning some parameters have default values, you can ignore it. -Argument Clinic infers which parameters are optional -based on whether or not they have default values. - -If your function has ``$`` in the format string, -meaning it takes keyword-only arguments, -specify ``*`` on a line by itself before the first keyword-only argument, -indented the same as the parameter lines. - -:py:meth:`!_pickle.Pickler.dump` has neither, so our sample is unchanged. - -Next, if the existing C function calls :c:func:`PyArg_ParseTuple` -(as opposed to :c:func:`PyArg_ParseTupleAndKeywords`), then all its -arguments are positional-only. - -To mark parameters as positional-only in Argument Clinic, -add a ``/`` on a line by itself after the last positional-only parameter, -indented the same as the parameter lines. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -It can be helpful to write a per-parameter docstring for each parameter. -Since per-parameter docstrings are optional, -you can skip this step if you prefer. - -Nevertheless, here's how to add a per-parameter docstring. -The first line of the per-parameter docstring -must be indented further than the parameter definition. -The left margin of this first line establishes -the left margin for the whole per-parameter docstring; -all the text you write will be outdented by this amount. -You can write as much text as you like, across multiple lines if you wish. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - The object to be pickled. - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -Save and close the file, then run ``Tools/clinic/clinic.py`` on it. -With luck everything worked---your block now has output, -and a :file:`.c.h` file has been generated! -Reload the file in your text editor to see the generated code:: - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - The object to be pickled. - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - - static PyObject * - _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ - -Obviously, if Argument Clinic didn't produce any output, -it's because it found an error in your input. -Keep fixing your errors and retrying until Argument Clinic processes your file -without complaint. - -For readability, most of the glue code has been generated to a :file:`.c.h` -file. You'll need to include that in your original :file:`.c` file, -typically right after the clinic module block:: - - #include "clinic/_pickle.c.h" - -Double-check that the argument-parsing code Argument Clinic generated -looks basically the same as the existing code. - -First, ensure both places use the same argument-parsing function. -The existing code must call either -:c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`; -ensure that the code generated by Argument Clinic calls the -*exact* same function. - -Second, the format string passed in to :c:func:`!PyArg_ParseTuple` or -:c:func:`!PyArg_ParseTupleAndKeywords` should be *exactly* the same -as the hand-written one in the existing function, -up to the colon or semi-colon. - -Argument Clinic always generates its format strings -with a ``:`` followed by the name of the function. -If the existing code's format string ends with ``;``, -to provide usage help, this change is harmless --- don't worry about it. - -Third, for parameters whose format units require two arguments, -like a length variable, an encoding string, or a pointer -to a conversion function, ensure that the second argument is -*exactly* the same between the two invocations. - -Fourth, inside the output portion of the block, -you'll find a preprocessor macro defining the appropriate static -:c:type:`PyMethodDef` structure for this builtin:: - - #define __PICKLE_PICKLER_DUMP_METHODDEF \ - {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, - -This static structure should be *exactly* the same as the existing static -:c:type:`!PyMethodDef` structure for this builtin. - -If any of these items differ in *any way*, -adjust your Argument Clinic function specification and rerun -``Tools/clinic/clinic.py`` until they *are* the same. - -Notice that the last line of its output is the declaration -of your "impl" function. This is where the builtin's implementation goes. -Delete the existing prototype of the function you're modifying, but leave -the opening curly brace. Now delete its argument parsing code and the -declarations of all the variables it dumps the arguments into. -Notice how the Python arguments are now arguments to this impl function; -if the implementation used different names for these variables, fix it. - -Let's reiterate, just because it's kind of weird. -Your code should now look like this:: - - static return_type - your_function_impl(...) - /*[clinic end generated code: input=..., output=...]*/ - { - ... - -Argument Clinic generated the checksum line and the function prototype just -above it. You should write the opening and closing curly braces for the -function, and the implementation inside. - -Sample:: - - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ - /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - - /*[clinic input] - _pickle.Pickler.dump - - obj: 'O' - The object to be pickled. - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - - PyDoc_STRVAR(__pickle_Pickler_dump__doc__, - "Write a pickled representation of obj to the open file.\n" - "\n" - ... - static PyObject * - _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ - { - /* Check whether the Pickler was initialized correctly (issue3664). - Developers often forget to call __init__() in their subclasses, which - would trigger a segfault without this check. */ - if (self->write == NULL) { - PyErr_Format(PicklingError, - "Pickler.__init__() was not called by %s.__init__()", - Py_TYPE(self)->tp_name); - return NULL; - } - - if (_Pickler_ClearBuffer(self) < 0) { - return NULL; - } - - ... - -Remember the macro with the :c:type:`PyMethodDef` structure for this function? -Find the existing :c:type:`!PyMethodDef` structure for this -function and replace it with a reference to the macro. If the builtin -is at module scope, this will probably be very near the end of the file; -if the builtin is a class method, this will probably be below but relatively -near to the implementation. - -Note that the body of the macro contains a trailing comma; when you -replace the existing static :c:type:`!PyMethodDef` structure with the macro, -*don't* add a comma to the end. - -Sample:: - - static struct PyMethodDef Pickler_methods[] = { - __PICKLE_PICKLER_DUMP_METHODDEF - __PICKLE_PICKLER_CLEAR_MEMO_METHODDEF - {NULL, NULL} /* sentinel */ - }; - -Argument Clinic may generate new instances of ``_Py_ID``. For example:: - - &_Py_ID(new_unique_py_id) - -If it does, you'll have to run ``make regen-global-objects`` -to regenerate the list of precompiled identifiers at this point. - -Finally, compile, then run the relevant portions of the regression-test suite. -This change should not introduce any new compile-time warnings or errors, -and there should be no externally visible change to Python's behavior, -except for one difference: :py:func:`inspect.signature` run on your function -should now provide a valid signature! - -Congratulations, you've ported your first function to work with Argument Clinic! - - -.. _clinic-howtos: - -How-to guides -============= - - -How to rename C functions and variables generated by Argument Clinic --------------------------------------------------------------------- - -Argument Clinic automatically names the functions it generates for you. -Occasionally this may cause a problem, if the generated name collides with -the name of an existing C function. There's an easy solution: override the names -used for the C functions. Just add the keyword ``"as"`` -to your function declaration line, followed by the function name you wish to use. -Argument Clinic will use that function name for the base (generated) function, -then add ``"_impl"`` to the end and use that for the name of the impl function. - -For example, if we wanted to rename the C function names generated for -:py:meth:`pickle.Pickler.dump`, it'd look like this:: - - /*[clinic input] - pickle.Pickler.dump as pickler_dumper - - ... - -The base function would now be named :c:func:`!pickler_dumper`, -and the impl function would now be named :c:func:`!pickler_dumper_impl`. - - -Similarly, you may have a problem where you want to give a parameter -a specific Python name, but that name may be inconvenient in C. Argument -Clinic allows you to give a parameter different names in Python and in C, -using the same ``"as"`` syntax:: - - /*[clinic input] - pickle.Pickler.dump - - obj: object - file as file_obj: object - protocol: object = NULL - * - fix_imports: bool = True - -Here, the name used in Python (in the signature and the ``keywords`` -array) would be *file*, but the C variable would be named ``file_obj``. - -You can use this to rename the *self* parameter too! - - -How to convert functions using ``PyArg_UnpackTuple`` ----------------------------------------------------- - -To convert a function parsing its arguments with :c:func:`PyArg_UnpackTuple`, -simply write out all the arguments, specifying each as an ``object``. You -may specify the *type* argument to cast the type as appropriate. All -arguments should be marked positional-only (add a ``/`` on a line by itself -after the last argument). - -Currently the generated code will use :c:func:`PyArg_ParseTuple`, but this -will change soon. - - -How to use optional groups --------------------------- - -Some legacy functions have a tricky approach to parsing their arguments: -they count the number of positional arguments, then use a ``switch`` statement -to call one of several different :c:func:`PyArg_ParseTuple` calls depending on -how many positional arguments there are. (These functions cannot accept -keyword-only arguments.) This approach was used to simulate optional -arguments back before :c:func:`PyArg_ParseTupleAndKeywords` was created. - -While functions using this approach can often be converted to -use :c:func:`!PyArg_ParseTupleAndKeywords`, optional arguments, and default values, -it's not always possible. Some of these legacy functions have -behaviors :c:func:`!PyArg_ParseTupleAndKeywords` doesn't directly support. -The most obvious example is the builtin function :py:func:`range`, which has -an optional argument on the *left* side of its required argument! -Another example is :py:meth:`curses.window.addch`, which has a group of two -arguments that must always be specified together. (The arguments are -called *x* and *y*; if you call the function passing in *x*, -you must also pass in *y* — and if you don't pass in *x* you may not -pass in *y* either.) - -In any case, the goal of Argument Clinic is to support argument parsing -for all existing CPython builtins without changing their semantics. -Therefore Argument Clinic supports -this alternate approach to parsing, using what are called *optional groups*. -Optional groups are groups of arguments that must all be passed in together. -They can be to the left or the right of the required arguments. They -can *only* be used with positional-only parameters. - -.. note:: Optional groups are *only* intended for use when converting - functions that make multiple calls to :c:func:`PyArg_ParseTuple`! - Functions that use *any* other approach for parsing arguments - should *almost never* be converted to Argument Clinic using - optional groups. Functions using optional groups currently - cannot have accurate signatures in Python, because Python just - doesn't understand the concept. Please avoid using optional - groups wherever possible. - -To specify an optional group, add a ``[`` on a line by itself before -the parameters you wish to group together, and a ``]`` on a line by itself -after these parameters. As an example, here's how :py:meth:`curses.window.addch` -uses optional groups to make the first two parameters and the last -parameter optional:: - - /*[clinic input] - - curses.window.addch - - [ - x: int - X-coordinate. - y: int - Y-coordinate. - ] - - ch: object - Character to add. - - [ - attr: long - Attributes for the character. - ] - / - - ... - - -Notes: - -* For every optional group, one additional parameter will be passed into the - impl function representing the group. The parameter will be an int named - ``group_{direction}_{number}``, - where ``{direction}`` is either ``right`` or ``left`` depending on whether the group - is before or after the required parameters, and ``{number}`` is a monotonically - increasing number (starting at 1) indicating how far away the group is from - the required parameters. When the impl is called, this parameter will be set - to zero if this group was unused, and set to non-zero if this group was used. - (By used or unused, I mean whether or not the parameters received arguments - in this invocation.) - -* If there are no required arguments, the optional groups will behave - as if they're to the right of the required arguments. - -* In the case of ambiguity, the argument parsing code - favors parameters on the left (before the required parameters). - -* Optional groups can only contain positional-only parameters. - -* Optional groups are *only* intended for legacy code. Please do not - use optional groups for new code. - - -How to use real Argument Clinic converters, instead of "legacy converters" --------------------------------------------------------------------------- - -To save time, and to minimize how much you need to learn -to achieve your first port to Argument Clinic, the walkthrough above tells -you to use "legacy converters". "Legacy converters" are a convenience, -designed explicitly to make porting existing code to Argument Clinic -easier. And to be clear, their use is acceptable when porting code for -Python 3.4. - -However, in the long term we probably want all our blocks to -use Argument Clinic's real syntax for converters. Why? A couple -reasons: - -* The proper converters are far easier to read and clearer in their intent. -* There are some format units that are unsupported as "legacy converters", - because they require arguments, and the legacy converter syntax doesn't - support specifying arguments. -* In the future we may have a new argument parsing library that isn't - restricted to what :c:func:`PyArg_ParseTuple` supports; this flexibility - won't be available to parameters using legacy converters. - -Therefore, if you don't mind a little extra effort, please use the normal -converters instead of legacy converters. - -In a nutshell, the syntax for Argument Clinic (non-legacy) converters -looks like a Python function call. However, if there are no explicit -arguments to the function (all functions take their default values), -you may omit the parentheses. Thus ``bool`` and ``bool()`` are exactly -the same converters. - -All arguments to Argument Clinic converters are keyword-only. -All Argument Clinic converters accept the following arguments: - - *c_default* - The default value for this parameter when defined in C. - Specifically, this will be the initializer for the variable declared - in the "parse function". See :ref:`the section on default values ` - for how to use this. - Specified as a string. - - *annotation* - The annotation value for this parameter. Not currently supported, - because :pep:`8` mandates that the Python library may not use - annotations. - - *unused* - Wrap the argument with :c:macro:`Py_UNUSED` in the impl function signature. - -In addition, some converters accept additional arguments. Here is a list -of these arguments, along with their meanings: - - *accept* - A set of Python types (and possibly pseudo-types); - this restricts the allowable Python argument to values of these types. - (This is not a general-purpose facility; as a rule it only supports - specific lists of types as shown in the legacy converter table.) - - To accept ``None``, add ``NoneType`` to this set. - - *bitwise* - Only supported for unsigned integers. The native integer value of this - Python argument will be written to the parameter without any range checking, - even for negative values. - - *converter* - Only supported by the ``object`` converter. Specifies the name of a - :ref:`C "converter function" ` - to use to convert this object to a native type. - - *encoding* - Only supported for strings. Specifies the encoding to use when converting - this string from a Python str (Unicode) value into a C ``char *`` value. - - - *subclass_of* - Only supported for the ``object`` converter. Requires that the Python - value be a subclass of a Python type, as expressed in C. - - *type* - Only supported for the ``object`` and ``self`` converters. Specifies - the C type that will be used to declare the variable. Default value is - ``"PyObject *"``. - - *zeroes* - Only supported for strings. If true, embedded NUL bytes (``'\\0'``) are - permitted inside the value. The length of the string will be passed in - to the impl function, just after the string parameter, as a parameter named - ``_length``. - -Please note, not every possible combination of arguments will work. -Usually these arguments are implemented by specific :c:func:`PyArg_ParseTuple` -*format units*, with specific behavior. For example, currently you cannot -call ``unsigned_short`` without also specifying ``bitwise=True``. -Although it's perfectly reasonable to think this would work, these semantics don't -map to any existing format unit. So Argument Clinic doesn't support it. (Or, at -least, not yet.) - -Below is a table showing the mapping of legacy converters into real -Argument Clinic converters. On the left is the legacy converter, -on the right is the text you'd replace it with. - -========= ================================================================================= -``'B'`` ``unsigned_char(bitwise=True)`` -``'b'`` ``unsigned_char`` -``'c'`` ``char`` -``'C'`` ``int(accept={str})`` -``'d'`` ``double`` -``'D'`` ``Py_complex`` -``'es'`` ``str(encoding='name_of_encoding')`` -``'es#'`` ``str(encoding='name_of_encoding', zeroes=True)`` -``'et'`` ``str(encoding='name_of_encoding', accept={bytes, bytearray, str})`` -``'et#'`` ``str(encoding='name_of_encoding', accept={bytes, bytearray, str}, zeroes=True)`` -``'f'`` ``float`` -``'h'`` ``short`` -``'H'`` ``unsigned_short(bitwise=True)`` -``'i'`` ``int`` -``'I'`` ``unsigned_int(bitwise=True)`` -``'k'`` ``unsigned_long(bitwise=True)`` -``'K'`` ``unsigned_long_long(bitwise=True)`` -``'l'`` ``long`` -``'L'`` ``long long`` -``'n'`` ``Py_ssize_t`` -``'O'`` ``object`` -``'O!'`` ``object(subclass_of='&PySomething_Type')`` -``'O&'`` ``object(converter='name_of_c_function')`` -``'p'`` ``bool`` -``'S'`` ``PyBytesObject`` -``'s'`` ``str`` -``'s#'`` ``str(zeroes=True)`` -``'s*'`` ``Py_buffer(accept={buffer, str})`` -``'U'`` ``unicode`` -``'u'`` ``wchar_t`` -``'u#'`` ``wchar_t(zeroes=True)`` -``'w*'`` ``Py_buffer(accept={rwbuffer})`` -``'Y'`` ``PyByteArrayObject`` -``'y'`` ``str(accept={bytes})`` -``'y#'`` ``str(accept={robuffer}, zeroes=True)`` -``'y*'`` ``Py_buffer`` -``'Z'`` ``wchar_t(accept={str, NoneType})`` -``'Z#'`` ``wchar_t(accept={str, NoneType}, zeroes=True)`` -``'z'`` ``str(accept={str, NoneType})`` -``'z#'`` ``str(accept={str, NoneType}, zeroes=True)`` -``'z*'`` ``Py_buffer(accept={buffer, str, NoneType})`` -========= ================================================================================= - -As an example, here's our sample ``pickle.Pickler.dump`` using the proper -converter:: - - /*[clinic input] - pickle.Pickler.dump - - obj: object - The object to be pickled. - / - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - -One advantage of real converters is that they're more flexible than legacy -converters. For example, the ``unsigned_int`` converter (and all the -``unsigned_`` converters) can be specified without ``bitwise=True``. Their -default behavior performs range checking on the value, and they won't accept -negative numbers. You just can't do that with a legacy converter! - -Argument Clinic will show you all the converters it has -available. For each converter it'll show you all the parameters -it accepts, along with the default value for each parameter. -Just run ``Tools/clinic/clinic.py --converters`` to see the full list. - - -How to use the ``Py_buffer`` converter --------------------------------------- - -When using the ``Py_buffer`` converter -(or the ``'s*'``, ``'w*'``, ``'*y'``, or ``'z*'`` legacy converters), -you *must* not call :c:func:`PyBuffer_Release` on the provided buffer. -Argument Clinic generates code that does it for you (in the parsing function). - - -.. _clinic-howto-advanced-converters: - -How to use advanced converters ------------------------------- - -Remember those format units you skipped for your first -time because they were advanced? Here's how to handle those too. - -The trick is, all those format units take arguments—either -conversion functions, or types, or strings specifying an encoding. -(But "legacy converters" don't support arguments. That's why we -skipped them for your first function.) The argument you specified -to the format unit is now an argument to the converter; this -argument is either *converter* (for ``O&``), *subclass_of* (for ``O!``), -or *encoding* (for all the format units that start with ``e``). - -When using *subclass_of*, you may also want to use the other -custom argument for ``object()``: *type*, which lets you set the type -actually used for the parameter. For example, if you want to ensure -that the object is a subclass of :c:var:`PyUnicode_Type`, you probably want -to use the converter ``object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type')``. - -One possible problem with using Argument Clinic: it takes away some possible -flexibility for the format units starting with ``e``. When writing a -:c:func:`!PyArg_Parse*` call by hand, you could theoretically decide at runtime what -encoding string to pass to that call. But now this string must -be hard-coded at Argument-Clinic-preprocessing-time. This limitation is deliberate; -it made supporting this format unit much easier, and may allow for future optimizations. -This restriction doesn't seem unreasonable; CPython itself always passes in static -hard-coded encoding strings for parameters whose format units start with ``e``. - - -.. _clinic-howto-default-values: -.. _default_values: - -How to assign default values to parameter ------------------------------------------ - -Default values for parameters can be any of a number of values. -At their simplest, they can be string, int, or float literals: - -.. code-block:: none - - foo: str = "abc" - bar: int = 123 - bat: float = 45.6 - -They can also use any of Python's built-in constants: - -.. code-block:: none - - yep: bool = True - nope: bool = False - nada: object = None - -There's also special support for a default value of ``NULL``, and -for simple expressions, documented in the following sections. - - -The ``NULL`` default value -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For string and object parameters, you can set them to ``None`` to indicate -that there's no default. However, that means the C variable will be -initialized to ``Py_None``. For convenience's sakes, there's a special -value called ``NULL`` for just this reason: from Python's perspective it -behaves like a default value of ``None``, but the C variable is initialized -with ``NULL``. - - -Symbolic default values -^^^^^^^^^^^^^^^^^^^^^^^ - -The default value you provide for a parameter can't be any arbitrary -expression. Currently the following are explicitly supported: - -* Numeric constants (integer and float) -* String constants -* ``True``, ``False``, and ``None`` -* Simple symbolic constants like :py:data:`sys.maxsize`, which must - start with the name of the module - -(In the future, this may need to get even more elaborate, -to allow full expressions like ``CONSTANT - 1``.) - - -Expressions as default values -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The default value for a parameter can be more than just a literal value. -It can be an entire expression, using math operators and looking up attributes -on objects. However, this support isn't exactly simple, because of some -non-obvious semantics. - -Consider the following example: - -.. code-block:: none - - foo: Py_ssize_t = sys.maxsize - 1 - -:py:data:`sys.maxsize` can have different values on different platforms. Therefore -Argument Clinic can't simply evaluate that expression locally and hard-code it -in C. So it stores the default in such a way that it will get evaluated at -runtime, when the user asks for the function's signature. - -What namespace is available when the expression is evaluated? It's evaluated -in the context of the module the builtin came from. So, if your module has an -attribute called :py:attr:`!max_widgets`, you may simply use it: - -.. code-block:: none - - foo: Py_ssize_t = max_widgets - -If the symbol isn't found in the current module, it fails over to looking in -:py:data:`sys.modules`. That's how it can find :py:data:`sys.maxsize` for example. -(Since you don't know in advance what modules the user will load into their interpreter, -it's best to restrict yourself to modules that are preloaded by Python itself.) - -Evaluating default values only at runtime means Argument Clinic can't compute -the correct equivalent C default value. So you need to tell it explicitly. -When you use an expression, you must also specify the equivalent expression -in C, using the *c_default* parameter to the converter: - -.. code-block:: none - - foo: Py_ssize_t(c_default="PY_SSIZE_T_MAX - 1") = sys.maxsize - 1 - -Another complication: Argument Clinic can't know in advance whether or not the -expression you supply is valid. It parses it to make sure it looks legal, but -it can't *actually* know. You must be very careful when using expressions to -specify values that are guaranteed to be valid at runtime! - -Finally, because expressions must be representable as static C values, there -are many restrictions on legal expressions. Here's a list of Python features -you're not permitted to use: - -* Function calls. -* Inline if statements (``3 if foo else 5``). -* Automatic sequence unpacking (``*[1, 2, 3]``). -* List/set/dict comprehensions and generator expressions. -* Tuple/list/set/dict literals. - - -.. _clinic-howto-return-converters: - -How to use return converters ----------------------------- - -By default, the impl function Argument Clinic generates for you returns -:c:type:`PyObject * `. -But your C function often computes some C type, -then converts it into the :c:type:`!PyObject *` -at the last moment. Argument Clinic handles converting your inputs from Python types -into native C types—why not have it convert your return value from a native C type -into a Python type too? - -That's what a "return converter" does. It changes your impl function to return -some C type, then adds code to the generated (non-impl) function to handle converting -that value into the appropriate :c:type:`!PyObject *`. - -The syntax for return converters is similar to that of parameter converters. -You specify the return converter like it was a return annotation on the -function itself, using ``->`` notation. - -For example: - -.. code-block:: c - - /*[clinic input] - add -> int - - a: int - b: int - / - - [clinic start generated code]*/ - -Return converters behave much the same as parameter converters; -they take arguments, the arguments are all keyword-only, and if you're not changing -any of the default arguments you can omit the parentheses. - -(If you use both ``"as"`` *and* a return converter for your function, -the ``"as"`` should come before the return converter.) - -There's one additional complication when using return converters: how do you -indicate an error has occurred? Normally, a function returns a valid (non-``NULL``) -pointer for success, and ``NULL`` for failure. But if you use an integer return converter, -all integers are valid. How can Argument Clinic detect an error? Its solution: each return -converter implicitly looks for a special value that indicates an error. If you return -that value, and an error has been set (c:func:`PyErr_Occurred` returns a true -value), then the generated code will propagate the error. Otherwise it will -encode the value you return like normal. - -Currently Argument Clinic supports only a few return converters: - -.. code-block:: none - - bool - double - float - int - long - Py_ssize_t - size_t - unsigned int - unsigned long - -None of these take parameters. -For all of these, return ``-1`` to indicate error. - -To see all the return converters Argument Clinic supports, along with -their parameters (if any), -just run ``Tools/clinic/clinic.py --converters`` for the full list. - - -How to clone existing functions -------------------------------- - -If you have a number of functions that look similar, you may be able to -use Clinic's "clone" feature. When you clone an existing function, -you reuse: - -* its parameters, including - - * their names, - - * their converters, with all parameters, - - * their default values, - - * their per-parameter docstrings, - - * their *kind* (whether they're positional only, - positional or keyword, or keyword only), and - -* its return converter. - -The only thing not copied from the original function is its docstring; -the syntax allows you to specify a new docstring. - -Here's the syntax for cloning a function:: - - /*[clinic input] - module.class.new_function [as c_basename] = module.class.existing_function - - Docstring for new_function goes here. - [clinic start generated code]*/ - -(The functions can be in different modules or classes. I wrote -``module.class`` in the sample just to illustrate that you must -use the full path to *both* functions.) - -Sorry, there's no syntax for partially cloning a function, or cloning a function -then modifying it. Cloning is an all-or nothing proposition. - -Also, the function you are cloning from must have been previously defined -in the current file. - - -How to call Python code ------------------------ - -The rest of the advanced topics require you to write Python code -which lives inside your C file and modifies Argument Clinic's -runtime state. This is simple: you simply define a Python block. - -A Python block uses different delimiter lines than an Argument -Clinic function block. It looks like this:: - - /*[python input] - # python code goes here - [python start generated code]*/ - -All the code inside the Python block is executed at the -time it's parsed. All text written to stdout inside the block -is redirected into the "output" after the block. - -As an example, here's a Python block that adds a static integer -variable to the C code:: - - /*[python input] - print('static int __ignored_unused_variable__ = 0;') - [python start generated code]*/ - static int __ignored_unused_variable__ = 0; - /*[python checksum:...]*/ - - -.. _clinic-howto-self-converter: - -How to use the "self converter" -------------------------------- - -Argument Clinic automatically adds a "self" parameter for you -using a default converter. It automatically sets the ``type`` -of this parameter to the "pointer to an instance" you specified -when you declared the type. However, you can override -Argument Clinic's converter and specify one yourself. -Just add your own *self* parameter as the first parameter in a -block, and ensure that its converter is an instance of -:class:`!self_converter` or a subclass thereof. - -What's the point? This lets you override the type of ``self``, -or give it a different default name. - -How do you specify the custom type you want to cast ``self`` to? -If you only have one or two functions with the same type for ``self``, -you can directly use Argument Clinic's existing ``self`` converter, -passing in the type you want to use as the *type* parameter:: - - /*[clinic input] - - _pickle.Pickler.dump - - self: self(type="PicklerObject *") - obj: object - / - - Write a pickled representation of the given object to the open file. - [clinic start generated code]*/ - -On the other hand, if you have a lot of functions that will use the same -type for ``self``, it's best to create your own converter, subclassing -:class:`!self_converter` but overwriting the :py:attr:`!type` member:: - - /*[python input] - class PicklerObject_converter(self_converter): - type = "PicklerObject *" - [python start generated code]*/ - - /*[clinic input] - - _pickle.Pickler.dump - - self: PicklerObject - obj: object - / - - Write a pickled representation of the given object to the open file. - [clinic start generated code]*/ - - -How to use the "defining class" converter ------------------------------------------ - -Argument Clinic facilitates gaining access to the defining class of a method. -This is useful for :ref:`heap type ` methods that need to fetch -module level state. Use :c:func:`PyType_FromModuleAndSpec` to associate a new -heap type with a module. You can now use :c:func:`PyType_GetModuleState` on -the defining class to fetch the module state, for example from a module method. - -Example from :source:`Modules/zlibmodule.c`. -First, ``defining_class`` is added to the clinic input:: - - /*[clinic input] - zlib.Compress.compress - - cls: defining_class - data: Py_buffer - Binary data to be compressed. - / - - -After running the Argument Clinic tool, the following function signature is -generated:: - - /*[clinic start generated code]*/ - static PyObject * - zlib_Compress_compress_impl(compobject *self, PyTypeObject *cls, - Py_buffer *data) - /*[clinic end generated code: output=6731b3f0ff357ca6 input=04d00f65ab01d260]*/ - - -The following code can now use ``PyType_GetModuleState(cls)`` to fetch the -module state:: - - zlibstate *state = PyType_GetModuleState(cls); - - -Each method may only have one argument using this converter, and it must appear -after ``self``, or, if ``self`` is not used, as the first argument. The argument -will be of type ``PyTypeObject *``. The argument will not appear in the -:py:attr:`!__text_signature__`. - -The ``defining_class`` converter is not compatible with :py:meth:`!__init__` -and :py:meth:`!__new__` methods, which cannot use the :c:macro:`METH_METHOD` -convention. - -It is not possible to use ``defining_class`` with slot methods. In order to -fetch the module state from such methods, use :c:func:`PyType_GetModuleByDef` -to look up the module and then :c:func:`PyModule_GetState` to fetch the module -state. Example from the ``setattro`` slot method in -:source:`Modules/_threadmodule.c`:: - - static int - local_setattro(localobject *self, PyObject *name, PyObject *v) - { - PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module); - thread_module_state *state = get_thread_state(module); - ... - } - - -See also :pep:`573`. - - -.. _clinic-howto-custom-converter: - -How to write a custom converter -------------------------------- - -A converter is a Python class that inherits from :py:class:`CConverter`. -The main purpose of a custom converter, is for parameters parsed with -the ``O&`` format unit --- parsing such a parameter means calling -a :c:func:`PyArg_ParseTuple` "converter function". - -Your converter class should be named :samp:`{ConverterName}_converter`. -By following this convention, your converter class will be automatically -registered with Argument Clinic, with its *converter name* being the name of -your converter class with the ``_converter`` suffix stripped off. - -Instead of subclassing :py:meth:`!CConverter.__init__`, -write a :py:meth:`!converter_init` method. -:py:meth:`!converter_init` always accepts a *self* parameter. -After *self*, all additional parameters **must** be keyword-only. -Any arguments passed to the converter in Argument Clinic -will be passed along to your :py:meth:`!converter_init` method. -See :py:class:`CConverter` for a list of members you may wish to specify in -your subclass. - -Here's the simplest example of a custom converter, from :source:`Modules/zlibmodule.c`:: - - /*[python input] - - class ssize_t_converter(CConverter): - type = 'Py_ssize_t' - converter = 'ssize_t_converter' - - [python start generated code]*/ - /*[python end generated code: output=da39a3ee5e6b4b0d input=35521e4e733823c7]*/ - -This block adds a converter named ``ssize_t`` to Argument Clinic. -Parameters declared as ``ssize_t`` will be declared with type :c:type:`Py_ssize_t`, -and will be parsed by the ``'O&'`` format unit, -which will call the :c:func:`!ssize_t_converter` converter C function. -``ssize_t`` variables automatically support default values. - -More sophisticated custom converters can insert custom C code to -handle initialization and cleanup. -You can see more examples of custom converters in the CPython -source tree; grep the C files for the string ``CConverter``. - - -How to write a custom return converter --------------------------------------- - -Writing a custom return converter is much like writing -a custom converter. Except it's somewhat simpler, because return -converters are themselves much simpler. - -Return converters must subclass :py:class:`!CReturnConverter`. -There are no examples yet of custom return converters, -because they are not widely used yet. If you wish to -write your own return converter, please read :source:`Tools/clinic/clinic.py`, -specifically the implementation of :py:class:`!CReturnConverter` and -all its subclasses. - - -How to convert ``METH_O`` and ``METH_NOARGS`` functions -------------------------------------------------------- - -To convert a function using :c:macro:`METH_O`, make sure the function's -single argument is using the ``object`` converter, and mark the -arguments as positional-only:: - - /*[clinic input] - meth_o_sample - - argument: object - / - [clinic start generated code]*/ - - -To convert a function using :c:macro:`METH_NOARGS`, just don't specify -any arguments. - -You can still use a self converter, a return converter, and specify -a *type* argument to the object converter for :c:macro:`METH_O`. - - -How to convert ``tp_new`` and ``tp_init`` functions ---------------------------------------------------- - -You can convert :c:member:`~PyTypeObject.tp_new` and -:c:member:`~PyTypeObject.tp_init` functions. -Just name them ``__new__`` or ``__init__`` as appropriate. Notes: - -* The function name generated for ``__new__`` doesn't end in ``__new__`` - like it would by default. It's just the name of the class, converted - into a valid C identifier. - -* No :c:type:`PyMethodDef` ``#define`` is generated for these functions. - -* ``__init__`` functions return ``int``, not ``PyObject *``. - -* Use the docstring as the class docstring. - -* Although ``__new__`` and ``__init__`` functions must always - accept both the ``args`` and ``kwargs`` objects, when converting - you may specify any signature for these functions that you like. - (If your function doesn't support keywords, the parsing function - generated will throw an exception if it receives any.) - - -How to change and redirect Clinic's output ------------------------------------------- - -It can be inconvenient to have Clinic's output interspersed with -your conventional hand-edited C code. Luckily, Clinic is configurable: -you can buffer up its output for printing later (or earlier!), or write -its output to a separate file. You can also add a prefix or suffix to -every line of Clinic's generated output. - -While changing Clinic's output in this manner can be a boon to readability, -it may result in Clinic code using types before they are defined, or -your code attempting to use Clinic-generated code before it is defined. -These problems can be easily solved by rearranging the declarations in your file, -or moving where Clinic's generated code goes. (This is why the default behavior -of Clinic is to output everything into the current block; while many people -consider this hampers readability, it will never require rearranging your -code to fix definition-before-use problems.) - -Let's start with defining some terminology: - -*field* - A field, in this context, is a subsection of Clinic's output. - For example, the ``#define`` for the :c:type:`PyMethodDef` structure - is a field, called ``methoddef_define``. Clinic has seven - different fields it can output per function definition: - - .. code-block:: none - - docstring_prototype - docstring_definition - methoddef_define - impl_prototype - parser_prototype - parser_definition - impl_definition - - All the names are of the form ``"_"``, - where ``""`` is the semantic object represented (the parsing function, - the impl function, the docstring, or the methoddef structure) and ``""`` - represents what kind of statement the field is. Field names that end in - ``"_prototype"`` - represent forward declarations of that thing, without the actual body/data - of the thing; field names that end in ``"_definition"`` represent the actual - definition of the thing, with the body/data of the thing. (``"methoddef"`` - is special, it's the only one that ends with ``"_define"``, representing that - it's a preprocessor #define.) - -*destination* - A destination is a place Clinic can write output to. There are - five built-in destinations: - - ``block`` - The default destination: printed in the output section of - the current Clinic block. - - ``buffer`` - A text buffer where you can save text for later. Text sent - here is appended to the end of any existing text. It's an - error to have any text left in the buffer when Clinic finishes - processing a file. - - ``file`` - A separate "clinic file" that will be created automatically by Clinic. - The filename chosen for the file is ``{basename}.clinic{extension}``, - where ``basename`` and ``extension`` were assigned the output - from ``os.path.splitext()`` run on the current file. (Example: - the ``file`` destination for :file:`_pickle.c` would be written to - :file:`_pickle.clinic.c`.) - - **Important: When using a** ``file`` **destination, you** - *must check in* **the generated file!** - - ``two-pass`` - A buffer like ``buffer``. However, a two-pass buffer can only - be dumped once, and it prints out all text sent to it during - all processing, even from Clinic blocks *after* the dumping point. - - ``suppress`` - The text is suppressed—thrown away. - - -Clinic defines five new directives that let you reconfigure its output. - -The first new directive is ``dump``: - -.. code-block:: none - - dump - -This dumps the current contents of the named destination into the output of -the current block, and empties it. This only works with ``buffer`` and -``two-pass`` destinations. - -The second new directive is ``output``. The most basic form of ``output`` -is like this: - -.. code-block:: none - - output - -This tells Clinic to output *field* to *destination*. ``output`` also -supports a special meta-destination, called ``everything``, which tells -Clinic to output *all* fields to that *destination*. - -``output`` has a number of other functions: - -.. code-block:: none - - output push - output pop - output preset - - -``output push`` and ``output pop`` allow you to push and pop -configurations on an internal configuration stack, so that you -can temporarily modify the output configuration, then easily restore -the previous configuration. Simply push before your change to save -the current configuration, then pop when you wish to restore the -previous configuration. - -``output preset`` sets Clinic's output to one of several built-in -preset configurations, as follows: - - ``block`` - Clinic's original starting configuration. Writes everything - immediately after the input block. - - Suppress the ``parser_prototype`` - and ``docstring_prototype``, write everything else to ``block``. - - ``file`` - Designed to write everything to the "clinic file" that it can. - You then ``#include`` this file near the top of your file. - You may need to rearrange your file to make this work, though - usually this just means creating forward declarations for various - ``typedef`` and ``PyTypeObject`` definitions. - - Suppress the ``parser_prototype`` - and ``docstring_prototype``, write the ``impl_definition`` to - ``block``, and write everything else to ``file``. - - The default filename is ``"{dirname}/clinic/{basename}.h"``. - - ``buffer`` - Save up most of the output from Clinic, to be written into - your file near the end. For Python files implementing modules - or builtin types, it's recommended that you dump the buffer - just above the static structures for your module or - builtin type; these are normally very near the end. Using - ``buffer`` may require even more editing than ``file``, if - your file has static ``PyMethodDef`` arrays defined in the - middle of the file. - - Suppress the ``parser_prototype``, ``impl_prototype``, - and ``docstring_prototype``, write the ``impl_definition`` to - ``block``, and write everything else to ``file``. - - ``two-pass`` - Similar to the ``buffer`` preset, but writes forward declarations to - the ``two-pass`` buffer, and definitions to the ``buffer``. - This is similar to the ``buffer`` preset, but may require - less editing than ``buffer``. Dump the ``two-pass`` buffer - near the top of your file, and dump the ``buffer`` near - the end just like you would when using the ``buffer`` preset. - - Suppresses the ``impl_prototype``, write the ``impl_definition`` - to ``block``, write ``docstring_prototype``, ``methoddef_define``, - and ``parser_prototype`` to ``two-pass``, write everything else - to ``buffer``. - - ``partial-buffer`` - Similar to the ``buffer`` preset, but writes more things to ``block``, - only writing the really big chunks of generated code to ``buffer``. - This avoids the definition-before-use problem of ``buffer`` completely, - at the small cost of having slightly more stuff in the block's output. - Dump the ``buffer`` near the end, just like you would when using - the ``buffer`` preset. - - Suppresses the ``impl_prototype``, write the ``docstring_definition`` - and ``parser_definition`` to ``buffer``, write everything else to ``block``. - -The third new directive is ``destination``: - -.. code-block:: none - - destination [...] - -This performs an operation on the destination named ``name``. - -There are two defined subcommands: ``new`` and ``clear``. - -The ``new`` subcommand works like this: - -.. code-block:: none - - destination new - -This creates a new destination with name ```` and type ````. - -There are five destination types: - - ``suppress`` - Throws the text away. - - ``block`` - Writes the text to the current block. This is what Clinic - originally did. - - ``buffer`` - A simple text buffer, like the "buffer" builtin destination above. - - ``file`` - A text file. The file destination takes an extra argument, - a template to use for building the filename, like so: - - destination new - - The template can use three strings internally that will be replaced - by bits of the filename: - - {path} - The full path to the file, including directory and full filename. - {dirname} - The name of the directory the file is in. - {basename} - Just the name of the file, not including the directory. - {basename_root} - Basename with the extension clipped off - (everything up to but not including the last '.'). - {basename_extension} - The last '.' and everything after it. If the basename - does not contain a period, this will be the empty string. - - If there are no periods in the filename, {basename} and {filename} - are the same, and {extension} is empty. "{basename}{extension}" - is always exactly the same as "{filename}"." - - ``two-pass`` - A two-pass buffer, like the "two-pass" builtin destination above. - - -The ``clear`` subcommand works like this: - -.. code-block:: none - - destination clear - -It removes all the accumulated text up to this point in the destination. -(I don't know what you'd need this for, but I thought maybe it'd be -useful while someone's experimenting.) - -The fourth new directive is ``set``: - -.. code-block:: none - - set line_prefix "string" - set line_suffix "string" - -``set`` lets you set two internal variables in Clinic. -``line_prefix`` is a string that will be prepended to every line of Clinic's output; -``line_suffix`` is a string that will be appended to every line of Clinic's output. - -Both of these support two format strings: - - ``{block comment start}`` - Turns into the string ``/*``, the start-comment text sequence for C files. - - ``{block comment end}`` - Turns into the string ``*/``, the end-comment text sequence for C files. - -The final new directive is one you shouldn't need to use directly, -called ``preserve``: - -.. code-block:: none - - preserve - -This tells Clinic that the current contents of the output should be kept, unmodified. -This is used internally by Clinic when dumping output into ``file`` files; wrapping -it in a Clinic block lets Clinic use its existing checksum functionality to ensure -the file was not modified by hand before it gets overwritten. - - -How to use the ``#ifdef`` trick -------------------------------- - -If you're converting a function that isn't available on all platforms, -there's a trick you can use to make life a little easier. The existing -code probably looks like this:: - - #ifdef HAVE_FUNCTIONNAME - static module_functionname(...) - { - ... - } - #endif /* HAVE_FUNCTIONNAME */ - -And then in the ``PyMethodDef`` structure at the bottom the existing code -will have: - -.. code-block:: none - - #ifdef HAVE_FUNCTIONNAME - {'functionname', ... }, - #endif /* HAVE_FUNCTIONNAME */ - -In this scenario, you should enclose the body of your impl function inside the ``#ifdef``, -like so:: - - #ifdef HAVE_FUNCTIONNAME - /*[clinic input] - module.functionname - ... - [clinic start generated code]*/ - static module_functionname(...) - { - ... - } - #endif /* HAVE_FUNCTIONNAME */ - -Then, remove those three lines from the :c:type:`PyMethodDef` structure, -replacing them with the macro Argument Clinic generated: - -.. code-block:: none - - MODULE_FUNCTIONNAME_METHODDEF - -(You can find the real name for this macro inside the generated code. -Or you can calculate it yourself: it's the name of your function as defined -on the first line of your block, but with periods changed to underscores, -uppercased, and ``"_METHODDEF"`` added to the end.) - -Perhaps you're wondering: what if ``HAVE_FUNCTIONNAME`` isn't defined? -The ``MODULE_FUNCTIONNAME_METHODDEF`` macro won't be defined either! - -Here's where Argument Clinic gets very clever. It actually detects that the -Argument Clinic block might be deactivated by the ``#ifdef``. When that -happens, it generates a little extra code that looks like this:: - - #ifndef MODULE_FUNCTIONNAME_METHODDEF - #define MODULE_FUNCTIONNAME_METHODDEF - #endif /* !defined(MODULE_FUNCTIONNAME_METHODDEF) */ - -That means the macro always works. If the function is defined, this turns -into the correct structure, including the trailing comma. If the function is -undefined, this turns into nothing. - -However, this causes one ticklish problem: where should Argument Clinic put this -extra code when using the "block" output preset? It can't go in the output block, -because that could be deactivated by the ``#ifdef``. (That's the whole point!) - -In this situation, Argument Clinic writes the extra code to the "buffer" destination. -This may mean that you get a complaint from Argument Clinic: - -.. code-block:: none - - Warning in file "Modules/posixmodule.c" on line 12357: - Destination buffer 'buffer' not empty at end of file, emptying. - -When this happens, just open your file, find the ``dump buffer`` block that -Argument Clinic added to your file (it'll be at the very bottom), then -move it above the :c:type:`PyMethodDef` structure where that macro is used. - - -How to use Argument Clinic in Python files ------------------------------------------- - -It's actually possible to use Argument Clinic to preprocess Python files. -There's no point to using Argument Clinic blocks, of course, as the output -wouldn't make any sense to the Python interpreter. But using Argument Clinic -to run Python blocks lets you use Python as a Python preprocessor! - -Since Python comments are different from C comments, Argument Clinic -blocks embedded in Python files look slightly different. They look like this: - -.. code-block:: python3 - - #/*[python input] - #print("def foo(): pass") - #[python start generated code]*/ - def foo(): pass - #/*[python checksum:...]*/ + The Argument Clinic How-TO has been moved to the `Python Developer's Guide + `__. diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst index f521276a5a83c5..6280f057716803 100644 --- a/Doc/howto/index.rst +++ b/Doc/howto/index.rst @@ -28,7 +28,6 @@ Currently, the HOWTOs are: urllib2.rst argparse.rst ipaddress.rst - clinic.rst instrumentation.rst perf_profiling.rst annotations.rst diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 68fd4d7759a127..6cbc06efeb93a6 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -123,7 +123,7 @@ There is a new function parameter syntax ``/`` to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments. This is the same notation shown by ``help()`` for C functions annotated with Larry Hastings' -:ref:`Argument Clinic ` tool. +`Argument Clinic `__ tool. In the following example, parameters *a* and *b* are positional-only, while *c* or *d* can be positional or keyword, and *e* or *f* are From ea3ac56a05d00da82ffd4b9326654aab4893cb72 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 12 Oct 2023 12:03:09 +0200 Subject: [PATCH 1005/1206] [3.12] gh-107450: Raise OverflowError when parser column offset overflows (GH-110754) (#110762) (cherry picked from commit fb7843ee895ac7f6eeb58f356b1a320eea081cfc) Co-authored-by: Lysandros Nikolaou --- Lib/test/test_exceptions.py | 4 ++++ Parser/pegen_errors.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 72afb3b0fb03f8..5d460982ddfa48 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -318,6 +318,10 @@ def baz(): check('(yield i) = 2', 1, 2) check('def f(*):\n pass', 1, 7) + def testMemoryErrorBigSource(self): + with self.assertRaisesRegex(OverflowError, "column offset overflow"): + exec(f"if True:\n {' ' * 2**31}print('hello world')") + @cpython_only def testSettingException(self): # test that setting an exception at the C level works even if the diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index cbeb9da04d92d8..71c476517375bb 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -233,6 +233,12 @@ _PyPegen_raise_error(Parser *p, PyObject *errtype, int use_mark, const char *err col_offset = 0; } else { const char* start = p->tok->buf ? p->tok->line_start : p->tok->buf; + if (p->tok->cur - start > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Parser column offset overflow - source line is too big"); + p->error_indicator = 1; + return NULL; + } col_offset = Py_SAFE_DOWNCAST(p->tok->cur - start, intptr_t, int); } } else { From 4d0e6c895e8b7396ea9d84422db05b329d1985ac Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Thu, 12 Oct 2023 11:51:56 +0100 Subject: [PATCH 1006/1206] [3.12] gh-110696: Fix incorrect syntax error message for incorrect argument unpacking (GH-110706) (#110765) (cherry picked from commit 3d180347ae73119bb51500efeeafdcd62bcc6f78) --- Grammar/python.gram | 3 +- Lib/test/test_syntax.py | 11 + ...-10-11-13-46-14.gh-issue-110696.J9kSzr.rst | 2 + Parser/parser.c | 2696 ++++++++++------- 4 files changed, 1539 insertions(+), 1173 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-11-13-46-14.gh-issue-110696.J9kSzr.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index ed0b326fa58642..c442db2fa6172e 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -1128,7 +1128,8 @@ func_type_comment[Token*]: # From here on, there are rules for invalid syntax with specialised error messages invalid_arguments: - | a=args ',' '*' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable argument unpacking follows keyword argument unpacking") } + | ((','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' b='*' { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(b, "iterable argument unpacking follows keyword argument unpacking") } | a=expression b=for_if_clauses ',' [args | expression for_if_clauses] { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") } | a=NAME b='=' expression for_if_clauses { diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 4c988382f8b411..52fc3573ddb7e0 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1955,6 +1955,17 @@ def f(x: *b) ... SyntaxError: yield expression cannot be used within the definition of a generic + >>> f(**x, *y) + Traceback (most recent call last): + SyntaxError: iterable argument unpacking follows keyword argument unpacking + + >>> f(**x, *) + Traceback (most recent call last): + SyntaxError: iterable argument unpacking follows keyword argument unpacking + + >>> f(x, *:) + Traceback (most recent call last): + SyntaxError: invalid syntax """ import re diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-11-13-46-14.gh-issue-110696.J9kSzr.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-11-13-46-14.gh-issue-110696.J9kSzr.rst new file mode 100644 index 00000000000000..c845289d714f4c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-11-13-46-14.gh-issue-110696.J9kSzr.rst @@ -0,0 +1,2 @@ +Fix incorrect error message for invalid argument unpacking. Patch by Pablo +Galindo diff --git a/Parser/parser.c b/Parser/parser.c index f7229cb91681aa..42201c4031dcb2 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -481,65 +481,65 @@ static char *soft_keywords[] = { #define _tmp_157_type 1400 #define _tmp_158_type 1401 #define _tmp_159_type 1402 -#define _loop0_160_type 1403 +#define _tmp_160_type 1403 #define _loop0_161_type 1404 #define _loop0_162_type 1405 -#define _tmp_163_type 1406 +#define _loop0_163_type 1406 #define _tmp_164_type 1407 #define _tmp_165_type 1408 #define _tmp_166_type 1409 #define _tmp_167_type 1410 -#define _loop0_168_type 1411 +#define _tmp_168_type 1411 #define _loop0_169_type 1412 #define _loop0_170_type 1413 -#define _loop1_171_type 1414 -#define _tmp_172_type 1415 -#define _loop0_173_type 1416 -#define _tmp_174_type 1417 -#define _loop0_175_type 1418 -#define _loop1_176_type 1419 -#define _tmp_177_type 1420 +#define _loop0_171_type 1414 +#define _loop1_172_type 1415 +#define _tmp_173_type 1416 +#define _loop0_174_type 1417 +#define _tmp_175_type 1418 +#define _loop0_176_type 1419 +#define _loop1_177_type 1420 #define _tmp_178_type 1421 #define _tmp_179_type 1422 -#define _loop0_180_type 1423 -#define _tmp_181_type 1424 +#define _tmp_180_type 1423 +#define _loop0_181_type 1424 #define _tmp_182_type 1425 -#define _loop1_183_type 1426 -#define _tmp_184_type 1427 -#define _loop0_185_type 1428 +#define _tmp_183_type 1426 +#define _loop1_184_type 1427 +#define _tmp_185_type 1428 #define _loop0_186_type 1429 #define _loop0_187_type 1430 -#define _loop0_189_type 1431 -#define _gather_188_type 1432 -#define _tmp_190_type 1433 -#define _loop0_191_type 1434 -#define _tmp_192_type 1435 -#define _loop0_193_type 1436 -#define _loop1_194_type 1437 +#define _loop0_188_type 1431 +#define _loop0_190_type 1432 +#define _gather_189_type 1433 +#define _tmp_191_type 1434 +#define _loop0_192_type 1435 +#define _tmp_193_type 1436 +#define _loop0_194_type 1437 #define _loop1_195_type 1438 -#define _tmp_196_type 1439 +#define _loop1_196_type 1439 #define _tmp_197_type 1440 -#define _loop0_198_type 1441 -#define _tmp_199_type 1442 +#define _tmp_198_type 1441 +#define _loop0_199_type 1442 #define _tmp_200_type 1443 #define _tmp_201_type 1444 -#define _loop0_203_type 1445 -#define _gather_202_type 1446 -#define _loop0_205_type 1447 -#define _gather_204_type 1448 -#define _loop0_207_type 1449 -#define _gather_206_type 1450 -#define _loop0_209_type 1451 -#define _gather_208_type 1452 -#define _loop0_211_type 1453 -#define _gather_210_type 1454 -#define _tmp_212_type 1455 -#define _loop0_213_type 1456 -#define _loop1_214_type 1457 -#define _tmp_215_type 1458 -#define _loop0_216_type 1459 -#define _loop1_217_type 1460 -#define _tmp_218_type 1461 +#define _tmp_202_type 1445 +#define _loop0_204_type 1446 +#define _gather_203_type 1447 +#define _loop0_206_type 1448 +#define _gather_205_type 1449 +#define _loop0_208_type 1450 +#define _gather_207_type 1451 +#define _loop0_210_type 1452 +#define _gather_209_type 1453 +#define _loop0_212_type 1454 +#define _gather_211_type 1455 +#define _tmp_213_type 1456 +#define _loop0_214_type 1457 +#define _loop1_215_type 1458 +#define _tmp_216_type 1459 +#define _loop0_217_type 1460 +#define _loop1_218_type 1461 #define _tmp_219_type 1462 #define _tmp_220_type 1463 #define _tmp_221_type 1464 @@ -549,9 +549,9 @@ static char *soft_keywords[] = { #define _tmp_225_type 1468 #define _tmp_226_type 1469 #define _tmp_227_type 1470 -#define _loop0_229_type 1471 -#define _gather_228_type 1472 -#define _tmp_230_type 1473 +#define _tmp_228_type 1471 +#define _loop0_230_type 1472 +#define _gather_229_type 1473 #define _tmp_231_type 1474 #define _tmp_232_type 1475 #define _tmp_233_type 1476 @@ -564,8 +564,8 @@ static char *soft_keywords[] = { #define _tmp_240_type 1483 #define _tmp_241_type 1484 #define _tmp_242_type 1485 -#define _loop0_243_type 1486 -#define _tmp_244_type 1487 +#define _tmp_243_type 1486 +#define _loop0_244_type 1487 #define _tmp_245_type 1488 #define _tmp_246_type 1489 #define _tmp_247_type 1490 @@ -595,8 +595,14 @@ static char *soft_keywords[] = { #define _tmp_271_type 1514 #define _tmp_272_type 1515 #define _tmp_273_type 1516 -#define _tmp_274_type 1517 -#define _tmp_275_type 1518 +#define _loop0_275_type 1517 +#define _gather_274_type 1518 +#define _tmp_276_type 1519 +#define _tmp_277_type 1520 +#define _tmp_278_type 1521 +#define _tmp_279_type 1522 +#define _tmp_280_type 1523 +#define _tmp_281_type 1524 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -1001,65 +1007,65 @@ static void *_tmp_156_rule(Parser *p); static void *_tmp_157_rule(Parser *p); static void *_tmp_158_rule(Parser *p); static void *_tmp_159_rule(Parser *p); -static asdl_seq *_loop0_160_rule(Parser *p); +static void *_tmp_160_rule(Parser *p); static asdl_seq *_loop0_161_rule(Parser *p); static asdl_seq *_loop0_162_rule(Parser *p); -static void *_tmp_163_rule(Parser *p); +static asdl_seq *_loop0_163_rule(Parser *p); static void *_tmp_164_rule(Parser *p); static void *_tmp_165_rule(Parser *p); static void *_tmp_166_rule(Parser *p); static void *_tmp_167_rule(Parser *p); -static asdl_seq *_loop0_168_rule(Parser *p); +static void *_tmp_168_rule(Parser *p); static asdl_seq *_loop0_169_rule(Parser *p); static asdl_seq *_loop0_170_rule(Parser *p); -static asdl_seq *_loop1_171_rule(Parser *p); -static void *_tmp_172_rule(Parser *p); -static asdl_seq *_loop0_173_rule(Parser *p); -static void *_tmp_174_rule(Parser *p); -static asdl_seq *_loop0_175_rule(Parser *p); -static asdl_seq *_loop1_176_rule(Parser *p); -static void *_tmp_177_rule(Parser *p); +static asdl_seq *_loop0_171_rule(Parser *p); +static asdl_seq *_loop1_172_rule(Parser *p); +static void *_tmp_173_rule(Parser *p); +static asdl_seq *_loop0_174_rule(Parser *p); +static void *_tmp_175_rule(Parser *p); +static asdl_seq *_loop0_176_rule(Parser *p); +static asdl_seq *_loop1_177_rule(Parser *p); static void *_tmp_178_rule(Parser *p); static void *_tmp_179_rule(Parser *p); -static asdl_seq *_loop0_180_rule(Parser *p); -static void *_tmp_181_rule(Parser *p); +static void *_tmp_180_rule(Parser *p); +static asdl_seq *_loop0_181_rule(Parser *p); static void *_tmp_182_rule(Parser *p); -static asdl_seq *_loop1_183_rule(Parser *p); -static void *_tmp_184_rule(Parser *p); -static asdl_seq *_loop0_185_rule(Parser *p); +static void *_tmp_183_rule(Parser *p); +static asdl_seq *_loop1_184_rule(Parser *p); +static void *_tmp_185_rule(Parser *p); static asdl_seq *_loop0_186_rule(Parser *p); static asdl_seq *_loop0_187_rule(Parser *p); -static asdl_seq *_loop0_189_rule(Parser *p); -static asdl_seq *_gather_188_rule(Parser *p); -static void *_tmp_190_rule(Parser *p); -static asdl_seq *_loop0_191_rule(Parser *p); -static void *_tmp_192_rule(Parser *p); -static asdl_seq *_loop0_193_rule(Parser *p); -static asdl_seq *_loop1_194_rule(Parser *p); +static asdl_seq *_loop0_188_rule(Parser *p); +static asdl_seq *_loop0_190_rule(Parser *p); +static asdl_seq *_gather_189_rule(Parser *p); +static void *_tmp_191_rule(Parser *p); +static asdl_seq *_loop0_192_rule(Parser *p); +static void *_tmp_193_rule(Parser *p); +static asdl_seq *_loop0_194_rule(Parser *p); static asdl_seq *_loop1_195_rule(Parser *p); -static void *_tmp_196_rule(Parser *p); +static asdl_seq *_loop1_196_rule(Parser *p); static void *_tmp_197_rule(Parser *p); -static asdl_seq *_loop0_198_rule(Parser *p); -static void *_tmp_199_rule(Parser *p); +static void *_tmp_198_rule(Parser *p); +static asdl_seq *_loop0_199_rule(Parser *p); static void *_tmp_200_rule(Parser *p); static void *_tmp_201_rule(Parser *p); -static asdl_seq *_loop0_203_rule(Parser *p); -static asdl_seq *_gather_202_rule(Parser *p); -static asdl_seq *_loop0_205_rule(Parser *p); -static asdl_seq *_gather_204_rule(Parser *p); -static asdl_seq *_loop0_207_rule(Parser *p); -static asdl_seq *_gather_206_rule(Parser *p); -static asdl_seq *_loop0_209_rule(Parser *p); -static asdl_seq *_gather_208_rule(Parser *p); -static asdl_seq *_loop0_211_rule(Parser *p); -static asdl_seq *_gather_210_rule(Parser *p); -static void *_tmp_212_rule(Parser *p); -static asdl_seq *_loop0_213_rule(Parser *p); -static asdl_seq *_loop1_214_rule(Parser *p); -static void *_tmp_215_rule(Parser *p); -static asdl_seq *_loop0_216_rule(Parser *p); -static asdl_seq *_loop1_217_rule(Parser *p); -static void *_tmp_218_rule(Parser *p); +static void *_tmp_202_rule(Parser *p); +static asdl_seq *_loop0_204_rule(Parser *p); +static asdl_seq *_gather_203_rule(Parser *p); +static asdl_seq *_loop0_206_rule(Parser *p); +static asdl_seq *_gather_205_rule(Parser *p); +static asdl_seq *_loop0_208_rule(Parser *p); +static asdl_seq *_gather_207_rule(Parser *p); +static asdl_seq *_loop0_210_rule(Parser *p); +static asdl_seq *_gather_209_rule(Parser *p); +static asdl_seq *_loop0_212_rule(Parser *p); +static asdl_seq *_gather_211_rule(Parser *p); +static void *_tmp_213_rule(Parser *p); +static asdl_seq *_loop0_214_rule(Parser *p); +static asdl_seq *_loop1_215_rule(Parser *p); +static void *_tmp_216_rule(Parser *p); +static asdl_seq *_loop0_217_rule(Parser *p); +static asdl_seq *_loop1_218_rule(Parser *p); static void *_tmp_219_rule(Parser *p); static void *_tmp_220_rule(Parser *p); static void *_tmp_221_rule(Parser *p); @@ -1069,9 +1075,9 @@ static void *_tmp_224_rule(Parser *p); static void *_tmp_225_rule(Parser *p); static void *_tmp_226_rule(Parser *p); static void *_tmp_227_rule(Parser *p); -static asdl_seq *_loop0_229_rule(Parser *p); -static asdl_seq *_gather_228_rule(Parser *p); -static void *_tmp_230_rule(Parser *p); +static void *_tmp_228_rule(Parser *p); +static asdl_seq *_loop0_230_rule(Parser *p); +static asdl_seq *_gather_229_rule(Parser *p); static void *_tmp_231_rule(Parser *p); static void *_tmp_232_rule(Parser *p); static void *_tmp_233_rule(Parser *p); @@ -1084,8 +1090,8 @@ static void *_tmp_239_rule(Parser *p); static void *_tmp_240_rule(Parser *p); static void *_tmp_241_rule(Parser *p); static void *_tmp_242_rule(Parser *p); -static asdl_seq *_loop0_243_rule(Parser *p); -static void *_tmp_244_rule(Parser *p); +static void *_tmp_243_rule(Parser *p); +static asdl_seq *_loop0_244_rule(Parser *p); static void *_tmp_245_rule(Parser *p); static void *_tmp_246_rule(Parser *p); static void *_tmp_247_rule(Parser *p); @@ -1115,8 +1121,14 @@ static void *_tmp_270_rule(Parser *p); static void *_tmp_271_rule(Parser *p); static void *_tmp_272_rule(Parser *p); static void *_tmp_273_rule(Parser *p); -static void *_tmp_274_rule(Parser *p); -static void *_tmp_275_rule(Parser *p); +static asdl_seq *_loop0_275_rule(Parser *p); +static asdl_seq *_gather_274_rule(Parser *p); +static void *_tmp_276_rule(Parser *p); +static void *_tmp_277_rule(Parser *p); +static void *_tmp_278_rule(Parser *p); +static void *_tmp_279_rule(Parser *p); +static void *_tmp_280_rule(Parser *p); +static void *_tmp_281_rule(Parser *p); // file: statements? $ @@ -19707,7 +19719,7 @@ func_type_comment_rule(Parser *p) } // invalid_arguments: -// | args ',' '*' +// | ((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' '*' // | expression for_if_clauses ',' [args | expression for_if_clauses] // | NAME '=' expression for_if_clauses // | [(args ',')] NAME '=' &(',' | ')') @@ -19726,25 +19738,25 @@ invalid_arguments_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // args ',' '*' + { // ((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' '*' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ',' '*'")); + D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' '*'")); Token * _literal; - Token * _literal_1; - expr_ty a; + void *_tmp_150_var; + Token * b; if ( - (a = args_rule(p)) // args + (_tmp_150_var = _tmp_150_rule(p)) // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_literal_1 = _PyPegen_expect_token(p, 16)) // token='*' + (b = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ',' '*'")); - _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "iterable argument unpacking follows keyword argument unpacking" ); + D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' '*'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( b , "iterable argument unpacking follows keyword argument unpacking" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -19754,7 +19766,7 @@ invalid_arguments_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_arguments[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ',' '*'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' '*'")); } { // expression for_if_clauses ',' [args | expression for_if_clauses] if (p->error_indicator) { @@ -19774,7 +19786,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_150_rule(p), !p->error_indicator) // [args | expression for_if_clauses] + (_opt_var = _tmp_151_rule(p), !p->error_indicator) // [args | expression for_if_clauses] ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); @@ -19834,13 +19846,13 @@ invalid_arguments_rule(Parser *p) expr_ty a; Token * b; if ( - (_opt_var = _tmp_151_rule(p), !p->error_indicator) // [(args ',')] + (_opt_var = _tmp_152_rule(p), !p->error_indicator) // [(args ',')] && (a = _PyPegen_name_token(p)) // NAME && (b = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_152_rule, p) + _PyPegen_lookahead(1, _tmp_153_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | ')')")); @@ -19978,7 +19990,7 @@ invalid_kwarg_rule(Parser *p) Token* a; Token * b; if ( - (a = (Token*)_tmp_153_rule(p)) // 'True' | 'False' | 'None' + (a = (Token*)_tmp_154_rule(p)) // 'True' | 'False' | 'None' && (b = _PyPegen_expect_token(p, 22)) // token='=' ) @@ -20038,7 +20050,7 @@ invalid_kwarg_rule(Parser *p) expr_ty a; Token * b; if ( - _PyPegen_lookahead(0, _tmp_154_rule, p) + _PyPegen_lookahead(0, _tmp_155_rule, p) && (a = expression_rule(p)) // expression && @@ -20294,7 +20306,7 @@ invalid_expression_rule(Parser *p) expr_ty a; expr_ty b; if ( - _PyPegen_lookahead(0, _tmp_155_rule, p) + _PyPegen_lookahead(0, _tmp_156_rule, p) && (a = disjunction_rule(p)) // disjunction && @@ -20330,7 +20342,7 @@ invalid_expression_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - _PyPegen_lookahead(0, _tmp_156_rule, p) + _PyPegen_lookahead(0, _tmp_157_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); @@ -20451,7 +20463,7 @@ invalid_named_expression_rule(Parser *p) && (b = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_157_rule, p) + _PyPegen_lookahead(0, _tmp_158_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | ':=')")); @@ -20477,7 +20489,7 @@ invalid_named_expression_rule(Parser *p) Token * b; expr_ty bitwise_or_var; if ( - _PyPegen_lookahead(0, _tmp_158_rule, p) + _PyPegen_lookahead(0, _tmp_159_rule, p) && (a = bitwise_or_rule(p)) // bitwise_or && @@ -20485,7 +20497,7 @@ invalid_named_expression_rule(Parser *p) && (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_159_rule, p) + _PyPegen_lookahead(0, _tmp_160_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')")); @@ -20565,7 +20577,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_160_var; + asdl_seq * _loop0_161_var; expr_ty a; expr_ty expression_var; if ( @@ -20573,7 +20585,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_160_var = _loop0_160_rule(p)) // star_named_expressions* + (_loop0_161_var = _loop0_161_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -20630,10 +20642,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_161_var; + asdl_seq * _loop0_162_var; expr_ty a; if ( - (_loop0_161_var = _loop0_161_rule(p)) // ((star_targets '='))* + (_loop0_162_var = _loop0_162_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -20660,10 +20672,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_162_var; + asdl_seq * _loop0_163_var; expr_ty a; if ( - (_loop0_162_var = _loop0_162_rule(p)) // ((star_targets '='))* + (_loop0_163_var = _loop0_163_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -20689,7 +20701,7 @@ invalid_assignment_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); - void *_tmp_163_var; + void *_tmp_164_var; expr_ty a; AugOperator* augassign_var; if ( @@ -20697,7 +20709,7 @@ invalid_assignment_rule(Parser *p) && (augassign_var = augassign_rule(p)) // augassign && - (_tmp_163_var = _tmp_163_rule(p)) // yield_expr | star_expressions + (_tmp_164_var = _tmp_164_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); @@ -20919,11 +20931,11 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_164_var; + void *_tmp_165_var; expr_ty a; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_164_var = _tmp_164_rule(p)) // '[' | '(' | '{' + (_tmp_165_var = _tmp_165_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -20950,12 +20962,12 @@ invalid_comprehension_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses")); Token * _literal; - void *_tmp_165_var; + void *_tmp_166_var; expr_ty a; asdl_expr_seq* b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_165_var = _tmp_165_rule(p)) // '[' | '{' + (_tmp_166_var = _tmp_166_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20985,12 +20997,12 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' for_if_clauses")); - void *_tmp_166_var; + void *_tmp_167_var; expr_ty a; Token * b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_166_var = _tmp_166_rule(p)) // '[' | '{' + (_tmp_167_var = _tmp_167_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -21125,13 +21137,13 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slash_no_default | slash_with_default) param_maybe_default* '/'")); - asdl_seq * _loop0_168_var; - void *_tmp_167_var; + asdl_seq * _loop0_169_var; + void *_tmp_168_var; Token * a; if ( - (_tmp_167_var = _tmp_167_rule(p)) // slash_no_default | slash_with_default + (_tmp_168_var = _tmp_168_rule(p)) // slash_no_default | slash_with_default && - (_loop0_168_var = _loop0_168_rule(p)) // param_maybe_default* + (_loop0_169_var = _loop0_169_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21155,7 +21167,7 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default? param_no_default* invalid_parameters_helper param_no_default")); - asdl_seq * _loop0_169_var; + asdl_seq * _loop0_170_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21163,7 +21175,7 @@ invalid_parameters_rule(Parser *p) if ( (_opt_var = slash_no_default_rule(p), !p->error_indicator) // slash_no_default? && - (_loop0_169_var = _loop0_169_rule(p)) // param_no_default* + (_loop0_170_var = _loop0_170_rule(p)) // param_no_default* && (invalid_parameters_helper_var = invalid_parameters_helper_rule(p)) // invalid_parameters_helper && @@ -21189,18 +21201,18 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* '(' param_no_default+ ','? ')'")); - asdl_seq * _loop0_170_var; - asdl_seq * _loop1_171_var; + asdl_seq * _loop0_171_var; + asdl_seq * _loop1_172_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_170_var = _loop0_170_rule(p)) // param_no_default* + (_loop0_171_var = _loop0_171_rule(p)) // param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_loop1_171_var = _loop1_171_rule(p)) // param_no_default+ + (_loop1_172_var = _loop1_172_rule(p)) // param_no_default+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21227,22 +21239,22 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(slash_no_default | slash_with_default)] param_maybe_default* '*' (',' | param_no_default) param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_173_var; - asdl_seq * _loop0_175_var; + asdl_seq * _loop0_174_var; + asdl_seq * _loop0_176_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_174_var; + void *_tmp_175_var; Token * a; if ( - (_opt_var = _tmp_172_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] + (_opt_var = _tmp_173_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] && - (_loop0_173_var = _loop0_173_rule(p)) // param_maybe_default* + (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_174_var = _tmp_174_rule(p)) // ',' | param_no_default + (_tmp_175_var = _tmp_175_rule(p)) // ',' | param_no_default && - (_loop0_175_var = _loop0_175_rule(p)) // param_maybe_default* + (_loop0_176_var = _loop0_176_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21267,10 +21279,10 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_176_var; + asdl_seq * _loop1_177_var; Token * a; if ( - (_loop1_176_var = _loop1_176_rule(p)) // param_maybe_default+ + (_loop1_177_var = _loop1_177_rule(p)) // param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21319,7 +21331,7 @@ invalid_default_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_177_rule, p) + _PyPegen_lookahead(1, _tmp_178_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')")); @@ -21364,12 +21376,12 @@ invalid_star_etc_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); - void *_tmp_178_var; + void *_tmp_179_var; Token * a; if ( (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_178_var = _tmp_178_rule(p)) // ')' | ',' (')' | '**') + (_tmp_179_var = _tmp_179_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -21452,20 +21464,20 @@ invalid_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_180_var; - void *_tmp_179_var; - void *_tmp_181_var; + asdl_seq * _loop0_181_var; + void *_tmp_180_var; + void *_tmp_182_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_179_var = _tmp_179_rule(p)) // param_no_default | ',' + (_tmp_180_var = _tmp_180_rule(p)) // param_no_default | ',' && - (_loop0_180_var = _loop0_180_rule(p)) // param_maybe_default* + (_loop0_181_var = _loop0_181_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_181_var = _tmp_181_rule(p)) // param_no_default | ',' + (_tmp_182_var = _tmp_182_rule(p)) // param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); @@ -21580,7 +21592,7 @@ invalid_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_182_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_183_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')")); @@ -21645,13 +21657,13 @@ invalid_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - asdl_seq * _loop1_183_var; + asdl_seq * _loop1_184_var; if ( - (_loop1_183_var = _loop1_183_rule(p)) // param_with_default+ + (_loop1_184_var = _loop1_184_rule(p)) // param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - _res = _loop1_183_var; + _res = _loop1_184_var; goto done; } p->mark = _mark; @@ -21716,13 +21728,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/'")); - asdl_seq * _loop0_185_var; - void *_tmp_184_var; + asdl_seq * _loop0_186_var; + void *_tmp_185_var; Token * a; if ( - (_tmp_184_var = _tmp_184_rule(p)) // lambda_slash_no_default | lambda_slash_with_default + (_tmp_185_var = _tmp_185_rule(p)) // lambda_slash_no_default | lambda_slash_with_default && - (_loop0_185_var = _loop0_185_rule(p)) // lambda_param_maybe_default* + (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21746,7 +21758,7 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default")); - asdl_seq * _loop0_186_var; + asdl_seq * _loop0_187_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21754,7 +21766,7 @@ invalid_lambda_parameters_rule(Parser *p) if ( (_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default? && - (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_no_default* + (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_no_default* && (invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper && @@ -21780,18 +21792,18 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* '(' ','.lambda_param+ ','? ')'")); - asdl_seq * _gather_188_var; - asdl_seq * _loop0_187_var; + asdl_seq * _gather_189_var; + asdl_seq * _loop0_188_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_no_default* + (_loop0_188_var = _loop0_188_rule(p)) // lambda_param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_188_var = _gather_188_rule(p)) // ','.lambda_param+ + (_gather_189_var = _gather_189_rule(p)) // ','.lambda_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21818,22 +21830,22 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_191_var; - asdl_seq * _loop0_193_var; + asdl_seq * _loop0_192_var; + asdl_seq * _loop0_194_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_192_var; + void *_tmp_193_var; Token * a; if ( - (_opt_var = _tmp_190_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] + (_opt_var = _tmp_191_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] && - (_loop0_191_var = _loop0_191_rule(p)) // lambda_param_maybe_default* + (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_192_var = _tmp_192_rule(p)) // ',' | lambda_param_no_default + (_tmp_193_var = _tmp_193_rule(p)) // ',' | lambda_param_no_default && - (_loop0_193_var = _loop0_193_rule(p)) // lambda_param_maybe_default* + (_loop0_194_var = _loop0_194_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21858,10 +21870,10 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_194_var; + asdl_seq * _loop1_195_var; Token * a; if ( - (_loop1_194_var = _loop1_194_rule(p)) // lambda_param_maybe_default+ + (_loop1_195_var = _loop1_195_rule(p)) // lambda_param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21932,13 +21944,13 @@ invalid_lambda_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_195_var; + asdl_seq * _loop1_196_var; if ( - (_loop1_195_var = _loop1_195_rule(p)) // lambda_param_with_default+ + (_loop1_196_var = _loop1_196_rule(p)) // lambda_param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_lambda_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_195_var; + _res = _loop1_196_var; goto done; } p->mark = _mark; @@ -21974,11 +21986,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_196_var; + void *_tmp_197_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_196_var = _tmp_196_rule(p)) // ':' | ',' (':' | '**') + (_tmp_197_var = _tmp_197_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -22031,20 +22043,20 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_198_var; - void *_tmp_197_var; - void *_tmp_199_var; + asdl_seq * _loop0_199_var; + void *_tmp_198_var; + void *_tmp_200_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_197_var = _tmp_197_rule(p)) // lambda_param_no_default | ',' + (_tmp_198_var = _tmp_198_rule(p)) // lambda_param_no_default | ',' && - (_loop0_198_var = _loop0_198_rule(p)) // lambda_param_maybe_default* + (_loop0_199_var = _loop0_199_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_199_var = _tmp_199_rule(p)) // lambda_param_no_default | ',' + (_tmp_200_var = _tmp_200_rule(p)) // lambda_param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); @@ -22162,7 +22174,7 @@ invalid_lambda_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_200_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_201_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')")); @@ -22268,7 +22280,7 @@ invalid_with_item_rule(Parser *p) && (a = expression_rule(p)) // expression && - _PyPegen_lookahead(1, _tmp_201_rule, p) + _PyPegen_lookahead(1, _tmp_202_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' | ')' | ':')")); @@ -22441,14 +22453,14 @@ invalid_import_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); - asdl_seq * _gather_202_var; + asdl_seq * _gather_203_var; Token * _keyword; Token * a; expr_ty dotted_name_var; if ( (a = _PyPegen_expect_token(p, 607)) // token='import' && - (_gather_202_var = _gather_202_rule(p)) // ','.dotted_name+ + (_gather_203_var = _gather_203_rule(p)) // ','.dotted_name+ && (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && @@ -22544,7 +22556,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_204_var; + asdl_seq * _gather_205_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22554,7 +22566,7 @@ invalid_with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_204_var = _gather_204_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_205_var = _gather_205_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22578,7 +22590,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_206_var; + asdl_seq * _gather_207_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -22594,7 +22606,7 @@ invalid_with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_206_var = _gather_206_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_207_var = _gather_207_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22643,7 +22655,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_208_var; + asdl_seq * _gather_209_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22654,7 +22666,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (a = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_208_var = _gather_208_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_209_var = _gather_209_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22682,7 +22694,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_210_var; + asdl_seq * _gather_211_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -22699,7 +22711,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_210_var = _gather_210_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_211_var = _gather_211_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22796,7 +22808,7 @@ invalid_try_stmt_rule(Parser *p) && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_212_rule, p) + _PyPegen_lookahead(0, _tmp_213_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -22821,8 +22833,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_213_var; - asdl_seq * _loop1_214_var; + asdl_seq * _loop0_214_var; + asdl_seq * _loop1_215_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22833,9 +22845,9 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_213_var = _loop0_213_rule(p)) // block* + (_loop0_214_var = _loop0_214_rule(p)) // block* && - (_loop1_214_var = _loop1_214_rule(p)) // except_block+ + (_loop1_215_var = _loop1_215_rule(p)) // except_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && @@ -22843,7 +22855,7 @@ invalid_try_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_215_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22870,8 +22882,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_216_var; - asdl_seq * _loop1_217_var; + asdl_seq * _loop0_217_var; + asdl_seq * _loop1_218_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22880,13 +22892,13 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_216_var = _loop0_216_rule(p)) // block* + (_loop0_217_var = _loop0_217_rule(p)) // block* && - (_loop1_217_var = _loop1_217_rule(p)) // except_star_block+ + (_loop1_218_var = _loop1_218_rule(p)) // except_star_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && - (_opt_var = _tmp_218_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_219_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22953,7 +22965,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var_1 = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22991,7 +23003,7 @@ invalid_except_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var_1 = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23043,14 +23055,14 @@ invalid_except_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_221_var; + void *_tmp_222_var; Token * a; if ( (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_221_var = _tmp_221_rule(p)) // NEWLINE | ':' + (_tmp_222_var = _tmp_222_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -23155,7 +23167,7 @@ invalid_except_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_222_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23249,7 +23261,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23613,7 +23625,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_224_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_225_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -24101,7 +24113,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_225_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_2 = _tmp_226_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24160,7 +24172,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_226_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24195,7 +24207,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_228_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24245,11 +24257,11 @@ invalid_double_starred_kvpairs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_228_var; + asdl_seq * _gather_229_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_228_var = _gather_228_rule(p)) // ','.double_starred_kvpair+ + (_gather_229_var = _gather_229_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24257,7 +24269,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_228_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_229_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -24310,7 +24322,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_230_rule, p) + _PyPegen_lookahead(1, _tmp_231_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24420,7 +24432,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_231_rule, p) + _PyPegen_lookahead(1, _tmp_232_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24636,7 +24648,7 @@ invalid_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - _PyPegen_lookahead(0, _tmp_232_rule, p) + _PyPegen_lookahead(0, _tmp_233_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)")); @@ -24659,13 +24671,13 @@ invalid_replacement_field_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); Token * _literal; - void *_tmp_233_var; + void *_tmp_234_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_233_var = _tmp_233_rule(p)) // yield_expr | star_expressions + (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions && - _PyPegen_lookahead(0, _tmp_234_rule, p) + _PyPegen_lookahead(0, _tmp_235_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); @@ -24689,15 +24701,15 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); Token * _literal; Token * _literal_1; - void *_tmp_235_var; + void *_tmp_236_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_235_var = _tmp_235_rule(p)) // yield_expr | star_expressions + (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_236_rule, p) + _PyPegen_lookahead(0, _tmp_237_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); @@ -24722,12 +24734,12 @@ invalid_replacement_field_rule(Parser *p) Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_237_var; + void *_tmp_238_var; void *invalid_conversion_character_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_237_var = _tmp_237_rule(p)) // yield_expr | star_expressions + (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && @@ -24735,7 +24747,7 @@ invalid_replacement_field_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_237_var, _opt_var, invalid_conversion_character_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_238_var, _opt_var, invalid_conversion_character_var); goto done; } p->mark = _mark; @@ -24753,17 +24765,17 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_238_var; + void *_tmp_239_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions + (_tmp_239_var = _tmp_239_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_239_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_240_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_240_rule, p) + _PyPegen_lookahead(0, _tmp_241_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); @@ -24787,24 +24799,24 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_243_var; + asdl_seq * _loop0_244_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_241_var; + void *_tmp_242_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_241_var = _tmp_241_rule(p)) // yield_expr | star_expressions + (_tmp_242_var = _tmp_242_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_242_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_243_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_243_var = _loop0_243_rule(p)) // fstring_format_spec* + (_loop0_244_var = _loop0_244_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24833,15 +24845,15 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_244_var; + void *_tmp_245_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_244_var = _tmp_244_rule(p)) // yield_expr | star_expressions + (_tmp_245_var = _tmp_245_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_245_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_246_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24888,7 +24900,7 @@ invalid_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_246_rule, p) + _PyPegen_lookahead(1, _tmp_247_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -25751,12 +25763,12 @@ _loop1_14_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_247_var; + void *_tmp_248_var; while ( - (_tmp_247_var = _tmp_247_rule(p)) // star_targets '=' + (_tmp_248_var = _tmp_248_rule(p)) // star_targets '=' ) { - _res = _tmp_247_var; + _res = _tmp_248_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26320,12 +26332,12 @@ _loop0_24_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_248_var; + void *_tmp_249_var; while ( - (_tmp_248_var = _tmp_248_rule(p)) // '.' | '...' + (_tmp_249_var = _tmp_249_rule(p)) // '.' | '...' ) { - _res = _tmp_248_var; + _res = _tmp_249_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26387,12 +26399,12 @@ _loop1_25_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_249_var; + void *_tmp_250_var; while ( - (_tmp_249_var = _tmp_249_rule(p)) // '.' | '...' + (_tmp_250_var = _tmp_250_rule(p)) // '.' | '...' ) { - _res = _tmp_249_var; + _res = _tmp_250_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26785,12 +26797,12 @@ _loop1_32_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_250_var; + void *_tmp_251_var; while ( - (_tmp_250_var = _tmp_250_rule(p)) // '@' named_expression NEWLINE + (_tmp_251_var = _tmp_251_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_250_var; + _res = _tmp_251_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29915,12 +29927,12 @@ _loop1_82_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_251_var; + void *_tmp_252_var; while ( - (_tmp_251_var = _tmp_251_rule(p)) // ',' expression + (_tmp_252_var = _tmp_252_rule(p)) // ',' expression ) { - _res = _tmp_251_var; + _res = _tmp_252_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29987,12 +29999,12 @@ _loop1_83_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_252_var; + void *_tmp_253_var; while ( - (_tmp_252_var = _tmp_252_rule(p)) // ',' star_expression + (_tmp_253_var = _tmp_253_rule(p)) // ',' star_expression ) { - _res = _tmp_252_var; + _res = _tmp_253_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30176,12 +30188,12 @@ _loop1_86_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_253_var; + void *_tmp_254_var; while ( - (_tmp_253_var = _tmp_253_rule(p)) // 'or' conjunction + (_tmp_254_var = _tmp_254_rule(p)) // 'or' conjunction ) { - _res = _tmp_253_var; + _res = _tmp_254_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30248,12 +30260,12 @@ _loop1_87_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_254_var; + void *_tmp_255_var; while ( - (_tmp_254_var = _tmp_254_rule(p)) // 'and' inversion + (_tmp_255_var = _tmp_255_rule(p)) // 'and' inversion ) { - _res = _tmp_254_var; + _res = _tmp_255_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30440,7 +30452,7 @@ _loop0_91_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_255_rule(p)) // slice | starred_expression + (elem = _tmp_256_rule(p)) // slice | starred_expression ) { _res = elem; @@ -30505,7 +30517,7 @@ _gather_90_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_255_rule(p)) // slice | starred_expression + (elem = _tmp_256_rule(p)) // slice | starred_expression && (seq = _loop0_91_rule(p)) // _loop0_91 ) @@ -32104,12 +32116,12 @@ _loop1_115_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_256_var; + void *_tmp_257_var; while ( - (_tmp_256_var = _tmp_256_rule(p)) // fstring | string + (_tmp_257_var = _tmp_257_rule(p)) // fstring | string ) { - _res = _tmp_256_var; + _res = _tmp_257_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32414,12 +32426,12 @@ _loop0_120_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_257_var; + void *_tmp_258_var; while ( - (_tmp_257_var = _tmp_257_rule(p)) // 'if' disjunction + (_tmp_258_var = _tmp_258_rule(p)) // 'if' disjunction ) { - _res = _tmp_257_var; + _res = _tmp_258_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32481,12 +32493,12 @@ _loop0_121_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_258_var; + void *_tmp_259_var; while ( - (_tmp_258_var = _tmp_258_rule(p)) // 'if' disjunction + (_tmp_259_var = _tmp_259_rule(p)) // 'if' disjunction ) { - _res = _tmp_258_var; + _res = _tmp_259_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32612,7 +32624,7 @@ _loop0_124_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_259_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -32678,7 +32690,7 @@ _gather_123_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_259_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && (seq = _loop0_124_rule(p)) // _loop0_124 ) @@ -33239,12 +33251,12 @@ _loop0_134_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_260_var; + void *_tmp_261_var; while ( - (_tmp_260_var = _tmp_260_rule(p)) // ',' star_target + (_tmp_261_var = _tmp_261_rule(p)) // ',' star_target ) { - _res = _tmp_260_var; + _res = _tmp_261_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33423,12 +33435,12 @@ _loop1_137_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_261_var; + void *_tmp_262_var; while ( - (_tmp_261_var = _tmp_261_rule(p)) // ',' star_target + (_tmp_262_var = _tmp_262_rule(p)) // ',' star_target ) { - _res = _tmp_261_var; + _res = _tmp_262_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34133,9 +34145,68 @@ _tmp_149_rule(Parser *p) return _res; } -// _tmp_150: args | expression for_if_clauses +// _tmp_150: +// | (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) +// | kwargs static void * _tmp_150_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + void *_tmp_263_var; + if ( + (_tmp_263_var = _tmp_263_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs + ) + { + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + _res = _tmp_263_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + } + { // kwargs + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwargs")); + asdl_seq* kwargs_var; + if ( + (kwargs_var = kwargs_rule(p)) // kwargs + ) + { + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwargs")); + _res = kwargs_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwargs")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_151: args | expression for_if_clauses +static void * +_tmp_151_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34151,18 +34222,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); expr_ty args_var; if ( (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); _res = args_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args")); } { // expression for_if_clauses @@ -34170,7 +34241,7 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); expr_ty expression_var; asdl_comprehension_seq* for_if_clauses_var; if ( @@ -34179,12 +34250,12 @@ _tmp_150_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses")); } _res = NULL; @@ -34193,9 +34264,9 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: args ',' +// _tmp_152: args ',' static void * -_tmp_151_rule(Parser *p) +_tmp_152_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34211,7 +34282,7 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); Token * _literal; expr_ty args_var; if ( @@ -34220,12 +34291,12 @@ _tmp_151_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); _res = _PyPegen_dummy_name(p, args_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ','")); } _res = NULL; @@ -34234,9 +34305,9 @@ _tmp_151_rule(Parser *p) return _res; } -// _tmp_152: ',' | ')' +// _tmp_153: ',' | ')' static void * -_tmp_152_rule(Parser *p) +_tmp_153_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34252,18 +34323,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -34271,18 +34342,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } _res = NULL; @@ -34291,9 +34362,9 @@ _tmp_152_rule(Parser *p) return _res; } -// _tmp_153: 'True' | 'False' | 'None' +// _tmp_154: 'True' | 'False' | 'None' static void * -_tmp_153_rule(Parser *p) +_tmp_154_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34309,18 +34380,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'False' @@ -34328,18 +34399,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } { // 'None' @@ -34347,18 +34418,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } _res = NULL; @@ -34367,9 +34438,9 @@ _tmp_153_rule(Parser *p) return _res; } -// _tmp_154: NAME '=' +// _tmp_155: NAME '=' static void * -_tmp_154_rule(Parser *p) +_tmp_155_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34385,7 +34456,7 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); Token * _literal; expr_ty name_var; if ( @@ -34394,12 +34465,12 @@ _tmp_154_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); _res = _PyPegen_dummy_name(p, name_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME '='")); } _res = NULL; @@ -34408,9 +34479,9 @@ _tmp_154_rule(Parser *p) return _res; } -// _tmp_155: NAME STRING | SOFT_KEYWORD +// _tmp_156: NAME STRING | SOFT_KEYWORD static void * -_tmp_155_rule(Parser *p) +_tmp_156_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34426,7 +34497,7 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); expr_ty name_var; expr_ty string_var; if ( @@ -34435,12 +34506,12 @@ _tmp_155_rule(Parser *p) (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); _res = _PyPegen_dummy_name(p, name_var, string_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME STRING")); } { // SOFT_KEYWORD @@ -34448,18 +34519,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); expr_ty soft_keyword_var; if ( (soft_keyword_var = _PyPegen_soft_keyword_token(p)) // SOFT_KEYWORD ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); _res = soft_keyword_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "SOFT_KEYWORD")); } _res = NULL; @@ -34468,9 +34539,9 @@ _tmp_155_rule(Parser *p) return _res; } -// _tmp_156: 'else' | ':' +// _tmp_157: 'else' | ':' static void * -_tmp_156_rule(Parser *p) +_tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34486,18 +34557,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 645)) // token='else' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'else'")); } { // ':' @@ -34505,18 +34576,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -34525,9 +34596,9 @@ _tmp_156_rule(Parser *p) return _res; } -// _tmp_157: '=' | ':=' +// _tmp_158: '=' | ':=' static void * -_tmp_157_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34543,18 +34614,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34562,18 +34633,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34582,9 +34653,9 @@ _tmp_157_rule(Parser *p) return _res; } -// _tmp_158: list | tuple | genexp | 'True' | 'None' | 'False' +// _tmp_159: list | tuple | genexp | 'True' | 'None' | 'False' static void * -_tmp_158_rule(Parser *p) +_tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34600,18 +34671,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // tuple @@ -34619,18 +34690,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // genexp @@ -34638,18 +34709,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } { // 'True' @@ -34657,18 +34728,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'None' @@ -34676,18 +34747,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } { // 'False' @@ -34695,18 +34766,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } _res = NULL; @@ -34715,9 +34786,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _tmp_159: '=' | ':=' +// _tmp_160: '=' | ':=' static void * -_tmp_159_rule(Parser *p) +_tmp_160_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34733,18 +34804,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34752,18 +34823,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34772,9 +34843,9 @@ _tmp_159_rule(Parser *p) return _res; } -// _loop0_160: star_named_expressions +// _loop0_161: star_named_expressions static asdl_seq * -_loop0_160_rule(Parser *p) +_loop0_161_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34799,7 +34870,7 @@ _loop0_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_expr_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -34822,7 +34893,7 @@ _loop0_160_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34839,9 +34910,9 @@ _loop0_160_rule(Parser *p) return _seq; } -// _loop0_161: (star_targets '=') +// _loop0_162: (star_targets '=') static asdl_seq * -_loop0_161_rule(Parser *p) +_loop0_162_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34866,13 +34937,13 @@ _loop0_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_262_var; + D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_264_var; while ( - (_tmp_262_var = _tmp_262_rule(p)) // star_targets '=' + (_tmp_264_var = _tmp_264_rule(p)) // star_targets '=' ) { - _res = _tmp_262_var; + _res = _tmp_264_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34889,7 +34960,7 @@ _loop0_161_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34906,9 +34977,9 @@ _loop0_161_rule(Parser *p) return _seq; } -// _loop0_162: (star_targets '=') +// _loop0_163: (star_targets '=') static asdl_seq * -_loop0_162_rule(Parser *p) +_loop0_163_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34933,13 +35004,13 @@ _loop0_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_263_var; + D(fprintf(stderr, "%*c> _loop0_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_265_var; while ( - (_tmp_263_var = _tmp_263_rule(p)) // star_targets '=' + (_tmp_265_var = _tmp_265_rule(p)) // star_targets '=' ) { - _res = _tmp_263_var; + _res = _tmp_265_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34956,7 +35027,7 @@ _loop0_162_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34973,9 +35044,9 @@ _loop0_162_rule(Parser *p) return _seq; } -// _tmp_163: yield_expr | star_expressions +// _tmp_164: yield_expr | star_expressions static void * -_tmp_163_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -34991,18 +35062,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -35010,18 +35081,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -35030,9 +35101,9 @@ _tmp_163_rule(Parser *p) return _res; } -// _tmp_164: '[' | '(' | '{' +// _tmp_165: '[' | '(' | '{' static void * -_tmp_164_rule(Parser *p) +_tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35048,18 +35119,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '(' @@ -35067,18 +35138,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '{' @@ -35086,18 +35157,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35106,9 +35177,9 @@ _tmp_164_rule(Parser *p) return _res; } -// _tmp_165: '[' | '{' +// _tmp_166: '[' | '{' static void * -_tmp_165_rule(Parser *p) +_tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35124,18 +35195,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -35143,18 +35214,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35163,9 +35234,9 @@ _tmp_165_rule(Parser *p) return _res; } -// _tmp_166: '[' | '{' +// _tmp_167: '[' | '{' static void * -_tmp_166_rule(Parser *p) +_tmp_167_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35181,18 +35252,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -35200,18 +35271,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35220,9 +35291,9 @@ _tmp_166_rule(Parser *p) return _res; } -// _tmp_167: slash_no_default | slash_with_default +// _tmp_168: slash_no_default | slash_with_default static void * -_tmp_167_rule(Parser *p) +_tmp_168_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35238,18 +35309,18 @@ _tmp_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35257,18 +35328,18 @@ _tmp_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35277,9 +35348,9 @@ _tmp_167_rule(Parser *p) return _res; } -// _loop0_168: param_maybe_default +// _loop0_169: param_maybe_default static asdl_seq * -_loop0_168_rule(Parser *p) +_loop0_169_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35304,7 +35375,7 @@ _loop0_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35327,7 +35398,7 @@ _loop0_168_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35344,9 +35415,9 @@ _loop0_168_rule(Parser *p) return _seq; } -// _loop0_169: param_no_default +// _loop0_170: param_no_default static asdl_seq * -_loop0_169_rule(Parser *p) +_loop0_170_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35371,7 +35442,7 @@ _loop0_169_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35394,7 +35465,7 @@ _loop0_169_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_170[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35411,9 +35482,9 @@ _loop0_169_rule(Parser *p) return _seq; } -// _loop0_170: param_no_default +// _loop0_171: param_no_default static asdl_seq * -_loop0_170_rule(Parser *p) +_loop0_171_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35438,7 +35509,7 @@ _loop0_170_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35461,7 +35532,7 @@ _loop0_170_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_170[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_171[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35478,9 +35549,9 @@ _loop0_170_rule(Parser *p) return _seq; } -// _loop1_171: param_no_default +// _loop1_172: param_no_default static asdl_seq * -_loop1_171_rule(Parser *p) +_loop1_172_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35505,7 +35576,7 @@ _loop1_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -35528,7 +35599,7 @@ _loop1_171_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -35550,9 +35621,9 @@ _loop1_171_rule(Parser *p) return _seq; } -// _tmp_172: slash_no_default | slash_with_default +// _tmp_173: slash_no_default | slash_with_default static void * -_tmp_172_rule(Parser *p) +_tmp_173_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35568,18 +35639,18 @@ _tmp_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35587,18 +35658,18 @@ _tmp_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35607,9 +35678,9 @@ _tmp_172_rule(Parser *p) return _res; } -// _loop0_173: param_maybe_default +// _loop0_174: param_maybe_default static asdl_seq * -_loop0_173_rule(Parser *p) +_loop0_174_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35634,7 +35705,7 @@ _loop0_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35657,7 +35728,7 @@ _loop0_173_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35674,9 +35745,9 @@ _loop0_173_rule(Parser *p) return _seq; } -// _tmp_174: ',' | param_no_default +// _tmp_175: ',' | param_no_default static void * -_tmp_174_rule(Parser *p) +_tmp_175_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35692,18 +35763,18 @@ _tmp_174_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // param_no_default @@ -35711,18 +35782,18 @@ _tmp_174_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } _res = NULL; @@ -35731,9 +35802,9 @@ _tmp_174_rule(Parser *p) return _res; } -// _loop0_175: param_maybe_default +// _loop0_176: param_maybe_default static asdl_seq * -_loop0_175_rule(Parser *p) +_loop0_176_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35758,7 +35829,7 @@ _loop0_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35781,7 +35852,7 @@ _loop0_175_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_176[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35798,9 +35869,9 @@ _loop0_175_rule(Parser *p) return _seq; } -// _loop1_176: param_maybe_default +// _loop1_177: param_maybe_default static asdl_seq * -_loop1_176_rule(Parser *p) +_loop1_177_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35825,7 +35896,7 @@ _loop1_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -35848,7 +35919,7 @@ _loop1_176_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -35870,9 +35941,9 @@ _loop1_176_rule(Parser *p) return _seq; } -// _tmp_177: ')' | ',' +// _tmp_178: ')' | ',' static void * -_tmp_177_rule(Parser *p) +_tmp_178_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35888,18 +35959,18 @@ _tmp_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' @@ -35907,18 +35978,18 @@ _tmp_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -35927,9 +35998,9 @@ _tmp_177_rule(Parser *p) return _res; } -// _tmp_178: ')' | ',' (')' | '**') +// _tmp_179: ')' | ',' (')' | '**') static void * -_tmp_178_rule(Parser *p) +_tmp_179_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -35945,18 +36016,18 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -35964,21 +36035,21 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_264_var; + void *_tmp_266_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_264_var = _tmp_264_rule(p)) // ')' | '**' + (_tmp_266_var = _tmp_266_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_264_var); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_266_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -35987,9 +36058,9 @@ _tmp_178_rule(Parser *p) return _res; } -// _tmp_179: param_no_default | ',' +// _tmp_180: param_no_default | ',' static void * -_tmp_179_rule(Parser *p) +_tmp_180_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36005,18 +36076,18 @@ _tmp_179_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -36024,18 +36095,18 @@ _tmp_179_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -36044,9 +36115,9 @@ _tmp_179_rule(Parser *p) return _res; } -// _loop0_180: param_maybe_default +// _loop0_181: param_maybe_default static asdl_seq * -_loop0_180_rule(Parser *p) +_loop0_181_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36071,7 +36142,7 @@ _loop0_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -36094,7 +36165,7 @@ _loop0_180_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36111,9 +36182,9 @@ _loop0_180_rule(Parser *p) return _seq; } -// _tmp_181: param_no_default | ',' +// _tmp_182: param_no_default | ',' static void * -_tmp_181_rule(Parser *p) +_tmp_182_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36129,18 +36200,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -36148,18 +36219,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -36168,9 +36239,9 @@ _tmp_181_rule(Parser *p) return _res; } -// _tmp_182: '*' | '**' | '/' +// _tmp_183: '*' | '**' | '/' static void * -_tmp_182_rule(Parser *p) +_tmp_183_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36186,18 +36257,18 @@ _tmp_182_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -36205,18 +36276,18 @@ _tmp_182_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -36224,18 +36295,18 @@ _tmp_182_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -36244,9 +36315,9 @@ _tmp_182_rule(Parser *p) return _res; } -// _loop1_183: param_with_default +// _loop1_184: param_with_default static asdl_seq * -_loop1_183_rule(Parser *p) +_loop1_184_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36271,7 +36342,7 @@ _loop1_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -36294,7 +36365,7 @@ _loop1_183_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_184[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -36316,9 +36387,9 @@ _loop1_183_rule(Parser *p) return _seq; } -// _tmp_184: lambda_slash_no_default | lambda_slash_with_default +// _tmp_185: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_184_rule(Parser *p) +_tmp_185_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36334,18 +36405,18 @@ _tmp_184_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_185[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -36353,18 +36424,18 @@ _tmp_184_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_185[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -36373,9 +36444,9 @@ _tmp_184_rule(Parser *p) return _res; } -// _loop0_185: lambda_param_maybe_default +// _loop0_186: lambda_param_maybe_default static asdl_seq * -_loop0_185_rule(Parser *p) +_loop0_186_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36400,7 +36471,7 @@ _loop0_185_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36423,7 +36494,7 @@ _loop0_185_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_185[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36440,9 +36511,9 @@ _loop0_185_rule(Parser *p) return _seq; } -// _loop0_186: lambda_param_no_default +// _loop0_187: lambda_param_no_default static asdl_seq * -_loop0_186_rule(Parser *p) +_loop0_187_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36467,7 +36538,7 @@ _loop0_186_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -36490,7 +36561,7 @@ _loop0_186_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36507,9 +36578,9 @@ _loop0_186_rule(Parser *p) return _seq; } -// _loop0_187: lambda_param_no_default +// _loop0_188: lambda_param_no_default static asdl_seq * -_loop0_187_rule(Parser *p) +_loop0_188_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36534,7 +36605,7 @@ _loop0_187_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -36557,7 +36628,7 @@ _loop0_187_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_188[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36574,9 +36645,9 @@ _loop0_187_rule(Parser *p) return _seq; } -// _loop0_189: ',' lambda_param +// _loop0_190: ',' lambda_param static asdl_seq * -_loop0_189_rule(Parser *p) +_loop0_190_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36601,7 +36672,7 @@ _loop0_189_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); + D(fprintf(stderr, "%*c> _loop0_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); Token * _literal; arg_ty elem; while ( @@ -36633,7 +36704,7 @@ _loop0_189_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_189[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_190[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' lambda_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36650,9 +36721,9 @@ _loop0_189_rule(Parser *p) return _seq; } -// _gather_188: lambda_param _loop0_189 +// _gather_189: lambda_param _loop0_190 static asdl_seq * -_gather_188_rule(Parser *p) +_gather_189_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36663,27 +36734,27 @@ _gather_188_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // lambda_param _loop0_189 + { // lambda_param _loop0_190 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_189")); + D(fprintf(stderr, "%*c> _gather_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190")); arg_ty elem; asdl_seq * seq; if ( (elem = lambda_param_rule(p)) // lambda_param && - (seq = _loop0_189_rule(p)) // _loop0_189 + (seq = _loop0_190_rule(p)) // _loop0_190 ) { - D(fprintf(stderr, "%*c+ _gather_188[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_189")); + D(fprintf(stderr, "%*c+ _gather_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_188[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_189")); + D(fprintf(stderr, "%*c%s _gather_189[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_190")); } _res = NULL; done: @@ -36691,9 +36762,9 @@ _gather_188_rule(Parser *p) return _res; } -// _tmp_190: lambda_slash_no_default | lambda_slash_with_default +// _tmp_191: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_190_rule(Parser *p) +_tmp_191_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36709,18 +36780,18 @@ _tmp_190_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -36728,18 +36799,18 @@ _tmp_190_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -36748,9 +36819,9 @@ _tmp_190_rule(Parser *p) return _res; } -// _loop0_191: lambda_param_maybe_default +// _loop0_192: lambda_param_maybe_default static asdl_seq * -_loop0_191_rule(Parser *p) +_loop0_192_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36775,7 +36846,7 @@ _loop0_191_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36798,7 +36869,7 @@ _loop0_191_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_191[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_192[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36815,9 +36886,9 @@ _loop0_191_rule(Parser *p) return _seq; } -// _tmp_192: ',' | lambda_param_no_default +// _tmp_193: ',' | lambda_param_no_default static void * -_tmp_192_rule(Parser *p) +_tmp_193_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36833,18 +36904,18 @@ _tmp_192_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // lambda_param_no_default @@ -36852,18 +36923,18 @@ _tmp_192_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } _res = NULL; @@ -36872,9 +36943,9 @@ _tmp_192_rule(Parser *p) return _res; } -// _loop0_193: lambda_param_maybe_default +// _loop0_194: lambda_param_maybe_default static asdl_seq * -_loop0_193_rule(Parser *p) +_loop0_194_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36899,7 +36970,7 @@ _loop0_193_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36922,7 +36993,7 @@ _loop0_193_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_193[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_194[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36939,9 +37010,9 @@ _loop0_193_rule(Parser *p) return _seq; } -// _loop1_194: lambda_param_maybe_default +// _loop1_195: lambda_param_maybe_default static asdl_seq * -_loop1_194_rule(Parser *p) +_loop1_195_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -36966,7 +37037,7 @@ _loop1_194_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -36989,7 +37060,7 @@ _loop1_194_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_194[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_195[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -37011,9 +37082,9 @@ _loop1_194_rule(Parser *p) return _seq; } -// _loop1_195: lambda_param_with_default +// _loop1_196: lambda_param_with_default static asdl_seq * -_loop1_195_rule(Parser *p) +_loop1_196_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37038,7 +37109,7 @@ _loop1_195_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -37061,7 +37132,7 @@ _loop1_195_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_195[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -37083,9 +37154,9 @@ _loop1_195_rule(Parser *p) return _seq; } -// _tmp_196: ':' | ',' (':' | '**') +// _tmp_197: ':' | ',' (':' | '**') static void * -_tmp_196_rule(Parser *p) +_tmp_197_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37101,18 +37172,18 @@ _tmp_196_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -37120,21 +37191,21 @@ _tmp_196_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_265_var; + void *_tmp_267_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_265_var = _tmp_265_rule(p)) // ':' | '**' + (_tmp_267_var = _tmp_267_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_265_var); + D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_267_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -37143,9 +37214,9 @@ _tmp_196_rule(Parser *p) return _res; } -// _tmp_197: lambda_param_no_default | ',' +// _tmp_198: lambda_param_no_default | ',' static void * -_tmp_197_rule(Parser *p) +_tmp_198_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37161,18 +37232,18 @@ _tmp_197_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -37180,18 +37251,18 @@ _tmp_197_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37200,9 +37271,9 @@ _tmp_197_rule(Parser *p) return _res; } -// _loop0_198: lambda_param_maybe_default +// _loop0_199: lambda_param_maybe_default static asdl_seq * -_loop0_198_rule(Parser *p) +_loop0_199_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37227,7 +37298,7 @@ _loop0_198_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -37250,7 +37321,7 @@ _loop0_198_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_198[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37267,9 +37338,9 @@ _loop0_198_rule(Parser *p) return _seq; } -// _tmp_199: lambda_param_no_default | ',' +// _tmp_200: lambda_param_no_default | ',' static void * -_tmp_199_rule(Parser *p) +_tmp_200_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37285,18 +37356,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -37304,18 +37375,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37324,9 +37395,9 @@ _tmp_199_rule(Parser *p) return _res; } -// _tmp_200: '*' | '**' | '/' +// _tmp_201: '*' | '**' | '/' static void * -_tmp_200_rule(Parser *p) +_tmp_201_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37342,18 +37413,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -37361,18 +37432,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -37380,18 +37451,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -37400,9 +37471,9 @@ _tmp_200_rule(Parser *p) return _res; } -// _tmp_201: ',' | ')' | ':' +// _tmp_202: ',' | ')' | ':' static void * -_tmp_201_rule(Parser *p) +_tmp_202_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37418,18 +37489,18 @@ _tmp_201_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -37437,18 +37508,18 @@ _tmp_201_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -37456,18 +37527,18 @@ _tmp_201_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -37476,9 +37547,9 @@ _tmp_201_rule(Parser *p) return _res; } -// _loop0_203: ',' dotted_name +// _loop0_204: ',' dotted_name static asdl_seq * -_loop0_203_rule(Parser *p) +_loop0_204_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37503,7 +37574,7 @@ _loop0_203_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); + D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); Token * _literal; expr_ty elem; while ( @@ -37535,7 +37606,7 @@ _loop0_203_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_203[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_204[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37552,9 +37623,9 @@ _loop0_203_rule(Parser *p) return _seq; } -// _gather_202: dotted_name _loop0_203 +// _gather_203: dotted_name _loop0_204 static asdl_seq * -_gather_202_rule(Parser *p) +_gather_203_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37565,27 +37636,27 @@ _gather_202_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // dotted_name _loop0_203 + { // dotted_name _loop0_204 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_203")); + D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); expr_ty elem; asdl_seq * seq; if ( (elem = dotted_name_rule(p)) // dotted_name && - (seq = _loop0_203_rule(p)) // _loop0_203 + (seq = _loop0_204_rule(p)) // _loop0_204 ) { - D(fprintf(stderr, "%*c+ _gather_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_203")); + D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_202[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_203")); + D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_204")); } _res = NULL; done: @@ -37593,9 +37664,9 @@ _gather_202_rule(Parser *p) return _res; } -// _loop0_205: ',' (expression ['as' star_target]) +// _loop0_206: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_205_rule(Parser *p) +_loop0_206_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37620,13 +37691,13 @@ _loop0_205_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_266_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37652,7 +37723,7 @@ _loop0_205_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_205[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_206[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37669,9 +37740,9 @@ _loop0_205_rule(Parser *p) return _seq; } -// _gather_204: (expression ['as' star_target]) _loop0_205 +// _gather_205: (expression ['as' star_target]) _loop0_206 static asdl_seq * -_gather_204_rule(Parser *p) +_gather_205_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37682,27 +37753,27 @@ _gather_204_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_205 + { // (expression ['as' star_target]) _loop0_206 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_205")); + D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_266_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expression ['as' star_target] && - (seq = _loop0_205_rule(p)) // _loop0_205 + (seq = _loop0_206_rule(p)) // _loop0_206 ) { - D(fprintf(stderr, "%*c+ _gather_204[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_205")); + D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_204[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_205")); + D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); } _res = NULL; done: @@ -37710,9 +37781,9 @@ _gather_204_rule(Parser *p) return _res; } -// _loop0_207: ',' (expressions ['as' star_target]) +// _loop0_208: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_207_rule(Parser *p) +_loop0_208_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37737,13 +37808,13 @@ _loop0_207_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_267_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -37769,7 +37840,7 @@ _loop0_207_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_207[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37786,9 +37857,9 @@ _loop0_207_rule(Parser *p) return _seq; } -// _gather_206: (expressions ['as' star_target]) _loop0_207 +// _gather_207: (expressions ['as' star_target]) _loop0_208 static asdl_seq * -_gather_206_rule(Parser *p) +_gather_207_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37799,27 +37870,27 @@ _gather_206_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_207 + { // (expressions ['as' star_target]) _loop0_208 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_207")); + D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_267_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_207_rule(p)) // _loop0_207 + (seq = _loop0_208_rule(p)) // _loop0_208 ) { - D(fprintf(stderr, "%*c+ _gather_206[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_207")); + D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_206[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_207")); + D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); } _res = NULL; done: @@ -37827,9 +37898,9 @@ _gather_206_rule(Parser *p) return _res; } -// _loop0_209: ',' (expression ['as' star_target]) +// _loop0_210: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_209_rule(Parser *p) +_loop0_210_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37854,13 +37925,13 @@ _loop0_209_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_268_rule(p)) // expression ['as' star_target] + (elem = _tmp_270_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37886,7 +37957,7 @@ _loop0_209_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_209[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37903,9 +37974,9 @@ _loop0_209_rule(Parser *p) return _seq; } -// _gather_208: (expression ['as' star_target]) _loop0_209 +// _gather_209: (expression ['as' star_target]) _loop0_210 static asdl_seq * -_gather_208_rule(Parser *p) +_gather_209_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37916,27 +37987,27 @@ _gather_208_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_209 + { // (expression ['as' star_target]) _loop0_210 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_209")); + D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_268_rule(p)) // expression ['as' star_target] + (elem = _tmp_270_rule(p)) // expression ['as' star_target] && - (seq = _loop0_209_rule(p)) // _loop0_209 + (seq = _loop0_210_rule(p)) // _loop0_210 ) { - D(fprintf(stderr, "%*c+ _gather_208[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_209")); + D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_208[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_209")); + D(fprintf(stderr, "%*c%s _gather_209[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); } _res = NULL; done: @@ -37944,9 +38015,9 @@ _gather_208_rule(Parser *p) return _res; } -// _loop0_211: ',' (expressions ['as' star_target]) +// _loop0_212: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_211_rule(Parser *p) +_loop0_212_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -37971,13 +38042,13 @@ _loop0_211_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_269_rule(p)) // expressions ['as' star_target] + (elem = _tmp_271_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -38003,7 +38074,7 @@ _loop0_211_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_211[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_212[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38020,9 +38091,9 @@ _loop0_211_rule(Parser *p) return _seq; } -// _gather_210: (expressions ['as' star_target]) _loop0_211 +// _gather_211: (expressions ['as' star_target]) _loop0_212 static asdl_seq * -_gather_210_rule(Parser *p) +_gather_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38033,27 +38104,27 @@ _gather_210_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_211 + { // (expressions ['as' star_target]) _loop0_212 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_211")); + D(fprintf(stderr, "%*c> _gather_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_269_rule(p)) // expressions ['as' star_target] + (elem = _tmp_271_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_211_rule(p)) // _loop0_211 + (seq = _loop0_212_rule(p)) // _loop0_212 ) { - D(fprintf(stderr, "%*c+ _gather_210[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_211")); + D(fprintf(stderr, "%*c+ _gather_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_210[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_211")); + D(fprintf(stderr, "%*c%s _gather_211[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); } _res = NULL; done: @@ -38061,9 +38132,9 @@ _gather_210_rule(Parser *p) return _res; } -// _tmp_212: 'except' | 'finally' +// _tmp_213: 'except' | 'finally' static void * -_tmp_212_rule(Parser *p) +_tmp_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38079,18 +38150,18 @@ _tmp_212_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 637)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); } { // 'finally' @@ -38098,18 +38169,18 @@ _tmp_212_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' ) { - D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; @@ -38118,9 +38189,9 @@ _tmp_212_rule(Parser *p) return _res; } -// _loop0_213: block +// _loop0_214: block static asdl_seq * -_loop0_213_rule(Parser *p) +_loop0_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38145,7 +38216,7 @@ _loop0_213_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38168,7 +38239,7 @@ _loop0_213_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_213[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_214[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38185,9 +38256,9 @@ _loop0_213_rule(Parser *p) return _seq; } -// _loop1_214: except_block +// _loop1_215: except_block static asdl_seq * -_loop1_214_rule(Parser *p) +_loop1_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38212,7 +38283,7 @@ _loop1_214_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); excepthandler_ty except_block_var; while ( (except_block_var = except_block_rule(p)) // except_block @@ -38235,7 +38306,7 @@ _loop1_214_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_214[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_215[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -38257,9 +38328,9 @@ _loop1_214_rule(Parser *p) return _seq; } -// _tmp_215: 'as' NAME +// _tmp_216: 'as' NAME static void * -_tmp_215_rule(Parser *p) +_tmp_216_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38275,7 +38346,7 @@ _tmp_215_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38284,12 +38355,12 @@ _tmp_215_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_215[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38298,9 +38369,9 @@ _tmp_215_rule(Parser *p) return _res; } -// _loop0_216: block +// _loop0_217: block static asdl_seq * -_loop0_216_rule(Parser *p) +_loop0_217_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38325,7 +38396,7 @@ _loop0_216_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38348,7 +38419,7 @@ _loop0_216_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_216[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_217[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38365,9 +38436,9 @@ _loop0_216_rule(Parser *p) return _seq; } -// _loop1_217: except_star_block +// _loop1_218: except_star_block static asdl_seq * -_loop1_217_rule(Parser *p) +_loop1_218_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38392,7 +38463,7 @@ _loop1_217_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); excepthandler_ty except_star_block_var; while ( (except_star_block_var = except_star_block_rule(p)) // except_star_block @@ -38415,7 +38486,7 @@ _loop1_217_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_217[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_218[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -38437,9 +38508,9 @@ _loop1_217_rule(Parser *p) return _seq; } -// _tmp_218: expression ['as' NAME] +// _tmp_219: expression ['as' NAME] static void * -_tmp_218_rule(Parser *p) +_tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38455,22 +38526,22 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_270_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -38479,9 +38550,9 @@ _tmp_218_rule(Parser *p) return _res; } -// _tmp_219: 'as' NAME +// _tmp_220: 'as' NAME static void * -_tmp_219_rule(Parser *p) +_tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38497,7 +38568,7 @@ _tmp_219_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38506,12 +38577,12 @@ _tmp_219_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38520,9 +38591,9 @@ _tmp_219_rule(Parser *p) return _res; } -// _tmp_220: 'as' NAME +// _tmp_221: 'as' NAME static void * -_tmp_220_rule(Parser *p) +_tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38538,7 +38609,7 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38547,12 +38618,12 @@ _tmp_220_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38561,9 +38632,9 @@ _tmp_220_rule(Parser *p) return _res; } -// _tmp_221: NEWLINE | ':' +// _tmp_222: NEWLINE | ':' static void * -_tmp_221_rule(Parser *p) +_tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38579,18 +38650,18 @@ _tmp_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -38598,18 +38669,18 @@ _tmp_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -38618,9 +38689,9 @@ _tmp_221_rule(Parser *p) return _res; } -// _tmp_222: 'as' NAME +// _tmp_223: 'as' NAME static void * -_tmp_222_rule(Parser *p) +_tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38636,7 +38707,7 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38645,12 +38716,12 @@ _tmp_222_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38659,9 +38730,9 @@ _tmp_222_rule(Parser *p) return _res; } -// _tmp_223: 'as' NAME +// _tmp_224: 'as' NAME static void * -_tmp_223_rule(Parser *p) +_tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38677,7 +38748,7 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38686,12 +38757,12 @@ _tmp_223_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38700,9 +38771,9 @@ _tmp_223_rule(Parser *p) return _res; } -// _tmp_224: positional_patterns ',' +// _tmp_225: positional_patterns ',' static void * -_tmp_224_rule(Parser *p) +_tmp_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38718,7 +38789,7 @@ _tmp_224_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -38727,12 +38798,12 @@ _tmp_224_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -38741,9 +38812,9 @@ _tmp_224_rule(Parser *p) return _res; } -// _tmp_225: '->' expression +// _tmp_226: '->' expression static void * -_tmp_225_rule(Parser *p) +_tmp_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38759,7 +38830,7 @@ _tmp_225_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty expression_var; if ( @@ -38768,12 +38839,12 @@ _tmp_225_rule(Parser *p) (expression_var = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = _PyPegen_dummy_name(p, _literal, expression_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -38782,9 +38853,9 @@ _tmp_225_rule(Parser *p) return _res; } -// _tmp_226: '(' arguments? ')' +// _tmp_227: '(' arguments? ')' static void * -_tmp_226_rule(Parser *p) +_tmp_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38800,7 +38871,7 @@ _tmp_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38813,12 +38884,12 @@ _tmp_226_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38827,9 +38898,9 @@ _tmp_226_rule(Parser *p) return _res; } -// _tmp_227: '(' arguments? ')' +// _tmp_228: '(' arguments? ')' static void * -_tmp_227_rule(Parser *p) +_tmp_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38845,7 +38916,7 @@ _tmp_227_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38858,12 +38929,12 @@ _tmp_227_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38872,9 +38943,9 @@ _tmp_227_rule(Parser *p) return _res; } -// _loop0_229: ',' double_starred_kvpair +// _loop0_230: ',' double_starred_kvpair static asdl_seq * -_loop0_229_rule(Parser *p) +_loop0_230_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38899,7 +38970,7 @@ _loop0_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -38931,7 +39002,7 @@ _loop0_229_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38948,9 +39019,9 @@ _loop0_229_rule(Parser *p) return _seq; } -// _gather_228: double_starred_kvpair _loop0_229 +// _gather_229: double_starred_kvpair _loop0_230 static asdl_seq * -_gather_228_rule(Parser *p) +_gather_229_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -38961,84 +39032,27 @@ _gather_228_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_229 + { // double_starred_kvpair _loop0_230 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_229")); + D(fprintf(stderr, "%*c> _gather_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_229_rule(p)) // _loop0_229 + (seq = _loop0_230_rule(p)) // _loop0_230 ) { - D(fprintf(stderr, "%*c+ _gather_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_229")); + D(fprintf(stderr, "%*c+ _gather_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_228[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_229")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_230: '}' | ',' -static void * -_tmp_230_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '}' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 26)) // token='}' - ) - { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); - } - { // ',' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - ) - { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); + D(fprintf(stderr, "%*c%s _gather_229[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_230")); } _res = NULL; done: @@ -39103,7 +39117,7 @@ _tmp_231_rule(Parser *p) return _res; } -// _tmp_232: yield_expr | star_expressions +// _tmp_232: '}' | ',' static void * _tmp_232_rule(Parser *p) { @@ -39116,43 +39130,43 @@ _tmp_232_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // yield_expr + { // '}' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); - expr_ty yield_expr_var; + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; if ( - (yield_expr_var = yield_expr_rule(p)) // yield_expr + (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); - _res = yield_expr_var; + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } - { // star_expressions + { // ',' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); - expr_ty star_expressions_var; + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + Token * _literal; if ( - (star_expressions_var = star_expressions_rule(p)) // star_expressions + (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); - _res = star_expressions_var; + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; done: @@ -39217,9 +39231,66 @@ _tmp_233_rule(Parser *p) return _res; } -// _tmp_234: '=' | '!' | ':' | '}' +// _tmp_234: yield_expr | star_expressions static void * _tmp_234_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_235: '=' | '!' | ':' | '}' +static void * +_tmp_235_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39235,18 +39306,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // '!' @@ -39254,18 +39325,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39273,18 +39344,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39292,18 +39363,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39312,9 +39383,9 @@ _tmp_234_rule(Parser *p) return _res; } -// _tmp_235: yield_expr | star_expressions +// _tmp_236: yield_expr | star_expressions static void * -_tmp_235_rule(Parser *p) +_tmp_236_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39330,18 +39401,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39349,18 +39420,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39369,9 +39440,9 @@ _tmp_235_rule(Parser *p) return _res; } -// _tmp_236: '!' | ':' | '}' +// _tmp_237: '!' | ':' | '}' static void * -_tmp_236_rule(Parser *p) +_tmp_237_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39387,18 +39458,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39406,18 +39477,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39425,18 +39496,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39445,9 +39516,9 @@ _tmp_236_rule(Parser *p) return _res; } -// _tmp_237: yield_expr | star_expressions +// _tmp_238: yield_expr | star_expressions static void * -_tmp_237_rule(Parser *p) +_tmp_238_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39463,18 +39534,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39482,18 +39553,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39502,9 +39573,9 @@ _tmp_237_rule(Parser *p) return _res; } -// _tmp_238: yield_expr | star_expressions +// _tmp_239: yield_expr | star_expressions static void * -_tmp_238_rule(Parser *p) +_tmp_239_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39520,18 +39591,18 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39539,18 +39610,18 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39559,9 +39630,9 @@ _tmp_238_rule(Parser *p) return _res; } -// _tmp_239: '!' NAME +// _tmp_240: '!' NAME static void * -_tmp_239_rule(Parser *p) +_tmp_240_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39577,7 +39648,7 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39586,12 +39657,12 @@ _tmp_239_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39600,9 +39671,9 @@ _tmp_239_rule(Parser *p) return _res; } -// _tmp_240: ':' | '}' +// _tmp_241: ':' | '}' static void * -_tmp_240_rule(Parser *p) +_tmp_241_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39618,18 +39689,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39637,18 +39708,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39657,9 +39728,9 @@ _tmp_240_rule(Parser *p) return _res; } -// _tmp_241: yield_expr | star_expressions +// _tmp_242: yield_expr | star_expressions static void * -_tmp_241_rule(Parser *p) +_tmp_242_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39675,18 +39746,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39694,18 +39765,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39714,9 +39785,9 @@ _tmp_241_rule(Parser *p) return _res; } -// _tmp_242: '!' NAME +// _tmp_243: '!' NAME static void * -_tmp_242_rule(Parser *p) +_tmp_243_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39732,7 +39803,7 @@ _tmp_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39741,12 +39812,12 @@ _tmp_242_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39755,9 +39826,9 @@ _tmp_242_rule(Parser *p) return _res; } -// _loop0_243: fstring_format_spec +// _loop0_244: fstring_format_spec static asdl_seq * -_loop0_243_rule(Parser *p) +_loop0_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39782,7 +39853,7 @@ _loop0_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -39805,7 +39876,7 @@ _loop0_243_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -39822,9 +39893,9 @@ _loop0_243_rule(Parser *p) return _seq; } -// _tmp_244: yield_expr | star_expressions +// _tmp_245: yield_expr | star_expressions static void * -_tmp_244_rule(Parser *p) +_tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39840,18 +39911,18 @@ _tmp_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39859,18 +39930,18 @@ _tmp_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39879,9 +39950,9 @@ _tmp_244_rule(Parser *p) return _res; } -// _tmp_245: '!' NAME +// _tmp_246: '!' NAME static void * -_tmp_245_rule(Parser *p) +_tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39897,7 +39968,7 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39906,12 +39977,12 @@ _tmp_245_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39920,9 +39991,9 @@ _tmp_245_rule(Parser *p) return _res; } -// _tmp_246: ':' | '}' +// _tmp_247: ':' | '}' static void * -_tmp_246_rule(Parser *p) +_tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39938,18 +40009,18 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39957,18 +40028,18 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39977,9 +40048,9 @@ _tmp_246_rule(Parser *p) return _res; } -// _tmp_247: star_targets '=' +// _tmp_248: star_targets '=' static void * -_tmp_247_rule(Parser *p) +_tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -39995,7 +40066,7 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -40004,7 +40075,7 @@ _tmp_247_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40014,7 +40085,7 @@ _tmp_247_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40023,9 +40094,9 @@ _tmp_247_rule(Parser *p) return _res; } -// _tmp_248: '.' | '...' +// _tmp_249: '.' | '...' static void * -_tmp_248_rule(Parser *p) +_tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40041,18 +40112,18 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40060,18 +40131,18 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40080,9 +40151,9 @@ _tmp_248_rule(Parser *p) return _res; } -// _tmp_249: '.' | '...' +// _tmp_250: '.' | '...' static void * -_tmp_249_rule(Parser *p) +_tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40098,18 +40169,18 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40117,18 +40188,18 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40137,9 +40208,9 @@ _tmp_249_rule(Parser *p) return _res; } -// _tmp_250: '@' named_expression NEWLINE +// _tmp_251: '@' named_expression NEWLINE static void * -_tmp_250_rule(Parser *p) +_tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40155,7 +40226,7 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -40167,7 +40238,7 @@ _tmp_250_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40177,7 +40248,7 @@ _tmp_250_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -40186,9 +40257,9 @@ _tmp_250_rule(Parser *p) return _res; } -// _tmp_251: ',' expression +// _tmp_252: ',' expression static void * -_tmp_251_rule(Parser *p) +_tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40204,7 +40275,7 @@ _tmp_251_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -40213,7 +40284,7 @@ _tmp_251_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40223,7 +40294,7 @@ _tmp_251_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -40232,9 +40303,9 @@ _tmp_251_rule(Parser *p) return _res; } -// _tmp_252: ',' star_expression +// _tmp_253: ',' star_expression static void * -_tmp_252_rule(Parser *p) +_tmp_253_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40250,7 +40321,7 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -40259,7 +40330,7 @@ _tmp_252_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40269,7 +40340,7 @@ _tmp_252_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -40278,9 +40349,9 @@ _tmp_252_rule(Parser *p) return _res; } -// _tmp_253: 'or' conjunction +// _tmp_254: 'or' conjunction static void * -_tmp_253_rule(Parser *p) +_tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40296,7 +40367,7 @@ _tmp_253_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -40305,7 +40376,7 @@ _tmp_253_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40315,7 +40386,7 @@ _tmp_253_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -40324,9 +40395,9 @@ _tmp_253_rule(Parser *p) return _res; } -// _tmp_254: 'and' inversion +// _tmp_255: 'and' inversion static void * -_tmp_254_rule(Parser *p) +_tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40342,7 +40413,7 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -40351,7 +40422,7 @@ _tmp_254_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40361,7 +40432,7 @@ _tmp_254_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -40370,9 +40441,9 @@ _tmp_254_rule(Parser *p) return _res; } -// _tmp_255: slice | starred_expression +// _tmp_256: slice | starred_expression static void * -_tmp_255_rule(Parser *p) +_tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40388,18 +40459,18 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -40407,18 +40478,18 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -40427,9 +40498,9 @@ _tmp_255_rule(Parser *p) return _res; } -// _tmp_256: fstring | string +// _tmp_257: fstring | string static void * -_tmp_256_rule(Parser *p) +_tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40445,18 +40516,18 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -40464,18 +40535,18 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -40484,9 +40555,9 @@ _tmp_256_rule(Parser *p) return _res; } -// _tmp_257: 'if' disjunction +// _tmp_258: 'if' disjunction static void * -_tmp_257_rule(Parser *p) +_tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40502,7 +40573,7 @@ _tmp_257_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40511,7 +40582,7 @@ _tmp_257_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40521,7 +40592,7 @@ _tmp_257_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40530,9 +40601,9 @@ _tmp_257_rule(Parser *p) return _res; } -// _tmp_258: 'if' disjunction +// _tmp_259: 'if' disjunction static void * -_tmp_258_rule(Parser *p) +_tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40548,7 +40619,7 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40557,7 +40628,7 @@ _tmp_258_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40567,7 +40638,7 @@ _tmp_258_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40576,9 +40647,9 @@ _tmp_258_rule(Parser *p) return _res; } -// _tmp_259: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_260: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_259_rule(Parser *p) +_tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40594,18 +40665,18 @@ _tmp_259_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -40613,20 +40684,20 @@ _tmp_259_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_271_var; + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_273_var; if ( - (_tmp_271_var = _tmp_271_rule(p)) // assignment_expression | expression !':=' + (_tmp_273_var = _tmp_273_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_271_var; + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_273_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -40635,9 +40706,9 @@ _tmp_259_rule(Parser *p) return _res; } -// _tmp_260: ',' star_target +// _tmp_261: ',' star_target static void * -_tmp_260_rule(Parser *p) +_tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40653,7 +40724,7 @@ _tmp_260_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40662,7 +40733,7 @@ _tmp_260_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40672,7 +40743,7 @@ _tmp_260_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -40681,9 +40752,9 @@ _tmp_260_rule(Parser *p) return _res; } -// _tmp_261: ',' star_target +// _tmp_262: ',' star_target static void * -_tmp_261_rule(Parser *p) +_tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40699,7 +40770,7 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40708,7 +40779,7 @@ _tmp_261_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40718,7 +40789,7 @@ _tmp_261_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -40727,9 +40798,54 @@ _tmp_261_rule(Parser *p) return _res; } -// _tmp_262: star_targets '=' +// _tmp_263: +// | ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs static void * -_tmp_262_rule(Parser *p) +_tmp_263_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + asdl_seq * _gather_274_var; + Token * _literal; + asdl_seq* kwargs_var; + if ( + (_gather_274_var = _gather_274_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + && + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (kwargs_var = kwargs_rule(p)) // kwargs + ) + { + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + _res = _PyPegen_dummy_name(p, _gather_274_var, _literal, kwargs_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_264: star_targets '=' +static void * +_tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40745,7 +40861,7 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40754,12 +40870,12 @@ _tmp_262_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40768,9 +40884,9 @@ _tmp_262_rule(Parser *p) return _res; } -// _tmp_263: star_targets '=' +// _tmp_265: star_targets '=' static void * -_tmp_263_rule(Parser *p) +_tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40786,7 +40902,7 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40795,12 +40911,12 @@ _tmp_263_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40809,9 +40925,9 @@ _tmp_263_rule(Parser *p) return _res; } -// _tmp_264: ')' | '**' +// _tmp_266: ')' | '**' static void * -_tmp_264_rule(Parser *p) +_tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40827,18 +40943,18 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -40846,18 +40962,18 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -40866,9 +40982,9 @@ _tmp_264_rule(Parser *p) return _res; } -// _tmp_265: ':' | '**' +// _tmp_267: ':' | '**' static void * -_tmp_265_rule(Parser *p) +_tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40884,18 +41000,18 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -40903,18 +41019,18 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -40923,9 +41039,9 @@ _tmp_265_rule(Parser *p) return _res; } -// _tmp_266: expression ['as' star_target] +// _tmp_268: expression ['as' star_target] static void * -_tmp_266_rule(Parser *p) +_tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40941,22 +41057,22 @@ _tmp_266_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_276_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -40965,9 +41081,9 @@ _tmp_266_rule(Parser *p) return _res; } -// _tmp_267: expressions ['as' star_target] +// _tmp_269: expressions ['as' star_target] static void * -_tmp_267_rule(Parser *p) +_tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -40983,22 +41099,22 @@ _tmp_267_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_277_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41007,9 +41123,9 @@ _tmp_267_rule(Parser *p) return _res; } -// _tmp_268: expression ['as' star_target] +// _tmp_270: expression ['as' star_target] static void * -_tmp_268_rule(Parser *p) +_tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41025,22 +41141,22 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_278_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -41049,9 +41165,9 @@ _tmp_268_rule(Parser *p) return _res; } -// _tmp_269: expressions ['as' star_target] +// _tmp_271: expressions ['as' star_target] static void * -_tmp_269_rule(Parser *p) +_tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41067,22 +41183,22 @@ _tmp_269_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_275_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_279_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41091,9 +41207,9 @@ _tmp_269_rule(Parser *p) return _res; } -// _tmp_270: 'as' NAME +// _tmp_272: 'as' NAME static void * -_tmp_270_rule(Parser *p) +_tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41109,7 +41225,7 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -41118,12 +41234,12 @@ _tmp_270_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -41132,9 +41248,9 @@ _tmp_270_rule(Parser *p) return _res; } -// _tmp_271: assignment_expression | expression !':=' +// _tmp_273: assignment_expression | expression !':=' static void * -_tmp_271_rule(Parser *p) +_tmp_273_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41150,18 +41266,18 @@ _tmp_271_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -41169,7 +41285,7 @@ _tmp_271_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -41177,12 +41293,12 @@ _tmp_271_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -41191,9 +41307,127 @@ _tmp_271_rule(Parser *p) return _res; } -// _tmp_272: 'as' star_target +// _loop0_275: ',' (starred_expression | (assignment_expression | expression !':=') !'=') +static asdl_seq * +_loop0_275_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ',' (starred_expression | (assignment_expression | expression !':=') !'=') + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_275[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + Token * _literal; + void *elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = _tmp_280_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + ) + { + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_275[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _gather_274: +// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_275 +static asdl_seq * +_gather_274_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_seq * _res = NULL; + int _mark = p->mark; + { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_275 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_275")); + void *elem; + asdl_seq * seq; + if ( + (elem = _tmp_280_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + && + (seq = _loop0_275_rule(p)) // _loop0_275 + ) + { + D(fprintf(stderr, "%*c+ _gather_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_275")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_274[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_275")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_276: 'as' star_target static void * -_tmp_272_rule(Parser *p) +_tmp_276_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41209,7 +41443,7 @@ _tmp_272_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_276[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41218,12 +41452,12 @@ _tmp_272_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_276[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_276[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41232,9 +41466,9 @@ _tmp_272_rule(Parser *p) return _res; } -// _tmp_273: 'as' star_target +// _tmp_277: 'as' star_target static void * -_tmp_273_rule(Parser *p) +_tmp_277_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41250,7 +41484,7 @@ _tmp_273_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_277[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41259,12 +41493,12 @@ _tmp_273_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_277[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_277[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41273,9 +41507,9 @@ _tmp_273_rule(Parser *p) return _res; } -// _tmp_274: 'as' star_target +// _tmp_278: 'as' star_target static void * -_tmp_274_rule(Parser *p) +_tmp_278_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41291,7 +41525,7 @@ _tmp_274_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_278[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41300,12 +41534,12 @@ _tmp_274_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_278[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_278[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41314,9 +41548,9 @@ _tmp_274_rule(Parser *p) return _res; } -// _tmp_275: 'as' star_target +// _tmp_279: 'as' star_target static void * -_tmp_275_rule(Parser *p) +_tmp_279_rule(Parser *p) { if (p->level++ == MAXSTACK) { _Pypegen_stack_overflow(p); @@ -41332,7 +41566,7 @@ _tmp_275_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_275[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_279[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41341,12 +41575,12 @@ _tmp_275_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_275[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_279[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_275[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_279[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41355,6 +41589,124 @@ _tmp_275_rule(Parser *p) return _res; } +// _tmp_280: starred_expression | (assignment_expression | expression !':=') !'=' +static void * +_tmp_280_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // starred_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_280[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + expr_ty starred_expression_var; + if ( + (starred_expression_var = starred_expression_rule(p)) // starred_expression + ) + { + D(fprintf(stderr, "%*c+ _tmp_280[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + _res = starred_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_280[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); + } + { // (assignment_expression | expression !':=') !'=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_280[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_281_var; + if ( + (_tmp_281_var = _tmp_281_rule(p)) // assignment_expression | expression !':=' + && + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' + ) + { + D(fprintf(stderr, "%*c+ _tmp_280[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_281_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_280[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_281: assignment_expression | expression !':=' +static void * +_tmp_281_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // assignment_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_281[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + expr_ty assignment_expression_var; + if ( + (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression + ) + { + D(fprintf(stderr, "%*c+ _tmp_281[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + _res = assignment_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_281[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); + } + { // expression !':=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_281[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + expr_ty expression_var; + if ( + (expression_var = expression_rule(p)) // expression + && + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' + ) + { + D(fprintf(stderr, "%*c+ _tmp_281[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + _res = expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_281[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); + } + _res = NULL; + done: + p->level--; + return _res; +} + void * _PyPegen_parse(Parser *p) { From 4b7a12db5488755fa5c2f2f879332205d799fe32 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 12 Oct 2023 22:03:07 +0200 Subject: [PATCH 1007/1206] [3.12] gh-110756: Sync regrtest with main branch (#110758) gh-110756: Sync regrtest with main branch Copy files from main to this branch: * Lib/test/libregrtest/*.py * Lib/test/__init__.py * Lib/test/__main__.py * Lib/test/autotest.py * Lib/test/pythoninfo.py * Lib/test/regrtest.py * Lib/test/test_regrtest.py Do not modify scripts running tests such as Makefile.pre.in, .github/workflows/build.yml or Tools/scripts/run_tests.py: do not use --fast-ci and --slow-ci in this change. Changes: * SPLITTESTDIRS: don't include test_inspect. * Add utils.process_cpu_count() using len(os.sched_getaffinity(0)). * test_regrtest doesn't use @support.without_optimizer which doesn't exist in Python 3.12. * Add support.set_sanitizer_env_var(). * Update test_faulthandler to use support.set_sanitizer_env_var(). --- Lib/test/__main__.py | 4 +- Lib/test/autotest.py | 2 +- Lib/test/libregrtest/__init__.py | 2 - Lib/test/libregrtest/cmdline.py | 114 ++- Lib/test/libregrtest/findtests.py | 105 +++ Lib/test/libregrtest/logger.py | 86 ++ Lib/test/libregrtest/main.py | 1174 +++++++++++---------------- Lib/test/libregrtest/pgo.py | 8 +- Lib/test/libregrtest/refleak.py | 29 +- Lib/test/libregrtest/result.py | 190 +++++ Lib/test/libregrtest/results.py | 261 ++++++ Lib/test/libregrtest/run_workers.py | 607 ++++++++++++++ Lib/test/libregrtest/runtests.py | 162 ++++ Lib/test/libregrtest/save_env.py | 6 +- Lib/test/libregrtest/setup.py | 139 ++-- Lib/test/libregrtest/single.py | 278 +++++++ Lib/test/libregrtest/utils.py | 398 ++++++++- Lib/test/libregrtest/worker.py | 116 +++ Lib/test/pythoninfo.py | 129 ++- Lib/test/regrtest.py | 2 +- Lib/test/support/__init__.py | 8 + Lib/test/test_faulthandler.py | 17 +- Lib/test/test_regrtest.py | 515 +++++++++--- 23 files changed, 3372 insertions(+), 980 deletions(-) create mode 100644 Lib/test/libregrtest/findtests.py create mode 100644 Lib/test/libregrtest/logger.py create mode 100644 Lib/test/libregrtest/result.py create mode 100644 Lib/test/libregrtest/results.py create mode 100644 Lib/test/libregrtest/run_workers.py create mode 100644 Lib/test/libregrtest/runtests.py create mode 100644 Lib/test/libregrtest/single.py create mode 100644 Lib/test/libregrtest/worker.py diff --git a/Lib/test/__main__.py b/Lib/test/__main__.py index 19a6b2b8904526..82b50ad2c6e777 100644 --- a/Lib/test/__main__.py +++ b/Lib/test/__main__.py @@ -1,2 +1,2 @@ -from test.libregrtest import main -main() +from test.libregrtest.main import main +main(_add_python_opts=True) diff --git a/Lib/test/autotest.py b/Lib/test/autotest.py index fa85cc153a133a..b5a1fab404c72d 100644 --- a/Lib/test/autotest.py +++ b/Lib/test/autotest.py @@ -1,5 +1,5 @@ # This should be equivalent to running regrtest.py from the cmdline. # It can be especially handy if you're in an interactive shell, e.g., # from test import autotest. -from test.libregrtest import main +from test.libregrtest.main import main main() diff --git a/Lib/test/libregrtest/__init__.py b/Lib/test/libregrtest/__init__.py index 5e8dba5dbde71a..e69de29bb2d1d6 100644 --- a/Lib/test/libregrtest/__init__.py +++ b/Lib/test/libregrtest/__init__.py @@ -1,2 +0,0 @@ -from test.libregrtest.cmdline import _parse_args, RESOURCE_NAMES, ALL_RESOURCES -from test.libregrtest.main import main diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py index d1a590d8c1a5b3..dd4cd335bef7e3 100644 --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -1,8 +1,9 @@ import argparse -import os +import os.path import shlex import sys from test.support import os_helper +from .utils import ALL_RESOURCES, RESOURCE_NAMES USAGE = """\ @@ -27,8 +28,10 @@ Additional option details: -r randomizes test execution order. You can use --randseed=int to provide an -int seed value for the randomizer; this is useful for reproducing troublesome -test orders. +int seed value for the randomizer. The randseed value will be used +to set seeds for all random usages in tests +(including randomizing the tests order if -r is set). +By default we always set random seed, but do not randomize test order. -s On the first invocation of regrtest using -s, the first test file found or the first test file given on the command line is run, and the name of @@ -130,25 +133,17 @@ """ -ALL_RESOURCES = ('audio', 'curses', 'largefile', 'network', - 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'walltime') - -# Other resources excluded from --use=all: -# -# - extralagefile (ex: test_zipfile64): really too slow to be enabled -# "by default" -# - tzdata: while needed to validate fully test_datetime, it makes -# test_datetime too slow (15-20 min on some buildbots) and so is disabled by -# default (see bpo-30822). -RESOURCE_NAMES = ALL_RESOURCES + ('extralargefile', 'tzdata') - - class Namespace(argparse.Namespace): def __init__(self, **kwargs) -> None: + self.ci = False self.testdir = None self.verbose = 0 self.quiet = False self.exclude = False + self.cleanup = False + self.wait = False + self.list_cases = False + self.list_tests = False self.single = False self.randomize = False self.fromfile = None @@ -157,7 +152,7 @@ def __init__(self, **kwargs) -> None: self.trace = False self.coverdir = 'coverage' self.runleaks = False - self.huntrleaks = False + self.huntrleaks: tuple[int, int, str] | None = None self.rerun = False self.verbose3 = False self.print_slow = False @@ -170,6 +165,14 @@ def __init__(self, **kwargs) -> None: self.ignore_tests = None self.pgo = False self.pgo_extended = False + self.worker_json = None + self.start = None + self.timeout = None + self.memlimit = None + self.threshold = None + self.fail_rerun = False + self.tempdir = None + self._add_python_opts = True super().__init__(**kwargs) @@ -198,19 +201,27 @@ def _create_parser(): # We add help explicitly to control what argument group it renders under. group.add_argument('-h', '--help', action='help', help='show this help message and exit') - group.add_argument('--timeout', metavar='TIMEOUT', type=float, + group.add_argument('--fast-ci', action='store_true', + help='Fast Continuous Integration (CI) mode used by ' + 'GitHub Actions') + group.add_argument('--slow-ci', action='store_true', + help='Slow Continuous Integration (CI) mode used by ' + 'buildbot workers') + group.add_argument('--timeout', metavar='TIMEOUT', help='dump the traceback and exit if a test takes ' 'more than TIMEOUT seconds; disabled if TIMEOUT ' 'is negative or equals to zero') group.add_argument('--wait', action='store_true', help='wait for user input, e.g., allow a debugger ' 'to be attached') - group.add_argument('--worker-args', metavar='ARGS') group.add_argument('-S', '--start', metavar='START', help='the name of the test at which to start.' + more_details) group.add_argument('-p', '--python', metavar='PYTHON', help='Command to run Python test subprocesses with.') + group.add_argument('--randseed', metavar='SEED', + dest='random_seed', type=int, + help='pass a global random seed') group = parser.add_argument_group('Verbosity') group.add_argument('-v', '--verbose', action='count', @@ -231,10 +242,6 @@ def _create_parser(): group = parser.add_argument_group('Selecting tests') group.add_argument('-r', '--randomize', action='store_true', help='randomize test execution order.' + more_details) - group.add_argument('--randseed', metavar='SEED', - dest='random_seed', type=int, - help='pass a random seed to reproduce a previous ' - 'random run') group.add_argument('-f', '--fromfile', metavar='FILE', help='read names of tests to run from a file.' + more_details) @@ -324,6 +331,9 @@ def _create_parser(): help='override the working directory for the test run') group.add_argument('--cleanup', action='store_true', help='remove old test_python_* directories') + group.add_argument('--dont-add-python-opts', dest='_add_python_opts', + action='store_false', + help="internal option, don't use it") return parser @@ -374,7 +384,50 @@ def _parse_args(args, **kwargs): for arg in ns.args: if arg.startswith('-'): parser.error("unrecognized arguments: %s" % arg) - sys.exit(1) + + if ns.timeout is not None: + # Support "--timeout=" (no value) so Makefile.pre.pre TESTTIMEOUT + # can be used by "make buildbottest" and "make test". + if ns.timeout != "": + try: + ns.timeout = float(ns.timeout) + except ValueError: + parser.error(f"invalid timeout value: {ns.timeout!r}") + else: + ns.timeout = None + + # Continuous Integration (CI): common options for fast/slow CI modes + if ns.slow_ci or ns.fast_ci: + # Similar to options: + # + # -j0 --randomize --fail-env-changed --fail-rerun --rerun + # --slowest --verbose3 + if ns.use_mp is None: + ns.use_mp = 0 + ns.randomize = True + ns.fail_env_changed = True + ns.fail_rerun = True + if ns.python is None: + ns.rerun = True + ns.print_slow = True + ns.verbose3 = True + else: + ns._add_python_opts = False + + # When both --slow-ci and --fast-ci options are present, + # --slow-ci has the priority + if ns.slow_ci: + # Similar to: -u "all" --timeout=1200 + if not ns.use: + ns.use = [['all']] + if ns.timeout is None: + ns.timeout = 1200 # 20 minutes + elif ns.fast_ci: + # Similar to: -u "all,-cpu" --timeout=600 + if not ns.use: + ns.use = [['all', '-cpu']] + if ns.timeout is None: + ns.timeout = 600 # 10 minutes if ns.single and ns.fromfile: parser.error("-s and -f don't go together!") @@ -401,10 +454,6 @@ def _parse_args(args, **kwargs): if ns.timeout is not None: if ns.timeout <= 0: ns.timeout = None - if ns.use_mp is not None: - if ns.use_mp <= 0: - # Use all cores + extras for tests that like to sleep - ns.use_mp = 2 + (os.cpu_count() or 1) if ns.use: for a in ns.use: for r in a: @@ -448,4 +497,13 @@ def _parse_args(args, **kwargs): # --forever implies --failfast ns.failfast = True + if ns.huntrleaks: + warmup, repetitions, _ = ns.huntrleaks + if warmup < 1 or repetitions < 1: + msg = ("Invalid values for the --huntrleaks/-R parameters. The " + "number of warmups and repetitions must be at least 1 " + "each (1:1).") + print(msg, file=sys.stderr, flush=True) + sys.exit(2) + return ns diff --git a/Lib/test/libregrtest/findtests.py b/Lib/test/libregrtest/findtests.py new file mode 100644 index 00000000000000..96cc3e0d021184 --- /dev/null +++ b/Lib/test/libregrtest/findtests.py @@ -0,0 +1,105 @@ +import os +import sys +import unittest + +from test import support + +from .utils import ( + StrPath, TestName, TestTuple, TestList, FilterTuple, + abs_module_name, count, printlist) + + +# If these test directories are encountered recurse into them and treat each +# "test_*.py" file or each sub-directory as a separate test module. This can +# increase parallelism. +# +# Beware this can't generally be done for any directory with sub-tests as the +# __init__.py may do things which alter what tests are to be run. +SPLITTESTDIRS: set[TestName] = { + "test_asyncio", + "test_concurrent_futures", + "test_future_stmt", + "test_gdb", + "test_multiprocessing_fork", + "test_multiprocessing_forkserver", + "test_multiprocessing_spawn", +} + + +def findtestdir(path: StrPath | None = None) -> StrPath: + return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir + + +def findtests(*, testdir: StrPath | None = None, exclude=(), + split_test_dirs: set[TestName] = SPLITTESTDIRS, + base_mod: str = "") -> TestList: + """Return a list of all applicable test modules.""" + testdir = findtestdir(testdir) + tests = [] + for name in os.listdir(testdir): + mod, ext = os.path.splitext(name) + if (not mod.startswith("test_")) or (mod in exclude): + continue + if base_mod: + fullname = f"{base_mod}.{mod}" + else: + fullname = mod + if fullname in split_test_dirs: + subdir = os.path.join(testdir, mod) + if not base_mod: + fullname = f"test.{mod}" + tests.extend(findtests(testdir=subdir, exclude=exclude, + split_test_dirs=split_test_dirs, + base_mod=fullname)) + elif ext in (".py", ""): + tests.append(fullname) + return sorted(tests) + + +def split_test_packages(tests, *, testdir: StrPath | None = None, exclude=(), + split_test_dirs=SPLITTESTDIRS): + testdir = findtestdir(testdir) + splitted = [] + for name in tests: + if name in split_test_dirs: + subdir = os.path.join(testdir, name) + splitted.extend(findtests(testdir=subdir, exclude=exclude, + split_test_dirs=split_test_dirs, + base_mod=name)) + else: + splitted.append(name) + return splitted + + +def _list_cases(suite): + for test in suite: + if isinstance(test, unittest.loader._FailedTest): + continue + if isinstance(test, unittest.TestSuite): + _list_cases(test) + elif isinstance(test, unittest.TestCase): + if support.match_test(test): + print(test.id()) + +def list_cases(tests: TestTuple, *, + match_tests: FilterTuple | None = None, + ignore_tests: FilterTuple | None = None, + test_dir: StrPath | None = None): + support.verbose = False + support.set_match_tests(match_tests, ignore_tests) + + skipped = [] + for test_name in tests: + module_name = abs_module_name(test_name, test_dir) + try: + suite = unittest.defaultTestLoader.loadTestsFromName(module_name) + _list_cases(suite) + except unittest.SkipTest: + skipped.append(test_name) + + if skipped: + sys.stdout.flush() + stderr = sys.stderr + print(file=stderr) + print(count(len(skipped), "test"), "skipped:", file=stderr) + printlist(skipped, file=stderr) diff --git a/Lib/test/libregrtest/logger.py b/Lib/test/libregrtest/logger.py new file mode 100644 index 00000000000000..a125706927393c --- /dev/null +++ b/Lib/test/libregrtest/logger.py @@ -0,0 +1,86 @@ +import os +import time + +from test.support import MS_WINDOWS +from .results import TestResults +from .runtests import RunTests +from .utils import print_warning + +if MS_WINDOWS: + from .win_utils import WindowsLoadTracker + + +class Logger: + def __init__(self, results: TestResults, quiet: bool, pgo: bool): + self.start_time = time.perf_counter() + self.test_count_text = '' + self.test_count_width = 3 + self.win_load_tracker: WindowsLoadTracker | None = None + self._results: TestResults = results + self._quiet: bool = quiet + self._pgo: bool = pgo + + def log(self, line: str = '') -> None: + empty = not line + + # add the system load prefix: "load avg: 1.80 " + load_avg = self.get_load_avg() + if load_avg is not None: + line = f"load avg: {load_avg:.2f} {line}" + + # add the timestamp prefix: "0:01:05 " + log_time = time.perf_counter() - self.start_time + + mins, secs = divmod(int(log_time), 60) + hours, mins = divmod(mins, 60) + formatted_log_time = "%d:%02d:%02d" % (hours, mins, secs) + + line = f"{formatted_log_time} {line}" + if empty: + line = line[:-1] + + print(line, flush=True) + + def get_load_avg(self) -> float | None: + if hasattr(os, 'getloadavg'): + return os.getloadavg()[0] + if self.win_load_tracker is not None: + return self.win_load_tracker.getloadavg() + return None + + def display_progress(self, test_index: int, text: str) -> None: + if self._quiet: + return + results = self._results + + # "[ 51/405/1] test_tcl passed" + line = f"{test_index:{self.test_count_width}}{self.test_count_text}" + fails = len(results.bad) + len(results.env_changed) + if fails and not self._pgo: + line = f"{line}/{fails}" + self.log(f"[{line}] {text}") + + def set_tests(self, runtests: RunTests) -> None: + if runtests.forever: + self.test_count_text = '' + self.test_count_width = 3 + else: + self.test_count_text = '/{}'.format(len(runtests.tests)) + self.test_count_width = len(self.test_count_text) - 1 + + def start_load_tracker(self) -> None: + if not MS_WINDOWS: + return + + try: + self.win_load_tracker = WindowsLoadTracker() + except PermissionError as error: + # Standard accounts may not have access to the performance + # counters. + print_warning(f'Failed to create WindowsLoadTracker: {error}') + + def stop_load_tracker(self) -> None: + if self.win_load_tracker is None: + return + self.win_load_tracker.close() + self.win_load_tracker = None diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 56d562d0b068dd..fe35df05c80e89 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -1,38 +1,30 @@ -import faulthandler -import locale import os -import platform import random import re +import shlex import sys import sysconfig -import tempfile import time -import unittest -from test.libregrtest.cmdline import _parse_args -from test.libregrtest.runtest import ( - findtests, split_test_packages, runtest, abs_module_name, - PROGRESS_MIN_TIME, State, MatchTestsDict, RunTests) -from test.libregrtest.setup import setup_tests -from test.libregrtest.pgo import setup_pgo_tests -from test.libregrtest.utils import (strip_py_suffix, count, format_duration, - printlist, get_build_info) -from test import support -from test.support import TestStats -from test.support import os_helper -from test.support import threading_helper - - -# bpo-38203: Maximum delay in seconds to exit Python (call Py_Finalize()). -# Used to protect against threading._shutdown() hang. -# Must be smaller than buildbot "1200 seconds without output" limit. -EXIT_TIMEOUT = 120.0 -EXITCODE_BAD_TEST = 2 -EXITCODE_ENV_CHANGED = 3 -EXITCODE_NO_TESTS_RAN = 4 -EXITCODE_RERUN_FAIL = 5 -EXITCODE_INTERRUPTED = 130 +from test import support +from test.support import os_helper, MS_WINDOWS + +from .cmdline import _parse_args, Namespace +from .findtests import findtests, split_test_packages, list_cases +from .logger import Logger +from .pgo import setup_pgo_tests +from .result import State +from .results import TestResults, EXITCODE_INTERRUPTED +from .runtests import RunTests, HuntRefleak +from .setup import setup_process, setup_test_dir +from .single import run_single_test, PROGRESS_MIN_TIME +from .utils import ( + StrPath, StrJSON, TestName, TestList, TestTuple, FilterTuple, + strip_py_suffix, count, format_duration, + printlist, get_temp_dir, get_work_dir, exit_timeout, + display_header, cleanup_temp_dir, print_warning, + is_cross_compiled, get_host_runner, process_cpu_count, + EXIT_TIMEOUT) class Regrtest: @@ -58,306 +50,212 @@ class Regrtest: directly to set the values that would normally be set by flags on the command line. """ - def __init__(self): - # Namespace of command line options - self.ns = None - - # tests - self.tests = [] - self.selected = [] - self.all_runtests: list[RunTests] = [] - - # test results - self.good: list[str] = [] - self.bad: list[str] = [] - self.rerun_bad: list[str] = [] - self.skipped: list[str] = [] - self.resource_denied: list[str] = [] - self.environment_changed: list[str] = [] - self.run_no_tests: list[str] = [] - self.rerun: list[str] = [] - - self.need_rerun: list[TestResult] = [] + def __init__(self, ns: Namespace, _add_python_opts: bool = False): + # Log verbosity + self.verbose: int = int(ns.verbose) + self.quiet: bool = ns.quiet + self.pgo: bool = ns.pgo + self.pgo_extended: bool = ns.pgo_extended + + # Test results + self.results: TestResults = TestResults() self.first_state: str | None = None - self.interrupted = False - self.total_stats = TestStats() - # used by --slow - self.test_times = [] + # Logger + self.logger = Logger(self.results, self.quiet, self.pgo) + + # Actions + self.want_header: bool = ns.header + self.want_list_tests: bool = ns.list_tests + self.want_list_cases: bool = ns.list_cases + self.want_wait: bool = ns.wait + self.want_cleanup: bool = ns.cleanup + self.want_rerun: bool = ns.rerun + self.want_run_leaks: bool = ns.runleaks + + self.ci_mode: bool = (ns.fast_ci or ns.slow_ci) + self.want_add_python_opts: bool = (_add_python_opts + and ns._add_python_opts) + + # Select tests + if ns.match_tests: + self.match_tests: FilterTuple | None = tuple(ns.match_tests) + else: + self.match_tests = None + if ns.ignore_tests: + self.ignore_tests: FilterTuple | None = tuple(ns.ignore_tests) + else: + self.ignore_tests = None + self.exclude: bool = ns.exclude + self.fromfile: StrPath | None = ns.fromfile + self.starting_test: TestName | None = ns.start + self.cmdline_args: TestList = ns.args - # used by --coverage, trace.Trace instance - self.tracer = None + # Workers + if ns.use_mp is None: + num_workers = 0 # run sequentially + elif ns.use_mp <= 0: + num_workers = -1 # use the number of CPUs + else: + num_workers = ns.use_mp + self.num_workers: int = num_workers + self.worker_json: StrJSON | None = ns.worker_json + + # Options to run tests + self.fail_fast: bool = ns.failfast + self.fail_env_changed: bool = ns.fail_env_changed + self.fail_rerun: bool = ns.fail_rerun + self.forever: bool = ns.forever + self.output_on_failure: bool = ns.verbose3 + self.timeout: float | None = ns.timeout + if ns.huntrleaks: + warmups, runs, filename = ns.huntrleaks + filename = os.path.abspath(filename) + self.hunt_refleak: HuntRefleak | None = HuntRefleak(warmups, runs, filename) + else: + self.hunt_refleak = None + self.test_dir: StrPath | None = ns.testdir + self.junit_filename: StrPath | None = ns.xmlpath + self.memory_limit: str | None = ns.memlimit + self.gc_threshold: int | None = ns.threshold + self.use_resources: tuple[str, ...] = tuple(ns.use_resources) + if ns.python: + self.python_cmd: tuple[str, ...] | None = tuple(ns.python) + else: + self.python_cmd = None + self.coverage: bool = ns.trace + self.coverage_dir: StrPath | None = ns.coverdir + self.tmp_dir: StrPath | None = ns.tempdir + + # Randomize + self.randomize: bool = ns.randomize + self.random_seed: int | None = ( + ns.random_seed + if ns.random_seed is not None + else random.getrandbits(32) + ) + if 'SOURCE_DATE_EPOCH' in os.environ: + self.randomize = False + self.random_seed = None + + # tests + self.first_runtests: RunTests | None = None + + # used by --slowest + self.print_slowest: bool = ns.print_slow # used to display the progress bar "[ 3/100]" self.start_time = time.perf_counter() - self.test_count_text = '' - self.test_count_width = 1 # used by --single - self.next_single_test = None - self.next_single_filename = None - - # used by --junit-xml - self.testsuite_xml = None - - # misc - self.win_load_tracker = None - self.tmp_dir = None - - def get_executed(self): - return (set(self.good) | set(self.bad) | set(self.skipped) - | set(self.resource_denied) | set(self.environment_changed) - | set(self.run_no_tests)) - - def accumulate_result(self, result, rerun=False): - fail_env_changed = self.ns.fail_env_changed - test_name = result.test_name - - match result.state: - case State.PASSED: - self.good.append(test_name) - case State.ENV_CHANGED: - self.environment_changed.append(test_name) - case State.SKIPPED: - self.skipped.append(test_name) - case State.RESOURCE_DENIED: - self.resource_denied.append(test_name) - case State.INTERRUPTED: - self.interrupted = True - case State.DID_NOT_RUN: - self.run_no_tests.append(test_name) - case _: - if result.is_failed(fail_env_changed): - self.bad.append(test_name) - self.need_rerun.append(result) - else: - raise ValueError(f"invalid test state: {result.state!r}") - - if result.has_meaningful_duration() and not rerun: - self.test_times.append((result.duration, test_name)) - if result.stats is not None: - self.total_stats.accumulate(result.stats) - if rerun: - self.rerun.append(test_name) - - xml_data = result.xml_data - if xml_data: - import xml.etree.ElementTree as ET - for e in xml_data: - try: - self.testsuite_xml.append(ET.fromstring(e)) - except ET.ParseError: - print(xml_data, file=sys.__stderr__) - raise + self.single_test_run: bool = ns.single + self.next_single_test: TestName | None = None + self.next_single_filename: StrPath | None = None def log(self, line=''): - empty = not line - - # add the system load prefix: "load avg: 1.80 " - load_avg = self.getloadavg() - if load_avg is not None: - line = f"load avg: {load_avg:.2f} {line}" - - # add the timestamp prefix: "0:01:05 " - test_time = time.perf_counter() - self.start_time - - mins, secs = divmod(int(test_time), 60) - hours, mins = divmod(mins, 60) - test_time = "%d:%02d:%02d" % (hours, mins, secs) + self.logger.log(line) - line = f"{test_time} {line}" - if empty: - line = line[:-1] - - print(line, flush=True) - - def display_progress(self, test_index, text): - quiet = self.ns.quiet - pgo = self.ns.pgo - if quiet: - return - - # "[ 51/405/1] test_tcl passed" - line = f"{test_index:{self.test_count_width}}{self.test_count_text}" - fails = len(self.bad) + len(self.environment_changed) - if fails and not pgo: - line = f"{line}/{fails}" - self.log(f"[{line}] {text}") - - def parse_args(self, kwargs): - ns = _parse_args(sys.argv[1:], **kwargs) - - if ns.xmlpath: - support.junit_xml_list = self.testsuite_xml = [] - - strip_py_suffix(ns.args) - - if ns.huntrleaks: - warmup, repetitions, _ = ns.huntrleaks - if warmup < 1 or repetitions < 1: - msg = ("Invalid values for the --huntrleaks/-R parameters. The " - "number of warmups and repetitions must be at least 1 " - "each (1:1).") - print(msg, file=sys.stderr, flush=True) - sys.exit(2) - - if ns.tempdir: - ns.tempdir = os.path.expanduser(ns.tempdir) - - self.ns = ns - - def find_tests(self, tests): - ns = self.ns - single = ns.single - fromfile = ns.fromfile - pgo = ns.pgo - exclude = ns.exclude - test_dir = ns.testdir - starting_test = ns.start - randomize = ns.randomize - - self.tests = tests - - if single: + def find_tests(self, tests: TestList | None = None) -> tuple[TestTuple, TestList | None]: + if self.single_test_run: self.next_single_filename = os.path.join(self.tmp_dir, 'pynexttest') try: with open(self.next_single_filename, 'r') as fp: next_test = fp.read().strip() - self.tests = [next_test] + tests = [next_test] except OSError: pass - if fromfile: - self.tests = [] + if self.fromfile: + tests = [] # regex to match 'test_builtin' in line: # '0:00:00 [ 4/400] test_builtin -- test_dict took 1 sec' regex = re.compile(r'\btest_[a-zA-Z0-9_]+\b') - with open(os.path.join(os_helper.SAVEDCWD, fromfile)) as fp: + with open(os.path.join(os_helper.SAVEDCWD, self.fromfile)) as fp: for line in fp: line = line.split('#', 1)[0] line = line.strip() match = regex.search(line) if match is not None: - self.tests.append(match.group()) + tests.append(match.group()) - strip_py_suffix(self.tests) + strip_py_suffix(tests) - if pgo: + if self.pgo: # add default PGO tests if no tests are specified - setup_pgo_tests(ns) + setup_pgo_tests(self.cmdline_args, self.pgo_extended) exclude_tests = set() - if exclude: - for arg in ns.args: + if self.exclude: + for arg in self.cmdline_args: exclude_tests.add(arg) - ns.args = [] + self.cmdline_args = [] - alltests = findtests(testdir=test_dir, exclude=exclude_tests) + alltests = findtests(testdir=self.test_dir, + exclude=exclude_tests) - if not fromfile: - self.selected = self.tests or ns.args - if self.selected: - self.selected = split_test_packages(self.selected) + if not self.fromfile: + selected = tests or self.cmdline_args + if selected: + selected = split_test_packages(selected) else: - self.selected = alltests + selected = alltests else: - self.selected = self.tests + selected = tests - if single: - self.selected = self.selected[:1] + if self.single_test_run: + selected = selected[:1] try: - pos = alltests.index(self.selected[0]) + pos = alltests.index(selected[0]) self.next_single_test = alltests[pos + 1] except IndexError: pass # Remove all the selected tests that precede start if it's set. - if starting_test: + if self.starting_test: try: - del self.selected[:self.selected.index(starting_test)] + del selected[:selected.index(self.starting_test)] except ValueError: - print(f"Cannot find starting test: {starting_test}") + print(f"Cannot find starting test: {self.starting_test}") sys.exit(1) - if randomize: - if ns.random_seed is None: - ns.random_seed = random.randrange(10000000) - random.seed(ns.random_seed) - random.shuffle(self.selected) + random.seed(self.random_seed) + if self.randomize: + random.shuffle(selected) - def list_tests(self): - for name in self.selected: + return (tuple(selected), tests) + + @staticmethod + def list_tests(tests: TestTuple): + for name in tests: print(name) - def _list_cases(self, suite): - for test in suite: - if isinstance(test, unittest.loader._FailedTest): - continue - if isinstance(test, unittest.TestSuite): - self._list_cases(test) - elif isinstance(test, unittest.TestCase): - if support.match_test(test): - print(test.id()) - - def list_cases(self): - ns = self.ns - test_dir = ns.testdir - support.verbose = False - support.set_match_tests(ns.match_tests, ns.ignore_tests) - - skipped = [] - for test_name in self.selected: - module_name = abs_module_name(test_name, test_dir) - try: - suite = unittest.defaultTestLoader.loadTestsFromName(module_name) - self._list_cases(suite) - except unittest.SkipTest: - skipped.append(test_name) - - if skipped: - sys.stdout.flush() - stderr = sys.stderr - print(file=stderr) - print(count(len(skipped), "test"), "skipped:", file=stderr) - printlist(skipped, file=stderr) - - def get_rerun_match(self, rerun_list) -> MatchTestsDict: - rerun_match_tests = {} - for result in rerun_list: - match_tests = result.get_rerun_match_tests() - # ignore empty match list - if match_tests: - rerun_match_tests[result.test_name] = match_tests - return rerun_match_tests - - def _rerun_failed_tests(self, need_rerun): + def _rerun_failed_tests(self, runtests: RunTests): # Configure the runner to re-run tests - ns = self.ns - ns.verbose = True - ns.failfast = False - ns.verbose3 = False - ns.forever = False - if ns.use_mp is None: - ns.use_mp = 1 + if self.num_workers == 0: + # Always run tests in fresh processes to have more deterministic + # initial state. Don't re-run tests in parallel but limit to a + # single worker process to have side effects (on the system load + # and timings) between tests. + self.num_workers = 1 - # Get tests to re-run - tests = [result.test_name for result in need_rerun] - match_tests = self.get_rerun_match(need_rerun) - self.set_tests(tests) - - # Clear previously failed tests - self.rerun_bad.extend(self.bad) - self.bad.clear() - self.need_rerun.clear() + tests, match_tests_dict = self.results.prepare_rerun() # Re-run failed tests self.log(f"Re-running {len(tests)} failed tests in verbose mode in subprocesses") - runtests = RunTests(tests, match_tests=match_tests, rerun=True) - self.all_runtests.append(runtests) - self._run_tests_mp(runtests) - - def rerun_failed_tests(self, need_rerun): - if self.ns.python: + runtests = runtests.copy( + tests=tests, + rerun=True, + verbose=True, + forever=False, + fail_fast=False, + match_tests_dict=match_tests_dict, + output_on_failure=False) + self.logger.set_tests(runtests) + self._run_tests_mp(runtests, self.num_workers) + return runtests + + def rerun_failed_tests(self, runtests: RunTests): + if self.python_cmd: # Temp patch for https://github.com/python/cpython/issues/94052 self.log( "Re-running failed tests is not supported with --python " @@ -365,126 +263,61 @@ def rerun_failed_tests(self, need_rerun): ) return - self.first_state = self.get_tests_state() + self.first_state = self.get_state() print() - self._rerun_failed_tests(need_rerun) + rerun_runtests = self._rerun_failed_tests(runtests) - if self.bad: - print(count(len(self.bad), 'test'), "failed again:") - printlist(self.bad) + if self.results.bad: + print(count(len(self.results.bad), 'test'), "failed again:") + printlist(self.results.bad) - self.display_result() - - def display_result(self): - pgo = self.ns.pgo - quiet = self.ns.quiet - print_slow = self.ns.print_slow + self.display_result(rerun_runtests) + def display_result(self, runtests): # If running the test suite for PGO then no one cares about results. - if pgo: + if runtests.pgo: return + state = self.get_state() print() - print("== Tests result: %s ==" % self.get_tests_state()) - - if self.interrupted: - print("Test suite interrupted by signal SIGINT.") - - omitted = set(self.selected) - self.get_executed() - if omitted: - print() - print(count(len(omitted), "test"), "omitted:") - printlist(omitted) - - if self.good and not quiet: - print() - if (not self.bad - and not self.skipped - and not self.interrupted - and len(self.good) > 1): - print("All", end=' ') - print(count(len(self.good), "test"), "OK.") - - if print_slow: - self.test_times.sort(reverse=True) - print() - print("10 slowest tests:") - for test_time, test in self.test_times[:10]: - print("- %s: %s" % (test, format_duration(test_time))) - - if self.bad: - print() - print(count(len(self.bad), "test"), "failed:") - printlist(self.bad) - - if self.environment_changed: - print() - print("{} altered the execution environment:".format( - count(len(self.environment_changed), "test"))) - printlist(self.environment_changed) - - if self.skipped and not quiet: - print() - print(count(len(self.skipped), "test"), "skipped:") - printlist(self.skipped) - - if self.resource_denied and not quiet: - print() - print(count(len(self.resource_denied), "test"), "skipped (resource denied):") - printlist(self.resource_denied) - - if self.rerun: - print() - print("%s:" % count(len(self.rerun), "re-run test")) - printlist(self.rerun) - - if self.run_no_tests: - print() - print(count(len(self.run_no_tests), "test"), "run no tests:") - printlist(self.run_no_tests) - - def run_test(self, test_index, test_name, previous_test, save_modules): - text = test_name - if previous_test: - text = '%s -- %s' % (text, previous_test) - self.display_progress(test_index, text) + print(f"== Tests result: {state} ==") - if self.tracer: + self.results.display_result(runtests.tests, + self.quiet, self.print_slowest) + + def run_test(self, test_name: TestName, runtests: RunTests, tracer): + if tracer is not None: # If we're tracing code coverage, then we don't exit with status # if on a false return value from main. - cmd = ('result = runtest(self.ns, test_name); ' - 'self.accumulate_result(result)') - ns = dict(locals()) - self.tracer.runctx(cmd, globals=globals(), locals=ns) - result = ns['result'] + cmd = ('result = run_single_test(test_name, runtests)') + namespace = dict(locals()) + tracer.runctx(cmd, globals=globals(), locals=namespace) + result = namespace['result'] else: - result = runtest(self.ns, test_name) - self.accumulate_result(result) + result = run_single_test(test_name, runtests) - # Unload the newly imported modules (best effort finalization) - for module in sys.modules.keys(): - if module not in save_modules and module.startswith("test."): - support.unload(module) + self.results.accumulate_result(result, runtests) return result def run_tests_sequentially(self, runtests): - ns = self.ns - coverage = ns.trace - fail_fast = ns.failfast - fail_env_changed = ns.fail_env_changed - timeout = ns.timeout - - if coverage: + if self.coverage: import trace - self.tracer = trace.Trace(trace=False, count=True) + tracer = trace.Trace(trace=False, count=True) + else: + tracer = None save_modules = sys.modules.keys() - msg = "Run tests sequentially" - if timeout: - msg += " (timeout: %s)" % format_duration(timeout) + jobs = runtests.get_jobs() + if jobs is not None: + tests = count(jobs, 'test') + else: + tests = 'tests' + msg = f"Run {tests} sequentially" + if runtests.timeout: + msg += " (timeout: %s)" % format_duration(runtests.timeout) self.log(msg) previous_test = None @@ -492,10 +325,19 @@ def run_tests_sequentially(self, runtests): for test_index, test_name in enumerate(tests_iter, 1): start_time = time.perf_counter() - result = self.run_test(test_index, test_name, - previous_test, save_modules) + text = test_name + if previous_test: + text = '%s -- %s' % (text, previous_test) + self.logger.display_progress(test_index, text) + + result = self.run_test(test_name, runtests, tracer) - if result.must_stop(fail_fast, fail_env_changed): + # Unload the newly imported modules (best effort finalization) + for module in sys.modules.keys(): + if module not in save_modules and module.startswith("test."): + support.unload(module) + + if result.must_stop(self.fail_fast, self.fail_env_changed): break previous_test = str(result) @@ -509,129 +351,19 @@ def run_tests_sequentially(self, runtests): if previous_test: print(previous_test) - def display_header(self): - # Print basic platform information - print("==", platform.python_implementation(), *sys.version.split()) - print("==", platform.platform(aliased=True), - "%s-endian" % sys.byteorder) - print("== Python build:", ' '.join(get_build_info())) - print("== cwd:", os.getcwd()) - cpu_count = os.cpu_count() - if cpu_count: - print("== CPU count:", cpu_count) - print("== encodings: locale=%s, FS=%s" - % (locale.getencoding(), sys.getfilesystemencoding())) - self.display_sanitizers() - - def display_sanitizers(self): - # This makes it easier to remember what to set in your local - # environment when trying to reproduce a sanitizer failure. - asan = support.check_sanitizer(address=True) - msan = support.check_sanitizer(memory=True) - ubsan = support.check_sanitizer(ub=True) - sanitizers = [] - if asan: - sanitizers.append("address") - if msan: - sanitizers.append("memory") - if ubsan: - sanitizers.append("undefined behavior") - if not sanitizers: - return + return tracer - print(f"== sanitizers: {', '.join(sanitizers)}") - for sanitizer, env_var in ( - (asan, "ASAN_OPTIONS"), - (msan, "MSAN_OPTIONS"), - (ubsan, "UBSAN_OPTIONS"), - ): - options= os.environ.get(env_var) - if sanitizer and options is not None: - print(f"== {env_var}={options!r}") - - def no_tests_run(self): - return not any((self.good, self.bad, self.skipped, self.interrupted, - self.environment_changed)) - - def get_tests_state(self): - fail_env_changed = self.ns.fail_env_changed - - result = [] - if self.bad: - result.append("FAILURE") - elif fail_env_changed and self.environment_changed: - result.append("ENV CHANGED") - elif self.no_tests_run(): - result.append("NO TESTS RAN") - - if self.interrupted: - result.append("INTERRUPTED") - - if not result: - result.append("SUCCESS") - - result = ', '.join(result) + def get_state(self): + state = self.results.get_state(self.fail_env_changed) if self.first_state: - result = '%s then %s' % (self.first_state, result) - return result - - def _run_tests_mp(self, runtests: RunTests) -> None: - from test.libregrtest.runtest_mp import run_tests_multiprocess - # If we're on windows and this is the parent runner (not a worker), - # track the load average. - if sys.platform == 'win32': - from test.libregrtest.win_utils import WindowsLoadTracker + state = f'{self.first_state} then {state}' + return state - try: - self.win_load_tracker = WindowsLoadTracker() - except PermissionError as error: - # Standard accounts may not have access to the performance - # counters. - print(f'Failed to create WindowsLoadTracker: {error}') + def _run_tests_mp(self, runtests: RunTests, num_workers: int) -> None: + from .run_workers import RunWorkers + RunWorkers(num_workers, runtests, self.logger, self.results).run() - try: - run_tests_multiprocess(self, runtests) - finally: - if self.win_load_tracker is not None: - self.win_load_tracker.close() - self.win_load_tracker = None - - def set_tests(self, tests): - self.tests = tests - if self.ns.forever: - self.test_count_text = '' - self.test_count_width = 3 - else: - self.test_count_text = '/{}'.format(len(self.tests)) - self.test_count_width = len(self.test_count_text) - 1 - - def run_tests(self): - # For a partial run, we do not need to clutter the output. - if (self.ns.header - or not(self.ns.pgo or self.ns.quiet or self.ns.single - or self.tests or self.ns.args)): - self.display_header() - - if self.ns.huntrleaks: - warmup, repetitions, _ = self.ns.huntrleaks - if warmup < 3: - msg = ("WARNING: Running tests with --huntrleaks/-R and less than " - "3 warmup repetitions can give false positives!") - print(msg, file=sys.stdout, flush=True) - - if self.ns.randomize: - print("Using random seed", self.ns.random_seed) - - tests = self.selected - self.set_tests(tests) - runtests = RunTests(tests, forever=self.ns.forever) - self.all_runtests.append(runtests) - if self.ns.use_mp: - self._run_tests_mp(runtests) - else: - self.run_tests_sequentially(runtests) - - def finalize(self): + def finalize_tests(self, tracer): if self.next_single_filename: if self.next_single_test: with open(self.next_single_filename, 'w') as fp: @@ -639,255 +371,299 @@ def finalize(self): else: os.unlink(self.next_single_filename) - if self.tracer: - r = self.tracer.results() - r.write_results(show_missing=True, summary=True, - coverdir=self.ns.coverdir) + if tracer is not None: + results = tracer.results() + results.write_results(show_missing=True, summary=True, + coverdir=self.coverage_dir) - if self.ns.runleaks: + if self.want_run_leaks: os.system("leaks %d" % os.getpid()) - self.save_xml_result() + if self.junit_filename: + self.results.write_junit(self.junit_filename) def display_summary(self): - duration = time.perf_counter() - self.start_time - first_runtests = self.all_runtests[0] - # the second runtests (re-run failed tests) disables forever, - # use the first runtests - forever = first_runtests.forever - filtered = bool(self.ns.match_tests) or bool(self.ns.ignore_tests) + duration = time.perf_counter() - self.logger.start_time + filtered = bool(self.match_tests) or bool(self.ignore_tests) # Total duration print() print("Total duration: %s" % format_duration(duration)) - # Total tests - total = self.total_stats - text = f'run={total.tests_run:,}' - if filtered: - text = f"{text} (filtered)" - stats = [text] - if total.failures: - stats.append(f'failures={total.failures:,}') - if total.skipped: - stats.append(f'skipped={total.skipped:,}') - print(f"Total tests: {' '.join(stats)}") - - # Total test files - all_tests = [self.good, self.bad, self.rerun, - self.skipped, - self.environment_changed, self.run_no_tests] - run = sum(map(len, all_tests)) - text = f'run={run}' - if not forever: - ntest = len(first_runtests.tests) - text = f"{text}/{ntest}" - if filtered: - text = f"{text} (filtered)" - report = [text] - for name, tests in ( - ('failed', self.bad), - ('env_changed', self.environment_changed), - ('skipped', self.skipped), - ('resource_denied', self.resource_denied), - ('rerun', self.rerun), - ('run_no_tests', self.run_no_tests), - ): - if tests: - report.append(f'{name}={len(tests)}') - print(f"Total test files: {' '.join(report)}") + self.results.display_summary(self.first_runtests, filtered) # Result - result = self.get_tests_state() - print(f"Result: {result}") + state = self.get_state() + print(f"Result: {state}") + + def create_run_tests(self, tests: TestTuple): + return RunTests( + tests, + fail_fast=self.fail_fast, + fail_env_changed=self.fail_env_changed, + match_tests=self.match_tests, + ignore_tests=self.ignore_tests, + match_tests_dict=None, + rerun=False, + forever=self.forever, + pgo=self.pgo, + pgo_extended=self.pgo_extended, + output_on_failure=self.output_on_failure, + timeout=self.timeout, + verbose=self.verbose, + quiet=self.quiet, + hunt_refleak=self.hunt_refleak, + test_dir=self.test_dir, + use_junit=(self.junit_filename is not None), + memory_limit=self.memory_limit, + gc_threshold=self.gc_threshold, + use_resources=self.use_resources, + python_cmd=self.python_cmd, + randomize=self.randomize, + random_seed=self.random_seed, + json_file=None, + ) + + def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int: + if self.hunt_refleak and self.hunt_refleak.warmups < 3: + msg = ("WARNING: Running tests with --huntrleaks/-R and " + "less than 3 warmup repetitions can give false positives!") + print(msg, file=sys.stdout, flush=True) + + if self.num_workers < 0: + # Use all CPUs + 2 extra worker processes for tests + # that like to sleep + self.num_workers = (process_cpu_count() or 1) + 2 - def save_xml_result(self): - if not self.ns.xmlpath and not self.testsuite_xml: - return - - import xml.etree.ElementTree as ET - root = ET.Element("testsuites") - - # Manually count the totals for the overall summary - totals = {'tests': 0, 'errors': 0, 'failures': 0} - for suite in self.testsuite_xml: - root.append(suite) - for k in totals: - try: - totals[k] += int(suite.get(k, 0)) - except ValueError: - pass - - for k, v in totals.items(): - root.set(k, str(v)) - - xmlpath = os.path.join(os_helper.SAVEDCWD, self.ns.xmlpath) - with open(xmlpath, 'wb') as f: - for s in ET.tostringlist(root): - f.write(s) - - def fix_umask(self): - if support.is_emscripten: - # Emscripten has default umask 0o777, which breaks some tests. - # see https://github.com/emscripten-core/emscripten/issues/17269 - old_mask = os.umask(0) - if old_mask == 0o777: - os.umask(0o027) - else: - os.umask(old_mask) - - def set_temp_dir(self): - if self.ns.tempdir: - self.tmp_dir = self.ns.tempdir - - if not self.tmp_dir: - # When tests are run from the Python build directory, it is best practice - # to keep the test files in a subfolder. This eases the cleanup of leftover - # files using the "make distclean" command. - if sysconfig.is_python_build(): - self.tmp_dir = sysconfig.get_config_var('abs_builddir') - if self.tmp_dir is None: - self.tmp_dir = sysconfig.get_config_var('abs_srcdir') - if not self.tmp_dir: - # gh-74470: On Windows, only srcdir is available. Using - # abs_builddir mostly matters on UNIX when building - # Python out of the source tree, especially when the - # source tree is read only. - self.tmp_dir = sysconfig.get_config_var('srcdir') - self.tmp_dir = os.path.join(self.tmp_dir, 'build') - else: - self.tmp_dir = tempfile.gettempdir() + # For a partial run, we do not need to clutter the output. + if (self.want_header + or not(self.pgo or self.quiet or self.single_test_run + or tests or self.cmdline_args)): + display_header(self.use_resources, self.python_cmd) - self.tmp_dir = os.path.abspath(self.tmp_dir) + print("Using random seed", self.random_seed) - def is_worker(self): - return (self.ns.worker_args is not None) + runtests = self.create_run_tests(selected) + self.first_runtests = runtests + self.logger.set_tests(runtests) - def create_temp_dir(self): - os.makedirs(self.tmp_dir, exist_ok=True) + setup_process() - # Define a writable temp dir that will be used as cwd while running - # the tests. The name of the dir includes the pid to allow parallel - # testing (see the -j option). - # Emscripten and WASI have stubbed getpid(), Emscripten has only - # milisecond clock resolution. Use randint() instead. - if sys.platform in {"emscripten", "wasi"}: - nounce = random.randint(0, 1_000_000) + if self.hunt_refleak and not self.num_workers: + # gh-109739: WindowsLoadTracker thread interfers with refleak check + use_load_tracker = False else: - nounce = os.getpid() + # WindowsLoadTracker is only needed on Windows + use_load_tracker = MS_WINDOWS - if self.is_worker(): - test_cwd = 'test_python_worker_{}'.format(nounce) - else: - test_cwd = 'test_python_{}'.format(nounce) - test_cwd += os_helper.FS_NONASCII - test_cwd = os.path.join(self.tmp_dir, test_cwd) - return test_cwd - - def cleanup(self): - import glob - - path = os.path.join(glob.escape(self.tmp_dir), 'test_python_*') - print("Cleanup %s directory" % self.tmp_dir) - for name in glob.glob(path): - if os.path.isdir(name): - print("Remove directory: %s" % name) - os_helper.rmtree(name) + if use_load_tracker: + self.logger.start_load_tracker() + try: + if self.num_workers: + self._run_tests_mp(runtests, self.num_workers) + tracer = None else: - print("Remove file: %s" % name) - os_helper.unlink(name) + tracer = self.run_tests_sequentially(runtests) - def main(self, tests=None, **kwargs): - self.parse_args(kwargs) + self.display_result(runtests) - self.set_temp_dir() + if self.want_rerun and self.results.need_rerun(): + self.rerun_failed_tests(runtests) + finally: + if use_load_tracker: + self.logger.stop_load_tracker() - self.fix_umask() + self.display_summary() + self.finalize_tests(tracer) - if self.ns.cleanup: - self.cleanup() - sys.exit(0) + return self.results.get_exitcode(self.fail_env_changed, + self.fail_rerun) - test_cwd = self.create_temp_dir() + def run_tests(self, selected: TestTuple, tests: TestList | None) -> int: + os.makedirs(self.tmp_dir, exist_ok=True) + work_dir = get_work_dir(self.tmp_dir) - try: - # Run the tests in a context manager that temporarily changes the CWD - # to a temporary and writable directory. If it's not possible to - # create or change the CWD, the original CWD will be used. + # Put a timeout on Python exit + with exit_timeout(): + # Run the tests in a context manager that temporarily changes the + # CWD to a temporary and writable directory. If it's not possible + # to create or change the CWD, the original CWD will be used. # The original CWD is available from os_helper.SAVEDCWD. - with os_helper.temp_cwd(test_cwd, quiet=True): - # When using multiprocessing, worker processes will use test_cwd - # as their parent temporary directory. So when the main process - # exit, it removes also subdirectories of worker processes. - self.ns.tempdir = test_cwd + with os_helper.temp_cwd(work_dir, quiet=True): + # When using multiprocessing, worker processes will use + # work_dir as their parent temporary directory. So when the + # main process exit, it removes also subdirectories of worker + # processes. + return self._run_tests(selected, tests) + + def _add_cross_compile_opts(self, regrtest_opts): + # WASM/WASI buildbot builders pass multiple PYTHON environment + # variables such as PYTHONPATH and _PYTHON_HOSTRUNNER. + keep_environ = bool(self.python_cmd) + environ = None + + # Are we using cross-compilation? + cross_compile = is_cross_compiled() + + # Get HOSTRUNNER + hostrunner = get_host_runner() + + if cross_compile: + # emulate -E, but keep PYTHONPATH + cross compile env vars, + # so test executable can load correct sysconfigdata file. + keep = { + '_PYTHON_PROJECT_BASE', + '_PYTHON_HOST_PLATFORM', + '_PYTHON_SYSCONFIGDATA_NAME', + 'PYTHONPATH' + } + old_environ = os.environ + new_environ = { + name: value for name, value in os.environ.items() + if not name.startswith(('PYTHON', '_PYTHON')) or name in keep + } + # Only set environ if at least one variable was removed + if new_environ != old_environ: + environ = new_environ + keep_environ = True + + if cross_compile and hostrunner: + if self.num_workers == 0: + # For now use only two cores for cross-compiled builds; + # hostrunner can be expensive. + regrtest_opts.extend(['-j', '2']) + + # If HOSTRUNNER is set and -p/--python option is not given, then + # use hostrunner to execute python binary for tests. + if not self.python_cmd: + buildpython = sysconfig.get_config_var("BUILDPYTHON") + python_cmd = f"{hostrunner} {buildpython}" + regrtest_opts.extend(["--python", python_cmd]) + keep_environ = True + + return (environ, keep_environ) + + def _add_ci_python_opts(self, python_opts, keep_environ): + # --fast-ci and --slow-ci add options to Python: + # "-u -W default -bb -E" + + # Unbuffered stdout and stderr + if not sys.stdout.write_through: + python_opts.append('-u') + + # Add warnings filter 'default' + if 'default' not in sys.warnoptions: + python_opts.extend(('-W', 'default')) + + # Error on bytes/str comparison + if sys.flags.bytes_warning < 2: + python_opts.append('-bb') + + if not keep_environ: + # Ignore PYTHON* environment variables + if not sys.flags.ignore_environment: + python_opts.append('-E') + + def _execute_python(self, cmd, environ): + # Make sure that messages before execv() are logged + sys.stdout.flush() + sys.stderr.flush() + + cmd_text = shlex.join(cmd) + try: + print(f"+ {cmd_text}", flush=True) - self._main(tests, kwargs) - except SystemExit as exc: - # bpo-38203: Python can hang at exit in Py_Finalize(), especially - # on threading._shutdown() call: put a timeout - if threading_helper.can_start_thread: - faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True) + if hasattr(os, 'execv') and not MS_WINDOWS: + os.execv(cmd[0], cmd) + # On success, execv() do no return. + # On error, it raises an OSError. + else: + import subprocess + with subprocess.Popen(cmd, env=environ) as proc: + try: + proc.wait() + except KeyboardInterrupt: + # There is no need to call proc.terminate(): on CTRL+C, + # SIGTERM is also sent to the child process. + try: + proc.wait(timeout=EXIT_TIMEOUT) + except subprocess.TimeoutExpired: + proc.kill() + proc.wait() + sys.exit(EXITCODE_INTERRUPTED) + + sys.exit(proc.returncode) + except Exception as exc: + print_warning(f"Failed to change Python options: {exc!r}\n" + f"Command: {cmd_text}") + # continue executing main() + + def _add_python_opts(self): + python_opts = [] + regrtest_opts = [] + + environ, keep_environ = self._add_cross_compile_opts(regrtest_opts) + if self.ci_mode: + self._add_ci_python_opts(python_opts, keep_environ) + + if (not python_opts) and (not regrtest_opts) and (environ is None): + # Nothing changed: nothing to do + return - sys.exit(exc.code) + # Create new command line + cmd = list(sys.orig_argv) + if python_opts: + cmd[1:1] = python_opts + if regrtest_opts: + cmd.extend(regrtest_opts) + cmd.append("--dont-add-python-opts") - def getloadavg(self): - if self.win_load_tracker is not None: - return self.win_load_tracker.getloadavg() + self._execute_python(cmd, environ) - if hasattr(os, 'getloadavg'): - return os.getloadavg()[0] + def _init(self): + # Set sys.stdout encoder error handler to backslashreplace, + # similar to sys.stderr error handler, to avoid UnicodeEncodeError + # when printing a traceback or any other non-encodable character. + sys.stdout.reconfigure(errors="backslashreplace") - return None + if self.junit_filename and not os.path.isabs(self.junit_filename): + self.junit_filename = os.path.abspath(self.junit_filename) - def get_exitcode(self): - exitcode = 0 - if self.bad: - exitcode = EXITCODE_BAD_TEST - elif self.interrupted: - exitcode = EXITCODE_INTERRUPTED - elif self.ns.fail_env_changed and self.environment_changed: - exitcode = EXITCODE_ENV_CHANGED - elif self.no_tests_run(): - exitcode = EXITCODE_NO_TESTS_RAN - elif self.rerun and self.ns.fail_rerun: - exitcode = EXITCODE_RERUN_FAIL - return exitcode - - def action_run_tests(self): - self.run_tests() - self.display_result() - - need_rerun = self.need_rerun - if self.ns.rerun and need_rerun: - self.rerun_failed_tests(need_rerun) + strip_py_suffix(self.cmdline_args) - self.display_summary() - self.finalize() + self.tmp_dir = get_temp_dir(self.tmp_dir) - def _main(self, tests, kwargs): - if self.is_worker(): - from test.libregrtest.runtest_mp import run_tests_worker - run_tests_worker(self.ns.worker_args) - return + def main(self, tests: TestList | None = None): + if self.want_add_python_opts: + self._add_python_opts() + + self._init() + + if self.want_cleanup: + cleanup_temp_dir(self.tmp_dir) + sys.exit(0) - if self.ns.wait: + if self.want_wait: input("Press any key to continue...") - setup_tests(self.ns) - self.find_tests(tests) + setup_test_dir(self.test_dir) + selected, tests = self.find_tests(tests) exitcode = 0 - if self.ns.list_tests: - self.list_tests() - elif self.ns.list_cases: - self.list_cases() + if self.want_list_tests: + self.list_tests(selected) + elif self.want_list_cases: + list_cases(selected, + match_tests=self.match_tests, + ignore_tests=self.ignore_tests, + test_dir=self.test_dir) else: - self.action_run_tests() - exitcode = self.get_exitcode() + exitcode = self.run_tests(selected, tests) sys.exit(exitcode) -def main(tests=None, **kwargs): +def main(tests=None, _add_python_opts=False, **kwargs): """Run the Python suite.""" - Regrtest().main(tests=tests, **kwargs) + ns = _parse_args(sys.argv[1:], **kwargs) + Regrtest(ns, _add_python_opts=_add_python_opts).main(tests=tests) diff --git a/Lib/test/libregrtest/pgo.py b/Lib/test/libregrtest/pgo.py index 42ce5fba7a97c3..e3a6927be5db1d 100644 --- a/Lib/test/libregrtest/pgo.py +++ b/Lib/test/libregrtest/pgo.py @@ -42,15 +42,15 @@ 'test_set', 'test_sqlite3', 'test_statistics', + 'test_str', 'test_struct', 'test_tabnanny', 'test_time', - 'test_unicode', 'test_xml_etree', 'test_xml_etree_c', ] -def setup_pgo_tests(ns): - if not ns.args and not ns.pgo_extended: +def setup_pgo_tests(cmdline_args, pgo_extended: bool): + if not cmdline_args and not pgo_extended: # run default set of tests for PGO training - ns.args = PGO_TESTS[:] + cmdline_args[:] = PGO_TESTS[:] diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index 206802b60ddcd0..ada1a65b867ee6 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -1,10 +1,13 @@ -import os import sys import warnings from inspect import isabstract +from typing import Any + from test import support from test.support import os_helper -from test.libregrtest.utils import clear_caches + +from .runtests import HuntRefleak +from .utils import clear_caches try: from _abc import _get_dump @@ -19,7 +22,9 @@ def _get_dump(cls): cls._abc_negative_cache, cls._abc_negative_cache_version) -def dash_R(ns, test_name, test_func): +def runtest_refleak(test_name, test_func, + hunt_refleak: HuntRefleak, + quiet: bool): """Run a test multiple times, looking for reference leaks. Returns: @@ -41,6 +46,7 @@ def dash_R(ns, test_name, test_func): fs = warnings.filters[:] ps = copyreg.dispatch_table.copy() pic = sys.path_importer_cache.copy() + zdc: dict[str, Any] | None try: import zipimport except ImportError: @@ -62,9 +68,10 @@ def dash_R(ns, test_name, test_func): def get_pooled_int(value): return int_pool.setdefault(value, value) - nwarmup, ntracked, fname = ns.huntrleaks - fname = os.path.join(os_helper.SAVEDCWD, fname) - repcount = nwarmup + ntracked + warmups = hunt_refleak.warmups + runs = hunt_refleak.runs + filename = hunt_refleak.filename + repcount = warmups + runs # Pre-allocate to ensure that the loop doesn't allocate anything new rep_range = list(range(repcount)) @@ -78,7 +85,7 @@ def get_pooled_int(value): # initialize variables to make pyflakes quiet rc_before = alloc_before = fd_before = interned_before = 0 - if not ns.quiet: + if not quiet: print("beginning", repcount, "repetitions", file=sys.stderr) print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr, flush=True) @@ -102,7 +109,7 @@ def get_pooled_int(value): rc_after = gettotalrefcount() - interned_after * 2 fd_after = fd_count() - if not ns.quiet: + if not quiet: print('.', end='', file=sys.stderr, flush=True) rc_deltas[i] = get_pooled_int(rc_after - rc_before) @@ -114,7 +121,7 @@ def get_pooled_int(value): fd_before = fd_after interned_before = interned_after - if not ns.quiet: + if not quiet: print(file=sys.stderr) # These checkers return False on success, True on failure @@ -143,12 +150,12 @@ def check_fd_deltas(deltas): (fd_deltas, 'file descriptors', check_fd_deltas) ]: # ignore warmup runs - deltas = deltas[nwarmup:] + deltas = deltas[warmups:] if checker(deltas): msg = '%s leaked %s %s, sum=%s' % ( test_name, deltas, item_name, sum(deltas)) print(msg, file=sys.stderr, flush=True) - with open(fname, "a", encoding="utf-8") as refrep: + with open(filename, "a", encoding="utf-8") as refrep: print(msg, file=refrep) refrep.flush() failed = True diff --git a/Lib/test/libregrtest/result.py b/Lib/test/libregrtest/result.py new file mode 100644 index 00000000000000..d6b0d5ad383a5b --- /dev/null +++ b/Lib/test/libregrtest/result.py @@ -0,0 +1,190 @@ +import dataclasses +import json +from typing import Any + +from test.support import TestStats + +from .utils import ( + StrJSON, TestName, FilterTuple, + format_duration, normalize_test_name, print_warning) + + +# Avoid enum.Enum to reduce the number of imports when tests are run +class State: + PASSED = "PASSED" + FAILED = "FAILED" + SKIPPED = "SKIPPED" + UNCAUGHT_EXC = "UNCAUGHT_EXC" + REFLEAK = "REFLEAK" + ENV_CHANGED = "ENV_CHANGED" + RESOURCE_DENIED = "RESOURCE_DENIED" + INTERRUPTED = "INTERRUPTED" + WORKER_FAILED = "WORKER_FAILED" # non-zero worker process exit code + WORKER_BUG = "WORKER_BUG" # exception when running a worker + DID_NOT_RUN = "DID_NOT_RUN" + TIMEOUT = "TIMEOUT" + + @staticmethod + def is_failed(state): + return state in { + State.FAILED, + State.UNCAUGHT_EXC, + State.REFLEAK, + State.WORKER_FAILED, + State.WORKER_BUG, + State.TIMEOUT} + + @staticmethod + def has_meaningful_duration(state): + # Consider that the duration is meaningless for these cases. + # For example, if a whole test file is skipped, its duration + # is unlikely to be the duration of executing its tests, + # but just the duration to execute code which skips the test. + return state not in { + State.SKIPPED, + State.RESOURCE_DENIED, + State.INTERRUPTED, + State.WORKER_FAILED, + State.WORKER_BUG, + State.DID_NOT_RUN} + + @staticmethod + def must_stop(state): + return state in { + State.INTERRUPTED, + State.WORKER_BUG, + } + + +@dataclasses.dataclass(slots=True) +class TestResult: + test_name: TestName + state: str | None = None + # Test duration in seconds + duration: float | None = None + xml_data: list[str] | None = None + stats: TestStats | None = None + + # errors and failures copied from support.TestFailedWithDetails + errors: list[tuple[str, str]] | None = None + failures: list[tuple[str, str]] | None = None + + def is_failed(self, fail_env_changed: bool) -> bool: + if self.state == State.ENV_CHANGED: + return fail_env_changed + return State.is_failed(self.state) + + def _format_failed(self): + if self.errors and self.failures: + le = len(self.errors) + lf = len(self.failures) + error_s = "error" + ("s" if le > 1 else "") + failure_s = "failure" + ("s" if lf > 1 else "") + return f"{self.test_name} failed ({le} {error_s}, {lf} {failure_s})" + + if self.errors: + le = len(self.errors) + error_s = "error" + ("s" if le > 1 else "") + return f"{self.test_name} failed ({le} {error_s})" + + if self.failures: + lf = len(self.failures) + failure_s = "failure" + ("s" if lf > 1 else "") + return f"{self.test_name} failed ({lf} {failure_s})" + + return f"{self.test_name} failed" + + def __str__(self) -> str: + match self.state: + case State.PASSED: + return f"{self.test_name} passed" + case State.FAILED: + return self._format_failed() + case State.SKIPPED: + return f"{self.test_name} skipped" + case State.UNCAUGHT_EXC: + return f"{self.test_name} failed (uncaught exception)" + case State.REFLEAK: + return f"{self.test_name} failed (reference leak)" + case State.ENV_CHANGED: + return f"{self.test_name} failed (env changed)" + case State.RESOURCE_DENIED: + return f"{self.test_name} skipped (resource denied)" + case State.INTERRUPTED: + return f"{self.test_name} interrupted" + case State.WORKER_FAILED: + return f"{self.test_name} worker non-zero exit code" + case State.WORKER_BUG: + return f"{self.test_name} worker bug" + case State.DID_NOT_RUN: + return f"{self.test_name} ran no tests" + case State.TIMEOUT: + return f"{self.test_name} timed out ({format_duration(self.duration)})" + case _: + raise ValueError("unknown result state: {state!r}") + + def has_meaningful_duration(self): + return State.has_meaningful_duration(self.state) + + def set_env_changed(self): + if self.state is None or self.state == State.PASSED: + self.state = State.ENV_CHANGED + + def must_stop(self, fail_fast: bool, fail_env_changed: bool) -> bool: + if State.must_stop(self.state): + return True + if fail_fast and self.is_failed(fail_env_changed): + return True + return False + + def get_rerun_match_tests(self) -> FilterTuple | None: + match_tests = [] + + errors = self.errors or [] + failures = self.failures or [] + for error_list, is_error in ( + (errors, True), + (failures, False), + ): + for full_name, *_ in error_list: + match_name = normalize_test_name(full_name, is_error=is_error) + if match_name is None: + # 'setUpModule (test.test_sys)': don't filter tests + return None + if not match_name: + error_type = "ERROR" if is_error else "FAIL" + print_warning(f"rerun failed to parse {error_type} test name: " + f"{full_name!r}: don't filter tests") + return None + match_tests.append(match_name) + + if not match_tests: + return None + return tuple(match_tests) + + def write_json_into(self, file) -> None: + json.dump(self, file, cls=_EncodeTestResult) + + @staticmethod + def from_json(worker_json: StrJSON) -> 'TestResult': + return json.loads(worker_json, object_hook=_decode_test_result) + + +class _EncodeTestResult(json.JSONEncoder): + def default(self, o: Any) -> dict[str, Any]: + if isinstance(o, TestResult): + result = dataclasses.asdict(o) + result["__test_result__"] = o.__class__.__name__ + return result + else: + return super().default(o) + + +def _decode_test_result(data: dict[str, Any]) -> TestResult | dict[str, Any]: + if "__test_result__" in data: + data.pop('__test_result__') + if data['stats'] is not None: + data['stats'] = TestStats(**data['stats']) + return TestResult(**data) + else: + return data diff --git a/Lib/test/libregrtest/results.py b/Lib/test/libregrtest/results.py new file mode 100644 index 00000000000000..3708078ff0bf3a --- /dev/null +++ b/Lib/test/libregrtest/results.py @@ -0,0 +1,261 @@ +import sys +from test.support import TestStats + +from .runtests import RunTests +from .result import State, TestResult +from .utils import ( + StrPath, TestName, TestTuple, TestList, FilterDict, + printlist, count, format_duration) + + +# Python uses exit code 1 when an exception is not catched +# argparse.ArgumentParser.error() uses exit code 2 +EXITCODE_BAD_TEST = 2 +EXITCODE_ENV_CHANGED = 3 +EXITCODE_NO_TESTS_RAN = 4 +EXITCODE_RERUN_FAIL = 5 +EXITCODE_INTERRUPTED = 130 # 128 + signal.SIGINT=2 + + +class TestResults: + def __init__(self): + self.bad: TestList = [] + self.good: TestList = [] + self.rerun_bad: TestList = [] + self.skipped: TestList = [] + self.resource_denied: TestList = [] + self.env_changed: TestList = [] + self.run_no_tests: TestList = [] + self.rerun: TestList = [] + self.rerun_results: list[TestResult] = [] + + self.interrupted: bool = False + self.worker_bug: bool = False + self.test_times: list[tuple[float, TestName]] = [] + self.stats = TestStats() + # used by --junit-xml + self.testsuite_xml: list[str] = [] + + def is_all_good(self): + return (not self.bad + and not self.skipped + and not self.interrupted + and not self.worker_bug) + + def get_executed(self): + return (set(self.good) | set(self.bad) | set(self.skipped) + | set(self.resource_denied) | set(self.env_changed) + | set(self.run_no_tests)) + + def no_tests_run(self): + return not any((self.good, self.bad, self.skipped, self.interrupted, + self.env_changed)) + + def get_state(self, fail_env_changed): + state = [] + if self.bad: + state.append("FAILURE") + elif fail_env_changed and self.env_changed: + state.append("ENV CHANGED") + elif self.no_tests_run(): + state.append("NO TESTS RAN") + + if self.interrupted: + state.append("INTERRUPTED") + if self.worker_bug: + state.append("WORKER BUG") + if not state: + state.append("SUCCESS") + + return ', '.join(state) + + def get_exitcode(self, fail_env_changed, fail_rerun): + exitcode = 0 + if self.bad: + exitcode = EXITCODE_BAD_TEST + elif self.interrupted: + exitcode = EXITCODE_INTERRUPTED + elif fail_env_changed and self.env_changed: + exitcode = EXITCODE_ENV_CHANGED + elif self.no_tests_run(): + exitcode = EXITCODE_NO_TESTS_RAN + elif fail_rerun and self.rerun: + exitcode = EXITCODE_RERUN_FAIL + elif self.worker_bug: + exitcode = EXITCODE_BAD_TEST + return exitcode + + def accumulate_result(self, result: TestResult, runtests: RunTests): + test_name = result.test_name + rerun = runtests.rerun + fail_env_changed = runtests.fail_env_changed + + match result.state: + case State.PASSED: + self.good.append(test_name) + case State.ENV_CHANGED: + self.env_changed.append(test_name) + self.rerun_results.append(result) + case State.SKIPPED: + self.skipped.append(test_name) + case State.RESOURCE_DENIED: + self.resource_denied.append(test_name) + case State.INTERRUPTED: + self.interrupted = True + case State.DID_NOT_RUN: + self.run_no_tests.append(test_name) + case _: + if result.is_failed(fail_env_changed): + self.bad.append(test_name) + self.rerun_results.append(result) + else: + raise ValueError(f"invalid test state: {result.state!r}") + + if result.state == State.WORKER_BUG: + self.worker_bug = True + + if result.has_meaningful_duration() and not rerun: + self.test_times.append((result.duration, test_name)) + if result.stats is not None: + self.stats.accumulate(result.stats) + if rerun: + self.rerun.append(test_name) + + xml_data = result.xml_data + if xml_data: + self.add_junit(xml_data) + + def need_rerun(self): + return bool(self.rerun_results) + + def prepare_rerun(self) -> tuple[TestTuple, FilterDict]: + tests: TestList = [] + match_tests_dict = {} + for result in self.rerun_results: + tests.append(result.test_name) + + match_tests = result.get_rerun_match_tests() + # ignore empty match list + if match_tests: + match_tests_dict[result.test_name] = match_tests + + # Clear previously failed tests + self.rerun_bad.extend(self.bad) + self.bad.clear() + self.env_changed.clear() + self.rerun_results.clear() + + return (tuple(tests), match_tests_dict) + + def add_junit(self, xml_data: list[str]): + import xml.etree.ElementTree as ET + for e in xml_data: + try: + self.testsuite_xml.append(ET.fromstring(e)) + except ET.ParseError: + print(xml_data, file=sys.__stderr__) + raise + + def write_junit(self, filename: StrPath): + if not self.testsuite_xml: + # Don't create empty XML file + return + + import xml.etree.ElementTree as ET + root = ET.Element("testsuites") + + # Manually count the totals for the overall summary + totals = {'tests': 0, 'errors': 0, 'failures': 0} + for suite in self.testsuite_xml: + root.append(suite) + for k in totals: + try: + totals[k] += int(suite.get(k, 0)) + except ValueError: + pass + + for k, v in totals.items(): + root.set(k, str(v)) + + with open(filename, 'wb') as f: + for s in ET.tostringlist(root): + f.write(s) + + def display_result(self, tests: TestTuple, quiet: bool, print_slowest: bool): + if print_slowest: + self.test_times.sort(reverse=True) + print() + print("10 slowest tests:") + for test_time, test in self.test_times[:10]: + print("- %s: %s" % (test, format_duration(test_time))) + + all_tests = [] + omitted = set(tests) - self.get_executed() + + # less important + all_tests.append((omitted, "test", "{} omitted:")) + if not quiet: + all_tests.append((self.skipped, "test", "{} skipped:")) + all_tests.append((self.resource_denied, "test", "{} skipped (resource denied):")) + all_tests.append((self.run_no_tests, "test", "{} run no tests:")) + + # more important + all_tests.append((self.env_changed, "test", "{} altered the execution environment (env changed):")) + all_tests.append((self.rerun, "re-run test", "{}:")) + all_tests.append((self.bad, "test", "{} failed:")) + + for tests_list, count_text, title_format in all_tests: + if tests_list: + print() + count_text = count(len(tests_list), count_text) + print(title_format.format(count_text)) + printlist(tests_list) + + if self.good and not quiet: + print() + text = count(len(self.good), "test") + text = f"{text} OK." + if (self.is_all_good() and len(self.good) > 1): + text = f"All {text}" + print(text) + + if self.interrupted: + print() + print("Test suite interrupted by signal SIGINT.") + + def display_summary(self, first_runtests: RunTests, filtered: bool): + # Total tests + stats = self.stats + text = f'run={stats.tests_run:,}' + if filtered: + text = f"{text} (filtered)" + report = [text] + if stats.failures: + report.append(f'failures={stats.failures:,}') + if stats.skipped: + report.append(f'skipped={stats.skipped:,}') + print(f"Total tests: {' '.join(report)}") + + # Total test files + all_tests = [self.good, self.bad, self.rerun, + self.skipped, + self.env_changed, self.run_no_tests] + run = sum(map(len, all_tests)) + text = f'run={run}' + if not first_runtests.forever: + ntest = len(first_runtests.tests) + text = f"{text}/{ntest}" + if filtered: + text = f"{text} (filtered)" + report = [text] + for name, tests in ( + ('failed', self.bad), + ('env_changed', self.env_changed), + ('skipped', self.skipped), + ('resource_denied', self.resource_denied), + ('rerun', self.rerun), + ('run_no_tests', self.run_no_tests), + ): + if tests: + report.append(f'{name}={len(tests)}') + print(f"Total test files: {' '.join(report)}") diff --git a/Lib/test/libregrtest/run_workers.py b/Lib/test/libregrtest/run_workers.py new file mode 100644 index 00000000000000..16f8331abd32f9 --- /dev/null +++ b/Lib/test/libregrtest/run_workers.py @@ -0,0 +1,607 @@ +import contextlib +import dataclasses +import faulthandler +import os.path +import queue +import signal +import subprocess +import sys +import tempfile +import threading +import time +import traceback +from typing import Literal, TextIO + +from test import support +from test.support import os_helper, MS_WINDOWS + +from .logger import Logger +from .result import TestResult, State +from .results import TestResults +from .runtests import RunTests, JsonFile, JsonFileType +from .single import PROGRESS_MIN_TIME +from .utils import ( + StrPath, TestName, + format_duration, print_warning, count, plural, get_signal_name) +from .worker import create_worker_process, USE_PROCESS_GROUP + +if MS_WINDOWS: + import locale + import msvcrt + + + +# Display the running tests if nothing happened last N seconds +PROGRESS_UPDATE = 30.0 # seconds +assert PROGRESS_UPDATE >= PROGRESS_MIN_TIME + +# Kill the main process after 5 minutes. It is supposed to write an update +# every PROGRESS_UPDATE seconds. Tolerate 5 minutes for Python slowest +# buildbot workers. +MAIN_PROCESS_TIMEOUT = 5 * 60.0 +assert MAIN_PROCESS_TIMEOUT >= PROGRESS_UPDATE + +# Time to wait until a worker completes: should be immediate +WAIT_COMPLETED_TIMEOUT = 30.0 # seconds + +# Time to wait a killed process (in seconds) +WAIT_KILLED_TIMEOUT = 60.0 + + +# We do not use a generator so multiple threads can call next(). +class MultiprocessIterator: + + """A thread-safe iterator over tests for multiprocess mode.""" + + def __init__(self, tests_iter): + self.lock = threading.Lock() + self.tests_iter = tests_iter + + def __iter__(self): + return self + + def __next__(self): + with self.lock: + if self.tests_iter is None: + raise StopIteration + return next(self.tests_iter) + + def stop(self): + with self.lock: + self.tests_iter = None + + +@dataclasses.dataclass(slots=True, frozen=True) +class MultiprocessResult: + result: TestResult + # bpo-45410: stderr is written into stdout to keep messages order + worker_stdout: str | None = None + err_msg: str | None = None + + +ExcStr = str +QueueOutput = tuple[Literal[False], MultiprocessResult] | tuple[Literal[True], ExcStr] + + +class ExitThread(Exception): + pass + + +class WorkerError(Exception): + def __init__(self, + test_name: TestName, + err_msg: str | None, + stdout: str | None, + state: str): + result = TestResult(test_name, state=state) + self.mp_result = MultiprocessResult(result, stdout, err_msg) + super().__init__() + + +class WorkerThread(threading.Thread): + def __init__(self, worker_id: int, runner: "RunWorkers") -> None: + super().__init__() + self.worker_id = worker_id + self.runtests = runner.runtests + self.pending = runner.pending + self.output = runner.output + self.timeout = runner.worker_timeout + self.log = runner.log + self.test_name: TestName | None = None + self.start_time: float | None = None + self._popen: subprocess.Popen[str] | None = None + self._killed = False + self._stopped = False + + def __repr__(self) -> str: + info = [f'WorkerThread #{self.worker_id}'] + if self.is_alive(): + info.append("running") + else: + info.append('stopped') + test = self.test_name + if test: + info.append(f'test={test}') + popen = self._popen + if popen is not None: + dt = time.monotonic() - self.start_time + info.extend((f'pid={self._popen.pid}', + f'time={format_duration(dt)}')) + return '<%s>' % ' '.join(info) + + def _kill(self) -> None: + popen = self._popen + if popen is None: + return + + if self._killed: + return + self._killed = True + + if USE_PROCESS_GROUP: + what = f"{self} process group" + else: + what = f"{self} process" + + print(f"Kill {what}", file=sys.stderr, flush=True) + try: + if USE_PROCESS_GROUP: + os.killpg(popen.pid, signal.SIGKILL) + else: + popen.kill() + except ProcessLookupError: + # popen.kill(): the process completed, the WorkerThread thread + # read its exit status, but Popen.send_signal() read the returncode + # just before Popen.wait() set returncode. + pass + except OSError as exc: + print_warning(f"Failed to kill {what}: {exc!r}") + + def stop(self) -> None: + # Method called from a different thread to stop this thread + self._stopped = True + self._kill() + + def _run_process(self, runtests: RunTests, output_fd: int, + tmp_dir: StrPath | None = None) -> int | None: + popen = create_worker_process(runtests, output_fd, tmp_dir) + self._popen = popen + self._killed = False + + try: + if self._stopped: + # If kill() has been called before self._popen is set, + # self._popen is still running. Call again kill() + # to ensure that the process is killed. + self._kill() + raise ExitThread + + try: + # gh-94026: stdout+stderr are written to tempfile + retcode = popen.wait(timeout=self.timeout) + assert retcode is not None + return retcode + except subprocess.TimeoutExpired: + if self._stopped: + # kill() has been called: communicate() fails on reading + # closed stdout + raise ExitThread + + # On timeout, kill the process + self._kill() + + # None means TIMEOUT for the caller + retcode = None + # bpo-38207: Don't attempt to call communicate() again: on it + # can hang until all child processes using stdout + # pipes completes. + except OSError: + if self._stopped: + # kill() has been called: communicate() fails + # on reading closed stdout + raise ExitThread + raise + except: + self._kill() + raise + finally: + self._wait_completed() + self._popen = None + + def create_stdout(self, stack: contextlib.ExitStack) -> TextIO: + """Create stdout temporay file (file descriptor).""" + + if MS_WINDOWS: + # gh-95027: When stdout is not a TTY, Python uses the ANSI code + # page for the sys.stdout encoding. If the main process runs in a + # terminal, sys.stdout uses WindowsConsoleIO with UTF-8 encoding. + encoding = locale.getencoding() + else: + encoding = sys.stdout.encoding + + # gh-94026: Write stdout+stderr to a tempfile as workaround for + # non-blocking pipes on Emscripten with NodeJS. + # gh-109425: Use "backslashreplace" error handler: log corrupted + # stdout+stderr, instead of failing with a UnicodeDecodeError and not + # logging stdout+stderr at all. + stdout_file = tempfile.TemporaryFile('w+', + encoding=encoding, + errors='backslashreplace') + stack.enter_context(stdout_file) + return stdout_file + + def create_json_file(self, stack: contextlib.ExitStack) -> tuple[JsonFile, TextIO | None]: + """Create JSON file.""" + + json_file_use_stdout = self.runtests.json_file_use_stdout() + if json_file_use_stdout: + json_file = JsonFile(None, JsonFileType.STDOUT) + json_tmpfile = None + else: + json_tmpfile = tempfile.TemporaryFile('w+', encoding='utf8') + stack.enter_context(json_tmpfile) + + json_fd = json_tmpfile.fileno() + if MS_WINDOWS: + json_handle = msvcrt.get_osfhandle(json_fd) + json_file = JsonFile(json_handle, + JsonFileType.WINDOWS_HANDLE) + else: + json_file = JsonFile(json_fd, JsonFileType.UNIX_FD) + return (json_file, json_tmpfile) + + def create_worker_runtests(self, test_name: TestName, json_file: JsonFile) -> RunTests: + """Create the worker RunTests.""" + + tests = (test_name,) + if self.runtests.rerun: + match_tests = self.runtests.get_match_tests(test_name) + else: + match_tests = None + + kwargs = {} + if match_tests: + kwargs['match_tests'] = match_tests + if self.runtests.output_on_failure: + kwargs['verbose'] = True + kwargs['output_on_failure'] = False + return self.runtests.copy( + tests=tests, + json_file=json_file, + **kwargs) + + def run_tmp_files(self, worker_runtests: RunTests, + stdout_fd: int) -> tuple[int | None, list[StrPath]]: + # gh-93353: Check for leaked temporary files in the parent process, + # since the deletion of temporary files can happen late during + # Python finalization: too late for libregrtest. + if not support.is_wasi: + # Don't check for leaked temporary files and directories if Python is + # run on WASI. WASI don't pass environment variables like TMPDIR to + # worker processes. + tmp_dir = tempfile.mkdtemp(prefix="test_python_") + tmp_dir = os.path.abspath(tmp_dir) + try: + retcode = self._run_process(worker_runtests, + stdout_fd, tmp_dir) + finally: + tmp_files = os.listdir(tmp_dir) + os_helper.rmtree(tmp_dir) + else: + retcode = self._run_process(worker_runtests, stdout_fd) + tmp_files = [] + + return (retcode, tmp_files) + + def read_stdout(self, stdout_file: TextIO) -> str: + stdout_file.seek(0) + try: + return stdout_file.read().strip() + except Exception as exc: + # gh-101634: Catch UnicodeDecodeError if stdout cannot be + # decoded from encoding + raise WorkerError(self.test_name, + f"Cannot read process stdout: {exc}", + stdout=None, + state=State.WORKER_BUG) + + def read_json(self, json_file: JsonFile, json_tmpfile: TextIO | None, + stdout: str) -> tuple[TestResult, str]: + try: + if json_tmpfile is not None: + json_tmpfile.seek(0) + worker_json = json_tmpfile.read() + elif json_file.file_type == JsonFileType.STDOUT: + stdout, _, worker_json = stdout.rpartition("\n") + stdout = stdout.rstrip() + else: + with json_file.open(encoding='utf8') as json_fp: + worker_json = json_fp.read() + except Exception as exc: + # gh-101634: Catch UnicodeDecodeError if stdout cannot be + # decoded from encoding + err_msg = f"Failed to read worker process JSON: {exc}" + raise WorkerError(self.test_name, err_msg, stdout, + state=State.WORKER_BUG) + + if not worker_json: + raise WorkerError(self.test_name, "empty JSON", stdout, + state=State.WORKER_BUG) + + try: + result = TestResult.from_json(worker_json) + except Exception as exc: + # gh-101634: Catch UnicodeDecodeError if stdout cannot be + # decoded from encoding + err_msg = f"Failed to parse worker process JSON: {exc}" + raise WorkerError(self.test_name, err_msg, stdout, + state=State.WORKER_BUG) + + return (result, stdout) + + def _runtest(self, test_name: TestName) -> MultiprocessResult: + with contextlib.ExitStack() as stack: + stdout_file = self.create_stdout(stack) + json_file, json_tmpfile = self.create_json_file(stack) + worker_runtests = self.create_worker_runtests(test_name, json_file) + + retcode, tmp_files = self.run_tmp_files(worker_runtests, + stdout_file.fileno()) + + stdout = self.read_stdout(stdout_file) + + if retcode is None: + raise WorkerError(self.test_name, stdout=stdout, + err_msg=None, + state=State.TIMEOUT) + if retcode != 0: + name = get_signal_name(retcode) + if name: + retcode = f"{retcode} ({name})" + raise WorkerError(self.test_name, f"Exit code {retcode}", stdout, + state=State.WORKER_FAILED) + + result, stdout = self.read_json(json_file, json_tmpfile, stdout) + + if tmp_files: + msg = (f'\n\n' + f'Warning -- {test_name} leaked temporary files ' + f'({len(tmp_files)}): {", ".join(sorted(tmp_files))}') + stdout += msg + result.set_env_changed() + + return MultiprocessResult(result, stdout) + + def run(self) -> None: + fail_fast = self.runtests.fail_fast + fail_env_changed = self.runtests.fail_env_changed + while not self._stopped: + try: + try: + test_name = next(self.pending) + except StopIteration: + break + + self.start_time = time.monotonic() + self.test_name = test_name + try: + mp_result = self._runtest(test_name) + except WorkerError as exc: + mp_result = exc.mp_result + finally: + self.test_name = None + mp_result.result.duration = time.monotonic() - self.start_time + self.output.put((False, mp_result)) + + if mp_result.result.must_stop(fail_fast, fail_env_changed): + break + except ExitThread: + break + except BaseException: + self.output.put((True, traceback.format_exc())) + break + + def _wait_completed(self) -> None: + popen = self._popen + + try: + popen.wait(WAIT_COMPLETED_TIMEOUT) + except (subprocess.TimeoutExpired, OSError) as exc: + print_warning(f"Failed to wait for {self} completion " + f"(timeout={format_duration(WAIT_COMPLETED_TIMEOUT)}): " + f"{exc!r}") + + def wait_stopped(self, start_time: float) -> None: + # bpo-38207: RunWorkers.stop_workers() called self.stop() + # which killed the process. Sometimes, killing the process from the + # main thread does not interrupt popen.communicate() in + # WorkerThread thread. This loop with a timeout is a workaround + # for that. + # + # Moreover, if this method fails to join the thread, it is likely + # that Python will hang at exit while calling threading._shutdown() + # which tries again to join the blocked thread. Regrtest.main() + # uses EXIT_TIMEOUT to workaround this second bug. + while True: + # Write a message every second + self.join(1.0) + if not self.is_alive(): + break + dt = time.monotonic() - start_time + self.log(f"Waiting for {self} thread for {format_duration(dt)}") + if dt > WAIT_KILLED_TIMEOUT: + print_warning(f"Failed to join {self} in {format_duration(dt)}") + break + + +def get_running(workers: list[WorkerThread]) -> str | None: + running: list[str] = [] + for worker in workers: + test_name = worker.test_name + if not test_name: + continue + dt = time.monotonic() - worker.start_time + if dt >= PROGRESS_MIN_TIME: + text = f'{test_name} ({format_duration(dt)})' + running.append(text) + if not running: + return None + return f"running ({len(running)}): {', '.join(running)}" + + +class RunWorkers: + def __init__(self, num_workers: int, runtests: RunTests, + logger: Logger, results: TestResults) -> None: + self.num_workers = num_workers + self.runtests = runtests + self.log = logger.log + self.display_progress = logger.display_progress + self.results: TestResults = results + + self.output: queue.Queue[QueueOutput] = queue.Queue() + tests_iter = runtests.iter_tests() + self.pending = MultiprocessIterator(tests_iter) + self.timeout = runtests.timeout + if self.timeout is not None: + # Rely on faulthandler to kill a worker process. This timouet is + # when faulthandler fails to kill a worker process. Give a maximum + # of 5 minutes to faulthandler to kill the worker. + self.worker_timeout: float | None = min(self.timeout * 1.5, self.timeout + 5 * 60) + else: + self.worker_timeout = None + self.workers: list[WorkerThread] | None = None + + jobs = self.runtests.get_jobs() + if jobs is not None: + # Don't spawn more threads than the number of jobs: + # these worker threads would never get anything to do. + self.num_workers = min(self.num_workers, jobs) + + def start_workers(self) -> None: + self.workers = [WorkerThread(index, self) + for index in range(1, self.num_workers + 1)] + jobs = self.runtests.get_jobs() + if jobs is not None: + tests = count(jobs, 'test') + else: + tests = 'tests' + nworkers = len(self.workers) + processes = plural(nworkers, "process", "processes") + msg = (f"Run {tests} in parallel using " + f"{nworkers} worker {processes}") + if self.timeout: + msg += (" (timeout: %s, worker timeout: %s)" + % (format_duration(self.timeout), + format_duration(self.worker_timeout))) + self.log(msg) + for worker in self.workers: + worker.start() + + def stop_workers(self) -> None: + start_time = time.monotonic() + for worker in self.workers: + worker.stop() + for worker in self.workers: + worker.wait_stopped(start_time) + + def _get_result(self) -> QueueOutput | None: + pgo = self.runtests.pgo + use_faulthandler = (self.timeout is not None) + + # bpo-46205: check the status of workers every iteration to avoid + # waiting forever on an empty queue. + while any(worker.is_alive() for worker in self.workers): + if use_faulthandler: + faulthandler.dump_traceback_later(MAIN_PROCESS_TIMEOUT, + exit=True) + + # wait for a thread + try: + return self.output.get(timeout=PROGRESS_UPDATE) + except queue.Empty: + pass + + if not pgo: + # display progress + running = get_running(self.workers) + if running: + self.log(running) + + # all worker threads are done: consume pending results + try: + return self.output.get(timeout=0) + except queue.Empty: + return None + + def display_result(self, mp_result: MultiprocessResult) -> None: + result = mp_result.result + pgo = self.runtests.pgo + + text = str(result) + if mp_result.err_msg: + # WORKER_BUG + text += ' (%s)' % mp_result.err_msg + elif (result.duration >= PROGRESS_MIN_TIME and not pgo): + text += ' (%s)' % format_duration(result.duration) + if not pgo: + running = get_running(self.workers) + if running: + text += f' -- {running}' + self.display_progress(self.test_index, text) + + def _process_result(self, item: QueueOutput) -> TestResult: + """Returns True if test runner must stop.""" + if item[0]: + # Thread got an exception + format_exc = item[1] + print_warning(f"regrtest worker thread failed: {format_exc}") + result = TestResult("", state=State.WORKER_BUG) + self.results.accumulate_result(result, self.runtests) + return result + + self.test_index += 1 + mp_result = item[1] + result = mp_result.result + self.results.accumulate_result(result, self.runtests) + self.display_result(mp_result) + + # Display worker stdout + if not self.runtests.output_on_failure: + show_stdout = True + else: + # --verbose3 ignores stdout on success + show_stdout = (result.state != State.PASSED) + if show_stdout: + stdout = mp_result.worker_stdout + if stdout: + print(stdout, flush=True) + + return result + + def run(self) -> None: + fail_fast = self.runtests.fail_fast + fail_env_changed = self.runtests.fail_env_changed + + self.start_workers() + + self.test_index = 0 + try: + while True: + item = self._get_result() + if item is None: + break + + result = self._process_result(item) + if result.must_stop(fail_fast, fail_env_changed): + break + except KeyboardInterrupt: + print() + self.results.interrupted = True + finally: + if self.timeout is not None: + faulthandler.cancel_dump_traceback_later() + + # Always ensure that all worker processes are no longer + # worker when we exit this function + self.pending.stop() + self.stop_workers() diff --git a/Lib/test/libregrtest/runtests.py b/Lib/test/libregrtest/runtests.py new file mode 100644 index 00000000000000..4da312db4cb02e --- /dev/null +++ b/Lib/test/libregrtest/runtests.py @@ -0,0 +1,162 @@ +import contextlib +import dataclasses +import json +import os +import subprocess +from typing import Any + +from test import support + +from .utils import ( + StrPath, StrJSON, TestTuple, FilterTuple, FilterDict) + + +class JsonFileType: + UNIX_FD = "UNIX_FD" + WINDOWS_HANDLE = "WINDOWS_HANDLE" + STDOUT = "STDOUT" + + +@dataclasses.dataclass(slots=True, frozen=True) +class JsonFile: + # file type depends on file_type: + # - UNIX_FD: file descriptor (int) + # - WINDOWS_HANDLE: handle (int) + # - STDOUT: use process stdout (None) + file: int | None + file_type: str + + def configure_subprocess(self, popen_kwargs: dict) -> None: + match self.file_type: + case JsonFileType.UNIX_FD: + # Unix file descriptor + popen_kwargs['pass_fds'] = [self.file] + case JsonFileType.WINDOWS_HANDLE: + # Windows handle + startupinfo = subprocess.STARTUPINFO() + startupinfo.lpAttributeList = {"handle_list": [self.file]} + popen_kwargs['startupinfo'] = startupinfo + + @contextlib.contextmanager + def inherit_subprocess(self): + if self.file_type == JsonFileType.WINDOWS_HANDLE: + os.set_handle_inheritable(self.file, True) + try: + yield + finally: + os.set_handle_inheritable(self.file, False) + else: + yield + + def open(self, mode='r', *, encoding): + if self.file_type == JsonFileType.STDOUT: + raise ValueError("for STDOUT file type, just use sys.stdout") + + file = self.file + if self.file_type == JsonFileType.WINDOWS_HANDLE: + import msvcrt + # Create a file descriptor from the handle + file = msvcrt.open_osfhandle(file, os.O_WRONLY) + return open(file, mode, encoding=encoding) + + +@dataclasses.dataclass(slots=True, frozen=True) +class HuntRefleak: + warmups: int + runs: int + filename: StrPath + + +@dataclasses.dataclass(slots=True, frozen=True) +class RunTests: + tests: TestTuple + fail_fast: bool + fail_env_changed: bool + match_tests: FilterTuple | None + ignore_tests: FilterTuple | None + match_tests_dict: FilterDict | None + rerun: bool + forever: bool + pgo: bool + pgo_extended: bool + output_on_failure: bool + timeout: float | None + verbose: int + quiet: bool + hunt_refleak: HuntRefleak | None + test_dir: StrPath | None + use_junit: bool + memory_limit: str | None + gc_threshold: int | None + use_resources: tuple[str, ...] + python_cmd: tuple[str, ...] | None + randomize: bool + random_seed: int | None + json_file: JsonFile | None + + def copy(self, **override): + state = dataclasses.asdict(self) + state.update(override) + return RunTests(**state) + + def get_match_tests(self, test_name) -> FilterTuple | None: + if self.match_tests_dict is not None: + return self.match_tests_dict.get(test_name, None) + else: + return None + + def get_jobs(self): + # Number of run_single_test() calls needed to run all tests. + # None means that there is not bound limit (--forever option). + if self.forever: + return None + return len(self.tests) + + def iter_tests(self): + if self.forever: + while True: + yield from self.tests + else: + yield from self.tests + + def as_json(self) -> StrJSON: + return json.dumps(self, cls=_EncodeRunTests) + + @staticmethod + def from_json(worker_json: StrJSON) -> 'RunTests': + return json.loads(worker_json, object_hook=_decode_runtests) + + def json_file_use_stdout(self) -> bool: + # Use STDOUT in two cases: + # + # - If --python command line option is used; + # - On Emscripten and WASI. + # + # On other platforms, UNIX_FD or WINDOWS_HANDLE can be used. + return ( + bool(self.python_cmd) + or support.is_emscripten + or support.is_wasi + ) + + +class _EncodeRunTests(json.JSONEncoder): + def default(self, o: Any) -> dict[str, Any]: + if isinstance(o, RunTests): + result = dataclasses.asdict(o) + result["__runtests__"] = True + return result + else: + return super().default(o) + + +def _decode_runtests(data: dict[str, Any]) -> RunTests | dict[str, Any]: + if "__runtests__" in data: + data.pop('__runtests__') + if data['hunt_refleak']: + data['hunt_refleak'] = HuntRefleak(**data['hunt_refleak']) + if data['json_file']: + data['json_file'] = JsonFile(**data['json_file']) + return RunTests(**data) + else: + return data diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py index 164fe9806b5f0d..b2cc381344b2ef 100644 --- a/Lib/test/libregrtest/save_env.py +++ b/Lib/test/libregrtest/save_env.py @@ -3,9 +3,11 @@ import os import sys import threading + from test import support from test.support import os_helper -from test.libregrtest.utils import print_warning + +from .utils import print_warning class SkipTestEnvironment(Exception): @@ -34,7 +36,7 @@ class saved_test_environment: items is also printed. """ - def __init__(self, test_name, verbose=0, quiet=False, *, pgo=False): + def __init__(self, test_name, verbose, quiet, *, pgo): self.test_name = test_name self.verbose = verbose self.quiet = quiet diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index ec021668553fb4..793347f60ad93c 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -1,24 +1,32 @@ -import atexit import faulthandler +import gc import os +import random import signal import sys import unittest from test import support from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII -try: - import gc -except ImportError: - gc = None -from test.libregrtest.utils import (setup_unraisable_hook, - setup_threading_excepthook) +from .runtests import RunTests +from .utils import ( + setup_unraisable_hook, setup_threading_excepthook, fix_umask, + adjust_rlimit_nofile) UNICODE_GUARD_ENV = "PYTHONREGRTEST_UNICODE_GUARD" -def setup_tests(ns): +def setup_test_dir(testdir: str | None) -> None: + if testdir: + # Prepend test directory to sys.path, so runtest() will be able + # to locate tests + sys.path.insert(0, os.path.abspath(testdir)) + + +def setup_process(): + fix_umask() + try: stderr_fd = sys.__stderr__.fileno() except (ValueError, AttributeError): @@ -40,14 +48,9 @@ def setup_tests(ns): for signum in signals: faulthandler.register(signum, chain=True, file=stderr_fd) - _adjust_resource_limits() - replace_stdout() - support.record_original_stdout(sys.stdout) + adjust_rlimit_nofile() - if ns.testdir: - # Prepend test directory to sys.path, so runtest() will be able - # to locate tests - sys.path.insert(0, os.path.abspath(ns.testdir)) + support.record_original_stdout(sys.stdout) # Some times __path__ and __file__ are not absolute (e.g. while running from # Lib/) and, if we change the CWD to run the tests in a temporary dir, some @@ -66,19 +69,6 @@ def setup_tests(ns): if getattr(module, '__file__', None): module.__file__ = os.path.abspath(module.__file__) - if ns.huntrleaks: - unittest.BaseTestSuite._cleanup = False - - if ns.memlimit is not None: - support.set_memlimit(ns.memlimit) - - if ns.threshold is not None: - gc.set_threshold(ns.threshold) - - support.suppress_msvcrt_asserts(ns.verbose and ns.verbose >= 2) - - support.use_resources = ns.use_resources - if hasattr(sys, 'addaudithook'): # Add an auditing hook for all tests to ensure PySys_Audit is tested def _test_audit_hook(name, args): @@ -88,7 +78,37 @@ def _test_audit_hook(name, args): setup_unraisable_hook() setup_threading_excepthook() - timeout = ns.timeout + # Ensure there's a non-ASCII character in env vars at all times to force + # tests consider this case. See BPO-44647 for details. + if TESTFN_UNDECODABLE and os.supports_bytes_environ: + os.environb.setdefault(UNICODE_GUARD_ENV.encode(), TESTFN_UNDECODABLE) + elif FS_NONASCII: + os.environ.setdefault(UNICODE_GUARD_ENV, FS_NONASCII) + + +def setup_tests(runtests: RunTests): + support.verbose = runtests.verbose + support.failfast = runtests.fail_fast + support.PGO = runtests.pgo + support.PGO_EXTENDED = runtests.pgo_extended + + support.set_match_tests(runtests.match_tests, runtests.ignore_tests) + + if runtests.use_junit: + support.junit_xml_list = [] + from test.support.testresult import RegressionTestResult + RegressionTestResult.USE_XML = True + else: + support.junit_xml_list = None + + if runtests.memory_limit is not None: + support.set_memlimit(runtests.memory_limit) + + support.suppress_msvcrt_asserts(runtests.verbose >= 2) + + support.use_resources = runtests.use_resources + + timeout = runtests.timeout if timeout is not None: # For a slow buildbot worker, increase SHORT_TIMEOUT and LONG_TIMEOUT support.LOOPBACK_TIMEOUT = max(support.LOOPBACK_TIMEOUT, timeout / 120) @@ -102,61 +122,10 @@ def _test_audit_hook(name, args): support.SHORT_TIMEOUT = min(support.SHORT_TIMEOUT, timeout) support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, timeout) - if ns.xmlpath: - from test.support.testresult import RegressionTestResult - RegressionTestResult.USE_XML = True - - # Ensure there's a non-ASCII character in env vars at all times to force - # tests consider this case. See BPO-44647 for details. - if TESTFN_UNDECODABLE and os.supports_bytes_environ: - os.environb.setdefault(UNICODE_GUARD_ENV.encode(), TESTFN_UNDECODABLE) - elif FS_NONASCII: - os.environ.setdefault(UNICODE_GUARD_ENV, FS_NONASCII) - - -def replace_stdout(): - """Set stdout encoder error handler to backslashreplace (as stderr error - handler) to avoid UnicodeEncodeError when printing a traceback""" - stdout = sys.stdout - try: - fd = stdout.fileno() - except ValueError: - # On IDLE, sys.stdout has no file descriptor and is not a TextIOWrapper - # object. Leaving sys.stdout unchanged. - # - # Catch ValueError to catch io.UnsupportedOperation on TextIOBase - # and ValueError on a closed stream. - return - - sys.stdout = open(fd, 'w', - encoding=stdout.encoding, - errors="backslashreplace", - closefd=False, - newline='\n') - - def restore_stdout(): - sys.stdout.close() - sys.stdout = stdout - atexit.register(restore_stdout) + if runtests.hunt_refleak: + unittest.BaseTestSuite._cleanup = False + if runtests.gc_threshold is not None: + gc.set_threshold(runtests.gc_threshold) -def _adjust_resource_limits(): - """Adjust the system resource limits (ulimit) if needed.""" - try: - import resource - from resource import RLIMIT_NOFILE - except ImportError: - return - fd_limit, max_fds = resource.getrlimit(RLIMIT_NOFILE) - # On macOS the default fd limit is sometimes too low (256) for our - # test suite to succeed. Raise it to something more reasonable. - # 1024 is a common Linux default. - desired_fds = 1024 - if fd_limit < desired_fds and fd_limit < max_fds: - new_fd_limit = min(desired_fds, max_fds) - try: - resource.setrlimit(RLIMIT_NOFILE, (new_fd_limit, max_fds)) - print(f"Raised RLIMIT_NOFILE: {fd_limit} -> {new_fd_limit}") - except (ValueError, OSError) as err: - print(f"Unable to raise RLIMIT_NOFILE from {fd_limit} to " - f"{new_fd_limit}: {err}.") + random.seed(runtests.random_seed) diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py new file mode 100644 index 00000000000000..0304f858edf42c --- /dev/null +++ b/Lib/test/libregrtest/single.py @@ -0,0 +1,278 @@ +import doctest +import faulthandler +import gc +import importlib +import io +import sys +import time +import traceback +import unittest + +from test import support +from test.support import TestStats +from test.support import threading_helper + +from .result import State, TestResult +from .runtests import RunTests +from .save_env import saved_test_environment +from .setup import setup_tests +from .utils import ( + TestName, + clear_caches, remove_testfn, abs_module_name, print_warning) + + +# Minimum duration of a test to display its duration or to mention that +# the test is running in background +PROGRESS_MIN_TIME = 30.0 # seconds + + +def run_unittest(test_mod): + loader = unittest.TestLoader() + tests = loader.loadTestsFromModule(test_mod) + for error in loader.errors: + print(error, file=sys.stderr) + if loader.errors: + raise Exception("errors while loading tests") + return support.run_unittest(tests) + + +def regrtest_runner(result: TestResult, test_func, runtests: RunTests) -> None: + # Run test_func(), collect statistics, and detect reference and memory + # leaks. + if runtests.hunt_refleak: + from .refleak import runtest_refleak + refleak, test_result = runtest_refleak(result.test_name, test_func, + runtests.hunt_refleak, + runtests.quiet) + else: + test_result = test_func() + refleak = False + + if refleak: + result.state = State.REFLEAK + + stats: TestStats | None + + match test_result: + case TestStats(): + stats = test_result + case unittest.TestResult(): + stats = TestStats.from_unittest(test_result) + case doctest.TestResults(): + stats = TestStats.from_doctest(test_result) + case None: + print_warning(f"{result.test_name} test runner returned None: {test_func}") + stats = None + case _: + print_warning(f"Unknown test result type: {type(test_result)}") + stats = None + + result.stats = stats + + +# Storage of uncollectable GC objects (gc.garbage) +GC_GARBAGE = [] + + +def _load_run_test(result: TestResult, runtests: RunTests) -> None: + # Load the test module and run the tests. + test_name = result.test_name + module_name = abs_module_name(test_name, runtests.test_dir) + + # Remove the module from sys.module to reload it if it was already imported + sys.modules.pop(module_name, None) + + test_mod = importlib.import_module(module_name) + + if hasattr(test_mod, "test_main"): + # https://github.com/python/cpython/issues/89392 + raise Exception(f"Module {test_name} defines test_main() which " + f"is no longer supported by regrtest") + def test_func(): + return run_unittest(test_mod) + + try: + regrtest_runner(result, test_func, runtests) + finally: + # First kill any dangling references to open files etc. + # This can also issue some ResourceWarnings which would otherwise get + # triggered during the following test run, and possibly produce + # failures. + support.gc_collect() + + remove_testfn(test_name, runtests.verbose) + + if gc.garbage: + support.environment_altered = True + print_warning(f"{test_name} created {len(gc.garbage)} " + f"uncollectable object(s)") + + # move the uncollectable objects somewhere, + # so we don't see them again + GC_GARBAGE.extend(gc.garbage) + gc.garbage.clear() + + support.reap_children() + + +def _runtest_env_changed_exc(result: TestResult, runtests: RunTests, + display_failure: bool = True) -> None: + # Handle exceptions, detect environment changes. + + # Reset the environment_altered flag to detect if a test altered + # the environment + support.environment_altered = False + + pgo = runtests.pgo + if pgo: + display_failure = False + quiet = runtests.quiet + + test_name = result.test_name + try: + clear_caches() + support.gc_collect() + + with saved_test_environment(test_name, + runtests.verbose, quiet, pgo=pgo): + _load_run_test(result, runtests) + except support.ResourceDenied as exc: + if not quiet and not pgo: + print(f"{test_name} skipped -- {exc}", flush=True) + result.state = State.RESOURCE_DENIED + return + except unittest.SkipTest as exc: + if not quiet and not pgo: + print(f"{test_name} skipped -- {exc}", flush=True) + result.state = State.SKIPPED + return + except support.TestFailedWithDetails as exc: + msg = f"test {test_name} failed" + if display_failure: + msg = f"{msg} -- {exc}" + print(msg, file=sys.stderr, flush=True) + result.state = State.FAILED + result.errors = exc.errors + result.failures = exc.failures + result.stats = exc.stats + return + except support.TestFailed as exc: + msg = f"test {test_name} failed" + if display_failure: + msg = f"{msg} -- {exc}" + print(msg, file=sys.stderr, flush=True) + result.state = State.FAILED + result.stats = exc.stats + return + except support.TestDidNotRun: + result.state = State.DID_NOT_RUN + return + except KeyboardInterrupt: + print() + result.state = State.INTERRUPTED + return + except: + if not pgo: + msg = traceback.format_exc() + print(f"test {test_name} crashed -- {msg}", + file=sys.stderr, flush=True) + result.state = State.UNCAUGHT_EXC + return + + if support.environment_altered: + result.set_env_changed() + # Don't override the state if it was already set (REFLEAK or ENV_CHANGED) + if result.state is None: + result.state = State.PASSED + + +def _runtest(result: TestResult, runtests: RunTests) -> None: + # Capture stdout and stderr, set faulthandler timeout, + # and create JUnit XML report. + verbose = runtests.verbose + output_on_failure = runtests.output_on_failure + timeout = runtests.timeout + + use_timeout = ( + timeout is not None and threading_helper.can_start_thread + ) + if use_timeout: + faulthandler.dump_traceback_later(timeout, exit=True) + + try: + setup_tests(runtests) + + if output_on_failure: + support.verbose = True + + stream = io.StringIO() + orig_stdout = sys.stdout + orig_stderr = sys.stderr + print_warning = support.print_warning + orig_print_warnings_stderr = print_warning.orig_stderr + + output = None + try: + sys.stdout = stream + sys.stderr = stream + # print_warning() writes into the temporary stream to preserve + # messages order. If support.environment_altered becomes true, + # warnings will be written to sys.stderr below. + print_warning.orig_stderr = stream + + _runtest_env_changed_exc(result, runtests, display_failure=False) + # Ignore output if the test passed successfully + if result.state != State.PASSED: + output = stream.getvalue() + finally: + sys.stdout = orig_stdout + sys.stderr = orig_stderr + print_warning.orig_stderr = orig_print_warnings_stderr + + if output is not None: + sys.stderr.write(output) + sys.stderr.flush() + else: + # Tell tests to be moderately quiet + support.verbose = verbose + _runtest_env_changed_exc(result, runtests, + display_failure=not verbose) + + xml_list = support.junit_xml_list + if xml_list: + import xml.etree.ElementTree as ET + result.xml_data = [ET.tostring(x).decode('us-ascii') + for x in xml_list] + finally: + if use_timeout: + faulthandler.cancel_dump_traceback_later() + support.junit_xml_list = None + + +def run_single_test(test_name: TestName, runtests: RunTests) -> TestResult: + """Run a single test. + + test_name -- the name of the test + + Returns a TestResult. + + If runtests.use_junit, xml_data is a list containing each generated + testsuite element. + """ + start_time = time.perf_counter() + result = TestResult(test_name) + pgo = runtests.pgo + try: + _runtest(result, runtests) + except: + if not pgo: + msg = traceback.format_exc() + print(f"test {test_name} crashed -- {msg}", + file=sys.stderr, flush=True) + result.state = State.UNCAUGHT_EXC + + sys.stdout.flush() + sys.stderr.flush() + + result.duration = time.perf_counter() - start_time + return result diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index 28acb531f4d93e..86192ed9084f40 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -1,9 +1,59 @@ +import contextlib +import faulthandler +import locale import math import os.path +import platform +import random +import shlex +import signal +import subprocess import sys import sysconfig +import tempfile import textwrap +from collections.abc import Callable + from test import support +from test.support import os_helper +from test.support import threading_helper + + +# All temporary files and temporary directories created by libregrtest should +# use TMP_PREFIX so cleanup_temp_dir() can remove them all. +TMP_PREFIX = 'test_python_' +WORK_DIR_PREFIX = TMP_PREFIX +WORKER_WORK_DIR_PREFIX = WORK_DIR_PREFIX + 'worker_' + +# bpo-38203: Maximum delay in seconds to exit Python (call Py_Finalize()). +# Used to protect against threading._shutdown() hang. +# Must be smaller than buildbot "1200 seconds without output" limit. +EXIT_TIMEOUT = 120.0 + + +ALL_RESOURCES = ('audio', 'curses', 'largefile', 'network', + 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'walltime') + +# Other resources excluded from --use=all: +# +# - extralagefile (ex: test_zipfile64): really too slow to be enabled +# "by default" +# - tzdata: while needed to validate fully test_datetime, it makes +# test_datetime too slow (15-20 min on some buildbots) and so is disabled by +# default (see bpo-30822). +RESOURCE_NAMES = ALL_RESOURCES + ('extralargefile', 'tzdata') + + +# Types for types hints +StrPath = str +TestName = str +StrJSON = str +TestTuple = tuple[TestName, ...] +TestList = list[TestName] +# --match and --ignore options: list of patterns +# ('*' joker character can be used) +FilterTuple = tuple[TestName, ...] +FilterDict = dict[TestName, FilterTuple] def format_duration(seconds): @@ -31,7 +81,7 @@ def format_duration(seconds): return ' '.join(parts) -def strip_py_suffix(names: list[str]): +def strip_py_suffix(names: list[str] | None) -> None: if not names: return for idx, name in enumerate(names): @@ -40,11 +90,20 @@ def strip_py_suffix(names: list[str]): names[idx] = basename +def plural(n, singular, plural=None): + if n == 1: + return singular + elif plural is not None: + return plural + else: + return singular + 's' + + def count(n, word): if n == 1: - return "%d %s" % (n, word) + return f"{n} {word}" else: - return "%d %ss" % (n, word) + return f"{n} {word}s" def printlist(x, width=70, indent=4, file=None): @@ -228,6 +287,11 @@ def get_build_info(): ldflags_nodist = sysconfig.get_config_var('PY_LDFLAGS_NODIST') or '' build = [] + + # --disable-gil + if sysconfig.get_config_var('Py_NOGIL'): + build.append("nogil") + if hasattr(sys, 'gettotalrefcount'): # --with-pydebug build.append('debug') @@ -292,3 +356,331 @@ def get_build_info(): build.append("dtrace") return build + + +def get_temp_dir(tmp_dir: StrPath | None = None) -> StrPath: + if tmp_dir: + tmp_dir = os.path.expanduser(tmp_dir) + else: + # When tests are run from the Python build directory, it is best practice + # to keep the test files in a subfolder. This eases the cleanup of leftover + # files using the "make distclean" command. + if sysconfig.is_python_build(): + if not support.is_wasi: + tmp_dir = sysconfig.get_config_var('abs_builddir') + if tmp_dir is None: + tmp_dir = sysconfig.get_config_var('abs_srcdir') + if not tmp_dir: + # gh-74470: On Windows, only srcdir is available. Using + # abs_builddir mostly matters on UNIX when building + # Python out of the source tree, especially when the + # source tree is read only. + tmp_dir = sysconfig.get_config_var('srcdir') + tmp_dir = os.path.join(tmp_dir, 'build') + else: + # WASI platform + tmp_dir = sysconfig.get_config_var('projectbase') + tmp_dir = os.path.join(tmp_dir, 'build') + + # When get_temp_dir() is called in a worker process, + # get_temp_dir() path is different than in the parent process + # which is not a WASI process. So the parent does not create + # the same "tmp_dir" than the test worker process. + os.makedirs(tmp_dir, exist_ok=True) + else: + tmp_dir = tempfile.gettempdir() + + return os.path.abspath(tmp_dir) + + +def fix_umask(): + if support.is_emscripten: + # Emscripten has default umask 0o777, which breaks some tests. + # see https://github.com/emscripten-core/emscripten/issues/17269 + old_mask = os.umask(0) + if old_mask == 0o777: + os.umask(0o027) + else: + os.umask(old_mask) + + +def get_work_dir(parent_dir: StrPath, worker: bool = False) -> StrPath: + # Define a writable temp dir that will be used as cwd while running + # the tests. The name of the dir includes the pid to allow parallel + # testing (see the -j option). + # Emscripten and WASI have stubbed getpid(), Emscripten has only + # milisecond clock resolution. Use randint() instead. + if support.is_emscripten or support.is_wasi: + nounce = random.randint(0, 1_000_000) + else: + nounce = os.getpid() + + if worker: + work_dir = WORK_DIR_PREFIX + str(nounce) + else: + work_dir = WORKER_WORK_DIR_PREFIX + str(nounce) + work_dir += os_helper.FS_NONASCII + work_dir = os.path.join(parent_dir, work_dir) + return work_dir + + +@contextlib.contextmanager +def exit_timeout(): + try: + yield + except SystemExit as exc: + # bpo-38203: Python can hang at exit in Py_Finalize(), especially + # on threading._shutdown() call: put a timeout + if threading_helper.can_start_thread: + faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True) + sys.exit(exc.code) + + +def remove_testfn(test_name: TestName, verbose: int) -> None: + # Try to clean up os_helper.TESTFN if left behind. + # + # While tests shouldn't leave any files or directories behind, when a test + # fails that can be tedious for it to arrange. The consequences can be + # especially nasty on Windows, since if a test leaves a file open, it + # cannot be deleted by name (while there's nothing we can do about that + # here either, we can display the name of the offending test, which is a + # real help). + name = os_helper.TESTFN + if not os.path.exists(name): + return + + nuker: Callable[[str], None] + if os.path.isdir(name): + import shutil + kind, nuker = "directory", shutil.rmtree + elif os.path.isfile(name): + kind, nuker = "file", os.unlink + else: + raise RuntimeError(f"os.path says {name!r} exists but is neither " + f"directory nor file") + + if verbose: + print_warning(f"{test_name} left behind {kind} {name!r}") + support.environment_altered = True + + try: + import stat + # fix possible permissions problems that might prevent cleanup + os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + nuker(name) + except Exception as exc: + print_warning(f"{test_name} left behind {kind} {name!r} " + f"and it couldn't be removed: {exc}") + + +def abs_module_name(test_name: TestName, test_dir: StrPath | None) -> TestName: + if test_name.startswith('test.') or test_dir: + return test_name + else: + # Import it from the test package + return 'test.' + test_name + + +# gh-90681: When rerunning tests, we might need to rerun the whole +# class or module suite if some its life-cycle hooks fail. +# Test level hooks are not affected. +_TEST_LIFECYCLE_HOOKS = frozenset(( + 'setUpClass', 'tearDownClass', + 'setUpModule', 'tearDownModule', +)) + +def normalize_test_name(test_full_name, *, is_error=False): + short_name = test_full_name.split(" ")[0] + if is_error and short_name in _TEST_LIFECYCLE_HOOKS: + if test_full_name.startswith(('setUpModule (', 'tearDownModule (')): + # if setUpModule() or tearDownModule() failed, don't filter + # tests with the test file name, don't use use filters. + return None + + # This means that we have a failure in a life-cycle hook, + # we need to rerun the whole module or class suite. + # Basically the error looks like this: + # ERROR: setUpClass (test.test_reg_ex.RegTest) + # or + # ERROR: setUpModule (test.test_reg_ex) + # So, we need to parse the class / module name. + lpar = test_full_name.index('(') + rpar = test_full_name.index(')') + return test_full_name[lpar + 1: rpar].split('.')[-1] + return short_name + + +def adjust_rlimit_nofile(): + """ + On macOS the default fd limit (RLIMIT_NOFILE) is sometimes too low (256) + for our test suite to succeed. Raise it to something more reasonable. 1024 + is a common Linux default. + """ + try: + import resource + except ImportError: + return + + fd_limit, max_fds = resource.getrlimit(resource.RLIMIT_NOFILE) + + desired_fds = 1024 + + if fd_limit < desired_fds and fd_limit < max_fds: + new_fd_limit = min(desired_fds, max_fds) + try: + resource.setrlimit(resource.RLIMIT_NOFILE, + (new_fd_limit, max_fds)) + print(f"Raised RLIMIT_NOFILE: {fd_limit} -> {new_fd_limit}") + except (ValueError, OSError) as err: + print_warning(f"Unable to raise RLIMIT_NOFILE from {fd_limit} to " + f"{new_fd_limit}: {err}.") + + +def get_host_runner(): + if (hostrunner := os.environ.get("_PYTHON_HOSTRUNNER")) is None: + hostrunner = sysconfig.get_config_var("HOSTRUNNER") + return hostrunner + + +def is_cross_compiled(): + return ('_PYTHON_HOST_PLATFORM' in os.environ) + + +def format_resources(use_resources: tuple[str, ...]): + use_resources = set(use_resources) + all_resources = set(ALL_RESOURCES) + + # Express resources relative to "all" + relative_all = ['all'] + for name in sorted(all_resources - use_resources): + relative_all.append(f'-{name}') + for name in sorted(use_resources - all_resources): + relative_all.append(f'{name}') + all_text = ','.join(relative_all) + all_text = f"resources: {all_text}" + + # List of enabled resources + text = ','.join(sorted(use_resources)) + text = f"resources ({len(use_resources)}): {text}" + + # Pick the shortest string (prefer relative to all if lengths are equal) + if len(all_text) <= len(text): + return all_text + else: + return text + + +def process_cpu_count(): + if hasattr(os, 'sched_getaffinity'): + return len(os.sched_getaffinity(0)) + else: + return os.cpu_count() + + +def display_header(use_resources: tuple[str, ...], + python_cmd: tuple[str, ...] | None): + # Print basic platform information + print("==", platform.python_implementation(), *sys.version.split()) + print("==", platform.platform(aliased=True), + "%s-endian" % sys.byteorder) + print("== Python build:", ' '.join(get_build_info())) + print("== cwd:", os.getcwd()) + + cpu_count = os.cpu_count() + if cpu_count: + affinity = process_cpu_count() + if affinity and affinity != cpu_count: + cpu_count = f"{affinity} (process) / {cpu_count} (system)" + print("== CPU count:", cpu_count) + print("== encodings: locale=%s FS=%s" + % (locale.getencoding(), sys.getfilesystemencoding())) + + if use_resources: + text = format_resources(use_resources) + print(f"== {text}") + else: + print("== resources: all test resources are disabled, " + "use -u option to unskip tests") + + cross_compile = is_cross_compiled() + if cross_compile: + print("== cross compiled: Yes") + if python_cmd: + cmd = shlex.join(python_cmd) + print(f"== host python: {cmd}") + + get_cmd = [*python_cmd, '-m', 'platform'] + proc = subprocess.run( + get_cmd, + stdout=subprocess.PIPE, + text=True, + cwd=os_helper.SAVEDCWD) + stdout = proc.stdout.replace('\n', ' ').strip() + if stdout: + print(f"== host platform: {stdout}") + elif proc.returncode: + print(f"== host platform: ") + else: + hostrunner = get_host_runner() + if hostrunner: + print(f"== host runner: {hostrunner}") + + # This makes it easier to remember what to set in your local + # environment when trying to reproduce a sanitizer failure. + asan = support.check_sanitizer(address=True) + msan = support.check_sanitizer(memory=True) + ubsan = support.check_sanitizer(ub=True) + sanitizers = [] + if asan: + sanitizers.append("address") + if msan: + sanitizers.append("memory") + if ubsan: + sanitizers.append("undefined behavior") + if sanitizers: + print(f"== sanitizers: {', '.join(sanitizers)}") + for sanitizer, env_var in ( + (asan, "ASAN_OPTIONS"), + (msan, "MSAN_OPTIONS"), + (ubsan, "UBSAN_OPTIONS"), + ): + options= os.environ.get(env_var) + if sanitizer and options is not None: + print(f"== {env_var}={options!r}") + + print(flush=True) + + +def cleanup_temp_dir(tmp_dir: StrPath): + import glob + + path = os.path.join(glob.escape(tmp_dir), TMP_PREFIX + '*') + print("Cleanup %s directory" % tmp_dir) + for name in glob.glob(path): + if os.path.isdir(name): + print("Remove directory: %s" % name) + os_helper.rmtree(name) + else: + print("Remove file: %s" % name) + os_helper.unlink(name) + +WINDOWS_STATUS = { + 0xC0000005: "STATUS_ACCESS_VIOLATION", + 0xC00000FD: "STATUS_STACK_OVERFLOW", + 0xC000013A: "STATUS_CONTROL_C_EXIT", +} + +def get_signal_name(exitcode): + if exitcode < 0: + signum = -exitcode + try: + return signal.Signals(signum).name + except ValueError: + pass + + try: + return WINDOWS_STATUS[exitcode] + except KeyError: + pass + + return None diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py new file mode 100644 index 00000000000000..a9c8be0bb65d08 --- /dev/null +++ b/Lib/test/libregrtest/worker.py @@ -0,0 +1,116 @@ +import subprocess +import sys +import os +from typing import Any, NoReturn + +from test import support +from test.support import os_helper + +from .setup import setup_process, setup_test_dir +from .runtests import RunTests, JsonFile, JsonFileType +from .single import run_single_test +from .utils import ( + StrPath, StrJSON, FilterTuple, + get_temp_dir, get_work_dir, exit_timeout) + + +USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg")) + + +def create_worker_process(runtests: RunTests, output_fd: int, + tmp_dir: StrPath | None = None) -> subprocess.Popen: + python_cmd = runtests.python_cmd + worker_json = runtests.as_json() + + python_opts = support.args_from_interpreter_flags() + if python_cmd is not None: + executable = python_cmd + # Remove -E option, since --python=COMMAND can set PYTHON environment + # variables, such as PYTHONPATH, in the worker process. + python_opts = [opt for opt in python_opts if opt != "-E"] + else: + executable = (sys.executable,) + cmd = [*executable, *python_opts, + '-u', # Unbuffered stdout and stderr + '-m', 'test.libregrtest.worker', + worker_json] + + env = dict(os.environ) + if tmp_dir is not None: + env['TMPDIR'] = tmp_dir + env['TEMP'] = tmp_dir + env['TMP'] = tmp_dir + + # Running the child from the same working directory as regrtest's original + # invocation ensures that TEMPDIR for the child is the same when + # sysconfig.is_python_build() is true. See issue 15300. + # + # Emscripten and WASI Python must start in the Python source code directory + # to get 'python.js' or 'python.wasm' file. Then worker_process() changes + # to a temporary directory created to run tests. + work_dir = os_helper.SAVEDCWD + + kwargs: dict[str, Any] = dict( + env=env, + stdout=output_fd, + # bpo-45410: Write stderr into stdout to keep messages order + stderr=output_fd, + text=True, + close_fds=True, + cwd=work_dir, + ) + if USE_PROCESS_GROUP: + kwargs['start_new_session'] = True + + # Pass json_file to the worker process + json_file = runtests.json_file + json_file.configure_subprocess(kwargs) + + with json_file.inherit_subprocess(): + return subprocess.Popen(cmd, **kwargs) + + +def worker_process(worker_json: StrJSON) -> NoReturn: + runtests = RunTests.from_json(worker_json) + test_name = runtests.tests[0] + match_tests: FilterTuple | None = runtests.match_tests + json_file: JsonFile = runtests.json_file + + setup_test_dir(runtests.test_dir) + setup_process() + + if runtests.rerun: + if match_tests: + matching = "matching: " + ", ".join(match_tests) + print(f"Re-running {test_name} in verbose mode ({matching})", flush=True) + else: + print(f"Re-running {test_name} in verbose mode", flush=True) + + result = run_single_test(test_name, runtests) + + if json_file.file_type == JsonFileType.STDOUT: + print() + result.write_json_into(sys.stdout) + else: + with json_file.open('w', encoding='utf-8') as json_fp: + result.write_json_into(json_fp) + + sys.exit(0) + + +def main(): + if len(sys.argv) != 2: + print("usage: python -m test.libregrtest.worker JSON") + sys.exit(1) + worker_json = sys.argv[1] + + tmp_dir = get_temp_dir() + work_dir = get_work_dir(tmp_dir, worker=True) + + with exit_timeout(): + with os_helper.temp_cwd(work_dir, quiet=True): + worker_process(worker_json) + + +if __name__ == "__main__": + main() diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py index c0b21124499df0..4f3ebb12ed957d 100644 --- a/Lib/test/pythoninfo.py +++ b/Lib/test/pythoninfo.py @@ -1,18 +1,13 @@ """ Collect various information about Python to help debugging test failures. """ -from __future__ import print_function import errno import re import sys import traceback -import unittest import warnings -MS_WINDOWS = (sys.platform == 'win32') - - def normalize_text(text): if text is None: return None @@ -244,6 +239,7 @@ def format_attr(attr, value): 'getresgid', 'getresuid', 'getuid', + 'process_cpu_count', 'uname', ): call_func(info_add, 'os.%s' % func, os, func) @@ -273,6 +269,7 @@ def format_groups(groups): "ARCHFLAGS", "ARFLAGS", "AUDIODEV", + "BUILDPYTHON", "CC", "CFLAGS", "COLUMNS", @@ -317,7 +314,6 @@ def format_groups(groups): "TEMP", "TERM", "TILE_LIBRARY", - "TIX_LIBRARY", "TMP", "TMPDIR", "TRAVIS", @@ -326,15 +322,24 @@ def format_groups(groups): "VIRTUAL_ENV", "WAYLAND_DISPLAY", "WINDIR", + "_PYTHON_HOSTRUNNER", "_PYTHON_HOST_PLATFORM", "_PYTHON_PROJECT_BASE", "_PYTHON_SYSCONFIGDATA_NAME", "__PYVENV_LAUNCHER__", + + # Sanitizer options + "ASAN_OPTIONS", + "LSAN_OPTIONS", + "MSAN_OPTIONS", + "TSAN_OPTIONS", + "UBSAN_OPTIONS", )) for name, value in os.environ.items(): uname = name.upper() if (uname in ENV_VARS - # Copy PYTHON* and LC_* variables + # Copy PYTHON* variables like PYTHONPATH + # Copy LC_* variables like LC_ALL or uname.startswith(("PYTHON", "LC_")) # Visual Studio: VS140COMNTOOLS or (uname.startswith("VS") and uname.endswith("COMNTOOLS"))): @@ -487,13 +492,10 @@ def collect_datetime(info_add): def collect_sysconfig(info_add): - # On Windows, sysconfig is not reliable to get macros used - # to build Python - if MS_WINDOWS: - return - import sysconfig + info_add('sysconfig.is_python_build', sysconfig.is_python_build()) + for name in ( 'ABIFLAGS', 'ANDROID_API_LEVEL', @@ -502,6 +504,7 @@ def collect_sysconfig(info_add): 'CFLAGS', 'CFLAGSFORSHARED', 'CONFIG_ARGS', + 'HOSTRUNNER', 'HOST_GNU_TYPE', 'MACHDEP', 'MULTIARCH', @@ -514,11 +517,13 @@ def collect_sysconfig(info_add): 'PY_STDMODULE_CFLAGS', 'Py_DEBUG', 'Py_ENABLE_SHARED', + 'Py_NOGIL', 'SHELL', 'SOABI', 'abs_builddir', 'abs_srcdir', 'prefix', + 'srcdir', ): value = sysconfig.get_config_var(name) if name == 'ANDROID_API_LEVEL' and not value: @@ -665,7 +670,29 @@ def collect_testcapi(info_add): except ImportError: return - call_func(info_add, 'pymem.allocator', _testcapi, 'pymem_getallocatorsname') + for name in ( + 'LONG_MAX', # always 32-bit on Windows, 64-bit on 64-bit Unix + 'PY_SSIZE_T_MAX', + 'Py_C_RECURSION_LIMIT', + 'SIZEOF_TIME_T', # 32-bit or 64-bit depending on the platform + 'SIZEOF_WCHAR_T', # 16-bit or 32-bit depending on the platform + ): + copy_attr(info_add, f'_testcapi.{name}', _testcapi, name) + + +def collect_testinternalcapi(info_add): + try: + import _testinternalcapi + except ImportError: + return + + call_func(info_add, 'pymem.allocator', _testinternalcapi, 'pymem_getallocatorsname') + + for name in ( + 'SIZEOF_PYGC_HEAD', + 'SIZEOF_PYOBJECT', + ): + copy_attr(info_add, f'_testinternalcapi.{name}', _testinternalcapi, name) def collect_resource(info_add): @@ -684,6 +711,7 @@ def collect_resource(info_add): def collect_test_socket(info_add): + import unittest try: from test import test_socket except (ImportError, unittest.SkipTest): @@ -695,15 +723,12 @@ def collect_test_socket(info_add): copy_attributes(info_add, test_socket, 'test_socket.%s', attributes) -def collect_test_support(info_add): +def collect_support(info_add): try: from test import support except ImportError: return - attributes = ('IPV6_ENABLED',) - copy_attributes(info_add, support, 'test_support.%s', attributes) - attributes = ( 'MS_WINDOWS', 'has_fork_support', @@ -717,17 +742,64 @@ def collect_test_support(info_add): ) copy_attributes(info_add, support, 'support.%s', attributes) - call_func(info_add, 'test_support._is_gui_available', support, '_is_gui_available') - call_func(info_add, 'test_support.python_is_optimized', support, 'python_is_optimized') + call_func(info_add, 'support._is_gui_available', support, '_is_gui_available') + call_func(info_add, 'support.python_is_optimized', support, 'python_is_optimized') - info_add('test_support.check_sanitizer(address=True)', + info_add('support.check_sanitizer(address=True)', support.check_sanitizer(address=True)) - info_add('test_support.check_sanitizer(memory=True)', + info_add('support.check_sanitizer(memory=True)', support.check_sanitizer(memory=True)) - info_add('test_support.check_sanitizer(ub=True)', + info_add('support.check_sanitizer(ub=True)', support.check_sanitizer(ub=True)) +def collect_support_os_helper(info_add): + try: + from test.support import os_helper + except ImportError: + return + + for name in ( + 'can_symlink', + 'can_xattr', + 'can_chmod', + 'can_dac_override', + ): + func = getattr(os_helper, name) + info_add(f'support_os_helper.{name}', func()) + + +def collect_support_socket_helper(info_add): + try: + from test.support import socket_helper + except ImportError: + return + + attributes = ( + 'IPV6_ENABLED', + 'has_gethostname', + ) + copy_attributes(info_add, socket_helper, 'support_socket_helper.%s', attributes) + + for name in ( + 'tcp_blackhole', + ): + func = getattr(socket_helper, name) + info_add(f'support_socket_helper.{name}', func()) + + +def collect_support_threading_helper(info_add): + try: + from test.support import threading_helper + except ImportError: + return + + attributes = ( + 'can_start_thread', + ) + copy_attributes(info_add, threading_helper, 'support_threading_helper.%s', attributes) + + def collect_cc(info_add): import subprocess import sysconfig @@ -882,6 +954,12 @@ def collect_fips(info_add): pass +def collect_tempfile(info_add): + import tempfile + + info_add('tempfile.gettempdir', tempfile.gettempdir()) + + def collect_libregrtest_utils(info_add): try: from test.libregrtest import utils @@ -924,6 +1002,8 @@ def collect_info(info): collect_sys, collect_sysconfig, collect_testcapi, + collect_testinternalcapi, + collect_tempfile, collect_time, collect_tkinter, collect_windows, @@ -932,7 +1012,10 @@ def collect_info(info): # Collecting from tests should be last as they have side effects. collect_test_socket, - collect_test_support, + collect_support, + collect_support_os_helper, + collect_support_socket_helper, + collect_support_threading_helper, ): try: collect_func(info_add) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 0ffb3ed454eda0..46a74fe276f553 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -8,7 +8,7 @@ import os import sys -from test.libregrtest import main +from test.libregrtest.main import main # Alias for backward compatibility (just in case) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 9d69ade251dcae..37fd9443e18007 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -433,6 +433,14 @@ def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False): HAVE_ASAN_FORK_BUG = check_sanitizer(address=True) +def set_sanitizer_env_var(env, option): + for name in ('ASAN_OPTIONS', 'MSAN_OPTIONS', 'UBSAN_OPTIONS'): + if name in env: + env[name] += f':{option}' + else: + env[name] = option + + def system_must_validate_cert(f): """Skip the test on TLS certificate validation failures.""" @functools.wraps(f) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 67ebc554cddb7c..d0473500a17735 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -8,7 +8,6 @@ import sys from test import support from test.support import os_helper, script_helper, is_android, MS_WINDOWS -from test.support import skip_if_sanitizer import tempfile import unittest from textwrap import dedent @@ -34,7 +33,7 @@ def expected_traceback(lineno1, lineno2, header, min_count=1): return '^' + regex + '$' def skip_segfault_on_android(test): - # Issue #32138: Raising SIGSEGV on Android may not cause a crash. + # gh-76319: Raising SIGSEGV on Android may not cause a crash. return unittest.skipIf(is_android, 'raising SIGSEGV on Android is unreliable')(test) @@ -62,8 +61,16 @@ def get_output(self, code, filename=None, fd=None): pass_fds = [] if fd is not None: pass_fds.append(fd) + env = dict(os.environ) + + # Sanitizers must not handle SIGSEGV (ex: for test_enable_fd()) + option = 'handle_segv=0' + support.set_sanitizer_env_var(env, option) + with support.SuppressCrashReport(): - process = script_helper.spawn_python('-c', code, pass_fds=pass_fds) + process = script_helper.spawn_python('-c', code, + pass_fds=pass_fds, + env=env) with process: output, stderr = process.communicate() exitcode = process.wait() @@ -302,8 +309,6 @@ def test_gil_released(self): 3, 'Segmentation fault') - @skip_if_sanitizer(memory=True, ub=True, reason="sanitizer " - "builds change crashing process output.") @skip_segfault_on_android def test_enable_file(self): with temporary_filename() as filename: @@ -319,8 +324,6 @@ def test_enable_file(self): @unittest.skipIf(sys.platform == "win32", "subprocess doesn't support pass_fds on Windows") - @skip_if_sanitizer(memory=True, ub=True, reason="sanitizer " - "builds change crashing process output.") @skip_segfault_on_android def test_enable_fd(self): with tempfile.TemporaryFile('wb+') as fp: diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index a72c052cb83e0d..45573a2719c543 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -11,18 +11,23 @@ import locale import os.path import platform +import random import re +import shlex +import signal import subprocess import sys import sysconfig import tempfile import textwrap import unittest -from test import libregrtest from test import support from test.support import os_helper, TestStats -from test.libregrtest import utils, setup -from test.libregrtest.runtest import normalize_test_name +from test.libregrtest import cmdline +from test.libregrtest import main +from test.libregrtest import setup +from test.libregrtest import utils +from test.libregrtest.utils import normalize_test_name if not support.has_subprocess_support: raise unittest.SkipTest("test module requires subprocess") @@ -52,9 +57,13 @@ class ParseArgsTestCase(unittest.TestCase): Test regrtest's argument parsing, function _parse_args(). """ + @staticmethod + def parse_args(args): + return cmdline._parse_args(args) + def checkError(self, args, msg): with support.captured_stderr() as err, self.assertRaises(SystemExit): - libregrtest._parse_args(args) + self.parse_args(args) self.assertIn(msg, err.getvalue()) def test_help(self): @@ -62,83 +71,93 @@ def test_help(self): with self.subTest(opt=opt): with support.captured_stdout() as out, \ self.assertRaises(SystemExit): - libregrtest._parse_args([opt]) + self.parse_args([opt]) self.assertIn('Run Python regression tests.', out.getvalue()) def test_timeout(self): - ns = libregrtest._parse_args(['--timeout', '4.2']) + ns = self.parse_args(['--timeout', '4.2']) self.assertEqual(ns.timeout, 4.2) + + # negative, zero and empty string are treated as "no timeout" + for value in ('-1', '0', ''): + with self.subTest(value=value): + ns = self.parse_args([f'--timeout={value}']) + self.assertEqual(ns.timeout, None) + self.checkError(['--timeout'], 'expected one argument') - self.checkError(['--timeout', 'foo'], 'invalid float value') + self.checkError(['--timeout', 'foo'], 'invalid timeout value:') def test_wait(self): - ns = libregrtest._parse_args(['--wait']) + ns = self.parse_args(['--wait']) self.assertTrue(ns.wait) - def test_worker_args(self): - ns = libregrtest._parse_args(['--worker-args', '[[], {}]']) - self.assertEqual(ns.worker_args, '[[], {}]') - self.checkError(['--worker-args'], 'expected one argument') - def test_start(self): for opt in '-S', '--start': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, 'foo']) + ns = self.parse_args([opt, 'foo']) self.assertEqual(ns.start, 'foo') self.checkError([opt], 'expected one argument') def test_verbose(self): - ns = libregrtest._parse_args(['-v']) + ns = self.parse_args(['-v']) self.assertEqual(ns.verbose, 1) - ns = libregrtest._parse_args(['-vvv']) + ns = self.parse_args(['-vvv']) self.assertEqual(ns.verbose, 3) - ns = libregrtest._parse_args(['--verbose']) + ns = self.parse_args(['--verbose']) self.assertEqual(ns.verbose, 1) - ns = libregrtest._parse_args(['--verbose'] * 3) + ns = self.parse_args(['--verbose'] * 3) self.assertEqual(ns.verbose, 3) - ns = libregrtest._parse_args([]) + ns = self.parse_args([]) self.assertEqual(ns.verbose, 0) def test_rerun(self): for opt in '-w', '--rerun', '--verbose2': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.rerun) def test_verbose3(self): for opt in '-W', '--verbose3': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.verbose3) def test_quiet(self): for opt in '-q', '--quiet': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.quiet) self.assertEqual(ns.verbose, 0) def test_slowest(self): for opt in '-o', '--slowest': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.print_slow) def test_header(self): - ns = libregrtest._parse_args(['--header']) + ns = self.parse_args(['--header']) self.assertTrue(ns.header) - ns = libregrtest._parse_args(['--verbose']) + ns = self.parse_args(['--verbose']) self.assertTrue(ns.header) def test_randomize(self): for opt in '-r', '--randomize': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.randomize) + with os_helper.EnvironmentVarGuard() as env: + env['SOURCE_DATE_EPOCH'] = '1' + + ns = self.parse_args(['--randomize']) + regrtest = main.Regrtest(ns) + self.assertFalse(regrtest.randomize) + self.assertIsNone(regrtest.random_seed) + def test_randseed(self): - ns = libregrtest._parse_args(['--randseed', '12345']) + ns = self.parse_args(['--randseed', '12345']) self.assertEqual(ns.random_seed, 12345) self.assertTrue(ns.randomize) self.checkError(['--randseed'], 'expected one argument') @@ -147,7 +166,7 @@ def test_randseed(self): def test_fromfile(self): for opt in '-f', '--fromfile': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, 'foo']) + ns = self.parse_args([opt, 'foo']) self.assertEqual(ns.fromfile, 'foo') self.checkError([opt], 'expected one argument') self.checkError([opt, 'foo', '-s'], "don't go together") @@ -155,20 +174,20 @@ def test_fromfile(self): def test_exclude(self): for opt in '-x', '--exclude': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.exclude) def test_single(self): for opt in '-s', '--single': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.single) self.checkError([opt, '-f', 'foo'], "don't go together") def test_ignore(self): for opt in '-i', '--ignore': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, 'pattern']) + ns = self.parse_args([opt, 'pattern']) self.assertEqual(ns.ignore_tests, ['pattern']) self.checkError([opt], 'expected one argument') @@ -178,7 +197,7 @@ def test_ignore(self): print('matchfile2', file=fp) filename = os.path.abspath(os_helper.TESTFN) - ns = libregrtest._parse_args(['-m', 'match', + ns = self.parse_args(['-m', 'match', '--ignorefile', filename]) self.assertEqual(ns.ignore_tests, ['matchfile1', 'matchfile2']) @@ -186,11 +205,11 @@ def test_ignore(self): def test_match(self): for opt in '-m', '--match': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, 'pattern']) + ns = self.parse_args([opt, 'pattern']) self.assertEqual(ns.match_tests, ['pattern']) self.checkError([opt], 'expected one argument') - ns = libregrtest._parse_args(['-m', 'pattern1', + ns = self.parse_args(['-m', 'pattern1', '-m', 'pattern2']) self.assertEqual(ns.match_tests, ['pattern1', 'pattern2']) @@ -200,7 +219,7 @@ def test_match(self): print('matchfile2', file=fp) filename = os.path.abspath(os_helper.TESTFN) - ns = libregrtest._parse_args(['-m', 'match', + ns = self.parse_args(['-m', 'match', '--matchfile', filename]) self.assertEqual(ns.match_tests, ['match', 'matchfile1', 'matchfile2']) @@ -208,65 +227,65 @@ def test_match(self): def test_failfast(self): for opt in '-G', '--failfast': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, '-v']) + ns = self.parse_args([opt, '-v']) self.assertTrue(ns.failfast) - ns = libregrtest._parse_args([opt, '-W']) + ns = self.parse_args([opt, '-W']) self.assertTrue(ns.failfast) self.checkError([opt], '-G/--failfast needs either -v or -W') def test_use(self): for opt in '-u', '--use': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, 'gui,network']) + ns = self.parse_args([opt, 'gui,network']) self.assertEqual(ns.use_resources, ['gui', 'network']) - ns = libregrtest._parse_args([opt, 'gui,none,network']) + ns = self.parse_args([opt, 'gui,none,network']) self.assertEqual(ns.use_resources, ['network']) - expected = list(libregrtest.ALL_RESOURCES) + expected = list(cmdline.ALL_RESOURCES) expected.remove('gui') - ns = libregrtest._parse_args([opt, 'all,-gui']) + ns = self.parse_args([opt, 'all,-gui']) self.assertEqual(ns.use_resources, expected) self.checkError([opt], 'expected one argument') self.checkError([opt, 'foo'], 'invalid resource') # all + a resource not part of "all" - ns = libregrtest._parse_args([opt, 'all,tzdata']) + ns = self.parse_args([opt, 'all,tzdata']) self.assertEqual(ns.use_resources, - list(libregrtest.ALL_RESOURCES) + ['tzdata']) + list(cmdline.ALL_RESOURCES) + ['tzdata']) # test another resource which is not part of "all" - ns = libregrtest._parse_args([opt, 'extralargefile']) + ns = self.parse_args([opt, 'extralargefile']) self.assertEqual(ns.use_resources, ['extralargefile']) def test_memlimit(self): for opt in '-M', '--memlimit': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, '4G']) + ns = self.parse_args([opt, '4G']) self.assertEqual(ns.memlimit, '4G') self.checkError([opt], 'expected one argument') def test_testdir(self): - ns = libregrtest._parse_args(['--testdir', 'foo']) + ns = self.parse_args(['--testdir', 'foo']) self.assertEqual(ns.testdir, os.path.join(os_helper.SAVEDCWD, 'foo')) self.checkError(['--testdir'], 'expected one argument') def test_runleaks(self): for opt in '-L', '--runleaks': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.runleaks) def test_huntrleaks(self): for opt in '-R', '--huntrleaks': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, ':']) + ns = self.parse_args([opt, ':']) self.assertEqual(ns.huntrleaks, (5, 4, 'reflog.txt')) - ns = libregrtest._parse_args([opt, '6:']) + ns = self.parse_args([opt, '6:']) self.assertEqual(ns.huntrleaks, (6, 4, 'reflog.txt')) - ns = libregrtest._parse_args([opt, ':3']) + ns = self.parse_args([opt, ':3']) self.assertEqual(ns.huntrleaks, (5, 3, 'reflog.txt')) - ns = libregrtest._parse_args([opt, '6:3:leaks.log']) + ns = self.parse_args([opt, '6:3:leaks.log']) self.assertEqual(ns.huntrleaks, (6, 3, 'leaks.log')) self.checkError([opt], 'expected one argument') self.checkError([opt, '6'], @@ -277,7 +296,7 @@ def test_huntrleaks(self): def test_multiprocess(self): for opt in '-j', '--multiprocess': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, '2']) + ns = self.parse_args([opt, '2']) self.assertEqual(ns.use_mp, 2) self.checkError([opt], 'expected one argument') self.checkError([opt, 'foo'], 'invalid int value') @@ -287,13 +306,13 @@ def test_multiprocess(self): def test_coverage(self): for opt in '-T', '--coverage': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.trace) def test_coverdir(self): for opt in '-D', '--coverdir': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, 'foo']) + ns = self.parse_args([opt, 'foo']) self.assertEqual(ns.coverdir, os.path.join(os_helper.SAVEDCWD, 'foo')) self.checkError([opt], 'expected one argument') @@ -301,13 +320,13 @@ def test_coverdir(self): def test_nocoverdir(self): for opt in '-N', '--nocoverdir': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertIsNone(ns.coverdir) def test_threshold(self): for opt in '-t', '--threshold': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt, '1000']) + ns = self.parse_args([opt, '1000']) self.assertEqual(ns.threshold, 1000) self.checkError([opt], 'expected one argument') self.checkError([opt, 'foo'], 'invalid int value') @@ -316,7 +335,7 @@ def test_nowindows(self): for opt in '-n', '--nowindows': with self.subTest(opt=opt): with contextlib.redirect_stderr(io.StringIO()) as stderr: - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.nowindows) err = stderr.getvalue() self.assertIn('the --nowindows (-n) option is deprecated', err) @@ -324,39 +343,39 @@ def test_nowindows(self): def test_forever(self): for opt in '-F', '--forever': with self.subTest(opt=opt): - ns = libregrtest._parse_args([opt]) + ns = self.parse_args([opt]) self.assertTrue(ns.forever) def test_unrecognized_argument(self): self.checkError(['--xxx'], 'usage:') def test_long_option__partial(self): - ns = libregrtest._parse_args(['--qui']) + ns = self.parse_args(['--qui']) self.assertTrue(ns.quiet) self.assertEqual(ns.verbose, 0) def test_two_options(self): - ns = libregrtest._parse_args(['--quiet', '--exclude']) + ns = self.parse_args(['--quiet', '--exclude']) self.assertTrue(ns.quiet) self.assertEqual(ns.verbose, 0) self.assertTrue(ns.exclude) def test_option_with_empty_string_value(self): - ns = libregrtest._parse_args(['--start', '']) + ns = self.parse_args(['--start', '']) self.assertEqual(ns.start, '') def test_arg(self): - ns = libregrtest._parse_args(['foo']) + ns = self.parse_args(['foo']) self.assertEqual(ns.args, ['foo']) def test_option_and_arg(self): - ns = libregrtest._parse_args(['--quiet', 'foo']) + ns = self.parse_args(['--quiet', 'foo']) self.assertTrue(ns.quiet) self.assertEqual(ns.verbose, 0) self.assertEqual(ns.args, ['foo']) def test_arg_option_arg(self): - ns = libregrtest._parse_args(['test_unaryop', '-v', 'test_binop']) + ns = self.parse_args(['test_unaryop', '-v', 'test_binop']) self.assertEqual(ns.verbose, 1) self.assertEqual(ns.args, ['test_unaryop', 'test_binop']) @@ -364,6 +383,55 @@ def test_unknown_option(self): self.checkError(['--unknown-option'], 'unrecognized arguments: --unknown-option') + def check_ci_mode(self, args, use_resources, rerun=True): + ns = cmdline._parse_args(args) + + # Check Regrtest attributes which are more reliable than Namespace + # which has an unclear API + regrtest = main.Regrtest(ns) + self.assertEqual(regrtest.num_workers, -1) + self.assertEqual(regrtest.want_rerun, rerun) + self.assertTrue(regrtest.randomize) + self.assertIsInstance(regrtest.random_seed, int) + self.assertTrue(regrtest.fail_env_changed) + self.assertTrue(regrtest.fail_rerun) + self.assertTrue(regrtest.print_slowest) + self.assertTrue(regrtest.output_on_failure) + self.assertEqual(sorted(regrtest.use_resources), sorted(use_resources)) + return regrtest + + def test_fast_ci(self): + args = ['--fast-ci'] + use_resources = sorted(cmdline.ALL_RESOURCES) + use_resources.remove('cpu') + regrtest = self.check_ci_mode(args, use_resources) + self.assertEqual(regrtest.timeout, 10 * 60) + + def test_fast_ci_python_cmd(self): + args = ['--fast-ci', '--python', 'python -X dev'] + use_resources = sorted(cmdline.ALL_RESOURCES) + use_resources.remove('cpu') + regrtest = self.check_ci_mode(args, use_resources, rerun=False) + self.assertEqual(regrtest.timeout, 10 * 60) + self.assertEqual(regrtest.python_cmd, ('python', '-X', 'dev')) + + def test_fast_ci_resource(self): + # it should be possible to override resources + args = ['--fast-ci', '-u', 'network'] + use_resources = ['network'] + self.check_ci_mode(args, use_resources) + + def test_slow_ci(self): + args = ['--slow-ci'] + use_resources = sorted(cmdline.ALL_RESOURCES) + regrtest = self.check_ci_mode(args, use_resources) + self.assertEqual(regrtest.timeout, 20 * 60) + + def test_dont_add_python_opts(self): + args = ['--dont-add-python-opts'] + ns = cmdline._parse_args(args) + self.assertFalse(ns._add_python_opts) + @dataclasses.dataclass(slots=True) class Rerun: @@ -419,10 +487,12 @@ def regex_search(self, regex, output): self.fail("%r not found in %r" % (regex, output)) return match - def check_line(self, output, regex, full=False): + def check_line(self, output, pattern, full=False, regex=True): + if not regex: + pattern = re.escape(pattern) if full: - regex += '\n' - regex = re.compile(r'^' + regex, re.MULTILINE) + pattern += '\n' + regex = re.compile(r'^' + pattern, re.MULTILINE) self.assertRegex(output, regex) def parse_executed_tests(self, output): @@ -431,13 +501,14 @@ def parse_executed_tests(self, output): parser = re.finditer(regex, output, re.MULTILINE) return list(match.group(1) for match in parser) - def check_executed_tests(self, output, tests, skipped=(), failed=(), + def check_executed_tests(self, output, tests, *, stats, + skipped=(), failed=(), env_changed=(), omitted=(), rerun=None, run_no_tests=(), resource_denied=(), - randomize=False, interrupted=False, + randomize=False, parallel=False, interrupted=False, fail_env_changed=False, - *, stats, forever=False, filtered=False): + forever=False, filtered=False): if isinstance(tests, str): tests = [tests] if isinstance(skipped, str): @@ -454,9 +525,11 @@ def check_executed_tests(self, output, tests, skipped=(), failed=(), run_no_tests = [run_no_tests] if isinstance(stats, int): stats = TestStats(stats) + if parallel: + randomize = True rerun_failed = [] - if rerun is not None: + if rerun is not None and not env_changed: failed = [rerun.name] if not rerun.success: rerun_failed.append(rerun.name) @@ -493,7 +566,8 @@ def list_regex(line_format, tests): self.check_line(output, regex) if env_changed: - regex = list_regex('%s test%s altered the execution environment', + regex = list_regex(r'%s test%s altered the execution environment ' + r'\(env changed\)', env_changed) self.check_line(output, regex) @@ -504,7 +578,7 @@ def list_regex(line_format, tests): if rerun is not None: regex = list_regex('%s re-run test%s', [rerun.name]) self.check_line(output, regex) - regex = LOG_PREFIX + fr"Re-running 1 failed tests in verbose mode" + regex = LOG_PREFIX + r"Re-running 1 failed tests in verbose mode" self.check_line(output, regex) regex = fr"Re-running {rerun.name} in verbose mode" if rerun.match: @@ -583,13 +657,13 @@ def list_regex(line_format, tests): state = ', '.join(state) if rerun is not None: new_state = 'SUCCESS' if rerun.success else 'FAILURE' - state = 'FAILURE then ' + new_state + state = f'{state} then {new_state}' self.check_line(output, f'Result: {state}', full=True) def parse_random_seed(self, output): match = self.regex_search(r'Using random seed ([0-9]+)', output) randseed = int(match.group(1)) - self.assertTrue(0 <= randseed <= 10000000, randseed) + self.assertTrue(0 <= randseed, randseed) return randseed def run_command(self, args, input=None, exitcode=0, **kw): @@ -598,7 +672,7 @@ def run_command(self, args, input=None, exitcode=0, **kw): if 'stderr' not in kw: kw['stderr'] = subprocess.STDOUT proc = subprocess.run(args, - universal_newlines=True, + text=True, input=input, stdout=subprocess.PIPE, **kw) @@ -621,7 +695,11 @@ def run_command(self, args, input=None, exitcode=0, **kw): return proc def run_python(self, args, **kw): - args = [sys.executable, '-X', 'faulthandler', '-I', *args] + extraargs = [] + if 'uops' in sys._xoptions: + # Pass -X uops along + extraargs.extend(['-X', 'uops']) + args = [sys.executable, *extraargs, '-X', 'faulthandler', '-I', *args] proc = self.run_command(args, **kw) return proc.stdout @@ -676,8 +754,8 @@ def check_output(self, output): self.check_executed_tests(output, self.tests, randomize=True, stats=len(self.tests)) - def run_tests(self, args): - output = self.run_python(args) + def run_tests(self, args, env=None): + output = self.run_python(args, env=env) self.check_output(output) def test_script_regrtest(self): @@ -718,14 +796,6 @@ def test_script_autotest(self): args = [*self.python_args, script, *self.regrtest_args, *self.tests] self.run_tests(args) - @unittest.skipUnless(sysconfig.is_python_build(), - 'run_tests.py script is not installed') - def test_tools_script_run_tests(self): - # Tools/scripts/run_tests.py - script = os.path.join(ROOT_DIR, 'Tools', 'scripts', 'run_tests.py') - args = [script, *self.regrtest_args, *self.tests] - self.run_tests(args) - def run_batch(self, *args): proc = self.run_command(args) self.check_output(proc.stdout) @@ -880,6 +950,10 @@ def test_random(self): test_random2 = int(match.group(1)) self.assertEqual(test_random2, test_random) + # check that random.seed is used by default + output = self.run_tests(test, exitcode=EXITCODE_NO_TESTS_RAN) + self.assertIsInstance(self.parse_random_seed(output), int) + def test_fromfile(self): # test --fromfile tests = [self.create_test() for index in range(5)] @@ -1014,12 +1088,16 @@ def test_run(self): stats=TestStats(4, 1), forever=True) - def check_leak(self, code, what): + def check_leak(self, code, what, *, run_workers=False): test = self.create_test('huntrleaks', code=code) filename = 'reflog.txt' self.addCleanup(os_helper.unlink, filename) - output = self.run_tests('--huntrleaks', '3:3:', test, + cmd = ['--huntrleaks', '3:3:'] + if run_workers: + cmd.append('-j1') + cmd.append(test) + output = self.run_tests(*cmd, exitcode=EXITCODE_BAD_TEST, stderr=subprocess.STDOUT) self.check_executed_tests(output, [test], failed=test, stats=1) @@ -1035,7 +1113,7 @@ def check_leak(self, code, what): self.assertIn(line2, reflog) @unittest.skipUnless(support.Py_DEBUG, 'need a debug build') - def test_huntrleaks(self): + def check_huntrleaks(self, *, run_workers: bool): # test --huntrleaks code = textwrap.dedent(""" import unittest @@ -1046,7 +1124,13 @@ class RefLeakTest(unittest.TestCase): def test_leak(self): GLOBAL_LIST.append(object()) """) - self.check_leak(code, 'references') + self.check_leak(code, 'references', run_workers=run_workers) + + def test_huntrleaks(self): + self.check_huntrleaks(run_workers=False) + + def test_huntrleaks_mp(self): + self.check_huntrleaks(run_workers=True) @unittest.skipUnless(support.Py_DEBUG, 'need a debug build') def test_huntrleaks_fd_leak(self): @@ -1104,7 +1188,7 @@ def test_crashed(self): tests = [crash_test] output = self.run_tests("-j2", *tests, exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, tests, failed=crash_test, - randomize=True, stats=0) + parallel=True, stats=0) def parse_methods(self, output): regex = re.compile("^(test[^ ]+).*ok$", flags=re.MULTILINE) @@ -1124,8 +1208,6 @@ def test_method3(self): def test_method4(self): pass """) - all_methods = ['test_method1', 'test_method2', - 'test_method3', 'test_method4'] testname = self.create_test(code=code) # only run a subset @@ -1208,6 +1290,15 @@ def test_env_changed(self): self.check_executed_tests(output, [testname], env_changed=testname, fail_env_changed=True, stats=1) + # rerun + output = self.run_tests("--rerun", testname) + self.check_executed_tests(output, [testname], + env_changed=testname, + rerun=Rerun(testname, + match=None, + success=True), + stats=2) + def test_rerun_fail(self): # FAILURE then FAILURE code = textwrap.dedent(""" @@ -1730,16 +1821,15 @@ def test_leak_tmp_file(self): self.check_executed_tests(output, testnames, env_changed=testnames, fail_env_changed=True, - randomize=True, + parallel=True, stats=len(testnames)) for testname in testnames: self.assertIn(f"Warning -- {testname} leaked temporary " f"files (1): mytmpfile", output) - def test_mp_decode_error(self): - # gh-101634: If a worker stdout cannot be decoded, report a failed test - # and a non-zero exit code. + def test_worker_decode_error(self): + # gh-109425: Use "backslashreplace" error handler to decode stdout. if sys.platform == 'win32': encoding = locale.getencoding() else: @@ -1747,34 +1837,46 @@ def test_mp_decode_error(self): if encoding is None: encoding = sys.__stdout__.encoding if encoding is None: - self.skipTest(f"cannot get regrtest worker encoding") - - nonascii = b"byte:\xa0\xa9\xff\n" + self.skipTest("cannot get regrtest worker encoding") + + nonascii = bytes(ch for ch in range(128, 256)) + corrupted_output = b"nonascii:%s\n" % (nonascii,) + # gh-108989: On Windows, assertion errors are written in UTF-16: when + # decoded each letter is follow by a NUL character. + assertion_failed = 'Assertion failed: tstate_is_alive(tstate)\n' + corrupted_output += assertion_failed.encode('utf-16-le') try: - nonascii.decode(encoding) + corrupted_output.decode(encoding) except UnicodeDecodeError: pass else: - self.skipTest(f"{encoding} can decode non-ASCII bytes {nonascii!a}") + self.skipTest(f"{encoding} can decode non-ASCII bytes") + + expected_line = corrupted_output.decode(encoding, 'backslashreplace') code = textwrap.dedent(fr""" import sys + import unittest + + class Tests(unittest.TestCase): + def test_pass(self): + pass + # bytes which cannot be decoded from UTF-8 - nonascii = {nonascii!a} - sys.stdout.buffer.write(nonascii) + corrupted_output = {corrupted_output!a} + sys.stdout.buffer.write(corrupted_output) sys.stdout.buffer.flush() """) testname = self.create_test(code=code) - output = self.run_tests("--fail-env-changed", "-v", "-j1", testname, - exitcode=EXITCODE_BAD_TEST) + output = self.run_tests("--fail-env-changed", "-v", "-j1", testname) self.check_executed_tests(output, [testname], - failed=[testname], - randomize=True, - stats=0) + parallel=True, + stats=1) + self.check_line(output, expected_line, regex=False) def test_doctest(self): - code = textwrap.dedent(fr''' + code = textwrap.dedent(r''' import doctest import sys from test import support @@ -1809,9 +1911,169 @@ def load_tests(loader, tests, pattern): exitcode=EXITCODE_BAD_TEST) self.check_executed_tests(output, [testname], failed=[testname], - randomize=True, + parallel=True, stats=TestStats(1, 1, 0)) + def _check_random_seed(self, run_workers: bool): + # gh-109276: When -r/--randomize is used, random.seed() is called + # with the same random seed before running each test file. + code = textwrap.dedent(r''' + import random + import unittest + + class RandomSeedTest(unittest.TestCase): + def test_randint(self): + numbers = [random.randint(0, 1000) for _ in range(10)] + print(f"Random numbers: {numbers}") + ''') + tests = [self.create_test(name=f'test_random{i}', code=code) + for i in range(1, 3+1)] + + random_seed = 856_656_202 + cmd = ["--randomize", f"--randseed={random_seed}"] + if run_workers: + # run as many worker processes than the number of tests + cmd.append(f'-j{len(tests)}') + cmd.extend(tests) + output = self.run_tests(*cmd) + + random.seed(random_seed) + # Make the assumption that nothing consume entropy between libregrest + # setup_tests() which calls random.seed() and RandomSeedTest calling + # random.randint(). + numbers = [random.randint(0, 1000) for _ in range(10)] + expected = f"Random numbers: {numbers}" + + regex = r'^Random numbers: .*$' + matches = re.findall(regex, output, flags=re.MULTILINE) + self.assertEqual(matches, [expected] * len(tests)) + + def test_random_seed(self): + self._check_random_seed(run_workers=False) + + def test_random_seed_workers(self): + self._check_random_seed(run_workers=True) + + def test_python_command(self): + code = textwrap.dedent(r""" + import sys + import unittest + + class WorkerTests(unittest.TestCase): + def test_dev_mode(self): + self.assertTrue(sys.flags.dev_mode) + """) + tests = [self.create_test(code=code) for _ in range(3)] + + # Custom Python command: "python -X dev" + python_cmd = [sys.executable, '-X', 'dev'] + # test.libregrtest.cmdline uses shlex.split() to parse the Python + # command line string + python_cmd = shlex.join(python_cmd) + + output = self.run_tests("--python", python_cmd, "-j0", *tests) + self.check_executed_tests(output, tests, + stats=len(tests), parallel=True) + + def check_add_python_opts(self, option): + # --fast-ci and --slow-ci add "-u -W default -bb -E" options to Python + code = textwrap.dedent(r""" + import sys + import unittest + from test import support + try: + from _testinternalcapi import get_config + except ImportError: + get_config = None + + # WASI/WASM buildbots don't use -E option + use_environment = (support.is_emscripten or support.is_wasi) + + class WorkerTests(unittest.TestCase): + @unittest.skipUnless(get_config is None, 'need get_config()') + def test_config(self): + config = get_config()['config'] + # -u option + self.assertEqual(config['buffered_stdio'], 0) + # -W default option + self.assertTrue(config['warnoptions'], ['default']) + # -bb option + self.assertTrue(config['bytes_warning'], 2) + # -E option + self.assertTrue(config['use_environment'], use_environment) + + def test_python_opts(self): + # -u option + self.assertTrue(sys.__stdout__.write_through) + self.assertTrue(sys.__stderr__.write_through) + + # -W default option + self.assertTrue(sys.warnoptions, ['default']) + + # -bb option + self.assertEqual(sys.flags.bytes_warning, 2) + + # -E option + self.assertEqual(not sys.flags.ignore_environment, + use_environment) + """) + testname = self.create_test(code=code) + + # Use directly subprocess to control the exact command line + cmd = [sys.executable, + "-m", "test", option, + f'--testdir={self.tmptestdir}', + testname] + proc = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True) + self.assertEqual(proc.returncode, 0, proc) + + def test_add_python_opts(self): + for opt in ("--fast-ci", "--slow-ci"): + with self.subTest(opt=opt): + self.check_add_python_opts(opt) + + # gh-76319: Raising SIGSEGV on Android may not cause a crash. + @unittest.skipIf(support.is_android, + 'raising SIGSEGV on Android is unreliable') + def test_worker_output_on_failure(self): + try: + from faulthandler import _sigsegv + except ImportError: + self.skipTest("need faulthandler._sigsegv") + + code = textwrap.dedent(r""" + import faulthandler + import unittest + from test import support + + class CrashTests(unittest.TestCase): + def test_crash(self): + print("just before crash!", flush=True) + + with support.SuppressCrashReport(): + faulthandler._sigsegv(True) + """) + testname = self.create_test(code=code) + + # Sanitizers must not handle SIGSEGV (ex: for test_enable_fd()) + env = dict(os.environ) + option = 'handle_segv=0' + support.set_sanitizer_env_var(env, option) + + output = self.run_tests("-j1", testname, + exitcode=EXITCODE_BAD_TEST, + env=env) + self.check_executed_tests(output, testname, + failed=[testname], + stats=0, parallel=True) + if not support.MS_WINDOWS: + exitcode = -int(signal.SIGSEGV) + self.assertIn(f"Exit code {exitcode} (SIGSEGV)", output) + self.check_line(output, "just before crash!", full=True, regex=False) + class TestUtils(unittest.TestCase): def test_format_duration(self): @@ -1847,6 +2109,35 @@ def test_normalize_test_name(self): self.assertIsNone(normalize('setUpModule (test.test_x)', is_error=True)) self.assertIsNone(normalize('tearDownModule (test.test_module)', is_error=True)) + def test_get_signal_name(self): + for exitcode, expected in ( + (-int(signal.SIGINT), 'SIGINT'), + (-int(signal.SIGSEGV), 'SIGSEGV'), + (3221225477, "STATUS_ACCESS_VIOLATION"), + (0xC00000FD, "STATUS_STACK_OVERFLOW"), + ): + self.assertEqual(utils.get_signal_name(exitcode), expected, exitcode) + + def test_format_resources(self): + format_resources = utils.format_resources + ALL_RESOURCES = utils.ALL_RESOURCES + self.assertEqual( + format_resources(("network",)), + 'resources (1): network') + self.assertEqual( + format_resources(("audio", "decimal", "network")), + 'resources (3): audio,decimal,network') + self.assertEqual( + format_resources(ALL_RESOURCES), + 'resources: all') + self.assertEqual( + format_resources(tuple(name for name in ALL_RESOURCES + if name != "cpu")), + 'resources: all,-cpu') + self.assertEqual( + format_resources((*ALL_RESOURCES, "tzdata")), + 'resources: all,tzdata') + if __name__ == '__main__': unittest.main() From 80f958529bc5c466add532df4c8dd314995f689f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 12 Oct 2023 23:24:12 +0200 Subject: [PATCH 1008/1206] [3.12] gh-110756: Sync regrtest with main branch (#110779) gh-110756: Sync regrtest with main branch * Remove runtest.py and runtest_mp.py of Lib/test/libregrtest/. * Backport support._parse_memlimit(). --- Lib/test/libregrtest/runtest.py | 577 -------------------------- Lib/test/libregrtest/runtest_mp.py | 631 ----------------------------- Lib/test/support/__init__.py | 40 +- Lib/test/test_support.py | 41 +- 4 files changed, 61 insertions(+), 1228 deletions(-) delete mode 100644 Lib/test/libregrtest/runtest.py delete mode 100644 Lib/test/libregrtest/runtest_mp.py diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py deleted file mode 100644 index 8b7844cb4b3bae..00000000000000 --- a/Lib/test/libregrtest/runtest.py +++ /dev/null @@ -1,577 +0,0 @@ -import dataclasses -import doctest -import faulthandler -import gc -import importlib -import io -import os -import sys -import time -import traceback -import unittest - -from test import support -from test.support import TestStats -from test.support import os_helper -from test.support import threading_helper -from test.libregrtest.cmdline import Namespace -from test.libregrtest.save_env import saved_test_environment -from test.libregrtest.utils import clear_caches, format_duration, print_warning - - -MatchTests = list[str] -MatchTestsDict = dict[str, MatchTests] - - -# Avoid enum.Enum to reduce the number of imports when tests are run -class State: - PASSED = "PASSED" - FAILED = "FAILED" - SKIPPED = "SKIPPED" - UNCAUGHT_EXC = "UNCAUGHT_EXC" - REFLEAK = "REFLEAK" - ENV_CHANGED = "ENV_CHANGED" - RESOURCE_DENIED = "RESOURCE_DENIED" - INTERRUPTED = "INTERRUPTED" - MULTIPROCESSING_ERROR = "MULTIPROCESSING_ERROR" - DID_NOT_RUN = "DID_NOT_RUN" - TIMEOUT = "TIMEOUT" - - @staticmethod - def is_failed(state): - return state in { - State.FAILED, - State.UNCAUGHT_EXC, - State.REFLEAK, - State.MULTIPROCESSING_ERROR, - State.TIMEOUT} - - @staticmethod - def has_meaningful_duration(state): - # Consider that the duration is meaningless for these cases. - # For example, if a whole test file is skipped, its duration - # is unlikely to be the duration of executing its tests, - # but just the duration to execute code which skips the test. - return state not in { - State.SKIPPED, - State.RESOURCE_DENIED, - State.INTERRUPTED, - State.MULTIPROCESSING_ERROR, - State.DID_NOT_RUN} - - @staticmethod - def must_stop(state): - return state in { - State.INTERRUPTED, - State.MULTIPROCESSING_ERROR} - - -# gh-90681: When rerunning tests, we might need to rerun the whole -# class or module suite if some its life-cycle hooks fail. -# Test level hooks are not affected. -_TEST_LIFECYCLE_HOOKS = frozenset(( - 'setUpClass', 'tearDownClass', - 'setUpModule', 'tearDownModule', -)) - -def normalize_test_name(test_full_name, *, is_error=False): - short_name = test_full_name.split(" ")[0] - if is_error and short_name in _TEST_LIFECYCLE_HOOKS: - if test_full_name.startswith(('setUpModule (', 'tearDownModule (')): - # if setUpModule() or tearDownModule() failed, don't filter - # tests with the test file name, don't use use filters. - return None - - # This means that we have a failure in a life-cycle hook, - # we need to rerun the whole module or class suite. - # Basically the error looks like this: - # ERROR: setUpClass (test.test_reg_ex.RegTest) - # or - # ERROR: setUpModule (test.test_reg_ex) - # So, we need to parse the class / module name. - lpar = test_full_name.index('(') - rpar = test_full_name.index(')') - return test_full_name[lpar + 1: rpar].split('.')[-1] - return short_name - - -@dataclasses.dataclass(slots=True) -class TestResult: - test_name: str - state: str | None = None - # Test duration in seconds - duration: float | None = None - xml_data: list[str] | None = None - stats: TestStats | None = None - - # errors and failures copied from support.TestFailedWithDetails - errors: list[tuple[str, str]] | None = None - failures: list[tuple[str, str]] | None = None - - def is_failed(self, fail_env_changed: bool) -> bool: - if self.state == State.ENV_CHANGED: - return fail_env_changed - return State.is_failed(self.state) - - def _format_failed(self): - if self.errors and self.failures: - le = len(self.errors) - lf = len(self.failures) - error_s = "error" + ("s" if le > 1 else "") - failure_s = "failure" + ("s" if lf > 1 else "") - return f"{self.test_name} failed ({le} {error_s}, {lf} {failure_s})" - - if self.errors: - le = len(self.errors) - error_s = "error" + ("s" if le > 1 else "") - return f"{self.test_name} failed ({le} {error_s})" - - if self.failures: - lf = len(self.failures) - failure_s = "failure" + ("s" if lf > 1 else "") - return f"{self.test_name} failed ({lf} {failure_s})" - - return f"{self.test_name} failed" - - def __str__(self) -> str: - match self.state: - case State.PASSED: - return f"{self.test_name} passed" - case State.FAILED: - return self._format_failed() - case State.SKIPPED: - return f"{self.test_name} skipped" - case State.UNCAUGHT_EXC: - return f"{self.test_name} failed (uncaught exception)" - case State.REFLEAK: - return f"{self.test_name} failed (reference leak)" - case State.ENV_CHANGED: - return f"{self.test_name} failed (env changed)" - case State.RESOURCE_DENIED: - return f"{self.test_name} skipped (resource denied)" - case State.INTERRUPTED: - return f"{self.test_name} interrupted" - case State.MULTIPROCESSING_ERROR: - return f"{self.test_name} process crashed" - case State.DID_NOT_RUN: - return f"{self.test_name} ran no tests" - case State.TIMEOUT: - return f"{self.test_name} timed out ({format_duration(self.duration)})" - case _: - raise ValueError("unknown result state: {state!r}") - - def has_meaningful_duration(self): - return State.has_meaningful_duration(self.state) - - def set_env_changed(self): - if self.state is None or self.state == State.PASSED: - self.state = State.ENV_CHANGED - - def must_stop(self, fail_fast: bool, fail_env_changed: bool) -> bool: - if State.must_stop(self.state): - return True - if fail_fast and self.is_failed(fail_env_changed): - return True - return False - - def get_rerun_match_tests(self): - match_tests = [] - - errors = self.errors or [] - failures = self.failures or [] - for error_list, is_error in ( - (errors, True), - (failures, False), - ): - for full_name, *_ in error_list: - match_name = normalize_test_name(full_name, is_error=is_error) - if match_name is None: - # 'setUpModule (test.test_sys)': don't filter tests - return None - if not match_name: - error_type = "ERROR" if is_error else "FAIL" - print_warning(f"rerun failed to parse {error_type} test name: " - f"{full_name!r}: don't filter tests") - return None - match_tests.append(match_name) - - return match_tests - - -@dataclasses.dataclass(slots=True, frozen=True) -class RunTests: - tests: list[str] - match_tests: MatchTestsDict | None = None - rerun: bool = False - forever: bool = False - - def get_match_tests(self, test_name) -> MatchTests | None: - if self.match_tests is not None: - return self.match_tests.get(test_name, None) - else: - return None - - def iter_tests(self): - tests = tuple(self.tests) - if self.forever: - while True: - yield from tests - else: - yield from tests - - -# Minimum duration of a test to display its duration or to mention that -# the test is running in background -PROGRESS_MIN_TIME = 30.0 # seconds - -#If these test directories are encountered recurse into them and treat each -# test_ .py or dir as a separate test module. This can increase parallelism. -# Beware this can't generally be done for any directory with sub-tests as the -# __init__.py may do things which alter what tests are to be run. - -SPLITTESTDIRS = { - "test_asyncio", - "test_concurrent_futures", - "test_future_stmt", - "test_gdb", - "test_multiprocessing_fork", - "test_multiprocessing_forkserver", - "test_multiprocessing_spawn", -} - - -def findtestdir(path=None): - return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir - - -def findtests(*, testdir=None, exclude=(), - split_test_dirs=SPLITTESTDIRS, base_mod=""): - """Return a list of all applicable test modules.""" - testdir = findtestdir(testdir) - tests = [] - for name in os.listdir(testdir): - mod, ext = os.path.splitext(name) - if (not mod.startswith("test_")) or (mod in exclude): - continue - if mod in split_test_dirs: - subdir = os.path.join(testdir, mod) - mod = f"{base_mod or 'test'}.{mod}" - tests.extend(findtests(testdir=subdir, exclude=exclude, - split_test_dirs=split_test_dirs, base_mod=mod)) - elif ext in (".py", ""): - tests.append(f"{base_mod}.{mod}" if base_mod else mod) - return sorted(tests) - - -def split_test_packages(tests, *, testdir=None, exclude=(), - split_test_dirs=SPLITTESTDIRS): - testdir = findtestdir(testdir) - splitted = [] - for name in tests: - if name in split_test_dirs: - subdir = os.path.join(testdir, name) - splitted.extend(findtests(testdir=subdir, exclude=exclude, - split_test_dirs=split_test_dirs, - base_mod=name)) - else: - splitted.append(name) - return splitted - - -def abs_module_name(test_name: str, test_dir: str | None) -> str: - if test_name.startswith('test.') or test_dir: - return test_name - else: - # Import it from the test package - return 'test.' + test_name - - -def setup_support(ns: Namespace): - support.PGO = ns.pgo - support.PGO_EXTENDED = ns.pgo_extended - support.set_match_tests(ns.match_tests, ns.ignore_tests) - support.failfast = ns.failfast - support.verbose = ns.verbose - if ns.xmlpath: - support.junit_xml_list = [] - else: - support.junit_xml_list = None - - -def _runtest(result: TestResult, ns: Namespace) -> None: - # Capture stdout and stderr, set faulthandler timeout, - # and create JUnit XML report. - verbose = ns.verbose - output_on_failure = ns.verbose3 - timeout = ns.timeout - - use_timeout = ( - timeout is not None and threading_helper.can_start_thread - ) - if use_timeout: - faulthandler.dump_traceback_later(timeout, exit=True) - - try: - setup_support(ns) - - if output_on_failure: - support.verbose = True - - stream = io.StringIO() - orig_stdout = sys.stdout - orig_stderr = sys.stderr - print_warning = support.print_warning - orig_print_warnings_stderr = print_warning.orig_stderr - - output = None - try: - sys.stdout = stream - sys.stderr = stream - # print_warning() writes into the temporary stream to preserve - # messages order. If support.environment_altered becomes true, - # warnings will be written to sys.stderr below. - print_warning.orig_stderr = stream - - _runtest_env_changed_exc(result, ns, display_failure=False) - # Ignore output if the test passed successfully - if result.state != State.PASSED: - output = stream.getvalue() - finally: - sys.stdout = orig_stdout - sys.stderr = orig_stderr - print_warning.orig_stderr = orig_print_warnings_stderr - - if output is not None: - sys.stderr.write(output) - sys.stderr.flush() - else: - # Tell tests to be moderately quiet - support.verbose = verbose - _runtest_env_changed_exc(result, ns, display_failure=not verbose) - - xml_list = support.junit_xml_list - if xml_list: - import xml.etree.ElementTree as ET - result.xml_data = [ET.tostring(x).decode('us-ascii') - for x in xml_list] - finally: - if use_timeout: - faulthandler.cancel_dump_traceback_later() - support.junit_xml_list = None - - -def runtest(ns: Namespace, test_name: str) -> TestResult: - """Run a single test. - - ns -- regrtest namespace of options - test_name -- the name of the test - - Returns a TestResult. - - If ns.xmlpath is not None, xml_data is a list containing each - generated testsuite element. - """ - start_time = time.perf_counter() - result = TestResult(test_name) - try: - _runtest(result, ns) - except: - if not ns.pgo: - msg = traceback.format_exc() - print(f"test {test_name} crashed -- {msg}", - file=sys.stderr, flush=True) - result.state = State.UNCAUGHT_EXC - result.duration = time.perf_counter() - start_time - return result - - -def run_unittest(test_mod): - loader = unittest.TestLoader() - tests = loader.loadTestsFromModule(test_mod) - for error in loader.errors: - print(error, file=sys.stderr) - if loader.errors: - raise Exception("errors while loading tests") - return support.run_unittest(tests) - - -def save_env(ns: Namespace, test_name: str): - return saved_test_environment(test_name, ns.verbose, ns.quiet, pgo=ns.pgo) - - -def regrtest_runner(result, test_func, ns) -> None: - # Run test_func(), collect statistics, and detect reference and memory - # leaks. - if ns.huntrleaks: - from test.libregrtest.refleak import dash_R - refleak, test_result = dash_R(ns, result.test_name, test_func) - else: - test_result = test_func() - refleak = False - - if refleak: - result.state = State.REFLEAK - - match test_result: - case TestStats(): - stats = test_result - case unittest.TestResult(): - stats = TestStats.from_unittest(test_result) - case doctest.TestResults(): - stats = TestStats.from_doctest(test_result) - case None: - print_warning(f"{result.test_name} test runner returned None: {test_func}") - stats = None - case _: - print_warning(f"Unknown test result type: {type(test_result)}") - stats = None - - result.stats = stats - - -# Storage of uncollectable objects -FOUND_GARBAGE = [] - - -def _load_run_test(result: TestResult, ns: Namespace) -> None: - # Load the test function, run the test function. - module_name = abs_module_name(result.test_name, ns.testdir) - - # Remove the module from sys.module to reload it if it was already imported - sys.modules.pop(module_name, None) - - test_mod = importlib.import_module(module_name) - - if hasattr(test_mod, "test_main"): - # https://github.com/python/cpython/issues/89392 - raise Exception(f"Module {result.test_name} defines test_main() which is no longer supported by regrtest") - def test_func(): - return run_unittest(test_mod) - - try: - with save_env(ns, result.test_name): - regrtest_runner(result, test_func, ns) - finally: - # First kill any dangling references to open files etc. - # This can also issue some ResourceWarnings which would otherwise get - # triggered during the following test run, and possibly produce - # failures. - support.gc_collect() - - remove_testfn(result.test_name, ns.verbose) - - if gc.garbage: - support.environment_altered = True - print_warning(f"{result.test_name} created {len(gc.garbage)} " - f"uncollectable object(s)") - - # move the uncollectable objects somewhere, - # so we don't see them again - FOUND_GARBAGE.extend(gc.garbage) - gc.garbage.clear() - - support.reap_children() - - -def _runtest_env_changed_exc(result: TestResult, ns: Namespace, - display_failure: bool = True) -> None: - # Detect environment changes, handle exceptions. - - # Reset the environment_altered flag to detect if a test altered - # the environment - support.environment_altered = False - - if ns.pgo: - display_failure = False - - test_name = result.test_name - try: - clear_caches() - support.gc_collect() - - with save_env(ns, test_name): - _load_run_test(result, ns) - except support.ResourceDenied as msg: - if not ns.quiet and not ns.pgo: - print(f"{test_name} skipped -- {msg}", flush=True) - result.state = State.RESOURCE_DENIED - return - except unittest.SkipTest as msg: - if not ns.quiet and not ns.pgo: - print(f"{test_name} skipped -- {msg}", flush=True) - result.state = State.SKIPPED - return - except support.TestFailedWithDetails as exc: - msg = f"test {test_name} failed" - if display_failure: - msg = f"{msg} -- {exc}" - print(msg, file=sys.stderr, flush=True) - result.state = State.FAILED - result.errors = exc.errors - result.failures = exc.failures - result.stats = exc.stats - return - except support.TestFailed as exc: - msg = f"test {test_name} failed" - if display_failure: - msg = f"{msg} -- {exc}" - print(msg, file=sys.stderr, flush=True) - result.state = State.FAILED - result.stats = exc.stats - return - except support.TestDidNotRun: - result.state = State.DID_NOT_RUN - return - except KeyboardInterrupt: - print() - result.state = State.INTERRUPTED - return - except: - if not ns.pgo: - msg = traceback.format_exc() - print(f"test {test_name} crashed -- {msg}", - file=sys.stderr, flush=True) - result.state = State.UNCAUGHT_EXC - return - - if support.environment_altered: - result.set_env_changed() - # Don't override the state if it was already set (REFLEAK or ENV_CHANGED) - if result.state is None: - result.state = State.PASSED - - -def remove_testfn(test_name: str, verbose: int) -> None: - # Try to clean up os_helper.TESTFN if left behind. - # - # While tests shouldn't leave any files or directories behind, when a test - # fails that can be tedious for it to arrange. The consequences can be - # especially nasty on Windows, since if a test leaves a file open, it - # cannot be deleted by name (while there's nothing we can do about that - # here either, we can display the name of the offending test, which is a - # real help). - name = os_helper.TESTFN - if not os.path.exists(name): - return - - if os.path.isdir(name): - import shutil - kind, nuker = "directory", shutil.rmtree - elif os.path.isfile(name): - kind, nuker = "file", os.unlink - else: - raise RuntimeError(f"os.path says {name!r} exists but is neither " - f"directory nor file") - - if verbose: - print_warning(f"{test_name} left behind {kind} {name!r}") - support.environment_altered = True - - try: - import stat - # fix possible permissions problems that might prevent cleanup - os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) - nuker(name) - except Exception as exc: - print_warning(f"{test_name} left behind {kind} {name!r} " - f"and it couldn't be removed: {exc}") diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py deleted file mode 100644 index 60089554cab5dd..00000000000000 --- a/Lib/test/libregrtest/runtest_mp.py +++ /dev/null @@ -1,631 +0,0 @@ -import dataclasses -import faulthandler -import json -import os.path -import queue -import signal -import subprocess -import sys -import tempfile -import threading -import time -import traceback -from typing import NamedTuple, NoReturn, Literal, Any, TextIO - -from test import support -from test.support import os_helper -from test.support import TestStats - -from test.libregrtest.cmdline import Namespace -from test.libregrtest.main import Regrtest -from test.libregrtest.runtest import ( - runtest, TestResult, State, PROGRESS_MIN_TIME, - MatchTests, RunTests) -from test.libregrtest.setup import setup_tests -from test.libregrtest.utils import format_duration, print_warning - -if sys.platform == 'win32': - import locale - - -# Display the running tests if nothing happened last N seconds -PROGRESS_UPDATE = 30.0 # seconds -assert PROGRESS_UPDATE >= PROGRESS_MIN_TIME - -# Kill the main process after 5 minutes. It is supposed to write an update -# every PROGRESS_UPDATE seconds. Tolerate 5 minutes for Python slowest -# buildbot workers. -MAIN_PROCESS_TIMEOUT = 5 * 60.0 -assert MAIN_PROCESS_TIMEOUT >= PROGRESS_UPDATE - -# Time to wait until a worker completes: should be immediate -JOIN_TIMEOUT = 30.0 # seconds - -USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg")) - - -@dataclasses.dataclass(slots=True) -class WorkerJob: - test_name: str - namespace: Namespace - rerun: bool = False - match_tests: MatchTests | None = None - - -class _EncodeWorkerJob(json.JSONEncoder): - def default(self, o: Any) -> dict[str, Any]: - match o: - case WorkerJob(): - result = dataclasses.asdict(o) - result["__worker_job__"] = True - return result - case Namespace(): - result = vars(o) - result["__namespace__"] = True - return result - case _: - return super().default(o) - - -def _decode_worker_job(d: dict[str, Any]) -> WorkerJob | dict[str, Any]: - if "__worker_job__" in d: - d.pop('__worker_job__') - return WorkerJob(**d) - if "__namespace__" in d: - d.pop('__namespace__') - return Namespace(**d) - else: - return d - - -def _parse_worker_args(worker_json: str) -> tuple[Namespace, str]: - return json.loads(worker_json, - object_hook=_decode_worker_job) - - -def run_test_in_subprocess(worker_job: WorkerJob, - output_file: TextIO, - tmp_dir: str | None = None) -> subprocess.Popen: - ns = worker_job.namespace - python = ns.python - worker_args = json.dumps(worker_job, cls=_EncodeWorkerJob) - - if python is not None: - executable = python - else: - executable = [sys.executable] - cmd = [*executable, *support.args_from_interpreter_flags(), - '-u', # Unbuffered stdout and stderr - '-m', 'test.regrtest', - '--worker-args', worker_args] - - env = dict(os.environ) - if tmp_dir is not None: - env['TMPDIR'] = tmp_dir - env['TEMP'] = tmp_dir - env['TMP'] = tmp_dir - - # Running the child from the same working directory as regrtest's original - # invocation ensures that TEMPDIR for the child is the same when - # sysconfig.is_python_build() is true. See issue 15300. - kw = dict( - env=env, - stdout=output_file, - # bpo-45410: Write stderr into stdout to keep messages order - stderr=output_file, - text=True, - close_fds=(os.name != 'nt'), - cwd=os_helper.SAVEDCWD, - ) - if USE_PROCESS_GROUP: - kw['start_new_session'] = True - return subprocess.Popen(cmd, **kw) - - -def run_tests_worker(worker_json: str) -> NoReturn: - worker_job = _parse_worker_args(worker_json) - ns = worker_job.namespace - test_name = worker_job.test_name - rerun = worker_job.rerun - match_tests = worker_job.match_tests - - setup_tests(ns) - - if rerun: - if match_tests: - matching = "matching: " + ", ".join(match_tests) - print(f"Re-running {test_name} in verbose mode ({matching})", flush=True) - else: - print(f"Re-running {test_name} in verbose mode", flush=True) - ns.verbose = True - - if match_tests is not None: - ns.match_tests = match_tests - - result = runtest(ns, test_name) - print() # Force a newline (just in case) - - # Serialize TestResult as dict in JSON - print(json.dumps(result, cls=EncodeTestResult), flush=True) - sys.exit(0) - - -# We do not use a generator so multiple threads can call next(). -class MultiprocessIterator: - - """A thread-safe iterator over tests for multiprocess mode.""" - - def __init__(self, tests_iter): - self.lock = threading.Lock() - self.tests_iter = tests_iter - - def __iter__(self): - return self - - def __next__(self): - with self.lock: - if self.tests_iter is None: - raise StopIteration - return next(self.tests_iter) - - def stop(self): - with self.lock: - self.tests_iter = None - - -class MultiprocessResult(NamedTuple): - result: TestResult - # bpo-45410: stderr is written into stdout to keep messages order - worker_stdout: str | None = None - err_msg: str | None = None - - -ExcStr = str -QueueOutput = tuple[Literal[False], MultiprocessResult] | tuple[Literal[True], ExcStr] - - -class ExitThread(Exception): - pass - - -class TestWorkerProcess(threading.Thread): - def __init__(self, worker_id: int, runner: "MultiprocessTestRunner") -> None: - super().__init__() - self.worker_id = worker_id - self.runtests = runner.runtests - self.pending = runner.pending - self.output = runner.output - self.ns = runner.ns - self.timeout = runner.worker_timeout - self.regrtest = runner.regrtest - self.rerun = runner.rerun - self.current_test_name = None - self.start_time = None - self._popen = None - self._killed = False - self._stopped = False - - def __repr__(self) -> str: - info = [f'TestWorkerProcess #{self.worker_id}'] - if self.is_alive(): - info.append("running") - else: - info.append('stopped') - test = self.current_test_name - if test: - info.append(f'test={test}') - popen = self._popen - if popen is not None: - dt = time.monotonic() - self.start_time - info.extend((f'pid={self._popen.pid}', - f'time={format_duration(dt)}')) - return '<%s>' % ' '.join(info) - - def _kill(self) -> None: - popen = self._popen - if popen is None: - return - - if self._killed: - return - self._killed = True - - if USE_PROCESS_GROUP: - what = f"{self} process group" - else: - what = f"{self}" - - print(f"Kill {what}", file=sys.stderr, flush=True) - try: - if USE_PROCESS_GROUP: - os.killpg(popen.pid, signal.SIGKILL) - else: - popen.kill() - except ProcessLookupError: - # popen.kill(): the process completed, the TestWorkerProcess thread - # read its exit status, but Popen.send_signal() read the returncode - # just before Popen.wait() set returncode. - pass - except OSError as exc: - print_warning(f"Failed to kill {what}: {exc!r}") - - def stop(self) -> None: - # Method called from a different thread to stop this thread - self._stopped = True - self._kill() - - def mp_result_error( - self, - test_result: TestResult, - stdout: str | None = None, - err_msg=None - ) -> MultiprocessResult: - return MultiprocessResult(test_result, stdout, err_msg) - - def _run_process(self, worker_job, output_file: TextIO, - tmp_dir: str | None = None) -> int: - self.current_test_name = worker_job.test_name - try: - popen = run_test_in_subprocess(worker_job, output_file, tmp_dir) - - self._killed = False - self._popen = popen - except: - self.current_test_name = None - raise - - try: - if self._stopped: - # If kill() has been called before self._popen is set, - # self._popen is still running. Call again kill() - # to ensure that the process is killed. - self._kill() - raise ExitThread - - try: - # gh-94026: stdout+stderr are written to tempfile - retcode = popen.wait(timeout=self.timeout) - assert retcode is not None - return retcode - except subprocess.TimeoutExpired: - if self._stopped: - # kill() has been called: communicate() fails on reading - # closed stdout - raise ExitThread - - # On timeout, kill the process - self._kill() - - # None means TIMEOUT for the caller - retcode = None - # bpo-38207: Don't attempt to call communicate() again: on it - # can hang until all child processes using stdout - # pipes completes. - except OSError: - if self._stopped: - # kill() has been called: communicate() fails - # on reading closed stdout - raise ExitThread - raise - except: - self._kill() - raise - finally: - self._wait_completed() - self._popen = None - self.current_test_name = None - - def _runtest(self, test_name: str) -> MultiprocessResult: - if sys.platform == 'win32': - # gh-95027: When stdout is not a TTY, Python uses the ANSI code - # page for the sys.stdout encoding. If the main process runs in a - # terminal, sys.stdout uses WindowsConsoleIO with UTF-8 encoding. - encoding = locale.getencoding() - else: - encoding = sys.stdout.encoding - - match_tests = self.runtests.get_match_tests(test_name) - - # gh-94026: Write stdout+stderr to a tempfile as workaround for - # non-blocking pipes on Emscripten with NodeJS. - with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_file: - worker_job = WorkerJob(test_name, - namespace=self.ns, - rerun=self.rerun, - match_tests=match_tests) - # gh-93353: Check for leaked temporary files in the parent process, - # since the deletion of temporary files can happen late during - # Python finalization: too late for libregrtest. - if not support.is_wasi: - # Don't check for leaked temporary files and directories if Python is - # run on WASI. WASI don't pass environment variables like TMPDIR to - # worker processes. - tmp_dir = tempfile.mkdtemp(prefix="test_python_") - tmp_dir = os.path.abspath(tmp_dir) - try: - retcode = self._run_process(worker_job, stdout_file, tmp_dir) - finally: - tmp_files = os.listdir(tmp_dir) - os_helper.rmtree(tmp_dir) - else: - retcode = self._run_process(worker_job, stdout_file) - tmp_files = () - stdout_file.seek(0) - - try: - stdout = stdout_file.read().strip() - except Exception as exc: - # gh-101634: Catch UnicodeDecodeError if stdout cannot be - # decoded from encoding - err_msg = f"Cannot read process stdout: {exc}" - result = TestResult(test_name, state=State.MULTIPROCESSING_ERROR) - return self.mp_result_error(result, err_msg=err_msg) - - if retcode is None: - result = TestResult(test_name, state=State.TIMEOUT) - return self.mp_result_error(result, stdout) - - err_msg = None - if retcode != 0: - err_msg = "Exit code %s" % retcode - else: - stdout, _, worker_json = stdout.rpartition("\n") - stdout = stdout.rstrip() - if not worker_json: - err_msg = "Failed to parse worker stdout" - else: - try: - # deserialize run_tests_worker() output - result = json.loads(worker_json, - object_hook=decode_test_result) - except Exception as exc: - err_msg = "Failed to parse worker JSON: %s" % exc - - if err_msg: - result = TestResult(test_name, state=State.MULTIPROCESSING_ERROR) - return self.mp_result_error(result, stdout, err_msg) - - if tmp_files: - msg = (f'\n\n' - f'Warning -- {test_name} leaked temporary files ' - f'({len(tmp_files)}): {", ".join(sorted(tmp_files))}') - stdout += msg - result.set_env_changed() - - return MultiprocessResult(result, stdout) - - def run(self) -> None: - fail_fast = self.ns.failfast - fail_env_changed = self.ns.fail_env_changed - while not self._stopped: - try: - try: - test_name = next(self.pending) - except StopIteration: - break - - self.start_time = time.monotonic() - mp_result = self._runtest(test_name) - mp_result.result.duration = time.monotonic() - self.start_time - self.output.put((False, mp_result)) - - if mp_result.result.must_stop(fail_fast, fail_env_changed): - break - except ExitThread: - break - except BaseException: - self.output.put((True, traceback.format_exc())) - break - - def _wait_completed(self) -> None: - popen = self._popen - - try: - popen.wait(JOIN_TIMEOUT) - except (subprocess.TimeoutExpired, OSError) as exc: - print_warning(f"Failed to wait for {self} completion " - f"(timeout={format_duration(JOIN_TIMEOUT)}): " - f"{exc!r}") - - def wait_stopped(self, start_time: float) -> None: - # bpo-38207: MultiprocessTestRunner.stop_workers() called self.stop() - # which killed the process. Sometimes, killing the process from the - # main thread does not interrupt popen.communicate() in - # TestWorkerProcess thread. This loop with a timeout is a workaround - # for that. - # - # Moreover, if this method fails to join the thread, it is likely - # that Python will hang at exit while calling threading._shutdown() - # which tries again to join the blocked thread. Regrtest.main() - # uses EXIT_TIMEOUT to workaround this second bug. - while True: - # Write a message every second - self.join(1.0) - if not self.is_alive(): - break - dt = time.monotonic() - start_time - self.regrtest.log(f"Waiting for {self} thread " - f"for {format_duration(dt)}") - if dt > JOIN_TIMEOUT: - print_warning(f"Failed to join {self} in {format_duration(dt)}") - break - - -def get_running(workers: list[TestWorkerProcess]) -> list[TestWorkerProcess]: - running = [] - for worker in workers: - current_test_name = worker.current_test_name - if not current_test_name: - continue - dt = time.monotonic() - worker.start_time - if dt >= PROGRESS_MIN_TIME: - text = '%s (%s)' % (current_test_name, format_duration(dt)) - running.append(text) - return running - - -class MultiprocessTestRunner: - def __init__(self, regrtest: Regrtest, runtests: RunTests) -> None: - ns = regrtest.ns - timeout = ns.timeout - - self.regrtest = regrtest - self.runtests = runtests - self.rerun = runtests.rerun - self.log = self.regrtest.log - self.ns = ns - self.output: queue.Queue[QueueOutput] = queue.Queue() - tests_iter = runtests.iter_tests() - self.pending = MultiprocessIterator(tests_iter) - if timeout is not None: - # Rely on faulthandler to kill a worker process. This timouet is - # when faulthandler fails to kill a worker process. Give a maximum - # of 5 minutes to faulthandler to kill the worker. - self.worker_timeout = min(timeout * 1.5, timeout + 5 * 60) - else: - self.worker_timeout = None - self.workers = None - - def start_workers(self) -> None: - use_mp = self.ns.use_mp - timeout = self.ns.timeout - self.workers = [TestWorkerProcess(index, self) - for index in range(1, use_mp + 1)] - msg = f"Run tests in parallel using {len(self.workers)} child processes" - if timeout: - msg += (" (timeout: %s, worker timeout: %s)" - % (format_duration(timeout), - format_duration(self.worker_timeout))) - self.log(msg) - for worker in self.workers: - worker.start() - - def stop_workers(self) -> None: - start_time = time.monotonic() - for worker in self.workers: - worker.stop() - for worker in self.workers: - worker.wait_stopped(start_time) - - def _get_result(self) -> QueueOutput | None: - pgo = self.ns.pgo - use_faulthandler = (self.ns.timeout is not None) - timeout = PROGRESS_UPDATE - - # bpo-46205: check the status of workers every iteration to avoid - # waiting forever on an empty queue. - while any(worker.is_alive() for worker in self.workers): - if use_faulthandler: - faulthandler.dump_traceback_later(MAIN_PROCESS_TIMEOUT, - exit=True) - - # wait for a thread - try: - return self.output.get(timeout=timeout) - except queue.Empty: - pass - - # display progress - running = get_running(self.workers) - if running and not pgo: - self.log('running: %s' % ', '.join(running)) - - # all worker threads are done: consume pending results - try: - return self.output.get(timeout=0) - except queue.Empty: - return None - - def display_result(self, mp_result: MultiprocessResult) -> None: - result = mp_result.result - pgo = self.ns.pgo - - text = str(result) - if mp_result.err_msg: - # MULTIPROCESSING_ERROR - text += ' (%s)' % mp_result.err_msg - elif (result.duration >= PROGRESS_MIN_TIME and not pgo): - text += ' (%s)' % format_duration(result.duration) - running = get_running(self.workers) - if running and not pgo: - text += ' -- running: %s' % ', '.join(running) - self.regrtest.display_progress(self.test_index, text) - - def _process_result(self, item: QueueOutput) -> bool: - """Returns True if test runner must stop.""" - rerun = self.runtests.rerun - if item[0]: - # Thread got an exception - format_exc = item[1] - print_warning(f"regrtest worker thread failed: {format_exc}") - result = TestResult("", state=State.MULTIPROCESSING_ERROR) - self.regrtest.accumulate_result(result, rerun=rerun) - return result - - self.test_index += 1 - mp_result = item[1] - result = mp_result.result - self.regrtest.accumulate_result(result, rerun=rerun) - self.display_result(mp_result) - - if mp_result.worker_stdout: - print(mp_result.worker_stdout, flush=True) - - return result - - def run_tests(self) -> None: - fail_fast = self.ns.failfast - fail_env_changed = self.ns.fail_env_changed - timeout = self.ns.timeout - - self.start_workers() - - self.test_index = 0 - try: - while True: - item = self._get_result() - if item is None: - break - - result = self._process_result(item) - if result.must_stop(fail_fast, fail_env_changed): - break - except KeyboardInterrupt: - print() - self.regrtest.interrupted = True - finally: - if timeout is not None: - faulthandler.cancel_dump_traceback_later() - - # Always ensure that all worker processes are no longer - # worker when we exit this function - self.pending.stop() - self.stop_workers() - - -def run_tests_multiprocess(regrtest: Regrtest, runtests: RunTests) -> None: - MultiprocessTestRunner(regrtest, runtests).run_tests() - - -class EncodeTestResult(json.JSONEncoder): - """Encode a TestResult (sub)class object into a JSON dict.""" - - def default(self, o: Any) -> dict[str, Any]: - if isinstance(o, TestResult): - result = dataclasses.asdict(o) - result["__test_result__"] = o.__class__.__name__ - return result - - return super().default(o) - - -def decode_test_result(d: dict[str, Any]) -> TestResult | dict[str, Any]: - """Decode a TestResult (sub)class object from a JSON dict.""" - - if "__test_result__" not in d: - return d - - d.pop('__test_result__') - if d['stats'] is not None: - d['stats'] = TestStats(**d['stats']) - return TestResult(**d) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 37fd9443e18007..ded8ad96606a7c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -400,19 +400,19 @@ def check_sanitizer(*, address=False, memory=False, ub=False): raise ValueError('At least one of address, memory, or ub must be True') - _cflags = sysconfig.get_config_var('CFLAGS') or '' - _config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' + cflags = sysconfig.get_config_var('CFLAGS') or '' + config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' memory_sanitizer = ( - '-fsanitize=memory' in _cflags or - '--with-memory-sanitizer' in _config_args + '-fsanitize=memory' in cflags or + '--with-memory-sanitizer' in config_args ) address_sanitizer = ( - '-fsanitize=address' in _cflags or - '--with-address-sanitizer' in _config_args + '-fsanitize=address' in cflags or + '--with-address-sanitizer' in config_args ) ub_sanitizer = ( - '-fsanitize=undefined' in _cflags or - '--with-undefined-behavior-sanitizer' in _config_args + '-fsanitize=undefined' in cflags or + '--with-undefined-behavior-sanitizer' in config_args ) return ( (memory and memory_sanitizer) or @@ -916,27 +916,31 @@ def inner(*args, **kwds): MAX_Py_ssize_t = sys.maxsize -def set_memlimit(limit): - global max_memuse - global real_max_memuse +def _parse_memlimit(limit: str) -> int: sizes = { 'k': 1024, 'm': _1M, 'g': _1G, 't': 1024*_1G, } - m = re.match(r'(\d+(\.\d+)?) (K|M|G|T)b?$', limit, + m = re.match(r'(\d+(?:\.\d+)?) (K|M|G|T)b?$', limit, re.IGNORECASE | re.VERBOSE) if m is None: - raise ValueError('Invalid memory limit %r' % (limit,)) - memlimit = int(float(m.group(1)) * sizes[m.group(3).lower()]) - real_max_memuse = memlimit - if memlimit > MAX_Py_ssize_t: - memlimit = MAX_Py_ssize_t + raise ValueError(f'Invalid memory limit: {limit!r}') + return int(float(m.group(1)) * sizes[m.group(2).lower()]) + +def set_memlimit(limit: str) -> None: + global max_memuse + global real_max_memuse + memlimit = _parse_memlimit(limit) if memlimit < _2G - 1: - raise ValueError('Memory limit %r too low to be useful' % (limit,)) + raise ValueError('Memory limit {limit!r} too low to be useful') + + real_max_memuse = memlimit + memlimit = min(memlimit, MAX_Py_ssize_t) max_memuse = memlimit + class _MemoryWatchdog: """An object which periodically watches the process' memory consumption and prints it out. diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index b9b05fc4306a31..4a93249af313cf 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -764,7 +764,45 @@ def recursive_function(depth): else: self.fail("RecursionError was not raised") - #self.assertEqual(available, 2) + def test_parse_memlimit(self): + parse = support._parse_memlimit + KiB = 1024 + MiB = KiB * 1024 + GiB = MiB * 1024 + TiB = GiB * 1024 + self.assertEqual(parse('0k'), 0) + self.assertEqual(parse('3k'), 3 * KiB) + self.assertEqual(parse('2.4m'), int(2.4 * MiB)) + self.assertEqual(parse('4g'), int(4 * GiB)) + self.assertEqual(parse('1t'), TiB) + + for limit in ('', '3', '3.5.10k', '10x'): + with self.subTest(limit=limit): + with self.assertRaises(ValueError): + parse(limit) + + def test_set_memlimit(self): + _4GiB = 4 * 1024 ** 3 + TiB = 1024 ** 4 + old_max_memuse = support.max_memuse + old_real_max_memuse = support.real_max_memuse + try: + if sys.maxsize > 2**32: + support.set_memlimit('4g') + self.assertEqual(support.max_memuse, _4GiB) + self.assertEqual(support.real_max_memuse, _4GiB) + + big = 2**100 // TiB + support.set_memlimit(f'{big}t') + self.assertEqual(support.max_memuse, sys.maxsize) + self.assertEqual(support.real_max_memuse, big * TiB) + else: + support.set_memlimit('4g') + self.assertEqual(support.max_memuse, sys.maxsize) + self.assertEqual(support.real_max_memuse, _4GiB) + finally: + support.max_memuse = old_max_memuse + support.real_max_memuse = old_real_max_memuse def test_copy_python_src_ignore(self): # Get source directory @@ -813,7 +851,6 @@ def test_copy_python_src_ignore(self): # EnvironmentVarGuard # transient_internet # run_with_locale - # set_memlimit # bigmemtest # precisionbigmemtest # bigaddrspacetest From 27d5ea291c16bcdfaad25e2e371c2ba3d591ed37 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Oct 2023 01:24:37 +0200 Subject: [PATCH 1009/1206] [3.12] gh-110782: Fix crash when TypeVar is constructed with keyword args (GH-110784) (#110787) gh-110782: Fix crash when TypeVar is constructed with keyword args (GH-110784) (cherry picked from commit d2a536b1706d4a79303b7ac53684bb82eac2de23) Co-authored-by: Jelle Zijlstra --- Lib/test/test_typing.py | 6 +++ ...-10-12-15-03-24.gh-issue-110782.EqzIzi.rst | 2 + Objects/typevarobject.c | 38 ++++++++++--------- 3 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-12-15-03-24.gh-issue-110782.EqzIzi.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 03f03fea3b04d4..957d7afe7ca4cf 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -554,6 +554,12 @@ def test_many_weakrefs(self): vals[x] = cls(str(x)) del vals + def test_constructor(self): + T = TypeVar(name="T") + self.assertEqual(T.__name__, "T") + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, None) + def template_replace(templates: list[str], replacements: dict[str, list[str]]) -> list[tuple[str]]: """Renders templates with possible combinations of replacements. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-12-15-03-24.gh-issue-110782.EqzIzi.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-12-15-03-24.gh-issue-110782.EqzIzi.rst new file mode 100644 index 00000000000000..6eddcc0120829c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-12-15-03-24.gh-issue-110782.EqzIzi.rst @@ -0,0 +1,2 @@ +Fix crash when :class:`typing.TypeVar` is constructed with a keyword +argument. Patch by Jelle Zijlstra. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 069e1d98ea4978..db9c2191d60090 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -364,24 +364,26 @@ typevar_new_impl(PyTypeObject *type, PyObject *name, PyObject *constraints, } } - if (!PyTuple_CheckExact(constraints)) { - PyErr_SetString(PyExc_TypeError, - "constraints must be a tuple"); - return NULL; - } - Py_ssize_t n_constraints = PyTuple_GET_SIZE(constraints); - if (n_constraints == 1) { - PyErr_SetString(PyExc_TypeError, - "A single constraint is not allowed"); - Py_XDECREF(bound); - return NULL; - } else if (n_constraints == 0) { - constraints = NULL; - } else if (bound != NULL) { - PyErr_SetString(PyExc_TypeError, - "Constraints cannot be combined with bound=..."); - Py_XDECREF(bound); - return NULL; + if (constraints != NULL) { + if (!PyTuple_CheckExact(constraints)) { + PyErr_SetString(PyExc_TypeError, + "constraints must be a tuple"); + return NULL; + } + Py_ssize_t n_constraints = PyTuple_GET_SIZE(constraints); + if (n_constraints == 1) { + PyErr_SetString(PyExc_TypeError, + "A single constraint is not allowed"); + Py_XDECREF(bound); + return NULL; + } else if (n_constraints == 0) { + constraints = NULL; + } else if (bound != NULL) { + PyErr_SetString(PyExc_TypeError, + "Constraints cannot be combined with bound=..."); + Py_XDECREF(bound); + return NULL; + } } PyObject *module = caller(); if (module == NULL) { From 08242cdd7bd65865a6f1000671e958cf687b4f45 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:31:39 +0200 Subject: [PATCH 1010/1206] [3.12] gh-107450: Fix parser column offset overflow test on Windows (GH-110768) (#110808) (cherry picked from commit 05439d308740b621d03562451a7608eb725937ae) Co-authored-by: Lysandros Nikolaou Co-authored-by: Nikita Sobolev --- Lib/test/test_exceptions.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 5d460982ddfa48..9de7e7355e5742 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -318,8 +318,10 @@ def baz(): check('(yield i) = 2', 1, 2) check('def f(*):\n pass', 1, 7) - def testMemoryErrorBigSource(self): - with self.assertRaisesRegex(OverflowError, "column offset overflow"): + @support.requires_resource('cpu') + @support.bigmemtest(support._2G, memuse=1.5) + def testMemoryErrorBigSource(self, _size): + with self.assertRaises(OverflowError): exec(f"if True:\n {' ' * 2**31}print('hello world')") @cpython_only From f2e353b9d85384f1e6320e8bd3e300a22994535a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:59:55 +0200 Subject: [PATCH 1011/1206] [3.12] gh-110803: Reorganize docs for what PyType_Slot doesn't cover (GH-110813) (#110823) gh-110803: Reorganize docs for what PyType_Slot doesn't cover (GH-110813) * gh-110803: Reorganize docs for what PyType_Slot doesn't cover - Cover the offset fields first - Mention the old alternative for MANAGED flags, which is needed to support older Pythons - De-emphasize the internal flags: use an inline list. - Add a note to PyMemberDef saying what to do with it * Remove an older draft... (cherry picked from commit 2ab34f0e425d90d0a153104ef2f4343dce2a414d) Co-authored-by: Petr Viktorin --- Doc/c-api/structures.rst | 6 +++++- Doc/c-api/type.rst | 41 ++++++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 747cfa62294c21..25cb4ed40f63e7 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -406,7 +406,11 @@ Accessing attributes of extension types .. c:type:: PyMemberDef Structure which describes an attribute of a type which corresponds to a C - struct member. Its fields are, in order: + struct member. + When defining a class, put a NULL-terminated array of these + structures in the :c:member:`~PyTypeObject.tp_members` slot. + + Its fields are, in order: .. c:member:: const char* name diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 0f58326f6c06b7..5aaa8147dd3176 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -461,21 +461,34 @@ The following functions and structs are used to create * ``Py_nb_add`` to set :c:member:`PyNumberMethods.nb_add` * ``Py_sq_length`` to set :c:member:`PySequenceMethods.sq_length` - The following fields cannot be set at all using :c:type:`PyType_Spec` and - :c:type:`PyType_Slot`: - - * :c:member:`~PyTypeObject.tp_dict` - * :c:member:`~PyTypeObject.tp_mro` - * :c:member:`~PyTypeObject.tp_cache` - * :c:member:`~PyTypeObject.tp_subclasses` - * :c:member:`~PyTypeObject.tp_weaklist` + The following “offset†fields cannot be set using :c:type:`PyType_Slot`: + + * :c:member:`~PyTypeObject.tp_weaklistoffset` + (use :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead if possible) + * :c:member:`~PyTypeObject.tp_dictoffset` + (use :c:macro:`Py_TPFLAGS_MANAGED_DICT` instead if possible) + * :c:member:`~PyTypeObject.tp_vectorcall_offset` + (use ``"__vectorcalloffset__"`` in + :ref:`PyMemberDef `) + + If it is not possible to switch to a ``MANAGED`` flag (for example, + for vectorcall or to support Python older than 3.12), specify the + offset in :c:member:`Py_tp_members `. + See :ref:`PyMemberDef documentation ` + for details. + + The following fields cannot be set at all when creating a heap type: + * :c:member:`~PyTypeObject.tp_vectorcall` - * :c:member:`~PyTypeObject.tp_weaklistoffset` - (use :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` instead) - * :c:member:`~PyTypeObject.tp_dictoffset` - (use :c:macro:`Py_TPFLAGS_MANAGED_DICT` instead) - * :c:member:`~PyTypeObject.tp_vectorcall_offset` - (see :ref:`PyMemberDef `) + (use :c:member:`~PyTypeObject.tp_new` and/or + :c:member:`~PyTypeObject.tp_init`) + + * Internal fields: + :c:member:`~PyTypeObject.tp_dict`, + :c:member:`~PyTypeObject.tp_mro`, + :c:member:`~PyTypeObject.tp_cache`, + :c:member:`~PyTypeObject.tp_subclasses`, and + :c:member:`~PyTypeObject.tp_weaklist`. Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be problematic on some platforms. From 1a7afa7ef41a79a923b93f9a58da7a4e3d359d4f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:24:28 +0200 Subject: [PATCH 1012/1206] [3.12] gh-110703: Add asyncio.wait_for() change notes for 3.11 (GH-110818) (#110826) gh-110703: Add asyncio.wait_for() change notes for 3.11 (GH-110818) * Remove redundant versionchanged * Add missing versionchanged * Update Doc/library/asyncio-task.rst --------- (cherry picked from commit f81e36f700ac8c6766207fcf3bc2540692af868b) Co-authored-by: paskozdilar <53006174+paskozdilar@users.noreply.github.com> Co-authored-by: Kumar Aditya --- Doc/library/asyncio-task.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index f488aa73a62f02..a3ea050c0713ac 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -764,9 +764,6 @@ Timeouts If the wait is cancelled, the future *aw* is also cancelled. - .. versionchanged:: 3.10 - Removed the *loop* parameter. - .. _asyncio_example_waitfor: Example:: @@ -797,6 +794,9 @@ Timeouts .. versionchanged:: 3.10 Removed the *loop* parameter. + .. versionchanged:: 3.11 + Raises :exc:`TimeoutError` instead of :exc:`asyncio.TimeoutError`. + Waiting Primitives ================== From 1c44f881c73f1eabe70704dd5acc6ad98d9156bd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:41:43 +0200 Subject: [PATCH 1013/1206] [3.12] gh-110815: Improve tests for PyArg_ParseTupleAndKeywords() (GH-110817) (GH-110825) (cherry picked from commit 548ce0923b9ef93b1c1df59f8febc4bb3daff28a) Co-authored-by: Serhiy Storchaka --- Lib/test/test_capi/test_getargs.py | 36 ++++++++++++++++++--- Modules/_testcapi/getargs.c | 52 ++++++++++++++++++++++-------- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_capi/test_getargs.py b/Lib/test/test_capi/test_getargs.py index ec4100e976e50d..2546c6e326c51b 100644 --- a/Lib/test/test_capi/test_getargs.py +++ b/Lib/test/test_capi/test_getargs.py @@ -55,6 +55,8 @@ LLONG_MIN = -2**63 ULLONG_MAX = 2**64-1 +NULL = None + class Index: def __index__(self): return 99 @@ -1241,6 +1243,27 @@ def test_parse_tuple_and_keywords(self): self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, (), {}, '', [42]) + def test_basic(self): + parse = _testcapi.parse_tuple_and_keywords + + self.assertEqual(parse((), {'a': 1}, 'O', ['a']), (1,)) + self.assertEqual(parse((), {}, '|O', ['a']), (NULL,)) + self.assertEqual(parse((1, 2), {}, 'OO', ['a', 'b']), (1, 2)) + self.assertEqual(parse((1,), {'b': 2}, 'OO', ['a', 'b']), (1, 2)) + self.assertEqual(parse((), {'a': 1, 'b': 2}, 'OO', ['a', 'b']), (1, 2)) + self.assertEqual(parse((), {'b': 2}, '|OO', ['a', 'b']), (NULL, 2)) + + with self.assertRaisesRegex(TypeError, + "function missing required argument 'a'"): + parse((), {}, 'O', ['a']) + with self.assertRaisesRegex(TypeError, + "'b' is an invalid keyword argument"): + parse((), {'b': 1}, '|O', ['a']) + with self.assertRaisesRegex(TypeError, + fr"argument for function given by name \('a'\) " + fr"and position \(1\)"): + parse((1,), {'a': 2}, 'O|O', ['a', 'b']) + def test_bad_use(self): # Test handling invalid format and keywords in # PyArg_ParseTupleAndKeywords() @@ -1268,20 +1291,23 @@ def test_bad_use(self): def test_positional_only(self): parse = _testcapi.parse_tuple_and_keywords - parse((1, 2, 3), {}, 'OOO', ['', '', 'a']) - parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a']) + self.assertEqual(parse((1, 2, 3), {}, 'OOO', ['', '', 'a']), (1, 2, 3)) + self.assertEqual(parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a']), (1, 2, 3)) with self.assertRaisesRegex(TypeError, r'function takes at least 2 positional arguments \(1 given\)'): parse((1,), {'a': 3}, 'OOO', ['', '', 'a']) - parse((1,), {}, 'O|OO', ['', '', 'a']) + self.assertEqual(parse((1,), {}, 'O|OO', ['', '', 'a']), + (1, NULL, NULL)) with self.assertRaisesRegex(TypeError, r'function takes at least 1 positional argument \(0 given\)'): parse((), {}, 'O|OO', ['', '', 'a']) - parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a']) + self.assertEqual(parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a']), + (1, 2, 3)) with self.assertRaisesRegex(TypeError, r'function takes exactly 2 positional arguments \(1 given\)'): parse((1,), {'a': 3}, 'OO$O', ['', '', 'a']) - parse((1,), {}, 'O|O$O', ['', '', 'a']) + self.assertEqual(parse((1,), {}, 'O|O$O', ['', '', 'a']), + (1, NULL, NULL)) with self.assertRaisesRegex(TypeError, r'function takes at least 1 positional argument \(0 given\)'): parse((), {}, 'O|O$O', ['', '', 'a']) diff --git a/Modules/_testcapi/getargs.c b/Modules/_testcapi/getargs.c index aa201319950de7..b47cc906dad84a 100644 --- a/Modules/_testcapi/getargs.c +++ b/Modules/_testcapi/getargs.c @@ -15,9 +15,9 @@ parse_tuple_and_keywords(PyObject *self, PyObject *args) const char *sub_format; PyObject *sub_keywords; - double buffers[8][4]; /* double ensures alignment where necessary */ - PyObject *converted[8]; - char *keywords[8 + 1]; /* space for NULL at end */ +#define MAX_PARAMS 8 + double buffers[MAX_PARAMS][4]; /* double ensures alignment where necessary */ + char *keywords[MAX_PARAMS + 1]; /* space for NULL at end */ PyObject *return_value = NULL; @@ -37,11 +37,10 @@ parse_tuple_and_keywords(PyObject *self, PyObject *args) } memset(buffers, 0, sizeof(buffers)); - memset(converted, 0, sizeof(converted)); memset(keywords, 0, sizeof(keywords)); Py_ssize_t size = PySequence_Fast_GET_SIZE(sub_keywords); - if (size > 8) { + if (size > MAX_PARAMS) { PyErr_SetString(PyExc_ValueError, "parse_tuple_and_keywords: too many keywords in sub_keywords"); goto exit; @@ -49,29 +48,56 @@ parse_tuple_and_keywords(PyObject *self, PyObject *args) for (Py_ssize_t i = 0; i < size; i++) { PyObject *o = PySequence_Fast_GET_ITEM(sub_keywords, i); - if (!PyUnicode_FSConverter(o, (void *)(converted + i))) { + if (PyUnicode_Check(o)) { + keywords[i] = (char *)PyUnicode_AsUTF8(o); + if (keywords[i] == NULL) { + goto exit; + } + } + else if (PyBytes_Check(o)) { + keywords[i] = PyBytes_AS_STRING(o); + } + else { PyErr_Format(PyExc_ValueError, "parse_tuple_and_keywords: " - "could not convert keywords[%zd] to narrow string", i); + "keywords must be str or bytes", i); goto exit; } - keywords[i] = PyBytes_AS_STRING(converted[i]); } + assert(MAX_PARAMS == 8); int result = PyArg_ParseTupleAndKeywords(sub_args, sub_kwargs, sub_format, keywords, buffers + 0, buffers + 1, buffers + 2, buffers + 3, buffers + 4, buffers + 5, buffers + 6, buffers + 7); if (result) { - return_value = Py_NewRef(Py_None); + int objects_only = 1; + for (const char *f = sub_format; *f; f++) { + if (Py_ISALNUM(*f) && strchr("OSUY", *f) == NULL) { + objects_only = 0; + break; + } + } + if (objects_only) { + return_value = PyTuple_New(size); + if (return_value == NULL) { + goto exit; + } + for (Py_ssize_t i = 0; i < size; i++) { + PyObject *arg = *(PyObject **)(buffers + i); + if (arg == NULL) { + arg = Py_None; + } + PyTuple_SET_ITEM(return_value, i, Py_NewRef(arg)); + } + } + else { + return_value = Py_NewRef(Py_None); + } } exit: - size = sizeof(converted) / sizeof(converted[0]); - for (Py_ssize_t i = 0; i < size; i++) { - Py_XDECREF(converted[i]); - } return return_value; } From 49da1176654dc69bfab253b82e297828d9a82648 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:59:12 +0200 Subject: [PATCH 1014/1206] [3.12] Bump sphinx-lint to 0.7.0 (GH-110830) (#110833) Bump sphinx-lint to 0.7.0 (GH-110830) (cherry picked from commit 0ed2329a1627fc8ae97b009114cd960c25567f75) Co-authored-by: Alex Waygood --- .pre-commit-config.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5b362a7c9d4c8a..4835b641b3106a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,13 +24,12 @@ repos: types_or: [c, inc, python, rst] - repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v0.6.8 + rev: v0.7.0 hooks: - id: sphinx-lint - args: [--enable=default-role] + args: [--enable=default-role, -j1] files: ^Doc/|^Misc/NEWS.d/next/ types: [rst] - require_serial: true - repo: meta hooks: From 0102faf0cac107fd4d0fde9902560c7cf0a3be9d Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 13 Oct 2023 20:05:03 +0300 Subject: [PATCH 1015/1206] [3.12] gh-108303: Move all inspect test files to `test_inspect/` (GH-109607) (#110732) (cherry picked from commit 732532b0af9d1b5c7ae4932526c8d20d86c15507) --- Lib/test/libregrtest/findtests.py | 1 + Lib/test/test_import/__init__.py | 1 - Lib/test/test_inspect/__init__.py | 6 ++++++ Lib/test/{ => test_inspect}/inspect_fodder.py | 0 Lib/test/{ => test_inspect}/inspect_fodder2.py | 0 .../{ => test_inspect}/inspect_stock_annotations.py | 0 .../inspect_stringized_annotations.py | 0 .../inspect_stringized_annotations_2.py | 0 Lib/test/{ => test_inspect}/test_inspect.py | 11 ++++++----- Lib/test/test_tokenize.py | 2 +- Makefile.pre.in | 1 + 11 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 Lib/test/test_inspect/__init__.py rename Lib/test/{ => test_inspect}/inspect_fodder.py (100%) rename Lib/test/{ => test_inspect}/inspect_fodder2.py (100%) rename Lib/test/{ => test_inspect}/inspect_stock_annotations.py (100%) rename Lib/test/{ => test_inspect}/inspect_stringized_annotations.py (100%) rename Lib/test/{ => test_inspect}/inspect_stringized_annotations_2.py (100%) rename Lib/test/{ => test_inspect}/test_inspect.py (99%) diff --git a/Lib/test/libregrtest/findtests.py b/Lib/test/libregrtest/findtests.py index 96cc3e0d021184..caf2872cfc9a18 100644 --- a/Lib/test/libregrtest/findtests.py +++ b/Lib/test/libregrtest/findtests.py @@ -20,6 +20,7 @@ "test_concurrent_futures", "test_future_stmt", "test_gdb", + "test_inspect", "test_multiprocessing_fork", "test_multiprocessing_forkserver", "test_multiprocessing_spawn", diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 8994f146b0155f..67904cf4256691 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1,5 +1,4 @@ import builtins -import contextlib import errno import glob import json diff --git a/Lib/test/test_inspect/__init__.py b/Lib/test/test_inspect/__init__.py new file mode 100644 index 00000000000000..f2a39a3fe29c7f --- /dev/null +++ b/Lib/test/test_inspect/__init__.py @@ -0,0 +1,6 @@ +import os +from test import support + + +def load_tests(*args): + return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/inspect_fodder.py b/Lib/test/test_inspect/inspect_fodder.py similarity index 100% rename from Lib/test/inspect_fodder.py rename to Lib/test/test_inspect/inspect_fodder.py diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/test_inspect/inspect_fodder2.py similarity index 100% rename from Lib/test/inspect_fodder2.py rename to Lib/test/test_inspect/inspect_fodder2.py diff --git a/Lib/test/inspect_stock_annotations.py b/Lib/test/test_inspect/inspect_stock_annotations.py similarity index 100% rename from Lib/test/inspect_stock_annotations.py rename to Lib/test/test_inspect/inspect_stock_annotations.py diff --git a/Lib/test/inspect_stringized_annotations.py b/Lib/test/test_inspect/inspect_stringized_annotations.py similarity index 100% rename from Lib/test/inspect_stringized_annotations.py rename to Lib/test/test_inspect/inspect_stringized_annotations.py diff --git a/Lib/test/inspect_stringized_annotations_2.py b/Lib/test/test_inspect/inspect_stringized_annotations_2.py similarity index 100% rename from Lib/test/inspect_stringized_annotations_2.py rename to Lib/test/test_inspect/inspect_stringized_annotations_2.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect/test_inspect.py similarity index 99% rename from Lib/test/test_inspect.py rename to Lib/test/test_inspect/test_inspect.py index 6f260c9a71782c..4a96502abffb66 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -31,12 +31,13 @@ from test.support.import_helper import DirsOnSysPath, ready_to_import from test.support.os_helper import TESTFN from test.support.script_helper import assert_python_ok, assert_python_failure -from test import inspect_fodder as mod -from test import inspect_fodder2 as mod2 from test import support -from test import inspect_stock_annotations -from test import inspect_stringized_annotations -from test import inspect_stringized_annotations_2 + +from . import inspect_fodder as mod +from . import inspect_fodder2 as mod2 +from . import inspect_stock_annotations +from . import inspect_stringized_annotations +from . import inspect_stringized_annotations_2 # Functions tested in this suite: diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index b8d069a87843e4..57fc149b6a4fa8 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1908,7 +1908,7 @@ def test_random_files(self): # TODO: Remove this once we can untokenize PEP 701 syntax testfiles.remove(os.path.join(tempdir, "test_fstring.py")) - for f in ('buffer', 'builtin', 'fileio', 'inspect', 'os', 'platform', 'sys'): + for f in ('buffer', 'builtin', 'fileio', 'os', 'platform', 'sys'): testfiles.remove(os.path.join(tempdir, "test_%s.py") % f) if not support.is_resource_enabled("cpu"): diff --git a/Makefile.pre.in b/Makefile.pre.in index aa2ac012affc18..0cb9db744433a9 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2141,6 +2141,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_email/data \ test/test_future_stmt \ test/test_gdb \ + test/test_inspect \ test/test_import \ test/test_import/data \ test/test_import/data/circular_imports \ From 0164832db57bab00a1d14db17e4aa24079961fd0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 14 Oct 2023 08:18:14 +0200 Subject: [PATCH 1016/1206] [3.12] gh-110392: Fix tty functions (GH-110642) (GH-110853) * tty.setraw() and tty.setcbreak() previously returned partially modified list of the original tty attributes. Now they return the correct list of the original tty attributes * tty.cfmakeraw() and tty.cfmakecbreak() now make a copy of the list of special characters before modifying it. (cherry picked from commit 84e2096fbdea880799f2fdb3f0992a8961106bed) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tty.py | 8 ++++++-- Lib/tty.py | 2 ++ .../2023-10-10-17-56-41.gh-issue-110392.6g6CnP.rst | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-10-17-56-41.gh-issue-110392.6g6CnP.rst diff --git a/Lib/test/test_tty.py b/Lib/test/test_tty.py index 6993047492b5ec..af20864aac361e 100644 --- a/Lib/test/test_tty.py +++ b/Lib/test/test_tty.py @@ -58,7 +58,9 @@ def test_cfmakecbreak(self): self.assertEqual(mode[5], self.mode[5]) def test_setraw(self): - mode = tty.setraw(self.fd) + mode0 = termios.tcgetattr(self.fd) + mode1 = tty.setraw(self.fd) + self.assertEqual(mode1, mode0) mode2 = termios.tcgetattr(self.fd) self.check_raw(mode2) mode3 = tty.setraw(self.fd, termios.TCSANOW) @@ -67,7 +69,9 @@ def test_setraw(self): tty.setraw(fd=self.fd, when=termios.TCSANOW) def test_setcbreak(self): - mode = tty.setcbreak(self.fd) + mode0 = termios.tcgetattr(self.fd) + mode1 = tty.setcbreak(self.fd) + self.assertEqual(mode1, mode0) mode2 = termios.tcgetattr(self.fd) self.check_cbreak(mode2) mode3 = tty.setcbreak(self.fd, termios.TCSANOW) diff --git a/Lib/tty.py b/Lib/tty.py index 7d916029ff2ce9..283e5c334f5751 100644 --- a/Lib/tty.py +++ b/Lib/tty.py @@ -39,6 +39,7 @@ def cfmakeraw(mode): # Case B: MIN>0, TIME=0 # A pending read shall block until MIN (here 1) bytes are received, # or a signal is received. + mode[CC] = list(mode[CC]) mode[CC][VMIN] = 1 mode[CC][VTIME] = 0 @@ -54,6 +55,7 @@ def cfmakecbreak(mode): # Case B: MIN>0, TIME=0 # A pending read shall block until MIN (here 1) bytes are received, # or a signal is received. + mode[CC] = list(mode[CC]) mode[CC][VMIN] = 1 mode[CC][VTIME] = 0 diff --git a/Misc/NEWS.d/next/Library/2023-10-10-17-56-41.gh-issue-110392.6g6CnP.rst b/Misc/NEWS.d/next/Library/2023-10-10-17-56-41.gh-issue-110392.6g6CnP.rst new file mode 100644 index 00000000000000..47e4e8ee1f058d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-10-17-56-41.gh-issue-110392.6g6CnP.rst @@ -0,0 +1,4 @@ +Fix :func:`tty.setraw` and :func:`tty.setcbreak`: previously they returned +partially modified list of the original tty attributes. +:func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` now make a copy of the +list of special characters before modifying it. From 12b9cb80be5e75e63bae7c63053f334705d2de90 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 14 Oct 2023 08:28:34 +0200 Subject: [PATCH 1017/1206] [3.12] gh-101100: Fix sphinx warnings in `usage/cmdline.rst` (GH-110841) (#110855) Co-authored-by: Nikita Sobolev --- Doc/tools/.nitignore | 1 - Doc/using/cmdline.rst | 17 +++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 5c3165c18e36a7..bda6c98fd08589 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -162,7 +162,6 @@ Doc/reference/import.rst Doc/reference/simple_stmts.rst Doc/tutorial/datastructures.rst Doc/tutorial/introduction.rst -Doc/using/cmdline.rst Doc/using/windows.rst Doc/whatsnew/2.0.rst Doc/whatsnew/2.1.rst diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index f68a2251f06d4a..6b60b286061144 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -103,7 +103,7 @@ source. :option:`-I` option can be used to run the script in isolated mode where :data:`sys.path` contains neither the current directory nor the user's - site-packages directory. All :envvar:`PYTHON*` environment variables are + site-packages directory. All ``PYTHON*`` environment variables are ignored, too. Many standard library modules contain code that is invoked on their execution @@ -161,7 +161,7 @@ source. :option:`-I` option can be used to run the script in isolated mode where :data:`sys.path` contains neither the script's directory nor the user's - site-packages directory. All :envvar:`PYTHON*` environment variables are + site-packages directory. All ``PYTHON*`` environment variables are ignored, too. .. audit-event:: cpython.run_file filename @@ -280,7 +280,7 @@ Miscellaneous options .. option:: -E - Ignore all :envvar:`PYTHON*` environment variables, e.g. + Ignore all ``PYTHON*`` environment variables, e.g. :envvar:`PYTHONPATH` and :envvar:`PYTHONHOME`, that might be set. See also the :option:`-P` and :option:`-I` (isolated) options. @@ -303,7 +303,7 @@ Miscellaneous options and :option:`-s` options. In isolated mode :data:`sys.path` contains neither the script's directory nor - the user's site-packages directory. All :envvar:`PYTHON*` environment + the user's site-packages directory. All ``PYTHON*`` environment variables are ignored, too. Further restrictions may be imposed to prevent the user from injecting malicious code. @@ -362,7 +362,7 @@ Miscellaneous options randomization is enabled by default. On previous versions of Python, this option turns on hash randomization, - so that the :meth:`__hash__` values of str and bytes objects + so that the :meth:`~object.__hash__` values of str and bytes objects are "salted" with an unpredictable random value. Although they remain constant within an individual Python process, they are not predictable between repeated invocations of Python. @@ -851,9 +851,10 @@ conflict. If this environment variable is set to a non-empty string, :func:`faulthandler.enable` is called at startup: install a handler for - :const:`SIGSEGV`, :const:`SIGFPE`, :const:`SIGABRT`, :const:`SIGBUS` and - :const:`SIGILL` signals to dump the Python traceback. This is equivalent to - :option:`-X` ``faulthandler`` option. + :const:`~signal.SIGSEGV`, :const:`~signal.SIGFPE`, + :const:`~signal.SIGABRT`, :const:`~signal.SIGBUS` and + :const:`~signal.SIGILL` signals to dump the Python traceback. + This is equivalent to :option:`-X` ``faulthandler`` option. .. versionadded:: 3.3 From a2cc9a4c3a979380b343239c5bb929a1eaada427 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 14 Oct 2023 08:42:19 +0200 Subject: [PATCH 1018/1206] [3.12] gh-109747: Improve errors for unsupported look-behind patterns (GH-109859) (GH-110859) Now re.error is raised instead of OverflowError or RuntimeError for too large width of look-behind pattern. The limit is increased to 2**32-1 (was 2**31-1). (cherry picked from commit e2b3d831fd2824d8a5713e3ed2a64aad0fb6b62d) Co-authored-by: Serhiy Storchaka --- Lib/re/_compiler.py | 4 +++- Lib/re/_parser.py | 13 ++++++++--- Lib/test/test_re.py | 23 +++++++++++++++++++ ...-09-25-20-05-41.gh-issue-109747._cRJH8.rst | 3 +++ Modules/_sre/sre.c | 2 -- Modules/_sre/sre_lib.h | 14 +++++------ 6 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-25-20-05-41.gh-issue-109747._cRJH8.rst diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index d8e0d2fdefdcca..285c21936f2cfa 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -149,6 +149,8 @@ def _compile(code, pattern, flags): emit(0) # look ahead else: lo, hi = av[1].getwidth() + if lo > MAXCODE: + raise error("looks too much behind") if lo != hi: raise error("look-behind requires fixed-width pattern") emit(lo) # look behind @@ -549,7 +551,7 @@ def _compile_info(code, pattern, flags): else: emit(MAXCODE) prefix = prefix[:MAXCODE] - emit(min(hi, MAXCODE)) + emit(hi) # add literal prefix if prefix: emit(len(prefix)) # length diff --git a/Lib/re/_parser.py b/Lib/re/_parser.py index 74bda2f103083c..4a492b79e84eb8 100644 --- a/Lib/re/_parser.py +++ b/Lib/re/_parser.py @@ -68,6 +68,10 @@ TYPE_FLAGS = SRE_FLAG_ASCII | SRE_FLAG_LOCALE | SRE_FLAG_UNICODE GLOBAL_FLAGS = SRE_FLAG_DEBUG | SRE_FLAG_TEMPLATE +# Maximal value returned by SubPattern.getwidth(). +# Must be larger than MAXREPEAT, MAXCODE and sys.maxsize. +MAXWIDTH = 1 << 64 + class State: # keeps track of state for parsing def __init__(self): @@ -178,7 +182,7 @@ def getwidth(self): lo = hi = 0 for op, av in self.data: if op is BRANCH: - i = MAXREPEAT - 1 + i = MAXWIDTH j = 0 for av in av[1]: l, h = av.getwidth() @@ -197,7 +201,10 @@ def getwidth(self): elif op in _REPEATCODES: i, j = av[2].getwidth() lo = lo + i * av[0] - hi = hi + j * av[1] + if av[1] == MAXREPEAT and j: + hi = MAXWIDTH + else: + hi = hi + j * av[1] elif op in _UNITCODES: lo = lo + 1 hi = hi + 1 @@ -217,7 +224,7 @@ def getwidth(self): hi = hi + j elif op is SUCCESS: break - self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) + self.width = min(lo, MAXWIDTH), min(hi, MAXWIDTH) return self.width class Tokenizer: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 382ef0b33cc05f..656429ba8522a1 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1799,6 +1799,29 @@ def test_repeat_minmax_overflow(self): self.assertRaises(OverflowError, re.compile, r".{%d,}?" % 2**128) self.assertRaises(OverflowError, re.compile, r".{%d,%d}" % (2**129, 2**128)) + def test_look_behind_overflow(self): + string = "x" * 2_500_000 + p1 = r"(?<=((.{%d}){%d}){%d})" + p2 = r"(?)', diff --git a/Misc/NEWS.d/next/Library/2023-09-25-20-05-41.gh-issue-109747._cRJH8.rst b/Misc/NEWS.d/next/Library/2023-09-25-20-05-41.gh-issue-109747._cRJH8.rst new file mode 100644 index 00000000000000..b64ba627897a1a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-25-20-05-41.gh-issue-109747._cRJH8.rst @@ -0,0 +1,3 @@ +Improve errors for unsupported look-behind patterns. Now re.error is raised +instead of OverflowError or RuntimeError for too large width of look-behind +pattern. diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index ace2e9bd7cc2f6..0547390454a30e 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -2024,8 +2024,6 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) GET_SKIP; GET_ARG; /* 0 for lookahead, width for lookbehind */ code--; /* Back up over arg to simplify math below */ - if (arg & 0x80000000) - FAIL; /* Width too large */ /* Stop 1 before the end; we check the SUCCESS below */ if (_validate_inner(code+1, code+skip-2, groups)) FAIL; diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h index f8d556b2db85c0..95c1ada908d222 100644 --- a/Modules/_sre/sre_lib.h +++ b/Modules/_sre/sre_lib.h @@ -589,8 +589,8 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) /* optimization info block */ /* <1=skip> <2=flags> <3=min> ... */ if (pattern[3] && (uintptr_t)(end - ptr) < pattern[3]) { - TRACE(("reject (got %zd chars, need %zd)\n", - end - ptr, (Py_ssize_t) pattern[3])); + TRACE(("reject (got %tu chars, need %zu)\n", + end - ptr, (size_t) pattern[3])); RETURN_FAILURE; } pattern += pattern[1] + 1; @@ -1507,7 +1507,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) /* */ TRACE(("|%p|%p|ASSERT %d\n", pattern, ptr, pattern[1])); - if (ptr - (SRE_CHAR *)state->beginning < (Py_ssize_t)pattern[1]) + if ((uintptr_t)(ptr - (SRE_CHAR *)state->beginning) < pattern[1]) RETURN_FAILURE; state->ptr = ptr - pattern[1]; DO_JUMP0(JUMP_ASSERT, jump_assert, pattern+2); @@ -1520,7 +1520,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) /* */ TRACE(("|%p|%p|ASSERT_NOT %d\n", pattern, ptr, pattern[1])); - if (ptr - (SRE_CHAR *)state->beginning >= (Py_ssize_t)pattern[1]) { + if ((uintptr_t)(ptr - (SRE_CHAR *)state->beginning) >= pattern[1]) { state->ptr = ptr - pattern[1]; LASTMARK_SAVE(); if (state->repeat) @@ -1655,9 +1655,9 @@ SRE(search)(SRE_STATE* state, SRE_CODE* pattern) flags = pattern[2]; - if (pattern[3] && end - ptr < (Py_ssize_t)pattern[3]) { - TRACE(("reject (got %u chars, need %u)\n", - (unsigned int)(end - ptr), pattern[3])); + if (pattern[3] && (uintptr_t)(end - ptr) < pattern[3]) { + TRACE(("reject (got %tu chars, need %zu)\n", + end - ptr, (size_t) pattern[3])); return 0; } if (pattern[3] > 1) { From 9a623221748f0abdbbb9a450fcfba70eb5847741 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 14 Oct 2023 08:43:59 +0200 Subject: [PATCH 1019/1206] [3.12] gh-107705: Fix file leak in test_tkinter in the C locale (GH-110507) (GH-110857) (cherry picked from commit ca0f3d858d069231ce7c5b382790a774f385b467) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tkinter/test_images.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tkinter/test_images.py b/Lib/test/test_tkinter/test_images.py index 9f49d6efc7892e..cc1ed286011af0 100644 --- a/Lib/test/test_tkinter/test_images.py +++ b/Lib/test/test_tkinter/test_images.py @@ -357,13 +357,18 @@ def test_get(self): self.assertRaises(tkinter.TclError, image.get, 15, 16) def test_write(self): + filename = os_helper.TESTFN + import locale + if locale.getlocale()[0] is None: + # Tcl uses Latin1 in the C locale + filename = os_helper.TESTFN_ASCII image = self.create() - self.addCleanup(os_helper.unlink, os_helper.TESTFN) + self.addCleanup(os_helper.unlink, filename) - image.write(os_helper.TESTFN) + image.write(filename) image2 = tkinter.PhotoImage('::img::test2', master=self.root, format='ppm', - file=os_helper.TESTFN) + file=filename) self.assertEqual(str(image2), '::img::test2') self.assertEqual(image2.type(), 'photo') self.assertEqual(image2.width(), 16) @@ -371,10 +376,10 @@ def test_write(self): self.assertEqual(image2.get(0, 0), image.get(0, 0)) self.assertEqual(image2.get(15, 8), image.get(15, 8)) - image.write(os_helper.TESTFN, format='gif', from_coords=(4, 6, 6, 9)) + image.write(filename, format='gif', from_coords=(4, 6, 6, 9)) image3 = tkinter.PhotoImage('::img::test3', master=self.root, format='gif', - file=os_helper.TESTFN) + file=filename) self.assertEqual(str(image3), '::img::test3') self.assertEqual(image3.type(), 'photo') self.assertEqual(image3.width(), 2) From 7c3e8e5af03413f56914ee2b49eb1f40eed942e8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 14 Oct 2023 10:20:24 +0300 Subject: [PATCH 1020/1206] [3.12] gh-110628: Add tests for PyLong C API (GH-110629) (GH-110854) (cherry picked from commit 9d40ebf1902812fad6aa85ede7b6f1fdff3c1291) --- Lib/test/test_capi/test_long.py | 366 ++++++++++++++++++++++++++++++++ Modules/_testcapi/long.c | 222 +++++++++++++++++++ Modules/_testcapimodule.c | 2 + 3 files changed, 590 insertions(+) diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py index 8928fd94a1d6a3..8261cc3829dc14 100644 --- a/Lib/test/test_capi/test_long.py +++ b/Lib/test/test_capi/test_long.py @@ -6,6 +6,25 @@ # Skip this test if the _testcapi module isn't available. _testcapi = import_helper.import_module('_testcapi') +NULL = None + +class IntSubclass(int): + pass + +class Index: + def __init__(self, value): + self.value = value + + def __index__(self): + return self.value + +# use __index__(), not __int__() +class MyIndexAndInt: + def __index__(self): + return 10 + def __int__(self): + return 22 + class LongTests(unittest.TestCase): @@ -34,6 +53,353 @@ def test_compact_known(self): self.assertEqual(_testcapi.call_long_compact_api(sys.maxsize), (False, -1)) + def test_long_check(self): + # Test PyLong_Check() + check = _testcapi.pylong_check + self.assertTrue(check(1)) + self.assertTrue(check(123456789012345678901234567890)) + self.assertTrue(check(-1)) + self.assertTrue(check(True)) + self.assertTrue(check(IntSubclass(1))) + self.assertFalse(check(1.0)) + self.assertFalse(check(object())) + # CRASHES check(NULL) + + def test_long_checkexact(self): + # Test PyLong_CheckExact() + check = _testcapi.pylong_checkexact + self.assertTrue(check(1)) + self.assertTrue(check(123456789012345678901234567890)) + self.assertTrue(check(-1)) + self.assertFalse(check(True)) + self.assertFalse(check(IntSubclass(1))) + self.assertFalse(check(1.0)) + self.assertFalse(check(object())) + # CRASHES check(NULL) + + def test_long_fromdouble(self): + # Test PyLong_FromDouble() + fromdouble = _testcapi.pylong_fromdouble + float_max = sys.float_info.max + for value in (5.0, 5.1, 5.9, -5.1, -5.9, 0.0, -0.0, float_max, -float_max): + with self.subTest(value=value): + self.assertEqual(fromdouble(value), int(value)) + self.assertRaises(OverflowError, fromdouble, float('inf')) + self.assertRaises(OverflowError, fromdouble, float('-inf')) + self.assertRaises(ValueError, fromdouble, float('nan')) + + def test_long_fromvoidptr(self): + # Test PyLong_FromVoidPtr() + fromvoidptr = _testcapi.pylong_fromvoidptr + obj = object() + x = fromvoidptr(obj) + y = fromvoidptr(NULL) + self.assertIsInstance(x, int) + self.assertGreaterEqual(x, 0) + self.assertIsInstance(y, int) + self.assertEqual(y, 0) + self.assertNotEqual(x, y) + + def test_long_fromstring(self): + # Test PyLong_FromString() + fromstring = _testcapi.pylong_fromstring + self.assertEqual(fromstring(b'123', 10), (123, 3)) + self.assertEqual(fromstring(b'cafe', 16), (0xcafe, 4)) + self.assertEqual(fromstring(b'xyz', 36), (44027, 3)) + self.assertEqual(fromstring(b'123', 0), (123, 3)) + self.assertEqual(fromstring(b'0xcafe', 0), (0xcafe, 6)) + self.assertRaises(ValueError, fromstring, b'cafe', 0) + self.assertEqual(fromstring(b'-123', 10), (-123, 4)) + self.assertEqual(fromstring(b' -123 ', 10), (-123, 6)) + self.assertEqual(fromstring(b'1_23', 10), (123, 4)) + self.assertRaises(ValueError, fromstring, b'- 123', 10) + self.assertRaises(ValueError, fromstring, b'', 10) + + self.assertRaises(ValueError, fromstring, b'123', 1) + self.assertRaises(ValueError, fromstring, b'123', -1) + self.assertRaises(ValueError, fromstring, b'123', 37) + + self.assertRaises(ValueError, fromstring, '١٢٣٤٥٦٧٨٩٠'.encode(), 0) + self.assertRaises(ValueError, fromstring, '١٢٣٤٥٦٧٨٩٠'.encode(), 16) + + self.assertEqual(fromstring(b'123\x00', 0), (123, 3)) + self.assertEqual(fromstring(b'123\x00456', 0), (123, 3)) + self.assertEqual(fromstring(b'123\x00', 16), (0x123, 3)) + self.assertEqual(fromstring(b'123\x00456', 16), (0x123, 3)) + + # CRASHES fromstring(NULL, 0) + # CRASHES fromstring(NULL, 16) + + def test_long_fromunicodeobject(self): + # Test PyLong_FromUnicodeObject() + fromunicodeobject = _testcapi.pylong_fromunicodeobject + self.assertEqual(fromunicodeobject('123', 10), 123) + self.assertEqual(fromunicodeobject('cafe', 16), 0xcafe) + self.assertEqual(fromunicodeobject('xyz', 36), 44027) + self.assertEqual(fromunicodeobject('123', 0), 123) + self.assertEqual(fromunicodeobject('0xcafe', 0), 0xcafe) + self.assertRaises(ValueError, fromunicodeobject, 'cafe', 0) + self.assertEqual(fromunicodeobject('-123', 10), -123) + self.assertEqual(fromunicodeobject(' -123 ', 10), -123) + self.assertEqual(fromunicodeobject('1_23', 10), 123) + self.assertRaises(ValueError, fromunicodeobject, '- 123', 10) + self.assertRaises(ValueError, fromunicodeobject, '', 10) + + self.assertRaises(ValueError, fromunicodeobject, '123', 1) + self.assertRaises(ValueError, fromunicodeobject, '123', -1) + self.assertRaises(ValueError, fromunicodeobject, '123', 37) + + self.assertEqual(fromunicodeobject('١٢٣٤٥٦٧٨٩٠', 0), 1234567890) + self.assertEqual(fromunicodeobject('١٢٣٤٥٦٧٨٩٠', 16), 0x1234567890) + + self.assertRaises(ValueError, fromunicodeobject, '123\x00', 0) + self.assertRaises(ValueError, fromunicodeobject, '123\x00456', 0) + self.assertRaises(ValueError, fromunicodeobject, '123\x00', 16) + self.assertRaises(ValueError, fromunicodeobject, '123\x00456', 16) + + # CRASHES fromunicodeobject(NULL, 0) + # CRASHES fromunicodeobject(NULL, 16) + + def test_long_aslong(self): + # Test PyLong_AsLong() and PyLong_FromLong() + aslong = _testcapi.pylong_aslong + from _testcapi import LONG_MIN, LONG_MAX + # round trip (object -> long -> object) + for value in (LONG_MIN, LONG_MAX, -1, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(aslong(value), value) + + self.assertEqual(aslong(IntSubclass(42)), 42) + self.assertEqual(aslong(Index(42)), 42) + self.assertEqual(aslong(MyIndexAndInt()), 10) + + self.assertRaises(OverflowError, aslong, LONG_MIN - 1) + self.assertRaises(OverflowError, aslong, LONG_MAX + 1) + self.assertRaises(TypeError, aslong, 1.0) + self.assertRaises(TypeError, aslong, b'2') + self.assertRaises(TypeError, aslong, '3') + self.assertRaises(SystemError, aslong, NULL) + + def test_long_aslongandoverflow(self): + # Test PyLong_AsLongAndOverflow() + aslongandoverflow = _testcapi.pylong_aslongandoverflow + from _testcapi import LONG_MIN, LONG_MAX + # round trip (object -> long -> object) + for value in (LONG_MIN, LONG_MAX, -1, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(aslongandoverflow(value), (value, 0)) + + self.assertEqual(aslongandoverflow(IntSubclass(42)), (42, 0)) + self.assertEqual(aslongandoverflow(Index(42)), (42, 0)) + self.assertEqual(aslongandoverflow(MyIndexAndInt()), (10, 0)) + + self.assertEqual(aslongandoverflow(LONG_MIN - 1), (-1, -1)) + self.assertEqual(aslongandoverflow(LONG_MAX + 1), (-1, 1)) + # CRASHES aslongandoverflow(1.0) + # CRASHES aslongandoverflow(NULL) + + def test_long_asunsignedlong(self): + # Test PyLong_AsUnsignedLong() and PyLong_FromUnsignedLong() + asunsignedlong = _testcapi.pylong_asunsignedlong + from _testcapi import ULONG_MAX + # round trip (object -> unsigned long -> object) + for value in (ULONG_MAX, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(asunsignedlong(value), value) + + self.assertEqual(asunsignedlong(IntSubclass(42)), 42) + self.assertRaises(TypeError, asunsignedlong, Index(42)) + self.assertRaises(TypeError, asunsignedlong, MyIndexAndInt()) + + self.assertRaises(OverflowError, asunsignedlong, -1) + self.assertRaises(OverflowError, asunsignedlong, ULONG_MAX + 1) + self.assertRaises(TypeError, asunsignedlong, 1.0) + self.assertRaises(TypeError, asunsignedlong, b'2') + self.assertRaises(TypeError, asunsignedlong, '3') + self.assertRaises(SystemError, asunsignedlong, NULL) + + def test_long_asunsignedlongmask(self): + # Test PyLong_AsUnsignedLongMask() + asunsignedlongmask = _testcapi.pylong_asunsignedlongmask + from _testcapi import ULONG_MAX + # round trip (object -> unsigned long -> object) + for value in (ULONG_MAX, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(asunsignedlongmask(value), value) + + self.assertEqual(asunsignedlongmask(IntSubclass(42)), 42) + self.assertEqual(asunsignedlongmask(Index(42)), 42) + self.assertEqual(asunsignedlongmask(MyIndexAndInt()), 10) + + self.assertEqual(asunsignedlongmask(-1), ULONG_MAX) + self.assertEqual(asunsignedlongmask(ULONG_MAX + 1), 0) + self.assertRaises(TypeError, asunsignedlongmask, 1.0) + self.assertRaises(TypeError, asunsignedlongmask, b'2') + self.assertRaises(TypeError, asunsignedlongmask, '3') + self.assertRaises(SystemError, asunsignedlongmask, NULL) + + def test_long_aslonglong(self): + # Test PyLong_AsLongLong() and PyLong_FromLongLong() + aslonglong = _testcapi.pylong_aslonglong + from _testcapi import LLONG_MIN, LLONG_MAX + # round trip (object -> long long -> object) + for value in (LLONG_MIN, LLONG_MAX, -1, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(aslonglong(value), value) + + self.assertEqual(aslonglong(IntSubclass(42)), 42) + self.assertEqual(aslonglong(Index(42)), 42) + self.assertEqual(aslonglong(MyIndexAndInt()), 10) + + self.assertRaises(OverflowError, aslonglong, LLONG_MIN - 1) + self.assertRaises(OverflowError, aslonglong, LLONG_MAX + 1) + self.assertRaises(TypeError, aslonglong, 1.0) + self.assertRaises(TypeError, aslonglong, b'2') + self.assertRaises(TypeError, aslonglong, '3') + self.assertRaises(SystemError, aslonglong, NULL) + + def test_long_aslonglongandoverflow(self): + # Test PyLong_AsLongLongAndOverflow() + aslonglongandoverflow = _testcapi.pylong_aslonglongandoverflow + from _testcapi import LLONG_MIN, LLONG_MAX + # round trip (object -> long long -> object) + for value in (LLONG_MIN, LLONG_MAX, -1, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(aslonglongandoverflow(value), (value, 0)) + + self.assertEqual(aslonglongandoverflow(IntSubclass(42)), (42, 0)) + self.assertEqual(aslonglongandoverflow(Index(42)), (42, 0)) + self.assertEqual(aslonglongandoverflow(MyIndexAndInt()), (10, 0)) + + self.assertEqual(aslonglongandoverflow(LLONG_MIN - 1), (-1, -1)) + self.assertEqual(aslonglongandoverflow(LLONG_MAX + 1), (-1, 1)) + # CRASHES aslonglongandoverflow(1.0) + # CRASHES aslonglongandoverflow(NULL) + + def test_long_asunsignedlonglong(self): + # Test PyLong_AsUnsignedLongLong() and PyLong_FromUnsignedLongLong() + asunsignedlonglong = _testcapi.pylong_asunsignedlonglong + from _testcapi import ULLONG_MAX + # round trip (object -> unsigned long long -> object) + for value in (ULLONG_MAX, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(asunsignedlonglong(value), value) + + self.assertEqual(asunsignedlonglong(IntSubclass(42)), 42) + self.assertRaises(TypeError, asunsignedlonglong, Index(42)) + self.assertRaises(TypeError, asunsignedlonglong, MyIndexAndInt()) + + self.assertRaises(OverflowError, asunsignedlonglong, -1) + self.assertRaises(OverflowError, asunsignedlonglong, ULLONG_MAX + 1) + self.assertRaises(TypeError, asunsignedlonglong, 1.0) + self.assertRaises(TypeError, asunsignedlonglong, b'2') + self.assertRaises(TypeError, asunsignedlonglong, '3') + self.assertRaises(SystemError, asunsignedlonglong, NULL) + + def test_long_asunsignedlonglongmask(self): + # Test PyLong_AsUnsignedLongLongMask() + asunsignedlonglongmask = _testcapi.pylong_asunsignedlonglongmask + from _testcapi import ULLONG_MAX + # round trip (object -> unsigned long long -> object) + for value in (ULLONG_MAX, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(asunsignedlonglongmask(value), value) + + self.assertEqual(asunsignedlonglongmask(IntSubclass(42)), 42) + self.assertEqual(asunsignedlonglongmask(Index(42)), 42) + self.assertEqual(asunsignedlonglongmask(MyIndexAndInt()), 10) + + self.assertEqual(asunsignedlonglongmask(-1), ULLONG_MAX) + self.assertEqual(asunsignedlonglongmask(ULLONG_MAX + 1), 0) + self.assertRaises(TypeError, asunsignedlonglongmask, 1.0) + self.assertRaises(TypeError, asunsignedlonglongmask, b'2') + self.assertRaises(TypeError, asunsignedlonglongmask, '3') + self.assertRaises(SystemError, asunsignedlonglongmask, NULL) + + def test_long_as_ssize_t(self): + # Test PyLong_AsSsize_t() and PyLong_FromSsize_t() + as_ssize_t = _testcapi.pylong_as_ssize_t + from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX + # round trip (object -> Py_ssize_t -> object) + for value in (PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(as_ssize_t(value), value) + + self.assertEqual(as_ssize_t(IntSubclass(42)), 42) + self.assertRaises(TypeError, as_ssize_t, Index(42)) + self.assertRaises(TypeError, as_ssize_t, MyIndexAndInt()) + + self.assertRaises(OverflowError, as_ssize_t, PY_SSIZE_T_MIN - 1) + self.assertRaises(OverflowError, as_ssize_t, PY_SSIZE_T_MAX + 1) + self.assertRaises(TypeError, as_ssize_t, 1.0) + self.assertRaises(TypeError, as_ssize_t, b'2') + self.assertRaises(TypeError, as_ssize_t, '3') + self.assertRaises(SystemError, as_ssize_t, NULL) + + def test_long_as_size_t(self): + # Test PyLong_AsSize_t() and PyLong_FromSize_t() + as_size_t = _testcapi.pylong_as_size_t + from _testcapi import SIZE_MAX + # round trip (object -> size_t -> object) + for value in (SIZE_MAX, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(as_size_t(value), value) + + self.assertEqual(as_size_t(IntSubclass(42)), 42) + self.assertRaises(TypeError, as_size_t, Index(42)) + self.assertRaises(TypeError, as_size_t, MyIndexAndInt()) + + self.assertRaises(OverflowError, as_size_t, -1) + self.assertRaises(OverflowError, as_size_t, SIZE_MAX + 1) + self.assertRaises(TypeError, as_size_t, 1.0) + self.assertRaises(TypeError, as_size_t, b'2') + self.assertRaises(TypeError, as_size_t, '3') + self.assertRaises(SystemError, as_size_t, NULL) + + def test_long_asdouble(self): + # Test PyLong_AsDouble() + asdouble = _testcapi.pylong_asdouble + MAX = int(sys.float_info.max) + for value in (-MAX, MAX, -1, 0, 1, 1234): + with self.subTest(value=value): + self.assertEqual(asdouble(value), float(value)) + self.assertIsInstance(asdouble(value), float) + + self.assertEqual(asdouble(IntSubclass(42)), 42.0) + self.assertRaises(TypeError, asdouble, Index(42)) + self.assertRaises(TypeError, asdouble, MyIndexAndInt()) + + self.assertRaises(OverflowError, asdouble, 2 * MAX) + self.assertRaises(OverflowError, asdouble, -2 * MAX) + self.assertRaises(TypeError, asdouble, 1.0) + self.assertRaises(TypeError, asdouble, b'2') + self.assertRaises(TypeError, asdouble, '3') + self.assertRaises(SystemError, asdouble, NULL) + + def test_long_asvoidptr(self): + # Test PyLong_AsVoidPtr() + fromvoidptr = _testcapi.pylong_fromvoidptr + asvoidptr = _testcapi.pylong_asvoidptr + obj = object() + x = fromvoidptr(obj) + y = fromvoidptr(NULL) + self.assertIs(asvoidptr(x), obj) + self.assertIs(asvoidptr(y), NULL) + self.assertIs(asvoidptr(IntSubclass(x)), obj) + + # negative values + M = (1 << _testcapi.SIZEOF_VOID_P * 8) + if x >= M//2: + self.assertIs(asvoidptr(x - M), obj) + if y >= M//2: + self.assertIs(asvoidptr(y - M), NULL) + + self.assertRaises(TypeError, asvoidptr, Index(x)) + self.assertRaises(TypeError, asvoidptr, object()) + self.assertRaises(OverflowError, asvoidptr, 2**1000) + self.assertRaises(OverflowError, asvoidptr, -2**1000) + # CRASHES asvoidptr(NULL) + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 61dd96596dad1c..213c676e5c081c 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -1,4 +1,6 @@ +#define PY_SSIZE_T_CLEAN #include "parts.h" +#include "util.h" static PyObject * @@ -546,6 +548,208 @@ check_long_compact_api(PyObject *self, PyObject *arg) return Py_BuildValue("in", is_compact, value); } +static PyObject * +pylong_check(PyObject *module, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyLong_Check(obj)); +} + +static PyObject * +pylong_checkexact(PyObject *module, PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyLong_CheckExact(obj)); +} + +static PyObject * +pylong_fromdouble(PyObject *module, PyObject *arg) +{ + double value; + if (!PyArg_Parse(arg, "d", &value)) { + return NULL; + } + return PyLong_FromDouble(value); +} + +static PyObject * +pylong_fromstring(PyObject *module, PyObject *args) +{ + const char *str; + Py_ssize_t len; + int base; + char *end = UNINITIALIZED_PTR; + if (!PyArg_ParseTuple(args, "z#i", &str, &len, &base)) { + return NULL; + } + + PyObject *result = PyLong_FromString(str, &end, base); + if (result == NULL) { + // XXX 'end' is not always set. + return NULL; + } + return Py_BuildValue("Nn", result, (Py_ssize_t)(end - str)); +} + +static PyObject * +pylong_fromunicodeobject(PyObject *module, PyObject *args) +{ + PyObject *unicode; + int base; + if (!PyArg_ParseTuple(args, "Oi", &unicode, &base)) { + return NULL; + } + + NULLABLE(unicode); + return PyLong_FromUnicodeObject(unicode, base); +} + +static PyObject * +pylong_fromvoidptr(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + return PyLong_FromVoidPtr((void *)arg); +} + +static PyObject * +pylong_aslong(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + long value = PyLong_AsLong(arg); + if (value == -1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromLong(value); +} + +static PyObject * +pylong_aslongandoverflow(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + int overflow = UNINITIALIZED_INT; + long value = PyLong_AsLongAndOverflow(arg, &overflow); + if (value == -1 && PyErr_Occurred()) { + assert(overflow == -1); + return NULL; + } + return Py_BuildValue("li", value, overflow); +} + +static PyObject * +pylong_asunsignedlong(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + unsigned long value = PyLong_AsUnsignedLong(arg); + if (value == (unsigned long)-1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromUnsignedLong(value); +} + +static PyObject * +pylong_asunsignedlongmask(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + unsigned long value = PyLong_AsUnsignedLongMask(arg); + if (value == (unsigned long)-1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromUnsignedLong(value); +} + +static PyObject * +pylong_aslonglong(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + long long value = PyLong_AsLongLong(arg); + if (value == -1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromLongLong(value); +} + +static PyObject * +pylong_aslonglongandoverflow(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + int overflow = UNINITIALIZED_INT; + long long value = PyLong_AsLongLongAndOverflow(arg, &overflow); + if (value == -1 && PyErr_Occurred()) { + assert(overflow == -1); + return NULL; + } + return Py_BuildValue("Li", value, overflow); +} + +static PyObject * +pylong_asunsignedlonglong(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + unsigned long long value = PyLong_AsUnsignedLongLong(arg); + if (value == (unsigned long long)-1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromUnsignedLongLong(value); +} + +static PyObject * +pylong_asunsignedlonglongmask(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + unsigned long long value = PyLong_AsUnsignedLongLongMask(arg); + if (value == (unsigned long long)-1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromUnsignedLongLong(value); +} + +static PyObject * +pylong_as_ssize_t(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + Py_ssize_t value = PyLong_AsSsize_t(arg); + if (value == -1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromSsize_t(value); +} + +static PyObject * +pylong_as_size_t(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + size_t value = PyLong_AsSize_t(arg); + if (value == (size_t)-1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromSize_t(value); +} + +static PyObject * +pylong_asdouble(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + double value = PyLong_AsDouble(arg); + if (value == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyFloat_FromDouble(value); +} + +static PyObject * +pylong_asvoidptr(PyObject *module, PyObject *arg) +{ + NULLABLE(arg); + void *value = PyLong_AsVoidPtr(arg); + if (value == NULL) { + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_NONE; + } + return Py_NewRef((PyObject *)value); +} + static PyMethodDef test_methods[] = { {"test_long_and_overflow", test_long_and_overflow, METH_NOARGS}, {"test_long_api", test_long_api, METH_NOARGS}, @@ -556,6 +760,24 @@ static PyMethodDef test_methods[] = { {"test_long_numbits", test_long_numbits, METH_NOARGS}, {"test_longlong_api", test_longlong_api, METH_NOARGS}, {"call_long_compact_api", check_long_compact_api, METH_O}, + {"pylong_check", pylong_check, METH_O}, + {"pylong_checkexact", pylong_checkexact, METH_O}, + {"pylong_fromdouble", pylong_fromdouble, METH_O}, + {"pylong_fromstring", pylong_fromstring, METH_VARARGS}, + {"pylong_fromunicodeobject", pylong_fromunicodeobject, METH_VARARGS}, + {"pylong_fromvoidptr", pylong_fromvoidptr, METH_O}, + {"pylong_aslong", pylong_aslong, METH_O}, + {"pylong_aslongandoverflow", pylong_aslongandoverflow, METH_O}, + {"pylong_asunsignedlong", pylong_asunsignedlong, METH_O}, + {"pylong_asunsignedlongmask", pylong_asunsignedlongmask, METH_O}, + {"pylong_aslonglong", pylong_aslonglong, METH_O}, + {"pylong_aslonglongandoverflow", pylong_aslonglongandoverflow, METH_O}, + {"pylong_asunsignedlonglong", pylong_asunsignedlonglong, METH_O}, + {"pylong_asunsignedlonglongmask", pylong_asunsignedlonglongmask, METH_O}, + {"pylong_as_ssize_t", pylong_as_ssize_t, METH_O}, + {"pylong_as_size_t", pylong_as_size_t, METH_O}, + {"pylong_asdouble", pylong_asdouble, METH_O}, + {"pylong_asvoidptr", pylong_asvoidptr, METH_O}, {NULL}, }; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index fd48984a7c45e7..6af1e388cb8342 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3978,7 +3978,9 @@ PyInit__testcapi(void) PyModule_AddObject(m, "ULLONG_MAX", PyLong_FromUnsignedLongLong(ULLONG_MAX)); PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyLong_FromSsize_t(PY_SSIZE_T_MAX)); PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyLong_FromSsize_t(PY_SSIZE_T_MIN)); + PyModule_AddObject(m, "SIZE_MAX", PyLong_FromSize_t(SIZE_MAX)); PyModule_AddObject(m, "SIZEOF_WCHAR_T", PyLong_FromSsize_t(sizeof(wchar_t))); + PyModule_AddObject(m, "SIZEOF_VOID_P", PyLong_FromSsize_t(sizeof(void*))); PyModule_AddObject(m, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t))); PyModule_AddObject(m, "Py_Version", PyLong_FromUnsignedLong(Py_Version)); Py_INCREF(&PyInstanceMethod_Type); From 9786959a115ebc55c35e59546a94978bae09fc5d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 14 Oct 2023 09:58:31 +0200 Subject: [PATCH 1021/1206] [3.12] gh-110715: Add missing import in zipfile (gh-110822) (gh-110861) gh-110715: Add missing import in zipfile (gh-110822) (cherry picked from commit 4110cfec1233139b4e7c63459ba465ab80554e3e) Co-authored-by: Kirill Podoprigora --- Lib/test/test_zipfile/test_core.py | 25 ++++++++++++++++++------- Lib/zipfile/__init__.py | 1 + 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 9960259c4cde0c..c2cc2c827ca695 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -1769,13 +1769,9 @@ def test_write_unicode_filenames(self): self.assertEqual(zf.filelist[0].filename, "foo.txt") self.assertEqual(zf.filelist[1].filename, "\xf6.txt") - @requires_zlib() - def test_read_zipfile_containing_unicode_path_extra_field(self): + def create_zipfile_with_extra_data(self, filename, extra_data_name): with zipfile.ZipFile(TESTFN, mode='w') as zf: - # create a file with a non-ASCII name - filename = 'ì´ë¦„.txt' - filename_encoded = filename.encode('utf-8') - + filename_encoded = filename.encode("utf-8") # create a ZipInfo object with Unicode path extra field zip_info = zipfile.ZipInfo(filename) @@ -1785,7 +1781,7 @@ def test_read_zipfile_containing_unicode_path_extra_field(self): import zlib filename_crc = struct.pack(' Date: Sat, 14 Oct 2023 12:27:08 +0200 Subject: [PATCH 1022/1206] [3.12] remove redundant call to attach_loop in watcher (GH-110847) (#110867) (cherry picked from commit 596589104fe5a4d90cb145b2cc69b71cc9aa9f07) Co-authored-by: Thomas Grainger --- Lib/asyncio/unix_events.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index f985f9776ed0aa..0a618c42d2d257 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -1461,8 +1461,6 @@ def _init_watcher(self): self._watcher = PidfdChildWatcher() else: self._watcher = ThreadedChildWatcher() - if threading.current_thread() is threading.main_thread(): - self._watcher.attach_loop(self._local._loop) def set_event_loop(self, loop): """Set the event loop. From 744f752f04cd5ad0b18670cd66a82a9b042df0ad Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 14 Oct 2023 16:28:58 +0200 Subject: [PATCH 1023/1206] [3.12] gh-101100: Fix sphinx warnings in `library/time.rst` (GH-110862) (#110877) gh-101100: Fix sphinx warnings in `library/time.rst` (GH-110862) (cherry picked from commit 12deda763359d46d4eccbb8991afed71fa31a68b) Co-authored-by: Nikita Sobolev --- Doc/library/time.rst | 93 ++++++++++++++++++++++++++++---------------- Doc/tools/.nitignore | 1 - 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst index 9f23a6fc7d5341..93eceed29d2b5b 100644 --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -71,8 +71,8 @@ An explanation of some terminology and conventions is in order. * On the other hand, the precision of :func:`.time` and :func:`sleep` is better than their Unix equivalents: times are expressed as floating point numbers, :func:`.time` returns the most accurate time available (using Unix - :c:func:`gettimeofday` where available), and :func:`sleep` will accept a time - with a nonzero fraction (Unix :c:func:`select` is used to implement this, where + :c:func:`!gettimeofday` where available), and :func:`sleep` will accept a time + with a nonzero fraction (Unix :c:func:`!select` is used to implement this, where available). * The time value as returned by :func:`gmtime`, :func:`localtime`, and @@ -84,12 +84,14 @@ An explanation of some terminology and conventions is in order. See :class:`struct_time` for a description of these objects. .. versionchanged:: 3.3 - The :class:`struct_time` type was extended to provide the :attr:`tm_gmtoff` - and :attr:`tm_zone` attributes when platform supports corresponding + The :class:`struct_time` type was extended to provide + the :attr:`~struct_time.tm_gmtoff` and :attr:`~struct_time.tm_zone` + attributes when platform supports corresponding ``struct tm`` members. .. versionchanged:: 3.6 - The :class:`struct_time` attributes :attr:`tm_gmtoff` and :attr:`tm_zone` + The :class:`struct_time` attributes + :attr:`~struct_time.tm_gmtoff` and :attr:`~struct_time.tm_zone` are now available on all platforms. * Use the following functions to convert between time representations: @@ -496,6 +498,8 @@ Functions When used with the :func:`strptime` function, the ``%p`` directive only affects the output hour field if the ``%I`` directive is used to parse the hour. + .. _leap-second: + (2) The range really is ``0`` to ``61``; value ``60`` is valid in timestamps representing `leap seconds`_ and value ``61`` is supported @@ -566,32 +570,55 @@ Functions tuple` interface: values can be accessed by index and by attribute name. The following values are present: - +-------+-------------------+---------------------------------+ - | Index | Attribute | Values | - +=======+===================+=================================+ - | 0 | :attr:`tm_year` | (for example, 1993) | - +-------+-------------------+---------------------------------+ - | 1 | :attr:`tm_mon` | range [1, 12] | - +-------+-------------------+---------------------------------+ - | 2 | :attr:`tm_mday` | range [1, 31] | - +-------+-------------------+---------------------------------+ - | 3 | :attr:`tm_hour` | range [0, 23] | - +-------+-------------------+---------------------------------+ - | 4 | :attr:`tm_min` | range [0, 59] | - +-------+-------------------+---------------------------------+ - | 5 | :attr:`tm_sec` | range [0, 61]; see **(2)** in | - | | | :func:`strftime` description | - +-------+-------------------+---------------------------------+ - | 6 | :attr:`tm_wday` | range [0, 6], Monday is 0 | - +-------+-------------------+---------------------------------+ - | 7 | :attr:`tm_yday` | range [1, 366] | - +-------+-------------------+---------------------------------+ - | 8 | :attr:`tm_isdst` | 0, 1 or -1; see below | - +-------+-------------------+---------------------------------+ - | N/A | :attr:`tm_zone` | abbreviation of timezone name | - +-------+-------------------+---------------------------------+ - | N/A | :attr:`tm_gmtoff` | offset east of UTC in seconds | - +-------+-------------------+---------------------------------+ + .. list-table:: + + * - Index + - Attribute + - Values + + * - 0 + - .. attribute:: tm_year + - (for example, 1993) + + * - 1 + - .. attribute:: tm_mon + - range [1, 12] + + * - 2 + - .. attribute:: tm_day + - range [1, 31] + + * - 3 + - .. attribute:: tm_hour + - range [0, 23] + + * - 4 + - .. attribute:: tm_min + - range [0, 59] + + * - 5 + - .. attribute:: tm_sec + - range [0, 61]; see :ref:`Note (2) ` in :func:`strftime` + + * - 6 + - .. attribute:: tm_wday + - range [0, 6]; Monday is 0 + + * - 7 + - .. attribute:: tm_yday + - range [1, 366] + + * - 8 + - .. attribute:: tm_isdst + - 0, 1 or -1; see below + + * - N/A + - .. attribute:: tm_zone + - abbreviation of timezone name + + * - N/A + - .. attribute:: tm_gmtoff + - offset east of UTC in seconds Note that unlike the C structure, the month value is a range of [1, 12], not [0, 11]. @@ -912,8 +939,8 @@ Timezone Constants For the above Timezone constants (:data:`altzone`, :data:`daylight`, :data:`timezone`, and :data:`tzname`), the value is determined by the timezone rules in effect at module load time or the last time :func:`tzset` is called and may be incorrect - for times in the past. It is recommended to use the :attr:`tm_gmtoff` and - :attr:`tm_zone` results from :func:`localtime` to obtain timezone information. + for times in the past. It is recommended to use the :attr:`~struct_time.tm_gmtoff` and + :attr:`~struct_time.tm_zone` results from :func:`localtime` to obtain timezone information. .. seealso:: diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index bda6c98fd08589..431609b1d0f9c0 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -131,7 +131,6 @@ Doc/library/telnetlib.rst Doc/library/tempfile.rst Doc/library/termios.rst Doc/library/test.rst -Doc/library/time.rst Doc/library/tkinter.rst Doc/library/tkinter.scrolledtext.rst Doc/library/tkinter.tix.rst From b6755d81d45a1d75e3d2485386dabf7bdde66632 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sun, 15 Oct 2023 04:38:40 +0300 Subject: [PATCH 1024/1206] [3.12] gh-109216: Fix possible memory leak in `BUILD_MAP` (#109324) --- ...-09-11-12-41-42.gh-issue-109216.60QOSb.rst | 2 + Python/bytecodes.c | 3 - Python/generated_cases.c.h | 501 +++++++++--------- 3 files changed, 251 insertions(+), 255 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-11-12-41-42.gh-issue-109216.60QOSb.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-11-12-41-42.gh-issue-109216.60QOSb.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-11-12-41-42.gh-issue-109216.60QOSb.rst new file mode 100644 index 00000000000000..f36310fc5f8064 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-11-12-41-42.gh-issue-109216.60QOSb.rst @@ -0,0 +1,2 @@ +Fix possible memory leak in :opcode:`BUILD_MAP`. + diff --git a/Python/bytecodes.c b/Python/bytecodes.c index dfebaaa300fc8a..e20b9ff1b3ef5e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1543,9 +1543,6 @@ dummy_func( values, 2, values+1, 2, oparg); - if (map == NULL) - goto error; - DECREF_INPUTS(); ERROR_IF(map == NULL, error); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e4cff7bdc3384b..5ebfe0e455116f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2129,16 +2129,13 @@ values, 2, values+1, 2, oparg); - if (map == NULL) - goto error; - - #line 2136 "Python/generated_cases.c.h" + #line 2133 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1550 "Python/bytecodes.c" + #line 1547 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2142 "Python/generated_cases.c.h" + #line 2139 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2146,7 +2143,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1554 "Python/bytecodes.c" + #line 1551 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2186,7 +2183,7 @@ Py_DECREF(ann_dict); } } - #line 2190 "Python/generated_cases.c.h" + #line 2187 "Python/generated_cases.c.h" DISPATCH(); } @@ -2194,7 +2191,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1596 "Python/bytecodes.c" + #line 1593 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2204,14 +2201,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2208 "Python/generated_cases.c.h" + #line 2205 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1606 "Python/bytecodes.c" + #line 1603 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2215 "Python/generated_cases.c.h" + #line 2212 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2219,7 +2216,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1610 "Python/bytecodes.c" + #line 1607 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2227,12 +2224,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2231 "Python/generated_cases.c.h" + #line 2228 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1618 "Python/bytecodes.c" + #line 1615 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2236 "Python/generated_cases.c.h" + #line 2233 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2240,17 +2237,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1624 "Python/bytecodes.c" + #line 1621 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2249 "Python/generated_cases.c.h" + #line 2246 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1629 "Python/bytecodes.c" + #line 1626 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2254 "Python/generated_cases.c.h" + #line 2251 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2260,26 +2257,26 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1636 "Python/bytecodes.c" + #line 1633 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2270 "Python/generated_cases.c.h" + #line 2267 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1645 "Python/bytecodes.c" + #line 1642 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2283 "Python/generated_cases.c.h" + #line 2280 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2290,7 +2287,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1659 "Python/bytecodes.c" + #line 1656 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2332,16 +2329,16 @@ } } } - #line 2336 "Python/generated_cases.c.h" + #line 2333 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1701 "Python/bytecodes.c" + #line 1698 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2345 "Python/generated_cases.c.h" + #line 2342 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2356,20 +2353,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1708 "Python/bytecodes.c" + #line 1705 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2367 "Python/generated_cases.c.h" + #line 2364 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1715 "Python/bytecodes.c" + #line 1712 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2373 "Python/generated_cases.c.h" + #line 2370 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2384,7 +2381,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1719 "Python/bytecodes.c" + #line 1716 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2407,7 +2404,7 @@ res = res2; res2 = NULL; } - #line 2411 "Python/generated_cases.c.h" + #line 2408 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2421,7 +2418,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1758 "Python/bytecodes.c" + #line 1755 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2455,9 +2452,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2459 "Python/generated_cases.c.h" + #line 2456 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1792 "Python/bytecodes.c" + #line 1789 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2466,12 +2463,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2470 "Python/generated_cases.c.h" + #line 2467 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1801 "Python/bytecodes.c" + #line 1798 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2475 "Python/generated_cases.c.h" + #line 2472 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2485,7 +2482,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1806 "Python/bytecodes.c" + #line 1803 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2498,7 +2495,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2502 "Python/generated_cases.c.h" + #line 2499 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2513,7 +2510,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1822 "Python/bytecodes.c" + #line 1819 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2526,7 +2523,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2530 "Python/generated_cases.c.h" + #line 2527 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2541,7 +2538,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1838 "Python/bytecodes.c" + #line 1835 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2568,7 +2565,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2572 "Python/generated_cases.c.h" + #line 2569 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2583,7 +2580,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1868 "Python/bytecodes.c" + #line 1865 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2593,7 +2590,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2597 "Python/generated_cases.c.h" + #line 2594 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2608,7 +2605,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1881 "Python/bytecodes.c" + #line 1878 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2620,7 +2617,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2624 "Python/generated_cases.c.h" + #line 2621 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2634,7 +2631,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1896 "Python/bytecodes.c" + #line 1893 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2658,7 +2655,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2662 "Python/generated_cases.c.h" + #line 2659 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2666,7 +2663,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1922 "Python/bytecodes.c" + #line 1919 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2692,7 +2689,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2696 "Python/generated_cases.c.h" + #line 2693 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2700,7 +2697,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1950 "Python/bytecodes.c" + #line 1947 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2718,7 +2715,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2722 "Python/generated_cases.c.h" + #line 2719 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2729,7 +2726,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1970 "Python/bytecodes.c" + #line 1967 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2768,7 +2765,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2772 "Python/generated_cases.c.h" + #line 2769 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2779,7 +2776,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2011 "Python/bytecodes.c" + #line 2008 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2789,7 +2786,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2793 "Python/generated_cases.c.h" + #line 2790 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2801,7 +2798,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2030 "Python/bytecodes.c" + #line 2027 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2814,12 +2811,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2818 "Python/generated_cases.c.h" + #line 2815 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2043 "Python/bytecodes.c" + #line 2040 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2823 "Python/generated_cases.c.h" + #line 2820 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2830,7 +2827,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2047 "Python/bytecodes.c" + #line 2044 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2841,7 +2838,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2845 "Python/generated_cases.c.h" + #line 2842 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2852,7 +2849,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2061 "Python/bytecodes.c" + #line 2058 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2867,7 +2864,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2871 "Python/generated_cases.c.h" + #line 2868 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2878,7 +2875,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2079 "Python/bytecodes.c" + #line 2076 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2890,7 +2887,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2894 "Python/generated_cases.c.h" + #line 2891 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2901,14 +2898,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2093 "Python/bytecodes.c" + #line 2090 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2907 "Python/generated_cases.c.h" + #line 2904 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2095 "Python/bytecodes.c" + #line 2092 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2912 "Python/generated_cases.c.h" + #line 2909 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2918,15 +2915,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2099 "Python/bytecodes.c" + #line 2096 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2924 "Python/generated_cases.c.h" + #line 2921 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2101 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2930 "Python/generated_cases.c.h" + #line 2927 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2937,12 +2934,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2106 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2943 "Python/generated_cases.c.h" + #line 2940 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2108 "Python/bytecodes.c" + #line 2105 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2950,10 +2947,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2954 "Python/generated_cases.c.h" + #line 2951 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2116 "Python/bytecodes.c" + #line 2113 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2962,7 +2959,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2966 "Python/generated_cases.c.h" + #line 2963 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2972,21 +2969,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2127 "Python/bytecodes.c" + #line 2124 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2979 "Python/generated_cases.c.h" + #line 2976 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2130 "Python/bytecodes.c" + #line 2127 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2986 "Python/generated_cases.c.h" + #line 2983 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2135 "Python/bytecodes.c" + #line 2132 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2990 "Python/generated_cases.c.h" + #line 2987 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2995,15 +2992,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2139 "Python/bytecodes.c" + #line 2136 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3002 "Python/generated_cases.c.h" + #line 2999 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2142 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3007 "Python/generated_cases.c.h" + #line 3004 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3012,29 +3009,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2146 "Python/bytecodes.c" + #line 2143 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3020 "Python/generated_cases.c.h" + #line 3017 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2152 "Python/bytecodes.c" + #line 2149 "Python/bytecodes.c" JUMPBY(oparg); - #line 3029 "Python/generated_cases.c.h" + #line 3026 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2156 "Python/bytecodes.c" + #line 2153 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3038 "Python/generated_cases.c.h" + #line 3035 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3042,15 +3039,15 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2162 "Python/bytecodes.c" + #line 2159 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3052 "Python/generated_cases.c.h" + #line 3049 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2168 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3058,22 +3055,22 @@ if (err < 0) goto pop_1_error; } } - #line 3062 "Python/generated_cases.c.h" + #line 3059 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2178 "Python/bytecodes.c" + #line 2175 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3075 "Python/generated_cases.c.h" + #line 3072 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2184 "Python/bytecodes.c" + #line 2181 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3081,63 +3078,63 @@ if (err < 0) goto pop_1_error; } } - #line 3085 "Python/generated_cases.c.h" + #line 3082 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2194 "Python/bytecodes.c" + #line 2191 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3094 "Python/generated_cases.c.h" + #line 3091 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2196 "Python/bytecodes.c" + #line 2193 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3099 "Python/generated_cases.c.h" + #line 3096 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2201 "Python/bytecodes.c" + #line 2198 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3111 "Python/generated_cases.c.h" + #line 3108 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2206 "Python/bytecodes.c" + #line 2203 "Python/bytecodes.c" } - #line 3115 "Python/generated_cases.c.h" + #line 3112 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2210 "Python/bytecodes.c" + #line 2207 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3128 "Python/generated_cases.c.h" + #line 3125 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2219 "Python/bytecodes.c" + #line 2216 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3141 "Python/generated_cases.c.h" + #line 3138 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3148,16 +3145,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2227 "Python/bytecodes.c" + #line 2224 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3157 "Python/generated_cases.c.h" + #line 3154 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2232 "Python/bytecodes.c" + #line 2229 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3165,7 +3162,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3169 "Python/generated_cases.c.h" + #line 3166 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3174,10 +3171,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2242 "Python/bytecodes.c" + #line 2239 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3181 "Python/generated_cases.c.h" + #line 3178 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3187,10 +3184,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2248 "Python/bytecodes.c" + #line 2245 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3194 "Python/generated_cases.c.h" + #line 3191 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3201,11 +3198,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2254 "Python/bytecodes.c" + #line 2251 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3209 "Python/generated_cases.c.h" + #line 3206 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3214,14 +3211,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2260 "Python/bytecodes.c" + #line 2257 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3221 "Python/generated_cases.c.h" + #line 3218 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2263 "Python/bytecodes.c" + #line 2260 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3225 "Python/generated_cases.c.h" + #line 3222 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3229,7 +3226,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2267 "Python/bytecodes.c" + #line 2264 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3252,11 +3249,11 @@ if (iter == NULL) { goto error; } - #line 3256 "Python/generated_cases.c.h" + #line 3253 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2290 "Python/bytecodes.c" + #line 2287 "Python/bytecodes.c" } - #line 3260 "Python/generated_cases.c.h" + #line 3257 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3267,7 +3264,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2309 "Python/bytecodes.c" + #line 2306 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3298,7 +3295,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3302 "Python/generated_cases.c.h" + #line 3299 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3306,7 +3303,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2342 "Python/bytecodes.c" + #line 2339 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3332,14 +3329,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3336 "Python/generated_cases.c.h" + #line 3333 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2370 "Python/bytecodes.c" + #line 2367 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3359,7 +3356,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3363 "Python/generated_cases.c.h" + #line 3360 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3369,7 +3366,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2392 "Python/bytecodes.c" + #line 2389 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3389,7 +3386,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3393 "Python/generated_cases.c.h" + #line 3390 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3399,7 +3396,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2414 "Python/bytecodes.c" + #line 2411 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3417,7 +3414,7 @@ if (next == NULL) { goto error; } - #line 3421 "Python/generated_cases.c.h" + #line 3418 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3426,7 +3423,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2434 "Python/bytecodes.c" + #line 2431 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3442,14 +3439,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3446 "Python/generated_cases.c.h" + #line 3443 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2452 "Python/bytecodes.c" + #line 2449 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3472,16 +3469,16 @@ Py_DECREF(enter); goto error; } - #line 3476 "Python/generated_cases.c.h" + #line 3473 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2475 "Python/bytecodes.c" + #line 2472 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3485 "Python/generated_cases.c.h" + #line 3482 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3493,7 +3490,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2485 "Python/bytecodes.c" + #line 2482 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3519,16 +3516,16 @@ Py_DECREF(enter); goto error; } - #line 3523 "Python/generated_cases.c.h" + #line 3520 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2511 "Python/bytecodes.c" + #line 2508 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3532 "Python/generated_cases.c.h" + #line 3529 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3540,7 +3537,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2520 "Python/bytecodes.c" + #line 2517 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3566,7 +3563,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3570 "Python/generated_cases.c.h" + #line 3567 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3575,7 +3572,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2548 "Python/bytecodes.c" + #line 2545 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3585,7 +3582,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3589 "Python/generated_cases.c.h" + #line 3586 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3599,7 +3596,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2560 "Python/bytecodes.c" + #line 2557 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3616,7 +3613,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3620 "Python/generated_cases.c.h" + #line 3617 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3630,7 +3627,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2579 "Python/bytecodes.c" + #line 2576 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3640,7 +3637,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3644 "Python/generated_cases.c.h" + #line 3641 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3654,7 +3651,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2591 "Python/bytecodes.c" + #line 2588 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3668,7 +3665,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3672 "Python/generated_cases.c.h" + #line 3669 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3677,16 +3674,16 @@ } TARGET(KW_NAMES) { - #line 2607 "Python/bytecodes.c" + #line 2604 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3685 "Python/generated_cases.c.h" + #line 3682 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2613 "Python/bytecodes.c" + #line 2610 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3699,7 +3696,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3703 "Python/generated_cases.c.h" + #line 3700 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3709,7 +3706,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2658 "Python/bytecodes.c" + #line 2655 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3791,7 +3788,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3795 "Python/generated_cases.c.h" + #line 3792 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3803,7 +3800,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2746 "Python/bytecodes.c" + #line 2743 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3813,7 +3810,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3817 "Python/generated_cases.c.h" + #line 3814 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3822,7 +3819,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2758 "Python/bytecodes.c" + #line 2755 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3848,7 +3845,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3852 "Python/generated_cases.c.h" + #line 3849 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3856,7 +3853,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2786 "Python/bytecodes.c" + #line 2783 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3892,7 +3889,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3896 "Python/generated_cases.c.h" + #line 3893 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3900,7 +3897,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2824 "Python/bytecodes.c" + #line 2821 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3910,7 +3907,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3914 "Python/generated_cases.c.h" + #line 3911 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3923,7 +3920,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2836 "Python/bytecodes.c" + #line 2833 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3934,7 +3931,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3938 "Python/generated_cases.c.h" + #line 3935 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3948,7 +3945,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2850 "Python/bytecodes.c" + #line 2847 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3959,7 +3956,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3963 "Python/generated_cases.c.h" + #line 3960 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3973,7 +3970,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2864 "Python/bytecodes.c" + #line 2861 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3995,7 +3992,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3999 "Python/generated_cases.c.h" + #line 3996 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4009,7 +4006,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2889 "Python/bytecodes.c" + #line 2886 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4037,7 +4034,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4041 "Python/generated_cases.c.h" + #line 4038 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4051,7 +4048,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2920 "Python/bytecodes.c" + #line 2917 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4083,7 +4080,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4087 "Python/generated_cases.c.h" + #line 4084 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4097,7 +4094,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2955 "Python/bytecodes.c" + #line 2952 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4129,7 +4126,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4133 "Python/generated_cases.c.h" + #line 4130 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4143,7 +4140,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2990 "Python/bytecodes.c" + #line 2987 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4168,7 +4165,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4172 "Python/generated_cases.c.h" + #line 4169 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4181,7 +4178,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3017 "Python/bytecodes.c" + #line 3014 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4208,7 +4205,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4212 "Python/generated_cases.c.h" + #line 4209 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4220,7 +4217,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3047 "Python/bytecodes.c" + #line 3044 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -4238,14 +4235,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4242 "Python/generated_cases.c.h" + #line 4239 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3067 "Python/bytecodes.c" + #line 3064 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4276,7 +4273,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4280 "Python/generated_cases.c.h" + #line 4277 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4289,7 +4286,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3101 "Python/bytecodes.c" + #line 3098 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4318,7 +4315,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4322 "Python/generated_cases.c.h" + #line 4319 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4331,7 +4328,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3133 "Python/bytecodes.c" + #line 3130 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4360,7 +4357,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4364 "Python/generated_cases.c.h" + #line 4361 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4373,7 +4370,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3165 "Python/bytecodes.c" + #line 3162 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4401,7 +4398,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4405 "Python/generated_cases.c.h" + #line 4402 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4411,9 +4408,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3196 "Python/bytecodes.c" + #line 3193 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4417 "Python/generated_cases.c.h" + #line 4414 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4422,7 +4419,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3200 "Python/bytecodes.c" + #line 3197 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4484,14 +4481,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4488 "Python/generated_cases.c.h" + #line 4485 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3262 "Python/bytecodes.c" + #line 3259 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4495 "Python/generated_cases.c.h" + #line 4492 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4506,7 +4503,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3272 "Python/bytecodes.c" + #line 3269 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4535,14 +4532,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4539 "Python/generated_cases.c.h" + #line 4536 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3303 "Python/bytecodes.c" + #line 3300 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4563,7 +4560,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4567 "Python/generated_cases.c.h" + #line 4564 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4571,15 +4568,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3326 "Python/bytecodes.c" + #line 3323 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4577 "Python/generated_cases.c.h" + #line 4574 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3328 "Python/bytecodes.c" + #line 3325 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4583 "Python/generated_cases.c.h" + #line 4580 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4590,7 +4587,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3332 "Python/bytecodes.c" + #line 3329 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4625,7 +4622,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4629 "Python/generated_cases.c.h" + #line 4626 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4634,10 +4631,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3369 "Python/bytecodes.c" + #line 3366 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4641 "Python/generated_cases.c.h" + #line 4638 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4649,7 +4646,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3374 "Python/bytecodes.c" + #line 3371 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4664,12 +4661,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4668 "Python/generated_cases.c.h" + #line 4665 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3389 "Python/bytecodes.c" + #line 3386 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4673 "Python/generated_cases.c.h" + #line 4670 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4679,16 +4676,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3394 "Python/bytecodes.c" + #line 3391 "Python/bytecodes.c" assert(oparg >= 2); - #line 4685 "Python/generated_cases.c.h" + #line 4682 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3398 "Python/bytecodes.c" + #line 3395 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4700,26 +4697,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4704 "Python/generated_cases.c.h" + #line 4701 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3412 "Python/bytecodes.c" + #line 3409 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4710 "Python/generated_cases.c.h" + #line 4707 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3416 "Python/bytecodes.c" + #line 3413 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4717 "Python/generated_cases.c.h" + #line 4714 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3421 "Python/bytecodes.c" + #line 3418 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4728,12 +4725,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4732 "Python/generated_cases.c.h" + #line 4729 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3432 "Python/bytecodes.c" + #line 3429 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4742,12 +4739,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4746 "Python/generated_cases.c.h" + #line 4743 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3443 "Python/bytecodes.c" + #line 3440 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4759,12 +4756,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4763 "Python/generated_cases.c.h" + #line 4760 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3457 "Python/bytecodes.c" + #line 3454 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4776,30 +4773,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4780 "Python/generated_cases.c.h" + #line 4777 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3471 "Python/bytecodes.c" + #line 3468 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4791 "Python/generated_cases.c.h" + #line 4788 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3479 "Python/bytecodes.c" + #line 3476 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4798 "Python/generated_cases.c.h" + #line 4795 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3484 "Python/bytecodes.c" + #line 3481 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4805 "Python/generated_cases.c.h" + #line 4802 "Python/generated_cases.c.h" } From 72b0f0eaf52ac46d5f6e165f737d6f891cf8d172 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 15 Oct 2023 10:59:19 +0300 Subject: [PATCH 1025/1206] [3.12] bpo-42663: Fix parsing TZ strings in zoneinfo module (GH-23825) (GH-110882) zipinfo now supports the full range of values in the TZ string determined by RFC 8536 and detects all invalid formats. Both Python and C implementations now raise exceptions of the same type on invalid data. (cherry picked from commit ab08ff7882b6181fb785eed7410dbf8030aded70) --- Lib/test/test_zoneinfo/test_zoneinfo.py | 125 +++++- Lib/zoneinfo/_zoneinfo.py | 86 ++-- ...2-05-06-15-49-57.gh-issue-86826.rf006W.rst | 4 + Modules/_zoneinfo.c | 369 +++++++----------- 4 files changed, 326 insertions(+), 258 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-05-06-15-49-57.gh-issue-86826.rf006W.rst diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index ae921f7432c466..3766ceac8385f2 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1001,6 +1001,80 @@ def test_tzstr_from_utc(self): self.assertEqual(dt_act, dt_utc) + def test_extreme_tzstr(self): + tzstrs = [ + # Extreme offset hour + "AAA24", + "AAA+24", + "AAA-24", + "AAA24BBB,J60/2,J300/2", + "AAA+24BBB,J60/2,J300/2", + "AAA-24BBB,J60/2,J300/2", + "AAA4BBB24,J60/2,J300/2", + "AAA4BBB+24,J60/2,J300/2", + "AAA4BBB-24,J60/2,J300/2", + # Extreme offset minutes + "AAA4:00BBB,J60/2,J300/2", + "AAA4:59BBB,J60/2,J300/2", + "AAA4BBB5:00,J60/2,J300/2", + "AAA4BBB5:59,J60/2,J300/2", + # Extreme offset seconds + "AAA4:00:00BBB,J60/2,J300/2", + "AAA4:00:59BBB,J60/2,J300/2", + "AAA4BBB5:00:00,J60/2,J300/2", + "AAA4BBB5:00:59,J60/2,J300/2", + # Extreme total offset + "AAA24:59:59BBB5,J60/2,J300/2", + "AAA-24:59:59BBB5,J60/2,J300/2", + "AAA4BBB24:59:59,J60/2,J300/2", + "AAA4BBB-24:59:59,J60/2,J300/2", + # Extreme months + "AAA4BBB,M12.1.1/2,M1.1.1/2", + "AAA4BBB,M1.1.1/2,M12.1.1/2", + # Extreme weeks + "AAA4BBB,M1.5.1/2,M1.1.1/2", + "AAA4BBB,M1.1.1/2,M1.5.1/2", + # Extreme weekday + "AAA4BBB,M1.1.6/2,M2.1.1/2", + "AAA4BBB,M1.1.1/2,M2.1.6/2", + # Extreme numeric offset + "AAA4BBB,0/2,20/2", + "AAA4BBB,0/2,0/14", + "AAA4BBB,20/2,365/2", + "AAA4BBB,365/2,365/14", + # Extreme julian offset + "AAA4BBB,J1/2,J20/2", + "AAA4BBB,J1/2,J1/14", + "AAA4BBB,J20/2,J365/2", + "AAA4BBB,J365/2,J365/14", + # Extreme transition hour + "AAA4BBB,J60/167,J300/2", + "AAA4BBB,J60/+167,J300/2", + "AAA4BBB,J60/-167,J300/2", + "AAA4BBB,J60/2,J300/167", + "AAA4BBB,J60/2,J300/+167", + "AAA4BBB,J60/2,J300/-167", + # Extreme transition minutes + "AAA4BBB,J60/2:00,J300/2", + "AAA4BBB,J60/2:59,J300/2", + "AAA4BBB,J60/2,J300/2:00", + "AAA4BBB,J60/2,J300/2:59", + # Extreme transition seconds + "AAA4BBB,J60/2:00:00,J300/2", + "AAA4BBB,J60/2:00:59,J300/2", + "AAA4BBB,J60/2,J300/2:00:00", + "AAA4BBB,J60/2,J300/2:00:59", + # Extreme total transition time + "AAA4BBB,J60/167:59:59,J300/2", + "AAA4BBB,J60/-167:59:59,J300/2", + "AAA4BBB,J60/2,J300/167:59:59", + "AAA4BBB,J60/2,J300/-167:59:59", + ] + + for tzstr in tzstrs: + with self.subTest(tzstr=tzstr): + self.zone_from_tzstr(tzstr) + def test_invalid_tzstr(self): invalid_tzstrs = [ "PST8PDT", # DST but no transition specified @@ -1008,16 +1082,33 @@ def test_invalid_tzstr(self): "GMT,M3.2.0/2,M11.1.0/3", # Transition rule but no DST "GMT0+11,M3.2.0/2,M11.1.0/3", # Unquoted alphanumeric in DST "PST8PDT,M3.2.0/2", # Only one transition rule - # Invalid offsets - "STD+25", - "STD-25", - "STD+374", - "STD+374DST,M3.2.0/2,M11.1.0/3", - "STD+23DST+25,M3.2.0/2,M11.1.0/3", - "STD-23DST-25,M3.2.0/2,M11.1.0/3", + # Invalid offset hours + "AAA168", + "AAA+168", + "AAA-168", + "AAA168BBB,J60/2,J300/2", + "AAA+168BBB,J60/2,J300/2", + "AAA-168BBB,J60/2,J300/2", + "AAA4BBB168,J60/2,J300/2", + "AAA4BBB+168,J60/2,J300/2", + "AAA4BBB-168,J60/2,J300/2", + # Invalid offset minutes + "AAA4:0BBB,J60/2,J300/2", + "AAA4:100BBB,J60/2,J300/2", + "AAA4BBB5:0,J60/2,J300/2", + "AAA4BBB5:100,J60/2,J300/2", + # Invalid offset seconds + "AAA4:00:0BBB,J60/2,J300/2", + "AAA4:00:100BBB,J60/2,J300/2", + "AAA4BBB5:00:0,J60/2,J300/2", + "AAA4BBB5:00:100,J60/2,J300/2", # Completely invalid dates "AAA4BBB,M1443339,M11.1.0/3", "AAA4BBB,M3.2.0/2,0349309483959c", + "AAA4BBB,,J300/2", + "AAA4BBB,z,J300/2", + "AAA4BBB,J60/2,", + "AAA4BBB,J60/2,z", # Invalid months "AAA4BBB,M13.1.1/2,M1.1.1/2", "AAA4BBB,M1.1.1/2,M13.1.1/2", @@ -1037,6 +1128,26 @@ def test_invalid_tzstr(self): # Invalid julian offset "AAA4BBB,J0/2,J20/2", "AAA4BBB,J20/2,J366/2", + # Invalid transition time + "AAA4BBB,J60/2/3,J300/2", + "AAA4BBB,J60/2,J300/2/3", + # Invalid transition hour + "AAA4BBB,J60/168,J300/2", + "AAA4BBB,J60/+168,J300/2", + "AAA4BBB,J60/-168,J300/2", + "AAA4BBB,J60/2,J300/168", + "AAA4BBB,J60/2,J300/+168", + "AAA4BBB,J60/2,J300/-168", + # Invalid transition minutes + "AAA4BBB,J60/2:0,J300/2", + "AAA4BBB,J60/2:100,J300/2", + "AAA4BBB,J60/2,J300/2:0", + "AAA4BBB,J60/2,J300/2:100", + # Invalid transition seconds + "AAA4BBB,J60/2:00:0,J300/2", + "AAA4BBB,J60/2:00:100,J300/2", + "AAA4BBB,J60/2,J300/2:00:0", + "AAA4BBB,J60/2,J300/2:00:100", ] for invalid_tzstr in invalid_tzstrs: diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index eede15b8271058..b77dc0ed391bb3 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -517,8 +517,8 @@ class _DayOffset: __slots__ = ["d", "julian", "hour", "minute", "second"] def __init__(self, d, julian, hour=2, minute=0, second=0): - if not (0 + julian) <= d <= 365: - min_day = 0 + julian + min_day = 0 + julian # convert bool to int + if not min_day <= d <= 365: raise ValueError(f"d must be in [{min_day}, 365], not: {d}") self.d = d @@ -560,11 +560,11 @@ class _CalendarOffset: ) def __init__(self, m, w, d, hour=2, minute=0, second=0): - if not 0 < m <= 12: - raise ValueError("m must be in (0, 12]") + if not 1 <= m <= 12: + raise ValueError("m must be in [1, 12]") - if not 0 < w <= 5: - raise ValueError("w must be in (0, 5]") + if not 1 <= w <= 5: + raise ValueError("w must be in [1, 5]") if not 0 <= d <= 6: raise ValueError("d must be in [0, 6]") @@ -634,18 +634,21 @@ def _parse_tz_str(tz_str): offset_str, *start_end_str = tz_str.split(",", 1) - # fmt: off parser_re = re.compile( - r"(?P[^<0-9:.+-]+|<[a-zA-Z0-9+\-]+>)" + - r"((?P[+-]?\d{1,2}(:\d{2}(:\d{2})?)?)" + - r"((?P[^0-9:.+-]+|<[a-zA-Z0-9+\-]+>)" + - r"((?P[+-]?\d{1,2}(:\d{2}(:\d{2})?)?))?" + - r")?" + # dst - r")?$" # stdoff + r""" + (?P[^<0-9:.+-]+|<[a-zA-Z0-9+-]+>) + (?: + (?P[+-]?\d{1,3}(?::\d{2}(?::\d{2})?)?) + (?: + (?P[^0-9:.+-]+|<[a-zA-Z0-9+-]+>) + (?P[+-]?\d{1,3}(?::\d{2}(?::\d{2})?)?)? + )? # dst + )? # stdoff + """, + re.ASCII|re.VERBOSE ) - # fmt: on - m = parser_re.match(offset_str) + m = parser_re.fullmatch(offset_str) if m is None: raise ValueError(f"{tz_str} is not a valid TZ string") @@ -696,16 +699,17 @@ def _parse_tz_str(tz_str): def _parse_dst_start_end(dststr): - date, *time = dststr.split("/") - if date[0] == "M": + date, *time = dststr.split("/", 1) + type = date[:1] + if type == "M": n_is_julian = False - m = re.match(r"M(\d{1,2})\.(\d).(\d)$", date) + m = re.fullmatch(r"M(\d{1,2})\.(\d).(\d)", date, re.ASCII) if m is None: raise ValueError(f"Invalid dst start/end date: {dststr}") date_offset = tuple(map(int, m.groups())) offset = _CalendarOffset(*date_offset) else: - if date[0] == "J": + if type == "J": n_is_julian = True date = date[1:] else: @@ -715,38 +719,54 @@ def _parse_dst_start_end(dststr): offset = _DayOffset(doy, n_is_julian) if time: - time_components = list(map(int, time[0].split(":"))) - n_components = len(time_components) - if n_components < 3: - time_components.extend([0] * (3 - n_components)) - offset.hour, offset.minute, offset.second = time_components + offset.hour, offset.minute, offset.second = _parse_transition_time(time[0]) return offset +def _parse_transition_time(time_str): + match = re.fullmatch( + r"(?P[+-])?(?P\d{1,3})(:(?P\d{2})(:(?P\d{2}))?)?", + time_str, + re.ASCII + ) + if match is None: + raise ValueError(f"Invalid time: {time_str}") + + h, m, s = (int(v or 0) for v in match.group("h", "m", "s")) + + if h > 167: + raise ValueError( + f"Hour must be in [0, 167]: {time_str}" + ) + + if match.group("sign") == "-": + h, m, s = -h, -m, -s + + return h, m, s + + def _parse_tz_delta(tz_delta): - match = re.match( - r"(?P[+-])?(?P\d{1,2})(:(?P\d{2})(:(?P\d{2}))?)?", + match = re.fullmatch( + r"(?P[+-])?(?P\d{1,3})(:(?P\d{2})(:(?P\d{2}))?)?", tz_delta, + re.ASCII ) # Anything passed to this function should already have hit an equivalent # regular expression to find the section to parse. assert match is not None, tz_delta - h, m, s = ( - int(v) if v is not None else 0 - for v in map(match.group, ("h", "m", "s")) - ) + h, m, s = (int(v or 0) for v in match.group("h", "m", "s")) total = h * 3600 + m * 60 + s - if not -86400 < total < 86400: + if h > 24: raise ValueError( - f"Offset must be strictly between -24h and +24h: {tz_delta}" + f"Offset hours must be in [0, 24]: {tz_delta}" ) # Yes, +5 maps to an offset of -5h if match.group("sign") != "-": - total *= -1 + total = -total return total diff --git a/Misc/NEWS.d/next/Library/2022-05-06-15-49-57.gh-issue-86826.rf006W.rst b/Misc/NEWS.d/next/Library/2022-05-06-15-49-57.gh-issue-86826.rf006W.rst new file mode 100644 index 00000000000000..02cd75eec4be9e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-06-15-49-57.gh-issue-86826.rf006W.rst @@ -0,0 +1,4 @@ +:mod:`zipinfo` now supports the full range of values in the TZ string +determined by RFC 8536 and detects all invalid formats. +Both Python and C implementations now raise exceptions of the same +type on invalid data. diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 38b806c244061d..8fc86162410619 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -62,21 +62,21 @@ struct TransitionRuleType { typedef struct { TransitionRuleType base; - uint8_t month; - uint8_t week; - uint8_t day; - int8_t hour; - int8_t minute; - int8_t second; + uint8_t month; /* 1 - 12 */ + uint8_t week; /* 1 - 5 */ + uint8_t day; /* 0 - 6 */ + int16_t hour; /* -167 - 167, RFC 8536 §3.3.1 */ + int8_t minute; /* signed 2 digits */ + int8_t second; /* signed 2 digits */ } CalendarRule; typedef struct { TransitionRuleType base; - uint8_t julian; - unsigned int day; - int8_t hour; - int8_t minute; - int8_t second; + uint8_t julian; /* 0, 1 */ + uint16_t day; /* 0 - 365 */ + int16_t hour; /* -167 - 167, RFC 8536 §3.3.1 */ + int8_t minute; /* signed 2 digits */ + int8_t second; /* signed 2 digits */ } DayRule; struct StrongCacheNode { @@ -134,15 +134,14 @@ ts_to_local(size_t *trans_idx, int64_t *trans_utc, long *utcoff, static int parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out); -static Py_ssize_t -parse_abbr(const char *const p, PyObject **abbr); -static Py_ssize_t -parse_tz_delta(const char *const p, long *total_seconds); -static Py_ssize_t -parse_transition_time(const char *const p, int8_t *hour, int8_t *minute, - int8_t *second); -static Py_ssize_t -parse_transition_rule(const char *const p, TransitionRuleType **out); +static int +parse_abbr(const char **p, PyObject **abbr); +static int +parse_tz_delta(const char **p, long *total_seconds); +static int +parse_transition_time(const char **p, int *hour, int *minute, int *second); +static int +parse_transition_rule(const char **p, TransitionRuleType **out); static _ttinfo * find_tzrule_ttinfo(_tzrule *rule, int64_t ts, unsigned char fold, int year); @@ -1328,14 +1327,14 @@ calendarrule_year_to_timestamp(TransitionRuleType *base_self, int year) } int64_t ordinal = ymd_to_ord(year, self->month, month_day) - EPOCHORDINAL; - return ((ordinal * 86400) + (int64_t)(self->hour * 3600) + - (int64_t)(self->minute * 60) + (int64_t)(self->second)); + return ordinal * 86400 + (int64_t)self->hour * 3600 + + (int64_t)self->minute * 60 + self->second; } /* Constructor for CalendarRule. */ int -calendarrule_new(uint8_t month, uint8_t week, uint8_t day, int8_t hour, - int8_t minute, int8_t second, CalendarRule *out) +calendarrule_new(int month, int week, int day, int hour, + int minute, int second, CalendarRule *out) { // These bounds come from the POSIX standard, which describes an Mm.n.d // rule as: @@ -1344,33 +1343,36 @@ calendarrule_new(uint8_t month, uint8_t week, uint8_t day, int8_t hour, // 5, 1 <= m <= 12, where week 5 means "the last d day in month m" which // may occur in either the fourth or the fifth week). Week 1 is the first // week in which the d'th day occurs. Day zero is Sunday. - if (month <= 0 || month > 12) { - PyErr_Format(PyExc_ValueError, "Month must be in (0, 12]"); + if (month < 1 || month > 12) { + PyErr_Format(PyExc_ValueError, "Month must be in [1, 12]"); return -1; } - if (week <= 0 || week > 5) { - PyErr_Format(PyExc_ValueError, "Week must be in (0, 5]"); + if (week < 1 || week > 5) { + PyErr_Format(PyExc_ValueError, "Week must be in [1, 5]"); return -1; } - // If the 'day' parameter type is changed to a signed type, - // "day < 0" check must be added. - if (/* day < 0 || */ day > 6) { + if (day < 0 || day > 6) { PyErr_Format(PyExc_ValueError, "Day must be in [0, 6]"); return -1; } + if (hour < -167 || hour > 167) { + PyErr_Format(PyExc_ValueError, "Hour must be in [0, 167]"); + return -1; + } + TransitionRuleType base = {&calendarrule_year_to_timestamp}; CalendarRule new_offset = { .base = base, - .month = month, - .week = week, - .day = day, - .hour = hour, - .minute = minute, - .second = second, + .month = (uint8_t)month, + .week = (uint8_t)week, + .day = (uint8_t)day, + .hour = (int16_t)hour, + .minute = (int8_t)minute, + .second = (int8_t)second, }; *out = new_offset; @@ -1410,40 +1412,45 @@ dayrule_year_to_timestamp(TransitionRuleType *base_self, int year) // always transitions on a given calendar day (other than February 29th), // you would use a Julian day, e.g. J91 always refers to April 1st and J365 // always refers to December 31st. - unsigned int day = self->day; + uint16_t day = self->day; if (self->julian && day >= 59 && is_leap_year(year)) { day += 1; } - return ((days_before_year + day) * 86400) + (self->hour * 3600) + - (self->minute * 60) + self->second; + return (days_before_year + day) * 86400 + (int64_t)self->hour * 3600 + + (int64_t)self->minute * 60 + self->second; } /* Constructor for DayRule. */ static int -dayrule_new(uint8_t julian, unsigned int day, int8_t hour, int8_t minute, - int8_t second, DayRule *out) +dayrule_new(int julian, int day, int hour, int minute, + int second, DayRule *out) { // The POSIX standard specifies that Julian days must be in the range (1 <= // n <= 365) and that non-Julian (they call it "0-based Julian") days must // be in the range (0 <= n <= 365). if (day < julian || day > 365) { - PyErr_Format(PyExc_ValueError, "day must be in [%u, 365], not: %u", + PyErr_Format(PyExc_ValueError, "day must be in [%d, 365], not: %d", julian, day); return -1; } + if (hour < -167 || hour > 167) { + PyErr_Format(PyExc_ValueError, "Hour must be in [0, 167]"); + return -1; + } + TransitionRuleType base = { &dayrule_year_to_timestamp, }; DayRule tmp = { .base = base, - .julian = julian, - .day = day, - .hour = hour, - .minute = minute, - .second = second, + .julian = (uint8_t)julian, + .day = (int16_t)day, + .hour = (int16_t)hour, + .minute = (int8_t)minute, + .second = (int8_t)second, }; *out = tmp; @@ -1600,21 +1607,18 @@ parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out) const char *p = tz_str; // Read the `std` abbreviation, which must be at least 3 characters long. - Py_ssize_t num_chars = parse_abbr(p, &std_abbr); - if (num_chars < 1) { - PyErr_Format(PyExc_ValueError, "Invalid STD format in %R", tz_str_obj); + if (parse_abbr(&p, &std_abbr)) { + if (!PyErr_Occurred()) { + PyErr_Format(PyExc_ValueError, "Invalid STD format in %R", tz_str_obj); + } goto error; } - p += num_chars; - // Now read the STD offset, which is required - num_chars = parse_tz_delta(p, &std_offset); - if (num_chars < 0) { + if (parse_tz_delta(&p, &std_offset)) { PyErr_Format(PyExc_ValueError, "Invalid STD offset in %R", tz_str_obj); goto error; } - p += num_chars; // If the string ends here, there is no DST, otherwise we must parse the // DST abbreviation and start and end dates and times. @@ -1622,12 +1626,12 @@ parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out) goto complete; } - num_chars = parse_abbr(p, &dst_abbr); - if (num_chars < 1) { - PyErr_Format(PyExc_ValueError, "Invalid DST format in %R", tz_str_obj); + if (parse_abbr(&p, &dst_abbr)) { + if (!PyErr_Occurred()) { + PyErr_Format(PyExc_ValueError, "Invalid DST format in %R", tz_str_obj); + } goto error; } - p += num_chars; if (*p == ',') { // From the POSIX standard: @@ -1637,14 +1641,11 @@ parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out) dst_offset = std_offset + 3600; } else { - num_chars = parse_tz_delta(p, &dst_offset); - if (num_chars < 0) { + if (parse_tz_delta(&p, &dst_offset)) { PyErr_Format(PyExc_ValueError, "Invalid DST offset in %R", tz_str_obj); goto error; } - - p += num_chars; } TransitionRuleType **transitions[2] = {&start, &end}; @@ -1657,14 +1658,12 @@ parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out) } p++; - num_chars = parse_transition_rule(p, transitions[i]); - if (num_chars < 0) { + if (parse_transition_rule(&p, transitions[i])) { PyErr_Format(PyExc_ValueError, "Malformed transition rule in TZ string: %R", tz_str_obj); goto error; } - p += num_chars; } if (*p != '\0') { @@ -1699,21 +1698,25 @@ parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out) } static int -parse_uint(const char *const p, uint8_t *value) +parse_digits(const char **p, int min, int max, int *value) { - if (!isdigit(*p)) { - return -1; + assert(max <= 3); + *value = 0; + for (int i = 0; i < max; i++, (*p)++) { + if (!Py_ISDIGIT(**p)) { + return (i < min) ? -1 : 0; + } + *value *= 10; + *value += (**p) - '0'; } - - *value = (*p) - '0'; return 0; } /* Parse the STD and DST abbreviations from a TZ string. */ -static Py_ssize_t -parse_abbr(const char *const p, PyObject **abbr) +static int +parse_abbr(const char **p, PyObject **abbr) { - const char *ptr = p; + const char *ptr = *p; const char *str_start; const char *str_end; @@ -1742,7 +1745,7 @@ parse_abbr(const char *const p, PyObject **abbr) ptr++; } else { - str_start = p; + str_start = ptr; // From the POSIX standard: // // In the unquoted form, all characters in these fields shall be @@ -1752,6 +1755,9 @@ parse_abbr(const char *const p, PyObject **abbr) ptr++; } str_end = ptr; + if (str_end == str_start) { + return -1; + } } *abbr = PyUnicode_FromStringAndSize(str_start, str_end - str_start); @@ -1759,12 +1765,13 @@ parse_abbr(const char *const p, PyObject **abbr) return -1; } - return ptr - p; + *p = ptr; + return 0; } /* Parse a UTC offset from a TZ str. */ -static Py_ssize_t -parse_tz_delta(const char *const p, long *total_seconds) +static int +parse_tz_delta(const char **p, long *total_seconds) { // From the POSIX spec: // @@ -1779,75 +1786,30 @@ parse_tz_delta(const char *const p, long *total_seconds) // The POSIX spec says that the values for `hour` must be between 0 and 24 // hours, but RFC 8536 §3.3.1 specifies that the hours part of the // transition times may be signed and range from -167 to 167. - long sign = -1; - long hours = 0; - long minutes = 0; - long seconds = 0; - - const char *ptr = p; - char buff = *ptr; - if (buff == '-' || buff == '+') { - // Negative numbers correspond to *positive* offsets, from the spec: - // - // If preceded by a '-', the timezone shall be east of the Prime - // Meridian; otherwise, it shall be west (which may be indicated by - // an optional preceding '+' ). - if (buff == '-') { - sign = 1; - } - - ptr++; - } - - // The hour can be 1 or 2 numeric characters - for (size_t i = 0; i < 2; ++i) { - buff = *ptr; - if (!isdigit(buff)) { - if (i == 0) { - return -1; - } - else { - break; - } - } + int hours = 0; + int minutes = 0; + int seconds = 0; - hours *= 10; - hours += buff - '0'; - ptr++; - } - - if (hours > 24 || hours < 0) { + if (parse_transition_time(p, &hours, &minutes, &seconds)) { return -1; } - // Minutes and seconds always of the format ":dd" - long *outputs[2] = {&minutes, &seconds}; - for (size_t i = 0; i < 2; ++i) { - if (*ptr != ':') { - goto complete; - } - ptr++; - - for (size_t j = 0; j < 2; ++j) { - buff = *ptr; - if (!isdigit(buff)) { - return -1; - } - *(outputs[i]) *= 10; - *(outputs[i]) += buff - '0'; - ptr++; - } + if (hours > 24 || hours < -24) { + return -1; } -complete: - *total_seconds = sign * ((hours * 3600) + (minutes * 60) + seconds); - - return ptr - p; + // Negative numbers correspond to *positive* offsets, from the spec: + // + // If preceded by a '-', the timezone shall be east of the Prime + // Meridian; otherwise, it shall be west (which may be indicated by + // an optional preceding '+' ). + *total_seconds = -((hours * 3600L) + (minutes * 60) + seconds); + return 0; } /* Parse the date portion of a transition rule. */ -static Py_ssize_t -parse_transition_rule(const char *const p, TransitionRuleType **out) +static int +parse_transition_rule(const char **p, TransitionRuleType **out) { // The full transition rule indicates when to change back and forth between // STD and DST, and has the form: @@ -1859,10 +1821,10 @@ parse_transition_rule(const char *const p, TransitionRuleType **out) // does not include the ',' at the end of the first rule. // // The POSIX spec states that if *time* is not given, the default is 02:00. - const char *ptr = p; - int8_t hour = 2; - int8_t minute = 0; - int8_t second = 0; + const char *ptr = *p; + int hour = 2; + int minute = 0; + int second = 0; // Rules come in one of three flavors: // @@ -1871,44 +1833,30 @@ parse_transition_rule(const char *const p, TransitionRuleType **out) // 3. Mm.n.d: Specifying by month, week and day-of-week. if (*ptr == 'M') { - uint8_t month, week, day; + int month, week, day; ptr++; - if (parse_uint(ptr, &month)) { + + if (parse_digits(&ptr, 1, 2, &month)) { return -1; } - ptr++; - if (*ptr != '.') { - uint8_t tmp; - if (parse_uint(ptr, &tmp)) { - return -1; - } - - month *= 10; - month += tmp; - ptr++; + if (*ptr++ != '.') { + return -1; } - - uint8_t *values[2] = {&week, &day}; - for (size_t i = 0; i < 2; ++i) { - if (*ptr != '.') { - return -1; - } - ptr++; - - if (parse_uint(ptr, values[i])) { - return -1; - } - ptr++; + if (parse_digits(&ptr, 1, 1, &week)) { + return -1; + } + if (*ptr++ != '.') { + return -1; + } + if (parse_digits(&ptr, 1, 1, &day)) { + return -1; } if (*ptr == '/') { ptr++; - Py_ssize_t num_chars = - parse_transition_time(ptr, &hour, &minute, &second); - if (num_chars < 0) { + if (parse_transition_time(&ptr, &hour, &minute, &second)) { return -1; } - ptr += num_chars; } CalendarRule *rv = PyMem_Calloc(1, sizeof(CalendarRule)); @@ -1924,33 +1872,22 @@ parse_transition_rule(const char *const p, TransitionRuleType **out) *out = (TransitionRuleType *)rv; } else { - uint8_t julian = 0; - unsigned int day = 0; + int julian = 0; + int day = 0; if (*ptr == 'J') { julian = 1; ptr++; } - for (size_t i = 0; i < 3; ++i) { - if (!isdigit(*ptr)) { - if (i == 0) { - return -1; - } - break; - } - day *= 10; - day += (*ptr) - '0'; - ptr++; + if (parse_digits(&ptr, 1, 3, &day)) { + return -1; } if (*ptr == '/') { ptr++; - Py_ssize_t num_chars = - parse_transition_time(ptr, &hour, &minute, &second); - if (num_chars < 0) { + if (parse_transition_time(&ptr, &hour, &minute, &second)) { return -1; } - ptr += num_chars; } DayRule *rv = PyMem_Calloc(1, sizeof(DayRule)); @@ -1965,13 +1902,13 @@ parse_transition_rule(const char *const p, TransitionRuleType **out) *out = (TransitionRuleType *)rv; } - return ptr - p; + *p = ptr; + return 0; } /* Parse the time portion of a transition rule (e.g. following an /) */ -static Py_ssize_t -parse_transition_time(const char *const p, int8_t *hour, int8_t *minute, - int8_t *second) +static int +parse_transition_time(const char **p, int *hour, int *minute, int *second) { // From the spec: // @@ -1983,12 +1920,9 @@ parse_transition_time(const char *const p, int8_t *hour, int8_t *minute, // h[h][:mm[:ss]] // // RFC 8536 also allows transition times to be signed and to range from - // -167 to +167, but the current version only supports [0, 99]. - // - // TODO: Support the full range of transition hours. - int8_t *components[3] = {hour, minute, second}; - const char *ptr = p; - int8_t sign = 1; + // -167 to +167. + const char *ptr = *p; + int sign = 1; if (*ptr == '-' || *ptr == '+') { if (*ptr == '-') { @@ -1997,32 +1931,31 @@ parse_transition_time(const char *const p, int8_t *hour, int8_t *minute, ptr++; } - for (size_t i = 0; i < 3; ++i) { - if (i > 0) { - if (*ptr != ':') { - break; - } - ptr++; + // The hour can be 1 to 3 numeric characters + if (parse_digits(&ptr, 1, 3, hour)) { + return -1; + } + *hour *= sign; + + // Minutes and seconds always of the format ":dd" + if (*ptr == ':') { + ptr++; + if (parse_digits(&ptr, 2, 2, minute)) { + return -1; } + *minute *= sign; - uint8_t buff = 0; - for (size_t j = 0; j < 2; j++) { - if (!isdigit(*ptr)) { - if (i == 0 && j > 0) { - break; - } + if (*ptr == ':') { + ptr++; + if (parse_digits(&ptr, 2, 2, second)) { return -1; } - - buff *= 10; - buff += (*ptr) - '0'; - ptr++; + *second *= sign; } - - *(components[i]) = sign * buff; } - return ptr - p; + *p = ptr; + return 0; } /* Constructor for a _tzrule. @@ -2377,8 +2310,8 @@ get_local_timestamp(PyObject *dt, int64_t *local_ts) } } - *local_ts = (int64_t)(ord - EPOCHORDINAL) * 86400 + - (int64_t)(hour * 3600 + minute * 60 + second); + *local_ts = (int64_t)(ord - EPOCHORDINAL) * 86400L + + (int64_t)(hour * 3600L + minute * 60 + second); return 0; } From 97f4b667e74f493f5b9b1e9ffa4bdcf2420f020b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 15 Oct 2023 19:00:44 +0200 Subject: [PATCH 1026/1206] [3.12] gh-110886 Doc: add a link to BNF Wikipedia article (GH-110887) (#110900) Co-authored-by: partev Co-authored-by: Hugo van Kemenade --- Doc/reference/introduction.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/reference/introduction.rst b/Doc/reference/introduction.rst index 81f0a5c5d43883..cf186705e6e987 100644 --- a/Doc/reference/introduction.rst +++ b/Doc/reference/introduction.rst @@ -90,7 +90,8 @@ Notation .. index:: BNF, grammar, syntax, notation -The descriptions of lexical analysis and syntax use a modified BNF grammar +The descriptions of lexical analysis and syntax use a modified +`Backus–Naur form (BNF) `_ grammar notation. This uses the following style of definition: .. productionlist:: notation From 9c39149b4bd1f37c61f2bd66b9d0050a5185cc0b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 15 Oct 2023 20:32:08 +0300 Subject: [PATCH 1027/1206] [3.12] gh-106193: Rename and fix duplicated tests in `test_monitoring` (GH-109139) (#110897) --- Lib/test/test_monitoring.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 8c9755d2a41a2d..8eaf581b8dbd7f 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1168,7 +1168,7 @@ def func1(): ('instruction', 'func1', 14), ('line', 'get_events', 11)]) -class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase): +class TestInstallIncrementally(MonitoringTestBase, unittest.TestCase): def check_events(self, func, must_include, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): try: @@ -1197,19 +1197,19 @@ def func1(): MUST_INCLUDE_LI = [ ('instruction', 'func1', 2), - ('line', 'func1', 1), + ('line', 'func1', 2), ('instruction', 'func1', 4), ('instruction', 'func1', 6)] def test_line_then_instruction(self): recorders = [ LineRecorder, InstructionRecorder ] self.check_events(self.func1, - recorders = recorders, must_include = self.EXPECTED_LI) + recorders = recorders, must_include = self.MUST_INCLUDE_LI) def test_instruction_then_line(self): - recorders = [ InstructionRecorder, LineRecorderLowNoise ] + recorders = [ InstructionRecorder, LineRecorder ] self.check_events(self.func1, - recorders = recorders, must_include = self.EXPECTED_LI) + recorders = recorders, must_include = self.MUST_INCLUDE_LI) @staticmethod def func2(): @@ -1224,12 +1224,12 @@ def func2(): - def test_line_then_instruction(self): + def test_call_then_instruction(self): recorders = [ CallRecorder, InstructionRecorder ] self.check_events(self.func2, recorders = recorders, must_include = self.MUST_INCLUDE_CI) - def test_instruction_then_line(self): + def test_instruction_then_call(self): recorders = [ InstructionRecorder, CallRecorder ] self.check_events(self.func2, recorders = recorders, must_include = self.MUST_INCLUDE_CI) From 7de3c8b7b6ffb727678e7938359a366cd75850bd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 15 Oct 2023 19:34:37 +0200 Subject: [PATCH 1028/1206] [3.12] Lint: Include test_monitoring.py for Ruff (GH-110898) (#110899) Lint: Include test_monitoring.py for Ruff (GH-110898) (cherry picked from commit 9608704cde4441c76c1b8b765e3aea072bca3b0d) Co-authored-by: Hugo van Kemenade Co-authored-by: Alex Waygood --- Lib/test/.ruff.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml index 52a84f6a379427..9b23c2610f9389 100644 --- a/Lib/test/.ruff.toml +++ b/Lib/test/.ruff.toml @@ -36,6 +36,4 @@ extend-exclude = [ "test_tokenize.py", "test_yield_from.py", "time_hashlib.py", - # Pending https://github.com/python/cpython/pull/109139 - "test_monitoring.py", ] From b4ed73042efc545759808558ba5deebd1e0618e5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:14:52 +0200 Subject: [PATCH 1029/1206] [3.12] gh-110527: Improve `PySet_Clear` docs (GH-110528) (#110928) gh-110527: Improve `PySet_Clear` docs (GH-110528) (cherry picked from commit bfc1cd8145db00df23fbbd2ed95324bb96c0b25b) Co-authored-by: Nikita Sobolev --- Doc/c-api/set.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index 1e8a09509032f5..09c0fb6b9c5f23 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -163,4 +163,6 @@ subtypes but not for instances of :class:`frozenset` or its subtypes. .. c:function:: int PySet_Clear(PyObject *set) - Empty an existing set of all elements. + Empty an existing set of all elements. Return ``0`` on + success. Return ``-1`` and raise :exc:`SystemError` if *set* is not an instance of + :class:`set` or its subtype. From 89f9c226a180a7348e610b33651bbe59ace9fa82 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:35:01 +0200 Subject: [PATCH 1030/1206] [3.12] regrtest: Prepend 'use' options in --{fast,slow}-ci (GH-110363) (#110925) regrtest: Prepend 'use' options in --{fast,slow}-ci (GH-110363) This allows individual resources to be disabled without having to explicitly re-enable all others. (cherry picked from commit b75186f69edcf54615910a5cd707996144163ef7) Co-authored-by: Zachary Ware --- Lib/test/libregrtest/cmdline.py | 10 ++++++---- Lib/test/test_regrtest.py | 8 +++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py index dd4cd335bef7e3..b1b00893402d8e 100644 --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -418,14 +418,16 @@ def _parse_args(args, **kwargs): # --slow-ci has the priority if ns.slow_ci: # Similar to: -u "all" --timeout=1200 - if not ns.use: - ns.use = [['all']] + if ns.use is None: + ns.use = [] + ns.use.insert(0, ['all']) if ns.timeout is None: ns.timeout = 1200 # 20 minutes elif ns.fast_ci: # Similar to: -u "all,-cpu" --timeout=600 - if not ns.use: - ns.use = [['all', '-cpu']] + if ns.use is None: + ns.use = [] + ns.use.insert(0, ['all', '-cpu']) if ns.timeout is None: ns.timeout = 600 # 10 minutes diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 45573a2719c543..c8e182397c835e 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -416,9 +416,11 @@ def test_fast_ci_python_cmd(self): self.assertEqual(regrtest.python_cmd, ('python', '-X', 'dev')) def test_fast_ci_resource(self): - # it should be possible to override resources - args = ['--fast-ci', '-u', 'network'] - use_resources = ['network'] + # it should be possible to override resources individually + args = ['--fast-ci', '-u-network'] + use_resources = sorted(cmdline.ALL_RESOURCES) + use_resources.remove('cpu') + use_resources.remove('network') self.check_ci_mode(args, use_resources) def test_slow_ci(self): From b8e5b1b28ac4855ce6b4d04c777fb35811a82d42 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 16 Oct 2023 16:48:02 +0100 Subject: [PATCH 1031/1206] [3.12] Enable ruff on several more files in `Lib/test` (#110929) (#110934) (cherry-picked from commit 02d26c4bef3ad0f9c97e47993a7fa67898842e5c) --- Lib/test/.ruff.toml | 5 ----- Lib/test/test_ctypes/test_arrays.py | 10 +++++----- Lib/test/test_ctypes/test_functions.py | 6 +++--- Lib/test/test_genericclass.py | 4 ++-- Lib/test/test_keywordonlyarg.py | 2 +- Lib/test/test_subclassinit.py | 10 +++++----- 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml index 9b23c2610f9389..231b0e508f51c1 100644 --- a/Lib/test/.ruff.toml +++ b/Lib/test/.ruff.toml @@ -20,19 +20,14 @@ extend-exclude = [ "test_buffer.py", "test_capi/test_misc.py", "test_capi/test_unicode.py", - "test_ctypes/test_arrays.py", - "test_ctypes/test_functions.py", "test_dataclasses/__init__.py", "test_descr.py", "test_enum.py", "test_functools.py", - "test_genericclass.py", "test_grammar.py", "test_import/__init__.py", - "test_keywordonlyarg.py", "test_lib2to3/data/py3_test_grammar.py", "test_pkg.py", - "test_subclassinit.py", "test_tokenize.py", "test_yield_from.py", "time_hashlib.py", diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py index 415a5785a9c1bb..78aead26da78f3 100644 --- a/Lib/test/test_ctypes/test_arrays.py +++ b/Lib/test/test_ctypes/test_arrays.py @@ -178,10 +178,10 @@ def test_bad_subclass(self): class T(Array): pass with self.assertRaises(AttributeError): - class T(Array): + class T2(Array): _type_ = c_int with self.assertRaises(AttributeError): - class T(Array): + class T3(Array): _length_ = 13 def test_bad_length(self): @@ -190,15 +190,15 @@ class T(Array): _type_ = c_int _length_ = - sys.maxsize * 2 with self.assertRaises(ValueError): - class T(Array): + class T2(Array): _type_ = c_int _length_ = -1 with self.assertRaises(TypeError): - class T(Array): + class T3(Array): _type_ = c_int _length_ = 1.87 with self.assertRaises(OverflowError): - class T(Array): + class T4(Array): _type_ = c_int _length_ = sys.maxsize * 2 diff --git a/Lib/test/test_ctypes/test_functions.py b/Lib/test/test_ctypes/test_functions.py index 703bd2c601ccf6..bc7f211e53c228 100644 --- a/Lib/test/test_ctypes/test_functions.py +++ b/Lib/test/test_ctypes/test_functions.py @@ -42,16 +42,16 @@ class X(object, Array): from _ctypes import _Pointer with self.assertRaises(TypeError): - class X(object, _Pointer): + class X2(object, _Pointer): pass from _ctypes import _SimpleCData with self.assertRaises(TypeError): - class X(object, _SimpleCData): + class X3(object, _SimpleCData): _type_ = "i" with self.assertRaises(TypeError): - class X(object, Structure): + class X4(object, Structure): _fields_ = [] def test_c_char_parm(self): diff --git a/Lib/test/test_genericclass.py b/Lib/test/test_genericclass.py index d8bb37f69e18a1..aece757fc1933e 100644 --- a/Lib/test/test_genericclass.py +++ b/Lib/test/test_genericclass.py @@ -98,7 +98,7 @@ def __mro_entries__(self): return () d = C_too_few() with self.assertRaises(TypeError): - class D(d): ... + class E(d): ... def test_mro_entry_errors_2(self): class C_not_callable: @@ -111,7 +111,7 @@ def __mro_entries__(self): return object c = C_not_tuple() with self.assertRaises(TypeError): - class D(c): ... + class E(c): ... def test_mro_entry_metaclass(self): meta_args = [] diff --git a/Lib/test/test_keywordonlyarg.py b/Lib/test/test_keywordonlyarg.py index df82f677a00a48..918f953cae5702 100644 --- a/Lib/test/test_keywordonlyarg.py +++ b/Lib/test/test_keywordonlyarg.py @@ -170,7 +170,7 @@ def f(v=a, x=b, *, y=c, z=d): pass self.assertEqual(str(err.exception), "name 'b' is not defined") with self.assertRaises(NameError) as err: - f = lambda v=a, x=b, *, y=c, z=d: None + g = lambda v=a, x=b, *, y=c, z=d: None self.assertEqual(str(err.exception), "name 'b' is not defined") diff --git a/Lib/test/test_subclassinit.py b/Lib/test/test_subclassinit.py index 310473a4a2fe58..0d32aa509bd25c 100644 --- a/Lib/test/test_subclassinit.py +++ b/Lib/test/test_subclassinit.py @@ -230,7 +230,7 @@ def __init__(self, name, bases, namespace, otherarg): super().__init__(name, bases, namespace) with self.assertRaises(TypeError): - class MyClass(metaclass=MyMeta, otherarg=1): + class MyClass2(metaclass=MyMeta, otherarg=1): pass class MyMeta(type): @@ -241,10 +241,10 @@ def __init__(self, name, bases, namespace, otherarg): super().__init__(name, bases, namespace) self.otherarg = otherarg - class MyClass(metaclass=MyMeta, otherarg=1): + class MyClass3(metaclass=MyMeta, otherarg=1): pass - self.assertEqual(MyClass.otherarg, 1) + self.assertEqual(MyClass3.otherarg, 1) def test_errors_changed_pep487(self): # These tests failed before Python 3.6, PEP 487 @@ -263,10 +263,10 @@ def __new__(cls, name, bases, namespace, otherarg): self.otherarg = otherarg return self - class MyClass(metaclass=MyMeta, otherarg=1): + class MyClass2(metaclass=MyMeta, otherarg=1): pass - self.assertEqual(MyClass.otherarg, 1) + self.assertEqual(MyClass2.otherarg, 1) def test_type(self): t = type('NewClass', (object,), {}) From 3b87e520fcbe4ceb94e3a46a874a450ee9d50b01 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Mon, 16 Oct 2023 18:59:18 +0200 Subject: [PATCH 1032/1206] [3.12] gh-107450: Check for overflow in the tokenizer and fix overflow test (GH-110832) (#110931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit a1ac5590e0f8fe008e5562d22edab65d0c1c5507) Co-authored-by: Lysandros Nikolaou Co-authored-by: Filipe Laíns Co-authored-by: Serhiy Storchaka --- Include/errcode.h | 38 ++++++++++++++++++------------------- Lib/test/test_exceptions.py | 16 ++++++++++++---- Parser/pegen_errors.c | 11 +++++------ Parser/tokenizer.c | 4 ++++ 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/Include/errcode.h b/Include/errcode.h index 54ae929bf25870..bd9066bb41516f 100644 --- a/Include/errcode.h +++ b/Include/errcode.h @@ -4,7 +4,6 @@ extern "C" { #endif - /* Error codes passed around between file input, tokenizer, parser and interpreter. This is necessary so we can turn them into Python exceptions at a higher level. Note that some errors have a @@ -13,24 +12,25 @@ extern "C" { the parser only returns E_EOF when it hits EOF immediately, and it never returns E_OK. */ -#define E_OK 10 /* No error */ -#define E_EOF 11 /* End Of File */ -#define E_INTR 12 /* Interrupted */ -#define E_TOKEN 13 /* Bad token */ -#define E_SYNTAX 14 /* Syntax error */ -#define E_NOMEM 15 /* Ran out of memory */ -#define E_DONE 16 /* Parsing complete */ -#define E_ERROR 17 /* Execution error */ -#define E_TABSPACE 18 /* Inconsistent mixing of tabs and spaces */ -#define E_OVERFLOW 19 /* Node had too many children */ -#define E_TOODEEP 20 /* Too many indentation levels */ -#define E_DEDENT 21 /* No matching outer block for dedent */ -#define E_DECODE 22 /* Error in decoding into Unicode */ -#define E_EOFS 23 /* EOF in triple-quoted string */ -#define E_EOLS 24 /* EOL in single-quoted string */ -#define E_LINECONT 25 /* Unexpected characters after a line continuation */ -#define E_BADSINGLE 27 /* Ill-formed single statement input */ -#define E_INTERACT_STOP 28 /* Interactive mode stopped tokenization */ +#define E_OK 10 /* No error */ +#define E_EOF 11 /* End Of File */ +#define E_INTR 12 /* Interrupted */ +#define E_TOKEN 13 /* Bad token */ +#define E_SYNTAX 14 /* Syntax error */ +#define E_NOMEM 15 /* Ran out of memory */ +#define E_DONE 16 /* Parsing complete */ +#define E_ERROR 17 /* Execution error */ +#define E_TABSPACE 18 /* Inconsistent mixing of tabs and spaces */ +#define E_OVERFLOW 19 /* Node had too many children */ +#define E_TOODEEP 20 /* Too many indentation levels */ +#define E_DEDENT 21 /* No matching outer block for dedent */ +#define E_DECODE 22 /* Error in decoding into Unicode */ +#define E_EOFS 23 /* EOF in triple-quoted string */ +#define E_EOLS 24 /* EOL in single-quoted string */ +#define E_LINECONT 25 /* Unexpected characters after a line continuation */ +#define E_BADSINGLE 27 /* Ill-formed single statement input */ +#define E_INTERACT_STOP 28 /* Interactive mode stopped tokenization */ +#define E_COLUMNOVERFLOW 29 /* Column offset overflow */ #ifdef __cplusplus } diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 9de7e7355e5742..304901515992e8 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -18,6 +18,12 @@ from test.support.warnings_helper import check_warnings from test import support +try: + from _testcapi import INT_MAX +except ImportError: + INT_MAX = 2**31 - 1 + + class NaiveException(Exception): def __init__(self, x): @@ -318,11 +324,13 @@ def baz(): check('(yield i) = 2', 1, 2) check('def f(*):\n pass', 1, 7) + @unittest.skipIf(INT_MAX >= sys.maxsize, "Downcasting to int is safe for col_offset") @support.requires_resource('cpu') - @support.bigmemtest(support._2G, memuse=1.5) - def testMemoryErrorBigSource(self, _size): - with self.assertRaises(OverflowError): - exec(f"if True:\n {' ' * 2**31}print('hello world')") + @support.bigmemtest(INT_MAX, memuse=2, dry_run=False) + def testMemoryErrorBigSource(self, size): + src = b"if True:\n%*s" % (size, b"pass") + with self.assertRaisesRegex(OverflowError, "Parser column offset overflow"): + compile(src, '', 'exec') @cpython_only def testSettingException(self): diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index 71c476517375bb..6390a66719259a 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -66,6 +66,7 @@ _Pypegen_tokenizer_error(Parser *p) const char *msg = NULL; PyObject* errtype = PyExc_SyntaxError; Py_ssize_t col_offset = -1; + p->error_indicator = 1; switch (p->tok->done) { case E_TOKEN: msg = "invalid token"; @@ -101,6 +102,10 @@ _Pypegen_tokenizer_error(Parser *p) msg = "unexpected character after line continuation character"; break; } + case E_COLUMNOVERFLOW: + PyErr_SetString(PyExc_OverflowError, + "Parser column offset overflow - source line is too big"); + return -1; default: msg = "unknown parsing error"; } @@ -233,12 +238,6 @@ _PyPegen_raise_error(Parser *p, PyObject *errtype, int use_mark, const char *err col_offset = 0; } else { const char* start = p->tok->buf ? p->tok->line_start : p->tok->buf; - if (p->tok->cur - start > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Parser column offset overflow - source line is too big"); - p->error_indicator = 1; - return NULL; - } col_offset = Py_SAFE_DOWNCAST(p->tok->cur - start, intptr_t, int); } } else { diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index a7786d0c17e9e3..a59b728e60c1fa 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1366,6 +1366,10 @@ tok_nextc(struct tok_state *tok) int rc; for (;;) { if (tok->cur != tok->inp) { + if ((unsigned int) tok->col_offset >= (unsigned int) INT_MAX) { + tok->done = E_COLUMNOVERFLOW; + return EOF; + } tok->col_offset++; return Py_CHARMASK(*tok->cur++); /* Fast path */ } From 94525a7a4db3a5e82f0e635e21778e8bb31f800a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:03:18 +0200 Subject: [PATCH 1033/1206] [3.12] C-API docs: Clarify the size of arenas (GH-110895) (#110946) C-API docs: Clarify the size of arenas (GH-110895) Clarify the size of arenas From 3.10.0 alpha 7, the pymalloc allocator uses arenas with a fixed size of 1 MiB on 64-bit platforms instead of 256 KiB on 32-bit platforms. (cherry picked from commit f07ca27709855d4637b43bba23384cc795143ee3) Co-authored-by: Mienxiu <82512658+mienxiu@users.noreply.github.com> --- Doc/c-api/memory.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index e98c178ac27a37..52ef4170e8810b 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -626,7 +626,8 @@ The pymalloc allocator Python has a *pymalloc* allocator optimized for small objects (smaller or equal to 512 bytes) with a short lifetime. It uses memory mappings called "arenas" -with a fixed size of 256 KiB. It falls back to :c:func:`PyMem_RawMalloc` and +with a fixed size of either 256 KiB on 32-bit platforms or 1 MiB on 64-bit +platforms. It falls back to :c:func:`PyMem_RawMalloc` and :c:func:`PyMem_RawRealloc` for allocations larger than 512 bytes. *pymalloc* is the :ref:`default allocator ` of the From 99b7e1c1d7b02adaf98f24bfb843cc57b677f9d6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 17 Oct 2023 07:29:43 +0200 Subject: [PATCH 1034/1206] [3.12] Bump sphinx-lint to v0.8.1 (GH-110933) (#110957) Co-authored-by: Alex Waygood --- .pre-commit-config.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4835b641b3106a..b2cc6f25764cca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,12 +24,11 @@ repos: types_or: [c, inc, python, rst] - repo: https://github.com/sphinx-contrib/sphinx-lint - rev: v0.7.0 + rev: v0.8.1 hooks: - id: sphinx-lint - args: [--enable=default-role, -j1] + args: [--enable=default-role] files: ^Doc/|^Misc/NEWS.d/next/ - types: [rst] - repo: meta hooks: From 9aa899354a09188328dc930ec3b31a8346b9dca0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 17 Oct 2023 12:13:31 +0200 Subject: [PATCH 1035/1206] [3.12] gh-110695: test_asyncio uses 50 ms for clock resolution (GH-110952) (#110970) gh-110695: test_asyncio uses 50 ms for clock resolution (GH-110952) Before utils.CLOCK_RES constant was added (20 ms), test_asyncio already used 50 ms. (cherry picked from commit 9a9fba825f8aaee4ea9b3429875c6c6324d0dee0) Co-authored-by: Victor Stinner --- Lib/test/test_asyncio/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 71391dd8603a66..8d44717b2ade6f 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -37,9 +37,9 @@ # Use the maximum known clock resolution (gh-75191, gh-110088): Windows -# GetTickCount64() has a resolution of 15.6 ms. Use 20 ms to tolerate rounding +# GetTickCount64() has a resolution of 15.6 ms. Use 50 ms to tolerate rounding # issues. -CLOCK_RES = 0.020 +CLOCK_RES = 0.050 def data_file(*filename): From c1e5343928b4e52cc91251fc8680ec3acc31e7a8 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 17 Oct 2023 16:01:57 +0300 Subject: [PATCH 1036/1206] [3.12] Bump test deps: `ruff` and `pre-commit-hooks` (GH-110972) (#110980) (cherry picked from commit b75b1f389f083db8568bff573c33ab4ecf29655a) --- .pre-commit-config.yaml | 4 ++-- Tools/clinic/requirements-dev.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b2cc6f25764cca..f0e0fb8c1152f4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.292 + rev: v0.1.0 hooks: - id: ruff name: Run Ruff on Lib/test/ @@ -12,7 +12,7 @@ repos: files: ^Tools/clinic/|Lib/test/test_clinic.py - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-toml exclude: ^Lib/test/test_tomllib/ diff --git a/Tools/clinic/requirements-dev.txt b/Tools/clinic/requirements-dev.txt index 154934003c31c4..35aa575500e634 100644 --- a/Tools/clinic/requirements-dev.txt +++ b/Tools/clinic/requirements-dev.txt @@ -1,2 +1,2 @@ # Requirements file for external linters and checks we run on Tools/clinic/ in CI -mypy==1.3.0 +mypy==1.6.0 From f0c2390a1f89541dabe8b81bb8be0348635e030a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:45:55 +0200 Subject: [PATCH 1037/1206] [3.12] gh-110995: Fix test_gdb check_usable_gdb() (GH-110998) (#111003) gh-110995: Fix test_gdb check_usable_gdb() (GH-110998) Fix detection of gdb built without Python scripting support. * check_usable_gdb() doesn't check gdb exit code when calling run_gdb(). * Use shutil.which() to get the path to the gdb program. (cherry picked from commit 920b3dfacad615c7bb9bd9a35774469f8809b453) Co-authored-by: Victor Stinner --- Lib/test/test_gdb/util.py | 17 +++++++++++------ ...23-10-17-17-54-36.gh-issue-110995.Fx8KRD.rst | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-17-17-54-36.gh-issue-110995.Fx8KRD.rst diff --git a/Lib/test/test_gdb/util.py b/Lib/test/test_gdb/util.py index 7f4e3cba3534bd..8fe9cfc543395e 100644 --- a/Lib/test/test_gdb/util.py +++ b/Lib/test/test_gdb/util.py @@ -1,6 +1,7 @@ import os import re import shlex +import shutil import subprocess import sys import sysconfig @@ -8,6 +9,8 @@ from test import support +GDB_PROGRAM = shutil.which('gdb') or 'gdb' + # Location of custom hooks file in a repository checkout. CHECKOUT_HOOK_PATH = os.path.join(os.path.dirname(sys.executable), 'python-gdb.py') @@ -27,7 +30,7 @@ def clean_environment(): # Temporary value until it's initialized by get_gdb_version() below GDB_VERSION = (0, 0) -def run_gdb(*args, exitcode=0, **env_vars): +def run_gdb(*args, exitcode=0, check=True, **env_vars): """Runs gdb in --batch mode with the additional arguments given by *args. Returns its (stdout, stderr) decoded from utf-8 using the replace handler. @@ -36,7 +39,7 @@ def run_gdb(*args, exitcode=0, **env_vars): if env_vars: env.update(env_vars) - cmd = ['gdb', + cmd = [GDB_PROGRAM, # Batch mode: Exit after processing all the command files # specified with -x/--command '--batch', @@ -59,7 +62,7 @@ def run_gdb(*args, exitcode=0, **env_vars): stdout = proc.stdout stderr = proc.stderr - if proc.returncode != exitcode: + if check and proc.returncode != exitcode: cmd_text = shlex.join(cmd) raise Exception(f"{cmd_text} failed with exit code {proc.returncode}, " f"expected exit code {exitcode}:\n" @@ -72,10 +75,10 @@ def run_gdb(*args, exitcode=0, **env_vars): def get_gdb_version(): try: stdout, stderr = run_gdb('--version') - except OSError: + except OSError as exc: # This is what "no gdb" looks like. There may, however, be other # errors that manifest this way too. - raise unittest.SkipTest("Couldn't find gdb program on the path") + raise unittest.SkipTest(f"Couldn't find gdb program on the path: {exc}") # Regex to parse: # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7 @@ -106,7 +109,8 @@ def check_usable_gdb(): # disallow this without a customized .gdbinit. stdout, stderr = run_gdb( '--eval-command=python import sys; print(sys.version_info)', - '--args', sys.executable) + '--args', sys.executable, + check=False) if "auto-loading has been declined" in stderr: raise unittest.SkipTest( @@ -144,6 +148,7 @@ def setup_module(): print(f"gdb version {GDB_VERSION[0]}.{GDB_VERSION[1]}:") for line in GDB_VERSION_TEXT.splitlines(): print(" " * 4 + line) + print(f" path: {GDB_PROGRAM}") print() diff --git a/Misc/NEWS.d/next/Tests/2023-10-17-17-54-36.gh-issue-110995.Fx8KRD.rst b/Misc/NEWS.d/next/Tests/2023-10-17-17-54-36.gh-issue-110995.Fx8KRD.rst new file mode 100644 index 00000000000000..db29eaf234b731 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-17-17-54-36.gh-issue-110995.Fx8KRD.rst @@ -0,0 +1,2 @@ +test_gdb: Fix detection of gdb built without Python scripting support. Patch +by Victor Stinner. From ae838afe35caf594f70156b99473a230f8672b33 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Oct 2023 00:38:42 +0200 Subject: [PATCH 1038/1206] [3.12] gh-107457: update dis documentation with changes in 3.12 (GH-108900) (#110985) gh-107457: update dis documentation with changes in 3.12 (GH-108900) (cherry picked from commit 198aa67d4ceb5298c3c60f7a77524f5ba084c121) Co-authored-by: Matthieu Dartiailh --- Doc/library/dis.rst | 59 +++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index ef016c1fc00a5d..3d0142e9490535 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -42,6 +42,14 @@ interpreter. bytecode to specialize it for different runtime conditions. The adaptive bytecode can be shown by passing ``adaptive=True``. + .. versionchanged:: 3.12 + The argument of a jump is the offset of the target instruction relative + to the instruction that appears immediately after the jump instruction's + :opcode:`CACHE` entries. + + As a consequence, the presence of the :opcode:`CACHE` instructions is + transparent for forward jumps but needs to be taken into account when + reasoning about backward jumps. Example: Given the function :func:`!myfunc`:: @@ -450,6 +458,14 @@ operations on it as if it was a Python list. The top of the stack corresponds to .. versionadded:: 3.12 +.. opcode:: END_SEND + + Implements ``del STACK[-2]``. + Used to clean up when a generator exits. + + .. versionadded:: 3.12 + + .. opcode:: COPY (i) Push the i-th item to the top of the stack without removing it from its original @@ -1085,15 +1101,21 @@ iterations of the loop. .. opcode:: LOAD_SUPER_ATTR (namei) - This opcode implements :func:`super` (e.g. ``super().method()`` and - ``super().attr``). It works the same as :opcode:`LOAD_ATTR`, except that - ``namei`` is shifted left by 2 bits instead of 1, and instead of expecting a - single receiver on the stack, it expects three objects (from top of stack - down): ``self`` (the first argument to the current method), ``cls`` (the - class within which the current method was defined), and the global ``super``. + This opcode implements :func:`super`, both in its zero-argument and + two-argument forms (e.g. ``super().method()``, ``super().attr`` and + ``super(cls, self).method()``, ``super(cls, self).attr``). + + It pops three values from the stack (from top of stack down): + - ``self``: the first argument to the current method + - ``cls``: the class within which the current method was defined + - the global ``super`` + + With respect to its argument, it works similarly to :opcode:`LOAD_ATTR`, + except that ``namei`` is shifted left by 2 bits instead of 1. The low bit of ``namei`` signals to attempt a method load, as with - :opcode:`LOAD_ATTR`. + :opcode:`LOAD_ATTR`, which results in pushing ``None`` and the loaded method. + When it is unset a single value is pushed to the stack. The second-low bit of ``namei``, if set, means that this was a two-argument call to :func:`super` (unset means zero-argument). @@ -1520,9 +1542,9 @@ iterations of the loop. Equivalent to ``STACK[-1] = STACK[-2].send(STACK[-1])``. Used in ``yield from`` and ``await`` statements. - If the call raises :exc:`StopIteration`, pop both items, push the - exception's ``value`` attribute, and increment the bytecode counter by - *delta*. + If the call raises :exc:`StopIteration`, pop the top value from the stack, + push the exception's ``value`` attribute, and increment the bytecode counter + by *delta*. .. versionadded:: 3.11 @@ -1550,7 +1572,7 @@ iterations of the loop. Calls an intrinsic function with one argument. Passes ``STACK[-1]`` as the argument and sets ``STACK[-1]`` to the result. Used to implement - functionality that is necessary but not performance critical. + functionality that is not performance critical. The operand determines which intrinsic function is called: @@ -1598,9 +1620,13 @@ iterations of the loop. .. opcode:: CALL_INTRINSIC_2 - Calls an intrinsic function with two arguments. Passes ``STACK[-2]``, ``STACK[-1]`` as the - arguments and sets ``STACK[-1]`` to the result. Used to implement functionality that is - necessary but not performance critical. + Calls an intrinsic function with two arguments. Used to implement functionality + that is not performance critical:: + + arg2 = STACK.pop() + arg1 = STACK.pop() + result = intrinsic2(arg1, arg2) + STACK.push(result) The operand determines which intrinsic function is called: @@ -1685,8 +1711,9 @@ These collections are provided for automatic introspection of bytecode instructions: .. versionchanged:: 3.12 - The collections now contain pseudo instructions as well. These are - opcodes with values ``>= MIN_PSEUDO_OPCODE``. + The collections now contain pseudo instructions and instrumented + instructions as well. These are opcodes with values ``>= MIN_PSEUDO_OPCODE`` + and ``>= MIN_INSTRUMENTED_OPCODE``. .. data:: opname From 8134811089f1907ea56085c6a7de9ce0afbc56c8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Oct 2023 06:30:14 +0200 Subject: [PATCH 1039/1206] [3.12] Regen Doc/requirements-oldest-sphinx.txt (GH-111012) (#111022) Regen Doc/requirements-oldest-sphinx.txt (GH-111012) Fix https://github.com/python/cpython/security/dependabot/4: use urllib3 version 2.0.7. (cherry picked from commit e7ae43ad7dde74e731a9d258e372d17f3b2eb893) Co-authored-by: Victor Stinner --- Doc/requirements-oldest-sphinx.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/requirements-oldest-sphinx.txt b/Doc/requirements-oldest-sphinx.txt index 5de739fc10b085..597341d99ffeaa 100644 --- a/Doc/requirements-oldest-sphinx.txt +++ b/Doc/requirements-oldest-sphinx.txt @@ -16,7 +16,6 @@ alabaster==0.7.13 Babel==2.13.0 certifi==2023.7.22 charset-normalizer==3.3.0 -colorama==0.4.6 docutils==0.17.1 idna==3.4 imagesize==1.4.1 @@ -33,4 +32,4 @@ sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 -urllib3==2.0.6 +urllib3==2.0.7 From 2bca5f43af8fc1c7643fb7769d04a25fbd5f0d98 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 17 Oct 2023 22:26:34 -0700 Subject: [PATCH 1040/1206] =?UTF-8?q?[3.12]=20gh-110938:=20Fix=20error=20m?= =?UTF-8?q?essages=20for=20indented=20blocks=20with=20functio=E2=80=A6=20(?= =?UTF-8?q?#110990)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [3.12] gh-110938: Fix error messages for indented blocks with functions and classes with generic type parameters (GH-110973) (cherry picked from commit 24e4ec7766fd471deb5b7e5087f0e7dba8576cfb) Co-authored-by: Pablo Galindo Salgado --- Grammar/python.gram | 6 +-- Lib/test/test_syntax.py | 10 ++++ ...-10-17-11-03-45.gh-issue-110938.X3sbMb.rst | 2 + Parser/parser.c | 50 ++++++++++++------- 4 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-17-11-03-45.gh-issue-110938.X3sbMb.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index c442db2fa6172e..a4fd3f27dba944 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -1369,11 +1369,11 @@ invalid_for_stmt: | [ASYNC] a='for' star_targets 'in' star_expressions ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after 'for' statement on line %d", a->lineno) } invalid_def_raw: - | [ASYNC] a='def' NAME '(' [params] ')' ['->' expression] ':' NEWLINE !INDENT { + | [ASYNC] a='def' NAME [type_params] '(' [params] ')' ['->' expression] ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after function definition on line %d", a->lineno) } invalid_class_def_raw: - | 'class' NAME ['(' [arguments] ')'] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") } - | a='class' NAME ['(' [arguments] ')'] ':' NEWLINE !INDENT { + | 'class' NAME [type_params] ['(' [arguments] ')'] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") } + | a='class' NAME [type_params] ['(' [arguments] ')'] ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after class definition on line %d", a->lineno) } invalid_double_starred_kvpairs: diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 52fc3573ddb7e0..f5cf9667d564a0 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1446,11 +1446,21 @@ Traceback (most recent call last): IndentationError: expected an indented block after function definition on line 1 + >>> def foo[T](x, /, y, *, z=2): + ... pass + Traceback (most recent call last): + IndentationError: expected an indented block after function definition on line 1 + >>> class Blech(A): ... pass Traceback (most recent call last): IndentationError: expected an indented block after class definition on line 1 + >>> class Blech[T](A): + ... pass + Traceback (most recent call last): + IndentationError: expected an indented block after class definition on line 1 + >>> match something: ... pass Traceback (most recent call last): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-17-11-03-45.gh-issue-110938.X3sbMb.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-17-11-03-45.gh-issue-110938.X3sbMb.rst new file mode 100644 index 00000000000000..a2f9319e69de9b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-17-11-03-45.gh-issue-110938.X3sbMb.rst @@ -0,0 +1,2 @@ +Fix error messages for indented blocks with functions and classes with +generic type parameters. Patch by Pablo Galindo diff --git a/Parser/parser.c b/Parser/parser.c index 42201c4031dcb2..25b4ead78191d3 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -24069,7 +24069,7 @@ invalid_for_stmt_rule(Parser *p) } // invalid_def_raw: -// | ASYNC? 'def' NAME '(' params? ')' ['->' expression] ':' NEWLINE !INDENT +// | ASYNC? 'def' NAME type_params? '(' params? ')' ['->' expression] ':' NEWLINE !INDENT static void * invalid_def_raw_rule(Parser *p) { @@ -24082,12 +24082,12 @@ invalid_def_raw_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // ASYNC? 'def' NAME '(' params? ')' ['->' expression] ':' NEWLINE !INDENT + { // ASYNC? 'def' NAME type_params? '(' params? ')' ['->' expression] ':' NEWLINE !INDENT if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'def' NAME '(' params? ')' ['->' expression] ':' NEWLINE !INDENT")); + D(fprintf(stderr, "%*c> invalid_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'def' NAME type_params? '(' params? ')' ['->' expression] ':' NEWLINE !INDENT")); Token * _literal; Token * _literal_1; Token * _literal_2; @@ -24097,6 +24097,8 @@ invalid_def_raw_rule(Parser *p) UNUSED(_opt_var_1); // Silence compiler warnings void *_opt_var_2; UNUSED(_opt_var_2); // Silence compiler warnings + void *_opt_var_3; + UNUSED(_opt_var_3); // Silence compiler warnings Token * a; expr_ty name_var; Token * newline_var; @@ -24107,13 +24109,15 @@ invalid_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && + (_opt_var_1 = type_params_rule(p), !p->error_indicator) // type_params? + && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_opt_var_1 = params_rule(p), !p->error_indicator) // params? + (_opt_var_2 = params_rule(p), !p->error_indicator) // params? && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_226_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_3 = _tmp_226_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24122,7 +24126,7 @@ invalid_def_raw_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, INDENT) // token=INDENT ) { - D(fprintf(stderr, "%*c+ invalid_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC? 'def' NAME '(' params? ')' ['->' expression] ':' NEWLINE !INDENT")); + D(fprintf(stderr, "%*c+ invalid_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC? 'def' NAME type_params? '(' params? ')' ['->' expression] ':' NEWLINE !INDENT")); _res = RAISE_INDENTATION_ERROR ( "expected an indented block after function definition on line %d" , a -> lineno ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24133,7 +24137,7 @@ invalid_def_raw_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_def_raw[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC? 'def' NAME '(' params? ')' ['->' expression] ':' NEWLINE !INDENT")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC? 'def' NAME type_params? '(' params? ')' ['->' expression] ':' NEWLINE !INDENT")); } _res = NULL; done: @@ -24142,8 +24146,8 @@ invalid_def_raw_rule(Parser *p) } // invalid_class_def_raw: -// | 'class' NAME ['(' arguments? ')'] NEWLINE -// | 'class' NAME ['(' arguments? ')'] ':' NEWLINE !INDENT +// | 'class' NAME type_params? ['(' arguments? ')'] NEWLINE +// | 'class' NAME type_params? ['(' arguments? ')'] ':' NEWLINE !INDENT static void * invalid_class_def_raw_rule(Parser *p) { @@ -24156,15 +24160,17 @@ invalid_class_def_raw_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // 'class' NAME ['(' arguments? ')'] NEWLINE + { // 'class' NAME type_params? ['(' arguments? ')'] NEWLINE if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_class_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class' NAME ['(' arguments? ')'] NEWLINE")); + D(fprintf(stderr, "%*c> invalid_class_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] NEWLINE")); Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings + void *_opt_var_1; + UNUSED(_opt_var_1); // Silence compiler warnings expr_ty name_var; Token * newline_var; if ( @@ -24172,12 +24178,14 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = type_params_rule(p), !p->error_indicator) // type_params? + && + (_opt_var_1 = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ invalid_class_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class' NAME ['(' arguments? ')'] NEWLINE")); + D(fprintf(stderr, "%*c+ invalid_class_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] NEWLINE")); _res = RAISE_SYNTAX_ERROR ( "expected ':'" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24188,17 +24196,19 @@ invalid_class_def_raw_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_class_def_raw[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class' NAME ['(' arguments? ')'] NEWLINE")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] NEWLINE")); } - { // 'class' NAME ['(' arguments? ')'] ':' NEWLINE !INDENT + { // 'class' NAME type_params? ['(' arguments? ')'] ':' NEWLINE !INDENT if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_class_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class' NAME ['(' arguments? ')'] ':' NEWLINE !INDENT")); + D(fprintf(stderr, "%*c> invalid_class_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] ':' NEWLINE !INDENT")); Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings + void *_opt_var_1; + UNUSED(_opt_var_1); // Silence compiler warnings Token * a; expr_ty name_var; Token * newline_var; @@ -24207,7 +24217,9 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_228_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = type_params_rule(p), !p->error_indicator) // type_params? + && + (_opt_var_1 = _tmp_228_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24216,7 +24228,7 @@ invalid_class_def_raw_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, INDENT) // token=INDENT ) { - D(fprintf(stderr, "%*c+ invalid_class_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class' NAME ['(' arguments? ')'] ':' NEWLINE !INDENT")); + D(fprintf(stderr, "%*c+ invalid_class_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] ':' NEWLINE !INDENT")); _res = RAISE_INDENTATION_ERROR ( "expected an indented block after class definition on line %d" , a -> lineno ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24227,7 +24239,7 @@ invalid_class_def_raw_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_class_def_raw[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class' NAME ['(' arguments? ')'] ':' NEWLINE !INDENT")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] ':' NEWLINE !INDENT")); } _res = NULL; done: From 004618fed7c585d032f3e9327463d2c319b4e8bf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Oct 2023 08:02:17 +0200 Subject: [PATCH 1041/1206] [3.12] gh-110938: More syntax tests for PEP695 funcs and classes (GH-110986) (#111023) gh-110938: More syntax tests for PEP695 funcs and classes (GH-110986) (cherry picked from commit 220bcc9e27c89bf3b3609b80a31b1398840f195e) Co-authored-by: Nikita Sobolev --- Lib/test/test_syntax.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index f5cf9667d564a0..00c5f624ceb3ab 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1004,11 +1004,26 @@ Traceback (most recent call last): SyntaxError: expected ':' + >>> def f[T]() + ... pass + Traceback (most recent call last): + SyntaxError: expected ':' + >>> class A ... pass Traceback (most recent call last): SyntaxError: expected ':' + >>> class A[T] + ... pass + Traceback (most recent call last): + SyntaxError: expected ':' + + >>> class A[T]() + ... pass + Traceback (most recent call last): + SyntaxError: expected ':' + >>> class R&D: ... pass Traceback (most recent call last): From 577a8fb72ba182dd2984b66fa8a79ede67bb95e6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:01:18 +0200 Subject: [PATCH 1042/1206] [3.12] gh-111019: Align expected and actual titles in test output (GH-111020) (#111024) gh-111019: Align expected and actual titles in test output (GH-111020) Align expected and actual titles in output from assert_has_calls/assert_called_with for greater readability (cherry picked from commit 77dbd956090aac66e264d9d640f6adb6b0930b87) Co-authored-by: James --- Lib/test/test_unittest/testmock/testmock.py | 14 +++++++------- Lib/unittest/mock.py | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py index d1cae47a40eed4..34d76ba0adacfd 100644 --- a/Lib/test/test_unittest/testmock/testmock.py +++ b/Lib/test/test_unittest/testmock/testmock.py @@ -1039,7 +1039,7 @@ def test_assert_called_with_failure_message(self): actual = 'not called.' expected = "mock(1, '2', 3, bar='foo')" - message = 'expected call not found.\nExpected: %s\nActual: %s' + message = 'expected call not found.\nExpected: %s\n Actual: %s' self.assertRaisesWithMsg( AssertionError, message % (expected, actual), mock.assert_called_with, 1, '2', 3, bar='foo' @@ -1054,7 +1054,7 @@ def test_assert_called_with_failure_message(self): for meth in asserters: actual = "foo(1, '2', 3, foo='foo')" expected = "foo(1, '2', 3, bar='foo')" - message = 'expected call not found.\nExpected: %s\nActual: %s' + message = 'expected call not found.\nExpected: %s\n Actual: %s' self.assertRaisesWithMsg( AssertionError, message % (expected, actual), meth, 1, '2', 3, bar='foo' @@ -1064,7 +1064,7 @@ def test_assert_called_with_failure_message(self): for meth in asserters: actual = "foo(1, '2', 3, foo='foo')" expected = "foo(bar='foo')" - message = 'expected call not found.\nExpected: %s\nActual: %s' + message = 'expected call not found.\nExpected: %s\n Actual: %s' self.assertRaisesWithMsg( AssertionError, message % (expected, actual), meth, bar='foo' @@ -1074,7 +1074,7 @@ def test_assert_called_with_failure_message(self): for meth in asserters: actual = "foo(1, '2', 3, foo='foo')" expected = "foo(1, 2, 3)" - message = 'expected call not found.\nExpected: %s\nActual: %s' + message = 'expected call not found.\nExpected: %s\n Actual: %s' self.assertRaisesWithMsg( AssertionError, message % (expected, actual), meth, 1, 2, 3 @@ -1084,7 +1084,7 @@ def test_assert_called_with_failure_message(self): for meth in asserters: actual = "foo(1, '2', 3, foo='foo')" expected = "foo()" - message = 'expected call not found.\nExpected: %s\nActual: %s' + message = 'expected call not found.\nExpected: %s\n Actual: %s' self.assertRaisesWithMsg( AssertionError, message % (expected, actual), meth ) @@ -1533,7 +1533,7 @@ def f(x=None): pass '^{}$'.format( re.escape('Calls not found.\n' 'Expected: [call()]\n' - 'Actual: [call(1)]'))) as cm: + ' Actual: [call(1)]'))) as cm: mock.assert_has_calls([call()]) self.assertIsNone(cm.exception.__cause__) @@ -1545,7 +1545,7 @@ def f(x=None): pass 'Error processing expected calls.\n' "Errors: [None, TypeError('too many positional arguments')]\n" "Expected: [call(), call(1, 2)]\n" - 'Actual: [call(1)]'))) as cm: + ' Actual: [call(1)]'))) as cm: mock.assert_has_calls([call(), call(1, 2)]) self.assertIsInstance(cm.exception.__cause__, TypeError) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 7ca085760650af..30e8f1550f06aa 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -827,7 +827,7 @@ def _format_mock_call_signature(self, args, kwargs): def _format_mock_failure_message(self, args, kwargs, action='call'): - message = 'expected %s not found.\nExpected: %s\nActual: %s' + message = 'expected %s not found.\nExpected: %s\n Actual: %s' expected_string = self._format_mock_call_signature(args, kwargs) call_args = self.call_args actual_string = self._format_mock_call_signature(*call_args) @@ -930,7 +930,7 @@ def assert_called_with(self, /, *args, **kwargs): if self.call_args is None: expected = self._format_mock_call_signature(args, kwargs) actual = 'not called.' - error_message = ('expected call not found.\nExpected: %s\nActual: %s' + error_message = ('expected call not found.\nExpected: %s\n Actual: %s' % (expected, actual)) raise AssertionError(error_message) @@ -981,7 +981,7 @@ def assert_has_calls(self, calls, any_order=False): raise AssertionError( f'{problem}\n' f'Expected: {_CallList(calls)}' - f'{self._calls_repr(prefix="Actual").rstrip(".")}' + f'{self._calls_repr(prefix=" Actual").rstrip(".")}' ) from cause return From b8ce5d9c172c7c78b4e97a37f76abae48fb71ef5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:05:08 +0200 Subject: [PATCH 1043/1206] [3.12] gh-103737: IDLE - Remove unneeded .keys() for dict iteration (GH-110960) (#111026) gh-103737: IDLE - Remove unneeded .keys() for dict iteration (GH-110960) Add comments where .keys() is needed. Leave debugger usages along because situation is unclear as indicated in expanded comment. Most testing is manual. (cherry picked from commit baefbb21d91db2d950706737a6ebee9b2eff5c2d) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/config.py | 10 +++++++--- Lib/idlelib/configdialog.py | 22 +++++++++------------- Lib/idlelib/debugger.py | 2 +- Lib/idlelib/debugobj.py | 3 ++- Lib/idlelib/idle_test/test_config.py | 4 ++-- Lib/idlelib/idle_test/test_debugobj.py | 4 ++-- Lib/idlelib/pyshell.py | 7 ++++--- Lib/idlelib/stackviewer.py | 2 +- 8 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 2b09d79470b47c..898efeb4dd1550 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -597,7 +597,9 @@ def GetCoreKeys(self, keySetName=None): problem getting any core binding there will be an 'ultimate last resort fallback' to the CUA-ish bindings defined here. """ + # TODO: = dict(sorted([(v-event, keys), ...]))? keyBindings={ + # vitual-event: list of key events. '<>': ['', ''], '<>': ['', ''], '<>': ['', ''], @@ -880,7 +882,7 @@ def _dump(): # htest # (not really, but ignore in coverage) line, crc = 0, 0 def sprint(obj): - global line, crc + nonlocal line, crc txt = str(obj) line += 1 crc = crc32(txt.encode(encoding='utf-8'), crc) @@ -889,7 +891,7 @@ def sprint(obj): def dumpCfg(cfg): print('\n', cfg, '\n') # Cfg has variable '0xnnnnnnnn' address. - for key in sorted(cfg.keys()): + for key in sorted(cfg): sections = cfg[key].sections() sprint(key) sprint(sections) @@ -908,4 +910,6 @@ def dumpCfg(cfg): from unittest import main main('idlelib.idle_test.test_config', verbosity=2, exit=False) - # Run revised _dump() as htest? + _dump() + # Run revised _dump() (700+ lines) as htest? More sorting. + # Perhaps as window with tabs for textviews, making it config viewer. diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index cda7966d558a51..d56afe8a807fea 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -211,14 +211,8 @@ def help(self): contents=help_common+help_pages.get(page, '')) def deactivate_current_config(self): - """Remove current key bindings. - Iterate over window instances defined in parent and remove - the keybindings. - """ - # Before a config is saved, some cleanup of current - # config must be done - remove the previous keybindings. - win_instances = self.parent.instance_dict.keys() - for instance in win_instances: + """Remove current key bindings in current windows.""" + for instance in self.parent.instance_dict: instance.RemoveKeybindings() def activate_config_changes(self): @@ -227,8 +221,7 @@ def activate_config_changes(self): Dynamically update the current parent window instances with some of the configuration changes. """ - win_instances = self.parent.instance_dict.keys() - for instance in win_instances: + for instance in self.parent.instance_dict: instance.ResetColorizer() instance.ResetFont() instance.set_notabs_indentwidth() @@ -583,6 +576,8 @@ def create_page_highlight(self): (*)theme_message: Label """ self.theme_elements = { + # Display_name: ('internal_name, sort_number'). + # TODO: remove sort_number unneeded with dict ordering. 'Normal Code or Text': ('normal', '00'), 'Code Context': ('context', '01'), 'Python Keywords': ('keyword', '02'), @@ -765,7 +760,7 @@ def load_theme_cfg(self): self.builtinlist.SetMenu(item_list, item_list[0]) self.set_theme_type() # Load theme element option menu. - theme_names = list(self.theme_elements.keys()) + theme_names = list(self.theme_elements) theme_names.sort(key=lambda x: self.theme_elements[x][1]) self.targetlist.SetMenu(theme_names, theme_names[0]) self.paint_theme_sample() @@ -1477,12 +1472,13 @@ def load_keys_list(self, keyset_name): reselect = True list_index = self.bindingslist.index(ANCHOR) keyset = idleConf.GetKeySet(keyset_name) - bind_names = list(keyset.keys()) + # 'set' is dict mapping virtual event to list of key events. + bind_names = list(keyset) bind_names.sort() self.bindingslist.delete(0, END) for bind_name in bind_names: key = ' '.join(keyset[bind_name]) - bind_name = bind_name[2:-2] # Trim off the angle brackets. + bind_name = bind_name[2:-2] # Trim double angle brackets. if keyset_name in changes['keys']: # Handle any unsaved changes to this key set. if bind_name in changes['keys'][keyset_name]: diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index 452c62b42655b3..a92bb98d908d46 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -509,7 +509,7 @@ def load_dict(self, dict, force=0, rpc_client=None): # There is also an obscure bug in sorted(dict) where the # interpreter gets into a loop requesting non-existing dict[0], # dict[1], dict[2], etc from the debugger_r.DictProxy. - ### + # TODO recheck above; see debugger_r 159ff, debugobj 60. keys_list = dict.keys() names = sorted(keys_list) ### diff --git a/Lib/idlelib/debugobj.py b/Lib/idlelib/debugobj.py index 71d01c7070df54..032b686f379378 100644 --- a/Lib/idlelib/debugobj.py +++ b/Lib/idlelib/debugobj.py @@ -93,7 +93,8 @@ def setfunction(value, key=key, object=self.object): class DictTreeItem(SequenceTreeItem): def keys(self): - keys = list(self.object.keys()) + # TODO return sorted(self.object) + keys = list(self.object) try: keys.sort() except: diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py index 08ed76fe288294..a746f1538a62b0 100644 --- a/Lib/idlelib/idle_test/test_config.py +++ b/Lib/idlelib/idle_test/test_config.py @@ -274,8 +274,8 @@ def test_create_config_handlers(self): conf.CreateConfigHandlers() # Check keys are equal - self.assertCountEqual(conf.defaultCfg.keys(), conf.config_types) - self.assertCountEqual(conf.userCfg.keys(), conf.config_types) + self.assertCountEqual(conf.defaultCfg, conf.config_types) + self.assertCountEqual(conf.userCfg, conf.config_types) # Check conf parser are correct type for default_parser in conf.defaultCfg.values(): diff --git a/Lib/idlelib/idle_test/test_debugobj.py b/Lib/idlelib/idle_test/test_debugobj.py index 131ce22b8bb69b..90ace4e1bc4f9e 100644 --- a/Lib/idlelib/idle_test/test_debugobj.py +++ b/Lib/idlelib/idle_test/test_debugobj.py @@ -37,7 +37,7 @@ def test_isexpandable(self): def test_keys(self): ti = debugobj.SequenceTreeItem('label', 'abc') - self.assertEqual(list(ti.keys()), [0, 1, 2]) + self.assertEqual(list(ti.keys()), [0, 1, 2]) # keys() is a range. class DictTreeItemTest(unittest.TestCase): @@ -50,7 +50,7 @@ def test_isexpandable(self): def test_keys(self): ti = debugobj.DictTreeItem('label', {1:1, 0:0, 2:2}) - self.assertEqual(ti.keys(), [0, 1, 2]) + self.assertEqual(ti.keys(), [0, 1, 2]) # keys() is a sorted list. if __name__ == '__main__': diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 6028700356b171..7a2707935b60c9 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -747,10 +747,11 @@ def showtraceback(self): self.tkconsole.open_stack_viewer() def checklinecache(self): - c = linecache.cache - for key in list(c.keys()): + "Remove keys other than ''." + cache = linecache.cache + for key in list(cache): # Iterate list because mutate cache. if key[:1] + key[-1:] != "<>": - del c[key] + del cache[key] def runcommand(self, code): "Run the code without invoking the debugger" diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 7b00c4cdb7d033..4858cc682a4f45 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -99,7 +99,7 @@ def IsExpandable(self): def GetSubList(self): sublist = [] - for key in self.object.keys(): + for key in self.object.keys(): # self.object not necessarily dict. try: value = self.object[key] except KeyError: From 228b12493286a7cb959438cd5b1a018e0afb17a8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:32:09 +0200 Subject: [PATCH 1044/1206] [3.12] gh-111015: Install IDLE.app and Python Launcher.app on macOS with correct permissions (gh-111037) (cherry picked from commit cb1bf89c4066f30c80f7d1193b586a2ff8c40579) Co-authored-by: Joshua Root Co-authored-by: Ned Deily --- Mac/Makefile.in | 2 ++ Mac/PythonLauncher/Makefile.in | 2 ++ .../next/macOS/2023-10-18-01-40-36.gh-issue-111015.NaLI2L.rst | 1 + 3 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/macOS/2023-10-18-01-40-36.gh-issue-111015.NaLI2L.rst diff --git a/Mac/Makefile.in b/Mac/Makefile.in index 69ab4198988570..92b3328c07e574 100644 --- a/Mac/Makefile.in +++ b/Mac/Makefile.in @@ -259,6 +259,8 @@ install_IDLE: rm "$(DESTDIR)$(LIBDEST)/idlelib/config-extensions.def~" ; \ fi touch "$(DESTDIR)$(PYTHONAPPSDIR)/IDLE.app" + chmod -R ugo+rX,go-w "$(DESTDIR)$(PYTHONAPPSDIR)/IDLE.app" + chmod ugo+x "$(DESTDIR)$(PYTHONAPPSDIR)/IDLE.app/Contents/MacOS/IDLE" $(INSTALLED_PYTHONAPP): install_Python diff --git a/Mac/PythonLauncher/Makefile.in b/Mac/PythonLauncher/Makefile.in index 4c05f26e8358bc..9decadbdc60f00 100644 --- a/Mac/PythonLauncher/Makefile.in +++ b/Mac/PythonLauncher/Makefile.in @@ -27,6 +27,8 @@ install: Python\ Launcher.app -test -d "$(DESTDIR)$(PYTHONAPPSDIR)/Python Launcher.app" && rm -r "$(DESTDIR)$(PYTHONAPPSDIR)/Python Launcher.app" /bin/cp -r "Python Launcher.app" "$(DESTDIR)$(PYTHONAPPSDIR)" touch "$(DESTDIR)$(PYTHONAPPSDIR)/Python Launcher.app" + chmod -R ugo+rX,go-w "$(DESTDIR)$(PYTHONAPPSDIR)/Python Launcher.app" + chmod ugo+x "$(DESTDIR)$(PYTHONAPPSDIR)/Python Launcher.app/Contents/MacOS/Python Launcher" clean: rm -f *.o "Python Launcher" diff --git a/Misc/NEWS.d/next/macOS/2023-10-18-01-40-36.gh-issue-111015.NaLI2L.rst b/Misc/NEWS.d/next/macOS/2023-10-18-01-40-36.gh-issue-111015.NaLI2L.rst new file mode 100644 index 00000000000000..4c6eea136554c8 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-10-18-01-40-36.gh-issue-111015.NaLI2L.rst @@ -0,0 +1 @@ +Ensure that IDLE.app and Python Launcher.app are installed with appropriate permissions on macOS builds. From 9ef8caf293b6a54f73fb66e3eca653783b3e0f28 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Oct 2023 01:22:03 +0200 Subject: [PATCH 1045/1206] [3.12] GH-104232: Fix statement about trace return values (GH-111047) (cherry picked from commit d9246c7b734b8958da03494045208681d95f5b74) --- Doc/library/sys.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 6fb4c0f1c53893..3782d1e6c6f20a 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1552,9 +1552,8 @@ always available. function to be used for the new scope, or ``None`` if the scope shouldn't be traced. - The local trace function should return a reference to itself (or to another - function for further tracing in that scope), or ``None`` to turn off tracing - in that scope. + The local trace function should return a reference to itself, or to another + function which would then be used as the local trace function for the scope. If there is any error occurred in the trace function, it will be unset, just like ``settrace(None)`` is called. From d312135764569022a5345450a77653623f74269b Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 18 Oct 2023 16:30:13 -0700 Subject: [PATCH 1046/1206] [3.12] GH-103082: Clean up the sys.monitoring docs (GH-111048) (cherry picked from commit 19916941172844f9c52d7a6dce95efaa23035772) --- Doc/library/sys.monitoring.rst | 258 ++++++++++++++++++----------- Doc/tools/extensions/pyspecific.py | 8 + 2 files changed, 165 insertions(+), 101 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 5dcbdaf8e5d0e4..1024f66f3264ba 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -1,14 +1,16 @@ :mod:`sys.monitoring` --- Execution event monitoring ==================================================== -.. module:: sys.monitoring - :synopsis: Access and control event monitoring +.. module:: sys.monitoring + :synopsis: Access and control event monitoring + +.. versionadded:: 3.12 ----------------- .. note:: - ``sys.monitoring`` is a namespace within the ``sys`` module, + :mod:`sys.monitoring` is a namespace within the :mod:`sys` module, not an independent module, so there is no need to ``import sys.monitoring``, simply ``import sys`` and then use ``sys.monitoring``. @@ -18,45 +20,45 @@ This namespace provides access to the functions and constants necessary to activate and control event monitoring. As programs execute, events occur that might be of interest to tools that -monitor execution. The :mod:`!sys.monitoring` namespace provides means to +monitor execution. The :mod:`sys.monitoring` namespace provides means to receive callbacks when events of interest occur. The monitoring API consists of three components: -* Tool identifiers -* Events -* Callbacks +* `Tool identifiers`_ +* `Events`_ +* :ref:`Callbacks ` Tool identifiers ---------------- -A tool identifier is an integer and associated name. +A tool identifier is an integer and the associated name. Tool identifiers are used to discourage tools from interfering with each other and to allow multiple tools to operate at the same time. Currently tools are completely independent and cannot be used to monitor each other. This restriction may be lifted in the future. Before registering or activating events, a tool should choose an identifier. -Identifiers are integers in the range 0 to 5. +Identifiers are integers in the range 0 to 5 inclusive. Registering and using tools ''''''''''''''''''''''''''' .. function:: use_tool_id(id: int, name: str) -> None - Must be called before ``id`` can be used. - ``id`` must be in the range 0 to 5 inclusive. - Raises a ``ValueError`` if ``id`` is in use. + Must be called before *id* can be used. + *id* must be in the range 0 to 5 inclusive. + Raises a :exc:`ValueError` if *id* is in use. .. function:: free_tool_id(id: int) -> None - Should be called once a tool no longer requires ``id``. + Should be called once a tool no longer requires *id*. .. function:: get_tool(id: int) -> str | None - Returns the name of the tool if ``id`` is in use, + Returns the name of the tool if *id* is in use, otherwise it returns ``None``. - ``id`` must be in the range 0 to 5 inclusive. + *id* must be in the range 0 to 5 inclusive. All IDs are treated the same by the VM with regard to events, but the following IDs are pre-defined to make co-operation of tools easier:: @@ -75,48 +77,89 @@ Events The following events are supported: -BRANCH - A conditional branch is taken (or not). -CALL - A call in Python code (event occurs before the call). -C_RAISE - Exception raised from any callable, except Python functions (event occurs after the exit). -C_RETURN - Return from any callable, except Python functions (event occurs after the return). -EXCEPTION_HANDLED - An exception is handled. -INSTRUCTION - A VM instruction is about to be executed. -JUMP - An unconditional jump in the control flow graph is made. -LINE - An instruction is about to be executed that has a different line number from the preceding instruction. -PY_RESUME - Resumption of a Python function (for generator and coroutine functions), except for throw() calls. -PY_RETURN - Return from a Python function (occurs immediately before the return, the callee's frame will be on the stack). -PY_START - Start of a Python function (occurs immediately after the call, the callee's frame will be on the stack) -PY_THROW - A Python function is resumed by a throw() call. -PY_UNWIND - Exit from a Python function during exception unwinding. -PY_YIELD - Yield from a Python function (occurs immediately before the yield, the callee's frame will be on the stack). -RAISE - An exception is raised, except those that cause a ``STOP_ITERATION`` event. -RERAISE - An exception is re-raised, for example at the end of a ``finally`` block. -STOP_ITERATION - An artificial ``StopIteration`` is raised; see `the STOP_ITERATION event`_. +.. monitoring-event:: BRANCH + + A conditional branch is taken (or not). + +.. monitoring-event:: CALL + + A call in Python code (event occurs before the call). + +.. monitoring-event:: C_RAISE + + An exception raised from any callable, except for Python functions (event occurs after the exit). + +.. monitoring-event:: C_RETURN + + Return from any callable, except for Python functions (event occurs after the return). + +.. monitoring-event:: EXCEPTION_HANDLED + + An exception is handled. + +.. monitoring-event:: INSTRUCTION + + A VM instruction is about to be executed. + +.. monitoring-event:: JUMP + + An unconditional jump in the control flow graph is made. + +.. monitoring-event:: LINE + + An instruction is about to be executed that has a different line number from the preceding instruction. + +.. monitoring-event:: PY_RESUME + + Resumption of a Python function (for generator and coroutine functions), except for ``throw()`` calls. + +.. monitoring-event:: PY_RETURN + + Return from a Python function (occurs immediately before the return, the callee's frame will be on the stack). + +.. monitoring-event:: PY_START + + Start of a Python function (occurs immediately after the call, the callee's frame will be on the stack) + +.. monitoring-event:: PY_THROW + + A Python function is resumed by a ``throw()`` call. + +.. monitoring-event:: PY_UNWIND + + Exit from a Python function during exception unwinding. + +.. monitoring-event:: PY_YIELD + + Yield from a Python function (occurs immediately before the yield, the callee's frame will be on the stack). + +.. monitoring-event:: RAISE + + An exception is raised, except those that cause a :monitoring-event:`STOP_ITERATION` event. + +.. monitoring-event:: RERAISE + + An exception is re-raised, for example at the end of a :keyword:`finally` block. + +.. monitoring-event:: STOP_ITERATION + + An artificial :exc:`StopIteration` is raised; see `the STOP_ITERATION event`_. + More events may be added in the future. These events are attributes of the :mod:`!sys.monitoring.events` namespace. Each event is represented as a power-of-2 integer constant. To define a set of events, simply bitwise or the individual events together. -For example, to specify both ``PY_RETURN`` and ``PY_START`` events, use the -expression ``PY_RETURN | PY_START``. +For example, to specify both :monitoring-event:`PY_RETURN` and :monitoring-event:`PY_START` +events, use the expression ``PY_RETURN | PY_START``. + +.. monitoring-event:: NO_EVENTS + + An alias for ``0`` so users can do explict comparisions like:: + + if get_events(DEBUGGER_ID) == NO_EVENTS: + ... Events are divided into three groups: @@ -127,16 +170,16 @@ Local events are associated with normal execution of the program and happen at clearly defined locations. All local events can be disabled. The local events are: -* PY_START -* PY_RESUME -* PY_RETURN -* PY_YIELD -* CALL -* LINE -* INSTRUCTION -* JUMP -* BRANCH -* STOP_ITERATION +* :monitoring-event:`PY_START` +* :monitoring-event:`PY_RESUME` +* :monitoring-event:`PY_RETURN` +* :monitoring-event:`PY_YIELD` +* :monitoring-event:`CALL` +* :monitoring-event:`LINE` +* :monitoring-event:`INSTRUCTION` +* :monitoring-event:`JUMP` +* :monitoring-event:`BRANCH` +* :monitoring-event:`STOP_ITERATION` Ancillary events '''''''''''''''' @@ -144,12 +187,13 @@ Ancillary events Ancillary events can be monitored like other events, but are controlled by another event: -* C_RAISE -* C_RETURN +* :monitoring-event:`C_RAISE` +* :monitoring-event:`C_RETURN` -The ``C_RETURN`` and ``C_RAISE`` events are controlled by the ``CALL`` -event. ``C_RETURN`` and ``C_RAISE`` events will only be seen if the -corresponding ``CALL`` event is being monitored. +The :monitoring-event:`C_RETURN` and :monitoring-event:`C_RAISE` events +are controlled by the :monitoring-event:`CALL` event. +:monitoring-event:`C_RETURN` and :monitoring-event:`C_RAISE` events will only be seen if the +corresponding :monitoring-event:`CALL` event is being monitored. Other events '''''''''''' @@ -159,30 +203,31 @@ program and cannot be individually disabled. The other events that can be monitored are: -* PY_THROW -* PY_UNWIND -* RAISE -* EXCEPTION_HANDLED +* :monitoring-event:`PY_THROW` +* :monitoring-event:`PY_UNWIND` +* :monitoring-event:`RAISE` +* :monitoring-event:`EXCEPTION_HANDLED` The STOP_ITERATION event '''''''''''''''''''''''' :pep:`PEP 380 <380#use-of-stopiteration-to-return-values>` -specifies that a ``StopIteration`` exception is raised when returning a value +specifies that a :exc:`StopIteration` exception is raised when returning a value from a generator or coroutine. However, this is a very inefficient way to return a value, so some Python implementations, notably CPython 3.12+, do not raise an exception unless it would be visible to other code. To allow tools to monitor for real exceptions without slowing down generators -and coroutines, the ``STOP_ITERATION`` event is provided. -``STOP_ITERATION`` can be locally disabled, unlike ``RAISE``. +and coroutines, the :monitoring-event:`STOP_ITERATION` event is provided. +:monitoring-event:`STOP_ITERATION` can be locally disabled, unlike :monitoring-event:`RAISE`. Turning events on and off ------------------------- -In order to monitor an event, it must be turned on and a callback registered. +In order to monitor an event, it must be turned on and a corresponding callback +must be registered. Events can be turned on or off by setting the events either globally or for a particular code object. @@ -198,8 +243,8 @@ Events can be controlled globally by modifying the set of events being monitored .. function:: set_events(tool_id: int, event_set: int) - Activates all events which are set in ``event_set``. - Raises a ``ValueError`` if ``tool_id`` is not in use. + Activates all events which are set in *event_set*. + Raises a :exc:`ValueError` if *tool_id* is not in use. No events are active by default. @@ -210,12 +255,12 @@ Events can also be controlled on a per code object basis. .. function:: get_local_events(tool_id: int, code: CodeType) -> int - Returns all the local events for ``code`` + Returns all the local events for *code* .. function:: set_local_events(tool_id: int, code: CodeType, event_set: int) - Activates all the local events for ``code`` which are set in ``event_set``. - Raises a ``ValueError`` if ``tool_id`` is not in use. + Activates all the local events for *code* which are set in *event_set*. + Raises a :exc:`ValueError` if *tool_id* is not in use. Local events add to global events, but do not mask them. In other words, all global events will trigger for a code object, @@ -225,8 +270,13 @@ regardless of the local events. Disabling events '''''''''''''''' +.. data:: DISABLE + + A special value that can be returned from a callback function to disable + events for the current code location. + Local events can be disabled for a specific code location by returning -``sys.monitoring.DISABLE`` from a callback function. This does not change +:data:`sys.monitoring.DISABLE` from a callback function. This does not change which events are set, or any other code locations for the same event. Disabling events for specific locations is very important for high @@ -235,6 +285,8 @@ debugger with no overhead if the debugger disables all monitoring except for a few breakpoints. +.. _callbacks: + Registering callback functions ------------------------------ @@ -242,11 +294,11 @@ To register a callable for events call .. function:: register_callback(tool_id: int, event: int, func: Callable | None) -> Callable | None - Registers the callable ``func`` for the ``event`` with the given ``tool_id`` + Registers the callable *func* for the *event* with the given *tool_id* - If another callback was registered for the given ``tool_id`` and ``event``, + If another callback was registered for the given *tool_id* and *event*, it is unregistered and returned. - Otherwise ``register_callback`` returns ``None``. + Otherwise :func:`register_callback` returns ``None``. Functions can be unregistered by calling @@ -254,47 +306,51 @@ Functions can be unregistered by calling Callback functions can be registered and unregistered at any time. -Registering or unregistering a callback function will generate a ``sys.audit`` event. +Registering or unregistering a callback function will generate a :func:`sys.audit` event. Callback function arguments ''''''''''''''''''''''''''' +.. data:: MISSING + + A special value that is passed to a callback function to indicate + that there are no arguments to the call. + When an active event occurs, the registered callback function is called. Different events will provide the callback function with different arguments, as follows: -* ``PY_START`` and ``PY_RESUME``:: +* :monitoring-event:`PY_START` and :monitoring-event:`PY_RESUME`:: func(code: CodeType, instruction_offset: int) -> DISABLE | Any -* ``PY_RETURN`` and ``PY_YIELD``: +* :monitoring-event:`PY_RETURN` and :monitoring-event:`PY_YIELD`:: - ``func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any`` + func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any -* ``CALL``, ``C_RAISE`` and ``C_RETURN``: +* :monitoring-event:`CALL`, :monitoring-event:`C_RAISE` and :monitoring-event:`C_RETURN`:: - ``func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any`` + func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any - If there are no arguments, ``arg0`` is set to ``MISSING``. + If there are no arguments, *arg0* is set to :data:`sys.monitoring.MISSING`. -* ``RAISE``, ``RERAISE``, ``EXCEPTION_HANDLED``, ``PY_UNWIND``, ``PY_THROW`` and ``STOP_ITERATION``: +* :monitoring-event:`RAISE`, :monitoring-event:`RERAISE`, :monitoring-event:`EXCEPTION_HANDLED`, + :monitoring-event:`PY_UNWIND`, :monitoring-event:`PY_THROW` and :monitoring-event:`STOP_ITERATION`:: - ``func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any`` + func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any -* ``LINE``: +* :monitoring-event:`LINE`:: - ``func(code: CodeType, line_number: int) -> DISABLE | Any`` + func(code: CodeType, line_number: int) -> DISABLE | Any -* ``BRANCH`` and ``JUMP``: +* :monitoring-event:`BRANCH` and :monitoring-event:`JUMP`:: - ``func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any`` + func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any - Note that the ``destination_offset`` is where the code will next execute. + Note that the *destination_offset* is where the code will next execute. For an untaken branch this will be the offset of the instruction following the branch. -* ``INSTRUCTION``: - - ``func(code: CodeType, instruction_offset: int) -> DISABLE | Any`` - +* :monitoring-event:`INSTRUCTION`:: + func(code: CodeType, instruction_offset: int) -> DISABLE | Any diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index c286bcf34fa8ba..cdb8cf85e20af0 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -607,6 +607,13 @@ def parse_pdb_command(env, sig, signode): return fullname +def parse_monitoring_event(env, sig, signode): + """Transform a monitoring event signature into RST nodes.""" + signode += addnodes.desc_addname('sys.monitoring.events.', 'sys.monitoring.events.') + signode += addnodes.desc_name(sig, sig) + return sig + + def process_audit_events(app, doctree, fromdocname): for node in doctree.traverse(audit_event_list): break @@ -707,6 +714,7 @@ def setup(app): app.add_builder(PydocTopicsBuilder) app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature) app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command) + app.add_object_type('monitoring-event', 'monitoring-event', '%s (monitoring event)', parse_monitoring_event) app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)') app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction) app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod) From e37d56e8ddb8a95ab71d0eaba98c5be326428061 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Oct 2023 06:32:06 +0200 Subject: [PATCH 1047/1206] [3.12] gh-111050: IDLE - Simplify configdialog.HighPage.theme_elements (GH-111053) (#111055) gh-111050: IDLE - Simplify configdialog.HighPage.theme_elements (GH-111053) Replace tuple value with internal name, removing numbers. Remove sorting of already ordered dislay names. Remove '[0]' indexing into now-gone tuple. (cherry picked from commit 642eb8df951f2f1d4bf4d93ee568707c5bf40a96) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/configdialog.py | 44 +++++++++++----------- Lib/idlelib/idle_test/test_configdialog.py | 2 +- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index d56afe8a807fea..eedf97bf74fe6a 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -576,24 +576,23 @@ def create_page_highlight(self): (*)theme_message: Label """ self.theme_elements = { - # Display_name: ('internal_name, sort_number'). - # TODO: remove sort_number unneeded with dict ordering. - 'Normal Code or Text': ('normal', '00'), - 'Code Context': ('context', '01'), - 'Python Keywords': ('keyword', '02'), - 'Python Definitions': ('definition', '03'), - 'Python Builtins': ('builtin', '04'), - 'Python Comments': ('comment', '05'), - 'Python Strings': ('string', '06'), - 'Selected Text': ('hilite', '07'), - 'Found Text': ('hit', '08'), - 'Cursor': ('cursor', '09'), - 'Editor Breakpoint': ('break', '10'), - 'Shell Prompt': ('console', '11'), - 'Error Text': ('error', '12'), - 'Shell User Output': ('stdout', '13'), - 'Shell User Exception': ('stderr', '14'), - 'Line Number': ('linenumber', '16'), + # Display-name: internal-config-tag-name. + 'Normal Code or Text': 'normal', + 'Code Context': 'context', + 'Python Keywords': 'keyword', + 'Python Definitions': 'definition', + 'Python Builtins': 'builtin', + 'Python Comments': 'comment', + 'Python Strings': 'string', + 'Selected Text': 'hilite', + 'Found Text': 'hit', + 'Cursor': 'cursor', + 'Editor Breakpoint': 'break', + 'Shell Prompt': 'console', + 'Error Text': 'error', + 'Shell User Output': 'stdout', + 'Shell User Exception': 'stderr', + 'Line Number': 'linenumber', } self.builtin_name = tracers.add( StringVar(self), self.var_changed_builtin_name) @@ -653,7 +652,7 @@ def tem(event, elem=element): # event.widget.winfo_top_level().highlight_target.set(elem) self.highlight_target.set(elem) text.tag_bind( - self.theme_elements[element][0], '', tem) + self.theme_elements[element], '', tem) text['state'] = 'disabled' self.style.configure('frame_color_set.TFrame', borderwidth=1, relief='solid') @@ -761,7 +760,6 @@ def load_theme_cfg(self): self.set_theme_type() # Load theme element option menu. theme_names = list(self.theme_elements) - theme_names.sort(key=lambda x: self.theme_elements[x][1]) self.targetlist.SetMenu(theme_names, theme_names[0]) self.paint_theme_sample() self.set_highlight_target() @@ -888,7 +886,7 @@ def on_new_color_set(self): new_color = self.color.get() self.style.configure('frame_color_set.TFrame', background=new_color) plane = 'foreground' if self.fg_bg_toggle.get() else 'background' - sample_element = self.theme_elements[self.highlight_target.get()][0] + sample_element = self.theme_elements[self.highlight_target.get()] self.highlight_sample.tag_config(sample_element, **{plane: new_color}) theme = self.custom_name.get() theme_element = sample_element + '-' + plane @@ -1002,7 +1000,7 @@ def set_color_sample(self): frame_color_set """ # Set the color sample area. - tag = self.theme_elements[self.highlight_target.get()][0] + tag = self.theme_elements[self.highlight_target.get()] plane = 'foreground' if self.fg_bg_toggle.get() else 'background' color = self.highlight_sample.tag_cget(tag, plane) self.style.configure('frame_color_set.TFrame', background=color) @@ -1032,7 +1030,7 @@ def paint_theme_sample(self): else: # User theme theme = self.custom_name.get() for element_title in self.theme_elements: - element = self.theme_elements[element_title][0] + element = self.theme_elements[element_title] colors = idleConf.GetHighlight(theme, element) if element == 'cursor': # Cursor sample needs special painting. colors['background'] = idleConf.GetHighlight( diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py index e5d5b4013fca57..6f8518a9bb19d0 100644 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@ -430,7 +430,7 @@ def test_highlight_target_text_mouse(self): def tag_to_element(elem): for element, tag in d.theme_elements.items(): - elem[tag[0]] = element + elem[tag] = element def click_it(start): x, y, dx, dy = hs.bbox(start) From 40db34c901265280a637838af0dde310f89472a0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:18:22 +0200 Subject: [PATCH 1048/1206] [3.12] gh-111031: Check more files in `test_tokenize` (GH-111032) (#111061) gh-111031: Check more files in `test_tokenize` (GH-111032) (cherry picked from commit e9b5399bee7106beeeb38a45cfef3f0ed3fdd703) Co-authored-by: Nikita Sobolev --- Lib/test/test_tokenize.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 57fc149b6a4fa8..bbbc337b1883a9 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1898,19 +1898,9 @@ def test_random_files(self): tempdir = os.path.dirname(__file__) or os.curdir testfiles = glob.glob(os.path.join(glob.escape(tempdir), "test*.py")) - # Tokenize is broken on test_pep3131.py because regular expressions are - # broken on the obscure unicode identifiers in it. *sigh* - # With roundtrip extended to test the 5-tuple mode of untokenize, - # 7 more testfiles fail. Remove them also until the failure is diagnosed. - - testfiles.remove(os.path.join(tempdir, "test_unicode_identifiers.py")) - # TODO: Remove this once we can untokenize PEP 701 syntax testfiles.remove(os.path.join(tempdir, "test_fstring.py")) - for f in ('buffer', 'builtin', 'fileio', 'os', 'platform', 'sys'): - testfiles.remove(os.path.join(tempdir, "test_%s.py") % f) - if not support.is_resource_enabled("cpu"): testfiles = random.sample(testfiles, 10) From 68a5640a362be4f787f3da0e76cd174f7a458a4b Mon Sep 17 00:00:00 2001 From: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:25:49 +0300 Subject: [PATCH 1049/1206] [3.12] gh-108791: Fix pdb CLI invalid argument handling (GH-108816) (#111064) * [3.12] gh-108791: Fix `pdb` CLI invalid argument handling (GH-108816) (cherry picked from commit 162213f2db3835e1115178d38741544f4b4db416) Co-authored-by: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> --- Lib/pdb.py | 6 ++++++ Lib/test/test_pdb.py | 19 +++++++++++++++++-- ...-09-02-16-07-23.gh-issue-108791.fBcAqh.rst | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-02-16-07-23.gh-issue-108791.fBcAqh.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index df01829b48460e..2e048ac5ba6e6a 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -136,6 +136,9 @@ def check(self): if not os.path.exists(self): print('Error:', self.orig, 'does not exist') sys.exit(1) + if os.path.isdir(self): + print('Error:', self.orig, 'is a directory') + sys.exit(1) # Replace pdb's dir with script's dir in front of module search path. sys.path[0] = os.path.dirname(self) @@ -162,6 +165,9 @@ class _ModuleTarget(str): def check(self): try: self._details + except ImportError as e: + print(f"ImportError: {e}") + sys.exit(1) except Exception: traceback.print_exc() sys.exit(1) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 46f9d6ef8a1d44..49a87b1bb47a7c 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -2301,8 +2301,7 @@ def test_module_without_a_main(self): stdout, stderr = self._run_pdb( ['-m', module_name], "", expected_returncode=1 ) - self.assertIn("ImportError: No module named t_main.__main__", - stdout.splitlines()) + self.assertIn("ImportError: No module named t_main.__main__;", stdout) def test_package_without_a_main(self): pkg_name = 't_pkg' @@ -2320,6 +2319,22 @@ def test_package_without_a_main(self): "'t_pkg.t_main' is a package and cannot be directly executed", stdout) + def test_nonexistent_module(self): + assert not os.path.exists(os_helper.TESTFN) + stdout, stderr = self._run_pdb(["-m", os_helper.TESTFN], "", expected_returncode=1) + self.assertIn(f"ImportError: No module named {os_helper.TESTFN}", stdout) + + def test_dir_as_script(self): + with os_helper.temp_dir() as temp_dir: + stdout, stderr = self._run_pdb([temp_dir], "", expected_returncode=1) + self.assertIn(f"Error: {temp_dir} is a directory", stdout) + + def test_invalid_cmd_line_options(self): + stdout, stderr = self._run_pdb(["-c"], "", expected_returncode=1) + self.assertIn(f"Error: option -c requires argument", stdout) + stdout, stderr = self._run_pdb(["--spam"], "", expected_returncode=1) + self.assertIn(f"Error: option --spam not recognized", stdout) + def test_blocks_at_first_code_line(self): script = """ #This is a comment, on line 2 diff --git a/Misc/NEWS.d/next/Library/2023-09-02-16-07-23.gh-issue-108791.fBcAqh.rst b/Misc/NEWS.d/next/Library/2023-09-02-16-07-23.gh-issue-108791.fBcAqh.rst new file mode 100644 index 00000000000000..84a2cd589e10d5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-02-16-07-23.gh-issue-108791.fBcAqh.rst @@ -0,0 +1 @@ +Improved error handling in :mod:`pdb` command line interface, making it produce more concise error messages. From cdcab408a017fd8059921ffa0b4ee85be16e1e87 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:33:03 +0200 Subject: [PATCH 1050/1206] [3.12] GH-101100: Fix reference warnings for ``__getitem__`` (GH-110118) (#111073) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/glossary.rst | 8 ++++---- Doc/library/abc.rst | 2 +- Doc/library/collections.abc.rst | 8 ++++---- Doc/library/collections.rst | 6 +++--- Doc/library/email.compat32-message.rst | 2 +- Doc/library/email.message.rst | 2 +- Doc/library/functions.rst | 4 ++-- Doc/library/mailbox.rst | 2 +- Doc/library/operator.rst | 4 ++-- Doc/library/stdtypes.rst | 2 +- Doc/library/unittest.mock.rst | 2 +- Doc/library/wsgiref.rst | 4 ++-- Doc/library/xml.dom.pulldom.rst | 2 +- Doc/reference/compound_stmts.rst | 2 +- Doc/reference/expressions.rst | 6 +++--- Doc/whatsnew/2.2.rst | 10 +++++----- Doc/whatsnew/2.3.rst | 4 ++-- Doc/whatsnew/3.8.rst | 2 +- Misc/NEWS.d/3.11.0a1.rst | 2 +- Misc/NEWS.d/3.8.0a1.rst | 2 +- 20 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index f3d5c5eede9701..148f15152368f3 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -645,7 +645,7 @@ Glossary iterables include all sequence types (such as :class:`list`, :class:`str`, and :class:`tuple`) and some non-sequence types like :class:`dict`, :term:`file objects `, and objects of any classes you define - with an :meth:`__iter__` method or with a :meth:`__getitem__` method + with an :meth:`__iter__` method or with a :meth:`~object.__getitem__` method that implements :term:`sequence` semantics. Iterables can be @@ -1087,17 +1087,17 @@ Glossary sequence An :term:`iterable` which supports efficient element access using integer - indices via the :meth:`__getitem__` special method and defines a + indices via the :meth:`~object.__getitem__` special method and defines a :meth:`__len__` method that returns the length of the sequence. Some built-in sequence types are :class:`list`, :class:`str`, :class:`tuple`, and :class:`bytes`. Note that :class:`dict` also - supports :meth:`__getitem__` and :meth:`__len__`, but is considered a + supports :meth:`~object.__getitem__` and :meth:`__len__`, but is considered a mapping rather than a sequence because the lookups use arbitrary :term:`immutable` keys rather than integers. The :class:`collections.abc.Sequence` abstract base class defines a much richer interface that goes beyond just - :meth:`__getitem__` and :meth:`__len__`, adding :meth:`count`, + :meth:`~object.__getitem__` and :meth:`__len__`, adding :meth:`count`, :meth:`index`, :meth:`__contains__`, and :meth:`__reversed__`. Types that implement this expanded interface can be registered explicitly using diff --git a/Doc/library/abc.rst b/Doc/library/abc.rst index 274b2d69f0ab5c..fb4f9da169c5ab 100644 --- a/Doc/library/abc.rst +++ b/Doc/library/abc.rst @@ -154,7 +154,7 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: Finally, the last line makes ``Foo`` a virtual subclass of ``MyIterable``, even though it does not define an :meth:`~iterator.__iter__` method (it uses the old-style iterable protocol, defined in terms of :meth:`__len__` and - :meth:`__getitem__`). Note that this will not make ``get_iterator`` + :meth:`~object.__getitem__`). Note that this will not make ``get_iterator`` available as a method of ``Foo``, so it is provided separately. diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index 43a3286ba832cf..edc078953290d7 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -192,7 +192,7 @@ ABC Inherits from Abstract Methods Mi .. [2] Checking ``isinstance(obj, Iterable)`` detects classes that are registered as :class:`Iterable` or that have an :meth:`__iter__` method, but it does not detect classes that iterate with the - :meth:`__getitem__` method. The only reliable way to determine + :meth:`~object.__getitem__` method. The only reliable way to determine whether an object is :term:`iterable` is to call ``iter(obj)``. @@ -222,7 +222,7 @@ Collections Abstract Base Classes -- Detailed Descriptions Checking ``isinstance(obj, Iterable)`` detects classes that are registered as :class:`Iterable` or that have an :meth:`__iter__` method, but it does - not detect classes that iterate with the :meth:`__getitem__` method. + not detect classes that iterate with the :meth:`~object.__getitem__` method. The only reliable way to determine whether an object is :term:`iterable` is to call ``iter(obj)``. @@ -262,8 +262,8 @@ Collections Abstract Base Classes -- Detailed Descriptions Implementation note: Some of the mixin methods, such as :meth:`__iter__`, :meth:`__reversed__` and :meth:`index`, make - repeated calls to the underlying :meth:`__getitem__` method. - Consequently, if :meth:`__getitem__` is implemented with constant + repeated calls to the underlying :meth:`~object.__getitem__` method. + Consequently, if :meth:`~object.__getitem__` is implemented with constant access speed, the mixin methods will have linear performance; however, if the underlying method is linear (as it would be with a linked list), the mixins will have quadratic performance and will diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 41896d70c92577..eec2330ca97fd0 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -743,12 +743,12 @@ stack manipulations such as ``dup``, ``drop``, ``swap``, ``over``, ``pick``, If calling :attr:`default_factory` raises an exception this exception is propagated unchanged. - This method is called by the :meth:`__getitem__` method of the + This method is called by the :meth:`~object.__getitem__` method of the :class:`dict` class when the requested key is not found; whatever it - returns or raises is then returned or raised by :meth:`__getitem__`. + returns or raises is then returned or raised by :meth:`~object.__getitem__`. Note that :meth:`__missing__` is *not* called for any operations besides - :meth:`__getitem__`. This means that :meth:`get` will, like normal + :meth:`~object.__getitem__`. This means that :meth:`get` will, like normal dictionaries, return ``None`` as a default rather than using :attr:`default_factory`. diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst index 5bef155a4af310..c4c322a82e1f44 100644 --- a/Doc/library/email.compat32-message.rst +++ b/Doc/library/email.compat32-message.rst @@ -367,7 +367,7 @@ Here are the methods of the :class:`Message` class: .. method:: get(name, failobj=None) Return the value of the named header field. This is identical to - :meth:`__getitem__` except that optional *failobj* is returned if the + :meth:`~object.__getitem__` except that optional *failobj* is returned if the named header is missing (defaults to ``None``). Here are some additional useful methods: diff --git a/Doc/library/email.message.rst b/Doc/library/email.message.rst index 225f498781fa86..f58d93da6ed687 100644 --- a/Doc/library/email.message.rst +++ b/Doc/library/email.message.rst @@ -247,7 +247,7 @@ message objects. .. method:: get(name, failobj=None) Return the value of the named header field. This is identical to - :meth:`__getitem__` except that optional *failobj* is returned if the + :meth:`~object.__getitem__` except that optional *failobj* is returned if the named header is missing (*failobj* defaults to ``None``). diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 3277edd483b46b..954c7c0313e69c 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -983,7 +983,7 @@ are always available. They are listed here in alphabetical order. differently depending on the presence of the second argument. Without a second argument, *object* must be a collection object which supports the :term:`iterable` protocol (the :meth:`__iter__` method), or it must support - the sequence protocol (the :meth:`__getitem__` method with integer arguments + the sequence protocol (the :meth:`~object.__getitem__` method with integer arguments starting at ``0``). If it does not support either of those protocols, :exc:`TypeError` is raised. If the second argument, *sentinel*, is given, then *object* must be a callable object. The iterator created in this case @@ -1563,7 +1563,7 @@ are always available. They are listed here in alphabetical order. Return a reverse :term:`iterator`. *seq* must be an object which has a :meth:`__reversed__` method or supports the sequence protocol (the - :meth:`__len__` method and the :meth:`__getitem__` method with integer + :meth:`__len__` method and the :meth:`~object.__getitem__` method with integer arguments starting at ``0``). diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst index 91df07d914cae2..b27deb20f13236 100644 --- a/Doc/library/mailbox.rst +++ b/Doc/library/mailbox.rst @@ -167,7 +167,7 @@ Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. Return a representation of the message corresponding to *key*. If no such message exists, *default* is returned if the method was called as :meth:`get` and a :exc:`KeyError` exception is raised if the method was - called as :meth:`__getitem__`. The message is represented as an instance + called as :meth:`~object.__getitem__`. The message is represented as an instance of the appropriate format-specific :class:`Message` subclass unless a custom message factory was specified when the :class:`Mailbox` instance was initialized. diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index 57c67bcf3aa12e..96f2c287875d41 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -306,7 +306,7 @@ expect a function argument. itemgetter(*items) Return a callable object that fetches *item* from its operand using the - operand's :meth:`__getitem__` method. If multiple items are specified, + operand's :meth:`~object.__getitem__` method. If multiple items are specified, returns a tuple of lookup values. For example: * After ``f = itemgetter(2)``, the call ``f(r)`` returns ``r[2]``. @@ -326,7 +326,7 @@ expect a function argument. return tuple(obj[item] for item in items) return g - The items can be any type accepted by the operand's :meth:`__getitem__` + The items can be any type accepted by the operand's :meth:`~object.__getitem__` method. Dictionaries accept any :term:`hashable` value. Lists, tuples, and strings accept an index or a slice: diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 46ae60583df7d7..7891c32214391e 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2264,7 +2264,7 @@ expression support in the :mod:`re` module). Return a copy of the string in which each character has been mapped through the given translation table. The table must be an object that implements - indexing via :meth:`__getitem__`, typically a :term:`mapping` or + indexing via :meth:`~object.__getitem__`, typically a :term:`mapping` or :term:`sequence`. When indexed by a Unicode ordinal (an integer), the table object can do any of the following: return a Unicode ordinal or a string, to map the character to one or more other characters; return diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 3d8393c105ec32..25f6445732a520 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -1658,7 +1658,7 @@ Keywords can be used in the :func:`patch.dict` call to set values in the diction :func:`patch.dict` can be used with dictionary like objects that aren't actually dictionaries. At the very minimum they must support item getting, setting, deleting and either iteration or membership test. This corresponds to the -magic methods :meth:`__getitem__`, :meth:`__setitem__`, :meth:`__delitem__` and either +magic methods :meth:`~object.__getitem__`, :meth:`__setitem__`, :meth:`__delitem__` and either :meth:`__iter__` or :meth:`__contains__`. >>> class Container: diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst index 39a4c1ba142338..be9e56b04c1fbf 100644 --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -180,7 +180,7 @@ also provides these miscellaneous utilities: print(chunk) .. versionchanged:: 3.11 - Support for :meth:`__getitem__` method has been removed. + Support for :meth:`~object.__getitem__` method has been removed. :mod:`wsgiref.headers` -- WSGI response header tools @@ -201,7 +201,7 @@ manipulation of WSGI response headers using a mapping-like interface. an empty list. :class:`Headers` objects support typical mapping operations including - :meth:`__getitem__`, :meth:`get`, :meth:`__setitem__`, :meth:`setdefault`, + :meth:`~object.__getitem__`, :meth:`get`, :meth:`__setitem__`, :meth:`setdefault`, :meth:`__delitem__` and :meth:`__contains__`. For each of these methods, the key is the header name (treated case-insensitively), and the value is the first value associated with that header name. Setting a header diff --git a/Doc/library/xml.dom.pulldom.rst b/Doc/library/xml.dom.pulldom.rst index d1df465a598e53..843c2fd7fdb937 100644 --- a/Doc/library/xml.dom.pulldom.rst +++ b/Doc/library/xml.dom.pulldom.rst @@ -115,7 +115,7 @@ DOMEventStream Objects .. class:: DOMEventStream(stream, parser, bufsize) .. versionchanged:: 3.11 - Support for :meth:`__getitem__` method has been removed. + Support for :meth:`~object.__getitem__` method has been removed. .. method:: getEvent() diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index f79db828604b24..52308f30d85409 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -1058,7 +1058,7 @@ subject value: .. note:: Key-value pairs are matched using the two-argument form of the mapping subject's ``get()`` method. Matched key-value pairs must already be present in the mapping, and not created on-the-fly via :meth:`__missing__` or - :meth:`__getitem__`. + :meth:`~object.__getitem__`. In simple terms ``{KEY1: P1, KEY2: P2, ... }`` matches only if all the following happens: diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 26adc17e76ae08..cac7ae7efa3d4d 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -882,7 +882,7 @@ to the index so that, for example, ``x[-1]`` selects the last item of ``x``. The resulting value must be a nonnegative integer less than the number of items in the sequence, and the subscription selects the item whose index is that value (counting from zero). Since the support for negative indices and slicing -occurs in the object's :meth:`__getitem__` method, subclasses overriding +occurs in the object's :meth:`~object.__getitem__` method, subclasses overriding this method will need to explicitly add that support. .. index:: @@ -937,7 +937,7 @@ slice list contains no proper slice). single: step (slice object attribute) The semantics for a slicing are as follows. The primary is indexed (using the -same :meth:`__getitem__` method as +same :meth:`~object.__getitem__` method as normal subscription) with a key that is constructed from the slice list, as follows. If the slice list contains at least one comma, the key is a tuple containing the conversion of the slice items; otherwise, the conversion of the @@ -1663,7 +1663,7 @@ If an exception is raised during the iteration, it is as if :keyword:`in` raised that exception. Lastly, the old-style iteration protocol is tried: if a class defines -:meth:`__getitem__`, ``x in y`` is ``True`` if and only if there is a non-negative +:meth:`~object.__getitem__`, ``x in y`` is ``True`` if and only if there is a non-negative integer index *i* such that ``x is y[i] or x == y[i]``, and no lower integer index raises the :exc:`IndexError` exception. (If any other exception is raised, it is as if :keyword:`in` raised that exception). diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index d9ead57413cbbf..6dfe79cef00987 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -424,22 +424,22 @@ Another significant addition to 2.2 is an iteration interface at both the C and Python levels. Objects can define how they can be looped over by callers. In Python versions up to 2.1, the usual way to make ``for item in obj`` work is -to define a :meth:`__getitem__` method that looks something like this:: +to define a :meth:`~object.__getitem__` method that looks something like this:: def __getitem__(self, index): return -:meth:`__getitem__` is more properly used to define an indexing operation on an +:meth:`~object.__getitem__` is more properly used to define an indexing operation on an object so that you can write ``obj[5]`` to retrieve the sixth element. It's a bit misleading when you're using this only to support :keyword:`for` loops. Consider some file-like object that wants to be looped over; the *index* parameter is essentially meaningless, as the class probably assumes that a -series of :meth:`__getitem__` calls will be made with *index* incrementing by -one each time. In other words, the presence of the :meth:`__getitem__` method +series of :meth:`~object.__getitem__` calls will be made with *index* incrementing by +one each time. In other words, the presence of the :meth:`~object.__getitem__` method doesn't mean that using ``file[5]`` to randomly access the sixth element will work, though it really should. -In Python 2.2, iteration can be implemented separately, and :meth:`__getitem__` +In Python 2.2, iteration can be implemented separately, and :meth:`~object.__getitem__` methods can be limited to classes that really do support random access. The basic idea of iterators is simple. A new built-in function, ``iter(obj)`` or ``iter(C, sentinel)``, is used to get an iterator. ``iter(obj)`` returns diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index 0442c9fdd08ce3..be5b3026d935b0 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -925,7 +925,7 @@ Deletion is more straightforward:: >>> a [1, 3] -One can also now pass slice objects to the :meth:`__getitem__` methods of the +One can also now pass slice objects to the :meth:`~object.__getitem__` methods of the built-in sequences:: >>> range(10).__getitem__(slice(0, 5, 2)) @@ -1596,7 +1596,7 @@ complete list of changes, or look through the CVS logs for all the details. module. Adding the mix-in as a superclass provides the full dictionary interface - whenever the class defines :meth:`__getitem__`, :meth:`__setitem__`, + whenever the class defines :meth:`~object.__getitem__`, :meth:`__setitem__`, :meth:`__delitem__`, and :meth:`keys`. For example:: >>> import UserDict diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 6cbc06efeb93a6..e79b7cade7baf3 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1653,7 +1653,7 @@ Deprecated deprecated and will be prohibited in Python 3.9. (Contributed by Elvis Pranskevichus in :issue:`34075`.) -* The :meth:`__getitem__` methods of :class:`xml.dom.pulldom.DOMEventStream`, +* The :meth:`~object.__getitem__` methods of :class:`xml.dom.pulldom.DOMEventStream`, :class:`wsgiref.util.FileWrapper` and :class:`fileinput.FileInput` have been deprecated. diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index 45fb725aac80e3..d30acb3e064076 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -1720,7 +1720,7 @@ Improve the speed and accuracy of statistics.pvariance(). .. nonce: WI9zQY .. section: Library -Remove :meth:`__getitem__` methods of +Remove :meth:`~object.__getitem__` methods of :class:`xml.dom.pulldom.DOMEventStream`, :class:`wsgiref.util.FileWrapper` and :class:`fileinput.FileInput`, deprecated since Python 3.9. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index cb635e617e3ac6..4a5467a8bbd510 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -3592,7 +3592,7 @@ Python 3.5. .. nonce: V8Ou3K .. section: Library -Deprecate :meth:`__getitem__` methods of +Deprecate :meth:`~object.__getitem__` methods of :class:`xml.dom.pulldom.DOMEventStream`, :class:`wsgiref.util.FileWrapper` and :class:`fileinput.FileInput`. From 91a6e98e927ac529adeff57d33e87abcf448efec Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:34:25 +0200 Subject: [PATCH 1051/1206] [3.12] GH-101100: Fix reference warnings for ``__enter__`` and ``__exit__`` (GH-110112) (#111075) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/glossary.rst | 2 +- Doc/library/contextlib.rst | 22 +++++++++++----------- Doc/library/stdtypes.rst | 2 +- Doc/library/test.rst | 2 +- Doc/library/unittest.mock.rst | 4 ++-- Doc/reference/compound_stmts.rst | 20 ++++++++++---------- Doc/reference/datamodel.rst | 6 +++--- Doc/whatsnew/2.5.rst | 22 +++++++++++----------- Doc/whatsnew/2.6.rst | 26 +++++++++++++------------- Doc/whatsnew/2.7.rst | 8 ++++---- Misc/NEWS.d/3.10.0a7.rst | 2 +- 11 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 148f15152368f3..e43e755932b690 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -248,7 +248,7 @@ Glossary context manager An object which controls the environment seen in a :keyword:`with` - statement by defining :meth:`__enter__` and :meth:`__exit__` methods. + statement by defining :meth:`~object.__enter__` and :meth:`~object.__exit__` methods. See :pep:`343`. context variable diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 7cd081d1f54f43..66b9c137105223 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -45,7 +45,7 @@ Functions and classes provided: This function is a :term:`decorator` that can be used to define a factory function for :keyword:`with` statement context managers, without needing to - create a class or separate :meth:`__enter__` and :meth:`__exit__` methods. + create a class or separate :meth:`~object.__enter__` and :meth:`~object.__exit__` methods. While many objects natively support use in with statements, sometimes a resource needs to be managed that isn't a context manager in its own right, @@ -515,7 +515,7 @@ Functions and classes provided: # the with statement, even if attempts to open files later # in the list raise an exception - The :meth:`__enter__` method returns the :class:`ExitStack` instance, and + The :meth:`~object.__enter__` method returns the :class:`ExitStack` instance, and performs no additional operations. Each instance maintains a stack of registered callbacks that are called in @@ -543,9 +543,9 @@ Functions and classes provided: .. method:: enter_context(cm) - Enters a new context manager and adds its :meth:`__exit__` method to + Enters a new context manager and adds its :meth:`~object.__exit__` method to the callback stack. The return value is the result of the context - manager's own :meth:`__enter__` method. + manager's own :meth:`~object.__enter__` method. These context managers may suppress exceptions just as they normally would if used directly as part of a :keyword:`with` statement. @@ -556,18 +556,18 @@ Functions and classes provided: .. method:: push(exit) - Adds a context manager's :meth:`__exit__` method to the callback stack. + Adds a context manager's :meth:`~object.__exit__` method to the callback stack. As ``__enter__`` is *not* invoked, this method can be used to cover - part of an :meth:`__enter__` implementation with a context manager's own - :meth:`__exit__` method. + part of an :meth:`~object.__enter__` implementation with a context manager's own + :meth:`~object.__exit__` method. If passed an object that is not a context manager, this method assumes it is a callback with the same signature as a context manager's - :meth:`__exit__` method and adds it directly to the callback stack. + :meth:`~object.__exit__` method and adds it directly to the callback stack. By returning true values, these callbacks can suppress exceptions the - same way context manager :meth:`__exit__` methods can. + same way context manager :meth:`~object.__exit__` methods can. The passed in object is returned from the function, allowing this method to be used as a function decorator. @@ -714,7 +714,7 @@ Cleaning up in an ``__enter__`` implementation As noted in the documentation of :meth:`ExitStack.push`, this method can be useful in cleaning up an already allocated resource if later -steps in the :meth:`__enter__` implementation fail. +steps in the :meth:`~object.__enter__` implementation fail. Here's an example of doing this for a context manager that accepts resource acquisition and release functions, along with an optional validation function, @@ -871,7 +871,7 @@ And also as a function decorator:: Note that there is one additional limitation when using context managers as function decorators: there's no way to access the return value of -:meth:`__enter__`. If that value is needed, then it is still necessary to use +:meth:`~object.__enter__`. If that value is needed, then it is still necessary to use an explicit ``with`` statement. .. seealso:: diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 7891c32214391e..4d44ca2766416d 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4854,7 +4854,7 @@ before the statement body is executed and exited when the statement ends: The exception passed in should never be reraised explicitly - instead, this method should return a false value to indicate that the method completed successfully and does not want to suppress the raised exception. This allows - context management code to easily detect whether or not an :meth:`__exit__` + context management code to easily detect whether or not an :meth:`~object.__exit__` method has actually failed. Python defines several context managers to support easy thread synchronisation, diff --git a/Doc/library/test.rst b/Doc/library/test.rst index de60151bb32ce1..6be77260faa7ea 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1043,7 +1043,7 @@ The :mod:`test.support` module defines the following classes: :const:`resource.RLIMIT_CORE`'s soft limit to 0 to prevent coredump file creation. - On both platforms, the old value is restored by :meth:`__exit__`. + On both platforms, the old value is restored by :meth:`~object.__exit__`. .. class:: SaveSignals() diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 25f6445732a520..175ab0fb237dac 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2482,8 +2482,8 @@ are closed properly and is becoming common:: f.write('something') The issue is that even if you mock out the call to :func:`open` it is the -*returned object* that is used as a context manager (and has :meth:`__enter__` and -:meth:`__exit__` called). +*returned object* that is used as a context manager (and has :meth:`~object.__enter__` and +:meth:`~object.__exit__` called). Mocking context managers with a :class:`MagicMock` is common enough and fiddly enough that a helper function is useful. :: diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 52308f30d85409..8f6481339837a0 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -489,37 +489,37 @@ The execution of the :keyword:`with` statement with one "item" proceeds as follo #. The context expression (the expression given in the :token:`~python-grammar:with_item`) is evaluated to obtain a context manager. -#. The context manager's :meth:`__enter__` is loaded for later use. +#. The context manager's :meth:`~object.__enter__` is loaded for later use. -#. The context manager's :meth:`__exit__` is loaded for later use. +#. The context manager's :meth:`~object.__exit__` is loaded for later use. -#. The context manager's :meth:`__enter__` method is invoked. +#. The context manager's :meth:`~object.__enter__` method is invoked. #. If a target was included in the :keyword:`with` statement, the return value - from :meth:`__enter__` is assigned to it. + from :meth:`~object.__enter__` is assigned to it. .. note:: - The :keyword:`with` statement guarantees that if the :meth:`__enter__` - method returns without an error, then :meth:`__exit__` will always be + The :keyword:`with` statement guarantees that if the :meth:`~object.__enter__` + method returns without an error, then :meth:`~object.__exit__` will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 7 below. #. The suite is executed. -#. The context manager's :meth:`__exit__` method is invoked. If an exception +#. The context manager's :meth:`~object.__exit__` method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as - arguments to :meth:`__exit__`. Otherwise, three :const:`None` arguments are + arguments to :meth:`~object.__exit__`. Otherwise, three :const:`None` arguments are supplied. If the suite was exited due to an exception, and the return value from the - :meth:`__exit__` method was false, the exception is reraised. If the return + :meth:`~object.__exit__` method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following the :keyword:`with` statement. If the suite was exited for any reason other than an exception, the return - value from :meth:`__exit__` is ignored, and execution proceeds at the normal + value from :meth:`~object.__exit__` is ignored, and execution proceeds at the normal location for the kind of exit that was taken. The following code:: diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 362ac752149c05..b8ad4c7b7a94ad 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2939,7 +2939,7 @@ For more information on context managers, see :ref:`typecontextmanager`. (i.e., prevent it from being propagated), it should return a true value. Otherwise, the exception will be processed normally upon exit from this method. - Note that :meth:`__exit__` methods should not reraise the passed-in exception; + Note that :meth:`~object.__exit__` methods should not reraise the passed-in exception; this is the caller's responsibility. @@ -3257,12 +3257,12 @@ Asynchronous context managers can be used in an :keyword:`async with` statement. .. method:: object.__aenter__(self) - Semantically similar to :meth:`__enter__`, the only + Semantically similar to :meth:`~object.__enter__`, the only difference being that it must return an *awaitable*. .. method:: object.__aexit__(self, exc_type, exc_value, traceback) - Semantically similar to :meth:`__exit__`, the only + Semantically similar to :meth:`~object.__exit__`, the only difference being that it must return an *awaitable*. An example of an asynchronous context manager class:: diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index f58b3ede27facc..ad0931ecbed060 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -575,15 +575,15 @@ structure is:: with-block The expression is evaluated, and it should result in an object that supports the -context management protocol (that is, has :meth:`__enter__` and :meth:`__exit__` +context management protocol (that is, has :meth:`~object.__enter__` and :meth:`~object.__exit__` methods. -The object's :meth:`__enter__` is called before *with-block* is executed and +The object's :meth:`~object.__enter__` is called before *with-block* is executed and therefore can run set-up code. It also may return a value that is bound to the name *variable*, if given. (Note carefully that *variable* is *not* assigned the result of *expression*.) -After execution of the *with-block* is finished, the object's :meth:`__exit__` +After execution of the *with-block* is finished, the object's :meth:`~object.__exit__` method is called, even if the block raised an exception, and can therefore run clean-up code. @@ -609,7 +609,7 @@ part-way through the block. .. note:: In this case, *f* is the same object created by :func:`open`, because - :meth:`file.__enter__` returns *self*. + :meth:`~object.__enter__` returns *self*. The :mod:`threading` module's locks and condition variables also support the ':keyword:`with`' statement:: @@ -652,10 +652,10 @@ underlying implementation and should keep reading. A high-level explanation of the context management protocol is: * The expression is evaluated and should result in an object called a "context - manager". The context manager must have :meth:`__enter__` and :meth:`__exit__` + manager". The context manager must have :meth:`~object.__enter__` and :meth:`~object.__exit__` methods. -* The context manager's :meth:`__enter__` method is called. The value returned +* The context manager's :meth:`~object.__enter__` method is called. The value returned is assigned to *VAR*. If no ``'as VAR'`` clause is present, the value is simply discarded. @@ -669,7 +669,7 @@ A high-level explanation of the context management protocol is: if you do the author of the code containing the ':keyword:`with`' statement will never realize anything went wrong. -* If *BLOCK* didn't raise an exception, the :meth:`__exit__` method is still +* If *BLOCK* didn't raise an exception, the :meth:`~object.__exit__` method is still called, but *type*, *value*, and *traceback* are all ``None``. Let's think through an example. I won't present detailed code but will only @@ -703,7 +703,7 @@ rolled back if there's an exception. Here's the basic interface for def rollback (self): "Rolls back current transaction" -The :meth:`__enter__` method is pretty easy, having only to start a new +The :meth:`~object.__enter__` method is pretty easy, having only to start a new transaction. For this application the resulting cursor object would be a useful result, so the method will return it. The user can then add ``as cursor`` to their ':keyword:`with`' statement to bind the cursor to a variable name. :: @@ -715,7 +715,7 @@ their ':keyword:`with`' statement to bind the cursor to a variable name. :: cursor = self.cursor() return cursor -The :meth:`__exit__` method is the most complicated because it's where most of +The :meth:`~object.__exit__` method is the most complicated because it's where most of the work has to be done. The method has to check if an exception occurred. If there was no exception, the transaction is committed. The transaction is rolled back if there was an exception. @@ -748,10 +748,10 @@ are useful for writing objects for use with the ':keyword:`with`' statement. The decorator is called :func:`contextmanager`, and lets you write a single generator function instead of defining a new class. The generator should yield exactly one value. The code up to the :keyword:`yield` will be executed as the -:meth:`__enter__` method, and the value yielded will be the method's return +:meth:`~object.__enter__` method, and the value yielded will be the method's return value that will get bound to the variable in the ':keyword:`with`' statement's :keyword:`!as` clause, if any. The code after the :keyword:`yield` will be -executed in the :meth:`__exit__` method. Any exception raised in the block will +executed in the :meth:`~object.__exit__` method. Any exception raised in the block will be raised by the :keyword:`!yield` statement. Our database example from the previous section could be written using this diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 759a0757ebefa7..2b7ef2cd4fe4a9 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -269,15 +269,15 @@ structure is:: with-block The expression is evaluated, and it should result in an object that supports the -context management protocol (that is, has :meth:`__enter__` and :meth:`__exit__` +context management protocol (that is, has :meth:`~object.__enter__` and :meth:`~object.__exit__` methods). -The object's :meth:`__enter__` is called before *with-block* is executed and +The object's :meth:`~object.__enter__` is called before *with-block* is executed and therefore can run set-up code. It also may return a value that is bound to the name *variable*, if given. (Note carefully that *variable* is *not* assigned the result of *expression*.) -After execution of the *with-block* is finished, the object's :meth:`__exit__` +After execution of the *with-block* is finished, the object's :meth:`~object.__exit__` method is called, even if the block raised an exception, and can therefore run clean-up code. @@ -296,7 +296,7 @@ part-way through the block. .. note:: In this case, *f* is the same object created by :func:`open`, because - :meth:`file.__enter__` returns *self*. + :meth:`~object.__enter__` returns *self*. The :mod:`threading` module's locks and condition variables also support the ':keyword:`with`' statement:: @@ -339,16 +339,16 @@ underlying implementation and should keep reading. A high-level explanation of the context management protocol is: * The expression is evaluated and should result in an object called a "context - manager". The context manager must have :meth:`__enter__` and :meth:`__exit__` + manager". The context manager must have :meth:`~object.__enter__` and :meth:`~object.__exit__` methods. -* The context manager's :meth:`__enter__` method is called. The value returned +* The context manager's :meth:`~object.__enter__` method is called. The value returned is assigned to *VAR*. If no ``as VAR`` clause is present, the value is simply discarded. * The code in *BLOCK* is executed. -* If *BLOCK* raises an exception, the context manager's :meth:`__exit__` method +* If *BLOCK* raises an exception, the context manager's :meth:`~object.__exit__` method is called with three arguments, the exception details (``type, value, traceback``, the same values returned by :func:`sys.exc_info`, which can also be ``None`` if no exception occurred). The method's return value controls whether an exception @@ -357,7 +357,7 @@ A high-level explanation of the context management protocol is: if you do the author of the code containing the ':keyword:`with`' statement will never realize anything went wrong. -* If *BLOCK* didn't raise an exception, the :meth:`__exit__` method is still +* If *BLOCK* didn't raise an exception, the :meth:`~object.__exit__` method is still called, but *type*, *value*, and *traceback* are all ``None``. Let's think through an example. I won't present detailed code but will only @@ -391,7 +391,7 @@ rolled back if there's an exception. Here's the basic interface for def rollback(self): "Rolls back current transaction" -The :meth:`__enter__` method is pretty easy, having only to start a new +The :meth:`~object.__enter__` method is pretty easy, having only to start a new transaction. For this application the resulting cursor object would be a useful result, so the method will return it. The user can then add ``as cursor`` to their ':keyword:`with`' statement to bind the cursor to a variable name. :: @@ -403,7 +403,7 @@ their ':keyword:`with`' statement to bind the cursor to a variable name. :: cursor = self.cursor() return cursor -The :meth:`__exit__` method is the most complicated because it's where most of +The :meth:`~object.__exit__` method is the most complicated because it's where most of the work has to be done. The method has to check if an exception occurred. If there was no exception, the transaction is committed. The transaction is rolled back if there was an exception. @@ -436,10 +436,10 @@ are useful when writing objects for use with the ':keyword:`with`' statement. The decorator is called :func:`contextmanager`, and lets you write a single generator function instead of defining a new class. The generator should yield exactly one value. The code up to the :keyword:`yield` will be executed as the -:meth:`__enter__` method, and the value yielded will be the method's return +:meth:`~object.__enter__` method, and the value yielded will be the method's return value that will get bound to the variable in the ':keyword:`with`' statement's :keyword:`!as` clause, if any. The code after the :keyword:`!yield` will be -executed in the :meth:`__exit__` method. Any exception raised in the block will +executed in the :meth:`~object.__exit__` method. Any exception raised in the block will be raised by the :keyword:`!yield` statement. Using this decorator, our database example from the previous section @@ -1737,7 +1737,7 @@ Optimizations (Contributed by Antoine Pitrou.) Memory usage is reduced by using pymalloc for the Unicode string's data. -* The ``with`` statement now stores the :meth:`__exit__` method on the stack, +* The ``with`` statement now stores the :meth:`~object.__exit__` method on the stack, producing a small speedup. (Implemented by Jeffrey Yasskin.) * To reduce memory usage, the garbage collector will now clear internal diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 7c81cc17f5c7d3..6413877db456ef 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -930,8 +930,8 @@ Optimizations Several performance enhancements have been added: * A new opcode was added to perform the initial setup for - :keyword:`with` statements, looking up the :meth:`__enter__` and - :meth:`__exit__` methods. (Contributed by Benjamin Peterson.) + :keyword:`with` statements, looking up the :meth:`~object.__enter__` and + :meth:`~object.__exit__` methods. (Contributed by Benjamin Peterson.) * The garbage collector now performs better for one common usage pattern: when many objects are being allocated without deallocating @@ -2449,13 +2449,13 @@ that may require changes to your code: (Changed by Eric Smith; :issue:`5920`.) * Because of an optimization for the :keyword:`with` statement, the special - methods :meth:`__enter__` and :meth:`__exit__` must belong to the object's + methods :meth:`~object.__enter__` and :meth:`~object.__exit__` must belong to the object's type, and cannot be directly attached to the object's instance. This affects new-style classes (derived from :class:`object`) and C extension types. (:issue:`6101`.) * Due to a bug in Python 2.6, the *exc_value* parameter to - :meth:`__exit__` methods was often the string representation of the + :meth:`~object.__exit__` methods was often the string representation of the exception, not an instance. This was fixed in 2.7, so *exc_value* will be an instance as expected. (Fixed by Florent Xicluna; :issue:`7853`.) diff --git a/Misc/NEWS.d/3.10.0a7.rst b/Misc/NEWS.d/3.10.0a7.rst index 3a1694f444616a..d9cdfbd04c88d4 100644 --- a/Misc/NEWS.d/3.10.0a7.rst +++ b/Misc/NEWS.d/3.10.0a7.rst @@ -274,7 +274,7 @@ Co-authored-by: Tim Peters Only handle asynchronous exceptions and requests to drop the GIL when returning from a call or on the back edges of loops. Makes sure that -:meth:`__exit__` is always called in with statements, even for interrupts. +:meth:`~object.__exit__` is always called in with statements, even for interrupts. .. From 3e9d84c94c532afbb4c0e8779fcc0b90e829559e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 19 Oct 2023 17:35:04 +0200 Subject: [PATCH 1052/1206] [3.12] gh-109510: Clearly explain "Which Docstrings Are Examined" (GH-109696) (#111077) Co-authored-by: Unique-Usman <86585626+Unique-Usman@users.noreply.github.com> Co-authored-by: Mariatta Co-authored-by: Jacob Coffee Co-authored-by: Hugo van Kemenade Co-authored-by: C.A.M. Gerlach --- Doc/library/doctest.rst | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index d6e4dca0860671..b5583e46a682aa 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -277,13 +277,34 @@ Which Docstrings Are Examined? The module docstring, and all function, class and method docstrings are searched. Objects imported into the module are not searched. -In addition, if ``M.__test__`` exists and "is true", it must be a dict, and each +In addition, there are cases when you want tests to be part of a module but not part +of the help text, which requires that the tests not be included in the docstring. +Doctest looks for a module-level variable called ``__test__`` and uses it to locate other +tests. If ``M.__test__`` exists and is truthy, it must be a dict, and each entry maps a (string) name to a function object, class object, or string. Function and class object docstrings found from ``M.__test__`` are searched, and strings are treated as if they were docstrings. In output, a key ``K`` in -``M.__test__`` appears with name :: +``M.__test__`` appears with name ``M.__test__.K``. - .__test__.K +For example, place this block of code at the top of :file:`example.py`: + +.. code-block:: python + + __test__ = { + 'numbers': """ + >>> factorial(6) + 720 + + >>> [factorial(n) for n in range(6)] + [1, 1, 2, 6, 24, 120] + """ + } + +The value of ``example.__test__["numbers"]`` will be treated as a +docstring and all the tests inside it will be run. It is +important to note that the value can be mapped to a function, +class object, or module; if so, :mod:`!doctest` +searches them recursively for docstrings, which are then scanned for tests. Any classes found are recursively searched similarly, to test docstrings in their contained methods and nested classes. From 41dfae8f8620d33121ca19c53d132457c5875c98 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 19 Oct 2023 18:38:58 +0300 Subject: [PATCH 1053/1206] [3.12] gh-101100: Fix sphinx warnings in `library/getpass.rst` (GH-110461) (#111080) Co-authored-by: Nikita Sobolev --- Doc/library/getpass.rst | 2 +- Doc/tools/.nitignore | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/library/getpass.rst b/Doc/library/getpass.rst index d5bbe67fb30a62..5c79daf0f47d8e 100644 --- a/Doc/library/getpass.rst +++ b/Doc/library/getpass.rst @@ -43,7 +43,7 @@ The :mod:`getpass` module provides two functions: Return the "login name" of the user. This function checks the environment variables :envvar:`LOGNAME`, - :envvar:`USER`, :envvar:`LNAME` and :envvar:`USERNAME`, in order, and + :envvar:`USER`, :envvar:`!LNAME` and :envvar:`USERNAME`, in order, and returns the value of the first one which is set to a non-empty string. If none are set, the login name from the password database is returned on systems which support the :mod:`pwd` module, otherwise, an exception is diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 431609b1d0f9c0..f55c238489d4f3 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -76,7 +76,6 @@ Doc/library/ftplib.rst Doc/library/functions.rst Doc/library/functools.rst Doc/library/getopt.rst -Doc/library/getpass.rst Doc/library/gettext.rst Doc/library/gzip.rst Doc/library/http.client.rst From 42fd44ac97feaf4057ec26f15391fe63cdcaa4b5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Oct 2023 06:22:15 +0200 Subject: [PATCH 1054/1206] [3.12] gh-111092: Make turtledemo run without default root enabled (GH-111093) (#111095) gh-111092: Make turtledemo run without default root enabled (GH-111093) Add missing 'root' argument to PanedWindow call. Other root children already have it. (cherry picked from commit b802882fb2bff8b431df661322908c07491f3ce7) Co-authored-by: Terry Jan Reedy --- Lib/turtledemo/__main__.py | 2 +- .../next/Library/2023-10-19-22-46-34.gh-issue-111092.hgut12.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-19-22-46-34.gh-issue-111092.hgut12.rst diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py index f6c9d6aa6f9a32..2ab6c15e2c079e 100755 --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -161,7 +161,7 @@ def __init__(self, filename=None): label='Help', underline=0) root['menu'] = self.mBar - pane = PanedWindow(orient=HORIZONTAL, sashwidth=5, + pane = PanedWindow(root, orient=HORIZONTAL, sashwidth=5, sashrelief=SOLID, bg='#ddd') pane.add(self.makeTextFrame(pane)) pane.add(self.makeGraphFrame(pane)) diff --git a/Misc/NEWS.d/next/Library/2023-10-19-22-46-34.gh-issue-111092.hgut12.rst b/Misc/NEWS.d/next/Library/2023-10-19-22-46-34.gh-issue-111092.hgut12.rst new file mode 100644 index 00000000000000..487bd177d27e31 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-19-22-46-34.gh-issue-111092.hgut12.rst @@ -0,0 +1 @@ +Make turtledemo run without default root enabled. From 909225172a473a26b3ea4bb9b1c10f5486e432ee Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Oct 2023 06:49:41 +0200 Subject: [PATCH 1055/1206] [3.12] gh-101100: Fix Sphinx warnings in `library/tty.rst` (GH-111079) (#111097) gh-101100: Fix Sphinx warnings in `library/tty.rst` (GH-111079) Fix Sphinx warnings in library/tty.rst (cherry picked from commit c42c68aa7bd19b0de7f2132ed468bc4ce83d8aa9) Co-authored-by: Hugo van Kemenade --- Doc/library/termios.rst | 18 ++++++++++++++---- Doc/tools/.nitignore | 1 - 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst index fb1ff567d49e5c..03806178e9d3fb 100644 --- a/Doc/library/termios.rst +++ b/Doc/library/termios.rst @@ -43,10 +43,20 @@ The module defines the following functions: Set the tty attributes for file descriptor *fd* from the *attributes*, which is a list like the one returned by :func:`tcgetattr`. The *when* argument - determines when the attributes are changed: :const:`TCSANOW` to change - immediately, :const:`TCSADRAIN` to change after transmitting all queued output, - or :const:`TCSAFLUSH` to change after transmitting all queued output and - discarding all queued input. + determines when the attributes are changed: + + .. data:: TCSANOW + + Change attributes immediately. + + .. data:: TCSADRAIN + + Change attributes after transmitting all queued output. + + .. data:: TCSAFLUSH + + Change attributes after transmitting all queued output and + discarding all queued input. .. function:: tcsendbreak(fd, duration) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index f55c238489d4f3..2297a6aba748dc 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -135,7 +135,6 @@ Doc/library/tkinter.scrolledtext.rst Doc/library/tkinter.tix.rst Doc/library/tkinter.ttk.rst Doc/library/traceback.rst -Doc/library/tty.rst Doc/library/unittest.mock.rst Doc/library/unittest.rst Doc/library/urllib.parse.rst From b4c215e82d8acd0bdfa604cbe03d4d14055c3df1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Oct 2023 10:09:18 +0200 Subject: [PATCH 1056/1206] [3.12] gh-101100: Fix sphinx warnings in `library/codecs.rst` (GH-110979) (#111070) Co-authored-by: Nikita Sobolev Co-authored-by: Hugo van Kemenade --- Doc/library/codecs.rst | 71 ++++++++++++++++++++++-------------------- Doc/tools/.nitignore | 1 - 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst index 2db4a67d1973d5..9ce584874783da 100644 --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -520,44 +520,46 @@ The base :class:`Codec` class defines these methods which also define the function interfaces of the stateless encoder and decoder: -.. method:: Codec.encode(input, errors='strict') +.. class:: Codec - Encodes the object *input* and returns a tuple (output object, length consumed). - For instance, :term:`text encoding` converts - a string object to a bytes object using a particular - character set encoding (e.g., ``cp1252`` or ``iso-8859-1``). + .. method:: encode(input, errors='strict') - The *errors* argument defines the error handling to apply. - It defaults to ``'strict'`` handling. + Encodes the object *input* and returns a tuple (output object, length consumed). + For instance, :term:`text encoding` converts + a string object to a bytes object using a particular + character set encoding (e.g., ``cp1252`` or ``iso-8859-1``). - The method may not store state in the :class:`Codec` instance. Use - :class:`StreamWriter` for codecs which have to keep state in order to make - encoding efficient. + The *errors* argument defines the error handling to apply. + It defaults to ``'strict'`` handling. - The encoder must be able to handle zero length input and return an empty object - of the output object type in this situation. + The method may not store state in the :class:`Codec` instance. Use + :class:`StreamWriter` for codecs which have to keep state in order to make + encoding efficient. + The encoder must be able to handle zero length input and return an empty object + of the output object type in this situation. -.. method:: Codec.decode(input, errors='strict') - Decodes the object *input* and returns a tuple (output object, length - consumed). For instance, for a :term:`text encoding`, decoding converts - a bytes object encoded using a particular - character set encoding to a string object. + .. method:: decode(input, errors='strict') - For text encodings and bytes-to-bytes codecs, - *input* must be a bytes object or one which provides the read-only - buffer interface -- for example, buffer objects and memory mapped files. + Decodes the object *input* and returns a tuple (output object, length + consumed). For instance, for a :term:`text encoding`, decoding converts + a bytes object encoded using a particular + character set encoding to a string object. - The *errors* argument defines the error handling to apply. - It defaults to ``'strict'`` handling. + For text encodings and bytes-to-bytes codecs, + *input* must be a bytes object or one which provides the read-only + buffer interface -- for example, buffer objects and memory mapped files. - The method may not store state in the :class:`Codec` instance. Use - :class:`StreamReader` for codecs which have to keep state in order to make - decoding efficient. + The *errors* argument defines the error handling to apply. + It defaults to ``'strict'`` handling. - The decoder must be able to handle zero length input and return an empty object - of the output object type in this situation. + The method may not store state in the :class:`Codec` instance. Use + :class:`StreamReader` for codecs which have to keep state in order to make + decoding efficient. + + The decoder must be able to handle zero length input and return an empty object + of the output object type in this situation. Incremental Encoding and Decoding @@ -705,7 +707,7 @@ Stream Encoding and Decoding The :class:`StreamWriter` and :class:`StreamReader` classes provide generic working interfaces which can be used to implement new encoding submodules very -easily. See :mod:`encodings.utf_8` for an example of how this is done. +easily. See :mod:`!encodings.utf_8` for an example of how this is done. .. _stream-writer-objects: @@ -895,9 +897,10 @@ The design is such that one can use the factory functions returned by the .. class:: StreamRecoder(stream, encode, decode, Reader, Writer, errors='strict') Creates a :class:`StreamRecoder` instance which implements a two-way conversion: - *encode* and *decode* work on the frontend — the data visible to - code calling :meth:`read` and :meth:`write`, while *Reader* and *Writer* - work on the backend — the data in *stream*. + *encode* and *decode* work on the frontend — the data visible to + code calling :meth:`~StreamReader.read` and :meth:`~StreamWriter.write`, + while *Reader* and *Writer* + work on the backend — the data in *stream*. You can use these objects to do transparent transcodings, e.g., from Latin-1 to UTF-8 and back. @@ -1417,8 +1420,10 @@ to :class:`bytes` mappings. They are not supported by :meth:`bytes.decode` | | quotedprintable, | quoted printable. | ``quotetabs=True`` / | | | quoted_printable | | :meth:`quopri.decode` | +----------------------+------------------+------------------------------+------------------------------+ -| uu_codec | uu | Convert the operand using | :meth:`uu.encode` / | -| | | uuencode. | :meth:`uu.decode` | +| uu_codec | uu | Convert the operand using | :meth:`!uu.encode` / | +| | | uuencode. | :meth:`!uu.decode` | +| | | | (Note: :mod:`uu` is | +| | | | deprecated.) | +----------------------+------------------+------------------------------+------------------------------+ | zlib_codec | zip, zlib | Compress the operand using | :meth:`zlib.compress` / | | | | gzip. | :meth:`zlib.decompress` | diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 2297a6aba748dc..8a7008e9aa73f1 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -49,7 +49,6 @@ Doc/library/calendar.rst Doc/library/cgi.rst Doc/library/chunk.rst Doc/library/cmd.rst -Doc/library/codecs.rst Doc/library/collections.abc.rst Doc/library/collections.rst Doc/library/concurrent.futures.rst From 6b38ddba979a278077524fac0bd3ab24d8f24b28 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Oct 2023 12:22:09 +0200 Subject: [PATCH 1057/1206] [3.12] Add tests for failing PyUnicode_AsUTF8AndSize() with psize=NULL (GH-111100) (GH-111105) (cherry picked from commit b60f05870816019cfd9b2f7d104364613e66fc78) Co-authored-by: Serhiy Storchaka --- Lib/test/test_capi/test_unicode.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 9c7662065689ea..40ce9afc566477 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -902,7 +902,11 @@ def test_asutf8andsize(self): self.assertRaises(UnicodeEncodeError, unicode_asutf8andsize, '\ud8ff', 0) self.assertRaises(TypeError, unicode_asutf8andsize, b'abc', 0) self.assertRaises(TypeError, unicode_asutf8andsize, [], 0) + self.assertRaises(UnicodeEncodeError, unicode_asutf8andsize_null, '\ud8ff', 0) + self.assertRaises(TypeError, unicode_asutf8andsize_null, b'abc', 0) + self.assertRaises(TypeError, unicode_asutf8andsize_null, [], 0) # CRASHES unicode_asutf8andsize(NULL, 0) + # CRASHES unicode_asutf8andsize_null(NULL, 0) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') From dfc8d7ac935e09f85b01e3f946d5aa525a3ea696 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:37:31 +0200 Subject: [PATCH 1058/1206] gh-110913: Fix WindowsConsoleIO chunking of UTF-8 text (GH-111007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 11312eae6ec3acf51aacafce4cb6d1a5edfd5f2e) Co-authored-by: Tamás Hegedűs --- ...-10-19-21-46-18.gh-issue-110913.CWlPfg.rst | 1 + Modules/_io/winconsoleio.c | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-10-19-21-46-18.gh-issue-110913.CWlPfg.rst diff --git a/Misc/NEWS.d/next/Windows/2023-10-19-21-46-18.gh-issue-110913.CWlPfg.rst b/Misc/NEWS.d/next/Windows/2023-10-19-21-46-18.gh-issue-110913.CWlPfg.rst new file mode 100644 index 00000000000000..d4c1b56d98ef0e --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-10-19-21-46-18.gh-issue-110913.CWlPfg.rst @@ -0,0 +1 @@ +WindowsConsoleIO now correctly chunks large buffers without splitting up UTF-8 sequences. diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 7c6f226329dd35..c2c365e0807f0a 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -134,6 +134,23 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { return m; } +static DWORD +_find_last_utf8_boundary(const char *buf, DWORD len) +{ + /* This function never returns 0, returns the original len instead */ + DWORD count = 1; + if (len == 0 || (buf[len - 1] & 0x80) == 0) { + return len; + } + for (;; count++) { + if (count > 3 || count >= len) { + return len; + } + if ((buf[len - count] & 0xc0) != 0x80) { + return len - count; + } + } +} /*[clinic input] module _io @@ -975,7 +992,7 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, { BOOL res = TRUE; wchar_t *wbuf; - DWORD len, wlen, orig_len, n = 0; + DWORD len, wlen, n = 0; HANDLE handle; if (self->fd == -1) @@ -1007,21 +1024,8 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, have to reduce and recalculate. */ while (wlen > 32766 / sizeof(wchar_t)) { len /= 2; - orig_len = len; - /* Reduce the length until we hit the final byte of a UTF-8 sequence - * (top bit is unset). Fix for github issue 82052. - */ - while (len > 0 && (((char *)b->buf)[len-1] & 0x80) != 0) - --len; - /* If we hit a length of 0, something has gone wrong. This shouldn't - * be possible, as valid UTF-8 can have at most 3 non-final bytes - * before a final one, and our buffer is way longer than that. - * But to be on the safe side, if we hit this issue we just restore - * the original length and let the console API sort it out. - */ - if (len == 0) { - len = orig_len; - } + /* Fix for github issues gh-110913 and gh-82052. */ + len = _find_last_utf8_boundary(b->buf, len); wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, NULL, 0); } Py_END_ALLOW_THREADS From 4a1026077af65b308c98cdfe181b5f94c46fb48a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 20 Oct 2023 20:27:35 +0200 Subject: [PATCH 1059/1206] [3.12] gh-111126: Use `isinstance` instead of `assert[Not]IsInstance` in `test_typing` (GH-111127) (#111130) gh-111126: Use `isinstance` instead of `assert[Not]IsInstance` in `test_typing` (GH-111127) (cherry picked from commit ea7c26e4b89c71234c4a603567a93f0a44c9cc97) Co-authored-by: Nikita Sobolev --- Lib/test/test_typing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 957d7afe7ca4cf..dc5ab7d889e0f0 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2011,13 +2011,13 @@ def test_callable_instance_type_error(self): def f(): pass with self.assertRaises(TypeError): - self.assertIsInstance(f, Callable[[], None]) + isinstance(f, Callable[[], None]) with self.assertRaises(TypeError): - self.assertIsInstance(f, Callable[[], Any]) + isinstance(f, Callable[[], Any]) with self.assertRaises(TypeError): - self.assertNotIsInstance(None, Callable[[], None]) + isinstance(None, Callable[[], None]) with self.assertRaises(TypeError): - self.assertNotIsInstance(None, Callable[[], Any]) + isinstance(None, Callable[[], Any]) def test_repr(self): Callable = self.Callable From 727f8ee31cadf196ecab51762b2e84a884470618 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Oct 2023 00:23:15 +0200 Subject: [PATCH 1060/1206] [3.12] gh-111046: for wasi-threads, export memory as well via the linker (GH-111099) (GH-111141) gh-111046: for wasi-threads, export memory as well via the linker (GH-111099) (cherry picked from commit 5dfa71769f547fffa893a89b0b04d963a41b2441) Co-authored-by: YAMAMOTO Takashi --- .../Build/2023-10-20-15-29-31.gh-issue-111046.2DxQl8.rst | 1 + configure | 5 +++++ configure.ac | 5 +++++ 3 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2023-10-20-15-29-31.gh-issue-111046.2DxQl8.rst diff --git a/Misc/NEWS.d/next/Build/2023-10-20-15-29-31.gh-issue-111046.2DxQl8.rst b/Misc/NEWS.d/next/Build/2023-10-20-15-29-31.gh-issue-111046.2DxQl8.rst new file mode 100644 index 00000000000000..446b8b612862f9 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-10-20-15-29-31.gh-issue-111046.2DxQl8.rst @@ -0,0 +1 @@ +For wasi-threads, memory is now exported to fix compatibility issues with some wasm runtimes. diff --git a/configure b/configure index 0240ff86dccbf9..7c3250729c89d3 100755 --- a/configure +++ b/configure @@ -9439,10 +9439,15 @@ then : # without this, configure fails to find pthread_create, sem_init, # etc because they are only available in the sysroot for # wasm32-wasi-threads. + # Note: wasi-threads requires --import-memory. + # Note: wasi requires --export-memory. + # Note: --export-memory is implicit unless --import-memory is given + # Note: this requires LLVM >= 16. as_fn_append CFLAGS " -target wasm32-wasi-threads -pthread" as_fn_append CFLAGS_NODIST " -target wasm32-wasi-threads -pthread" as_fn_append LDFLAGS_NODIST " -target wasm32-wasi-threads -pthread" as_fn_append LDFLAGS_NODIST " -Wl,--import-memory" + as_fn_append LDFLAGS_NODIST " -Wl,--export-memory" as_fn_append LDFLAGS_NODIST " -Wl,--max-memory=10485760" fi diff --git a/configure.ac b/configure.ac index 34e0653623dd6e..3afa9aca8bbd43 100644 --- a/configure.ac +++ b/configure.ac @@ -2326,10 +2326,15 @@ AS_CASE([$ac_sys_system], # without this, configure fails to find pthread_create, sem_init, # etc because they are only available in the sysroot for # wasm32-wasi-threads. + # Note: wasi-threads requires --import-memory. + # Note: wasi requires --export-memory. + # Note: --export-memory is implicit unless --import-memory is given + # Note: this requires LLVM >= 16. AS_VAR_APPEND([CFLAGS], [" -target wasm32-wasi-threads -pthread"]) AS_VAR_APPEND([CFLAGS_NODIST], [" -target wasm32-wasi-threads -pthread"]) AS_VAR_APPEND([LDFLAGS_NODIST], [" -target wasm32-wasi-threads -pthread"]) AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--import-memory"]) + AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--export-memory"]) AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--max-memory=10485760"]) ]) From 0409057c8650e102bbc3c336c22574c054274a76 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Oct 2023 11:18:35 +0200 Subject: [PATCH 1061/1206] [3.12] gh-110932: Fix regrtest for SOURCE_DATE_EPOCH (GH-111143) (#111154) gh-110932: Fix regrtest for SOURCE_DATE_EPOCH (GH-111143) If the SOURCE_DATE_EPOCH environment variable is defined, use its value as the random seed. (cherry picked from commit 7237fb578dc9db9dc557759a24d8083425107b91) Co-authored-by: Victor Stinner --- Lib/test/libregrtest/main.py | 21 +++--- Lib/test/libregrtest/runtests.py | 2 +- Lib/test/test_regrtest.py | 72 +++++++++++++++---- ...-10-21-00-10-36.gh-issue-110932.jktjJU.rst | 2 + 4 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-21-00-10-36.gh-issue-110932.jktjJU.rst diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index fe35df05c80e89..e765ed5c613acb 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -129,14 +129,19 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False): # Randomize self.randomize: bool = ns.randomize - self.random_seed: int | None = ( - ns.random_seed - if ns.random_seed is not None - else random.getrandbits(32) - ) - if 'SOURCE_DATE_EPOCH' in os.environ: + if ('SOURCE_DATE_EPOCH' in os.environ + # don't use the variable if empty + and os.environ['SOURCE_DATE_EPOCH'] + ): self.randomize = False - self.random_seed = None + # SOURCE_DATE_EPOCH should be an integer, but use a string to not + # fail if it's not integer. random.seed() accepts a string. + # https://reproducible-builds.org/docs/source-date-epoch/ + self.random_seed: int | str = os.environ['SOURCE_DATE_EPOCH'] + elif ns.random_seed is None: + self.random_seed = random.getrandbits(32) + else: + self.random_seed = ns.random_seed # tests self.first_runtests: RunTests | None = None @@ -441,7 +446,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int: or tests or self.cmdline_args)): display_header(self.use_resources, self.python_cmd) - print("Using random seed", self.random_seed) + print("Using random seed:", self.random_seed) runtests = self.create_run_tests(selected) self.first_runtests = runtests diff --git a/Lib/test/libregrtest/runtests.py b/Lib/test/libregrtest/runtests.py index 4da312db4cb02e..893b311c31297c 100644 --- a/Lib/test/libregrtest/runtests.py +++ b/Lib/test/libregrtest/runtests.py @@ -91,7 +91,7 @@ class RunTests: use_resources: tuple[str, ...] python_cmd: tuple[str, ...] | None randomize: bool - random_seed: int | None + random_seed: int | str json_file: JsonFile | None def copy(self, **override): diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index c8e182397c835e..91f2fb0286adfe 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -143,18 +143,26 @@ def test_header(self): self.assertTrue(ns.header) def test_randomize(self): - for opt in '-r', '--randomize': + for opt in ('-r', '--randomize'): with self.subTest(opt=opt): ns = self.parse_args([opt]) self.assertTrue(ns.randomize) with os_helper.EnvironmentVarGuard() as env: - env['SOURCE_DATE_EPOCH'] = '1' - + # with SOURCE_DATE_EPOCH + env['SOURCE_DATE_EPOCH'] = '1697839080' ns = self.parse_args(['--randomize']) regrtest = main.Regrtest(ns) self.assertFalse(regrtest.randomize) - self.assertIsNone(regrtest.random_seed) + self.assertIsInstance(regrtest.random_seed, str) + self.assertEqual(regrtest.random_seed, '1697839080') + + # without SOURCE_DATE_EPOCH + del env['SOURCE_DATE_EPOCH'] + ns = self.parse_args(['--randomize']) + regrtest = main.Regrtest(ns) + self.assertTrue(regrtest.randomize) + self.assertIsInstance(regrtest.random_seed, int) def test_randseed(self): ns = self.parse_args(['--randseed', '12345']) @@ -388,7 +396,13 @@ def check_ci_mode(self, args, use_resources, rerun=True): # Check Regrtest attributes which are more reliable than Namespace # which has an unclear API - regrtest = main.Regrtest(ns) + with os_helper.EnvironmentVarGuard() as env: + # Ignore SOURCE_DATE_EPOCH env var if it's set + if 'SOURCE_DATE_EPOCH' in env: + del env['SOURCE_DATE_EPOCH'] + + regrtest = main.Regrtest(ns) + self.assertEqual(regrtest.num_workers, -1) self.assertEqual(regrtest.want_rerun, rerun) self.assertTrue(regrtest.randomize) @@ -662,21 +676,26 @@ def list_regex(line_format, tests): state = f'{state} then {new_state}' self.check_line(output, f'Result: {state}', full=True) - def parse_random_seed(self, output): - match = self.regex_search(r'Using random seed ([0-9]+)', output) - randseed = int(match.group(1)) - self.assertTrue(0 <= randseed, randseed) - return randseed + def parse_random_seed(self, output: str) -> str: + match = self.regex_search(r'Using random seed: (.*)', output) + return match.group(1) def run_command(self, args, input=None, exitcode=0, **kw): if not input: input = '' if 'stderr' not in kw: kw['stderr'] = subprocess.STDOUT + + env = kw.pop('env', None) + if env is None: + env = dict(os.environ) + env.pop('SOURCE_DATE_EPOCH', None) + proc = subprocess.run(args, text=True, input=input, stdout=subprocess.PIPE, + env=env, **kw) if proc.returncode != exitcode: msg = ("Command %s failed with exit code %s, but exit code %s expected!\n" @@ -752,7 +771,9 @@ def setUp(self): self.regrtest_args.append('-n') def check_output(self, output): - self.parse_random_seed(output) + randseed = self.parse_random_seed(output) + self.assertTrue(randseed.isdigit(), randseed) + self.check_executed_tests(output, self.tests, randomize=True, stats=len(self.tests)) @@ -943,7 +964,7 @@ def test_random(self): test_random = int(match.group(1)) # try to reproduce with the random seed - output = self.run_tests('-r', '--randseed=%s' % randseed, test, + output = self.run_tests('-r', f'--randseed={randseed}', test, exitcode=EXITCODE_NO_TESTS_RAN) randseed2 = self.parse_random_seed(output) self.assertEqual(randseed2, randseed) @@ -954,7 +975,32 @@ def test_random(self): # check that random.seed is used by default output = self.run_tests(test, exitcode=EXITCODE_NO_TESTS_RAN) - self.assertIsInstance(self.parse_random_seed(output), int) + randseed = self.parse_random_seed(output) + self.assertTrue(randseed.isdigit(), randseed) + + # check SOURCE_DATE_EPOCH (integer) + timestamp = '1697839080' + env = dict(os.environ, SOURCE_DATE_EPOCH=timestamp) + output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN, + env=env) + randseed = self.parse_random_seed(output) + self.assertEqual(randseed, timestamp) + self.check_line(output, 'TESTRANDOM: 520') + + # check SOURCE_DATE_EPOCH (string) + env = dict(os.environ, SOURCE_DATE_EPOCH='XYZ') + output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN, + env=env) + randseed = self.parse_random_seed(output) + self.assertEqual(randseed, 'XYZ') + self.check_line(output, 'TESTRANDOM: 22') + + # check SOURCE_DATE_EPOCH (empty string): ignore the env var + env = dict(os.environ, SOURCE_DATE_EPOCH='') + output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN, + env=env) + randseed = self.parse_random_seed(output) + self.assertTrue(randseed.isdigit(), randseed) def test_fromfile(self): # test --fromfile diff --git a/Misc/NEWS.d/next/Tests/2023-10-21-00-10-36.gh-issue-110932.jktjJU.rst b/Misc/NEWS.d/next/Tests/2023-10-21-00-10-36.gh-issue-110932.jktjJU.rst new file mode 100644 index 00000000000000..45bb0774a9abe3 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-21-00-10-36.gh-issue-110932.jktjJU.rst @@ -0,0 +1,2 @@ +Fix regrtest if the ``SOURCE_DATE_EPOCH`` environment variable is defined: +use the variable value as the random seed. Patch by Victor Stinner. From 552ceb2d0f46a74bf79669aa0daca49f906f3847 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Oct 2023 14:57:22 +0200 Subject: [PATCH 1062/1206] [3.12] gh-110572: Fix potential leaks in test_*_code in _testcapi/getargs.c (GH-110573) (GH-111161) (cherry picked from commit f71cd5394efe154ba92228b2b67be910cc1ede95) Co-authored-by: Nikita Sobolev --- Modules/_testcapi/getargs.c | 90 +++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/Modules/_testcapi/getargs.c b/Modules/_testcapi/getargs.c index b47cc906dad84a..fbfd6a46693381 100644 --- a/Modules/_testcapi/getargs.c +++ b/Modules/_testcapi/getargs.c @@ -361,68 +361,83 @@ getargs_K(PyObject *self, PyObject *args) static PyObject * test_k_code(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *tuple, *num; - unsigned long value; - - tuple = PyTuple_New(1); + PyObject *tuple = PyTuple_New(1); if (tuple == NULL) { return NULL; } /* a number larger than ULONG_MAX even on 64-bit platforms */ - num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16); + PyObject *num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16); if (num == NULL) { - return NULL; + goto error; } - value = PyLong_AsUnsignedLongMask(num); - if (value != ULONG_MAX) { + unsigned long value = PyLong_AsUnsignedLongMask(num); + if (value == (unsigned long)-1 && PyErr_Occurred()) { + Py_DECREF(num); + goto error; + } + else if (value != ULONG_MAX) { + Py_DECREF(num); PyErr_SetString(PyExc_AssertionError, "test_k_code: " "PyLong_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); - return NULL; + goto error; } PyTuple_SET_ITEM(tuple, 0, num); value = 0; if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) { - return NULL; + goto error; } if (value != ULONG_MAX) { PyErr_SetString(PyExc_AssertionError, "test_k_code: k code returned wrong value for long 0xFFF...FFF"); - return NULL; + goto error; } - Py_DECREF(num); + Py_DECREF(tuple); // also clears `num` + tuple = PyTuple_New(1); + if (tuple == NULL) { + return NULL; + } num = PyLong_FromString("-FFFFFFFF000000000000000042", NULL, 16); if (num == NULL) { - return NULL; + goto error; } value = PyLong_AsUnsignedLongMask(num); - if (value != (unsigned long)-0x42) { + if (value == (unsigned long)-1 && PyErr_Occurred()) { + Py_DECREF(num); + goto error; + } + else if (value != (unsigned long)-0x42) { + Py_DECREF(num); PyErr_SetString(PyExc_AssertionError, "test_k_code: " "PyLong_AsUnsignedLongMask() returned wrong value for long -0xFFF..000042"); - return NULL; + goto error; } PyTuple_SET_ITEM(tuple, 0, num); value = 0; if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) { - return NULL; + goto error; } if (value != (unsigned long)-0x42) { PyErr_SetString(PyExc_AssertionError, "test_k_code: k code returned wrong value for long -0xFFF..000042"); - return NULL; + goto error; } Py_DECREF(tuple); Py_RETURN_NONE; + +error: + Py_DECREF(tuple); + return NULL; } static PyObject * @@ -760,51 +775,56 @@ getargs_et_hash(PyObject *self, PyObject *args) static PyObject * test_L_code(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *tuple, *num; - long long value; - - tuple = PyTuple_New(1); + PyObject *tuple = PyTuple_New(1); if (tuple == NULL) { return NULL; } - num = PyLong_FromLong(42); + PyObject *num = PyLong_FromLong(42); if (num == NULL) { - return NULL; + goto error; } PyTuple_SET_ITEM(tuple, 0, num); - value = -1; + long long value = -1; if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) { - return NULL; + goto error; } if (value != 42) { PyErr_SetString(PyExc_AssertionError, "test_L_code: L code returned wrong value for long 42"); - return NULL; + goto error; } - Py_DECREF(num); + Py_DECREF(tuple); // also clears `num` + tuple = PyTuple_New(1); + if (tuple == NULL) { + return NULL; + } num = PyLong_FromLong(42); if (num == NULL) { - return NULL; + goto error; } PyTuple_SET_ITEM(tuple, 0, num); value = -1; if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) { - return NULL; + goto error; } if (value != 42) { PyErr_SetString(PyExc_AssertionError, "test_L_code: L code returned wrong value for int 42"); - return NULL; + goto error; } Py_DECREF(tuple); Py_RETURN_NONE; + +error: + Py_DECREF(tuple); + return NULL; } /* Test the s and z codes for PyArg_ParseTuple. @@ -821,7 +841,7 @@ test_s_code(PyObject *self, PyObject *Py_UNUSED(ignored)) PyObject *obj = PyUnicode_Decode("t\xeate", strlen("t\xeate"), "latin-1", NULL); if (obj == NULL) { - return NULL; + goto error; } PyTuple_SET_ITEM(tuple, 0, obj); @@ -831,15 +851,19 @@ test_s_code(PyObject *self, PyObject *Py_UNUSED(ignored)) */ char *value; if (!PyArg_ParseTuple(tuple, "s:test_s_code1", &value)) { - return NULL; + goto error; } if (!PyArg_ParseTuple(tuple, "z:test_s_code2", &value)) { - return NULL; + goto error; } Py_DECREF(tuple); Py_RETURN_NONE; + +error: + Py_DECREF(tuple); + return NULL; } #undef PyArg_ParseTupleAndKeywords From 6a5ff9365413fcb7361d5f9edc02f8cfaa0baea9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:07:09 +0200 Subject: [PATCH 1063/1206] [3.12] gh-111157: Mention `__notes__` in `traceback.format_exception_only` docstring (GH-111158) (#111163) gh-111157: Mention `__notes__` in `traceback.format_exception_only` docstring (GH-111158) (cherry picked from commit 5e7727b05232b43589d177c15263d7f4f8c584a0) Co-authored-by: Nikita Sobolev --- Lib/traceback.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Lib/traceback.py b/Lib/traceback.py index 813e13e1e0cc2b..c1be65982cc568 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -145,14 +145,11 @@ def format_exception_only(exc, /, value=_sentinel): The return value is a list of strings, each ending in a newline. - Normally, the list contains a single string; however, for - SyntaxError exceptions, it contains several lines that (when - printed) display detailed information about where the syntax - error occurred. - - The message indicating which exception occurred is always the last - string in the list. - + The list contains the exception's message, which is + normally a single string; however, for :exc:`SyntaxError` exceptions, it + contains several lines that (when printed) display detailed information + about where the syntax error occurred. Following the message, the list + contains the exception's ``__notes__``. """ if value is _sentinel: value = exc @@ -841,13 +838,13 @@ def format_exception_only(self): The return value is a generator of strings, each ending in a newline. - Normally, the generator emits a single string; however, for - SyntaxError exceptions, it emits several lines that (when - printed) display detailed information about where the syntax - error occurred. - - The message indicating which exception occurred is always the last - string in the output. + Generator yields the exception message. + For :exc:`SyntaxError` exceptions, it + also yields (before the exception message) + several lines that (when printed) + display detailed information about where the syntax error occurred. + Following the message, generator also yields + all the exception's ``__notes__``. """ if self.exc_type is None: yield _format_final_exc_line(None, self._str) From 1ea93024d45144745d71f96f493f85e3b950ca97 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 21 Oct 2023 20:33:26 +0300 Subject: [PATCH 1064/1206] [3.12] gh-110918: regrtest: allow to intermix --match and --ignore options (GH-110919) (GH-111167) Test case matching patterns specified by options --match, --ignore, --matchfile and --ignorefile are now tested in the order of specification, and the last match determines whether the test case be run or ignored. (cherry picked from commit 9a1fe09622cd0f1e24c2ba5335c94c5d70306fd0) --- Lib/test/libregrtest/cmdline.py | 40 +++++----- Lib/test/libregrtest/findtests.py | 7 +- Lib/test/libregrtest/main.py | 15 +--- Lib/test/libregrtest/run_workers.py | 2 +- Lib/test/libregrtest/runtests.py | 5 +- Lib/test/libregrtest/setup.py | 2 +- Lib/test/libregrtest/utils.py | 1 + Lib/test/libregrtest/worker.py | 6 +- Lib/test/support/__init__.py | 76 +++++++------------ Lib/test/test_regrtest.py | 42 +++++----- Lib/test/test_support.py | 67 +++++++++------- ...-10-16-13-47-24.gh-issue-110918.aFgZK3.rst | 4 + 12 files changed, 126 insertions(+), 141 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-16-13-47-24.gh-issue-110918.aFgZK3.rst diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py index b1b00893402d8e..905b3f862281f1 100644 --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -161,8 +161,7 @@ def __init__(self, **kwargs) -> None: self.forever = False self.header = False self.failfast = False - self.match_tests = None - self.ignore_tests = None + self.match_tests = [] self.pgo = False self.pgo_extended = False self.worker_json = None @@ -183,6 +182,20 @@ def error(self, message): super().error(message + "\nPass -h or --help for complete help.") +class FilterAction(argparse.Action): + def __call__(self, parser, namespace, value, option_string=None): + items = getattr(namespace, self.dest) + items.append((value, self.const)) + + +class FromFileFilterAction(argparse.Action): + def __call__(self, parser, namespace, value, option_string=None): + items = getattr(namespace, self.dest) + with open(value, encoding='utf-8') as fp: + for line in fp: + items.append((line.strip(), self.const)) + + def _create_parser(): # Set prog to prevent the uninformative "__main__.py" from displaying in # error messages when using "python -m test ...". @@ -192,6 +205,7 @@ def _create_parser(): epilog=EPILOG, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.set_defaults(match_tests=[]) # Arguments with this clause added to its help are described further in # the epilog's "Additional option details" section. @@ -251,17 +265,19 @@ def _create_parser(): help='single step through a set of tests.' + more_details) group.add_argument('-m', '--match', metavar='PAT', - dest='match_tests', action='append', + dest='match_tests', action=FilterAction, const=True, help='match test cases and methods with glob pattern PAT') group.add_argument('-i', '--ignore', metavar='PAT', - dest='ignore_tests', action='append', + dest='match_tests', action=FilterAction, const=False, help='ignore test cases and methods with glob pattern PAT') group.add_argument('--matchfile', metavar='FILENAME', - dest='match_filename', + dest='match_tests', + action=FromFileFilterAction, const=True, help='similar to --match but get patterns from a ' 'text file, one pattern per line') group.add_argument('--ignorefile', metavar='FILENAME', - dest='ignore_filename', + dest='match_tests', + action=FromFileFilterAction, const=False, help='similar to --matchfile but it receives patterns ' 'from text file to ignore') group.add_argument('-G', '--failfast', action='store_true', @@ -483,18 +499,6 @@ def _parse_args(args, **kwargs): print("WARNING: Disable --verbose3 because it's incompatible with " "--huntrleaks: see http://bugs.python.org/issue27103", file=sys.stderr) - if ns.match_filename: - if ns.match_tests is None: - ns.match_tests = [] - with open(ns.match_filename) as fp: - for line in fp: - ns.match_tests.append(line.strip()) - if ns.ignore_filename: - if ns.ignore_tests is None: - ns.ignore_tests = [] - with open(ns.ignore_filename) as fp: - for line in fp: - ns.ignore_tests.append(line.strip()) if ns.forever: # --forever implies --failfast ns.failfast = True diff --git a/Lib/test/libregrtest/findtests.py b/Lib/test/libregrtest/findtests.py index caf2872cfc9a18..f3ff3628bea134 100644 --- a/Lib/test/libregrtest/findtests.py +++ b/Lib/test/libregrtest/findtests.py @@ -5,7 +5,7 @@ from test import support from .utils import ( - StrPath, TestName, TestTuple, TestList, FilterTuple, + StrPath, TestName, TestTuple, TestList, TestFilter, abs_module_name, count, printlist) @@ -83,11 +83,10 @@ def _list_cases(suite): print(test.id()) def list_cases(tests: TestTuple, *, - match_tests: FilterTuple | None = None, - ignore_tests: FilterTuple | None = None, + match_tests: TestFilter | None = None, test_dir: StrPath | None = None): support.verbose = False - support.set_match_tests(match_tests, ignore_tests) + support.set_match_tests(match_tests) skipped = [] for test_name in tests: diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index e765ed5c613acb..8544bb484c8be0 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -19,7 +19,7 @@ from .setup import setup_process, setup_test_dir from .single import run_single_test, PROGRESS_MIN_TIME from .utils import ( - StrPath, StrJSON, TestName, TestList, TestTuple, FilterTuple, + StrPath, StrJSON, TestName, TestList, TestTuple, TestFilter, strip_py_suffix, count, format_duration, printlist, get_temp_dir, get_work_dir, exit_timeout, display_header, cleanup_temp_dir, print_warning, @@ -78,14 +78,7 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False): and ns._add_python_opts) # Select tests - if ns.match_tests: - self.match_tests: FilterTuple | None = tuple(ns.match_tests) - else: - self.match_tests = None - if ns.ignore_tests: - self.ignore_tests: FilterTuple | None = tuple(ns.ignore_tests) - else: - self.ignore_tests = None + self.match_tests: TestFilter = ns.match_tests self.exclude: bool = ns.exclude self.fromfile: StrPath | None = ns.fromfile self.starting_test: TestName | None = ns.start @@ -389,7 +382,7 @@ def finalize_tests(self, tracer): def display_summary(self): duration = time.perf_counter() - self.logger.start_time - filtered = bool(self.match_tests) or bool(self.ignore_tests) + filtered = bool(self.match_tests) # Total duration print() @@ -407,7 +400,6 @@ def create_run_tests(self, tests: TestTuple): fail_fast=self.fail_fast, fail_env_changed=self.fail_env_changed, match_tests=self.match_tests, - ignore_tests=self.ignore_tests, match_tests_dict=None, rerun=False, forever=self.forever, @@ -660,7 +652,6 @@ def main(self, tests: TestList | None = None): elif self.want_list_cases: list_cases(selected, match_tests=self.match_tests, - ignore_tests=self.ignore_tests, test_dir=self.test_dir) else: exitcode = self.run_tests(selected, tests) diff --git a/Lib/test/libregrtest/run_workers.py b/Lib/test/libregrtest/run_workers.py index 16f8331abd32f9..ab03cb54d6122e 100644 --- a/Lib/test/libregrtest/run_workers.py +++ b/Lib/test/libregrtest/run_workers.py @@ -261,7 +261,7 @@ def create_worker_runtests(self, test_name: TestName, json_file: JsonFile) -> Ru kwargs = {} if match_tests: - kwargs['match_tests'] = match_tests + kwargs['match_tests'] = [(test, True) for test in match_tests] if self.runtests.output_on_failure: kwargs['verbose'] = True kwargs['output_on_failure'] = False diff --git a/Lib/test/libregrtest/runtests.py b/Lib/test/libregrtest/runtests.py index 893b311c31297c..bfed1b4a2a5817 100644 --- a/Lib/test/libregrtest/runtests.py +++ b/Lib/test/libregrtest/runtests.py @@ -8,7 +8,7 @@ from test import support from .utils import ( - StrPath, StrJSON, TestTuple, FilterTuple, FilterDict) + StrPath, StrJSON, TestTuple, TestFilter, FilterTuple, FilterDict) class JsonFileType: @@ -72,8 +72,7 @@ class RunTests: tests: TestTuple fail_fast: bool fail_env_changed: bool - match_tests: FilterTuple | None - ignore_tests: FilterTuple | None + match_tests: TestFilter match_tests_dict: FilterDict | None rerun: bool forever: bool diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index 793347f60ad93c..6a96b051394d20 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -92,7 +92,7 @@ def setup_tests(runtests: RunTests): support.PGO = runtests.pgo support.PGO_EXTENDED = runtests.pgo_extended - support.set_match_tests(runtests.match_tests, runtests.ignore_tests) + support.set_match_tests(runtests.match_tests) if runtests.use_junit: support.junit_xml_list = [] diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index 86192ed9084f40..653654de52c243 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -52,6 +52,7 @@ TestList = list[TestName] # --match and --ignore options: list of patterns # ('*' joker character can be used) +TestFilter = list[tuple[TestName, bool]] FilterTuple = tuple[TestName, ...] FilterDict = dict[TestName, FilterTuple] diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py index a9c8be0bb65d08..2eccfabc25223a 100644 --- a/Lib/test/libregrtest/worker.py +++ b/Lib/test/libregrtest/worker.py @@ -10,7 +10,7 @@ from .runtests import RunTests, JsonFile, JsonFileType from .single import run_single_test from .utils import ( - StrPath, StrJSON, FilterTuple, + StrPath, StrJSON, TestFilter, get_temp_dir, get_work_dir, exit_timeout) @@ -73,7 +73,7 @@ def create_worker_process(runtests: RunTests, output_fd: int, def worker_process(worker_json: StrJSON) -> NoReturn: runtests = RunTests.from_json(worker_json) test_name = runtests.tests[0] - match_tests: FilterTuple | None = runtests.match_tests + match_tests: TestFilter = runtests.match_tests json_file: JsonFile = runtests.json_file setup_test_dir(runtests.test_dir) @@ -81,7 +81,7 @@ def worker_process(worker_json: StrJSON) -> NoReturn: if runtests.rerun: if match_tests: - matching = "matching: " + ", ".join(match_tests) + matching = "matching: " + ", ".join(pattern for pattern, result in match_tests if result) print(f"Re-running {test_name} in verbose mode ({matching})", flush=True) else: print(f"Re-running {test_name} in verbose mode", flush=True) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ded8ad96606a7c..e6aa2866d43735 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -6,8 +6,10 @@ import contextlib import dataclasses import functools +import itertools import getpass import opcode +import operator import os import re import stat @@ -1194,18 +1196,17 @@ def _run_suite(suite): # By default, don't filter tests -_match_test_func = None - -_accept_test_patterns = None -_ignore_test_patterns = None +_test_matchers = () +_test_patterns = () def match_test(test): # Function used by support.run_unittest() and regrtest --list-cases - if _match_test_func is None: - return True - else: - return _match_test_func(test.id()) + result = False + for matcher, result in reversed(_test_matchers): + if matcher(test.id()): + return result + return not result def _is_full_match_test(pattern): @@ -1218,47 +1219,30 @@ def _is_full_match_test(pattern): return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern)) -def set_match_tests(accept_patterns=None, ignore_patterns=None): - global _match_test_func, _accept_test_patterns, _ignore_test_patterns - - if accept_patterns is None: - accept_patterns = () - if ignore_patterns is None: - ignore_patterns = () - - accept_func = ignore_func = None - - if accept_patterns != _accept_test_patterns: - accept_patterns, accept_func = _compile_match_function(accept_patterns) - if ignore_patterns != _ignore_test_patterns: - ignore_patterns, ignore_func = _compile_match_function(ignore_patterns) - - # Create a copy since patterns can be mutable and so modified later - _accept_test_patterns = tuple(accept_patterns) - _ignore_test_patterns = tuple(ignore_patterns) +def set_match_tests(patterns): + global _test_matchers, _test_patterns - if accept_func is not None or ignore_func is not None: - def match_function(test_id): - accept = True - ignore = False - if accept_func: - accept = accept_func(test_id) - if ignore_func: - ignore = ignore_func(test_id) - return accept and not ignore - - _match_test_func = match_function + if not patterns: + _test_matchers = () + _test_patterns = () + else: + itemgetter = operator.itemgetter + patterns = tuple(patterns) + if patterns != _test_patterns: + _test_matchers = [ + (_compile_match_function(map(itemgetter(0), it)), result) + for result, it in itertools.groupby(patterns, itemgetter(1)) + ] + _test_patterns = patterns def _compile_match_function(patterns): - if not patterns: - func = None - # set_match_tests(None) behaves as set_match_tests(()) - patterns = () - elif all(map(_is_full_match_test, patterns)): + patterns = list(patterns) + + if all(map(_is_full_match_test, patterns)): # Simple case: all patterns are full test identifier. # The test.bisect_cmd utility only uses such full test identifiers. - func = set(patterns).__contains__ + return set(patterns).__contains__ else: import fnmatch regex = '|'.join(map(fnmatch.translate, patterns)) @@ -1266,7 +1250,7 @@ def _compile_match_function(patterns): # don't use flags=re.IGNORECASE regex_match = re.compile(regex).match - def match_test_regex(test_id): + def match_test_regex(test_id, regex_match=regex_match): if regex_match(test_id): # The regex matches the whole identifier, for example # 'test.test_os.FileTests.test_access'. @@ -1277,9 +1261,7 @@ def match_test_regex(test_id): # into: 'test', 'test_os', 'FileTests' and 'test_access'. return any(map(regex_match, test_id.split("."))) - func = match_test_regex - - return patterns, func + return match_test_regex def run_unittest(*classes): diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 91f2fb0286adfe..0c12b0efff88e5 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -192,34 +192,27 @@ def test_single(self): self.assertTrue(ns.single) self.checkError([opt, '-f', 'foo'], "don't go together") - def test_ignore(self): - for opt in '-i', '--ignore': + def test_match(self): + for opt in '-m', '--match': with self.subTest(opt=opt): ns = self.parse_args([opt, 'pattern']) - self.assertEqual(ns.ignore_tests, ['pattern']) + self.assertEqual(ns.match_tests, [('pattern', True)]) self.checkError([opt], 'expected one argument') - self.addCleanup(os_helper.unlink, os_helper.TESTFN) - with open(os_helper.TESTFN, "w") as fp: - print('matchfile1', file=fp) - print('matchfile2', file=fp) - - filename = os.path.abspath(os_helper.TESTFN) - ns = self.parse_args(['-m', 'match', - '--ignorefile', filename]) - self.assertEqual(ns.ignore_tests, - ['matchfile1', 'matchfile2']) - - def test_match(self): - for opt in '-m', '--match': + for opt in '-i', '--ignore': with self.subTest(opt=opt): ns = self.parse_args([opt, 'pattern']) - self.assertEqual(ns.match_tests, ['pattern']) + self.assertEqual(ns.match_tests, [('pattern', False)]) self.checkError([opt], 'expected one argument') - ns = self.parse_args(['-m', 'pattern1', - '-m', 'pattern2']) - self.assertEqual(ns.match_tests, ['pattern1', 'pattern2']) + ns = self.parse_args(['-m', 'pattern1', '-m', 'pattern2']) + self.assertEqual(ns.match_tests, [('pattern1', True), ('pattern2', True)]) + + ns = self.parse_args(['-m', 'pattern1', '-i', 'pattern2']) + self.assertEqual(ns.match_tests, [('pattern1', True), ('pattern2', False)]) + + ns = self.parse_args(['-i', 'pattern1', '-m', 'pattern2']) + self.assertEqual(ns.match_tests, [('pattern1', False), ('pattern2', True)]) self.addCleanup(os_helper.unlink, os_helper.TESTFN) with open(os_helper.TESTFN, "w") as fp: @@ -227,10 +220,13 @@ def test_match(self): print('matchfile2', file=fp) filename = os.path.abspath(os_helper.TESTFN) - ns = self.parse_args(['-m', 'match', - '--matchfile', filename]) + ns = self.parse_args(['-m', 'match', '--matchfile', filename]) + self.assertEqual(ns.match_tests, + [('match', True), ('matchfile1', True), ('matchfile2', True)]) + + ns = self.parse_args(['-i', 'match', '--ignorefile', filename]) self.assertEqual(ns.match_tests, - ['match', 'matchfile1', 'matchfile2']) + [('match', False), ('matchfile1', False), ('matchfile2', False)]) def test_failfast(self): for opt in '-G', '--failfast': diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 4a93249af313cf..60c43fde4865f0 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -560,100 +560,109 @@ def id(self): test_access = Test('test.test_os.FileTests.test_access') test_chdir = Test('test.test_os.Win32ErrorTests.test_chdir') + test_copy = Test('test.test_shutil.TestCopy.test_copy') # Test acceptance - with support.swap_attr(support, '_match_test_func', None): + with support.swap_attr(support, '_test_matchers', ()): # match all support.set_match_tests([]) self.assertTrue(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) # match all using None - support.set_match_tests(None, None) + support.set_match_tests(None) self.assertTrue(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) # match the full test identifier - support.set_match_tests([test_access.id()], None) + support.set_match_tests([(test_access.id(), True)]) self.assertTrue(support.match_test(test_access)) self.assertFalse(support.match_test(test_chdir)) # match the module name - support.set_match_tests(['test_os'], None) + support.set_match_tests([('test_os', True)]) self.assertTrue(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) + self.assertFalse(support.match_test(test_copy)) # Test '*' pattern - support.set_match_tests(['test_*'], None) + support.set_match_tests([('test_*', True)]) self.assertTrue(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) # Test case sensitivity - support.set_match_tests(['filetests'], None) + support.set_match_tests([('filetests', True)]) self.assertFalse(support.match_test(test_access)) - support.set_match_tests(['FileTests'], None) + support.set_match_tests([('FileTests', True)]) self.assertTrue(support.match_test(test_access)) # Test pattern containing '.' and a '*' metacharacter - support.set_match_tests(['*test_os.*.test_*'], None) + support.set_match_tests([('*test_os.*.test_*', True)]) self.assertTrue(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) + self.assertFalse(support.match_test(test_copy)) # Multiple patterns - support.set_match_tests([test_access.id(), test_chdir.id()], None) + support.set_match_tests([(test_access.id(), True), (test_chdir.id(), True)]) self.assertTrue(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) + self.assertFalse(support.match_test(test_copy)) - support.set_match_tests(['test_access', 'DONTMATCH'], None) + support.set_match_tests([('test_access', True), ('DONTMATCH', True)]) self.assertTrue(support.match_test(test_access)) self.assertFalse(support.match_test(test_chdir)) # Test rejection - with support.swap_attr(support, '_match_test_func', None): - # match all - support.set_match_tests(ignore_patterns=[]) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - - # match all using None - support.set_match_tests(None, None) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - + with support.swap_attr(support, '_test_matchers', ()): # match the full test identifier - support.set_match_tests(None, [test_access.id()]) + support.set_match_tests([(test_access.id(), False)]) self.assertFalse(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) # match the module name - support.set_match_tests(None, ['test_os']) + support.set_match_tests([('test_os', False)]) self.assertFalse(support.match_test(test_access)) self.assertFalse(support.match_test(test_chdir)) + self.assertTrue(support.match_test(test_copy)) # Test '*' pattern - support.set_match_tests(None, ['test_*']) + support.set_match_tests([('test_*', False)]) self.assertFalse(support.match_test(test_access)) self.assertFalse(support.match_test(test_chdir)) # Test case sensitivity - support.set_match_tests(None, ['filetests']) + support.set_match_tests([('filetests', False)]) self.assertTrue(support.match_test(test_access)) - support.set_match_tests(None, ['FileTests']) + support.set_match_tests([('FileTests', False)]) self.assertFalse(support.match_test(test_access)) # Test pattern containing '.' and a '*' metacharacter - support.set_match_tests(None, ['*test_os.*.test_*']) + support.set_match_tests([('*test_os.*.test_*', False)]) self.assertFalse(support.match_test(test_access)) self.assertFalse(support.match_test(test_chdir)) + self.assertTrue(support.match_test(test_copy)) # Multiple patterns - support.set_match_tests(None, [test_access.id(), test_chdir.id()]) + support.set_match_tests([(test_access.id(), False), (test_chdir.id(), False)]) + self.assertFalse(support.match_test(test_access)) + self.assertFalse(support.match_test(test_chdir)) + self.assertTrue(support.match_test(test_copy)) + + support.set_match_tests([('test_access', False), ('DONTMATCH', False)]) self.assertFalse(support.match_test(test_access)) + self.assertTrue(support.match_test(test_chdir)) + + # Test mixed filters + with support.swap_attr(support, '_test_matchers', ()): + support.set_match_tests([('*test_os', False), ('test_access', True)]) + self.assertTrue(support.match_test(test_access)) self.assertFalse(support.match_test(test_chdir)) + self.assertTrue(support.match_test(test_copy)) - support.set_match_tests(None, ['test_access', 'DONTMATCH']) + support.set_match_tests([('*test_os', True), ('test_access', False)]) self.assertFalse(support.match_test(test_access)) self.assertTrue(support.match_test(test_chdir)) + self.assertFalse(support.match_test(test_copy)) @unittest.skipIf(support.is_emscripten, "Unstable in Emscripten") @unittest.skipIf(support.is_wasi, "Unavailable on WASI") diff --git a/Misc/NEWS.d/next/Tests/2023-10-16-13-47-24.gh-issue-110918.aFgZK3.rst b/Misc/NEWS.d/next/Tests/2023-10-16-13-47-24.gh-issue-110918.aFgZK3.rst new file mode 100644 index 00000000000000..7cb79c0cbf29f1 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-16-13-47-24.gh-issue-110918.aFgZK3.rst @@ -0,0 +1,4 @@ +Test case matching patterns specified by options ``--match``, ``--ignore``, +``--matchfile`` and ``--ignorefile`` are now tested in the order of +specification, and the last match determines whether the test case be run or +ignored. From f6cde99bdb3419e86e478619e0fcf3282aaa8dd6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:39:34 +0200 Subject: [PATCH 1065/1206] [3.12] gh-111159: Fix `doctest` output comparison for exceptions with notes (GH-111160) (#111169) gh-111159: Fix `doctest` output comparison for exceptions with notes (GH-111160) (cherry picked from commit fd60549c0ac6c81f05594a5141d24b4433ae39be) Co-authored-by: Nikita Sobolev --- Lib/doctest.py | 15 +- Lib/test/test_doctest.py | 144 ++++++++++++++++++ ...-10-21-13-57-06.gh-issue-111159.GoHp7s.rst | 1 + 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst diff --git a/Lib/doctest.py b/Lib/doctest.py index a63df46a112e64..aeb28e8d292f6c 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1376,7 +1376,20 @@ def __run(self, test, compileflags, out): # The example raised an exception: check if it was expected. else: - exc_msg = traceback.format_exception_only(*exception[:2])[-1] + formatted_ex = traceback.format_exception_only(*exception[:2]) + if issubclass(exception[0], SyntaxError): + # SyntaxError / IndentationError is special: + # we don't care about the carets / suggestions / etc + # We only care about the error message and notes. + # They start with `SyntaxError:` (or any other class name) + exc_msg_index = next( + index + for index, line in enumerate(formatted_ex) + if line.startswith(f"{exception[0].__name__}:") + ) + formatted_ex = formatted_ex[exc_msg_index:] + + exc_msg = "".join(formatted_ex) if not quiet: got += _exception_traceback(exception) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index bca4915e0fa673..20059d3a3a7536 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -3168,6 +3168,150 @@ def test_run_doctestsuite_multiple_times(): """ +def test_exception_with_note(note): + """ + >>> test_exception_with_note('Note') + Traceback (most recent call last): + ... + ValueError: Text + Note + + >>> test_exception_with_note('Note') # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + ValueError: Text + Note + + >>> test_exception_with_note('''Note + ... multiline + ... example''') + Traceback (most recent call last): + ValueError: Text + Note + multiline + example + + Different note will fail the test: + + >>> def f(x): + ... r''' + ... >>> exc = ValueError('message') + ... >>> exc.add_note('note') + ... >>> raise exc + ... Traceback (most recent call last): + ... ValueError: message + ... wrong note + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File "...", line 5, in f + Failed example: + raise exc + Expected: + Traceback (most recent call last): + ValueError: message + wrong note + Got: + Traceback (most recent call last): + ... + ValueError: message + note + TestResults(failed=1, attempted=...) + """ + exc = ValueError('Text') + exc.add_note(note) + raise exc + + +def test_exception_with_multiple_notes(): + """ + >>> test_exception_with_multiple_notes() + Traceback (most recent call last): + ... + ValueError: Text + One + Two + """ + exc = ValueError('Text') + exc.add_note('One') + exc.add_note('Two') + raise exc + + +def test_syntax_error_with_note(cls, multiline=False): + """ + >>> test_syntax_error_with_note(SyntaxError) + Traceback (most recent call last): + ... + SyntaxError: error + Note + + >>> test_syntax_error_with_note(SyntaxError) + Traceback (most recent call last): + SyntaxError: error + Note + + >>> test_syntax_error_with_note(SyntaxError) + Traceback (most recent call last): + ... + File "x.py", line 23 + bad syntax + SyntaxError: error + Note + + >>> test_syntax_error_with_note(IndentationError) + Traceback (most recent call last): + ... + IndentationError: error + Note + + >>> test_syntax_error_with_note(TabError, multiline=True) + Traceback (most recent call last): + ... + TabError: error + Note + Line + """ + exc = cls("error", ("x.py", 23, None, "bad syntax")) + exc.add_note('Note\nLine' if multiline else 'Note') + raise exc + + +def test_syntax_error_with_incorrect_expected_note(): + """ + >>> def f(x): + ... r''' + ... >>> exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) + ... >>> exc.add_note('note1') + ... >>> exc.add_note('note2') + ... >>> raise exc + ... Traceback (most recent call last): + ... SyntaxError: error + ... wrong note + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File "...", line 6, in f + Failed example: + raise exc + Expected: + Traceback (most recent call last): + SyntaxError: error + wrong note + Got: + Traceback (most recent call last): + ... + SyntaxError: error + note1 + note2 + TestResults(failed=1, attempted=...) + """ + + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite(doctest)) tests.addTest(doctest.DocTestSuite()) diff --git a/Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst b/Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst new file mode 100644 index 00000000000000..bdec4f4443d80b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-21-13-57-06.gh-issue-111159.GoHp7s.rst @@ -0,0 +1 @@ +Fix :mod:`doctest` output comparison for exceptions with notes. From 322f79f5a2c47507b881e868071c078c343d4301 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Oct 2023 21:46:41 +0200 Subject: [PATCH 1066/1206] [3.12] Synchronize test_contextlib with test_contextlib_async (GH-111000) (GH-111114) (cherry picked from commit ff4e53cb747063e95eaec181fd396f062f885ac2) Co-authored-by: Serhiy Storchaka --- Lib/test/test_contextlib.py | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index b15829414e5dbb..3cc194417f257e 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -163,6 +163,15 @@ def whoo(): # The "gen" attribute is an implementation detail. self.assertFalse(ctx.gen.gi_suspended) + def test_contextmanager_trap_no_yield(self): + @contextmanager + def whoo(): + if False: + yield + ctx = whoo() + with self.assertRaises(RuntimeError): + ctx.__enter__() + def test_contextmanager_trap_second_yield(self): @contextmanager def whoo(): @@ -176,6 +185,19 @@ def whoo(): # The "gen" attribute is an implementation detail. self.assertFalse(ctx.gen.gi_suspended) + def test_contextmanager_non_normalised(self): + @contextmanager + def whoo(): + try: + yield + except RuntimeError: + raise SyntaxError + + ctx = whoo() + ctx.__enter__() + with self.assertRaises(SyntaxError): + ctx.__exit__(RuntimeError, None, None) + def test_contextmanager_except(self): state = [] @contextmanager @@ -255,6 +277,25 @@ def test_issue29692(): self.assertEqual(ex.args[0], 'issue29692:Unchained') self.assertIsNone(ex.__cause__) + def test_contextmanager_wrap_runtimeerror(self): + @contextmanager + def woohoo(): + try: + yield + except Exception as exc: + raise RuntimeError(f'caught {exc}') from exc + + with self.assertRaises(RuntimeError): + with woohoo(): + 1 / 0 + + # If the context manager wrapped StopIteration in a RuntimeError, + # we also unwrap it, because we can't tell whether the wrapping was + # done by the generator machinery or by the generator itself. + with self.assertRaises(StopIteration): + with woohoo(): + raise StopIteration + def _create_contextmanager_attribs(self): def attribs(**kw): def decorate(func): @@ -266,6 +307,7 @@ def decorate(func): @attribs(foo='bar') def baz(spam): """Whee!""" + yield return baz def test_contextmanager_attribs(self): @@ -322,8 +364,11 @@ def woohoo(a, *, b): def test_recursive(self): depth = 0 + ncols = 0 @contextmanager def woohoo(): + nonlocal ncols + ncols += 1 nonlocal depth before = depth depth += 1 @@ -337,6 +382,7 @@ def recursive(): recursive() recursive() + self.assertEqual(ncols, 10) self.assertEqual(depth, 0) From 028f47754c78864abf6eb1930493871727925b6a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Oct 2023 21:48:53 +0200 Subject: [PATCH 1067/1206] [3.12] gh-111085: Fix invalid state handling in TaskGroup and Timeout (GH-111111) (GH-111171) asyncio.TaskGroup and asyncio.Timeout classes now raise proper RuntimeError if they are improperly used. * When they are used without entering the context manager. * When they are used after finishing. * When the context manager is entered more than once (simultaneously or sequentially). * If there is no current task when entering the context manager. They now remain in a consistent state after an exception is thrown, so subsequent operations can be performed correctly (if they are allowed). (cherry picked from commit 6c23635f2b7067ef091a550954e09f8b7c329e3f) Co-authored-by: Serhiy Storchaka Co-authored-by: James Hilton-Balfe --- Lib/asyncio/taskgroups.py | 6 +-- Lib/asyncio/timeouts.py | 12 +++-- Lib/test/test_asyncio/test_taskgroups.py | 45 +++++++++++++++++ Lib/test/test_asyncio/test_timeouts.py | 48 ++++++++++++++++++- Lib/test/test_asyncio/utils.py | 15 ++++++ ...-10-20-15-29-10.gh-issue-110910.u2oPwX.rst | 3 ++ 6 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-20-15-29-10.gh-issue-110910.u2oPwX.rst diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 930da53d908e36..d264e51f1fd4e6 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -54,16 +54,14 @@ def __repr__(self): async def __aenter__(self): if self._entered: raise RuntimeError( - f"TaskGroup {self!r} has been already entered") - self._entered = True - + f"TaskGroup {self!r} has already been entered") if self._loop is None: self._loop = events.get_running_loop() - self._parent_task = tasks.current_task(self._loop) if self._parent_task is None: raise RuntimeError( f'TaskGroup {self!r} cannot determine the parent task') + self._entered = True return self diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index 029c468739bf2d..30042abb3ad804 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -49,8 +49,9 @@ def when(self) -> Optional[float]: def reschedule(self, when: Optional[float]) -> None: """Reschedule the timeout.""" - assert self._state is not _State.CREATED if self._state is not _State.ENTERED: + if self._state is _State.CREATED: + raise RuntimeError("Timeout has not been entered") raise RuntimeError( f"Cannot change state of {self._state.value} Timeout", ) @@ -82,11 +83,14 @@ def __repr__(self) -> str: return f"" async def __aenter__(self) -> "Timeout": + if self._state is not _State.CREATED: + raise RuntimeError("Timeout has already been entered") + task = tasks.current_task() + if task is None: + raise RuntimeError("Timeout should be used inside a task") self._state = _State.ENTERED - self._task = tasks.current_task() + self._task = task self._cancelling = self._task.cancelling() - if self._task is None: - raise RuntimeError("Timeout should be used inside a task") self.reschedule(self._when) return self diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py index 6a0231f2859a62..7a18362b54e469 100644 --- a/Lib/test/test_asyncio/test_taskgroups.py +++ b/Lib/test/test_asyncio/test_taskgroups.py @@ -8,6 +8,8 @@ from asyncio import taskgroups import unittest +from test.test_asyncio.utils import await_without_task + # To prevent a warning "test altered the execution environment" def tearDownModule(): @@ -779,6 +781,49 @@ async def main(): await asyncio.create_task(main()) + async def test_taskgroup_already_entered(self): + tg = taskgroups.TaskGroup() + async with tg: + with self.assertRaisesRegex(RuntimeError, "has already been entered"): + async with tg: + pass + + async def test_taskgroup_double_enter(self): + tg = taskgroups.TaskGroup() + async with tg: + pass + with self.assertRaisesRegex(RuntimeError, "has already been entered"): + async with tg: + pass + + async def test_taskgroup_finished(self): + tg = taskgroups.TaskGroup() + async with tg: + pass + coro = asyncio.sleep(0) + with self.assertRaisesRegex(RuntimeError, "is finished"): + tg.create_task(coro) + # We still have to await coro to avoid a warning + await coro + + async def test_taskgroup_not_entered(self): + tg = taskgroups.TaskGroup() + coro = asyncio.sleep(0) + with self.assertRaisesRegex(RuntimeError, "has not been entered"): + tg.create_task(coro) + # We still have to await coro to avoid a warning + await coro + + async def test_taskgroup_without_parent_task(self): + tg = taskgroups.TaskGroup() + with self.assertRaisesRegex(RuntimeError, "parent task"): + await await_without_task(tg.__aenter__()) + coro = asyncio.sleep(0) + with self.assertRaisesRegex(RuntimeError, "has not been entered"): + tg.create_task(coro) + # We still have to await coro to avoid a warning + await coro + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py index e9b59b953518b3..f54e79e4d8e600 100644 --- a/Lib/test/test_asyncio/test_timeouts.py +++ b/Lib/test/test_asyncio/test_timeouts.py @@ -5,11 +5,12 @@ import asyncio +from test.test_asyncio.utils import await_without_task + def tearDownModule(): asyncio.set_event_loop_policy(None) - class TimeoutTests(unittest.IsolatedAsyncioTestCase): async def test_timeout_basic(self): @@ -257,6 +258,51 @@ async def test_timeout_exception_cause (self): cause = exc.exception.__cause__ assert isinstance(cause, asyncio.CancelledError) + async def test_timeout_already_entered(self): + async with asyncio.timeout(0.01) as cm: + with self.assertRaisesRegex(RuntimeError, "has already been entered"): + async with cm: + pass + + async def test_timeout_double_enter(self): + async with asyncio.timeout(0.01) as cm: + pass + with self.assertRaisesRegex(RuntimeError, "has already been entered"): + async with cm: + pass + + async def test_timeout_finished(self): + async with asyncio.timeout(0.01) as cm: + pass + with self.assertRaisesRegex(RuntimeError, "finished"): + cm.reschedule(0.02) + + async def test_timeout_expired(self): + with self.assertRaises(TimeoutError): + async with asyncio.timeout(0.01) as cm: + await asyncio.sleep(1) + with self.assertRaisesRegex(RuntimeError, "expired"): + cm.reschedule(0.02) + + async def test_timeout_expiring(self): + async with asyncio.timeout(0.01) as cm: + with self.assertRaises(asyncio.CancelledError): + await asyncio.sleep(1) + with self.assertRaisesRegex(RuntimeError, "expiring"): + cm.reschedule(0.02) + + async def test_timeout_not_entered(self): + cm = asyncio.timeout(0.01) + with self.assertRaisesRegex(RuntimeError, "has not been entered"): + cm.reschedule(0.02) + + async def test_timeout_without_task(self): + cm = asyncio.timeout(0.01) + with self.assertRaisesRegex(RuntimeError, "task"): + await await_without_task(cm.__aenter__()) + with self.assertRaisesRegex(RuntimeError, "has not been entered"): + cm.reschedule(0.02) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 8d44717b2ade6f..9e8fe2af96b66e 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -613,3 +613,18 @@ def mock_nonblocking_socket(proto=socket.IPPROTO_TCP, type=socket.SOCK_STREAM, sock.family = family sock.gettimeout.return_value = 0.0 return sock + + +async def await_without_task(coro): + exc = None + def func(): + try: + for _ in coro.__await__(): + pass + except BaseException as err: + nonlocal exc + exc = err + asyncio.get_running_loop().call_soon(func) + await asyncio.sleep(0) + if exc is not None: + raise exc diff --git a/Misc/NEWS.d/next/Library/2023-10-20-15-29-10.gh-issue-110910.u2oPwX.rst b/Misc/NEWS.d/next/Library/2023-10-20-15-29-10.gh-issue-110910.u2oPwX.rst new file mode 100644 index 00000000000000..c750447e9fe4a5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-20-15-29-10.gh-issue-110910.u2oPwX.rst @@ -0,0 +1,3 @@ +Fix invalid state handling in :class:`asyncio.TaskGroup` and +:class:`asyncio.Timeout`. They now raise proper RuntimeError if they are +improperly used and are left in consistent state after this. From f2f89bf1c125d515fcb563460193bfb411637ba9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 22 Oct 2023 14:01:24 +0200 Subject: [PATCH 1068/1206] [3.12] gh-101100: Fix Sphinx warning in `tutorial/introduction.rst` (GH-111173) (#111175) gh-101100: Fix Sphinx warning in `tutorial/introduction.rst` (GH-111173) (cherry picked from commit 663cf513b0e973ab7aa4a8609d6616ad2c283f22) Co-authored-by: Maciej Olko --- Doc/tools/.nitignore | 1 - Doc/tutorial/introduction.rst | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 8a7008e9aa73f1..e59f6d76af068a 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -157,7 +157,6 @@ Doc/reference/expressions.rst Doc/reference/import.rst Doc/reference/simple_stmts.rst Doc/tutorial/datastructures.rst -Doc/tutorial/introduction.rst Doc/using/windows.rst Doc/whatsnew/2.0.rst Doc/whatsnew/2.1.rst diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index 172611dd0cfb41..4536ab9486d39c 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -428,7 +428,7 @@ type, i.e. it is possible to change their content:: [1, 8, 27, 64, 125] You can also add new items at the end of the list, by using -the :meth:`~list.append` *method* (we will see more about methods later):: +the :meth:`!list.append` *method* (we will see more about methods later):: >>> cubes.append(216) # add the cube of 6 >>> cubes.append(7 ** 3) # and the cube of 7 From 06fe8685a1af80daaad401f3e0869ec794965211 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 22 Oct 2023 19:28:09 +0200 Subject: [PATCH 1069/1206] [3.12] gh-101100: Fix sphinx warnings in `library/asyncio-dev.rst` (GH-111179) (#111185) gh-101100: Fix sphinx warnings in `library/asyncio-dev.rst` (GH-111179) * gh-101100: Fix sphinx warnings in `library/asyncio-dev.rst` * Update Doc/library/asyncio-eventloop.rst * Update Doc/library/asyncio-eventloop.rst --------- (cherry picked from commit 8c689c9b88426384a9736c708701923a1ab1da79) Co-authored-by: Nikita Sobolev Co-authored-by: Carol Willing --- Doc/library/asyncio-eventloop.rst | 14 +++++++++++--- Doc/tools/.nitignore | 1 - 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 04af53b980ff9e..f14fa5f18ce67f 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -243,9 +243,9 @@ Scheduling callbacks See the :ref:`concurrency and multithreading ` section of the documentation. -.. versionchanged:: 3.7 - The *context* keyword-only parameter was added. See :pep:`567` - for more details. + .. versionchanged:: 3.7 + The *context* keyword-only parameter was added. See :pep:`567` + for more details. .. _asyncio-pass-keywords: @@ -1391,6 +1391,14 @@ Enabling debug mode The new :ref:`Python Development Mode ` can now also be used to enable the debug mode. +.. attribute:: loop.slow_callback_duration + + This attribute can be used to set the + minimum execution duration in seconds that is considered "slow". + When debug mode is enabled, "slow" callbacks are logged. + + Default value is 100 milliseconds. + .. seealso:: The :ref:`debug mode of asyncio `. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index e59f6d76af068a..caf8804db440a4 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -34,7 +34,6 @@ Doc/library/__future__.rst Doc/library/abc.rst Doc/library/aifc.rst Doc/library/ast.rst -Doc/library/asyncio-dev.rst Doc/library/asyncio-eventloop.rst Doc/library/asyncio-extending.rst Doc/library/asyncio-policy.rst From 9e73c71aa90d8785e2e107595b4f9927a9a06a13 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 22 Oct 2023 21:14:50 +0200 Subject: [PATCH 1070/1206] [3.12] gh-110196: Fix ipaddress.IPv6Address.__reduce__ (GH-110198) (GH-111191) (cherry picked from commit 767f416feb551f495bacfff1e9ba1e6672c2f24e) Co-authored-by: Tian Gao --- Lib/ipaddress.py | 3 +++ Lib/test/test_ipaddress.py | 7 +++++++ .../Library/2023-10-02-05-23-27.gh-issue-110196.djwt0z.rst | 1 + 3 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-10-02-05-23-27.gh-issue-110196.djwt0z.rst diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index af1d5c4800cce8..9ca90fd0f75ba9 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1938,6 +1938,9 @@ def __eq__(self, other): return False return self._scope_id == getattr(other, '_scope_id', None) + def __reduce__(self): + return (self.__class__, (str(self),)) + @property def scope_id(self): """Identifier of a particular zone of the address's scope. diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index a5388b2e5debd8..fc27628af17f8d 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -4,6 +4,7 @@ """Unittest for ipaddress module.""" +import copy import unittest import re import contextlib @@ -542,11 +543,17 @@ def assertBadPart(addr, part): def test_pickle(self): self.pickle_test('2001:db8::') + self.pickle_test('2001:db8::%scope') def test_weakref(self): weakref.ref(self.factory('2001:db8::')) weakref.ref(self.factory('2001:db8::%scope')) + def test_copy(self): + addr = self.factory('2001:db8::%scope') + self.assertEqual(addr, copy.copy(addr)) + self.assertEqual(addr, copy.deepcopy(addr)) + class NetmaskTestMixin_v4(CommonTestMixin_v4): """Input validation on interfaces and networks is very similar""" diff --git a/Misc/NEWS.d/next/Library/2023-10-02-05-23-27.gh-issue-110196.djwt0z.rst b/Misc/NEWS.d/next/Library/2023-10-02-05-23-27.gh-issue-110196.djwt0z.rst new file mode 100644 index 00000000000000..341f3380fffd60 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-02-05-23-27.gh-issue-110196.djwt0z.rst @@ -0,0 +1 @@ +Add ``__reduce__`` method to :class:`IPv6Address` in order to keep ``scope_id`` From 8f94d0f692d4407e92944ec0c994457a5e93afe9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Oct 2023 09:31:56 +0200 Subject: [PATCH 1071/1206] [3.12] gh-110383: Added explanation about simplest regex use case for quantifiers. (GH-111110) (#111204) Co-authored-by: Nick Co-authored-by: Hugo van Kemenade --- Doc/howto/regex.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index c19c48301f5848..15372e74d6fedf 100644 --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -245,6 +245,9 @@ You can omit either *m* or *n*; in that case, a reasonable value is assumed for the missing value. Omitting *m* is interpreted as a lower limit of 0, while omitting *n* results in an upper bound of infinity. +The simplest case ``{m}`` matches the preceding item exactly **m** times. +For example, ``a/{2}b`` will only match ``'a//b'``. + Readers of a reductionist bent may notice that the three other quantifiers can all be expressed using this notation. ``{0,}`` is the same as ``*``, ``{1,}`` is equivalent to ``+``, and ``{0,1}`` is the same as ``?``. It's better to use From 4d781bce2704f32b2ff4ddb0f7d97701a565b3e6 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Oct 2023 10:11:41 +0200 Subject: [PATCH 1072/1206] [3.12] gh-110383: Italicize variable name (GH-111206) (#111207) Co-authored-by: Nick --- Doc/howto/regex.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index 15372e74d6fedf..5e2f9a9d1837fe 100644 --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -245,7 +245,7 @@ You can omit either *m* or *n*; in that case, a reasonable value is assumed for the missing value. Omitting *m* is interpreted as a lower limit of 0, while omitting *n* results in an upper bound of infinity. -The simplest case ``{m}`` matches the preceding item exactly **m** times. +The simplest case ``{m}`` matches the preceding item exactly *m* times. For example, ``a/{2}b`` will only match ``'a//b'``. Readers of a reductionist bent may notice that the three other quantifiers can From d4d947dd718c49e75f55e3b13bb7645b839d45b5 Mon Sep 17 00:00:00 2001 From: Furkan Onder Date: Mon, 23 Oct 2023 12:50:07 +0300 Subject: [PATCH 1073/1206] [3.12] gh-67565: Add tests for C-contiguity checks (GH-110951) (GH-111198) (cherry picked from commit 9376728ce45191fcc0b908c7487ad7985454537e) --- Lib/test/test_binascii.py | 6 ++++++ Lib/test/test_capi/test_getargs.py | 19 +++++++++++++++++++ Lib/test/test_ssl.py | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py index a2d7d0293ce1ae..8897c4c6c6b4ea 100644 --- a/Lib/test/test_binascii.py +++ b/Lib/test/test_binascii.py @@ -428,6 +428,12 @@ def test_b2a_base64_newline(self): self.assertEqual(binascii.b2a_base64(b, newline=False), b'aGVsbG8=') + def test_c_contiguity(self): + m = memoryview(bytearray(b'noncontig')) + noncontig_writable = m[::-2] + with self.assertRaises(BufferError): + binascii.b2a_hex(noncontig_writable) + class ArrayBinASCIITest(BinASCIITest): def type2test(self, s): diff --git a/Lib/test/test_capi/test_getargs.py b/Lib/test/test_capi/test_getargs.py index 2546c6e326c51b..ea12ab196ba774 100644 --- a/Lib/test/test_capi/test_getargs.py +++ b/Lib/test/test_capi/test_getargs.py @@ -153,6 +153,8 @@ class TupleSubclass(tuple): class DictSubclass(dict): pass +NONCONTIG_WRITABLE = memoryview(bytearray(b'noncontig'))[::-2] +NONCONTIG_READONLY = memoryview(b'noncontig')[::-2] class Unsigned_TestCase(unittest.TestCase): def test_b(self): @@ -837,6 +839,8 @@ def test_y_star(self): self.assertEqual(getargs_y_star(bytearray(b'bytearray')), b'bytearray') self.assertEqual(getargs_y_star(memoryview(b'memoryview')), b'memoryview') self.assertRaises(TypeError, getargs_y_star, None) + self.assertRaises(BufferError, getargs_y_star, NONCONTIG_WRITABLE) + self.assertRaises(BufferError, getargs_y_star, NONCONTIG_READONLY) def test_y_hash(self): from _testcapi import getargs_y_hash @@ -846,6 +850,9 @@ def test_y_hash(self): self.assertRaises(TypeError, getargs_y_hash, bytearray(b'bytearray')) self.assertRaises(TypeError, getargs_y_hash, memoryview(b'memoryview')) self.assertRaises(TypeError, getargs_y_hash, None) + # TypeError: must be read-only bytes-like object, not memoryview + self.assertRaises(TypeError, getargs_y_hash, NONCONTIG_WRITABLE) + self.assertRaises(TypeError, getargs_y_hash, NONCONTIG_READONLY) def test_w_star(self): # getargs_w_star() modifies first and last byte @@ -861,6 +868,8 @@ def test_w_star(self): self.assertEqual(getargs_w_star(memoryview(buf)), b'[emoryvie]') self.assertEqual(buf, bytearray(b'[emoryvie]')) self.assertRaises(TypeError, getargs_w_star, None) + self.assertRaises(TypeError, getargs_w_star, NONCONTIG_WRITABLE) + self.assertRaises(TypeError, getargs_w_star, NONCONTIG_READONLY) class String_TestCase(unittest.TestCase): @@ -893,6 +902,8 @@ def test_s_star(self): self.assertEqual(getargs_s_star(bytearray(b'bytearray')), b'bytearray') self.assertEqual(getargs_s_star(memoryview(b'memoryview')), b'memoryview') self.assertRaises(TypeError, getargs_s_star, None) + self.assertRaises(BufferError, getargs_s_star, NONCONTIG_WRITABLE) + self.assertRaises(BufferError, getargs_s_star, NONCONTIG_READONLY) def test_s_hash(self): from _testcapi import getargs_s_hash @@ -902,6 +913,9 @@ def test_s_hash(self): self.assertRaises(TypeError, getargs_s_hash, bytearray(b'bytearray')) self.assertRaises(TypeError, getargs_s_hash, memoryview(b'memoryview')) self.assertRaises(TypeError, getargs_s_hash, None) + # TypeError: must be read-only bytes-like object, not memoryview + self.assertRaises(TypeError, getargs_s_hash, NONCONTIG_WRITABLE) + self.assertRaises(TypeError, getargs_s_hash, NONCONTIG_READONLY) def test_s_hash_int(self): # "s#" without PY_SSIZE_T_CLEAN defined. @@ -937,6 +951,8 @@ def test_z_star(self): self.assertEqual(getargs_z_star(bytearray(b'bytearray')), b'bytearray') self.assertEqual(getargs_z_star(memoryview(b'memoryview')), b'memoryview') self.assertIsNone(getargs_z_star(None)) + self.assertRaises(BufferError, getargs_z_star, NONCONTIG_WRITABLE) + self.assertRaises(BufferError, getargs_z_star, NONCONTIG_READONLY) def test_z_hash(self): from _testcapi import getargs_z_hash @@ -946,6 +962,9 @@ def test_z_hash(self): self.assertRaises(TypeError, getargs_z_hash, bytearray(b'bytearray')) self.assertRaises(TypeError, getargs_z_hash, memoryview(b'memoryview')) self.assertIsNone(getargs_z_hash(None)) + # TypeError: must be read-only bytes-like object, not memoryview + self.assertRaises(TypeError, getargs_z_hash, NONCONTIG_WRITABLE) + self.assertRaises(TypeError, getargs_z_hash, NONCONTIG_READONLY) def test_es(self): from _testcapi import getargs_es diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 06304dcb4ec7b8..d8ae7b75e18150 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1739,6 +1739,10 @@ def test_buffer_types(self): self.assertEqual(bio.read(), b'bar') bio.write(memoryview(b'baz')) self.assertEqual(bio.read(), b'baz') + m = memoryview(bytearray(b'noncontig')) + noncontig_writable = m[::-2] + with self.assertRaises(BufferError): + bio.write(memoryview(noncontig_writable)) def test_error_types(self): bio = ssl.MemoryBIO() From 6a5aab0cb40672892eba4f5b0df5759505d7e5b9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:49:12 +0200 Subject: [PATCH 1074/1206] [3.12] gh-106310 - document the __signature__ attribute (GH-106311) (#111145) Co-authored-by: Gouvernathor <44340603+Gouvernathor@users.noreply.github.com> Co-authored-by: Alex Waygood --- Doc/library/inspect.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 23dde26ea3ecd7..9f0b965bb03f7a 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -640,6 +640,9 @@ function. Accepts a wide range of Python callables, from plain functions and classes to :func:`functools.partial` objects. + If the passed object has a ``__signature__`` attribute, this function + returns it without further computations. + For objects defined in modules using stringized annotations (``from __future__ import annotations``), :func:`signature` will attempt to automatically un-stringize the annotations using @@ -760,6 +763,8 @@ function. sig = MySignature.from_callable(min) assert isinstance(sig, MySignature) + Its behavior is otherwise identical to that of :func:`signature`. + .. versionadded:: 3.5 .. versionadded:: 3.10 From 82c045f3019203fa0f3443f2845d71f086c7e1fa Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Oct 2023 18:03:54 +0200 Subject: [PATCH 1075/1206] [3.12] typo: missing line of output in pull parser example (GH-111068) (#111217) Co-authored-by: Don Patterson <37046246+don-patterson@users.noreply.github.com> --- Doc/library/xml.etree.elementtree.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index 54c93008503c02..c9b32632c6b309 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -154,6 +154,7 @@ elements, call :meth:`XMLPullParser.read_events`. Here is an example:: ... print(elem.tag, 'text=', elem.text) ... end + mytag text= sometext more text The obvious use case is applications that operate in a non-blocking fashion where the XML data is being received from a socket or read incrementally from From 87123ab5454aaafe874098e1a4232247bc97860f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Oct 2023 18:09:59 +0200 Subject: [PATCH 1076/1206] [3.12] Add a version added note for PY_VECTORCALL_ARGUMENTS_OFFSET (GH-110963) (#111219) Co-authored-by: Anthony Shaw --- Doc/c-api/call.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index f4e401442c3d27..855e10e9a5fe40 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -108,6 +108,8 @@ This is a pointer to a function with the following signature: Doing so will allow callables such as bound methods to make their onward calls (which include a prepended *self* argument) very efficiently. + .. versionadded:: 3.8 + To call an object that implements vectorcall, use a :ref:`call API ` function as with any other callable. :c:func:`PyObject_Vectorcall` will usually be most efficient. From 38578dd665a0fd88b768d8d7c080fa404cc57923 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 23 Oct 2023 21:19:26 +0200 Subject: [PATCH 1077/1206] [3.12] gh-101100: Fix Sphinx warnings for `fileno` (GH-111118) (#111226) Co-authored-by: Hugo van Kemenade --- Doc/library/bz2.rst | 48 +++++++++++++++++++++++++++++---- Doc/library/mmap.rst | 2 +- Doc/library/multiprocessing.rst | 2 +- Doc/library/selectors.rst | 2 +- Doc/library/socket.rst | 2 +- Doc/library/tempfile.rst | 2 +- Doc/tools/.nitignore | 2 -- Doc/whatsnew/2.5.rst | 2 +- 8 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Doc/library/bz2.rst b/Doc/library/bz2.rst index ec4aeaa04395ac..6a95a4a6e8d183 100644 --- a/Doc/library/bz2.rst +++ b/Doc/library/bz2.rst @@ -91,7 +91,7 @@ The :mod:`bz2` module contains: and :meth:`~io.IOBase.truncate`. Iteration and the :keyword:`with` statement are supported. - :class:`BZ2File` also provides the following method: + :class:`BZ2File` also provides the following methods: .. method:: peek([n]) @@ -106,14 +106,52 @@ The :mod:`bz2` module contains: .. versionadded:: 3.3 + .. method:: fileno() + + Return the file descriptor for the underlying file. + + .. versionadded:: 3.3 + + .. method:: readable() + + Return whether the file was opened for reading. + + .. versionadded:: 3.3 + + .. method:: seekable() + + Return whether the file supports seeking. + + .. versionadded:: 3.3 + + .. method:: writable() + + Return whether the file was opened for writing. + + .. versionadded:: 3.3 + + .. method:: read1(size=-1) + + Read up to *size* uncompressed bytes, while trying to avoid + making multiple reads from the underlying stream. Reads up to a + buffer's worth of data if size is negative. + + Returns ``b''`` if the file is at EOF. + + .. versionadded:: 3.3 + + .. method:: readinto(b) + + Read bytes into *b*. + + Returns the number of bytes read (0 for EOF). + + .. versionadded:: 3.3 + .. versionchanged:: 3.1 Support for the :keyword:`with` statement was added. - .. versionchanged:: 3.3 - The :meth:`fileno`, :meth:`readable`, :meth:`seekable`, :meth:`writable`, - :meth:`read1` and :meth:`readinto` methods were added. - .. versionchanged:: 3.3 Support was added for *filename* being a :term:`file object` instead of an actual filename. diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst index 69afadff1f5f42..4ca7a64451d4c7 100644 --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -19,7 +19,7 @@ the current file position, and :meth:`seek` through the file to different positi A memory-mapped file is created by the :class:`~mmap.mmap` constructor, which is different on Unix and on Windows. In either case you must provide a file descriptor for a file opened for update. If you wish to map an existing Python -file object, use its :meth:`fileno` method to obtain the correct value for the +file object, use its :meth:`~io.IOBase.fileno` method to obtain the correct value for the *fileno* parameter. Otherwise, you can open the file using the :func:`os.open` function, which returns a file descriptor directly (the file still needs to be closed when done). diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 773fca45c8e70a..01a24172e5d3dc 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -2571,7 +2571,7 @@ multiple connections at the same time. **Windows**: An item in *object_list* must either be an integer handle which is waitable (according to the definition used by the documentation of the Win32 function ``WaitForMultipleObjects()``) - or it can be an object with a :meth:`fileno` method which returns a + or it can be an object with a :meth:`~io.IOBase.fileno` method which returns a socket handle or pipe handle. (Note that pipe handles and socket handles are **not** waitable handles.) diff --git a/Doc/library/selectors.rst b/Doc/library/selectors.rst index dd50bac37e49b8..76cbf91412f763 100644 --- a/Doc/library/selectors.rst +++ b/Doc/library/selectors.rst @@ -21,7 +21,7 @@ It defines a :class:`BaseSelector` abstract base class, along with several concrete implementations (:class:`KqueueSelector`, :class:`EpollSelector`...), that can be used to wait for I/O readiness notification on multiple file objects. In the following, "file object" refers to any object with a -:meth:`fileno()` method, or a raw file descriptor. See :term:`file object`. +:meth:`~io.IOBase.fileno` method, or a raw file descriptor. See :term:`file object`. :class:`DefaultSelector` is an alias to the most efficient implementation available on the current platform: this should be the default choice for most diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index c3cf48316b3248..14f11b40cb9b00 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -858,7 +858,7 @@ The following functions all create :ref:`socket objects `. .. function:: fromfd(fd, family, type, proto=0) Duplicate the file descriptor *fd* (an integer as returned by a file object's - :meth:`fileno` method) and build a socket object from the result. Address + :meth:`~io.IOBase.fileno` method) and build a socket object from the result. Address family, socket type and protocol number are as for the :func:`.socket` function above. The file descriptor should refer to a socket, but this is not checked --- subsequent operations on the object may fail if the file descriptor is invalid. diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index 42314648fec2bd..b2baa54d9522df 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -147,7 +147,7 @@ The module defines the following user-callable items: This class operates exactly as :func:`TemporaryFile` does, except that data is spooled in memory until the file size exceeds *max_size*, or - until the file's :func:`fileno` method is called, at which point the + until the file's :func:`~io.IOBase.fileno` method is called, at which point the contents are written to disk and operation proceeds as with :func:`TemporaryFile`. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index caf8804db440a4..4f12fd0f0459b9 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -43,7 +43,6 @@ Doc/library/asyncio-task.rst Doc/library/audioop.rst Doc/library/bdb.rst Doc/library/bisect.rst -Doc/library/bz2.rst Doc/library/calendar.rst Doc/library/cgi.rst Doc/library/chunk.rst @@ -112,7 +111,6 @@ Doc/library/reprlib.rst Doc/library/resource.rst Doc/library/rlcompleter.rst Doc/library/select.rst -Doc/library/selectors.rst Doc/library/shelve.rst Doc/library/signal.rst Doc/library/smtplib.rst diff --git a/Doc/whatsnew/2.5.rst b/Doc/whatsnew/2.5.rst index ad0931ecbed060..3608153db073a6 100644 --- a/Doc/whatsnew/2.5.rst +++ b/Doc/whatsnew/2.5.rst @@ -1347,7 +1347,7 @@ complete list of changes, or look through the SVN logs for all the details. :func:`input` function to allow opening files in binary or :term:`universal newlines` mode. Another new parameter, *openhook*, lets you use a function other than :func:`open` to open the input files. Once you're iterating over - the set of files, the :class:`FileInput` object's new :meth:`fileno` returns + the set of files, the :class:`FileInput` object's new :meth:`~fileinput.fileno` returns the file descriptor for the currently opened file. (Contributed by Georg Brandl.) From b622c2dcbe59c5ff579ee443244080f2f45168a5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 08:37:41 +0200 Subject: [PATCH 1078/1206] [3.12] Fix a code snippet typo in asyncio docs (GH-108427) (#111245) Co-authored-by: A <5249513+Dumeng@users.noreply.github.com> --- Doc/library/asyncio-task.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index a3ea050c0713ac..eb9db371e672e9 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -589,7 +589,7 @@ Shielding From Cancellation is equivalent to:: - res = await something() + res = await shield(something()) *except* that if the coroutine containing it is cancelled, the Task running in ``something()`` is not cancelled. From the point From 0bbdfe611a17ef4de30b1d2f8a71f394db246b60 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 08:39:26 +0200 Subject: [PATCH 1079/1206] [3.12] GH-94438: Restore ability to jump over None tests (GH-111243) (cherry picked from commit 6640f1d8d2462ca0877e1d2789e1721767e9caf2) Co-authored-by: Savannah Ostrowski --- Lib/test/test_sys_settrace.py | 34 +++++++++++++++++++ Misc/ACKS | 1 + ...3-10-23-22-11-09.gh-issue-94438.y2pITu.rst | 1 + Objects/frameobject.c | 2 ++ 4 files changed, 38 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-23-22-11-09.gh-issue-94438.y2pITu.rst diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index c29deeba4b31a2..84088d428c9cc9 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -2033,6 +2033,40 @@ def test_jump_simple_backwards(output): output.append(1) output.append(2) + @jump_test(1, 4, [5]) + def test_jump_is_none_forwards(output): + x = None + if x is None: + output.append(3) + else: + output.append(5) + + @jump_test(6, 5, [3, 5, 6]) + def test_jump_is_none_backwards(output): + x = None + if x is None: + output.append(3) + else: + output.append(5) + output.append(6) + + @jump_test(1, 4, [5]) + def test_jump_is_not_none_forwards(output): + x = None + if x is not None: + output.append(3) + else: + output.append(5) + + @jump_test(6, 5, [5, 5, 6]) + def test_jump_is_not_none_backwards(output): + x = None + if x is not None: + output.append(3) + else: + output.append(5) + output.append(6) + @jump_test(3, 5, [2, 5], warning=(RuntimeWarning, unbound_locals)) def test_jump_out_of_block_forwards(output): for i in 1, 2: diff --git a/Misc/ACKS b/Misc/ACKS index 5bba961158e684..df377b79c8ba6c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1342,6 +1342,7 @@ Michele Orrù Tomáš Orsava Oleg Oshmyan Denis Osipov +Savannah Ostrowski Denis S. Otkidach Peter Otten Michael Otteneder diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-23-22-11-09.gh-issue-94438.y2pITu.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-23-22-11-09.gh-issue-94438.y2pITu.rst new file mode 100644 index 00000000000000..b6e147a48a8cd8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-23-22-11-09.gh-issue-94438.y2pITu.rst @@ -0,0 +1 @@ +Fix a regression that prevented jumping across ``is None`` and ``is not None`` when debugging. Patch by Savannah Ostrowski. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 30c8d3c5270cad..d33c3cde526e9f 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -328,6 +328,8 @@ mark_stacks(PyCodeObject *code_obj, int len) switch (opcode) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: + case POP_JUMP_IF_NONE: + case POP_JUMP_IF_NOT_NONE: { int64_t target_stack; int j = next_i + oparg; From 03c14b04d3ce734d893f203d8c1d02262c308288 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 10:12:05 +0200 Subject: [PATCH 1080/1206] [3.12] Fix typo in sys docs (GH-111196) (#111248) Co-authored-by: James Tocknell Co-authored-by: Hugo van Kemenade --- Doc/library/sys.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 3782d1e6c6f20a..e0668b8f3614d0 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1778,7 +1778,7 @@ always available. However, if you are writing a library (and do not control in which context its code will be executed), be aware that the standard streams may be replaced with file-like objects like :class:`io.StringIO` which - do not support the :attr:!buffer` attribute. + do not support the :attr:`!buffer` attribute. .. data:: __stdin__ From df531912a7eacd204805356ea3ea3481c43f9613 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:53:21 +0200 Subject: [PATCH 1081/1206] [3.12] gh-75666: Tkinter: add tests for binding (GH-111202) (GH-111255) (cherry picked from commit 9bb202a1a90ef0edce20c495c9426d9766df11bb) Co-authored-by: Serhiy Storchaka --- Lib/test/test_tkinter/test_misc.py | 307 +++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index d1aca58d15fbd8..bac52ae0c054de 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -371,6 +371,309 @@ def test_info_patchlevel(self): self.assertTrue(str(vi).startswith(f'{vi.major}.{vi.minor}')) +class BindTest(AbstractTkTest, unittest.TestCase): + + def setUp(self): + super().setUp() + root = self.root + self.frame = tkinter.Frame(self.root, class_='Test', + width=150, height=100) + self.frame.pack() + + def assertCommandExist(self, funcid): + self.assertEqual(_info_commands(self.root, funcid), (funcid,)) + + def assertCommandNotExist(self, funcid): + self.assertEqual(_info_commands(self.root, funcid), ()) + + def test_bind(self): + event = '' + f = self.frame + self.assertEqual(f.bind(), ()) + self.assertEqual(f.bind(event), '') + def test1(e): pass + def test2(e): pass + + funcid = f.bind(event, test1) + self.assertEqual(f.bind(), (event,)) + script = f.bind(event) + self.assertIn(funcid, script) + self.assertCommandExist(funcid) + + funcid2 = f.bind(event, test2, add=True) + script = f.bind(event) + self.assertIn(funcid, script) + self.assertIn(funcid2, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + def test_unbind(self): + event = '' + f = self.frame + self.assertEqual(f.bind(), ()) + self.assertEqual(f.bind(event), '') + def test1(e): pass + def test2(e): pass + + funcid = f.bind(event, test1) + funcid2 = f.bind(event, test2, add=True) + + self.assertRaises(TypeError, f.unbind) + f.unbind(event) + self.assertEqual(f.bind(event), '') + self.assertEqual(f.bind(), ()) + + def test_unbind2(self): + f = self.frame + event = '' + self.assertEqual(f.bind(), ()) + self.assertEqual(f.bind(event), '') + def test1(e): pass + def test2(e): pass + + funcid = f.bind(event, test1) + funcid2 = f.bind(event, test2, add=True) + + f.unbind(event, funcid) + script = f.bind(event) + self.assertNotIn(funcid, script) + self.assertCommandNotExist(funcid) + self.assertCommandExist(funcid2) + + f.unbind(event, funcid2) + self.assertEqual(f.bind(event), '') + self.assertEqual(f.bind(), ()) + self.assertCommandNotExist(funcid) + self.assertCommandNotExist(funcid2) + + # non-idempotent + self.assertRaises(tkinter.TclError, f.unbind, event, funcid2) + + def test_bind_rebind(self): + event = '' + f = self.frame + self.assertEqual(f.bind(), ()) + self.assertEqual(f.bind(event), '') + def test1(e): pass + def test2(e): pass + def test3(e): pass + + funcid = f.bind(event, test1) + funcid2 = f.bind(event, test2, add=True) + script = f.bind(event) + self.assertIn(funcid2, script) + self.assertIn(funcid, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + funcid3 = f.bind(event, test3) + script = f.bind(event) + self.assertNotIn(funcid, script) + self.assertNotIn(funcid2, script) + self.assertIn(funcid3, script) + self.assertCommandExist(funcid3) + + def test_bind_class(self): + event = '' + bind_class = self.root.bind_class + unbind_class = self.root.unbind_class + self.assertRaises(TypeError, bind_class) + self.assertEqual(bind_class('Test'), ()) + self.assertEqual(bind_class('Test', event), '') + self.addCleanup(unbind_class, 'Test', event) + def test1(e): pass + def test2(e): pass + + funcid = bind_class('Test', event, test1) + self.assertEqual(bind_class('Test'), (event,)) + script = bind_class('Test', event) + self.assertIn(funcid, script) + self.assertCommandExist(funcid) + + funcid2 = bind_class('Test', event, test2, add=True) + script = bind_class('Test', event) + self.assertIn(funcid, script) + self.assertIn(funcid2, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + def test_unbind_class(self): + event = '' + bind_class = self.root.bind_class + unbind_class = self.root.unbind_class + self.assertEqual(bind_class('Test'), ()) + self.assertEqual(bind_class('Test', event), '') + self.addCleanup(unbind_class, 'Test', event) + def test1(e): pass + def test2(e): pass + + funcid = bind_class('Test', event, test1) + funcid2 = bind_class('Test', event, test2, add=True) + + self.assertRaises(TypeError, unbind_class) + self.assertRaises(TypeError, unbind_class, 'Test') + unbind_class('Test', event) + self.assertEqual(bind_class('Test', event), '') + self.assertEqual(bind_class('Test'), ()) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + unbind_class('Test', event) # idempotent + + def test_bind_class_rebind(self): + event = '' + bind_class = self.root.bind_class + unbind_class = self.root.unbind_class + self.assertEqual(bind_class('Test'), ()) + self.assertEqual(bind_class('Test', event), '') + self.addCleanup(unbind_class, 'Test', event) + def test1(e): pass + def test2(e): pass + def test3(e): pass + + funcid = bind_class('Test', event, test1) + funcid2 = bind_class('Test', event, test2, add=True) + script = bind_class('Test', event) + self.assertIn(funcid2, script) + self.assertIn(funcid, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + funcid3 = bind_class('Test', event, test3) + script = bind_class('Test', event) + self.assertNotIn(funcid, script) + self.assertNotIn(funcid2, script) + self.assertIn(funcid3, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + self.assertCommandExist(funcid3) + + def test_bind_all(self): + event = '' + bind_all = self.root.bind_all + unbind_all = self.root.unbind_all + self.assertNotIn(event, bind_all()) + self.assertEqual(bind_all(event), '') + self.addCleanup(unbind_all, event) + def test1(e): pass + def test2(e): pass + + funcid = bind_all(event, test1) + self.assertIn(event, bind_all()) + script = bind_all(event) + self.assertIn(funcid, script) + self.assertCommandExist(funcid) + + funcid2 = bind_all(event, test2, add=True) + script = bind_all(event) + self.assertIn(funcid, script) + self.assertIn(funcid2, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + def test_unbind_all(self): + event = '' + bind_all = self.root.bind_all + unbind_all = self.root.unbind_all + self.assertNotIn(event, bind_all()) + self.assertEqual(bind_all(event), '') + self.addCleanup(unbind_all, event) + def test1(e): pass + def test2(e): pass + + funcid = bind_all(event, test1) + funcid2 = bind_all(event, test2, add=True) + + unbind_all(event) + self.assertEqual(bind_all(event), '') + self.assertNotIn(event, bind_all()) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + unbind_all(event) # idempotent + + def test_bind_all_rebind(self): + event = '' + bind_all = self.root.bind_all + unbind_all = self.root.unbind_all + self.assertNotIn(event, bind_all()) + self.assertEqual(bind_all(event), '') + self.addCleanup(unbind_all, event) + def test1(e): pass + def test2(e): pass + def test3(e): pass + + funcid = bind_all(event, test1) + funcid2 = bind_all(event, test2, add=True) + script = bind_all(event) + self.assertIn(funcid2, script) + self.assertIn(funcid, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + + funcid3 = bind_all(event, test3) + script = bind_all(event) + self.assertNotIn(funcid, script) + self.assertNotIn(funcid2, script) + self.assertIn(funcid3, script) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid2) + self.assertCommandExist(funcid3) + + def test_bindtags(self): + f = self.frame + self.assertEqual(self.root.bindtags(), ('.', 'Tk', 'all')) + self.assertEqual(f.bindtags(), (str(f), 'Test', '.', 'all')) + f.bindtags(('a', 'b c')) + self.assertEqual(f.bindtags(), ('a', 'b c')) + + def test_bind_events(self): + event = '' + root = self.root + t = tkinter.Toplevel(root) + f = tkinter.Frame(t, class_='Test', width=150, height=100) + f.pack() + root.wait_visibility() # needed on Windows + root.update_idletasks() + self.addCleanup(root.unbind_class, 'Test', event) + self.addCleanup(root.unbind_class, 'Toplevel', event) + self.addCleanup(root.unbind_class, 'tag', event) + self.addCleanup(root.unbind_class, 'tag2', event) + self.addCleanup(root.unbind_all, event) + def test(what): + return lambda e: events.append((what, e.widget)) + + root.bind_all(event, test('all')) + root.bind_class('Test', event, test('frame class')) + root.bind_class('Toplevel', event, test('toplevel class')) + root.bind_class('tag', event, test('tag')) + root.bind_class('tag2', event, test('tag2')) + f.bind(event, test('frame')) + t.bind(event, test('toplevel')) + + events = [] + f.event_generate(event) + self.assertEqual(events, [ + ('frame', f), + ('frame class', f), + ('toplevel', f), + ('all', f), + ]) + + events = [] + t.event_generate(event) + self.assertEqual(events, [ + ('toplevel', t), + ('toplevel class', t), + ('all', t), + ]) + + f.bindtags(('tag', 'tag3')) + events = [] + f.event_generate(event) + self.assertEqual(events, [('tag', f)]) + + class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase): def test_default_root(self): @@ -426,5 +729,9 @@ def test_mainloop(self): self.assertRaises(RuntimeError, tkinter.mainloop) +def _info_commands(widget, pattern=None): + return widget.tk.splitlist(widget.tk.call('info', 'commands', pattern)) + + if __name__ == "__main__": unittest.main() From edff7c1614d148f9c9bc66e834e387e5930b7a49 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:30:21 +0200 Subject: [PATCH 1082/1206] [3.12] gh-111151: Convert monospaced directives to :ref: (GH-111152) (#111269) gh-111151: Convert monospaced directives to :ref: (GH-111152) (cherry picked from commit 1198076447f35b19a9173866ccb9839f3bcf3f17) Co-authored-by: InSync <122007197+InSyncWithFoo@users.noreply.github.com> --- Doc/library/asyncio-eventloop.rst | 6 ++++++ Doc/library/asyncio.rst | 6 +++--- Doc/library/typing.rst | 16 +++++++++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index f14fa5f18ce67f..0ff6136f185092 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -661,6 +661,8 @@ Opening network connections Creating network servers ^^^^^^^^^^^^^^^^^^^^^^^^ +.. _loop_create_server: + .. coroutinemethod:: loop.create_server(protocol_factory, \ host=None, port=None, *, \ family=socket.AF_UNSPEC, \ @@ -1191,6 +1193,8 @@ Working with pipes Unix signals ^^^^^^^^^^^^ +.. _loop_add_signal_handler: + .. method:: loop.add_signal_handler(signum, callback, *args) Set *callback* as the handler for the *signum* signal. @@ -1419,6 +1423,8 @@ async/await code consider using the high-level :ref:`Subprocess Support on Windows ` for details. +.. _loop_subprocess_exec: + .. coroutinemethod:: loop.subprocess_exec(protocol_factory, *args, \ stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ stderr=subprocess.PIPE, **kwargs) diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index c75ab47404c1e4..5f33c6813e74c0 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -46,9 +46,9 @@ Additionally, there are **low-level** APIs for *library and framework developers* to: * create and manage :ref:`event loops `, which - provide asynchronous APIs for :meth:`networking `, - running :meth:`subprocesses `, - handling :meth:`OS signals `, etc; + provide asynchronous APIs for :ref:`networking `, + running :ref:`subprocesses `, + handling :ref:`OS signals `, etc; * implement efficient protocols using :ref:`transports `; diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 3eae7797925d77..44665b63487b72 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -304,7 +304,7 @@ a callable with any arbitrary parameter list would be acceptable: x = concat # Also OK ``Callable`` cannot express complex signatures such as functions that take a -variadic number of arguments, :func:`overloaded functions `, or +variadic number of arguments, :ref:`overloaded functions `, or functions that have keyword-only parameters. However, these signatures can be expressed by defining a :class:`Protocol` class with a :meth:`~object.__call__` method: @@ -526,7 +526,7 @@ A user-defined class can be defined as a generic class. self.logger.info('%s: %s', self.name, message) This syntax indicates that the class ``LoggedVar`` is parameterised around a -single :class:`type variable ` ``T`` . This also makes ``T`` valid as +single :ref:`type variable ` ``T`` . This also makes ``T`` valid as a type within the class body. Generic classes implicitly inherit from :class:`Generic`. For compatibility @@ -1483,7 +1483,7 @@ These can be used as types in annotations. They all support subscription using Typing operator to conceptually mark an object as having been unpacked. For example, using the unpack operator ``*`` on a - :class:`type variable tuple ` is equivalent to using ``Unpack`` + :ref:`type variable tuple ` is equivalent to using ``Unpack`` to mark the type variable tuple as having been unpacked:: Ts = TypeVarTuple('Ts') @@ -1574,6 +1574,8 @@ without the dedicated syntax, as documented below. ... # Etc. +.. _typevar: + .. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False) Type variable. @@ -1718,9 +1720,11 @@ without the dedicated syntax, as documented below. :ref:`type parameter ` syntax introduced by :pep:`695`. The ``infer_variance`` parameter was added. +.. _typevartuple: + .. class:: TypeVarTuple(name) - Type variable tuple. A specialized form of :class:`type variable ` + Type variable tuple. A specialized form of :ref:`type variable ` that enables *variadic* generics. Type variable tuples can be declared in :ref:`type parameter lists ` @@ -1838,7 +1842,7 @@ without the dedicated syntax, as documented below. .. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False) Parameter specification variable. A specialized version of - :class:`type variables `. + :ref:`type variables `. In :ref:`type parameter lists `, parameter specifications can be declared with two asterisks (``**``):: @@ -2749,6 +2753,8 @@ Functions and decorators .. versionadded:: 3.11 +.. _overload: + .. decorator:: overload Decorator for creating overloaded functions and methods. From b180120468c100e8c77696ed90b892db59c699c7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:26:31 +0200 Subject: [PATCH 1083/1206] [3.12] Revert "Fix a code snippet typo in asyncio docs (GH-108427)" (GH-111271) (GH-111272) Revert "Fix a code snippet typo in asyncio docs (GH-108427)" (GH-111271) This reverts commit 7f316763402a7d5556deecc3acd06cb719e189b3. The change resulted in a tautology and should not have been made. There may be an opportunity for additional clarity in this section, but this change wasn't it :) (cherry picked from commit c7d68f907ad3e3aa17546df92a32bddb145a69bf) Ref: https://github.com/python/cpython/pull/108427#-issuecomment-1777525740 Co-authored-by: Zachary Ware --- Doc/library/asyncio-task.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index eb9db371e672e9..a3ea050c0713ac 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -589,7 +589,7 @@ Shielding From Cancellation is equivalent to:: - res = await shield(something()) + res = await something() *except* that if the coroutine containing it is cancelled, the Task running in ``something()`` is not cancelled. From the point From b6e508cc86e8a6a22efc34dd86249b876a0558e7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 19:44:46 +0200 Subject: [PATCH 1084/1206] [3.12] gh-109017: Use non alternate name for Kyiv (GH-109251) (GH-111280) tzdata provides Kiev as an alternative to Kyiv: https://sources.debian.org/src/tzdata/2023c-10/backward/?hl=314GH-L314 But Debian moved it to the tzdata-legacy package breaking the test: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050530 This patch switches to the name provided by tzdata. Also check that the new name is actually available. (cherry picked from commit 46407fe79ca78051cbf6c80e8b8e70a228f9fa50) Co-authored-by: Jochen Sprickerhof --- Lib/test/test_email/test_utils.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py index 25fa48c5ee217b..c9d973df0a2192 100644 --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -5,6 +5,7 @@ import unittest import sys import os.path +import zoneinfo class DateTimeTests(unittest.TestCase): @@ -142,13 +143,9 @@ def test_localtime_epoch_notz_daylight_false(self): t2 = utils.localtime(t0.replace(tzinfo=None)) self.assertEqual(t1, t2) - # XXX: Need a more robust test for Olson's tzdata - @unittest.skipIf(sys.platform.startswith('win'), - "Windows does not use Olson's TZ database") - @unittest.skipUnless(os.path.exists('/usr/share/zoneinfo') or - os.path.exists('/usr/lib/zoneinfo'), - "Can't find the Olson's TZ database") - @test.support.run_with_tz('Europe/Kiev') + @unittest.skipUnless("Europe/Kyiv" in zoneinfo.available_timezones(), + "Can't find a Kyiv timezone database") + @test.support.run_with_tz('Europe/Kyiv') def test_variable_tzname(self): t0 = datetime.datetime(1984, 1, 1, tzinfo=datetime.timezone.utc) t1 = utils.localtime(t0) From 2a28aa10a867a71261b671ffbb52dea594049bf5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 19:52:17 +0200 Subject: [PATCH 1085/1206] [3.12] GH-111182: Update EnumType.__contains__ docs (GH-111184) (GH-111281) GH-111182: Update EnumType.__contains__ docs (GH-111184) (cherry picked from commit c0ea67dd0d67a8ac59c61c777eae26288d3ac0f6) Co-authored-by: InSync <122007197+InSyncWithFoo@users.noreply.github.com> --- Doc/library/enum.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 487dace78c7288..57e1f581d4ea0e 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -198,11 +198,12 @@ Data Types >>> some_var = Color.RED >>> some_var in Color True + >>> Color.RED.value in Color + True - .. note:: + .. versionchanged:: 3.12 - In Python 3.12 it will be possible to check for member values and not - just members; until then, a ``TypeError`` will be raised if a + Before Python 3.12, a ``TypeError`` is raised if a non-Enum-member is used in a containment check. .. method:: EnumType.__dir__(cls) From a4eb2e308d8c044aa87e560b1ddccbc804e003f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 24 Oct 2023 23:28:35 +0200 Subject: [PATCH 1086/1206] [3.12] Fix first parameter name in `tool` functions from `sys.monitoring` (GH-111286) (#111290) Fix first parameter name in `tool` functions from `sys.monitoring` (GH-111286) (cherry picked from commit 8b44f3c54bb4f99445c108bc0240c458adae9c6f) Co-authored-by: Pavel Karateev --- Doc/library/sys.monitoring.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index 1024f66f3264ba..c2168cd9f06b08 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -44,21 +44,21 @@ Identifiers are integers in the range 0 to 5 inclusive. Registering and using tools ''''''''''''''''''''''''''' -.. function:: use_tool_id(id: int, name: str) -> None +.. function:: use_tool_id(tool_id: int, name: str) -> None - Must be called before *id* can be used. - *id* must be in the range 0 to 5 inclusive. - Raises a :exc:`ValueError` if *id* is in use. + Must be called before *tool_id* can be used. + *tool_id* must be in the range 0 to 5 inclusive. + Raises a :exc:`ValueError` if *tool_id* is in use. -.. function:: free_tool_id(id: int) -> None +.. function:: free_tool_id(tool_id: int) -> None - Should be called once a tool no longer requires *id*. + Should be called once a tool no longer requires *tool_id*. -.. function:: get_tool(id: int) -> str | None +.. function:: get_tool(tool_id: int) -> str | None - Returns the name of the tool if *id* is in use, + Returns the name of the tool if *tool_id* is in use, otherwise it returns ``None``. - *id* must be in the range 0 to 5 inclusive. + *tool_id* must be in the range 0 to 5 inclusive. All IDs are treated the same by the VM with regard to events, but the following IDs are pre-defined to make co-operation of tools easier:: From 6f130f231b8524f1b5c8d9c4cf155e93ef01062f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Oct 2023 02:32:08 +0200 Subject: [PATCH 1087/1206] =?UTF-8?q?[3.12]=20gh-102956:=20Fix=20returning?= =?UTF-8?q?=20of=20empty=20byte=20strings=20after=20seek=20in=20zipfile=20?= =?UTF-8?q?=E2=80=A6=20(GH-103565)=20(#111289)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-102956: Fix returning of empty byte strings after seek in zipfile … (GH-103565) (cherry picked from commit c73b0f35602abf5f283bf64266641f19bc82fce0) gh-102956: Fix returning of empty byte strings after seek in zipfile module. This was a regression in 3.12.0 due to a performance enhancement. Co-authored-by: Jokimax <77680901+Jokimax@users.noreply.github.com> --- Lib/test/test_zipfile/test_core.py | 16 ++++++++++++++++ Lib/zipfile/__init__.py | 10 +++++----- ...023-04-15-14-45-21.gh-issue-102956.Z6qeUy.rst | 1 + 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-04-15-14-45-21.gh-issue-102956.Z6qeUy.rst diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index c2cc2c827ca695..d8a83d4dbba4d0 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -2246,6 +2246,22 @@ def test_seek_tell(self): fp.seek(0, os.SEEK_SET) self.assertEqual(fp.tell(), 0) + def test_read_after_seek(self): + # Issue 102956: Make sure seek(x, os.SEEK_CUR) doesn't break read() + txt = b"Charge men!" + bloc = txt.find(b"men") + with zipfile.ZipFile(TESTFN, "w") as zipf: + zipf.writestr("foo.txt", txt) + with zipfile.ZipFile(TESTFN, mode="r") as zipf: + with zipf.open("foo.txt", "r") as fp: + fp.seek(bloc, os.SEEK_CUR) + self.assertEqual(fp.read(-1), b'men!') + with zipfile.ZipFile(TESTFN, mode="r") as zipf: + with zipf.open("foo.txt", "r") as fp: + fp.read(6) + fp.seek(1, os.SEEK_CUR) + self.assertEqual(fp.read(-1), b'men!') + @requires_bz2() def test_decompress_without_3rd_party_library(self): data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 5b981d5742c12e..59d105580a46bb 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -1122,8 +1122,12 @@ def seek(self, offset, whence=os.SEEK_SET): read_offset = new_pos - curr_pos buff_offset = read_offset + self._offset + if buff_offset >= 0 and buff_offset < len(self._readbuffer): + # Just move the _offset index if the new position is in the _readbuffer + self._offset = buff_offset + read_offset = 0 # Fast seek uncompressed unencrypted file - if self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0: + elif self._compress_type == ZIP_STORED and self._decrypter is None and read_offset > 0: # disable CRC checking after first seeking - it would be invalid self._expected_crc = None # seek actual file taking already buffered data into account @@ -1134,10 +1138,6 @@ def seek(self, offset, whence=os.SEEK_SET): # flush read buffer self._readbuffer = b'' self._offset = 0 - elif buff_offset >= 0 and buff_offset < len(self._readbuffer): - # Just move the _offset index if the new position is in the _readbuffer - self._offset = buff_offset - read_offset = 0 elif read_offset < 0: # Position is before the current position. Reset the ZipExtFile self._fileobj.seek(self._orig_compress_start) diff --git a/Misc/NEWS.d/next/Library/2023-04-15-14-45-21.gh-issue-102956.Z6qeUy.rst b/Misc/NEWS.d/next/Library/2023-04-15-14-45-21.gh-issue-102956.Z6qeUy.rst new file mode 100644 index 00000000000000..1a4bb9bc0dc46a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-15-14-45-21.gh-issue-102956.Z6qeUy.rst @@ -0,0 +1 @@ +Fix returning of empty byte strings after seek in zipfile module From 54e93d36d008351137835eda32072023d539adf9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 25 Oct 2023 12:10:03 +0300 Subject: [PATCH 1088/1206] [3.12] gh-111065: Add more tests for the C API with the PySys_ prefix (GH-111067) (GH-111305) * Move existing tests for PySys_GetObject() and PySys_SetObject() into specialized files. * Add test for PySys_GetXOptions() using _testcapi. * Add tests for PySys_FormatStdout(), PySys_FormatStderr(), PySys_WriteStdout() and PySys_WriteStderr() using ctypes. (cherry picked from commit b2ba2985275d1200e5c44c3f224d754141fc5292) --- Lib/test/test_capi/test_misc.py | 40 -------- Lib/test/test_capi/test_sys.py | 149 ++++++++++++++++++++++++++++++ Modules/Setup.stdlib.in | 2 +- Modules/_testcapi/parts.h | 1 + Modules/_testcapi/sys.c | 57 ++++++++++++ Modules/_testcapimodule.c | 34 +------ PCbuild/_testcapi.vcxproj | 1 + PCbuild/_testcapi.vcxproj.filters | 3 + 8 files changed, 215 insertions(+), 72 deletions(-) create mode 100644 Lib/test/test_capi/test_sys.py create mode 100644 Modules/_testcapi/sys.c diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index cf714e63cf95a5..5d0e036105ec2f 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1090,46 +1090,6 @@ class Data(_testcapi.ObjExtraData): del d.extra self.assertIsNone(d.extra) - def test_sys_getobject(self): - getobject = _testcapi.sys_getobject - - self.assertIs(getobject(b'stdout'), sys.stdout) - with support.swap_attr(sys, '\U0001f40d', 42): - self.assertEqual(getobject('\U0001f40d'.encode()), 42) - - self.assertIs(getobject(b'nonexisting'), AttributeError) - self.assertIs(getobject(b'\xff'), AttributeError) - # CRASHES getobject(NULL) - - def test_sys_setobject(self): - setobject = _testcapi.sys_setobject - - value = ['value'] - value2 = ['value2'] - try: - self.assertEqual(setobject(b'newattr', value), 0) - self.assertIs(sys.newattr, value) - self.assertEqual(setobject(b'newattr', value2), 0) - self.assertIs(sys.newattr, value2) - self.assertEqual(setobject(b'newattr', NULL), 0) - self.assertFalse(hasattr(sys, 'newattr')) - self.assertEqual(setobject(b'newattr', NULL), 0) - finally: - with contextlib.suppress(AttributeError): - del sys.newattr - try: - self.assertEqual(setobject('\U0001f40d'.encode(), value), 0) - self.assertIs(getattr(sys, '\U0001f40d'), value) - self.assertEqual(setobject('\U0001f40d'.encode(), NULL), 0) - self.assertFalse(hasattr(sys, '\U0001f40d')) - finally: - with contextlib.suppress(AttributeError): - delattr(sys, '\U0001f40d') - - with self.assertRaises(UnicodeDecodeError): - setobject(b'\xff', value) - # CRASHES setobject(NULL, value) - @requires_limited_api class TestHeapTypeRelative(unittest.TestCase): diff --git a/Lib/test/test_capi/test_sys.py b/Lib/test/test_capi/test_sys.py new file mode 100644 index 00000000000000..e26f35f5d8a2ee --- /dev/null +++ b/Lib/test/test_capi/test_sys.py @@ -0,0 +1,149 @@ +import unittest +import contextlib +import sys +from test import support +from test.support import import_helper + +try: + import _testcapi +except ImportError: + _testcapi = None + +NULL = None + +class CAPITest(unittest.TestCase): + # TODO: Test the following functions: + # + # PySys_Audit() + + maxDiff = None + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_sys_getobject(self): + # Test PySys_GetObject() + getobject = _testcapi.sys_getobject + + self.assertIs(getobject(b'stdout'), sys.stdout) + with support.swap_attr(sys, '\U0001f40d', 42): + self.assertEqual(getobject('\U0001f40d'.encode()), 42) + + self.assertIs(getobject(b'nonexisting'), AttributeError) + self.assertIs(getobject(b'\xff'), AttributeError) + # CRASHES getobject(NULL) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_sys_setobject(self): + # Test PySys_SetObject() + setobject = _testcapi.sys_setobject + + value = ['value'] + value2 = ['value2'] + try: + self.assertEqual(setobject(b'newattr', value), 0) + self.assertIs(sys.newattr, value) + self.assertEqual(setobject(b'newattr', value2), 0) + self.assertIs(sys.newattr, value2) + self.assertEqual(setobject(b'newattr', NULL), 0) + self.assertFalse(hasattr(sys, 'newattr')) + self.assertEqual(setobject(b'newattr', NULL), 0) + finally: + with contextlib.suppress(AttributeError): + del sys.newattr + try: + self.assertEqual(setobject('\U0001f40d'.encode(), value), 0) + self.assertIs(getattr(sys, '\U0001f40d'), value) + self.assertEqual(setobject('\U0001f40d'.encode(), NULL), 0) + self.assertFalse(hasattr(sys, '\U0001f40d')) + finally: + with contextlib.suppress(AttributeError): + delattr(sys, '\U0001f40d') + + with self.assertRaises(UnicodeDecodeError): + setobject(b'\xff', value) + # CRASHES setobject(NULL, value) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_sys_getxoptions(self): + # Test PySys_GetXOptions() + getxoptions = _testcapi.sys_getxoptions + + self.assertIs(getxoptions(), sys._xoptions) + + xoptions = sys._xoptions + try: + sys._xoptions = 'non-dict' + self.assertEqual(getxoptions(), {}) + self.assertIs(getxoptions(), sys._xoptions) + + del sys._xoptions + self.assertEqual(getxoptions(), {}) + self.assertIs(getxoptions(), sys._xoptions) + finally: + sys._xoptions = xoptions + self.assertIs(getxoptions(), sys._xoptions) + + def _test_sys_formatstream(self, funname, streamname): + import_helper.import_module('ctypes') + from ctypes import pythonapi, c_char_p, py_object + func = getattr(pythonapi, funname) + func.argtypes = (c_char_p,) + + # Supports plain C types. + with support.captured_output(streamname) as stream: + func(b'Hello, %s!', c_char_p(b'world')) + self.assertEqual(stream.getvalue(), 'Hello, world!') + + # Supports Python objects. + with support.captured_output(streamname) as stream: + func(b'Hello, %R!', py_object('world')) + self.assertEqual(stream.getvalue(), "Hello, 'world'!") + + # The total length is not limited. + with support.captured_output(streamname) as stream: + func(b'Hello, %s!', c_char_p(b'world'*200)) + self.assertEqual(stream.getvalue(), 'Hello, ' + 'world'*200 + '!') + + def test_sys_formatstdout(self): + # Test PySys_FormatStdout() + self._test_sys_formatstream('PySys_FormatStdout', 'stdout') + + def test_sys_formatstderr(self): + # Test PySys_FormatStderr() + self._test_sys_formatstream('PySys_FormatStderr', 'stderr') + + def _test_sys_writestream(self, funname, streamname): + import_helper.import_module('ctypes') + from ctypes import pythonapi, c_char_p + func = getattr(pythonapi, funname) + func.argtypes = (c_char_p,) + + # Supports plain C types. + with support.captured_output(streamname) as stream: + func(b'Hello, %s!', c_char_p(b'world')) + self.assertEqual(stream.getvalue(), 'Hello, world!') + + # There is a limit on the total length. + with support.captured_output(streamname) as stream: + func(b'Hello, %s!', c_char_p(b'world'*100)) + self.assertEqual(stream.getvalue(), 'Hello, ' + 'world'*100 + '!') + with support.captured_output(streamname) as stream: + func(b'Hello, %s!', c_char_p(b'world'*200)) + out = stream.getvalue() + self.assertEqual(out[:20], 'Hello, worldworldwor') + self.assertEqual(out[-13:], '... truncated') + self.assertGreater(len(out), 1000) + + def test_sys_writestdout(self): + # Test PySys_WriteStdout() + self._test_sys_writestream('PySys_WriteStdout', 'stdout') + + def test_sys_writestderr(self): + # Test PySys_WriteStderr() + self._test_sys_writestream('PySys_WriteStderr', 'stderr') + + +if __name__ == "__main__": + unittest.main() diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 140245d474cd41..62027eec0d43c9 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -168,7 +168,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index 9bbb54171b0a93..c119c354aafa15 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -45,6 +45,7 @@ int _PyTestCapi_Init_Buffer(PyObject *module); int _PyTestCapi_Init_PyOS(PyObject *module); int _PyTestCapi_Init_Immortal(PyObject *module); int _PyTestCapi_Init_GC(PyObject *mod); +int _PyTestCapi_Init_Sys(PyObject *); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapi/sys.c b/Modules/_testcapi/sys.c new file mode 100644 index 00000000000000..53a2ccb2e22f1d --- /dev/null +++ b/Modules/_testcapi/sys.c @@ -0,0 +1,57 @@ +#define PY_SSIZE_T_CLEAN +#include "parts.h" +#include "util.h" + + +static PyObject * +sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg) +{ + const char *name; + Py_ssize_t size; + if (!PyArg_Parse(arg, "z#", &name, &size)) { + return NULL; + } + PyObject *result = PySys_GetObject(name); + if (result == NULL) { + result = PyExc_AttributeError; + } + return Py_NewRef(result); +} + +static PyObject * +sys_setobject(PyObject *Py_UNUSED(module), PyObject *args) +{ + const char *name; + Py_ssize_t size; + PyObject *value; + if (!PyArg_ParseTuple(args, "z#O", &name, &size, &value)) { + return NULL; + } + NULLABLE(value); + RETURN_INT(PySys_SetObject(name, value)); +} + +static PyObject * +sys_getxoptions(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(ignored)) +{ + PyObject *result = PySys_GetXOptions(); + return Py_XNewRef(result); +} + + +static PyMethodDef test_methods[] = { + {"sys_getobject", sys_getobject, METH_O}, + {"sys_setobject", sys_setobject, METH_VARARGS}, + {"sys_getxoptions", sys_getxoptions, METH_NOARGS}, + {NULL}, +}; + +int +_PyTestCapi_Init_Sys(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 6af1e388cb8342..790e9545fe7659 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3243,35 +3243,6 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args)) } -static PyObject * -sys_getobject(PyObject *Py_UNUSED(module), PyObject *arg) -{ - const char *name; - Py_ssize_t size; - if (!PyArg_Parse(arg, "z#", &name, &size)) { - return NULL; - } - PyObject *result = PySys_GetObject(name); - if (result == NULL) { - result = PyExc_AttributeError; - } - return Py_NewRef(result); -} - -static PyObject * -sys_setobject(PyObject *Py_UNUSED(module), PyObject *args) -{ - const char *name; - Py_ssize_t size; - PyObject *value; - if (!PyArg_ParseTuple(args, "z#O", &name, &size, &value)) { - return NULL; - } - NULLABLE(value); - RETURN_INT(PySys_SetObject(name, value)); -} - - static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -3410,8 +3381,6 @@ static PyMethodDef TestMethods[] = { {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, {"test_atexit", test_atexit, METH_NOARGS}, - {"sys_getobject", sys_getobject, METH_O}, - {"sys_setobject", sys_setobject, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; @@ -4058,6 +4027,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_PyOS(m) < 0) { return NULL; } + if (_PyTestCapi_Init_Sys(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Immortal(m) < 0) { return NULL; } diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 8c0d7a502dd468..ce4cb7445669e1 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -115,6 +115,7 @@ + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index 61322332af7d1e..284adf90373d71 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -72,6 +72,9 @@ Source Files + + Source Files + Source Files From 5e94556f83256440c88f5342cb7908a96f178c0e Mon Sep 17 00:00:00 2001 From: Artyom Romanov <92092049+art3xa@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:04:55 +0500 Subject: [PATCH 1089/1206] [3.12] Bump test deps: `ruff` and `mypy` (GH-111288) (#111313) Bump test deps: `ruff` and `mypy` --- .pre-commit-config.yaml | 2 +- Tools/clinic/requirements-dev.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f0e0fb8c1152f4..35d9c64a8c5c15 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.0 + rev: v0.1.2 hooks: - id: ruff name: Run Ruff on Lib/test/ diff --git a/Tools/clinic/requirements-dev.txt b/Tools/clinic/requirements-dev.txt index 35aa575500e634..79ef43a4024c98 100644 --- a/Tools/clinic/requirements-dev.txt +++ b/Tools/clinic/requirements-dev.txt @@ -1,2 +1,2 @@ # Requirements file for external linters and checks we run on Tools/clinic/ in CI -mypy==1.6.0 +mypy==1.6.1 From 45c0b388809d561750c4f0c791de6ec571215d26 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Oct 2023 13:25:31 +0200 Subject: [PATCH 1090/1206] [3.12] gh-111174: Fix crash in getbuffer() called repeatedly for empty BytesIO (GH-111210) (GH-111314) (cherry picked from commit 9da98c0d9a7cc55c67fb0bd3fa162fd3b2c2629b) Co-authored-by: Serhiy Storchaka --- Lib/test/test_memoryio.py | 14 ++++++++++++++ .../2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst | 2 ++ Modules/_io/bytesio.c | 7 ++++--- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py index cd2faba1791c77..731299294e6877 100644 --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -463,6 +463,20 @@ def test_getbuffer(self): memio.close() self.assertRaises(ValueError, memio.getbuffer) + def test_getbuffer_empty(self): + memio = self.ioclass() + buf = memio.getbuffer() + self.assertEqual(bytes(buf), b"") + # Trying to change the size of the BytesIO while a buffer is exported + # raises a BufferError. + self.assertRaises(BufferError, memio.write, b'x') + buf2 = memio.getbuffer() + self.assertRaises(BufferError, memio.write, b'x') + buf.release() + self.assertRaises(BufferError, memio.write, b'x') + buf2.release() + memio.write(b'x') + def test_read1(self): buf = self.buftype("1234567890") self.assertEqual(self.ioclass(buf).read1(), buf) diff --git a/Misc/NEWS.d/next/Library/2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst b/Misc/NEWS.d/next/Library/2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst new file mode 100644 index 00000000000000..95c315404d0ee6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-23-13-53-58.gh-issue-111174.Oohmzd.rst @@ -0,0 +1,2 @@ +Fix crash in :meth:`io.BytesIO.getbuffer` called repeatedly for empty +BytesIO. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 80773058693259..7636394c35a459 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -124,12 +124,13 @@ unshare_buffer(bytesio *self, size_t size) static int resize_buffer(bytesio *self, size_t size) { + assert(self->buf != NULL); + assert(self->exports == 0); + /* Here, unsigned types are used to avoid dealing with signed integer overflow, which is undefined in C. */ size_t alloc = PyBytes_GET_SIZE(self->buf); - assert(self->buf != NULL); - /* For simplicity, stay in the range of the signed type. Anyway, Python doesn't allow strings to be longer than this. */ if (size > PY_SSIZE_T_MAX) @@ -1072,7 +1073,7 @@ bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags) "bytesiobuf_getbuffer: view==NULL argument is obsolete"); return -1; } - if (SHARED_BUF(b)) { + if (b->exports == 0 && SHARED_BUF(b)) { if (unshare_buffer(b, b->string_size) < 0) return -1; } From 5c4f9a1c7ed9fddd8c3ce4c1793af07f66f36a6b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 25 Oct 2023 14:56:27 +0300 Subject: [PATCH 1091/1206] [3.12] gh-111165: Move test running code from test.support to libregrtest (GH-111166) (GH-111316) Remove no longer used functions run_unittest() and run_doctest() from the test.support module. (cherry picked from commit f6a45a03d0e0ef6b00c45a0de9a606b1d23cbd2f) --- Doc/library/test.rst | 28 --- Lib/test/libregrtest/filter.py | 72 +++++++ Lib/test/libregrtest/findtests.py | 5 +- Lib/test/libregrtest/result.py | 26 ++- Lib/test/libregrtest/results.py | 3 +- Lib/test/libregrtest/setup.py | 5 +- Lib/test/libregrtest/single.py | 47 ++++- .../{support => libregrtest}/testresult.py | 0 Lib/test/support/__init__.py | 186 ------------------ Lib/test/test_regrtest.py | 118 ++++++++++- Lib/test/test_support.py | 115 ----------- ...-10-21-19-27-36.gh-issue-111165.FU6mUk.rst | 2 + 12 files changed, 266 insertions(+), 341 deletions(-) create mode 100644 Lib/test/libregrtest/filter.py rename Lib/test/{support => libregrtest}/testresult.py (100%) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-21-19-27-36.gh-issue-111165.FU6mUk.rst diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 6be77260faa7ea..6e962881f29c49 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -508,34 +508,6 @@ The :mod:`test.support` module defines the following functions: Define match patterns on test filenames and test method names for filtering tests. -.. function:: run_unittest(*classes) - - Execute :class:`unittest.TestCase` subclasses passed to the function. The - function scans the classes for methods starting with the prefix ``test_`` - and executes the tests individually. - - It is also legal to pass strings as parameters; these should be keys in - ``sys.modules``. Each associated module will be scanned by - ``unittest.TestLoader.loadTestsFromModule()``. This is usually seen in the - following :func:`test_main` function:: - - def test_main(): - support.run_unittest(__name__) - - This will run all tests defined in the named module. - - -.. function:: run_doctest(module, verbosity=None, optionflags=0) - - Run :func:`doctest.testmod` on the given *module*. Return - ``(failure_count, test_count)``. - - If *verbosity* is ``None``, :func:`doctest.testmod` is run with verbosity - set to :data:`verbose`. Otherwise, it is run with verbosity set to - ``None``. *optionflags* is passed as ``optionflags`` to - :func:`doctest.testmod`. - - .. function:: get_pagesize() Get size of a page in bytes. diff --git a/Lib/test/libregrtest/filter.py b/Lib/test/libregrtest/filter.py new file mode 100644 index 00000000000000..817624d79e9263 --- /dev/null +++ b/Lib/test/libregrtest/filter.py @@ -0,0 +1,72 @@ +import itertools +import operator +import re + + +# By default, don't filter tests +_test_matchers = () +_test_patterns = () + + +def match_test(test): + # Function used by support.run_unittest() and regrtest --list-cases + result = False + for matcher, result in reversed(_test_matchers): + if matcher(test.id()): + return result + return not result + + +def _is_full_match_test(pattern): + # If a pattern contains at least one dot, it's considered + # as a full test identifier. + # Example: 'test.test_os.FileTests.test_access'. + # + # ignore patterns which contain fnmatch patterns: '*', '?', '[...]' + # or '[!...]'. For example, ignore 'test_access*'. + return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern)) + + +def set_match_tests(patterns): + global _test_matchers, _test_patterns + + if not patterns: + _test_matchers = () + _test_patterns = () + else: + itemgetter = operator.itemgetter + patterns = tuple(patterns) + if patterns != _test_patterns: + _test_matchers = [ + (_compile_match_function(map(itemgetter(0), it)), result) + for result, it in itertools.groupby(patterns, itemgetter(1)) + ] + _test_patterns = patterns + + +def _compile_match_function(patterns): + patterns = list(patterns) + + if all(map(_is_full_match_test, patterns)): + # Simple case: all patterns are full test identifier. + # The test.bisect_cmd utility only uses such full test identifiers. + return set(patterns).__contains__ + else: + import fnmatch + regex = '|'.join(map(fnmatch.translate, patterns)) + # The search *is* case sensitive on purpose: + # don't use flags=re.IGNORECASE + regex_match = re.compile(regex).match + + def match_test_regex(test_id, regex_match=regex_match): + if regex_match(test_id): + # The regex matches the whole identifier, for example + # 'test.test_os.FileTests.test_access'. + return True + else: + # Try to match parts of the test identifier. + # For example, split 'test.test_os.FileTests.test_access' + # into: 'test', 'test_os', 'FileTests' and 'test_access'. + return any(map(regex_match, test_id.split("."))) + + return match_test_regex diff --git a/Lib/test/libregrtest/findtests.py b/Lib/test/libregrtest/findtests.py index f3ff3628bea134..78343775bc5b99 100644 --- a/Lib/test/libregrtest/findtests.py +++ b/Lib/test/libregrtest/findtests.py @@ -4,6 +4,7 @@ from test import support +from .filter import match_test, set_match_tests from .utils import ( StrPath, TestName, TestTuple, TestList, TestFilter, abs_module_name, count, printlist) @@ -79,14 +80,14 @@ def _list_cases(suite): if isinstance(test, unittest.TestSuite): _list_cases(test) elif isinstance(test, unittest.TestCase): - if support.match_test(test): + if match_test(test): print(test.id()) def list_cases(tests: TestTuple, *, match_tests: TestFilter | None = None, test_dir: StrPath | None = None): support.verbose = False - support.set_match_tests(match_tests) + set_match_tests(match_tests) skipped = [] for test_name in tests: diff --git a/Lib/test/libregrtest/result.py b/Lib/test/libregrtest/result.py index d6b0d5ad383a5b..8bfd3665ac93d5 100644 --- a/Lib/test/libregrtest/result.py +++ b/Lib/test/libregrtest/result.py @@ -2,13 +2,35 @@ import json from typing import Any -from test.support import TestStats - from .utils import ( StrJSON, TestName, FilterTuple, format_duration, normalize_test_name, print_warning) +@dataclasses.dataclass(slots=True) +class TestStats: + tests_run: int = 0 + failures: int = 0 + skipped: int = 0 + + @staticmethod + def from_unittest(result): + return TestStats(result.testsRun, + len(result.failures), + len(result.skipped)) + + @staticmethod + def from_doctest(results): + return TestStats(results.attempted, + results.failed, + results.skipped) + + def accumulate(self, stats): + self.tests_run += stats.tests_run + self.failures += stats.failures + self.skipped += stats.skipped + + # Avoid enum.Enum to reduce the number of imports when tests are run class State: PASSED = "PASSED" diff --git a/Lib/test/libregrtest/results.py b/Lib/test/libregrtest/results.py index 3708078ff0bf3a..1feb43f8c074db 100644 --- a/Lib/test/libregrtest/results.py +++ b/Lib/test/libregrtest/results.py @@ -1,8 +1,7 @@ import sys -from test.support import TestStats from .runtests import RunTests -from .result import State, TestResult +from .result import State, TestResult, TestStats from .utils import ( StrPath, TestName, TestTuple, TestList, FilterDict, printlist, count, format_duration) diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index 6a96b051394d20..97edba9f87d7f9 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -8,6 +8,7 @@ from test import support from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII +from .filter import set_match_tests from .runtests import RunTests from .utils import ( setup_unraisable_hook, setup_threading_excepthook, fix_umask, @@ -92,11 +93,11 @@ def setup_tests(runtests: RunTests): support.PGO = runtests.pgo support.PGO_EXTENDED = runtests.pgo_extended - support.set_match_tests(runtests.match_tests) + set_match_tests(runtests.match_tests) if runtests.use_junit: support.junit_xml_list = [] - from test.support.testresult import RegressionTestResult + from .testresult import RegressionTestResult RegressionTestResult.USE_XML = True else: support.junit_xml_list = None diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py index 0304f858edf42c..b4ae29905721dc 100644 --- a/Lib/test/libregrtest/single.py +++ b/Lib/test/libregrtest/single.py @@ -9,13 +9,14 @@ import unittest from test import support -from test.support import TestStats from test.support import threading_helper -from .result import State, TestResult +from .filter import match_test +from .result import State, TestResult, TestStats from .runtests import RunTests from .save_env import saved_test_environment from .setup import setup_tests +from .testresult import get_test_runner from .utils import ( TestName, clear_caches, remove_testfn, abs_module_name, print_warning) @@ -33,7 +34,47 @@ def run_unittest(test_mod): print(error, file=sys.stderr) if loader.errors: raise Exception("errors while loading tests") - return support.run_unittest(tests) + _filter_suite(tests, match_test) + return _run_suite(tests) + +def _filter_suite(suite, pred): + """Recursively filter test cases in a suite based on a predicate.""" + newtests = [] + for test in suite._tests: + if isinstance(test, unittest.TestSuite): + _filter_suite(test, pred) + newtests.append(test) + else: + if pred(test): + newtests.append(test) + suite._tests = newtests + +def _run_suite(suite): + """Run tests from a unittest.TestSuite-derived class.""" + runner = get_test_runner(sys.stdout, + verbosity=support.verbose, + capture_output=(support.junit_xml_list is not None)) + + result = runner.run(suite) + + if support.junit_xml_list is not None: + support.junit_xml_list.append(result.get_xml_element()) + + if not result.testsRun and not result.skipped and not result.errors: + raise support.TestDidNotRun + if not result.wasSuccessful(): + stats = TestStats.from_unittest(result) + if len(result.errors) == 1 and not result.failures: + err = result.errors[0][1] + elif len(result.failures) == 1 and not result.errors: + err = result.failures[0][1] + else: + err = "multiple errors occurred" + if not verbose: err += "; run in verbose mode for details" + errors = [(str(tc), exc_str) for tc, exc_str in result.errors] + failures = [(str(tc), exc_str) for tc, exc_str in result.failures] + raise support.TestFailedWithDetails(err, errors, failures, stats=stats) + return result def regrtest_runner(result: TestResult, test_func, runtests: RunTests) -> None: diff --git a/Lib/test/support/testresult.py b/Lib/test/libregrtest/testresult.py similarity index 100% rename from Lib/test/support/testresult.py rename to Lib/test/libregrtest/testresult.py diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index e6aa2866d43735..650d4aa7d4d84b 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -6,10 +6,8 @@ import contextlib import dataclasses import functools -import itertools import getpass import opcode -import operator import os import re import stat @@ -21,8 +19,6 @@ import unittest import warnings -from .testresult import get_test_runner - __all__ = [ # globals @@ -36,7 +32,6 @@ "is_resource_enabled", "requires", "requires_freebsd_version", "requires_linux_version", "requires_mac_ver", "check_syntax_error", - "run_unittest", "run_doctest", "requires_gzip", "requires_bz2", "requires_lzma", "bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute", "requires_IEEE_754", "requires_zlib", @@ -1132,155 +1127,6 @@ def requires_specialization(test): return unittest.skipUnless( opcode.ENABLE_SPECIALIZATION, "requires specialization")(test) -def _filter_suite(suite, pred): - """Recursively filter test cases in a suite based on a predicate.""" - newtests = [] - for test in suite._tests: - if isinstance(test, unittest.TestSuite): - _filter_suite(test, pred) - newtests.append(test) - else: - if pred(test): - newtests.append(test) - suite._tests = newtests - -@dataclasses.dataclass(slots=True) -class TestStats: - tests_run: int = 0 - failures: int = 0 - skipped: int = 0 - - @staticmethod - def from_unittest(result): - return TestStats(result.testsRun, - len(result.failures), - len(result.skipped)) - - @staticmethod - def from_doctest(results): - return TestStats(results.attempted, - results.failed) - - def accumulate(self, stats): - self.tests_run += stats.tests_run - self.failures += stats.failures - self.skipped += stats.skipped - - -def _run_suite(suite): - """Run tests from a unittest.TestSuite-derived class.""" - runner = get_test_runner(sys.stdout, - verbosity=verbose, - capture_output=(junit_xml_list is not None)) - - result = runner.run(suite) - - if junit_xml_list is not None: - junit_xml_list.append(result.get_xml_element()) - - if not result.testsRun and not result.skipped and not result.errors: - raise TestDidNotRun - if not result.wasSuccessful(): - stats = TestStats.from_unittest(result) - if len(result.errors) == 1 and not result.failures: - err = result.errors[0][1] - elif len(result.failures) == 1 and not result.errors: - err = result.failures[0][1] - else: - err = "multiple errors occurred" - if not verbose: err += "; run in verbose mode for details" - errors = [(str(tc), exc_str) for tc, exc_str in result.errors] - failures = [(str(tc), exc_str) for tc, exc_str in result.failures] - raise TestFailedWithDetails(err, errors, failures, stats=stats) - return result - - -# By default, don't filter tests -_test_matchers = () -_test_patterns = () - - -def match_test(test): - # Function used by support.run_unittest() and regrtest --list-cases - result = False - for matcher, result in reversed(_test_matchers): - if matcher(test.id()): - return result - return not result - - -def _is_full_match_test(pattern): - # If a pattern contains at least one dot, it's considered - # as a full test identifier. - # Example: 'test.test_os.FileTests.test_access'. - # - # ignore patterns which contain fnmatch patterns: '*', '?', '[...]' - # or '[!...]'. For example, ignore 'test_access*'. - return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern)) - - -def set_match_tests(patterns): - global _test_matchers, _test_patterns - - if not patterns: - _test_matchers = () - _test_patterns = () - else: - itemgetter = operator.itemgetter - patterns = tuple(patterns) - if patterns != _test_patterns: - _test_matchers = [ - (_compile_match_function(map(itemgetter(0), it)), result) - for result, it in itertools.groupby(patterns, itemgetter(1)) - ] - _test_patterns = patterns - - -def _compile_match_function(patterns): - patterns = list(patterns) - - if all(map(_is_full_match_test, patterns)): - # Simple case: all patterns are full test identifier. - # The test.bisect_cmd utility only uses such full test identifiers. - return set(patterns).__contains__ - else: - import fnmatch - regex = '|'.join(map(fnmatch.translate, patterns)) - # The search *is* case sensitive on purpose: - # don't use flags=re.IGNORECASE - regex_match = re.compile(regex).match - - def match_test_regex(test_id, regex_match=regex_match): - if regex_match(test_id): - # The regex matches the whole identifier, for example - # 'test.test_os.FileTests.test_access'. - return True - else: - # Try to match parts of the test identifier. - # For example, split 'test.test_os.FileTests.test_access' - # into: 'test', 'test_os', 'FileTests' and 'test_access'. - return any(map(regex_match, test_id.split("."))) - - return match_test_regex - - -def run_unittest(*classes): - """Run tests from unittest.TestCase-derived classes.""" - valid_types = (unittest.TestSuite, unittest.TestCase) - loader = unittest.TestLoader() - suite = unittest.TestSuite() - for cls in classes: - if isinstance(cls, str): - if cls in sys.modules: - suite.addTest(loader.loadTestsFromModule(sys.modules[cls])) - else: - raise ValueError("str arguments must be keys in sys.modules") - elif isinstance(cls, valid_types): - suite.addTest(cls) - else: - suite.addTest(loader.loadTestsFromTestCase(cls)) - _filter_suite(suite, match_test) - return _run_suite(suite) #======================================================================= # Check for the presence of docstrings. @@ -1302,38 +1148,6 @@ def _check_docstrings(): "test requires docstrings") -#======================================================================= -# doctest driver. - -def run_doctest(module, verbosity=None, optionflags=0): - """Run doctest on the given module. Return (#failures, #tests). - - If optional argument verbosity is not specified (or is None), pass - support's belief about verbosity on to doctest. Else doctest's - usual behavior is used (it searches sys.argv for -v). - """ - - import doctest - - if verbosity is None: - verbosity = verbose - else: - verbosity = None - - results = doctest.testmod(module, - verbose=verbosity, - optionflags=optionflags) - if results.failed: - stats = TestStats.from_doctest(results) - raise TestFailed(f"{results.failed} of {results.attempted} " - f"doctests failed", - stats=stats) - if verbose: - print('doctest (%s) ... %d tests with zero failures' % - (module.__name__, results.attempted)) - return results - - #======================================================================= # Support for saving and restoring the imported modules. diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 0c12b0efff88e5..aa3f65487a288e 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -22,11 +22,13 @@ import textwrap import unittest from test import support -from test.support import os_helper, TestStats +from test.support import os_helper from test.libregrtest import cmdline from test.libregrtest import main from test.libregrtest import setup from test.libregrtest import utils +from test.libregrtest.filter import set_match_tests, match_test +from test.libregrtest.result import TestStats from test.libregrtest.utils import normalize_test_name if not support.has_subprocess_support: @@ -2182,6 +2184,120 @@ def test_format_resources(self): format_resources((*ALL_RESOURCES, "tzdata")), 'resources: all,tzdata') + def test_match_test(self): + class Test: + def __init__(self, test_id): + self.test_id = test_id + + def id(self): + return self.test_id + + test_access = Test('test.test_os.FileTests.test_access') + test_chdir = Test('test.test_os.Win32ErrorTests.test_chdir') + test_copy = Test('test.test_shutil.TestCopy.test_copy') + + # Test acceptance + with support.swap_attr(support, '_test_matchers', ()): + # match all + set_match_tests([]) + self.assertTrue(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + + # match all using None + set_match_tests(None) + self.assertTrue(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + + # match the full test identifier + set_match_tests([(test_access.id(), True)]) + self.assertTrue(match_test(test_access)) + self.assertFalse(match_test(test_chdir)) + + # match the module name + set_match_tests([('test_os', True)]) + self.assertTrue(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + self.assertFalse(match_test(test_copy)) + + # Test '*' pattern + set_match_tests([('test_*', True)]) + self.assertTrue(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + + # Test case sensitivity + set_match_tests([('filetests', True)]) + self.assertFalse(match_test(test_access)) + set_match_tests([('FileTests', True)]) + self.assertTrue(match_test(test_access)) + + # Test pattern containing '.' and a '*' metacharacter + set_match_tests([('*test_os.*.test_*', True)]) + self.assertTrue(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + self.assertFalse(match_test(test_copy)) + + # Multiple patterns + set_match_tests([(test_access.id(), True), (test_chdir.id(), True)]) + self.assertTrue(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + self.assertFalse(match_test(test_copy)) + + set_match_tests([('test_access', True), ('DONTMATCH', True)]) + self.assertTrue(match_test(test_access)) + self.assertFalse(match_test(test_chdir)) + + # Test rejection + with support.swap_attr(support, '_test_matchers', ()): + # match the full test identifier + set_match_tests([(test_access.id(), False)]) + self.assertFalse(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + + # match the module name + set_match_tests([('test_os', False)]) + self.assertFalse(match_test(test_access)) + self.assertFalse(match_test(test_chdir)) + self.assertTrue(match_test(test_copy)) + + # Test '*' pattern + set_match_tests([('test_*', False)]) + self.assertFalse(match_test(test_access)) + self.assertFalse(match_test(test_chdir)) + + # Test case sensitivity + set_match_tests([('filetests', False)]) + self.assertTrue(match_test(test_access)) + set_match_tests([('FileTests', False)]) + self.assertFalse(match_test(test_access)) + + # Test pattern containing '.' and a '*' metacharacter + set_match_tests([('*test_os.*.test_*', False)]) + self.assertFalse(match_test(test_access)) + self.assertFalse(match_test(test_chdir)) + self.assertTrue(match_test(test_copy)) + + # Multiple patterns + set_match_tests([(test_access.id(), False), (test_chdir.id(), False)]) + self.assertFalse(match_test(test_access)) + self.assertFalse(match_test(test_chdir)) + self.assertTrue(match_test(test_copy)) + + set_match_tests([('test_access', False), ('DONTMATCH', False)]) + self.assertFalse(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + + # Test mixed filters + with support.swap_attr(support, '_test_matchers', ()): + set_match_tests([('*test_os', False), ('test_access', True)]) + self.assertTrue(match_test(test_access)) + self.assertFalse(match_test(test_chdir)) + self.assertTrue(match_test(test_copy)) + + set_match_tests([('*test_os', True), ('test_access', False)]) + self.assertFalse(match_test(test_access)) + self.assertTrue(match_test(test_chdir)) + self.assertFalse(match_test(test_copy)) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 60c43fde4865f0..1b78d7e84c991a 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -550,120 +550,6 @@ def test_optim_args_from_interpreter_flags(self): with self.subTest(opts=opts): self.check_options(opts, 'optim_args_from_interpreter_flags') - def test_match_test(self): - class Test: - def __init__(self, test_id): - self.test_id = test_id - - def id(self): - return self.test_id - - test_access = Test('test.test_os.FileTests.test_access') - test_chdir = Test('test.test_os.Win32ErrorTests.test_chdir') - test_copy = Test('test.test_shutil.TestCopy.test_copy') - - # Test acceptance - with support.swap_attr(support, '_test_matchers', ()): - # match all - support.set_match_tests([]) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - - # match all using None - support.set_match_tests(None) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - - # match the full test identifier - support.set_match_tests([(test_access.id(), True)]) - self.assertTrue(support.match_test(test_access)) - self.assertFalse(support.match_test(test_chdir)) - - # match the module name - support.set_match_tests([('test_os', True)]) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - self.assertFalse(support.match_test(test_copy)) - - # Test '*' pattern - support.set_match_tests([('test_*', True)]) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - - # Test case sensitivity - support.set_match_tests([('filetests', True)]) - self.assertFalse(support.match_test(test_access)) - support.set_match_tests([('FileTests', True)]) - self.assertTrue(support.match_test(test_access)) - - # Test pattern containing '.' and a '*' metacharacter - support.set_match_tests([('*test_os.*.test_*', True)]) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - self.assertFalse(support.match_test(test_copy)) - - # Multiple patterns - support.set_match_tests([(test_access.id(), True), (test_chdir.id(), True)]) - self.assertTrue(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - self.assertFalse(support.match_test(test_copy)) - - support.set_match_tests([('test_access', True), ('DONTMATCH', True)]) - self.assertTrue(support.match_test(test_access)) - self.assertFalse(support.match_test(test_chdir)) - - # Test rejection - with support.swap_attr(support, '_test_matchers', ()): - # match the full test identifier - support.set_match_tests([(test_access.id(), False)]) - self.assertFalse(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - - # match the module name - support.set_match_tests([('test_os', False)]) - self.assertFalse(support.match_test(test_access)) - self.assertFalse(support.match_test(test_chdir)) - self.assertTrue(support.match_test(test_copy)) - - # Test '*' pattern - support.set_match_tests([('test_*', False)]) - self.assertFalse(support.match_test(test_access)) - self.assertFalse(support.match_test(test_chdir)) - - # Test case sensitivity - support.set_match_tests([('filetests', False)]) - self.assertTrue(support.match_test(test_access)) - support.set_match_tests([('FileTests', False)]) - self.assertFalse(support.match_test(test_access)) - - # Test pattern containing '.' and a '*' metacharacter - support.set_match_tests([('*test_os.*.test_*', False)]) - self.assertFalse(support.match_test(test_access)) - self.assertFalse(support.match_test(test_chdir)) - self.assertTrue(support.match_test(test_copy)) - - # Multiple patterns - support.set_match_tests([(test_access.id(), False), (test_chdir.id(), False)]) - self.assertFalse(support.match_test(test_access)) - self.assertFalse(support.match_test(test_chdir)) - self.assertTrue(support.match_test(test_copy)) - - support.set_match_tests([('test_access', False), ('DONTMATCH', False)]) - self.assertFalse(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - - # Test mixed filters - with support.swap_attr(support, '_test_matchers', ()): - support.set_match_tests([('*test_os', False), ('test_access', True)]) - self.assertTrue(support.match_test(test_access)) - self.assertFalse(support.match_test(test_chdir)) - self.assertTrue(support.match_test(test_copy)) - - support.set_match_tests([('*test_os', True), ('test_access', False)]) - self.assertFalse(support.match_test(test_access)) - self.assertTrue(support.match_test(test_chdir)) - self.assertFalse(support.match_test(test_copy)) - @unittest.skipIf(support.is_emscripten, "Unstable in Emscripten") @unittest.skipIf(support.is_wasi, "Unavailable on WASI") def test_fd_count(self): @@ -864,7 +750,6 @@ def test_copy_python_src_ignore(self): # precisionbigmemtest # bigaddrspacetest # requires_resource - # run_doctest # threading_cleanup # reap_threads # can_symlink diff --git a/Misc/NEWS.d/next/Tests/2023-10-21-19-27-36.gh-issue-111165.FU6mUk.rst b/Misc/NEWS.d/next/Tests/2023-10-21-19-27-36.gh-issue-111165.FU6mUk.rst new file mode 100644 index 00000000000000..11f302d943c29a --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-21-19-27-36.gh-issue-111165.FU6mUk.rst @@ -0,0 +1,2 @@ +Remove no longer used functions ``run_unittest()`` and ``run_doctest()`` +from the :mod:`test.support` module. From 3d67b69820e2e612b4c0b108da0ab7b864b74103 Mon Sep 17 00:00:00 2001 From: Artyom Romanov <92092049+art3xa@users.noreply.github.com> Date: Wed, 25 Oct 2023 17:54:05 +0500 Subject: [PATCH 1092/1206] [3.12] Sync location of `mypy` pin with the `main` branch (#111317) --- .github/dependabot.yml | 2 +- .github/workflows/mypy.yml | 4 ++-- Tools/{clinic => }/requirements-dev.txt | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename Tools/{clinic => }/requirements-dev.txt (100%) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f026b0f5f9454a..c8a3165d690364 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -13,7 +13,7 @@ updates: - "version-update:semver-minor" - "version-update:semver-patch" - package-ecosystem: "pip" - directory: "/Tools/clinic/" + directory: "/Tools/" schedule: interval: "monthly" labels: diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index f089a0b247aeb4..67a4af239e18fc 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -34,6 +34,6 @@ jobs: with: python-version: "3.x" cache: pip - cache-dependency-path: Tools/clinic/requirements-dev.txt - - run: pip install -r Tools/clinic/requirements-dev.txt + cache-dependency-path: Tools/requirements-dev.txt + - run: pip install -r Tools/requirements-dev.txt - run: mypy --config-file Tools/clinic/mypy.ini diff --git a/Tools/clinic/requirements-dev.txt b/Tools/requirements-dev.txt similarity index 100% rename from Tools/clinic/requirements-dev.txt rename to Tools/requirements-dev.txt From ed05bf600687ee506c37a5ee3bb63f37c42d3161 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:08:10 +0200 Subject: [PATCH 1093/1206] [3.12] gh-108590: Improve sqlite3 docs on encoding issues and how to handle those (GH-108699) (#111324) Add a guide for how to handle non-UTF-8 text encodings. Link to that guide from the 'text_factory' docs. (cherry picked from commit 1262e41842957c3b402fc0cf0a6eb2ea230c828f) Co-authored-by: Erlend E. Aasland Co-authored-by: Alex Waygood Co-authored-by: C.A.M. Gerlach Co-authored-by: Corvin Co-authored-by: Ezio Melotti Co-authored-by: Serhiy Storchaka --- Doc/library/sqlite3.rst | 83 +++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 87ea4658d16752..3cb2f4548c1e58 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1123,6 +1123,10 @@ Connection objects f.write('%s\n' % line) con.close() + .. seealso:: + + :ref:`sqlite3-howto-encoding` + .. method:: backup(target, *, pages=-1, progress=None, name="main", sleep=0.250) @@ -1189,6 +1193,10 @@ Connection objects .. versionadded:: 3.7 + .. seealso:: + + :ref:`sqlite3-howto-encoding` + .. method:: getlimit(category, /) Get a connection runtime limit. @@ -1410,39 +1418,8 @@ Connection objects and returns a text representation of it. The callable is invoked for SQLite values with the ``TEXT`` data type. By default, this attribute is set to :class:`str`. - If you want to return ``bytes`` instead, set *text_factory* to ``bytes``. - Example: - - .. testcode:: - - con = sqlite3.connect(":memory:") - cur = con.cursor() - - AUSTRIA = "Österreich" - - # by default, rows are returned as str - cur.execute("SELECT ?", (AUSTRIA,)) - row = cur.fetchone() - assert row[0] == AUSTRIA - - # but we can make sqlite3 always return bytestrings ... - con.text_factory = bytes - cur.execute("SELECT ?", (AUSTRIA,)) - row = cur.fetchone() - assert type(row[0]) is bytes - # the bytestrings will be encoded in UTF-8, unless you stored garbage in the - # database ... - assert row[0] == AUSTRIA.encode("utf-8") - - # we can also implement a custom text_factory ... - # here we implement one that appends "foo" to all strings - con.text_factory = lambda x: x.decode("utf-8") + "foo" - cur.execute("SELECT ?", ("bar",)) - row = cur.fetchone() - assert row[0] == "barfoo" - - con.close() + See :ref:`sqlite3-howto-encoding` for more details. .. attribute:: total_changes @@ -1601,7 +1578,6 @@ Cursor objects COMMIT; """) - .. method:: fetchone() If :attr:`~Cursor.row_factory` is ``None``, @@ -2580,6 +2556,47 @@ With some adjustments, the above recipe can be adapted to use a instead of a :class:`~collections.namedtuple`. +.. _sqlite3-howto-encoding: + +How to handle non-UTF-8 text encodings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, :mod:`!sqlite3` uses :class:`str` to adapt SQLite values +with the ``TEXT`` data type. +This works well for UTF-8 encoded text, but it might fail for other encodings +and invalid UTF-8. +You can use a custom :attr:`~Connection.text_factory` to handle such cases. + +Because of SQLite's `flexible typing`_, it is not uncommon to encounter table +columns with the ``TEXT`` data type containing non-UTF-8 encodings, +or even arbitrary data. +To demonstrate, let's assume we have a database with ISO-8859-2 (Latin-2) +encoded text, for example a table of Czech-English dictionary entries. +Assuming we now have a :class:`Connection` instance :py:data:`!con` +connected to this database, +we can decode the Latin-2 encoded text using this :attr:`~Connection.text_factory`: + +.. testcode:: + + con.text_factory = lambda data: str(data, encoding="latin2") + +For invalid UTF-8 or arbitrary data in stored in ``TEXT`` table columns, +you can use the following technique, borrowed from the :ref:`unicode-howto`: + +.. testcode:: + + con.text_factory = lambda data: str(data, errors="surrogateescape") + +.. note:: + + The :mod:`!sqlite3` module API does not support strings + containing surrogates. + +.. seealso:: + + :ref:`unicode-howto` + + .. _sqlite3-explanation: Explanation From 3641dae42f3840f2cdae9c07eee2c543e66f608f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Oct 2023 17:28:07 +0200 Subject: [PATCH 1094/1206] [3.12] gh-111165: Add missed "support." prefix for "verbose" (GH-111327) (GH-111328) (cherry picked from commit a4981921aa2c00f3883ef593fde1dbc034e3c304) Co-authored-by: Serhiy Storchaka --- Lib/test/libregrtest/single.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py index b4ae29905721dc..ad75ef54a8c3f8 100644 --- a/Lib/test/libregrtest/single.py +++ b/Lib/test/libregrtest/single.py @@ -70,7 +70,7 @@ def _run_suite(suite): err = result.failures[0][1] else: err = "multiple errors occurred" - if not verbose: err += "; run in verbose mode for details" + if not support.verbose: err += "; run in verbose mode for details" errors = [(str(tc), exc_str) for tc, exc_str in result.errors] failures = [(str(tc), exc_str) for tc, exc_str in result.failures] raise support.TestFailedWithDetails(err, errors, failures, stats=stats) From 7cce26bcd99d444878c211767794b72bc791ff97 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:13:05 +0200 Subject: [PATCH 1095/1206] [3.12] Docs: Add `restart_events()` and positional arg semantics for `sys.monitoring` (GH-111291) (#111335) Docs: Add `restart_events()` and positional arg semantics for `sys.monitoring` (GH-111291) (cherry picked from commit 3f84a19e6291db682fc9a570e7612e80e2ffbbb5) Co-authored-by: Tian Gao Co-authored-by: Alex Waygood --- Doc/library/sys.monitoring.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Doc/library/sys.monitoring.rst b/Doc/library/sys.monitoring.rst index c2168cd9f06b08..f2fe3d76248c2c 100644 --- a/Doc/library/sys.monitoring.rst +++ b/Doc/library/sys.monitoring.rst @@ -44,17 +44,17 @@ Identifiers are integers in the range 0 to 5 inclusive. Registering and using tools ''''''''''''''''''''''''''' -.. function:: use_tool_id(tool_id: int, name: str) -> None +.. function:: use_tool_id(tool_id: int, name: str, /) -> None Must be called before *tool_id* can be used. *tool_id* must be in the range 0 to 5 inclusive. Raises a :exc:`ValueError` if *tool_id* is in use. -.. function:: free_tool_id(tool_id: int) -> None +.. function:: free_tool_id(tool_id: int, /) -> None Should be called once a tool no longer requires *tool_id*. -.. function:: get_tool(tool_id: int) -> str | None +.. function:: get_tool(tool_id: int, /) -> str | None Returns the name of the tool if *tool_id* is in use, otherwise it returns ``None``. @@ -237,11 +237,11 @@ Setting events globally Events can be controlled globally by modifying the set of events being monitored. -.. function:: get_events(tool_id: int) -> int +.. function:: get_events(tool_id: int, /) -> int Returns the ``int`` representing all the active events. -.. function:: set_events(tool_id: int, event_set: int) +.. function:: set_events(tool_id: int, event_set: int, /) -> None Activates all events which are set in *event_set*. Raises a :exc:`ValueError` if *tool_id* is not in use. @@ -253,11 +253,11 @@ Per code object events Events can also be controlled on a per code object basis. -.. function:: get_local_events(tool_id: int, code: CodeType) -> int +.. function:: get_local_events(tool_id: int, code: CodeType, /) -> int Returns all the local events for *code* -.. function:: set_local_events(tool_id: int, code: CodeType, event_set: int) +.. function:: set_local_events(tool_id: int, code: CodeType, event_set: int, /) -> None Activates all the local events for *code* which are set in *event_set*. Raises a :exc:`ValueError` if *tool_id* is not in use. @@ -284,6 +284,11 @@ performance monitoring. For example, a program can be run under a debugger with no overhead if the debugger disables all monitoring except for a few breakpoints. +.. function:: restart_events() -> None + + Enable all the events that were disabled by :data:`sys.monitoring.DISABLE` + for all tools. + .. _callbacks: @@ -292,7 +297,7 @@ Registering callback functions To register a callable for events call -.. function:: register_callback(tool_id: int, event: int, func: Callable | None) -> Callable | None +.. function:: register_callback(tool_id: int, event: int, func: Callable | None, /) -> Callable | None Registers the callable *func* for the *event* with the given *tool_id* From 78c6faee08eb832b6eafe85340ca95e1e92f6402 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 26 Oct 2023 15:10:58 +0200 Subject: [PATCH 1096/1206] [3.12] gh-111348: Fix direct invocation of `test_doctest`; remove `test_doctest.test_coverage` (GH-111349) (#111359) gh-111348: Fix direct invocation of `test_doctest`; remove `test_doctest.test_coverage` (GH-111349) (cherry picked from commit 31c05b72c15885ad5ff298de39456d8baed28448) Co-authored-by: Nikita Sobolev Co-authored-by: Sergey B Kirpichev --- Lib/test/test_doctest.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 20059d3a3a7536..09c378fcac80e0 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -3318,19 +3318,5 @@ def load_tests(loader, tests, pattern): return tests -def test_coverage(coverdir): - trace = import_helper.import_module('trace') - tracer = trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,], - trace=0, count=1) - tracer.run('test_main()') - r = tracer.results() - print('Writing coverage results...') - r.write_results(show_missing=True, summary=True, - coverdir=coverdir) - - if __name__ == '__main__': - if '-c' in sys.argv: - test_coverage('/tmp/doctest.cover') - else: - unittest.main() + unittest.main(module='test.test_doctest') From e25d8b40cd70744513e190b1ca153087382b6b09 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 26 Oct 2023 19:08:41 +0200 Subject: [PATCH 1097/1206] GH-111293: Fix DirEntry.inode dropping higher bits on Windows (GH-111294) (cherry picked from commit b468538d356552f0242763fe44a17b1939e8bd55) Co-authored-by: zcxsythenew <30565051+zcxsythenew@users.noreply.github.com> --- .../Windows/2023-10-25-05-01-28.gh-issue-111293.FSsLT6.rst | 1 + Modules/posixmodule.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-10-25-05-01-28.gh-issue-111293.FSsLT6.rst diff --git a/Misc/NEWS.d/next/Windows/2023-10-25-05-01-28.gh-issue-111293.FSsLT6.rst b/Misc/NEWS.d/next/Windows/2023-10-25-05-01-28.gh-issue-111293.FSsLT6.rst new file mode 100644 index 00000000000000..4c6b255bc44c7b --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-10-25-05-01-28.gh-issue-111293.FSsLT6.rst @@ -0,0 +1 @@ +Fix :data:`os.DirEntry.inode` dropping higher 64 bits of a file id on some filesystems on Windows. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b33293992f0d8e..265c817ca6e37d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -14528,6 +14528,7 @@ typedef struct { #ifdef MS_WINDOWS struct _Py_stat_struct win32_lstat; uint64_t win32_file_index; + uint64_t win32_file_index_high; int got_file_index; #else /* POSIX */ #ifdef HAVE_DIRENT_D_TYPE @@ -14859,11 +14860,10 @@ os_DirEntry_inode_impl(DirEntry *self) } self->win32_file_index = stat.st_ino; + self->win32_file_index_high = stat.st_ino_high; self->got_file_index = 1; } - static_assert(sizeof(unsigned long long) >= sizeof(self->win32_file_index), - "DirEntry.win32_file_index is larger than unsigned long long"); - return PyLong_FromUnsignedLongLong(self->win32_file_index); + return _pystat_l128_from_l64_l64(self->win32_file_index, self->win32_file_index_high); #else /* POSIX */ static_assert(sizeof(unsigned long long) >= sizeof(self->d_ino), "DirEntry.d_ino is larger than unsigned long long"); From c81ebf5b3d9aa080d2039f1225f6fed91c29f5a8 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Fri, 27 Oct 2023 06:43:38 +0900 Subject: [PATCH 1098/1206] [3.12] bpo-43950: handle wide unicode characters in tracebacks (GH-28150) (#111346) --- Lib/test/test_traceback.py | 59 ++++++++++++++++++++++++++++++++++++-- Lib/traceback.py | 53 ++++++++++++++++++++++++++-------- Parser/pegen.c | 55 +++++++++++++++++++++++++++++++++++ Parser/pegen.h | 1 + Python/traceback.c | 35 ++++++++++++++++++++-- 5 files changed, 187 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index b9b0463f1700a5..e0ef9e03f1ff9f 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -922,8 +922,63 @@ def f(): f" File \"{__file__}\", line {self.callable_line}, in get_exception", " callable()", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 4}, in f", - " print(1, ï½—ï½—ï½—(", - " ^^^^", + f" print(1, ï½—ï½—ï½—(", + f" ^^^^^^^", + ] + self.assertEqual(actual, expected) + + def test_byte_offset_with_wide_characters_term_highlight(self): + def f(): + 说明说明 = 1 + şçöğıĤellö = 0 # not wide but still non-ascii + return 说明说明 / şçöğıĤellö + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 3}, in f", + f" return 说明说明 / şçöğıĤellö", + f" ~~~~~~~~~^~~~~~~~~~~~", + ] + self.assertEqual(actual, expected) + + def test_byte_offset_with_emojis_term_highlight(self): + def f(): + return "✨ðŸ" + func_说明说明("📗🚛", + "📗🚛") + "ðŸ" + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f", + f' return "✨ðŸ" + func_说明说明("📗🚛",', + f" ^^^^^^^^^^^^^", + ] + self.assertEqual(actual, expected) + + def test_byte_offset_wide_chars_subscript(self): + def f(): + my_dct = { + "✨🚛✨": { + "说明": { + "ðŸðŸðŸ": None + } + } + } + return my_dct["✨🚛✨"]["说明"]["ðŸ"]["说明"]["ðŸðŸ"] + + actual = self.get_exception(f) + expected = [ + f"Traceback (most recent call last):", + f" File \"{__file__}\", line {self.callable_line}, in get_exception", + f" callable()", + f" File \"{__file__}\", line {f.__code__.co_firstlineno + 8}, in f", + f' return my_dct["✨🚛✨"]["说明"]["ðŸ"]["说明"]["ðŸðŸ"]', + f" ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^", ] self.assertEqual(actual, expected) diff --git a/Lib/traceback.py b/Lib/traceback.py index c1be65982cc568..f61d5db0621ab5 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -470,7 +470,8 @@ def format_frame_summary(self, frame_summary): stripped_line = frame_summary.line.strip() row.append(' {}\n'.format(stripped_line)) - orig_line_len = len(frame_summary._original_line) + line = frame_summary._original_line + orig_line_len = len(line) frame_line_len = len(frame_summary.line.lstrip()) stripped_characters = orig_line_len - frame_line_len if ( @@ -478,31 +479,40 @@ def format_frame_summary(self, frame_summary): and frame_summary.end_colno is not None ): start_offset = _byte_offset_to_character_offset( - frame_summary._original_line, frame_summary.colno) + 1 + line, frame_summary.colno) end_offset = _byte_offset_to_character_offset( - frame_summary._original_line, frame_summary.end_colno) + 1 + line, frame_summary.end_colno) + code_segment = line[start_offset:end_offset] anchors = None if frame_summary.lineno == frame_summary.end_lineno: with suppress(Exception): - anchors = _extract_caret_anchors_from_line_segment( - frame_summary._original_line[start_offset - 1:end_offset - 1] - ) + anchors = _extract_caret_anchors_from_line_segment(code_segment) else: - end_offset = stripped_characters + len(stripped_line) + # Don't count the newline since the anchors only need to + # go up until the last character of the line. + end_offset = len(line.rstrip()) # show indicators if primary char doesn't span the frame line if end_offset - start_offset < len(stripped_line) or ( anchors and anchors.right_start_offset - anchors.left_end_offset > 0): + # When showing this on a terminal, some of the non-ASCII characters + # might be rendered as double-width characters, so we need to take + # that into account when calculating the length of the line. + dp_start_offset = _display_width(line, start_offset) + 1 + dp_end_offset = _display_width(line, end_offset) + 1 + row.append(' ') - row.append(' ' * (start_offset - stripped_characters)) + row.append(' ' * (dp_start_offset - stripped_characters)) if anchors: - row.append(anchors.primary_char * (anchors.left_end_offset)) - row.append(anchors.secondary_char * (anchors.right_start_offset - anchors.left_end_offset)) - row.append(anchors.primary_char * (end_offset - start_offset - anchors.right_start_offset)) + dp_left_end_offset = _display_width(code_segment, anchors.left_end_offset) + dp_right_start_offset = _display_width(code_segment, anchors.right_start_offset) + row.append(anchors.primary_char * dp_left_end_offset) + row.append(anchors.secondary_char * (dp_right_start_offset - dp_left_end_offset)) + row.append(anchors.primary_char * (dp_end_offset - dp_start_offset - dp_right_start_offset)) else: - row.append('^' * (end_offset - start_offset)) + row.append('^' * (dp_end_offset - dp_start_offset)) row.append('\n') @@ -623,6 +633,25 @@ def _extract_caret_anchors_from_line_segment(segment): return None +_WIDE_CHAR_SPECIFIERS = "WF" + +def _display_width(line, offset): + """Calculate the extra amount of width space the given source + code segment might take if it were to be displayed on a fixed + width output device. Supports wide unicode characters and emojis.""" + + # Fast track for ASCII-only strings + if line.isascii(): + return offset + + import unicodedata + + return sum( + 2 if unicodedata.east_asian_width(char) in _WIDE_CHAR_SPECIFIERS else 1 + for char in line[:offset] + ) + + class _ExceptionPrintContext: def __init__(self): diff --git a/Parser/pegen.c b/Parser/pegen.c index b9894dd0acc546..ff02e88cee753d 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -38,6 +38,61 @@ _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset) return size; } +// Calculate the extra amount of width space the given source +// code segment might take if it were to be displayed on a fixed +// width output device. Supports wide unicode characters and emojis. +Py_ssize_t +_PyPegen_calculate_display_width(PyObject *line, Py_ssize_t character_offset) +{ + PyObject *segment = PyUnicode_Substring(line, 0, character_offset); + if (!segment) { + return -1; + } + + // Fast track for ascii strings + if (PyUnicode_IS_ASCII(segment)) { + Py_DECREF(segment); + return character_offset; + } + + PyObject *width_fn = _PyImport_GetModuleAttrString("unicodedata", "east_asian_width"); + if (!width_fn) { + return -1; + } + + Py_ssize_t width = 0; + Py_ssize_t len = PyUnicode_GET_LENGTH(segment); + for (Py_ssize_t i = 0; i < len; i++) { + PyObject *chr = PyUnicode_Substring(segment, i, i + 1); + if (!chr) { + Py_DECREF(segment); + Py_DECREF(width_fn); + return -1; + } + + PyObject *width_specifier = PyObject_CallOneArg(width_fn, chr); + Py_DECREF(chr); + if (!width_specifier) { + Py_DECREF(segment); + Py_DECREF(width_fn); + return -1; + } + + if (_PyUnicode_EqualToASCIIString(width_specifier, "W") || + _PyUnicode_EqualToASCIIString(width_specifier, "F")) { + width += 2; + } + else { + width += 1; + } + Py_DECREF(width_specifier); + } + + Py_DECREF(segment); + Py_DECREF(width_fn); + return width; +} + // Here, mark is the start of the node, while p->mark is the end. // If node==NULL, they should be the same. int diff --git a/Parser/pegen.h b/Parser/pegen.h index a8bfa786b96115..268f380262b80e 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -151,6 +151,7 @@ expr_ty _PyPegen_name_token(Parser *p); expr_ty _PyPegen_number_token(Parser *p); void *_PyPegen_string_token(Parser *p); Py_ssize_t _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset); +Py_ssize_t _PyPegen_calculate_display_width(PyObject *segment, Py_ssize_t character_offset); // Error handling functions and APIs typedef enum { diff --git a/Python/traceback.c b/Python/traceback.c index 0070f1591a5275..4fc48816036782 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -900,8 +900,39 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen goto done; } - if (print_error_location_carets(f, truncation, start_offset, end_offset, - right_start_offset, left_end_offset, + // Convert all offsets to display offsets (e.g. the space they would take up if printed + // on the screen). + Py_ssize_t dp_start = _PyPegen_calculate_display_width(source_line, start_offset); + if (dp_start < 0) { + err = ignore_source_errors() < 0; + goto done; + } + + Py_ssize_t dp_end = _PyPegen_calculate_display_width(source_line, end_offset); + if (dp_end < 0) { + err = ignore_source_errors() < 0; + goto done; + } + + Py_ssize_t dp_left_end = -1; + Py_ssize_t dp_right_start = -1; + if (has_secondary_ranges) { + dp_left_end = _PyPegen_calculate_display_width(source_line, left_end_offset); + if (dp_left_end < 0) { + err = ignore_source_errors() < 0; + goto done; + } + + dp_right_start = _PyPegen_calculate_display_width(source_line, right_start_offset); + if (dp_right_start < 0) { + err = ignore_source_errors() < 0; + goto done; + } + } + + + if (print_error_location_carets(f, truncation, dp_start, dp_end, + dp_right_start, dp_left_end, primary_error_char, secondary_error_char) < 0) { err = -1; goto done; From a70b2cd2d2451ce0573c3fc6ec995254c75c8a51 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 27 Oct 2023 00:44:47 +0200 Subject: [PATCH 1099/1206] [3.12] GH-94438: Fix RuntimeWarning for jump tests in test_sys_settrace (GH-111369) (cherry picked from commit a254120f2f1dd99fa64f12594d1ed19c67df7d64) Co-authored-by: Tian Gao --- Lib/test/test_sys_settrace.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 84088d428c9cc9..7e16e94aa110b2 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -9,6 +9,7 @@ import asyncio from test.support import import_helper import contextlib +import warnings support.requires_working_socket(module=True) @@ -1970,6 +1971,9 @@ def run_test(self, func, jumpFrom, jumpTo, expected, error=None, stack.enter_context(self.assertRaisesRegex(*error)) if warning is not None: stack.enter_context(self.assertWarnsRegex(*warning)) + else: + stack.enter_context(warnings.catch_warnings()) + warnings.simplefilter('error') func(output) sys.settrace(None) @@ -2033,7 +2037,7 @@ def test_jump_simple_backwards(output): output.append(1) output.append(2) - @jump_test(1, 4, [5]) + @jump_test(1, 4, [5], warning=(RuntimeWarning, unbound_locals)) def test_jump_is_none_forwards(output): x = None if x is None: @@ -2050,7 +2054,7 @@ def test_jump_is_none_backwards(output): output.append(5) output.append(6) - @jump_test(1, 4, [5]) + @jump_test(2, 4, [5]) def test_jump_is_not_none_forwards(output): x = None if x is not None: From 307ca78d7f97e6942c64383464a7de073d8b6e42 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 27 Oct 2023 06:02:17 +0200 Subject: [PATCH 1100/1206] [3.12] gh-111380: Show SyntaxWarnings only once when parsing if invalid syntax is encouintered (GH-111381) (#111382) gh-111380: Show SyntaxWarnings only once when parsing if invalid syntax is encouintered (GH-111381) (cherry picked from commit 3d2f1f0b830d86f16f42c42b54d3ea4453dac318) Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_string_literals.py | 12 ++++++++++++ .../2023-10-27-11-51-40.gh-issue-111380.vgSbir.rst | 2 ++ Parser/string_parser.c | 5 +++++ 3 files changed, 19 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-27-11-51-40.gh-issue-111380.vgSbir.rst diff --git a/Lib/test/test_string_literals.py b/Lib/test/test_string_literals.py index 9b663c00223d1b..371e8193b3544d 100644 --- a/Lib/test/test_string_literals.py +++ b/Lib/test/test_string_literals.py @@ -131,6 +131,18 @@ def test_eval_str_invalid_escape(self): self.assertEqual(exc.lineno, 1) self.assertEqual(exc.offset, 1) + # Check that the warning is raised ony once if there are syntax errors + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always', category=SyntaxWarning) + with self.assertRaises(SyntaxError) as cm: + eval("'\\e' $") + exc = cm.exception + self.assertEqual(len(w), 1) + self.assertEqual(w[0].category, SyntaxWarning) + self.assertRegex(str(w[0].message), 'invalid escape sequence') + self.assertEqual(w[0].filename, '') + def test_eval_str_invalid_octal_escape(self): for i in range(0o400, 0o1000): with self.assertWarns(SyntaxWarning): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-27-11-51-40.gh-issue-111380.vgSbir.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-27-11-51-40.gh-issue-111380.vgSbir.rst new file mode 100644 index 00000000000000..4ce6398dbfe3b1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-27-11-51-40.gh-issue-111380.vgSbir.rst @@ -0,0 +1,2 @@ +Fix a bug that was causing :exc:`SyntaxWarning` to appear twice when parsing +if invalid syntax is encountered later. Patch by Pablo galindo diff --git a/Parser/string_parser.c b/Parser/string_parser.c index 20459e89463494..65c320c2173e92 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -11,6 +11,11 @@ static int warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token *t) { + if (p->call_invalid_rules) { + // Do not report warnings if we are in the second pass of the parser + // to avoid showing the warning twice. + return 0; + } unsigned char c = *first_invalid_escape; if ((t->type == FSTRING_MIDDLE || t->type == FSTRING_END) && (c == '{' || c == '}')) { // in this case the tokenizer has already emitted a warning, // see tokenizer.c:warn_invalid_escape_sequence From 7d22e855505bb1cd191b3ea224e828b084c0d699 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 27 Oct 2023 16:08:45 +0300 Subject: [PATCH 1101/1206] [3.12] gh-111187: Postpone removal version for locale.getdefaultlocale() to 3.15 (GH-111188) (#111323) --- Doc/library/locale.rst | 2 +- Doc/whatsnew/3.11.rst | 2 +- Doc/whatsnew/3.12.rst | 13 ++++++++++++- Lib/locale.py | 10 ++++++---- .../2023-10-22-21-28-05.gh-issue-111187._W11Ab.rst | 1 + 5 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-22-21-28-05.gh-issue-111187._W11Ab.rst diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index f2abb3638a141f..0817ae5883ce8a 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -303,7 +303,7 @@ The :mod:`locale` module defines the following exception and functions: *language code* and *encoding* may be ``None`` if their values cannot be determined. - .. deprecated-removed:: 3.11 3.13 + .. deprecated-removed:: 3.11 3.15 .. function:: getlocale(category=LC_CTYPE) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 88eaee9791415b..c28093ac193eaf 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1798,7 +1798,7 @@ Standard Library * :func:`importlib.resources.path` * The :func:`locale.getdefaultlocale` function is deprecated and will be - removed in Python 3.13. Use :func:`locale.setlocale`, + removed in Python 3.15. Use :func:`locale.setlocale`, :func:`locale.getpreferredencoding(False) ` and :func:`locale.getlocale` functions instead. (Contributed by Victor Stinner in :gh:`90817`.) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 18fca00c9d5a7b..99e566f7d253c8 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1360,7 +1360,7 @@ Other modules: APIs: * :class:`!configparser.LegacyInterpolation` (:gh:`90765`) -* :func:`locale.getdefaultlocale` (:gh:`90817`) +* ``locale.resetlocale()`` (:gh:`90817`) * :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`) * :func:`!unittest.findTestCases` (:gh:`50096`) * :func:`!unittest.getTestCaseNames` (:gh:`50096`) @@ -1429,6 +1429,17 @@ and will be removed in Python 3.14. * The ``co_lnotab`` attribute of code objects. +Pending Removal in Python 3.15 +------------------------------ + +The following APIs have been deprecated +and will be removed in Python 3.15. + +APIs: + +* :func:`locale.getdefaultlocale` (:gh:`90817`) + + Pending Removal in Future Versions ---------------------------------- diff --git a/Lib/locale.py b/Lib/locale.py index e94f0d1acbaa7d..4965c9730740cc 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -541,12 +541,14 @@ def getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): """ import warnings - warnings.warn( - "Use setlocale(), getencoding() and getlocale() instead", - DeprecationWarning, stacklevel=2 - ) + warnings._deprecated( + "locale.getdefaultlocale", + "{name!r} is deprecated and slated for removal in Python {remove}. " + "Use setlocale(), getencoding() and getlocale() instead.", + remove=(3, 15)) return _getdefaultlocale(envvars) + def _getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): try: # check if it's supported by the _locale module diff --git a/Misc/NEWS.d/next/Library/2023-10-22-21-28-05.gh-issue-111187._W11Ab.rst b/Misc/NEWS.d/next/Library/2023-10-22-21-28-05.gh-issue-111187._W11Ab.rst new file mode 100644 index 00000000000000..dc2424370bb96c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-22-21-28-05.gh-issue-111187._W11Ab.rst @@ -0,0 +1 @@ +Postpone removal version for locale.getdefaultlocale() to Python 3.15. From 2014c23de385c444a9eac8ebad84721c39a62b91 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:29:55 +0200 Subject: [PATCH 1102/1206] [3.12] Fix typos in import system docs (GH-111396) (#111397) Fix typos in import system docs (GH-111396) (cherry picked from commit 9a2f2f46caa556eae4c3ac3b45efa85bd91cc807) Co-authored-by: Jonathan Berthias --- Doc/reference/import.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 1a2677e7562b9c..a7beeea29b4556 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -559,7 +559,7 @@ listed below. functionality, for example getting data associated with a loader. It is **strongly** recommended that you rely on :attr:`__spec__` - instead instead of this attribute. + instead of this attribute. .. versionchanged:: 3.12 The value of ``__loader__`` is expected to be the same as @@ -580,7 +580,7 @@ listed below. relative imports for main modules, as defined in :pep:`366`. It is **strongly** recommended that you rely on :attr:`__spec__` - instead instead of this attribute. + instead of this attribute. .. versionchanged:: 3.6 The value of ``__package__`` is expected to be the same as @@ -650,7 +650,7 @@ listed below. from a file, that atypical scenario may be appropriate. It is **strongly** recommended that you rely on :attr:`__spec__` - instead instead of ``__cached__``. + instead of ``__cached__``. .. _package-path-rules: From 883233dcc3afaf0b1acb31deb486c6cb38d49350 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 27 Oct 2023 17:01:00 +0200 Subject: [PATCH 1103/1206] [3.12] gh-111343: Fix `itertools` docs: `start` arg is optional for `count` (gh-111344) (gh-111385) --- Doc/library/itertools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 5846d784c88ccc..f97e7f720ae4e4 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -41,7 +41,7 @@ operator can be mapped across two vectors to form an efficient dot-product: ================== ================= ================================================= ========================================= Iterator Arguments Results Example ================== ================= ================================================= ========================================= -:func:`count` start, [step] start, start+step, start+2*step, ... ``count(10) --> 10 11 12 13 14 ...`` +:func:`count` [start[, step]] start, start+step, start+2*step, ... ``count(10) --> 10 11 12 13 14 ...`` :func:`cycle` p p0, p1, ... plast, p0, p1, ... ``cycle('ABCD') --> A B C D A B C D ...`` :func:`repeat` elem [,n] elem, elem, elem, ... endlessly or up to n times ``repeat(10, 3) --> 10 10 10`` ================== ================= ================================================= ========================================= From 713210985bb9115060be7fcce6fa25b39abb2378 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 27 Oct 2023 17:15:06 +0200 Subject: [PATCH 1104/1206] [3.12] gh-111276: Clarify docs and comments about the role of LC_CTYPE (GH-111319) (#111391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix locale.LC_CTYPE documentation to no longer mention string.lower() et al. Those functions were removed in Python 3.0: https://docs.python.org/2/library/string.htmlGH-deprecated-string-functions Also, fix a comment in logging about locale-specific behavior of `str.lower()`. (cherry picked from commit 6d42759c5e47ab62d60a72b4ff15d29864554579) Co-authored-by: Åukasz Langa Co-authored-by: Hugo van Kemenade --- Doc/library/locale.rst | 15 ++++++++++----- Lib/logging/handlers.py | 6 ++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 0817ae5883ce8a..2a6d911d6b4ae3 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -464,11 +464,16 @@ The :mod:`locale` module defines the following exception and functions: .. data:: LC_CTYPE - .. index:: pair: module; string - - Locale category for the character type functions. Depending on the settings of - this category, the functions of module :mod:`string` dealing with case change - their behaviour. + Locale category for the character type functions. Most importantly, this + category defines the text encoding, i.e. how bytes are interpreted as + Unicode codepoints. See :pep:`538` and :pep:`540` for how this variable + might be automatically coerced to ``C.UTF-8`` to avoid issues created by + invalid settings in containers or incompatible settings passed over remote + SSH connections. + + Python doesn't internally use locale-dependent character transformation functions + from ``ctype.h``. Instead, an internal ``pyctype.h`` provides locale-independent + equivalents like :c:macro:`!Py_TOLOWER`. .. data:: LC_COLLATE diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 671cc9596b02dd..6e88184b5123c4 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -833,10 +833,8 @@ class SysLogHandler(logging.Handler): "local7": LOG_LOCAL7, } - #The map below appears to be trivially lowercasing the key. However, - #there's more to it than meets the eye - in some locales, lowercasing - #gives unexpected results. See SF #1524081: in the Turkish locale, - #"INFO".lower() != "info" + # Originally added to work around GH-43683. Unnecessary since GH-50043 but kept + # for backwards compatibility. priority_map = { "DEBUG" : "debug", "INFO" : "info", From 754fda88d1ec36b6277d11d9f8e9710b392eca19 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 27 Oct 2023 20:44:33 +0200 Subject: [PATCH 1105/1206] [3.12] gh-111406: Fix broken link to bpython's site (GH-111407) (#111408) gh-111406: Fix broken link to bpython's site (GH-111407) (cherry picked from commit 8a158a753c48d166ebceae0687e88ae0c0725c02) Co-authored-by: Zack Cerza --- Doc/tutorial/interactive.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/interactive.rst b/Doc/tutorial/interactive.rst index 0d3896a4832b59..4e054c4e6c2c32 100644 --- a/Doc/tutorial/interactive.rst +++ b/Doc/tutorial/interactive.rst @@ -51,4 +51,4 @@ bpython_. .. _GNU Readline: https://tiswww.case.edu/php/chet/readline/rltop.html .. _IPython: https://ipython.org/ -.. _bpython: https://www.bpython-interpreter.org/ +.. _bpython: https://bpython-interpreter.org/ From 2398036eeafad68d7cc0829e89405cc1974dc012 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Oct 2023 01:36:05 +0200 Subject: [PATCH 1106/1206] [3.12] gh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (GH-110884) (#111412) - `ThreadedChildWatcher.close()` is now *officially* a no-op; `_join_threads()` never did anything. - Threads created by that class are now named `asyncio-waitpid-NNN`. - `test.test_asyncio.utils.TestCase.close_loop()` now waits for the child watcher's threads, but not forever; if a thread hangs, it raises `RuntimeError`. (cherry picked from commit c3bb10c9303503e7b55a7bdf9acfa6b3bcb699c6) Co-authored-by: Guido van Rossum --- Lib/asyncio/unix_events.py | 11 ++--------- Lib/test/test_asyncio/utils.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 0a618c42d2d257..f2e920ada46aac 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -1367,14 +1367,7 @@ def is_active(self): return True def close(self): - self._join_threads() - - def _join_threads(self): - """Internal: Join all non-daemon threads""" - threads = [thread for thread in list(self._threads.values()) - if thread.is_alive() and not thread.daemon] - for thread in threads: - thread.join() + pass def __enter__(self): return self @@ -1393,7 +1386,7 @@ def __del__(self, _warn=warnings.warn): def add_child_handler(self, pid, callback, *args): loop = events.get_running_loop() thread = threading.Thread(target=self._do_waitpid, - name=f"waitpid-{next(self._pid_counter)}", + name=f"asyncio-waitpid-{next(self._pid_counter)}", args=(loop, pid, callback, args), daemon=True) self._threads[pid] = thread diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 9e8fe2af96b66e..ac8a8b449d3f97 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -547,6 +547,7 @@ def close_loop(loop): else: loop._default_executor.shutdown(wait=True) loop.close() + policy = support.maybe_get_event_loop_policy() if policy is not None: try: @@ -558,9 +559,13 @@ def close_loop(loop): pass else: if isinstance(watcher, asyncio.ThreadedChildWatcher): - threads = list(watcher._threads.values()) - for thread in threads: - thread.join() + # Wait for subprocess to finish, but not forever + for thread in list(watcher._threads.values()): + thread.join(timeout=support.SHORT_TIMEOUT) + if thread.is_alive(): + raise RuntimeError(f"thread {thread} still alive: " + "subprocess still running") + def set_event_loop(self, loop, *, cleanup=True): if loop is None: From c3f75b757f655e864c714482a4306f46c672b111 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Oct 2023 07:27:33 +0200 Subject: [PATCH 1107/1206] [3.12] gh-111342: fix typo in math.sumprod (GH-111416) (gh-111419) --- Lib/test/test_math.py | 1 + .../next/Library/2023-10-28-04-21-17.gh-issue-111342.m8Ln1k.rst | 1 + Modules/mathmodule.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-28-04-21-17.gh-issue-111342.m8Ln1k.rst diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 2bda61012164d1..faf067235c5dad 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1292,6 +1292,7 @@ def test_sumprod_accuracy(self): sumprod = math.sumprod self.assertEqual(sumprod([0.1] * 10, [1]*10), 1.0) self.assertEqual(sumprod([0.1] * 20, [True, False] * 10), 1.0) + self.assertEqual(sumprod([True, False] * 10, [0.1] * 20), 1.0) self.assertEqual(sumprod([1.0, 10E100, 1.0, -10E100], [1.0]*4), 2.0) @support.requires_resource('cpu') diff --git a/Misc/NEWS.d/next/Library/2023-10-28-04-21-17.gh-issue-111342.m8Ln1k.rst b/Misc/NEWS.d/next/Library/2023-10-28-04-21-17.gh-issue-111342.m8Ln1k.rst new file mode 100644 index 00000000000000..57707fd4acf1b2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-28-04-21-17.gh-issue-111342.m8Ln1k.rst @@ -0,0 +1 @@ +Fixed typo in :func:`math.sumprod`. diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 7b1104ba5ac404..23fa2b181648c9 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2831,7 +2831,7 @@ math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q) PyErr_Clear(); goto finalize_flt_path; } - } else if (q_type_float && (PyLong_CheckExact(p_i) || PyBool_Check(q_i))) { + } else if (q_type_float && (PyLong_CheckExact(p_i) || PyBool_Check(p_i))) { flt_q = PyFloat_AS_DOUBLE(q_i); flt_p = PyLong_AsDouble(p_i); if (flt_p == -1.0 && PyErr_Occurred()) { From cf29a2f25e359790c0c0f6a4ab0ab49ca5ffab5d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Oct 2023 09:57:55 +0200 Subject: [PATCH 1108/1206] [3.12] CI: Include Python version in cache.config key (GH-111410) (#111421) CI: Include Python version in cache.config key (GH-111410) * Include Python version in cache.config key, after Python setup * Remove EOL 3.7 from branch triggers (cherry picked from commit 9d4a1a480b65196c3aabbcd2d165d1fb86d0c8e5) Co-authored-by: Hugo van Kemenade --- .github/workflows/build.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af674de20c94ef..0bce1c57f17624 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,6 @@ on: - '3.10' - '3.9' - '3.8' - - '3.7' pull_request: branches: - 'main' @@ -22,7 +21,6 @@ on: - '3.10' - '3.9' - '3.8' - - '3.7' permissions: contents: read @@ -155,14 +153,14 @@ jobs: if: needs.check_source.outputs.run_tests == 'true' steps: - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' - name: Restore config.cache uses: actions/cache@v3 with: path: config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - - uses: actions/setup-python@v4 - with: - python-version: '3.x' + key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }}-${{ env.pythonLocation }} - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Add ccache to PATH @@ -310,7 +308,7 @@ jobs: - uses: actions/checkout@v4 - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Install Dependencies + - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure OpenSSL env vars run: | From 2e5d4e24ebcd671915427b6fd35a5b0eea412c4a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 28 Oct 2023 20:42:53 +0200 Subject: [PATCH 1109/1206] [3.12] gh-79033: Try to fix asyncio.Server.wait_closed() again (GH-111336) (#111424) gh-79033: Try to fix asyncio.Server.wait_closed() again (GH-111336) * Try to fix asyncio.Server.wait_closed() again I identified the condition that `wait_closed()` is intended to wait for: the server is closed *and* there are no more active connections. When this condition first becomes true, `_wakeup()` is called (either from `close()` or from `_detach()`) and it sets `_waiters` to `None`. So we just check for `self._waiters is None`; if it's not `None`, we know we have to wait, and do so. A problem was that the new test introduced in 3.12 explicitly tested that `wait_closed()` returns immediately when the server is *not* closed but there are currently no active connections. This was a mistake (probably a misunderstanding of the intended semantics). I've fixed the test, and added a separate test that checks exactly for this scenario. I also fixed an oddity where in `_wakeup()` the result of the waiter was set to the waiter itself. This result is not used anywhere and I changed this to `None`, to avoid a GC cycle. * Update Lib/asyncio/base_events.py --------- (cherry picked from commit 26553695592ad399f735d4dbaf32fd871d0bb1e1) Co-authored-by: Guido van Rossum Co-authored-by: Carol Willing --- Doc/library/asyncio-eventloop.rst | 8 ++-- Lib/asyncio/base_events.py | 24 +++++++++++- Lib/test/test_asyncio/test_server.py | 38 +++++++++++++++++-- ...3-10-25-11-54-00.gh-issue-79033.5ePgFl.rst | 6 +++ 4 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-25-11-54-00.gh-issue-79033.5ePgFl.rst diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 0ff6136f185092..b9f6f1f33284b4 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1619,8 +1619,9 @@ Do not instantiate the :class:`Server` class directly. The sockets that represent existing incoming client connections are left open. - The server is closed asynchronously, use the :meth:`wait_closed` - coroutine to wait until the server is closed. + The server is closed asynchronously; use the :meth:`wait_closed` + coroutine to wait until the server is closed (and no more + connections are active). .. method:: get_loop() @@ -1678,7 +1679,8 @@ Do not instantiate the :class:`Server` class directly. .. coroutinemethod:: wait_closed() - Wait until the :meth:`close` method completes. + Wait until the :meth:`close` method completes and all active + connections have finished. .. attribute:: sockets diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 259004650d5ab3..5318a597e09ae7 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -305,7 +305,7 @@ def _wakeup(self): self._waiters = None for waiter in waiters: if not waiter.done(): - waiter.set_result(waiter) + waiter.set_result(None) def _start_serving(self): if self._serving: @@ -377,7 +377,27 @@ async def serve_forever(self): self._serving_forever_fut = None async def wait_closed(self): - if self._waiters is None or self._active_count == 0: + """Wait until server is closed and all connections are dropped. + + - If the server is not closed, wait. + - If it is closed, but there are still active connections, wait. + + Anyone waiting here will be unblocked once both conditions + (server is closed and all connections have been dropped) + have become true, in either order. + + Historical note: In 3.11 and before, this was broken, returning + immediately if the server was already closed, even if there + were still active connections. An attempted fix in 3.12.0 was + still broken, returning immediately if the server was still + open and there were no active connections. Hopefully in 3.12.1 + we have it right. + """ + # Waiters are unblocked by self._wakeup(), which is called + # from two places: self.close() and self._detach(), but only + # when both conditions have become true. To signal that this + # has happened, self._wakeup() sets self._waiters to None. + if self._waiters is None: return waiter = self._loop.create_future() self._waiters.append(waiter) diff --git a/Lib/test/test_asyncio/test_server.py b/Lib/test/test_asyncio/test_server.py index 06d8b60f219f1a..7ff3f55f4f0c5a 100644 --- a/Lib/test/test_asyncio/test_server.py +++ b/Lib/test/test_asyncio/test_server.py @@ -122,29 +122,59 @@ async def main(srv): class TestServer2(unittest.IsolatedAsyncioTestCase): - async def test_wait_closed(self): + async def test_wait_closed_basic(self): async def serve(*args): pass srv = await asyncio.start_server(serve, socket_helper.HOSTv4, 0) + self.addCleanup(srv.close) - # active count = 0 + # active count = 0, not closed: should block task1 = asyncio.create_task(srv.wait_closed()) await asyncio.sleep(0) - self.assertTrue(task1.done()) + self.assertFalse(task1.done()) - # active count != 0 + # active count != 0, not closed: should block srv._attach() task2 = asyncio.create_task(srv.wait_closed()) await asyncio.sleep(0) + self.assertFalse(task1.done()) self.assertFalse(task2.done()) srv.close() await asyncio.sleep(0) + # active count != 0, closed: should block + task3 = asyncio.create_task(srv.wait_closed()) + await asyncio.sleep(0) + self.assertFalse(task1.done()) self.assertFalse(task2.done()) + self.assertFalse(task3.done()) srv._detach() + # active count == 0, closed: should unblock + await task1 await task2 + await task3 + await srv.wait_closed() # Return immediately + + async def test_wait_closed_race(self): + # Test a regression in 3.12.0, should be fixed in 3.12.1 + async def serve(*args): + pass + + srv = await asyncio.start_server(serve, socket_helper.HOSTv4, 0) + self.addCleanup(srv.close) + + task = asyncio.create_task(srv.wait_closed()) + await asyncio.sleep(0) + self.assertFalse(task.done()) + srv._attach() + loop = asyncio.get_running_loop() + loop.call_soon(srv.close) + loop.call_soon(srv._detach) + await srv.wait_closed() + + @unittest.skipUnless(hasattr(asyncio, 'ProactorEventLoop'), 'Windows only') diff --git a/Misc/NEWS.d/next/Library/2023-10-25-11-54-00.gh-issue-79033.5ePgFl.rst b/Misc/NEWS.d/next/Library/2023-10-25-11-54-00.gh-issue-79033.5ePgFl.rst new file mode 100644 index 00000000000000..f131bf590870ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-25-11-54-00.gh-issue-79033.5ePgFl.rst @@ -0,0 +1,6 @@ +Another attempt at fixing :func:`asyncio.Server.wait_closed()`. It now +blocks until both conditions are true: the server is closed, *and* there +are no more active connections. (This means that in some cases where in +3.12.0 this function would *incorrectly* have returned immediately, +it will now block; in particular, when there are no active connections +but the server hasn't been closed yet.) From f7ce40213d923d72963bd66488b27a81238e84c5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 29 Oct 2023 01:40:02 +0200 Subject: [PATCH 1110/1206] [3.12] gh-111426: Remove `test_cmd.test_coverage` (GH-111427) (#111432) gh-111426: Remove `test_cmd.test_coverage` (GH-111427) (cherry picked from commit 66bea2555dc7b3dd18282cc699fe9a22dea50de3) Co-authored-by: Nikita Sobolev --- Lib/test/test_cmd.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Lib/test/test_cmd.py b/Lib/test/test_cmd.py index 319801c71f776b..28f80766677e59 100644 --- a/Lib/test/test_cmd.py +++ b/Lib/test/test_cmd.py @@ -248,19 +248,9 @@ def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite()) return tests -def test_coverage(coverdir): - trace = support.import_module('trace') - tracer=trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,], - trace=0, count=1) - tracer.run('import importlib; importlib.reload(cmd); test_main()') - r=tracer.results() - print("Writing coverage results...") - r.write_results(show_missing=True, summary=True, coverdir=coverdir) if __name__ == "__main__": - if "-c" in sys.argv: - test_coverage('/tmp/cmd.cover') - elif "-i" in sys.argv: + if "-i" in sys.argv: samplecmdclass().cmdloop() else: unittest.main() From 0681b4c82c98fc69491711a21583cbfe49af729c Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 29 Oct 2023 18:29:29 +0100 Subject: [PATCH 1111/1206] [3.12] gh-111347: Remove wrong assertion in test_sendfile (GH-111377) (#111461) gh-111347: Remove wrong assertion in test_sendfile (GH-111377) Windows is different. (cherry picked from commit fa35b9e89b2e207fc8bae9eb0284260d0d922e7a) Co-authored-by: zcxsythenew <30565051+zcxsythenew@users.noreply.github.com> --- Lib/test/test_asyncio/test_sendfile.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index 0198da21d77028..d33ff197bbfa1d 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -470,8 +470,11 @@ def test_sendfile_close_peer_in_the_middle_of_receiving(self): self.assertTrue(1024 <= srv_proto.nbytes < len(self.DATA), srv_proto.nbytes) - self.assertTrue(1024 <= self.file.tell() < len(self.DATA), - self.file.tell()) + if not (sys.platform == 'win32' + and isinstance(self.loop, asyncio.ProactorEventLoop)): + # On Windows, Proactor uses transmitFile, which does not update tell() + self.assertTrue(1024 <= self.file.tell() < len(self.DATA), + self.file.tell()) self.assertTrue(cli_proto.transport.is_closing()) def test_sendfile_fallback_close_peer_in_the_middle_of_receiving(self): From 577c808cf97a84483ef59bdea47f8b2b783d7c78 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 29 Oct 2023 20:39:27 +0100 Subject: [PATCH 1112/1206] [3.12] gh-101100: Fix sphinx warnings in `library/asyncio-eventloop.rst` (GH-111222) (#111469) gh-101100: Fix sphinx warnings in `library/asyncio-eventloop.rst` (GH-111222) * gh-101100: Fix sphinx warnings in `library/asyncio-eventloop.rst` * Update Doc/library/socket.rst * Update asyncio-eventloop.rst * Update socket.rst --------- (cherry picked from commit 46389c32750f79ab3f398a0132cd002e8a64f809) Co-authored-by: Nikita Sobolev Co-authored-by: Hugo van Kemenade --- Doc/library/asyncio-eventloop.rst | 14 ++++++++------ Doc/library/socket.rst | 7 +++++++ Doc/tools/.nitignore | 1 - 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index b9f6f1f33284b4..78704d9bb25112 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -509,7 +509,7 @@ Opening network connections .. versionchanged:: 3.6 - The socket option :py:const:`~socket.TCP_NODELAY` is set by default + The socket option :ref:`socket.TCP_NODELAY ` is set by default for all TCP connections. .. versionchanged:: 3.7 @@ -581,7 +581,7 @@ Opening network connections * *reuse_port* tells the kernel to allow this endpoint to be bound to the same port as other existing endpoints are bound to, so long as they all set this flag when being created. This option is not supported on Windows - and some Unixes. If the :py:const:`~socket.SO_REUSEPORT` constant is not + and some Unixes. If the :ref:`socket.SO_REUSEPORT ` constant is not defined then this capability is unsupported. * *allow_broadcast* tells the kernel to allow this endpoint to send @@ -607,7 +607,8 @@ Opening network connections .. versionchanged:: 3.8.1 The *reuse_address* parameter is no longer supported, as using - :py:const:`~sockets.SO_REUSEADDR` poses a significant security concern for + :ref:`socket.SO_REUSEADDR ` + poses a significant security concern for UDP. Explicitly passing ``reuse_address=True`` will raise an exception. When multiple processes with differing UIDs assign sockets to an @@ -616,7 +617,8 @@ Opening network connections For supported platforms, *reuse_port* can be used as a replacement for similar functionality. With *reuse_port*, - :py:const:`~sockets.SO_REUSEPORT` is used instead, which specifically + :ref:`socket.SO_REUSEPORT ` + is used instead, which specifically prevents processes with differing UIDs from assigning sockets to the same socket address. @@ -758,7 +760,7 @@ Creating network servers .. versionchanged:: 3.6 Added *ssl_handshake_timeout* and *start_serving* parameters. - The socket option :py:const:`~socket.TCP_NODELAY` is set by default + The socket option :ref:`socket.TCP_NODELAY ` is set by default for all TCP connections. .. versionchanged:: 3.11 @@ -1888,7 +1890,7 @@ Set signal handlers for SIGINT and SIGTERM (This ``signals`` example only works on Unix.) -Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM` +Register handlers for signals :const:`~signal.SIGINT` and :const:`~signal.SIGTERM` using the :meth:`loop.add_signal_handler` method:: import asyncio diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 14f11b40cb9b00..9ff1aa3984e828 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -352,6 +352,11 @@ Constants defined then this protocol is unsupported. More constants may be available depending on the system. +.. data:: AF_UNSPEC + + :const:`AF_UNSPEC` means that + :func:`getaddrinfo` should return socket addresses for any + address family (either IPv4, IPv6, or any other) that can be used. .. data:: SOCK_STREAM SOCK_DGRAM @@ -380,6 +385,8 @@ Constants .. versionadded:: 3.2 +.. _socket-unix-constants: + .. data:: SO_* SOMAXCONN MSG_* diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 4f12fd0f0459b9..c4c97a1cb7bd9c 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -34,7 +34,6 @@ Doc/library/__future__.rst Doc/library/abc.rst Doc/library/aifc.rst Doc/library/ast.rst -Doc/library/asyncio-eventloop.rst Doc/library/asyncio-extending.rst Doc/library/asyncio-policy.rst Doc/library/asyncio-stream.rst From e5b6744f300553fe2591f73b59a88e8c6f5fa7e3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 29 Oct 2023 20:43:53 +0100 Subject: [PATCH 1113/1206] [3.12] gh-111165: Remove documentation for moved functions (GH-111467) (GH-111471) (cherry picked from commit 4d6bdf8aabcc92303041420a96750fbc52c9f213) Co-authored-by: Serhiy Storchaka --- Doc/library/test.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 6e962881f29c49..7a8d38685b984c 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -498,16 +498,6 @@ The :mod:`test.support` module defines the following functions: rather than looking directly in the path directories. -.. function:: match_test(test) - - Determine whether *test* matches the patterns set in :func:`set_match_tests`. - - -.. function:: set_match_tests(accept_patterns=None, ignore_patterns=None) - - Define match patterns on test filenames and test method names for filtering tests. - - .. function:: get_pagesize() Get size of a page in bytes. From 748bc4864869319c6c7aac0c1161cd54bc0c1bc5 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:36:00 +0100 Subject: [PATCH 1114/1206] [3.12] gh-108082: C API: Add tests for PyErr_WriteUnraisable() (GH-111455) (GH-111507) Also document the behavior when called with NULL. (cherry picked from commit bca330542912532baa33af20a107fcf956cf007a) Co-authored-by: Serhiy Storchaka --- Doc/c-api/exceptions.rst | 8 +++++ Lib/test/test_capi/test_exceptions.py | 45 +++++++++++++++++++++++++++ Modules/_testcapi/exceptions.c | 17 ++++++++++ 3 files changed, 70 insertions(+) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 2139da051e0193..f27e2bbfef05c5 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -88,9 +88,17 @@ Printing and clearing The function is called with a single argument *obj* that identifies the context in which the unraisable exception occurred. If possible, the repr of *obj* will be printed in the warning message. + If *obj* is ``NULL``, only the traceback is printed. An exception must be set when calling this function. + .. versionchanged:: 3.4 + Print a traceback. Print only traceback if *obj* is ``NULL``. + + .. versionchanged:: 3.8 + Use :func:`sys.unraisablehook`. + + .. c:function:: void PyErr_DisplayException(PyObject *exc) Print the standard traceback display of ``exc`` to ``sys.stderr``, including diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index b96cc7922a0ee7..1bff65b6559f0b 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -17,6 +17,10 @@ NULL = None +class CustomError(Exception): + pass + + class Test_Exceptions(unittest.TestCase): def test_exception(self): @@ -270,6 +274,47 @@ def test_setfromerrnowithfilename(self): (ENOENT, 'No such file or directory', 'file')) # CRASHES setfromerrnowithfilename(ENOENT, NULL, b'error') + def test_err_writeunraisable(self): + # Test PyErr_WriteUnraisable() + writeunraisable = _testcapi.err_writeunraisable + firstline = self.test_err_writeunraisable.__code__.co_firstlineno + + with support.catch_unraisable_exception() as cm: + writeunraisable(CustomError('oops!'), hex) + self.assertEqual(cm.unraisable.exc_type, CustomError) + self.assertEqual(str(cm.unraisable.exc_value), 'oops!') + self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, + firstline + 6) + self.assertIsNone(cm.unraisable.err_msg) + self.assertEqual(cm.unraisable.object, hex) + + with support.catch_unraisable_exception() as cm: + writeunraisable(CustomError('oops!'), NULL) + self.assertEqual(cm.unraisable.exc_type, CustomError) + self.assertEqual(str(cm.unraisable.exc_value), 'oops!') + self.assertEqual(cm.unraisable.exc_traceback.tb_lineno, + firstline + 15) + self.assertIsNone(cm.unraisable.err_msg) + self.assertIsNone(cm.unraisable.object) + + with (support.swap_attr(sys, 'unraisablehook', None), + support.captured_stderr() as stderr): + writeunraisable(CustomError('oops!'), hex) + lines = stderr.getvalue().splitlines() + self.assertEqual(lines[0], f'Exception ignored in: {hex!r}') + self.assertEqual(lines[1], 'Traceback (most recent call last):') + self.assertEqual(lines[-1], f'{__name__}.CustomError: oops!') + + with (support.swap_attr(sys, 'unraisablehook', None), + support.captured_stderr() as stderr): + writeunraisable(CustomError('oops!'), NULL) + lines = stderr.getvalue().splitlines() + self.assertEqual(lines[0], 'Traceback (most recent call last):') + self.assertEqual(lines[-1], f'{__name__}.CustomError: oops!') + + # CRASHES writeunraisable(NULL, hex) + # CRASHES writeunraisable(NULL, NULL) + class Test_PyUnstable_Exc_PrepReraiseStar(ExceptionIsLikeMixin, unittest.TestCase): diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index c511c6d071b6f1..4e02f5bec1a942 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -331,6 +331,22 @@ _testcapi_traceback_print_impl(PyObject *module, PyObject *traceback, Py_RETURN_NONE; } +static PyObject * +err_writeunraisable(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *exc, *obj; + if (!PyArg_ParseTuple(args, "OO", &exc, &obj)) { + return NULL; + } + NULLABLE(exc); + NULLABLE(obj); + if (exc) { + PyErr_SetRaisedException(Py_NewRef(exc)); + } + PyErr_WriteUnraisable(obj); + Py_RETURN_NONE; +} + /*[clinic input] _testcapi.unstable_exc_prep_reraise_star orig: object @@ -375,6 +391,7 @@ static PyTypeObject PyRecursingInfinitelyError_Type = { static PyMethodDef test_methods[] = { {"err_restore", err_restore, METH_VARARGS}, + {"err_writeunraisable", err_writeunraisable, METH_VARARGS}, _TESTCAPI_ERR_SET_RAISED_METHODDEF _TESTCAPI_EXCEPTION_PRINT_METHODDEF _TESTCAPI_FATAL_ERROR_METHODDEF From 7ac2c53333266fbb8af1eeb13cb3708b642b023b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:00:57 +0100 Subject: [PATCH 1115/1206] [3.12] gh-111284: Make multiprocessing tests with threads faster and more reliable (GH-111285) (GH-111510) (cherry picked from commit 624ace5a2f02715d084c29eaf2211cd0dd550690) Co-authored-by: Serhiy Storchaka --- Lib/test/_test_multiprocessing.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 83e9d165c411da..d52b10c2ec183c 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -2438,8 +2438,11 @@ def test_namespace(self): # # -def sqr(x, wait=0.0): - time.sleep(wait) +def sqr(x, wait=0.0, event=None): + if event is None: + time.sleep(wait) + else: + event.wait(wait) return x*x def mul(x, y): @@ -2578,10 +2581,18 @@ def test_async(self): self.assertTimingAlmostEqual(get.elapsed, TIMEOUT1) def test_async_timeout(self): - res = self.pool.apply_async(sqr, (6, TIMEOUT2 + support.SHORT_TIMEOUT)) - get = TimingWrapper(res.get) - self.assertRaises(multiprocessing.TimeoutError, get, timeout=TIMEOUT2) - self.assertTimingAlmostEqual(get.elapsed, TIMEOUT2) + p = self.Pool(3) + try: + event = threading.Event() if self.TYPE == 'threads' else None + res = p.apply_async(sqr, (6, TIMEOUT2 + support.SHORT_TIMEOUT, event)) + get = TimingWrapper(res.get) + self.assertRaises(multiprocessing.TimeoutError, get, timeout=TIMEOUT2) + self.assertTimingAlmostEqual(get.elapsed, TIMEOUT2) + finally: + if event is not None: + event.set() + p.terminate() + p.join() def test_imap(self): it = self.pool.imap(sqr, list(range(10))) @@ -2683,10 +2694,11 @@ def test_make_pool(self): def test_terminate(self): # Simulate slow tasks which take "forever" to complete + p = self.Pool(3) args = [support.LONG_TIMEOUT for i in range(10_000)] - result = self.pool.map_async(time.sleep, args, chunksize=1) - self.pool.terminate() - self.pool.join() + result = p.map_async(time.sleep, args, chunksize=1) + p.terminate() + p.join() def test_empty_iterable(self): # See Issue 12157 From ca36426b1c67c61f57d163c3fada8d6337c070d9 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Mon, 30 Oct 2023 19:53:01 +0000 Subject: [PATCH 1116/1206] [3.12] gh-111366: Correctly show custom syntax error messages in the codeop module functions (GH-111384). (#111517) --- Lib/codeop.py | 20 +++++++++++++------ Lib/test/test_codeop.py | 14 +++++++++++++ ...-10-27-12-17-49.gh-issue-111366._TSknV.rst | 3 +++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-27-12-17-49.gh-issue-111366._TSknV.rst diff --git a/Lib/codeop.py b/Lib/codeop.py index 2213b69f231f92..4dd096574bb6b8 100644 --- a/Lib/codeop.py +++ b/Lib/codeop.py @@ -70,8 +70,7 @@ def _maybe_compile(compiler, source, filename, symbol): return None # fallthrough - return compiler(source, filename, symbol) - + return compiler(source, filename, symbol, incomplete_input=False) def _is_syntax_error(err1, err2): rep1 = repr(err1) @@ -82,8 +81,13 @@ def _is_syntax_error(err1, err2): return True return False -def _compile(source, filename, symbol): - return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT) +def _compile(source, filename, symbol, incomplete_input=True): + flags = 0 + if incomplete_input: + flags |= PyCF_ALLOW_INCOMPLETE_INPUT + flags |= PyCF_DONT_IMPLY_DEDENT + return compile(source, filename, symbol, flags) + def compile_command(source, filename="", symbol="single"): r"""Compile a command and determine whether it is incomplete. @@ -114,8 +118,12 @@ class Compile: def __init__(self): self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT - def __call__(self, source, filename, symbol): - codeob = compile(source, filename, symbol, self.flags, True) + def __call__(self, source, filename, symbol, **kwargs): + flags = self.flags + if kwargs.get('incomplete_input', True) is False: + flags &= ~PyCF_DONT_IMPLY_DEDENT + flags &= ~PyCF_ALLOW_INCOMPLETE_INPUT + codeob = compile(source, filename, symbol, flags, True) for feature in _features: if codeob.co_flags & feature.compiler_flag: self.flags |= feature.compiler_flag diff --git a/Lib/test/test_codeop.py b/Lib/test/test_codeop.py index e3c382266fa058..2abb6c6d935b7e 100644 --- a/Lib/test/test_codeop.py +++ b/Lib/test/test_codeop.py @@ -5,6 +5,7 @@ import unittest import warnings from test.support import warnings_helper +from textwrap import dedent from codeop import compile_command, PyCF_DONT_IMPLY_DEDENT @@ -308,6 +309,19 @@ def test_invalid_warning(self): self.assertRegex(str(w[0].message), 'invalid escape sequence') self.assertEqual(w[0].filename, '') + def assertSyntaxErrorMatches(self, code, message): + with self.subTest(code): + with self.assertRaisesRegex(SyntaxError, message): + compile_command(code, symbol='exec') + + def test_syntax_errors(self): + self.assertSyntaxErrorMatches( + dedent("""\ + def foo(x,x): + pass + """), "duplicate argument 'x' in function definition") + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-27-12-17-49.gh-issue-111366._TSknV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-27-12-17-49.gh-issue-111366._TSknV.rst new file mode 100644 index 00000000000000..7e76ce916ea714 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-27-12-17-49.gh-issue-111366._TSknV.rst @@ -0,0 +1,3 @@ +Fix an issue in the :mod:`codeop` that was causing :exc:`SyntaxError` +exceptions raised in the presence of invalid syntax to not contain precise +error messages. Patch by Pablo Galindo From 1675c25495846361ddacde3e4ee5272edcf219e3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Oct 2023 22:47:22 +0100 Subject: [PATCH 1117/1206] [3.12] Remove myself from typing CODEOWNERS (GH-111523) (#111525) Co-authored-by: Ken Jin --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 913de4e2709284..f758482d2ca335 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -142,7 +142,7 @@ Lib/ast.py @isidentical **/*idlelib* @terryjreedy -**/*typing* @gvanrossum @Fidget-Spinner @JelleZijlstra @AlexWaygood +**/*typing* @gvanrossum @JelleZijlstra @AlexWaygood **/*ftplib @giampaolo **/*shutil @giampaolo From e820d7603bad40c4980633fc9fffea3eafe34236 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 31 Oct 2023 08:49:24 +0200 Subject: [PATCH 1118/1206] [3.12] gh-111301: Move `importlib.resources.files` change to What's new in Python 3.12 (#111512) (#111534) Co-authored-by: Karolina Surma <33810531+befeleme@users.noreply.github.com> --- Doc/whatsnew/3.12.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 99e566f7d253c8..feed5238bfab26 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -716,6 +716,9 @@ importlib.resources * :func:`importlib.resources.as_file` now supports resource directories. (Contributed by Jason R. Coombs in :gh:`97930`.) +* Rename first parameter of :func:`importlib.resources.files` to *anchor*. + (Contributed by Jason R. Coombs in :gh:`100598`.) + inspect ------- From dde5a99ba2173cf1ffbc1692d68000610250eacd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 31 Oct 2023 08:26:31 +0100 Subject: [PATCH 1119/1206] [3.12] gh-111531: Tkinter: fix reference leaks in bind_class() and bind_all() (GH-111533) (GH-111535) (cherry picked from commit e3353c498d79f0f3f108a9baf8807a12e77c2ebe) Co-authored-by: Serhiy Storchaka --- Lib/tkinter/__init__.py | 4 ++-- .../Library/2023-10-31-07-46-56.gh-issue-111531.6zUV_G.rst | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-31-07-46-56.gh-issue-111531.6zUV_G.rst diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index c59f8d11e8a9da..cb3e5f1ebab49d 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1459,7 +1459,7 @@ def bind_all(self, sequence=None, func=None, add=None): An additional boolean parameter ADD specifies whether FUNC will be called additionally to the other bound function or whether it will replace the previous function. See bind for the return value.""" - return self._bind(('bind', 'all'), sequence, func, add, 0) + return self._root()._bind(('bind', 'all'), sequence, func, add, True) def unbind_all(self, sequence): """Unbind for all widgets for event SEQUENCE all functions.""" @@ -1473,7 +1473,7 @@ def bind_class(self, className, sequence=None, func=None, add=None): whether it will replace the previous function. See bind for the return value.""" - return self._bind(('bind', className), sequence, func, add, 0) + return self._root()._bind(('bind', className), sequence, func, add, True) def unbind_class(self, className, sequence): """Unbind for all widgets with bindtag CLASSNAME for event SEQUENCE diff --git a/Misc/NEWS.d/next/Library/2023-10-31-07-46-56.gh-issue-111531.6zUV_G.rst b/Misc/NEWS.d/next/Library/2023-10-31-07-46-56.gh-issue-111531.6zUV_G.rst new file mode 100644 index 00000000000000..b722f0414184b1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-31-07-46-56.gh-issue-111531.6zUV_G.rst @@ -0,0 +1,2 @@ +Fix reference leaks in ``bind_class()`` and ``bind_all()`` methods of +:mod:`tkinter` widgets. From c21387c6b22bc6b85cf7fa8fecc3f257f5d782c0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:22:50 +0100 Subject: [PATCH 1120/1206] [3.12] gh-106861: Docs: Add availability directives to all Unix-only modules (GH-108975) (#111553) Co-authored-by: xzmeng --- Doc/library/fcntl.rst | 2 +- Doc/library/grp.rst | 2 +- Doc/library/posix.rst | 2 ++ Doc/library/pty.rst | 2 ++ Doc/library/pwd.rst | 2 +- Doc/library/resource.rst | 2 +- Doc/library/syslog.rst | 4 ++-- Doc/library/termios.rst | 2 ++ Doc/library/tty.rst | 2 ++ 9 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Doc/library/fcntl.rst b/Doc/library/fcntl.rst index 969a79fa873395..309ad652d4af34 100644 --- a/Doc/library/fcntl.rst +++ b/Doc/library/fcntl.rst @@ -18,7 +18,7 @@ interface to the :c:func:`fcntl` and :c:func:`ioctl` Unix routines. For a complete description of these calls, see :manpage:`fcntl(2)` and :manpage:`ioctl(2)` Unix manual pages. -.. include:: ../includes/wasm-notavail.rst +.. availability:: Unix, not Emscripten, not WASI. All functions in this module take a file descriptor *fd* as their first argument. This can be an integer file descriptor, such as returned by diff --git a/Doc/library/grp.rst b/Doc/library/grp.rst index 14af744e3ae8f4..ee55b12ea8643a 100644 --- a/Doc/library/grp.rst +++ b/Doc/library/grp.rst @@ -10,7 +10,7 @@ This module provides access to the Unix group database. It is available on all Unix versions. -.. include:: ../includes/wasm-notavail.rst +.. availability:: Unix, not Emscripten, not WASI. Group database entries are reported as a tuple-like object, whose attributes correspond to the members of the ``group`` structure (Attribute field below, see diff --git a/Doc/library/posix.rst b/Doc/library/posix.rst index 0413f9d02a8d57..5871574b442667 100644 --- a/Doc/library/posix.rst +++ b/Doc/library/posix.rst @@ -11,6 +11,8 @@ This module provides access to operating system functionality that is standardized by the C Standard and the POSIX standard (a thinly disguised Unix interface). +.. availability:: Unix. + .. index:: pair: module; os **Do not import this module directly.** Instead, import the module :mod:`os`, diff --git a/Doc/library/pty.rst b/Doc/library/pty.rst index ad4981c97119fa..af9378464edb9f 100644 --- a/Doc/library/pty.rst +++ b/Doc/library/pty.rst @@ -16,6 +16,8 @@ The :mod:`pty` module defines operations for handling the pseudo-terminal concept: starting another process and being able to write to and read from its controlling terminal programmatically. +.. availability:: Unix. + Pseudo-terminal handling is highly platform dependent. This code is mainly tested on Linux, FreeBSD, and macOS (it is supposed to work on other POSIX platforms but it's not been thoroughly tested). diff --git a/Doc/library/pwd.rst b/Doc/library/pwd.rst index 7cafc66fd7e93c..755f0d29ac7345 100644 --- a/Doc/library/pwd.rst +++ b/Doc/library/pwd.rst @@ -10,7 +10,7 @@ This module provides access to the Unix user account and password database. It is available on all Unix versions. -.. include:: ../includes/wasm-notavail.rst +.. availability:: Unix, not Emscripten, not WASI. Password database entries are reported as a tuple-like object, whose attributes correspond to the members of the ``passwd`` structure (Attribute field below, diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst index a5324c82c63484..ef65674d1b0a78 100644 --- a/Doc/library/resource.rst +++ b/Doc/library/resource.rst @@ -13,7 +13,7 @@ This module provides basic mechanisms for measuring and controlling system resources utilized by a program. -.. include:: ../includes/wasm-notavail.rst +.. availability:: Unix, not Emscripten, not WASI. Symbolic constants are used to specify particular system resources and to request usage information about either the current process or its children. diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst index f29ef03267b1ba..b5ab446e0096ed 100644 --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -11,12 +11,12 @@ This module provides an interface to the Unix ``syslog`` library routines. Refer to the Unix manual pages for a detailed description of the ``syslog`` facility. +.. availability:: Unix, not Emscripten, not WASI. + This module wraps the system ``syslog`` family of routines. A pure Python library that can speak to a syslog server is available in the :mod:`logging.handlers` module as :class:`SysLogHandler`. -.. include:: ../includes/wasm-notavail.rst - The module defines the following functions: diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst index 03806178e9d3fb..57705ddc4e6470 100644 --- a/Doc/library/termios.rst +++ b/Doc/library/termios.rst @@ -16,6 +16,8 @@ complete description of these calls, see :manpage:`termios(3)` Unix manual page. It is only available for those Unix versions that support POSIX *termios* style tty I/O control configured during installation. +.. availability:: Unix. + All functions in this module take a file descriptor *fd* as their first argument. This can be an integer file descriptor, such as returned by ``sys.stdin.fileno()``, or a :term:`file object`, such as ``sys.stdin`` itself. diff --git a/Doc/library/tty.rst b/Doc/library/tty.rst index a4777772e1fc6c..20ba7d7e0a45b3 100644 --- a/Doc/library/tty.rst +++ b/Doc/library/tty.rst @@ -15,6 +15,8 @@ The :mod:`tty` module defines functions for putting the tty into cbreak and raw modes. +.. availability:: Unix. + Because it requires the :mod:`termios` module, it will work only on Unix. The :mod:`tty` module defines the following functions: From 71e138d93e10fcbb0c0bc746e0eec6b254c73d58 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:27:37 +0100 Subject: [PATCH 1121/1206] [3.12] gh-93607: document `root` attribute of `iterparse` (GH-99410) (#111555) Co-authored-by: Prometheus3375 <35541026+Prometheus3375@users.noreply.github.com> Co-authored-by: Stanley <46876382+slateny@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/library/xml.etree.elementtree.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index c9b32632c6b309..57cfbb8d92244b 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -622,7 +622,9 @@ Functions *parser* is an optional parser instance. If not given, the standard :class:`XMLParser` parser is used. *parser* must be a subclass of :class:`XMLParser` and can only use the default :class:`TreeBuilder` as a - target. Returns an :term:`iterator` providing ``(event, elem)`` pairs. + target. Returns an :term:`iterator` providing ``(event, elem)`` pairs; + it has a ``root`` attribute that references the root element of the + resulting XML tree once *source* is fully read. Note that while :func:`iterparse` builds the tree incrementally, it issues blocking reads on *source* (or the file it names). As such, it's unsuitable From b1da63468e27121cd95726aac489c1affafbf5a1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:40:12 +0100 Subject: [PATCH 1122/1206] [3.12] gh-102249: Expand sys.call_tracing documentation (GH-102806) (#111557) Co-authored-by: Quentin Peter Co-authored-by: C.A.M. Gerlach --- Doc/library/sys.rst | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index e0668b8f3614d0..b4666d99b8684b 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -173,7 +173,11 @@ always available. Call ``func(*args)``, while tracing is enabled. The tracing state is saved, and restored afterwards. This is intended to be called from a debugger from - a checkpoint, to recursively debug some other code. + a checkpoint, to recursively debug or profile some other code. + + Tracing is suspended while calling a tracing function set by + :func:`settrace` or :func:`setprofile` to avoid infinite recursion. + :func:`!call_tracing` enables explicit recursion of the tracing function. .. data:: copyright @@ -1471,13 +1475,16 @@ always available. its return value is not used, so it can simply return ``None``. Error in the profile function will cause itself unset. + .. note:: + The same tracing mechanism is used for :func:`!setprofile` as :func:`settrace`. + To trace calls with :func:`!setprofile` inside a tracing function + (e.g. in a debugger breakpoint), see :func:`call_tracing`. + Profile functions should have three arguments: *frame*, *event*, and *arg*. *frame* is the current stack frame. *event* is a string: ``'call'``, ``'return'``, ``'c_call'``, ``'c_return'``, or ``'c_exception'``. *arg* depends on the event type. - .. audit-event:: sys.setprofile "" sys.setprofile - The events have the following meaning: ``'call'`` @@ -1499,6 +1506,9 @@ always available. ``'c_exception'`` A C function has raised an exception. *arg* is the C function object. + .. audit-event:: sys.setprofile "" sys.setprofile + + .. function:: setrecursionlimit(limit) Set the maximum depth of the Python interpreter stack to *limit*. This limit @@ -1558,6 +1568,10 @@ always available. If there is any error occurred in the trace function, it will be unset, just like ``settrace(None)`` is called. + .. note:: + Tracing is disabled while calling the trace function (e.g. a function set by + :func:`!settrace`). For recursive tracing see :func:`call_tracing`. + The events have the following meaning: ``'call'`` From 4f619e83fe1416c9b8d618533a0aaec0b4443b11 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 31 Oct 2023 18:18:11 +0000 Subject: [PATCH 1123/1206] [3.12] gh-109181: Speed up Traceback object creation by lazily compute the line number (GH-111548) (#111551) . (cherry picked from commit abb15420c11d9dda9c89f74eac8417240b321109) --- ...-10-31-14-25-21.gh-issue-109181.11h6Mc.rst | 2 ++ Python/traceback.c | 35 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst new file mode 100644 index 00000000000000..61a15b471cfb27 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst @@ -0,0 +1,2 @@ +Speed up :obj:`Traceback` object creation by lazily compute the line number. +Patch by Pablo Galindo diff --git a/Python/traceback.c b/Python/traceback.c index 4fc48816036782..b627b06df7e6a7 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -107,6 +107,26 @@ tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_)) return Py_NewRef(ret); } +static int +tb_get_lineno(PyTracebackObject* tb) { + PyFrameObject* frame = tb->tb_frame; + assert(frame != NULL); + return PyCode_Addr2Line(PyFrame_GetCode(frame), tb->tb_lasti); +} + +static PyObject * +tb_lineno_get(PyTracebackObject *self, void *Py_UNUSED(_)) +{ + int lineno = self->tb_lineno; + if (lineno == -1) { + lineno = tb_get_lineno(self); + if (lineno < 0) { + Py_RETURN_NONE; + } + } + return PyLong_FromLong(lineno); +} + static int tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_)) { @@ -150,12 +170,12 @@ static PyMethodDef tb_methods[] = { static PyMemberDef tb_memberlist[] = { {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY|PY_AUDIT_READ}, {"tb_lasti", T_INT, OFF(tb_lasti), READONLY}, - {"tb_lineno", T_INT, OFF(tb_lineno), READONLY}, {NULL} /* Sentinel */ }; static PyGetSetDef tb_getsetters[] = { {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL}, + {"tb_lineno", (getter)tb_lineno_get, NULL, NULL, NULL}, {NULL} /* Sentinel */ }; @@ -234,8 +254,7 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) assert(tb_next == NULL || PyTraceBack_Check(tb_next)); assert(frame != NULL); int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT); - return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, - PyFrame_GetLineNumber(frame)); + return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, -1); } @@ -983,9 +1002,13 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit, } while (tb != NULL) { code = PyFrame_GetCode(tb->tb_frame); + int tb_lineno = tb->tb_lineno; + if (tb_lineno == -1) { + tb_lineno = tb_get_lineno(tb); + } if (last_file == NULL || code->co_filename != last_file || - last_line == -1 || tb->tb_lineno != last_line || + last_line == -1 || tb_lineno != last_line || last_name == NULL || code->co_name != last_name) { if (cnt > TB_RECURSIVE_CUTOFF) { if (tb_print_line_repeated(f, cnt) < 0) { @@ -993,13 +1016,13 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit, } } last_file = code->co_filename; - last_line = tb->tb_lineno; + last_line = tb_lineno; last_name = code->co_name; cnt = 0; } cnt++; if (cnt <= TB_RECURSIVE_CUTOFF) { - if (tb_displayline(tb, f, code->co_filename, tb->tb_lineno, + if (tb_displayline(tb, f, code->co_filename, tb_lineno, tb->tb_frame, code->co_name, indent, margin) < 0) { goto error; } From ec00397912ea57a896cb7029e14fad89371b8b2f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 31 Oct 2023 23:01:28 +0100 Subject: [PATCH 1124/1206] [3.12] gh-111181: Fix enum doctests (GH-111180) (GH-111518) gh-111181: Fix enum doctests (GH-111180) (cherry picked from commit c4dc5a6ae8aa13abb743182df088f1a3526d1bcd) Co-authored-by: Nikita Sobolev Co-authored-by: Ethan Furman --- Doc/howto/enum.rst | 9 ++++++--- Lib/enum.py | 11 +++++------ Lib/test/test_enum.py | 17 +++++++++++------ 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index ebaa1cfe4c8b58..0830fb630d701b 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -483,6 +483,7 @@ Dataclass support When inheriting from a :class:`~dataclasses.dataclass`, the :meth:`~Enum.__repr__` omits the inherited class' name. For example:: + >>> from dataclasses import dataclass, field >>> @dataclass ... class CreatureDataMixin: ... size: str @@ -527,7 +528,8 @@ It is possible to modify how enum members are pickled/unpickled by defining :meth:`__reduce_ex__` in the enumeration class. The default method is by-value, but enums with complicated values may want to use by-name:: - >>> class MyEnum(Enum): + >>> import enum + >>> class MyEnum(enum.Enum): ... __reduce_ex__ = enum.pickle_by_enum_name .. note:: @@ -770,7 +772,7 @@ be combined with them (but may lose :class:`IntFlag` membership:: >>> Perm.X | 4 - >>> Perm.X | 8 + >>> Perm.X + 8 9 .. note:: @@ -1435,8 +1437,9 @@ alias:: ... GRENE = 2 ... Traceback (most recent call last): - ... + ... ValueError: aliases not allowed in DuplicateFreeEnum: 'GRENE' --> 'GREEN' + Error calling __set_name__ on '_proto_member' instance 'GRENE' in 'Color' .. note:: diff --git a/Lib/enum.py b/Lib/enum.py index c207dc234c0da2..4bd3756ec5bc0c 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1217,14 +1217,13 @@ def __str__(self): def __dir__(self): """ - Returns all members and all public methods + Returns public methods and other interesting attributes. """ - if self.__class__._member_type_ is object: - interesting = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value']) - else: + interesting = set() + if self.__class__._member_type_ is not object: interesting = set(object.__dir__(self)) for name in getattr(self, '__dict__', []): - if name[0] != '_': + if name[0] != '_' and name not in self._member_map_: interesting.add(name) for cls in self.__class__.mro(): for name, obj in cls.__dict__.items(): @@ -1237,7 +1236,7 @@ def __dir__(self): else: # in case it was added by `dir(self)` interesting.discard(name) - else: + elif name not in self._member_map_: interesting.add(name) names = sorted( set(['__class__', '__doc__', '__eq__', '__hash__', '__module__']) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 14f16f7f26efc3..3bd918fb941c76 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -18,7 +18,7 @@ from io import StringIO from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL from test import support -from test.support import ALWAYS_EQ +from test.support import ALWAYS_EQ, REPO_ROOT from test.support import threading_helper from datetime import timedelta @@ -26,14 +26,19 @@ def load_tests(loader, tests, ignore): tests.addTests(doctest.DocTestSuite(enum)) - if os.path.exists('Doc/library/enum.rst'): + + lib_tests = os.path.join(REPO_ROOT, 'Doc/library/enum.rst') + if os.path.exists(lib_tests): tests.addTests(doctest.DocFileSuite( - '../../Doc/library/enum.rst', + lib_tests, + module_relative=False, optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE, )) - if os.path.exists('Doc/howto/enum.rst'): + howto_tests = os.path.join(REPO_ROOT, 'Doc/howto/enum.rst') + if os.path.exists(howto_tests): tests.addTests(doctest.DocFileSuite( - '../../Doc/howto/enum.rst', + howto_tests, + module_relative=False, optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE, )) return tests @@ -5127,7 +5132,7 @@ def member_dir(member): allowed.add(name) else: allowed.discard(name) - else: + elif name not in member._member_map_: allowed.add(name) return sorted(allowed) From 21c8fbf28dda1f338303295b094b9cc365d101b2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 31 Oct 2023 23:14:21 +0100 Subject: [PATCH 1125/1206] [3.12] gh-111282: Fix NamedTemporaryFile example code (GH-111283) (GH-111579) (cherry picked from commit 102685c4c8481ec5d9c132fcf06b46057e815969) Co-authored-by: Krzysiek Karbowiak --- Doc/library/tempfile.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index b2baa54d9522df..b68a78e8267bcc 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -404,13 +404,13 @@ Here are some examples of typical usage of the :mod:`tempfile` module:: # create a temporary file using a context manager # close the file, use the name to open the file again - >>> with tempfile.TemporaryFile(delete_on_close=False) as fp: - ... fp.write(b'Hello world!') - ... fp.close() - # the file is closed, but not removed - # open the file again by using its name - ... with open(fp.name) as f - ... f.read() + >>> with tempfile.NamedTemporaryFile(delete_on_close=False) as fp: + ... fp.write(b'Hello world!') + ... fp.close() + ... # the file is closed, but not removed + ... # open the file again by using its name + ... with open(fp.name, mode='rb') as f: + ... f.read() b'Hello world!' >>> # file is now removed From 2162512d717e1a7f2bb24b31713ebce23542a2a2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Nov 2023 04:51:24 +0100 Subject: [PATCH 1126/1206] [3.12] gh-110367: Make regrtest --verbose3 compatible with --huntrleaks -jN (GH-111577) (#111589) gh-110367: Make regrtest --verbose3 compatible with --huntrleaks -jN (GH-111577) "./python -m test -j1 -R 3:3 --verbose3" now works as expected, since run_single_test() does not replace sys.stdout with StringIO in this case. (cherry picked from commit d9a5530d2327efa1fe66a04d31b5c67e42dbcd9c) Co-authored-by: Victor Stinner --- Lib/test/libregrtest/cmdline.py | 10 ++++++-- Lib/test/test_regrtest.py | 23 +++++++++++++++++++ ...-10-31-22-09-25.gh-issue-110367.UhQi44.rst | 3 +++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-10-31-22-09-25.gh-issue-110367.UhQi44.rst diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py index 905b3f862281f1..9ba6ec63cad9f8 100644 --- a/Lib/test/libregrtest/cmdline.py +++ b/Lib/test/libregrtest/cmdline.py @@ -494,10 +494,16 @@ def _parse_args(args, **kwargs): ns.randomize = True if ns.verbose: ns.header = True - if ns.huntrleaks and ns.verbose3: + # When -jN option is used, a worker process does not use --verbose3 + # and so -R 3:3 -jN --verbose3 just works as expected: there is no false + # alarm about memory leak. + if ns.huntrleaks and ns.verbose3 and ns.use_mp is None: ns.verbose3 = False + # run_single_test() replaces sys.stdout with io.StringIO if verbose3 + # is true. In this case, huntrleaks sees an write into StringIO as + # a memory leak, whereas it is not (gh-71290). print("WARNING: Disable --verbose3 because it's incompatible with " - "--huntrleaks: see http://bugs.python.org/issue27103", + "--huntrleaks without -jN option", file=sys.stderr) if ns.forever: # --forever implies --failfast diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index aa3f65487a288e..2f1bb03bc0ba4e 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -2120,6 +2120,29 @@ def test_crash(self): self.assertIn(f"Exit code {exitcode} (SIGSEGV)", output) self.check_line(output, "just before crash!", full=True, regex=False) + def test_verbose3(self): + code = textwrap.dedent(r""" + import unittest + from test import support + + class VerboseTests(unittest.TestCase): + def test_pass(self): + print("SPAM SPAM SPAM") + """) + testname = self.create_test(code=code) + + # Run sequentially + output = self.run_tests("--verbose3", testname) + self.check_executed_tests(output, testname, stats=1) + self.assertNotIn('SPAM SPAM SPAM', output) + + # -R option needs a debug build + if support.Py_DEBUG: + # Check for reference leaks, run in parallel + output = self.run_tests("-R", "3:3", "-j1", "--verbose3", testname) + self.check_executed_tests(output, testname, stats=1, parallel=True) + self.assertNotIn('SPAM SPAM SPAM', output) + class TestUtils(unittest.TestCase): def test_format_duration(self): diff --git a/Misc/NEWS.d/next/Tests/2023-10-31-22-09-25.gh-issue-110367.UhQi44.rst b/Misc/NEWS.d/next/Tests/2023-10-31-22-09-25.gh-issue-110367.UhQi44.rst new file mode 100644 index 00000000000000..0254288d3626cc --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-10-31-22-09-25.gh-issue-110367.UhQi44.rst @@ -0,0 +1,3 @@ +Make regrtest ``--verbose3`` option compatible with ``--huntrleaks -jN`` +options. The ``./python -m test -j1 -R 3:3 --verbose3`` command now works as +expected. Patch by Victor Stinner. From 9619e517d4aef6ffd0143110da7af5b14c86edba Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 1 Nov 2023 10:43:56 +0300 Subject: [PATCH 1127/1206] [3.12] gh-111495: add stub files for C API test modules (GH-111586) (GH-111592) This is to reduce merge conflicts (Modules/Setup.stdlib.in) for subsequent pull requests for the issue. (cherry picked from commit 33ed5fa69dbe25d64a910c450be527f4db9dc5dd) --- Modules/Setup.stdlib.in | 2 +- Modules/_testcapi/bytearray.c | 17 +++++++++++++++++ Modules/_testcapi/bytes.c | 17 +++++++++++++++++ Modules/_testcapi/codec.c | 17 +++++++++++++++++ Modules/_testcapi/complex.c | 16 ++++++++++++++++ Modules/_testcapi/file.c | 17 +++++++++++++++++ Modules/_testcapi/list.c | 17 +++++++++++++++++ Modules/_testcapi/numbers.c | 16 ++++++++++++++++ Modules/_testcapi/parts.h | 12 ++++++++++-- Modules/_testcapi/tuple.c | 17 +++++++++++++++++ Modules/_testcapimodule.c | 24 ++++++++++++++++++++++++ PCbuild/_testcapi.vcxproj | 8 ++++++++ PCbuild/_testcapi.vcxproj.filters | 27 +++++++++++++++++++++++++++ 13 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 Modules/_testcapi/bytearray.c create mode 100644 Modules/_testcapi/bytes.c create mode 100644 Modules/_testcapi/codec.c create mode 100644 Modules/_testcapi/complex.c create mode 100644 Modules/_testcapi/file.c create mode 100644 Modules/_testcapi/list.c create mode 100644 Modules/_testcapi/numbers.c create mode 100644 Modules/_testcapi/tuple.c diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 62027eec0d43c9..33608055962db5 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -168,7 +168,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/bytearray.c _testcapi/bytes.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/bytearray.c b/Modules/_testcapi/bytearray.c new file mode 100644 index 00000000000000..6ddb8fe1d5f6b5 --- /dev/null +++ b/Modules/_testcapi/bytearray.c @@ -0,0 +1,17 @@ +#include "parts.h" +#include "util.h" + + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_ByteArray(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/bytes.c b/Modules/_testcapi/bytes.c new file mode 100644 index 00000000000000..9fea716bfbcfd1 --- /dev/null +++ b/Modules/_testcapi/bytes.c @@ -0,0 +1,17 @@ +#include "parts.h" +#include "util.h" + + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_Bytes(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/codec.c b/Modules/_testcapi/codec.c new file mode 100644 index 00000000000000..d13f51e20331a1 --- /dev/null +++ b/Modules/_testcapi/codec.c @@ -0,0 +1,17 @@ +#include "parts.h" +#include "util.h" + + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_Codec(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0){ + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/complex.c b/Modules/_testcapi/complex.c new file mode 100644 index 00000000000000..0402b8ecc9588f --- /dev/null +++ b/Modules/_testcapi/complex.c @@ -0,0 +1,16 @@ +#include "parts.h" +#include "util.h" + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_Complex(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/file.c b/Modules/_testcapi/file.c new file mode 100644 index 00000000000000..634563f6ea12cb --- /dev/null +++ b/Modules/_testcapi/file.c @@ -0,0 +1,17 @@ +#include "parts.h" +#include "util.h" + + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_File(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0){ + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/list.c b/Modules/_testcapi/list.c new file mode 100644 index 00000000000000..9329ddc3bddab4 --- /dev/null +++ b/Modules/_testcapi/list.c @@ -0,0 +1,17 @@ +#include "parts.h" +#include "util.h" + + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_List(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0){ + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/numbers.c b/Modules/_testcapi/numbers.c new file mode 100644 index 00000000000000..6f7fa3fa7a4186 --- /dev/null +++ b/Modules/_testcapi/numbers.c @@ -0,0 +1,16 @@ +#include "parts.h" +#include "util.h" + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_Numbers(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index c119c354aafa15..1dd0995b87fd9e 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -27,6 +27,8 @@ int _PyTestCapi_Init_Vectorcall(PyObject *module); int _PyTestCapi_Init_Heaptype(PyObject *module); int _PyTestCapi_Init_Abstract(PyObject *module); +int _PyTestCapi_Init_ByteArray(PyObject *module); +int _PyTestCapi_Init_Bytes(PyObject *module); int _PyTestCapi_Init_Unicode(PyObject *module); int _PyTestCapi_Init_GetArgs(PyObject *module); int _PyTestCapi_Init_PyTime(PyObject *module); @@ -36,16 +38,22 @@ int _PyTestCapi_Init_Mem(PyObject *module); int _PyTestCapi_Init_Watchers(PyObject *module); int _PyTestCapi_Init_Long(PyObject *module); int _PyTestCapi_Init_Float(PyObject *module); +int _PyTestCapi_Init_Complex(PyObject *module); +int _PyTestCapi_Init_Numbers(PyObject *module); int _PyTestCapi_Init_Dict(PyObject *module); int _PyTestCapi_Init_Set(PyObject *module); +int _PyTestCapi_Init_List(PyObject *module); +int _PyTestCapi_Init_Tuple(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); int _PyTestCapi_Init_Buffer(PyObject *module); int _PyTestCapi_Init_PyOS(PyObject *module); +int _PyTestCapi_Init_File(PyObject *module); +int _PyTestCapi_Init_Codec(PyObject *module); int _PyTestCapi_Init_Immortal(PyObject *module); -int _PyTestCapi_Init_GC(PyObject *mod); -int _PyTestCapi_Init_Sys(PyObject *); +int _PyTestCapi_Init_GC(PyObject *module); +int _PyTestCapi_Init_Sys(PyObject *module); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapi/tuple.c b/Modules/_testcapi/tuple.c new file mode 100644 index 00000000000000..95dde8c0edadbe --- /dev/null +++ b/Modules/_testcapi/tuple.c @@ -0,0 +1,17 @@ +#include "parts.h" +#include "util.h" + + +static PyMethodDef test_methods[] = { + {NULL}, +}; + +int +_PyTestCapi_Init_Tuple(PyObject *m) +{ + if (PyModule_AddFunctions(m, test_methods) < 0){ + return -1; + } + + return 0; +} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 790e9545fe7659..b1cb9350e5984c 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3979,6 +3979,12 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Abstract(m) < 0) { return NULL; } + if (_PyTestCapi_Init_ByteArray(m) < 0) { + return NULL; + } + if (_PyTestCapi_Init_Bytes(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Unicode(m) < 0) { return NULL; } @@ -4006,12 +4012,24 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Float(m) < 0) { return NULL; } + if (_PyTestCapi_Init_Complex(m) < 0) { + return NULL; + } + if (_PyTestCapi_Init_Numbers(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Dict(m) < 0) { return NULL; } if (_PyTestCapi_Init_Set(m) < 0) { return NULL; } + if (_PyTestCapi_Init_List(m) < 0) { + return NULL; + } + if (_PyTestCapi_Init_Tuple(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Structmember(m) < 0) { return NULL; } @@ -4027,6 +4045,12 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_PyOS(m) < 0) { return NULL; } + if (_PyTestCapi_Init_File(m) < 0) { + return NULL; + } + if (_PyTestCapi_Init_Codec(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_Sys(m) < 0) { return NULL; } diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index ce4cb7445669e1..e032e67c256426 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -100,21 +100,29 @@ + + + + + + + + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index 284adf90373d71..e985856a6a92a5 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -30,12 +30,27 @@ Source Files + + Source Files + + + Source Files + Source Files Source Files + + Source Files + + + Source Files + + + Source Files + Source Files @@ -57,6 +72,12 @@ Source Files + + Source Files + + + Source Files + Source Files @@ -72,6 +93,12 @@ Source Files + + Source Files + + + Source Files + Source Files From e2557947a455bb7e990f0b878cf7c68f752b19f1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Nov 2023 11:43:14 +0100 Subject: [PATCH 1128/1206] [3.12] gh-111576: Improve documention for tkinter.messagebox (GH-111578) (GH-111597) (cherry picked from commit eaf67e37a2da28c1241362e3b4ff1202945c83c5) Co-authored-by: Serhiy Storchaka --- Doc/library/tkinter.messagebox.rst | 175 +++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 10 deletions(-) diff --git a/Doc/library/tkinter.messagebox.rst b/Doc/library/tkinter.messagebox.rst index 56c1d6c132afd2..56090a0a0e424b 100644 --- a/Doc/library/tkinter.messagebox.rst +++ b/Doc/library/tkinter.messagebox.rst @@ -11,7 +11,8 @@ The :mod:`tkinter.messagebox` module provides a template base class as well as a variety of convenience methods for commonly used configurations. The message -boxes are modal and will return a subset of (True, False, OK, None, Yes, No) based on +boxes are modal and will return a subset of (``True``, ``False``, ``None``, +:data:`OK`, :data:`CANCEL`, :data:`YES`, :data:`NO`) based on the user's selection. Common message box styles and layouts include but are not limited to: @@ -19,21 +20,175 @@ limited to: .. class:: Message(master=None, **options) - Create a default information message box. + Create a message window with an application-specified message, an icon + and a set of buttons. + Each of the buttons in the message window is identified by a unique symbolic name (see the *type* options). + + The following options are supported: + + *command* + Specifies the function to invoke when the user closes the dialog. + The name of the button clicked by the user to close the dialog is + passed as argument. + This is only available on macOS. + + *default* + Gives the :ref:`symbolic name ` of the default button + for this message window (:data:`OK`, :data:`CANCEL`, and so on). + If this option is not specified, the first button in the dialog will + be made the default. + + *detail* + Specifies an auxiliary message to the main message given by the + *message* option. + The message detail will be presented beneath the main message and, + where supported by the OS, in a less emphasized font than the main + message. + + *icon* + Specifies an :ref:`icon ` to display. + If this option is not specified, then the :data:`INFO` icon will be + displayed. + + *message* + Specifies the message to display in this message box. + The default value is an empty string. + + *parent* + Makes the specified window the logical parent of the message box. + The message box is displayed on top of its parent window. + + *title* + Specifies a string to display as the title of the message box. + This option is ignored on macOS, where platform guidelines forbid + the use of a title on this kind of dialog. + + *type* + Arranges for a :ref:`predefined set of buttons ` + to be displayed. + + .. method:: show(**options) + + Display a message window and wait for the user to select one of the buttons. Then return the symbolic name of the selected button. + Keyword arguments can override options specified in the constructor. + **Information message box** -.. method:: showinfo(title=None, message=None, **options) +.. function:: showinfo(title=None, message=None, **options) + + Creates and displays an information message box with the specified title + and message. **Warning message boxes** -.. method:: showwarning(title=None, message=None, **options) - showerror(title=None, message=None, **options) +.. function:: showwarning(title=None, message=None, **options) + + Creates and displays a warning message box with the specified title + and message. + +.. function:: showerror(title=None, message=None, **options) + + Creates and displays an error message box with the specified title + and message. **Question message boxes** -.. method:: askquestion(title=None, message=None, **options) - askokcancel(title=None, message=None, **options) - askretrycancel(title=None, message=None, **options) - askyesno(title=None, message=None, **options) - askyesnocancel(title=None, message=None, **options) +.. function:: askquestion(title=None, message=None, *, type=YESNO, **options) + + Ask a question. By default shows buttons :data:`YES` and :data:`NO`. + Returns the symbolic name of the selected button. + +.. function:: askokcancel(title=None, message=None, **options) + + Ask if operation should proceed. Shows buttons :data:`OK` and :data:`CANCEL`. + Returns ``True`` if the answer is ok and ``False`` otherwise. + +.. function:: askretrycancel(title=None, message=None, **options) + + Ask if operation should be retried. Shows buttons :data:`RETRY` and :data:`CANCEL`. + Return ``True`` if the answer is yes and ``False`` otherwise. + +.. function:: askyesno(title=None, message=None, **options) + + Ask a question. Shows buttons :data:`YES` and :data:`NO`. + Returns ``True`` if the answer is yes and ``False`` otherwise. + +.. function:: askyesnocancel(title=None, message=None, **options) + + Ask a question. Shows buttons :data:`YES`, :data:`NO` and :data:`CANCEL`. + Return ``True`` if the answer is yes, ``None`` if cancelled, and ``False`` + otherwise. + + +.. _messagebox-buttons: + +Symbolic names of buttons: + +.. data:: ABORT + :value: 'abort' +.. data:: RETRY + :value: 'retry' +.. data:: IGNORE + :value: 'ignore' +.. data:: OK + :value: 'ok' +.. data:: CANCEL + :value: 'cancel' +.. data:: YES + :value: 'yes' +.. data:: NO + :value: 'no' + +.. _messagebox-types: + +Predefined sets of buttons: + +.. data:: ABORTRETRYIGNORE + :value: 'abortretryignore' + + Displays three buttons whose symbolic names are :data:`ABORT`, + :data:`RETRY` and :data:`IGNORE`. + +.. data:: OK + :value: 'ok' + :noindex: + + Displays one button whose symbolic name is :data:`OK`. + +.. data:: OKCANCEL + :value: 'okcancel' + + Displays two buttons whose symbolic names are :data:`OK` and + :data:`CANCEL`. + +.. data:: RETRYCANCEL + :value: 'retrycancel' + + Displays two buttons whose symbolic names are :data:`RETRY` and + :data:`CANCEL`. + +.. data:: YESNO + :value: 'yesno' + + Displays two buttons whose symbolic names are :data:`YES` and + :data:`NO`. + +.. data:: YESNOCANCEL + :value: 'yesnocancel' + + Displays three buttons whose symbolic names are :data:`YES`, + :data:`NO` and :data:`CANCEL`. + +.. _messagebox-icons: + +Icon images: + +.. data:: ERROR + :value: 'error' +.. data:: INFO + :value: 'info' +.. data:: QUESTION + :value: 'question' +.. data:: WARNING + :value: 'warning' From d3d2cfead71e3a64704d8e578f22bba18b8e0284 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 1 Nov 2023 18:13:31 +0100 Subject: [PATCH 1129/1206] [3.12] gh-110968: Py_MOD_PER_INTERPRETER_GIL_SUPPORTED was added to 3.12 (#111588) Constants like Py_MOD_PER_INTERPRETER_GIL_SUPPORTED were only added to the limited C API version 3.12 and newer. --- Include/moduleobject.h | 12 +++++++----- Modules/xxlimited.c | 3 ++- Modules/xxlimited_35.c | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Include/moduleobject.h b/Include/moduleobject.h index b8bdfe29d80406..1717eb352d2a4d 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -84,13 +84,15 @@ struct PyModuleDef_Slot { #define _Py_mod_LAST_SLOT 3 #endif -/* for Py_mod_multiple_interpreters: */ -#define Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED ((void *)0) -#define Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED ((void *)1) -#define Py_MOD_PER_INTERPRETER_GIL_SUPPORTED ((void *)2) - #endif /* New in 3.5 */ +/* for Py_mod_multiple_interpreters: */ +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030c0000 +# define Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED ((void *)0) +# define Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED ((void *)1) +# define Py_MOD_PER_INTERPRETER_GIL_SUPPORTED ((void *)2) +#endif + struct PyModuleDef { PyModuleDef_Base m_base; const char* m_name; diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c index 3935c00fc26530..b9646debba9499 100644 --- a/Modules/xxlimited.c +++ b/Modules/xxlimited.c @@ -62,7 +62,8 @@ pass */ -#define Py_LIMITED_API 0x030b0000 +// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +#define Py_LIMITED_API 0x030c0000 #include "Python.h" #include diff --git a/Modules/xxlimited_35.c b/Modules/xxlimited_35.c index 1ff3ef1cb6f296..361c7e76d77f50 100644 --- a/Modules/xxlimited_35.c +++ b/Modules/xxlimited_35.c @@ -293,7 +293,6 @@ xx_modexec(PyObject *m) static PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_modexec}, - {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; From f1087855e24a01a3c358c520fd3f2fcbc04d1786 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Nov 2023 19:23:39 +0100 Subject: [PATCH 1130/1206] [3.12] gh-111495: Add tests for PyBytes and PyByteArray C API (GH-111496) (GH-111607) (cherry picked from commit 97b3cd38d105fd891ba46dd27d08f03d1c6dd348) Co-authored-by: Serhiy Storchaka --- Lib/test/test_capi/test_bytearray.py | 162 ++++++++++++++++++ Lib/test/test_capi/test_bytes.py | 216 ++++++++++++++++++++++++ Lib/test/test_capi/test_unicode.py | 4 +- Modules/_testcapi/bytearray.c | 107 ++++++++++++ Modules/_testcapi/bytes.c | 239 +++++++++++++++++++++++++++ 5 files changed, 727 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_capi/test_bytearray.py create mode 100644 Lib/test/test_capi/test_bytes.py diff --git a/Lib/test/test_capi/test_bytearray.py b/Lib/test/test_capi/test_bytearray.py new file mode 100644 index 00000000000000..6a0f313a62e0d6 --- /dev/null +++ b/Lib/test/test_capi/test_bytearray.py @@ -0,0 +1,162 @@ +import unittest +import sys +from test.support import import_helper + +_testcapi = import_helper.import_module('_testcapi') + +NULL = None + +class ByteArraySubclass(bytearray): + pass + +class BytesLike: + def __init__(self, value): + self.value = value + def __bytes__(self): + return self.value + + +class CAPITest(unittest.TestCase): + def test_check(self): + # Test PyByteArray_Check() + check = _testcapi.bytearray_check + self.assertTrue(check(bytearray(b'abc'))) + self.assertFalse(check(b'abc')) + self.assertTrue(check(ByteArraySubclass(b'abc'))) + self.assertFalse(check(BytesLike(b'abc'))) + self.assertFalse(check(3)) + self.assertFalse(check([])) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_checkexact(self): + # Test PyByteArray_CheckExact() + check = _testcapi.bytearray_checkexact + self.assertTrue(check(bytearray(b'abc'))) + self.assertFalse(check(b'abc')) + self.assertFalse(check(ByteArraySubclass(b'abc'))) + self.assertFalse(check(BytesLike(b'abc'))) + self.assertFalse(check(3)) + self.assertFalse(check([])) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_fromstringandsize(self): + # Test PyByteArray_FromStringAndSize() + fromstringandsize = _testcapi.bytearray_fromstringandsize + + self.assertEqual(fromstringandsize(b'abc'), bytearray(b'abc')) + self.assertEqual(fromstringandsize(b'abc', 2), bytearray(b'ab')) + self.assertEqual(fromstringandsize(b'abc\0def'), bytearray(b'abc\0def')) + self.assertEqual(fromstringandsize(b'', 0), bytearray()) + self.assertEqual(fromstringandsize(NULL, 0), bytearray()) + self.assertEqual(len(fromstringandsize(NULL, 3)), 3) + self.assertRaises(MemoryError, fromstringandsize, NULL, sys.maxsize) + + self.assertRaises(SystemError, fromstringandsize, b'abc', -1) + self.assertRaises(SystemError, fromstringandsize, NULL, -1) + + def test_fromobject(self): + # Test PyByteArray_FromObject() + fromobject = _testcapi.bytearray_fromobject + + self.assertEqual(fromobject(b'abc'), bytearray(b'abc')) + self.assertEqual(fromobject(bytearray(b'abc')), bytearray(b'abc')) + self.assertEqual(fromobject(ByteArraySubclass(b'abc')), bytearray(b'abc')) + self.assertEqual(fromobject([97, 98, 99]), bytearray(b'abc')) + self.assertEqual(fromobject(3), bytearray(b'\0\0\0')) + self.assertRaises(TypeError, fromobject, BytesLike(b'abc')) + self.assertRaises(TypeError, fromobject, 'abc') + self.assertRaises(TypeError, fromobject, object()) + + # CRASHES fromobject(NULL) + + def test_size(self): + # Test PyByteArray_Size() + size = _testcapi.bytearray_size + + self.assertEqual(size(bytearray(b'abc')), 3) + self.assertEqual(size(ByteArraySubclass(b'abc')), 3) + + # CRASHES size(b'abc') + # CRASHES size(object()) + # CRASHES size(NULL) + + def test_asstring(self): + """Test PyByteArray_AsString()""" + asstring = _testcapi.bytearray_asstring + + self.assertEqual(asstring(bytearray(b'abc'), 4), b'abc\0') + self.assertEqual(asstring(ByteArraySubclass(b'abc'), 4), b'abc\0') + self.assertEqual(asstring(bytearray(b'abc\0def'), 8), b'abc\0def\0') + + # CRASHES asstring(b'abc', 0) + # CRASHES asstring(object()', 0) + # CRASHES asstring(NULL, 0) + + def test_concat(self): + """Test PyByteArray_Concat()""" + concat = _testcapi.bytearray_concat + + ba = bytearray(b'abc') + self.assertEqual(concat(ba, b'def'), bytearray(b'abcdef')) + self.assertEqual(ba, b'abc') + + self.assertEqual(concat(b'abc', b'def'), bytearray(b'abcdef')) + self.assertEqual(concat(b'a\0b', b'c\0d'), bytearray(b'a\0bc\0d')) + self.assertEqual(concat(bytearray(b'abc'), b'def'), bytearray(b'abcdef')) + self.assertEqual(concat(b'abc', bytearray(b'def')), bytearray(b'abcdef')) + self.assertEqual(concat(bytearray(b'abc'), b''), bytearray(b'abc')) + self.assertEqual(concat(b'', bytearray(b'def')), bytearray(b'def')) + self.assertEqual(concat(memoryview(b'xabcy')[1:4], b'def'), + bytearray(b'abcdef')) + self.assertEqual(concat(b'abc', memoryview(b'xdefy')[1:4]), + bytearray(b'abcdef')) + + self.assertRaises(TypeError, concat, memoryview(b'axbycz')[::2], b'def') + self.assertRaises(TypeError, concat, b'abc', memoryview(b'dxeyfz')[::2]) + self.assertRaises(TypeError, concat, b'abc', 'def') + self.assertRaises(TypeError, concat, 'abc', b'def') + self.assertRaises(TypeError, concat, 'abc', 'def') + self.assertRaises(TypeError, concat, [], b'def') + self.assertRaises(TypeError, concat, b'abc', []) + self.assertRaises(TypeError, concat, [], []) + + # CRASHES concat(NULL, bytearray(b'def')) + # CRASHES concat(bytearray(b'abc'), NULL) + # CRASHES concat(NULL, object()) + # CRASHES concat(object(), NULL) + + def test_resize(self): + """Test PyByteArray_Resize()""" + resize = _testcapi.bytearray_resize + + ba = bytearray(b'abcdef') + self.assertEqual(resize(ba, 3), 0) + self.assertEqual(ba, bytearray(b'abc')) + self.assertEqual(resize(ba, 10), 0) + self.assertEqual(len(ba), 10) + self.assertEqual(ba[:3], bytearray(b'abc')) + self.assertEqual(resize(ba, 2**20), 0) + self.assertEqual(len(ba), 2**20) + self.assertEqual(ba[:3], bytearray(b'abc')) + self.assertEqual(resize(ba, 0), 0) + self.assertEqual(ba, bytearray()) + + ba = ByteArraySubclass(b'abcdef') + self.assertEqual(resize(ba, 3), 0) + self.assertEqual(ba, bytearray(b'abc')) + + self.assertRaises(MemoryError, resize, bytearray(), sys.maxsize) + self.assertRaises(MemoryError, resize, bytearray(1000), sys.maxsize) + + # CRASHES resize(bytearray(b'abc'), -1) + # CRASHES resize(b'abc', 0) + # CRASHES resize(object(), 0) + # CRASHES resize(NULL, 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py new file mode 100644 index 00000000000000..e366578ee47358 --- /dev/null +++ b/Lib/test/test_capi/test_bytes.py @@ -0,0 +1,216 @@ +import unittest +import sys +from test.support import import_helper + +_testcapi = import_helper.import_module('_testcapi') + +NULL = None + +class BytesSubclass(bytes): + pass + +class BytesLike: + def __init__(self, value): + self.value = value + def __bytes__(self): + return self.value + + +class CAPITest(unittest.TestCase): + def test_check(self): + # Test PyBytes_Check() + check = _testcapi.bytes_check + self.assertTrue(check(b'abc')) + self.assertFalse(check('abc')) + self.assertFalse(check(bytearray(b'abc'))) + self.assertTrue(check(BytesSubclass(b'abc'))) + self.assertFalse(check(BytesLike(b'abc'))) + self.assertFalse(check(3)) + self.assertFalse(check([])) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_checkexact(self): + # Test PyBytes_CheckExact() + check = _testcapi.bytes_checkexact + self.assertTrue(check(b'abc')) + self.assertFalse(check('abc')) + self.assertFalse(check(bytearray(b'abc'))) + self.assertFalse(check(BytesSubclass(b'abc'))) + self.assertFalse(check(BytesLike(b'abc'))) + self.assertFalse(check(3)) + self.assertFalse(check([])) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_fromstringandsize(self): + # Test PyBytes_FromStringAndSize() + fromstringandsize = _testcapi.bytes_fromstringandsize + + self.assertEqual(fromstringandsize(b'abc'), b'abc') + self.assertEqual(fromstringandsize(b'abc', 2), b'ab') + self.assertEqual(fromstringandsize(b'abc\0def'), b'abc\0def') + self.assertEqual(fromstringandsize(b'', 0), b'') + self.assertEqual(fromstringandsize(NULL, 0), b'') + self.assertEqual(len(fromstringandsize(NULL, 3)), 3) + self.assertRaises((MemoryError, OverflowError), fromstringandsize, NULL, sys.maxsize) + + self.assertRaises(SystemError, fromstringandsize, b'abc', -1) + self.assertRaises(SystemError, fromstringandsize, NULL, -1) + + def test_fromstring(self): + # Test PyBytes_FromString() + fromstring = _testcapi.bytes_fromstring + + self.assertEqual(fromstring(b'abc\0def'), b'abc') + self.assertEqual(fromstring(b''), b'') + + # CRASHES fromstring(NULL) + + def test_fromobject(self): + # Test PyBytes_FromObject() + fromobject = _testcapi.bytes_fromobject + + self.assertEqual(fromobject(b'abc'), b'abc') + self.assertEqual(fromobject(bytearray(b'abc')), b'abc') + self.assertEqual(fromobject(BytesSubclass(b'abc')), b'abc') + self.assertEqual(fromobject([97, 98, 99]), b'abc') + self.assertRaises(TypeError, fromobject, 3) + self.assertRaises(TypeError, fromobject, BytesLike(b'abc')) + self.assertRaises(TypeError, fromobject, 'abc') + self.assertRaises(TypeError, fromobject, object()) + self.assertRaises(SystemError, fromobject, NULL) + + def test_size(self): + # Test PyBytes_Size() + size = _testcapi.bytes_size + + self.assertEqual(size(b'abc'), 3) + self.assertEqual(size(BytesSubclass(b'abc')), 3) + self.assertRaises(TypeError, size, bytearray(b'abc')) + self.assertRaises(TypeError, size, 'abc') + self.assertRaises(TypeError, size, object()) + + # CRASHES size(NULL) + + def test_asstring(self): + """Test PyBytes_AsString()""" + asstring = _testcapi.bytes_asstring + + self.assertEqual(asstring(b'abc', 4), b'abc\0') + self.assertEqual(asstring(b'abc\0def', 8), b'abc\0def\0') + self.assertRaises(TypeError, asstring, 'abc', 0) + self.assertRaises(TypeError, asstring, object(), 0) + + # CRASHES asstring(NULL, 0) + + def test_asstringandsize(self): + """Test PyBytes_AsStringAndSize()""" + asstringandsize = _testcapi.bytes_asstringandsize + asstringandsize_null = _testcapi.bytes_asstringandsize_null + + self.assertEqual(asstringandsize(b'abc', 4), (b'abc\0', 3)) + self.assertEqual(asstringandsize(b'abc\0def', 8), (b'abc\0def\0', 7)) + self.assertEqual(asstringandsize_null(b'abc', 4), b'abc\0') + self.assertRaises(ValueError, asstringandsize_null, b'abc\0def', 8) + self.assertRaises(TypeError, asstringandsize, 'abc', 0) + self.assertRaises(TypeError, asstringandsize_null, 'abc', 0) + self.assertRaises(TypeError, asstringandsize, object(), 0) + self.assertRaises(TypeError, asstringandsize_null, object(), 0) + + # CRASHES asstringandsize(NULL, 0) + # CRASHES asstringandsize_null(NULL, 0) + + def test_repr(self): + # Test PyBytes_Repr() + bytes_repr = _testcapi.bytes_repr + + self.assertEqual(bytes_repr(b'''abc''', 0), r"""b'abc'""") + self.assertEqual(bytes_repr(b'''abc''', 1), r"""b'abc'""") + self.assertEqual(bytes_repr(b'''a'b"c"d''', 0), r"""b'a\'b"c"d'""") + self.assertEqual(bytes_repr(b'''a'b"c"d''', 1), r"""b'a\'b"c"d'""") + self.assertEqual(bytes_repr(b'''a'b"c''', 0), r"""b'a\'b"c'""") + self.assertEqual(bytes_repr(b'''a'b"c''', 1), r"""b'a\'b"c'""") + self.assertEqual(bytes_repr(b'''a'b'c"d''', 0), r"""b'a\'b\'c"d'""") + self.assertEqual(bytes_repr(b'''a'b'c"d''', 1), r"""b'a\'b\'c"d'""") + self.assertEqual(bytes_repr(b'''a'b'c'd''', 0), r"""b'a\'b\'c\'d'""") + self.assertEqual(bytes_repr(b'''a'b'c'd''', 1), r'''b"a'b'c'd"''') + + self.assertEqual(bytes_repr(BytesSubclass(b'abc'), 0), r"""b'abc'""") + + # UDEFINED bytes_repr(object(), 0) + # CRASHES bytes_repr(NULL, 0) + + def test_concat(self, concat=None): + """Test PyBytes_Concat()""" + if concat is None: + concat = _testcapi.bytes_concat + + self.assertEqual(concat(b'abc', b'def'), b'abcdef') + self.assertEqual(concat(b'a\0b', b'c\0d'), b'a\0bc\0d') + self.assertEqual(concat(bytearray(b'abc'), b'def'), b'abcdef') + self.assertEqual(concat(b'abc', bytearray(b'def')), b'abcdef') + self.assertEqual(concat(bytearray(b'abc'), b''), b'abc') + self.assertEqual(concat(b'', bytearray(b'def')), b'def') + self.assertEqual(concat(memoryview(b'xabcy')[1:4], b'def'), b'abcdef') + self.assertEqual(concat(b'abc', memoryview(b'xdefy')[1:4]), b'abcdef') + + self.assertEqual(concat(b'abc', b'def', True), b'abcdef') + self.assertEqual(concat(b'abc', bytearray(b'def'), True), b'abcdef') + # Check that it does not change the singleton + self.assertEqual(concat(bytes(), b'def', True), b'def') + self.assertEqual(len(bytes()), 0) + + self.assertRaises(TypeError, concat, memoryview(b'axbycz')[::2], b'def') + self.assertRaises(TypeError, concat, b'abc', memoryview(b'dxeyfz')[::2]) + self.assertRaises(TypeError, concat, b'abc', 'def') + self.assertRaises(TypeError, concat, 'abc', b'def') + self.assertRaises(TypeError, concat, 'abc', 'def') + self.assertRaises(TypeError, concat, [], b'def') + self.assertRaises(TypeError, concat, b'abc', []) + self.assertRaises(TypeError, concat, [], []) + + self.assertEqual(concat(NULL, b'def'), NULL) + self.assertEqual(concat(b'abc', NULL), NULL) + self.assertEqual(concat(NULL, object()), NULL) + self.assertEqual(concat(object(), NULL), NULL) + + def test_concatanddel(self): + """Test PyBytes_ConcatAndDel()""" + self.test_concat(_testcapi.bytes_concatanddel) + + def test_decodeescape(self): + """Test PyBytes_DecodeEscape()""" + decodeescape = _testcapi.bytes_decodeescape + + self.assertEqual(decodeescape(b'abc'), b'abc') + self.assertEqual(decodeescape(br'\t\n\r\x0b\x0c\x00\\\'\"'), + b'''\t\n\r\v\f\0\\'"''') + self.assertEqual(decodeescape(b'\t\n\r\x0b\x0c\x00'), b'\t\n\r\v\f\0') + self.assertEqual(decodeescape(br'\xa1\xa2'), b'\xa1\xa2') + self.assertEqual(decodeescape(br'\2\24\241'), b'\x02\x14\xa1') + self.assertEqual(decodeescape(b'\xa1\xa2'), b'\xa1\xa2') + with self.assertWarns(DeprecationWarning): + self.assertEqual(decodeescape(br'\u4f60'), br'\u4f60') + with self.assertWarns(DeprecationWarning): + self.assertEqual(decodeescape(br'\z'), br'\z') + with self.assertWarns(DeprecationWarning): + self.assertEqual(decodeescape(br'\541'), b'a') + + for b in b'\\', br'\x', br'\xa', br'\xz', br'\xaz': + self.assertRaises(ValueError, decodeescape, b) + self.assertRaises(ValueError, decodeescape, b, 'strict') + self.assertEqual(decodeescape(br'x\xa', 'replace'), b'x?') + self.assertEqual(decodeescape(br'x\xay', 'replace'), b'x?y') + self.assertEqual(decodeescape(br'x\xa\xy', 'replace'), b'x??y') + self.assertEqual(decodeescape(br'x\xa\xy', 'ignore'), b'xy') + self.assertRaises(ValueError, decodeescape, b'\\', 'spam') + self.assertEqual(decodeescape(NULL), b'') + + # CRASHES decodeescape(NULL, NULL, 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 40ce9afc566477..35a90b6ce082d7 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -193,7 +193,9 @@ def test_fromstringandsize(self): self.assertEqual(fromstringandsize(NULL, 0), '') self.assertRaises(SystemError, fromstringandsize, b'abc', -1) - # TODO: Test PyUnicode_FromStringAndSize(NULL, size) for size != 0 + self.assertRaises(SystemError, fromstringandsize, NULL, -1) + self.assertRaises(SystemError, fromstringandsize, NULL, 3) + self.assertRaises(SystemError, fromstringandsize, NULL, sys.maxsize) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') diff --git a/Modules/_testcapi/bytearray.c b/Modules/_testcapi/bytearray.c index 6ddb8fe1d5f6b5..7ce065aa4fa3dd 100644 --- a/Modules/_testcapi/bytearray.c +++ b/Modules/_testcapi/bytearray.c @@ -1,8 +1,115 @@ +#define PY_SSIZE_T_CLEAN #include "parts.h" #include "util.h" +/* Test PyByteArray_Check() */ +static PyObject * +bytearray_check(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyByteArray_Check(obj)); +} + +/* Test PyByteArray_CheckExact() */ +static PyObject * +bytearray_checkexact(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyByteArray_CheckExact(obj)); +} + +/* Test PyByteArray_FromStringAndSize() */ +static PyObject * +bytearray_fromstringandsize(PyObject *Py_UNUSED(module), PyObject *args) +{ + const char *s; + Py_ssize_t bsize; + Py_ssize_t size = -100; + + if (!PyArg_ParseTuple(args, "z#|n", &s, &bsize, &size)) { + return NULL; + } + + if (size == -100) { + size = bsize; + } + return PyByteArray_FromStringAndSize(s, size); +} + +/* Test PyByteArray_FromObject() */ +static PyObject * +bytearray_fromobject(PyObject *Py_UNUSED(module), PyObject *arg) +{ + NULLABLE(arg); + return PyByteArray_FromObject(arg); +} + +/* Test PyByteArray_Size() */ +static PyObject * +bytearray_size(PyObject *Py_UNUSED(module), PyObject *arg) +{ + NULLABLE(arg); + RETURN_SIZE(PyByteArray_Size(arg)); +} + +/* Test PyUnicode_AsString() */ +static PyObject * +bytearray_asstring(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t buflen; + const char *s; + + if (!PyArg_ParseTuple(args, "On", &obj, &buflen)) + return NULL; + + NULLABLE(obj); + s = PyByteArray_AsString(obj); + if (s == NULL) + return NULL; + + return PyByteArray_FromStringAndSize(s, buflen); +} + +/* Test PyByteArray_Concat() */ +static PyObject * +bytearray_concat(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *left, *right; + + if (!PyArg_ParseTuple(args, "OO", &left, &right)) + return NULL; + + NULLABLE(left); + NULLABLE(right); + return PyByteArray_Concat(left, right); +} + +/* Test PyByteArray_Resize() */ +static PyObject * +bytearray_resize(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "On", &obj, &size)) + return NULL; + + NULLABLE(obj); + RETURN_INT(PyByteArray_Resize(obj, size)); +} + + static PyMethodDef test_methods[] = { + {"bytearray_check", bytearray_check, METH_O}, + {"bytearray_checkexact", bytearray_checkexact, METH_O}, + {"bytearray_fromstringandsize", bytearray_fromstringandsize, METH_VARARGS}, + {"bytearray_fromobject", bytearray_fromobject, METH_O}, + {"bytearray_size", bytearray_size, METH_O}, + {"bytearray_asstring", bytearray_asstring, METH_VARARGS}, + {"bytearray_concat", bytearray_concat, METH_VARARGS}, + {"bytearray_resize", bytearray_resize, METH_VARARGS}, {NULL}, }; diff --git a/Modules/_testcapi/bytes.c b/Modules/_testcapi/bytes.c index 9fea716bfbcfd1..84a6cb88e4bdda 100644 --- a/Modules/_testcapi/bytes.c +++ b/Modules/_testcapi/bytes.c @@ -1,8 +1,247 @@ +#define PY_SSIZE_T_CLEAN #include "parts.h" #include "util.h" +/* Test PyBytes_Check() */ +static PyObject * +bytes_check(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyBytes_Check(obj)); +} + +/* Test PyBytes_CheckExact() */ +static PyObject * +bytes_checkexact(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyBytes_CheckExact(obj)); +} + +/* Test PyBytes_FromStringAndSize() */ +static PyObject * +bytes_fromstringandsize(PyObject *Py_UNUSED(module), PyObject *args) +{ + const char *s; + Py_ssize_t bsize; + Py_ssize_t size = -100; + + if (!PyArg_ParseTuple(args, "z#|n", &s, &bsize, &size)) { + return NULL; + } + + if (size == -100) { + size = bsize; + } + return PyBytes_FromStringAndSize(s, size); +} + +/* Test PyBytes_FromString() */ +static PyObject * +bytes_fromstring(PyObject *Py_UNUSED(module), PyObject *arg) +{ + const char *s; + Py_ssize_t size; + + if (!PyArg_Parse(arg, "z#", &s, &size)) { + return NULL; + } + return PyBytes_FromString(s); +} + +/* Test PyBytes_FromObject() */ +static PyObject * +bytes_fromobject(PyObject *Py_UNUSED(module), PyObject *arg) +{ + NULLABLE(arg); + return PyBytes_FromObject(arg); +} + +/* Test PyBytes_Size() */ +static PyObject * +bytes_size(PyObject *Py_UNUSED(module), PyObject *arg) +{ + NULLABLE(arg); + RETURN_SIZE(PyBytes_Size(arg)); +} + +/* Test PyUnicode_AsString() */ +static PyObject * +bytes_asstring(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t buflen; + const char *s; + + if (!PyArg_ParseTuple(args, "On", &obj, &buflen)) + return NULL; + + NULLABLE(obj); + s = PyBytes_AsString(obj); + if (s == NULL) + return NULL; + + return PyBytes_FromStringAndSize(s, buflen); +} + +/* Test PyBytes_AsStringAndSize() */ +static PyObject * +bytes_asstringandsize(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t buflen; + char *s = UNINITIALIZED_PTR; + Py_ssize_t size = UNINITIALIZED_SIZE; + + if (!PyArg_ParseTuple(args, "On", &obj, &buflen)) + return NULL; + + NULLABLE(obj); + if (PyBytes_AsStringAndSize(obj, &s, &size) < 0) { + return NULL; + } + + if (s == NULL) { + return Py_BuildValue("(On)", Py_None, size); + } + else { + return Py_BuildValue("(y#n)", s, buflen, size); + } +} + +static PyObject * +bytes_asstringandsize_null(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t buflen; + char *s = UNINITIALIZED_PTR; + + if (!PyArg_ParseTuple(args, "On", &obj, &buflen)) + return NULL; + + NULLABLE(obj); + if (PyBytes_AsStringAndSize(obj, &s, NULL) < 0) { + return NULL; + } + + if (s == NULL) { + Py_RETURN_NONE; + } + else { + return PyBytes_FromStringAndSize(s, buflen); + } +} + +/* Test PyBytes_Repr() */ +static PyObject * +bytes_repr(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + int smartquotes; + if (!PyArg_ParseTuple(args, "Oi", &obj, &smartquotes)) + return NULL; + + NULLABLE(obj); + return PyBytes_Repr(obj, smartquotes); +} + +/* Test PyBytes_Concat() */ +static PyObject * +bytes_concat(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *left, *right; + int new = 0; + + if (!PyArg_ParseTuple(args, "OO|p", &left, &right, &new)) + return NULL; + + NULLABLE(left); + NULLABLE(right); + if (new) { + assert(left != NULL); + assert(PyBytes_CheckExact(left)); + left = PyBytes_FromStringAndSize(PyBytes_AS_STRING(left), + PyBytes_GET_SIZE(left)); + if (left == NULL) { + return NULL; + } + } + else { + Py_XINCREF(left); + } + PyBytes_Concat(&left, right); + if (left == NULL && !PyErr_Occurred()) { + Py_RETURN_NONE; + } + return left; +} + +/* Test PyBytes_ConcatAndDel() */ +static PyObject * +bytes_concatanddel(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *left, *right; + int new = 0; + + if (!PyArg_ParseTuple(args, "OO|p", &left, &right, &new)) + return NULL; + + NULLABLE(left); + NULLABLE(right); + if (new) { + assert(left != NULL); + assert(PyBytes_CheckExact(left)); + left = PyBytes_FromStringAndSize(PyBytes_AS_STRING(left), + PyBytes_GET_SIZE(left)); + if (left == NULL) { + return NULL; + } + } + else { + Py_XINCREF(left); + } + Py_XINCREF(right); + PyBytes_ConcatAndDel(&left, right); + if (left == NULL && !PyErr_Occurred()) { + Py_RETURN_NONE; + } + return left; +} + +/* Test PyBytes_DecodeEscape() */ +static PyObject * +bytes_decodeescape(PyObject *Py_UNUSED(module), PyObject *args) +{ + const char *s; + Py_ssize_t bsize; + Py_ssize_t size = -100; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "z#|zn", &s, &bsize, &errors, &size)) + return NULL; + + if (size == -100) { + size = bsize; + } + return PyBytes_DecodeEscape(s, size, errors, 0, NULL); +} + + static PyMethodDef test_methods[] = { + {"bytes_check", bytes_check, METH_O}, + {"bytes_checkexact", bytes_checkexact, METH_O}, + {"bytes_fromstringandsize", bytes_fromstringandsize, METH_VARARGS}, + {"bytes_fromstring", bytes_fromstring, METH_O}, + {"bytes_fromobject", bytes_fromobject, METH_O}, + {"bytes_size", bytes_size, METH_O}, + {"bytes_asstring", bytes_asstring, METH_VARARGS}, + {"bytes_asstringandsize", bytes_asstringandsize, METH_VARARGS}, + {"bytes_asstringandsize_null", bytes_asstringandsize_null, METH_VARARGS}, + {"bytes_repr", bytes_repr, METH_VARARGS}, + {"bytes_concat", bytes_concat, METH_VARARGS}, + {"bytes_concatanddel", bytes_concatanddel, METH_VARARGS}, + {"bytes_decodeescape", bytes_decodeescape, METH_VARARGS}, {NULL}, }; From a94bdc245963a0c0a41f201a6a1311549d964945 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Nov 2023 20:58:02 +0100 Subject: [PATCH 1131/1206] [3.12] gh-111295: Fix error checking in time extension module init (GH-111296) (#111300) gh-111295: Fix error checking in time extension module init (GH-111296) Introduce ADD_INT macro wrapper for PyModule_AddIntConstant() (cherry picked from commit 81b03e78101c97c1d3fe5f90908bbf94e83d7df1) Co-authored-by: Nikita Sobolev --- ...-10-25-08-42-05.gh-issue-111295.H2K4lf.rst | 1 + Modules/timemodule.c | 27 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-25-08-42-05.gh-issue-111295.H2K4lf.rst diff --git a/Misc/NEWS.d/next/Library/2023-10-25-08-42-05.gh-issue-111295.H2K4lf.rst b/Misc/NEWS.d/next/Library/2023-10-25-08-42-05.gh-issue-111295.H2K4lf.rst new file mode 100644 index 00000000000000..28b85ec3eadab7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-25-08-42-05.gh-issue-111295.H2K4lf.rst @@ -0,0 +1 @@ +Fix :mod:`time` not checking for errors when initializing. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index f5b0f39e14abc3..3b46deacdf2de2 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1737,6 +1737,12 @@ get_gmtoff(time_t t, struct tm *p) static int init_timezone(PyObject *m) { +#define ADD_INT(NAME, VALUE) do { \ + if (PyModule_AddIntConstant(m, NAME, VALUE) < 0) { \ + return -1; \ + } \ +} while (0) + assert(!PyErr_Occurred()); /* This code moved from PyInit_time wholesale to allow calling it from @@ -1760,13 +1766,13 @@ init_timezone(PyObject *m) #if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) tzset(); #endif - PyModule_AddIntConstant(m, "timezone", _Py_timezone); + ADD_INT("timezone", _Py_timezone); #ifdef HAVE_ALTZONE - PyModule_AddIntConstant(m, "altzone", altzone); + ADD_INT("altzone", altzone); #else - PyModule_AddIntConstant(m, "altzone", _Py_timezone-3600); + ADD_INT("altzone", _Py_timezone-3600); #endif - PyModule_AddIntConstant(m, "daylight", _Py_daylight); + ADD_INT("daylight", _Py_daylight); #ifdef MS_WINDOWS TIME_ZONE_INFORMATION tzinfo = {0}; GetTimeZoneInformation(&tzinfo); @@ -1825,20 +1831,21 @@ init_timezone(PyObject *m) PyObject *tzname_obj; if (janzone < julyzone) { /* DST is reversed in the southern hemisphere */ - PyModule_AddIntConstant(m, "timezone", julyzone); - PyModule_AddIntConstant(m, "altzone", janzone); - PyModule_AddIntConstant(m, "daylight", janzone != julyzone); + ADD_INT("timezone", julyzone); + ADD_INT("altzone", janzone); + ADD_INT("daylight", janzone != julyzone); tzname_obj = Py_BuildValue("(zz)", julyname, janname); } else { - PyModule_AddIntConstant(m, "timezone", janzone); - PyModule_AddIntConstant(m, "altzone", julyzone); - PyModule_AddIntConstant(m, "daylight", janzone != julyzone); + ADD_INT("timezone", janzone); + ADD_INT("altzone", julyzone); + ADD_INT("daylight", janzone != julyzone); tzname_obj = Py_BuildValue("(zz)", janname, julyname); } if (_PyModule_Add(m, "tzname", tzname_obj) < 0) { return -1; } #endif // !HAVE_DECL_TZNAME +#undef ADD_INT if (PyErr_Occurred()) { return -1; From 99f0dd88b1ef8309a4e2a23a51bb47e18e1d81f3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 1 Nov 2023 21:01:28 +0100 Subject: [PATCH 1132/1206] [3.12] gh-111253: Fix error checking in _socket module init (GH-111254) (#111299) gh-111253: Fix error checking in _socket module init (GH-111254) (cherry picked from commit 3052c098ca2779c2d9ab9800dabe66d0efa01794) Co-authored-by: Nikita Sobolev --- .../Library/2023-10-24-12-20-46.gh-issue-111253.HFywSK.rst | 1 + Modules/socketmodule.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-24-12-20-46.gh-issue-111253.HFywSK.rst diff --git a/Misc/NEWS.d/next/Library/2023-10-24-12-20-46.gh-issue-111253.HFywSK.rst b/Misc/NEWS.d/next/Library/2023-10-24-12-20-46.gh-issue-111253.HFywSK.rst new file mode 100644 index 00000000000000..e21a42605aeaf6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-24-12-20-46.gh-issue-111253.HFywSK.rst @@ -0,0 +1 @@ +Add error checking during :mod:`!_socket` module init. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 62b0e67be15c49..de7229d2ced2f5 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -7703,10 +7703,10 @@ socket_exec(PyObject *m) /* FreeBSD divert(4) */ #ifdef PF_DIVERT - PyModule_AddIntMacro(m, PF_DIVERT); + ADD_INT_MACRO(m, PF_DIVERT); #endif #ifdef AF_DIVERT - PyModule_AddIntMacro(m, AF_DIVERT); + ADD_INT_MACRO(m, AF_DIVERT); #endif #ifdef AF_PACKET From 9aa88290d82e2808eed84e7a63d0bf9623f84f53 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Thu, 2 Nov 2023 13:48:49 +0530 Subject: [PATCH 1133/1206] [3.12] GH-110894: Call loop exception handler for exceptions in client_connected_cb (GH-111601) (#111632) Call loop exception handler for exceptions in `client_connected_cb` of `asyncio.start_server` so that applications can handle it.. (cherry picked from commit 229f44d353c71185414a072017f46f125676bdd6) --- Lib/asyncio/streams.py | 12 ++++++++ Lib/test/test_asyncio/test_streams.py | 29 +++++++++++++++++++ ...-11-01-14-03-24.gh-issue-110894.7-wZxC.rst | 1 + 3 files changed, 42 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-11-01-14-03-24.gh-issue-110894.7-wZxC.rst diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index aff081a1e0d02c..f63eeca2a7719a 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -244,7 +244,19 @@ def connection_made(self, transport): res = self._client_connected_cb(reader, self._stream_writer) if coroutines.iscoroutine(res): + def callback(task): + exc = task.exception() + if exc is not None: + self._loop.call_exception_handler({ + 'message': 'Unhandled exception in client_connected_cb', + 'exception': exc, + 'transport': transport, + }) + transport.close() + self._task = self._loop.create_task(res) + self._task.add_done_callback(callback) + self._strong_reader = None def connection_lost(self, exc): diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 7f9dc621808358..a0ed5ab7986768 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -1074,6 +1074,35 @@ def test_eof_feed_when_closing_writer(self): self.assertEqual(messages, []) + def test_unhandled_exceptions(self) -> None: + port = socket_helper.find_unused_port() + + messages = [] + self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) + + async def client(): + rd, wr = await asyncio.open_connection('localhost', port) + wr.write(b'test msg') + await wr.drain() + wr.close() + await wr.wait_closed() + + async def main(): + async def handle_echo(reader, writer): + raise Exception('test') + + server = await asyncio.start_server( + handle_echo, 'localhost', port) + await server.start_serving() + await client() + server.close() + await server.wait_closed() + + self.loop.run_until_complete(main()) + + self.assertEqual(messages[0]['message'], + 'Unhandled exception in client_connected_cb') + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-11-01-14-03-24.gh-issue-110894.7-wZxC.rst b/Misc/NEWS.d/next/Library/2023-11-01-14-03-24.gh-issue-110894.7-wZxC.rst new file mode 100644 index 00000000000000..c59fe6b9119eca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-01-14-03-24.gh-issue-110894.7-wZxC.rst @@ -0,0 +1 @@ +Call loop exception handler for exceptions in ``client_connected_cb`` of :func:`asyncio.start_server` so that applications can handle it. Patch by Kumar Aditya. From fcf91cd35fa10fcaef46fa13be79104add7f5ae7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:04:27 +0100 Subject: [PATCH 1134/1206] [3.12] gh-111625: Fix link to Info-ZIP homepage (GH-111626) (#111639) Co-authored-by: partev --- Doc/tools/templates/download.html | 4 ++-- Lib/test/ziptestdata/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/tools/templates/download.html b/Doc/tools/templates/download.html index 7920e0619f9337..b5353d6fb77ab4 100644 --- a/Doc/tools/templates/download.html +++ b/Doc/tools/templates/download.html @@ -49,12 +49,12 @@

Unpacking

Windows users can use the ZIP archives since those are customary on that -platform. These are created on Unix using the InfoZIP zip program.

+platform. These are created on Unix using the Info-ZIP zip program.

Problems

diff --git a/Lib/test/ziptestdata/README.md b/Lib/test/ziptestdata/README.md index 6b9147db76e178..00d96d445bf543 100644 --- a/Lib/test/ziptestdata/README.md +++ b/Lib/test/ziptestdata/README.md @@ -1,7 +1,7 @@ # Test data for `test_zipfile` The test executables in this directory are created manually from header.sh and -the `testdata_module_inside_zip.py` file. You must have infozip's zip utility +the `testdata_module_inside_zip.py` file. You must have Info-ZIP's zip utility installed (`apt install zip` on Debian). ## Purpose @@ -25,7 +25,7 @@ rm zip2.zip ### Modern format (4.5) zip64 file -Redirecting from stdin forces infozip's zip tool to create a zip64. +Redirecting from stdin forces Info-ZIP's zip tool to create a zip64. ``` zip -0 zip64.zip From 1c84a48032e22f8ce41c6a8f8fe25d3b0e1d6e48 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 2 Nov 2023 23:58:20 +0100 Subject: [PATCH 1135/1206] [3.12] Fix typo in documentation of `SysLogHandler.createSocket` (GH-111665) (#111669) (cherry picked from commit 489b80640ff9c4f10b25da6d562b06c62a10a76b) --- Doc/library/logging.handlers.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 2a825db54aed5c..2dd4bd081b0429 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -656,9 +656,7 @@ supports sending logging messages to a remote or local Unix syslog. to the other end. This method is called during handler initialization, but it's not regarded as an error if the other end isn't listening at this point - the method will be called again when emitting an event, if - but it's not regarded as an error if the other end isn't listening yet - --- the method will be called again when emitting an event, - if there is no socket at that point. + there is no socket at that point. .. versionadded:: 3.11 From 4db71c3ca7ba6c290ebdf54452ff0ccca0a174af Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 3 Nov 2023 07:28:55 +0100 Subject: [PATCH 1136/1206] [3.12] gh-54434: Make difflib.rst doctests pass. (GH-111677) (#111678) gh-54434: Make difflib.rst doctests pass. (GH-111677) (cherry picked from commit 0d3df272fbd131bff7f02d4d4279ad1e35081121) Co-authored-by: Terry Jan Reedy --- Doc/library/difflib.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst index c553611401d018..9abf19557f989c 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -171,9 +171,12 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. expressed in the ISO 8601 format. If not specified, the strings default to blanks. + >>> import sys + >>> from difflib import * >>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n'] >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n'] - >>> sys.stdout.writelines(context_diff(s1, s2, fromfile='before.py', tofile='after.py')) + >>> sys.stdout.writelines(context_diff(s1, s2, fromfile='before.py', + ... tofile='after.py')) *** before.py --- after.py *************** @@ -294,13 +297,12 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module. For inputs that do not have trailing newlines, set the *lineterm* argument to ``""`` so that the output will be uniformly newline free. - The context diff format normally has a header for filenames and modification + The unified diff format normally has a header for filenames and modification times. Any or all of these may be specified using strings for *fromfile*, *tofile*, *fromfiledate*, and *tofiledate*. The modification times are normally expressed in the ISO 8601 format. If not specified, the strings default to blanks. - >>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n'] >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n'] >>> sys.stdout.writelines(unified_diff(s1, s2, fromfile='before.py', tofile='after.py')) From 1a95ad68b4156fbd04bd5c479f3ef9ca30f0a8f5 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 3 Nov 2023 07:02:07 -0700 Subject: [PATCH 1137/1206] [3.12] gh-111654: remove redundant decref in LOAD_FROM_DICT_OR_DEREF (GH-111655) (#111674) (cherry picked from commit 3a1b09e6d070778d78d81084f88d37377d38ee9b) Co-authored-by: AN Long --- Lib/test/test_exceptions.py | 7 + ...-11-03-01-04-55.gh-issue-111654.scUhDO.rst | 2 + Python/bytecodes.c | 4 +- Python/generated_cases.c.h | 554 +++++++++--------- 4 files changed, 286 insertions(+), 281 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-11-03-01-04-55.gh-issue-111654.scUhDO.rst diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 304901515992e8..ad0b7c2154c020 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1824,6 +1824,13 @@ def f(): self.assertIn("nonsense", err.getvalue()) self.assertIn("ZeroDivisionError", err.getvalue()) + def test_gh_111654(self): + def f(): + class TestClass: + TestClass + + self.assertRaises(NameError, f) + # Note: name suggestion tests live in `test_traceback`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-11-03-01-04-55.gh-issue-111654.scUhDO.rst b/Misc/NEWS.d/next/Core and Builtins/2023-11-03-01-04-55.gh-issue-111654.scUhDO.rst new file mode 100644 index 00000000000000..e9a896e660916f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-11-03-01-04-55.gh-issue-111654.scUhDO.rst @@ -0,0 +1,2 @@ +Fix runtime crash when some error happens in opcode +``LOAD_FROM_DICT_OR_DEREF``. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e20b9ff1b3ef5e..b957d8895ba9b4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1425,7 +1425,6 @@ dummy_func( Py_INCREF(value); } else if (_PyErr_Occurred(tstate)) { - Py_DECREF(class_dict); goto error; } } @@ -1433,13 +1432,11 @@ dummy_func( value = PyObject_GetItem(class_dict, name); if (value == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(class_dict); goto error; } _PyErr_Clear(tstate); } } - Py_DECREF(class_dict); if (!value) { PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); @@ -1449,6 +1446,7 @@ dummy_func( } Py_INCREF(value); } + Py_DECREF(class_dict); } inst(LOAD_DEREF, ( -- value)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 5ebfe0e455116f..ea17c0410bc588 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1939,7 +1939,6 @@ Py_INCREF(value); } else if (_PyErr_Occurred(tstate)) { - Py_DECREF(class_dict); goto error; } } @@ -1947,13 +1946,11 @@ value = PyObject_GetItem(class_dict, name); if (value == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(class_dict); goto error; } _PyErr_Clear(tstate); } } - Py_DECREF(class_dict); if (!value) { PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); @@ -1963,14 +1960,15 @@ } Py_INCREF(value); } - #line 1967 "Python/generated_cases.c.h" + Py_DECREF(class_dict); + #line 1965 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1455 "Python/bytecodes.c" + #line 1453 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1978,7 +1976,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1982 "Python/generated_cases.c.h" + #line 1980 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1986,18 +1984,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1465 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1995 "Python/generated_cases.c.h" + #line 1993 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1472 "Python/bytecodes.c" + #line 1470 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -2008,22 +2006,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2012 "Python/generated_cases.c.h" + #line 2010 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1485 "Python/bytecodes.c" + #line 1483 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2021 "Python/generated_cases.c.h" + #line 2019 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1487 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2027 "Python/generated_cases.c.h" + #line 2025 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2033,10 +2031,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1491 "Python/bytecodes.c" + #line 1489 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2040 "Python/generated_cases.c.h" + #line 2038 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2046,10 +2044,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1496 "Python/bytecodes.c" + #line 1494 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2053 "Python/generated_cases.c.h" + #line 2051 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2059,7 +2057,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1501 "Python/bytecodes.c" + #line 1499 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2070,13 +2068,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2074 "Python/generated_cases.c.h" + #line 2072 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1512 "Python/bytecodes.c" + #line 1510 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2080 "Python/generated_cases.c.h" + #line 2078 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2085,13 +2083,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1519 "Python/bytecodes.c" + #line 1517 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2091 "Python/generated_cases.c.h" + #line 2089 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1521 "Python/bytecodes.c" + #line 1519 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2095 "Python/generated_cases.c.h" + #line 2093 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2099,7 +2097,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1525 "Python/bytecodes.c" + #line 1523 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2114,7 +2112,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2118 "Python/generated_cases.c.h" + #line 2116 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2124,18 +2122,18 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1542 "Python/bytecodes.c" + #line 1540 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, oparg); - #line 2133 "Python/generated_cases.c.h" + #line 2131 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1547 "Python/bytecodes.c" + #line 1545 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2139 "Python/generated_cases.c.h" + #line 2137 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2143,7 +2141,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1551 "Python/bytecodes.c" + #line 1549 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2183,7 +2181,7 @@ Py_DECREF(ann_dict); } } - #line 2187 "Python/generated_cases.c.h" + #line 2185 "Python/generated_cases.c.h" DISPATCH(); } @@ -2191,7 +2189,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1593 "Python/bytecodes.c" + #line 1591 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2201,14 +2199,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2205 "Python/generated_cases.c.h" + #line 2203 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1603 "Python/bytecodes.c" + #line 1601 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2212 "Python/generated_cases.c.h" + #line 2210 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2216,7 +2214,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1607 "Python/bytecodes.c" + #line 1605 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2224,12 +2222,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2228 "Python/generated_cases.c.h" + #line 2226 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1615 "Python/bytecodes.c" + #line 1613 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2233 "Python/generated_cases.c.h" + #line 2231 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2237,17 +2235,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1621 "Python/bytecodes.c" + #line 1619 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2246 "Python/generated_cases.c.h" + #line 2244 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1626 "Python/bytecodes.c" + #line 1624 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2251 "Python/generated_cases.c.h" + #line 2249 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2257,26 +2255,26 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1633 "Python/bytecodes.c" + #line 1631 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2267 "Python/generated_cases.c.h" + #line 2265 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1642 "Python/bytecodes.c" + #line 1640 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2280 "Python/generated_cases.c.h" + #line 2278 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2287,7 +2285,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1656 "Python/bytecodes.c" + #line 1654 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2329,16 +2327,16 @@ } } } - #line 2333 "Python/generated_cases.c.h" + #line 2331 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1698 "Python/bytecodes.c" + #line 1696 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2342 "Python/generated_cases.c.h" + #line 2340 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2353,20 +2351,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1705 "Python/bytecodes.c" + #line 1703 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2364 "Python/generated_cases.c.h" + #line 2362 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1712 "Python/bytecodes.c" + #line 1710 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2370 "Python/generated_cases.c.h" + #line 2368 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2381,7 +2379,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1716 "Python/bytecodes.c" + #line 1714 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2404,7 +2402,7 @@ res = res2; res2 = NULL; } - #line 2408 "Python/generated_cases.c.h" + #line 2406 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2418,7 +2416,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1755 "Python/bytecodes.c" + #line 1753 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2452,9 +2450,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2456 "Python/generated_cases.c.h" + #line 2454 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1789 "Python/bytecodes.c" + #line 1787 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2463,12 +2461,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2467 "Python/generated_cases.c.h" + #line 2465 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1798 "Python/bytecodes.c" + #line 1796 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2472 "Python/generated_cases.c.h" + #line 2470 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2482,7 +2480,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1803 "Python/bytecodes.c" + #line 1801 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2495,7 +2493,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2499 "Python/generated_cases.c.h" + #line 2497 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2510,7 +2508,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1819 "Python/bytecodes.c" + #line 1817 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2523,7 +2521,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2527 "Python/generated_cases.c.h" + #line 2525 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2538,7 +2536,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1835 "Python/bytecodes.c" + #line 1833 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2565,7 +2563,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2569 "Python/generated_cases.c.h" + #line 2567 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2580,7 +2578,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1865 "Python/bytecodes.c" + #line 1863 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2590,7 +2588,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2594 "Python/generated_cases.c.h" + #line 2592 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2605,7 +2603,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1878 "Python/bytecodes.c" + #line 1876 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2617,7 +2615,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2621 "Python/generated_cases.c.h" + #line 2619 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2631,7 +2629,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1893 "Python/bytecodes.c" + #line 1891 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2655,7 +2653,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2659 "Python/generated_cases.c.h" + #line 2657 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2663,7 +2661,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1919 "Python/bytecodes.c" + #line 1917 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2689,7 +2687,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2693 "Python/generated_cases.c.h" + #line 2691 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2697,7 +2695,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1947 "Python/bytecodes.c" + #line 1945 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2715,7 +2713,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2719 "Python/generated_cases.c.h" + #line 2717 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2726,7 +2724,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1967 "Python/bytecodes.c" + #line 1965 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2765,7 +2763,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2769 "Python/generated_cases.c.h" + #line 2767 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2776,7 +2774,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2008 "Python/bytecodes.c" + #line 2006 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2786,7 +2784,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2790 "Python/generated_cases.c.h" + #line 2788 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2798,7 +2796,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2027 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2811,12 +2809,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2815 "Python/generated_cases.c.h" + #line 2813 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2040 "Python/bytecodes.c" + #line 2038 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2820 "Python/generated_cases.c.h" + #line 2818 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2827,7 +2825,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2044 "Python/bytecodes.c" + #line 2042 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2838,7 +2836,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2842 "Python/generated_cases.c.h" + #line 2840 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2849,7 +2847,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2058 "Python/bytecodes.c" + #line 2056 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2864,7 +2862,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2868 "Python/generated_cases.c.h" + #line 2866 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2875,7 +2873,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2076 "Python/bytecodes.c" + #line 2074 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2887,7 +2885,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2891 "Python/generated_cases.c.h" + #line 2889 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2898,14 +2896,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2090 "Python/bytecodes.c" + #line 2088 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2904 "Python/generated_cases.c.h" + #line 2902 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2092 "Python/bytecodes.c" + #line 2090 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2909 "Python/generated_cases.c.h" + #line 2907 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2915,15 +2913,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2096 "Python/bytecodes.c" + #line 2094 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2921 "Python/generated_cases.c.h" + #line 2919 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2098 "Python/bytecodes.c" + #line 2096 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2927 "Python/generated_cases.c.h" + #line 2925 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2934,12 +2932,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2103 "Python/bytecodes.c" + #line 2101 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2940 "Python/generated_cases.c.h" + #line 2938 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2105 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2947,10 +2945,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2951 "Python/generated_cases.c.h" + #line 2949 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2113 "Python/bytecodes.c" + #line 2111 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2959,7 +2957,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2963 "Python/generated_cases.c.h" + #line 2961 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2969,21 +2967,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2124 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2976 "Python/generated_cases.c.h" + #line 2974 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2127 "Python/bytecodes.c" + #line 2125 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2983 "Python/generated_cases.c.h" + #line 2981 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2132 "Python/bytecodes.c" + #line 2130 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2987 "Python/generated_cases.c.h" + #line 2985 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2992,15 +2990,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2136 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2999 "Python/generated_cases.c.h" + #line 2997 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2139 "Python/bytecodes.c" + #line 2137 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3004 "Python/generated_cases.c.h" + #line 3002 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3009,29 +3007,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2143 "Python/bytecodes.c" + #line 2141 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3017 "Python/generated_cases.c.h" + #line 3015 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2149 "Python/bytecodes.c" + #line 2147 "Python/bytecodes.c" JUMPBY(oparg); - #line 3026 "Python/generated_cases.c.h" + #line 3024 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2153 "Python/bytecodes.c" + #line 2151 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3035 "Python/generated_cases.c.h" + #line 3033 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3039,15 +3037,15 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2159 "Python/bytecodes.c" + #line 2157 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3049 "Python/generated_cases.c.h" + #line 3047 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2165 "Python/bytecodes.c" + #line 2163 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3055,22 +3053,22 @@ if (err < 0) goto pop_1_error; } } - #line 3059 "Python/generated_cases.c.h" + #line 3057 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2175 "Python/bytecodes.c" + #line 2173 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3072 "Python/generated_cases.c.h" + #line 3070 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2181 "Python/bytecodes.c" + #line 2179 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3078,63 +3076,63 @@ if (err < 0) goto pop_1_error; } } - #line 3082 "Python/generated_cases.c.h" + #line 3080 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2191 "Python/bytecodes.c" + #line 2189 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3091 "Python/generated_cases.c.h" + #line 3089 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2193 "Python/bytecodes.c" + #line 2191 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3096 "Python/generated_cases.c.h" + #line 3094 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2198 "Python/bytecodes.c" + #line 2196 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3108 "Python/generated_cases.c.h" + #line 3106 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2203 "Python/bytecodes.c" + #line 2201 "Python/bytecodes.c" } - #line 3112 "Python/generated_cases.c.h" + #line 3110 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2207 "Python/bytecodes.c" + #line 2205 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3125 "Python/generated_cases.c.h" + #line 3123 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2216 "Python/bytecodes.c" + #line 2214 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3138 "Python/generated_cases.c.h" + #line 3136 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3145,16 +3143,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2224 "Python/bytecodes.c" + #line 2222 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3154 "Python/generated_cases.c.h" + #line 3152 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2229 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3162,7 +3160,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3166 "Python/generated_cases.c.h" + #line 3164 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3171,10 +3169,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2239 "Python/bytecodes.c" + #line 2237 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3178 "Python/generated_cases.c.h" + #line 3176 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3184,10 +3182,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2245 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3191 "Python/generated_cases.c.h" + #line 3189 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3198,11 +3196,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2251 "Python/bytecodes.c" + #line 2249 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3206 "Python/generated_cases.c.h" + #line 3204 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3211,14 +3209,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2257 "Python/bytecodes.c" + #line 2255 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3218 "Python/generated_cases.c.h" + #line 3216 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2260 "Python/bytecodes.c" + #line 2258 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3222 "Python/generated_cases.c.h" + #line 3220 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3226,7 +3224,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2264 "Python/bytecodes.c" + #line 2262 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3249,11 +3247,11 @@ if (iter == NULL) { goto error; } - #line 3253 "Python/generated_cases.c.h" + #line 3251 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2287 "Python/bytecodes.c" + #line 2285 "Python/bytecodes.c" } - #line 3257 "Python/generated_cases.c.h" + #line 3255 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3264,7 +3262,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2306 "Python/bytecodes.c" + #line 2304 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3295,7 +3293,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3299 "Python/generated_cases.c.h" + #line 3297 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3303,7 +3301,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2339 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3329,14 +3327,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3333 "Python/generated_cases.c.h" + #line 3331 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2367 "Python/bytecodes.c" + #line 2365 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3356,7 +3354,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3360 "Python/generated_cases.c.h" + #line 3358 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3366,7 +3364,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2389 "Python/bytecodes.c" + #line 2387 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3386,7 +3384,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3390 "Python/generated_cases.c.h" + #line 3388 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3396,7 +3394,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2411 "Python/bytecodes.c" + #line 2409 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3414,7 +3412,7 @@ if (next == NULL) { goto error; } - #line 3418 "Python/generated_cases.c.h" + #line 3416 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3423,7 +3421,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2431 "Python/bytecodes.c" + #line 2429 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3439,14 +3437,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3443 "Python/generated_cases.c.h" + #line 3441 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2449 "Python/bytecodes.c" + #line 2447 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3469,16 +3467,16 @@ Py_DECREF(enter); goto error; } - #line 3473 "Python/generated_cases.c.h" + #line 3471 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2472 "Python/bytecodes.c" + #line 2470 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3482 "Python/generated_cases.c.h" + #line 3480 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3490,7 +3488,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2482 "Python/bytecodes.c" + #line 2480 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3516,16 +3514,16 @@ Py_DECREF(enter); goto error; } - #line 3520 "Python/generated_cases.c.h" + #line 3518 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2508 "Python/bytecodes.c" + #line 2506 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3529 "Python/generated_cases.c.h" + #line 3527 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3537,7 +3535,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2517 "Python/bytecodes.c" + #line 2515 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3563,7 +3561,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3567 "Python/generated_cases.c.h" + #line 3565 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3572,7 +3570,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2545 "Python/bytecodes.c" + #line 2543 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3582,7 +3580,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3586 "Python/generated_cases.c.h" + #line 3584 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3596,7 +3594,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2557 "Python/bytecodes.c" + #line 2555 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3613,7 +3611,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3617 "Python/generated_cases.c.h" + #line 3615 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3627,7 +3625,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2576 "Python/bytecodes.c" + #line 2574 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3637,7 +3635,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3641 "Python/generated_cases.c.h" + #line 3639 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3651,7 +3649,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2588 "Python/bytecodes.c" + #line 2586 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3665,7 +3663,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3669 "Python/generated_cases.c.h" + #line 3667 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3674,16 +3672,16 @@ } TARGET(KW_NAMES) { - #line 2604 "Python/bytecodes.c" + #line 2602 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3682 "Python/generated_cases.c.h" + #line 3680 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2610 "Python/bytecodes.c" + #line 2608 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3696,7 +3694,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3700 "Python/generated_cases.c.h" + #line 3698 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3706,7 +3704,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2655 "Python/bytecodes.c" + #line 2653 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3788,7 +3786,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3792 "Python/generated_cases.c.h" + #line 3790 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3800,7 +3798,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2743 "Python/bytecodes.c" + #line 2741 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3810,7 +3808,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3814 "Python/generated_cases.c.h" + #line 3812 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3819,7 +3817,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2755 "Python/bytecodes.c" + #line 2753 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3845,7 +3843,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3849 "Python/generated_cases.c.h" + #line 3847 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3853,7 +3851,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2783 "Python/bytecodes.c" + #line 2781 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3889,7 +3887,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3893 "Python/generated_cases.c.h" + #line 3891 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3897,7 +3895,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2821 "Python/bytecodes.c" + #line 2819 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3907,7 +3905,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3911 "Python/generated_cases.c.h" + #line 3909 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3920,7 +3918,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2833 "Python/bytecodes.c" + #line 2831 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3931,7 +3929,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3935 "Python/generated_cases.c.h" + #line 3933 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3945,7 +3943,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2847 "Python/bytecodes.c" + #line 2845 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3956,7 +3954,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3960 "Python/generated_cases.c.h" + #line 3958 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3970,7 +3968,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2861 "Python/bytecodes.c" + #line 2859 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3992,7 +3990,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3996 "Python/generated_cases.c.h" + #line 3994 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4006,7 +4004,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2886 "Python/bytecodes.c" + #line 2884 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4034,7 +4032,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4038 "Python/generated_cases.c.h" + #line 4036 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4048,7 +4046,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2917 "Python/bytecodes.c" + #line 2915 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4080,7 +4078,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4084 "Python/generated_cases.c.h" + #line 4082 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4094,7 +4092,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2952 "Python/bytecodes.c" + #line 2950 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4126,7 +4124,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4130 "Python/generated_cases.c.h" + #line 4128 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4140,7 +4138,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2987 "Python/bytecodes.c" + #line 2985 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4165,7 +4163,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4169 "Python/generated_cases.c.h" + #line 4167 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4178,7 +4176,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3014 "Python/bytecodes.c" + #line 3012 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4205,7 +4203,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4209 "Python/generated_cases.c.h" + #line 4207 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4217,7 +4215,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3044 "Python/bytecodes.c" + #line 3042 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -4235,14 +4233,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4239 "Python/generated_cases.c.h" + #line 4237 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3064 "Python/bytecodes.c" + #line 3062 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4273,7 +4271,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4277 "Python/generated_cases.c.h" + #line 4275 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4286,7 +4284,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3098 "Python/bytecodes.c" + #line 3096 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4315,7 +4313,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4319 "Python/generated_cases.c.h" + #line 4317 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4328,7 +4326,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3130 "Python/bytecodes.c" + #line 3128 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4357,7 +4355,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4361 "Python/generated_cases.c.h" + #line 4359 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4370,7 +4368,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3162 "Python/bytecodes.c" + #line 3160 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4398,7 +4396,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4402 "Python/generated_cases.c.h" + #line 4400 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4408,9 +4406,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3193 "Python/bytecodes.c" + #line 3191 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4414 "Python/generated_cases.c.h" + #line 4412 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4419,7 +4417,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3197 "Python/bytecodes.c" + #line 3195 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4481,14 +4479,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4485 "Python/generated_cases.c.h" + #line 4483 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3259 "Python/bytecodes.c" + #line 3257 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4492 "Python/generated_cases.c.h" + #line 4490 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4503,7 +4501,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3269 "Python/bytecodes.c" + #line 3267 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4532,14 +4530,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4536 "Python/generated_cases.c.h" + #line 4534 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3300 "Python/bytecodes.c" + #line 3298 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4560,7 +4558,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4564 "Python/generated_cases.c.h" + #line 4562 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4568,15 +4566,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3323 "Python/bytecodes.c" + #line 3321 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4574 "Python/generated_cases.c.h" + #line 4572 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3325 "Python/bytecodes.c" + #line 3323 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4580 "Python/generated_cases.c.h" + #line 4578 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4587,7 +4585,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3329 "Python/bytecodes.c" + #line 3327 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4622,7 +4620,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4626 "Python/generated_cases.c.h" + #line 4624 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4631,10 +4629,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3366 "Python/bytecodes.c" + #line 3364 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4638 "Python/generated_cases.c.h" + #line 4636 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4646,7 +4644,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3371 "Python/bytecodes.c" + #line 3369 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4661,12 +4659,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4665 "Python/generated_cases.c.h" + #line 4663 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3386 "Python/bytecodes.c" + #line 3384 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4670 "Python/generated_cases.c.h" + #line 4668 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4676,16 +4674,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3391 "Python/bytecodes.c" + #line 3389 "Python/bytecodes.c" assert(oparg >= 2); - #line 4682 "Python/generated_cases.c.h" + #line 4680 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3395 "Python/bytecodes.c" + #line 3393 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4697,26 +4695,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4701 "Python/generated_cases.c.h" + #line 4699 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3409 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4707 "Python/generated_cases.c.h" + #line 4705 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3413 "Python/bytecodes.c" + #line 3411 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4714 "Python/generated_cases.c.h" + #line 4712 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3418 "Python/bytecodes.c" + #line 3416 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4725,12 +4723,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4729 "Python/generated_cases.c.h" + #line 4727 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3429 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4739,12 +4737,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4743 "Python/generated_cases.c.h" + #line 4741 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3440 "Python/bytecodes.c" + #line 3438 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4756,12 +4754,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4760 "Python/generated_cases.c.h" + #line 4758 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3454 "Python/bytecodes.c" + #line 3452 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4773,30 +4771,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4777 "Python/generated_cases.c.h" + #line 4775 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3468 "Python/bytecodes.c" + #line 3466 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4788 "Python/generated_cases.c.h" + #line 4786 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3476 "Python/bytecodes.c" + #line 3474 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4795 "Python/generated_cases.c.h" + #line 4793 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3481 "Python/bytecodes.c" + #line 3479 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4802 "Python/generated_cases.c.h" + #line 4800 "Python/generated_cases.c.h" } From 02f8f781dac62112362fa8a96f5c08deccb7b27f Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Nov 2023 01:56:34 +0100 Subject: [PATCH 1138/1206] [3.12] gh-111644: Fix support threading_cleanup() (GH-111714) (#111716) gh-111644: Fix support threading_cleanup() (GH-111714) Copy the list of dangling threads to make sure that the list of "Dangling thread" is complete. Previously, the list was incomplete if threads completed just before the list was displayed. Changes: * Rewrite the warning to make it easier to understand. * Use support.sleeping_retry(). * threading_cleanup() no longer copies threading._dangling, but only counts the number of dangling thread. * Remove support.gc_support() call. (cherry picked from commit f62c7ccf9abf6e0493978da9cf9ca43adcd403f9) Co-authored-by: Victor Stinner --- Lib/test/support/threading_helper.py | 53 +++++++++++++++------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/Lib/test/support/threading_helper.py b/Lib/test/support/threading_helper.py index 7f16050f32b9d1..afa25a76f63829 100644 --- a/Lib/test/support/threading_helper.py +++ b/Lib/test/support/threading_helper.py @@ -22,34 +22,37 @@ def threading_setup(): - return _thread._count(), threading._dangling.copy() + return _thread._count(), len(threading._dangling) def threading_cleanup(*original_values): - _MAX_COUNT = 100 - - for count in range(_MAX_COUNT): - values = _thread._count(), threading._dangling - if values == original_values: - break - - if not count: - # Display a warning at the first iteration - support.environment_altered = True - dangling_threads = values[1] - support.print_warning(f"threading_cleanup() failed to cleanup " - f"{values[0] - original_values[0]} threads " - f"(count: {values[0]}, " - f"dangling: {len(dangling_threads)})") - for thread in dangling_threads: - support.print_warning(f"Dangling thread: {thread!r}") - - # Don't hold references to threads - dangling_threads = None - values = None - - time.sleep(0.01) - support.gc_collect() + orig_count, orig_ndangling = original_values + + timeout = 1.0 + for _ in support.sleeping_retry(timeout, error=False): + # Copy the thread list to get a consistent output. threading._dangling + # is a WeakSet, its value changes when it's read. + dangling_threads = list(threading._dangling) + count = _thread._count() + + if count <= orig_count: + return + + # Timeout! + support.environment_altered = True + support.print_warning( + f"threading_cleanup() failed to clean up threads " + f"in {timeout:.1f} seconds\n" + f" before: thread count={orig_count}, dangling={orig_ndangling}\n" + f" after: thread count={count}, dangling={len(dangling_threads)}") + for thread in dangling_threads: + support.print_warning(f"Dangling thread: {thread!r}") + + # The warning happens when a test spawns threads and some of these threads + # are still running after the test completes. To fix this warning, join + # threads explicitly to wait until they complete. + # + # To make the warning more likely, reduce the timeout. def reap_threads(func): From d15fac2a6798d0cd149c1cb3c36167863cbc19e3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Nov 2023 07:29:20 +0100 Subject: [PATCH 1139/1206] [3.12] gh-111644: Fix asyncio test_unhandled_exceptions() (GH-111713) (#111718) gh-111644: Fix asyncio test_unhandled_exceptions() (GH-111713) Fix test_unhandled_exceptions() of test_asyncio.test_streams: break explicitly a reference cycle. Fix also StreamTests.tearDown(): the loop must not be closed explicitly, but using set_event_loop() which takes care of shutting down the executor with executor.shutdown(wait=True). BaseEventLoop.close() calls executor.shutdown(wait=False). (cherry picked from commit ac01e2243a1104b2154c0d1bdbc9f8d5b3ada778) Co-authored-by: Victor Stinner --- Lib/test/test_asyncio/test_streams.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index a0ed5ab7986768..5a22232c00a36a 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -37,8 +37,7 @@ def tearDown(self): # just in case if we have transport close callbacks test_utils.run_briefly(self.loop) - self.loop.close() - gc.collect() + # set_event_loop() takes care of closing self.loop in a safe way super().tearDown() def _basetest_open_connection(self, open_connection_fut): @@ -1102,6 +1101,8 @@ async def handle_echo(reader, writer): self.assertEqual(messages[0]['message'], 'Unhandled exception in client_connected_cb') + # Break explicitly reference cycle + messages = None if __name__ == '__main__': From 3b839ccfdfb6db8faf832add17e7a9b6c517230a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 4 Nov 2023 11:21:06 +0100 Subject: [PATCH 1140/1206] [3.12] gh-111159: Fix `SyntaxError` doctests for non-builtin exception classes (GH-111541) (#111732) gh-111159: Fix `SyntaxError` doctests for non-builtin exception classes (GH-111541) (cherry picked from commit 18c954849bcdd5acb6ef91cd90d92f3b5c685134) Co-authored-by: Nikita Sobolev --- Lib/doctest.py | 6 +++++- Lib/test/test_doctest.py | 18 ++++++++++++++++++ ...3-11-04-10-24-25.gh-issue-111541.x0RBI1.rst | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-04-10-24-25.gh-issue-111541.x0RBI1.rst diff --git a/Lib/doctest.py b/Lib/doctest.py index aeb28e8d292f6c..d7eaa8b131ed2f 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1382,10 +1382,14 @@ def __run(self, test, compileflags, out): # we don't care about the carets / suggestions / etc # We only care about the error message and notes. # They start with `SyntaxError:` (or any other class name) + exception_line_prefixes = ( + f"{exception[0].__qualname__}:", + f"{exception[0].__module__}.{exception[0].__qualname__}:", + ) exc_msg_index = next( index for index, line in enumerate(formatted_ex) - if line.startswith(f"{exception[0].__name__}:") + if line.startswith(exception_line_prefixes) ) formatted_ex = formatted_ex[exc_msg_index:] diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 09c378fcac80e0..0706049a90e41b 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -3279,6 +3279,24 @@ def test_syntax_error_with_note(cls, multiline=False): raise exc +def test_syntax_error_subclass_from_stdlib(): + """ + `ParseError` is a subclass of `SyntaxError`, but it is not a builtin: + + >>> test_syntax_error_subclass_from_stdlib() + Traceback (most recent call last): + ... + xml.etree.ElementTree.ParseError: error + error + Note + Line + """ + from xml.etree.ElementTree import ParseError + exc = ParseError("error\nerror") + exc.add_note('Note\nLine') + raise exc + + def test_syntax_error_with_incorrect_expected_note(): """ >>> def f(x): diff --git a/Misc/NEWS.d/next/Library/2023-11-04-10-24-25.gh-issue-111541.x0RBI1.rst b/Misc/NEWS.d/next/Library/2023-11-04-10-24-25.gh-issue-111541.x0RBI1.rst new file mode 100644 index 00000000000000..719b63dad36fb7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-04-10-24-25.gh-issue-111541.x0RBI1.rst @@ -0,0 +1 @@ +Fix :mod:`doctest` for :exc:`SyntaxError` not-builtin subclasses. From cd778b4917b29b4868aa339e920f947ab6cb6cb9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 4 Nov 2023 12:28:34 +0200 Subject: [PATCH 1141/1206] [3.12] gh-111495: Test C API functions with extreme sizes and indices (GH-111631) (GH-111731) (cherry picked from commit a8e1f474c20ab15140dd0cfcb96b696857907a60) --- Lib/test/test_capi/test_abstract.py | 54 ++++++++++------ Lib/test/test_capi/test_bytearray.py | 10 +-- Lib/test/test_capi/test_bytes.py | 10 ++- Lib/test/test_capi/test_unicode.py | 97 +++++++++++++++++++++++----- 4 files changed, 130 insertions(+), 41 deletions(-) diff --git a/Lib/test/test_capi/test_abstract.py b/Lib/test/test_capi/test_abstract.py index 116edd8d4d2fd6..d01ee66ed4ff20 100644 --- a/Lib/test/test_capi/test_abstract.py +++ b/Lib/test/test_capi/test_abstract.py @@ -1,10 +1,10 @@ import unittest import sys from collections import OrderedDict -from test import support from test.support import import_helper -import _testcapi +_testcapi = import_helper.import_module('_testcapi') +from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX NULL = None @@ -446,6 +446,8 @@ def test_sequence_getitem(self): self.assertEqual(getitem(lst, 1), 'b') self.assertEqual(getitem(lst, -1), 'c') self.assertRaises(IndexError, getitem, lst, 3) + self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX) + self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN) self.assertRaises(TypeError, getitem, 42, 1) self.assertRaises(TypeError, getitem, {}, 1) @@ -470,6 +472,9 @@ def test_sequence_repeat(self): self.assertEqual(repeat(('a', 'b'), 2), ('a', 'b', 'a', 'b')) self.assertEqual(repeat(['a', 'b'], 0), []) self.assertEqual(repeat(['a', 'b'], -1), []) + self.assertEqual(repeat(['a', 'b'], PY_SSIZE_T_MIN), []) + self.assertEqual(repeat([], PY_SSIZE_T_MAX), []) + self.assertRaises(MemoryError, repeat, ['a', 'b'], PY_SSIZE_T_MAX) self.assertRaises(TypeError, repeat, set(), 2) self.assertRaises(TypeError, repeat, 42, 2) @@ -503,6 +508,9 @@ def test_sequence_inplacerepeat(self): self.assertEqual(inplacerepeat(('a', 'b'), 2), ('a', 'b', 'a', 'b')) self.assertEqual(inplacerepeat(['a', 'b'], 0), []) self.assertEqual(inplacerepeat(['a', 'b'], -1), []) + self.assertEqual(inplacerepeat(['a', 'b'], PY_SSIZE_T_MIN), []) + self.assertEqual(inplacerepeat([], PY_SSIZE_T_MAX), []) + self.assertRaises(MemoryError, inplacerepeat, ['a', 'b'], PY_SSIZE_T_MAX) self.assertRaises(TypeError, inplacerepeat, set(), 2) self.assertRaises(TypeError, inplacerepeat, 42, 2) @@ -519,6 +527,8 @@ def test_sequence_setitem(self): setitem(lst, 0, NULL) self.assertEqual(lst, ['x', 'y']) self.assertRaises(IndexError, setitem, lst, 3, 'x') + self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MAX, 'x') + self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MIN, 'x') self.assertRaises(TypeError, setitem, 42, 1, 'x') self.assertRaises(TypeError, setitem, {}, 1, 'x') @@ -532,6 +542,8 @@ def test_sequence_delitem(self): delitem(lst, -1) self.assertEqual(lst, ['a']) self.assertRaises(IndexError, delitem, lst, 3) + self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MAX) + self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MIN) self.assertRaises(TypeError, delitem, 42, 1) self.assertRaises(TypeError, delitem, {}, 1) @@ -541,13 +553,19 @@ def test_sequence_setslice(self): setslice = _testcapi.sequence_setslice # Correct case: - data = [1, 2, 3, 4, 5] - data_copy = data.copy() - - setslice(data, 1, 3, [8, 9]) - data_copy[1:3] = [8, 9] - self.assertEqual(data, data_copy) - self.assertEqual(data, [1, 8, 9, 4, 5]) + for start in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]: + for stop in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]: + data = [1, 2, 3, 4, 5] + data_copy = [1, 2, 3, 4, 5] + setslice(data, start, stop, [8, 9]) + data_copy[start:stop] = [8, 9] + self.assertEqual(data, data_copy) + + data = [1, 2, 3, 4, 5] + data_copy = [1, 2, 3, 4, 5] + setslice(data, start, stop, NULL) + del data_copy[start:stop] + self.assertEqual(data, data_copy) # Custom class: class Custom: @@ -573,21 +591,17 @@ def __setitem__(self, index, value): self.assertRaises(TypeError, setslice, object(), 1, 3, 'xy') self.assertRaises(SystemError, setslice, NULL, 1, 3, 'xy') - data_copy = data.copy() - setslice(data_copy, 1, 3, NULL) - self.assertEqual(data_copy, [1, 4, 5]) - def test_sequence_delslice(self): delslice = _testcapi.sequence_delslice # Correct case: - data = [1, 2, 3, 4, 5] - data_copy = data.copy() - - delslice(data, 1, 3) - del data_copy[1:3] - self.assertEqual(data, data_copy) - self.assertEqual(data, [1, 4, 5]) + for start in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]: + for stop in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]: + data = [1, 2, 3, 4, 5] + data_copy = [1, 2, 3, 4, 5] + delslice(data, start, stop) + del data_copy[start:stop] + self.assertEqual(data, data_copy) # Custom class: class Custom: diff --git a/Lib/test/test_capi/test_bytearray.py b/Lib/test/test_capi/test_bytearray.py index 6a0f313a62e0d6..833122c4e319d8 100644 --- a/Lib/test/test_capi/test_bytearray.py +++ b/Lib/test/test_capi/test_bytearray.py @@ -1,8 +1,8 @@ import unittest -import sys from test.support import import_helper _testcapi = import_helper.import_module('_testcapi') +from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX NULL = None @@ -53,10 +53,12 @@ def test_fromstringandsize(self): self.assertEqual(fromstringandsize(b'', 0), bytearray()) self.assertEqual(fromstringandsize(NULL, 0), bytearray()) self.assertEqual(len(fromstringandsize(NULL, 3)), 3) - self.assertRaises(MemoryError, fromstringandsize, NULL, sys.maxsize) + self.assertRaises(MemoryError, fromstringandsize, NULL, PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromstringandsize, b'abc', -1) + self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN) self.assertRaises(SystemError, fromstringandsize, NULL, -1) + self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN) def test_fromobject(self): # Test PyByteArray_FromObject() @@ -149,8 +151,8 @@ def test_resize(self): self.assertEqual(resize(ba, 3), 0) self.assertEqual(ba, bytearray(b'abc')) - self.assertRaises(MemoryError, resize, bytearray(), sys.maxsize) - self.assertRaises(MemoryError, resize, bytearray(1000), sys.maxsize) + self.assertRaises(MemoryError, resize, bytearray(), PY_SSIZE_T_MAX) + self.assertRaises(MemoryError, resize, bytearray(1000), PY_SSIZE_T_MAX) # CRASHES resize(bytearray(b'abc'), -1) # CRASHES resize(b'abc', 0) diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py index e366578ee47358..bb5d724ff187d4 100644 --- a/Lib/test/test_capi/test_bytes.py +++ b/Lib/test/test_capi/test_bytes.py @@ -1,8 +1,8 @@ import unittest -import sys from test.support import import_helper _testcapi = import_helper.import_module('_testcapi') +from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX NULL = None @@ -55,10 +55,13 @@ def test_fromstringandsize(self): self.assertEqual(fromstringandsize(b'', 0), b'') self.assertEqual(fromstringandsize(NULL, 0), b'') self.assertEqual(len(fromstringandsize(NULL, 3)), 3) - self.assertRaises((MemoryError, OverflowError), fromstringandsize, NULL, sys.maxsize) + self.assertRaises((MemoryError, OverflowError), + fromstringandsize, NULL, PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromstringandsize, b'abc', -1) + self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN) self.assertRaises(SystemError, fromstringandsize, NULL, -1) + self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN) def test_fromstring(self): # Test PyBytes_FromString() @@ -208,7 +211,10 @@ def test_decodeescape(self): self.assertEqual(decodeescape(br'x\xa\xy', 'ignore'), b'xy') self.assertRaises(ValueError, decodeescape, b'\\', 'spam') self.assertEqual(decodeescape(NULL), b'') + self.assertRaises(OverflowError, decodeescape, b'abc', NULL, PY_SSIZE_T_MAX) + self.assertRaises(OverflowError, decodeescape, NULL, NULL, PY_SSIZE_T_MAX) + # CRASHES decodeescape(b'abc', NULL, -1) # CRASHES decodeescape(NULL, NULL, 1) diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 35a90b6ce082d7..1f07f9046f6e4e 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -5,6 +5,7 @@ try: import _testcapi + from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX except ImportError: _testcapi = None @@ -26,9 +27,17 @@ def test_new(self): for maxchar in 0, 0x61, 0xa1, 0x4f60, 0x1f600, 0x10ffff: self.assertEqual(new(0, maxchar), '') self.assertEqual(new(5, maxchar), chr(maxchar)*5) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX, maxchar) self.assertEqual(new(0, 0x110000), '') + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2, 0x4f60) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2+1, 0x4f60) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2, 0x1f600) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2+1, 0x1f600) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//4, 0x1f600) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//4+1, 0x1f600) self.assertRaises(SystemError, new, 5, 0x110000) self.assertRaises(SystemError, new, -1, 0) + self.assertRaises(SystemError, new, PY_SSIZE_T_MIN, 0) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -49,8 +58,8 @@ def test_fill(self): for to in strings[:idx]: self.assertRaises(ValueError, fill, to, 0, 0, fill_char) for to in strings[idx:]: - for start in range(7): - for length in range(-1, 7 - start): + for start in [*range(7), PY_SSIZE_T_MAX]: + for length in [*range(-1, 7 - start), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]: filled = max(min(length, 5 - start), 0) if filled == 5 and to != strings[idx]: # narrow -> wide @@ -62,6 +71,7 @@ def test_fill(self): s = strings[0] self.assertRaises(IndexError, fill, s, -1, 0, 0x78) + self.assertRaises(IndexError, fill, s, PY_SSIZE_T_MIN, 0, 0x78) self.assertRaises(ValueError, fill, s, 0, 0, 0x110000) self.assertRaises(SystemError, fill, b'abc', 0, 0, 0x78) self.assertRaises(SystemError, fill, [], 0, 0, 0x78) @@ -72,7 +82,7 @@ def test_fill(self): @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_writechar(self): - """Test PyUnicode_ReadChar()""" + """Test PyUnicode_WriteChar()""" from _testcapi import unicode_writechar as writechar strings = [ @@ -92,10 +102,12 @@ def test_writechar(self): self.assertRaises(IndexError, writechar, 'abc', 3, 0x78) self.assertRaises(IndexError, writechar, 'abc', -1, 0x78) + self.assertRaises(IndexError, writechar, 'abc', PY_SSIZE_T_MAX, 0x78) + self.assertRaises(IndexError, writechar, 'abc', PY_SSIZE_T_MIN, 0x78) self.assertRaises(TypeError, writechar, b'abc', 0, 0x78) self.assertRaises(TypeError, writechar, [], 0, 0x78) # CRASHES writechar(NULL, 0, 0x78) - # TODO: Test PyUnicode_CopyCharacters() with non-modifiable and legacy + # TODO: Test PyUnicode_WriteChar() with non-modifiable and legacy # unicode. @support.cpython_only @@ -113,7 +125,11 @@ def test_resize(self): self.assertEqual(resize(s, 3), (s, 0)) self.assertEqual(resize(s, 2), (s[:2], 0)) self.assertEqual(resize(s, 4), (s + '\0', 0)) + self.assertEqual(resize(s, 10), (s + '\0'*7, 0)) self.assertEqual(resize(s, 0), ('', 0)) + self.assertRaises(MemoryError, resize, s, PY_SSIZE_T_MAX) + self.assertRaises(SystemError, resize, s, -1) + self.assertRaises(SystemError, resize, s, PY_SSIZE_T_MIN) self.assertRaises(SystemError, resize, b'abc', 0) self.assertRaises(SystemError, resize, [], 0) self.assertRaises(SystemError, resize, NULL, 0) @@ -192,10 +208,13 @@ def test_fromstringandsize(self): self.assertEqual(fromstringandsize(b'', 0), '') self.assertEqual(fromstringandsize(NULL, 0), '') + self.assertRaises(MemoryError, fromstringandsize, b'abc', PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromstringandsize, b'abc', -1) + self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN) self.assertRaises(SystemError, fromstringandsize, NULL, -1) + self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN) self.assertRaises(SystemError, fromstringandsize, NULL, 3) - self.assertRaises(SystemError, fromstringandsize, NULL, sys.maxsize) + self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MAX) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -243,7 +262,9 @@ def test_fromkindanddata(self): for kind in -1, 0, 3, 5, 8: self.assertRaises(SystemError, fromkindanddata, kind, b'') self.assertRaises(ValueError, fromkindanddata, 1, b'abc', -1) + self.assertRaises(ValueError, fromkindanddata, 1, b'abc', PY_SSIZE_T_MIN) self.assertRaises(ValueError, fromkindanddata, 1, NULL, -1) + self.assertRaises(ValueError, fromkindanddata, 1, NULL, PY_SSIZE_T_MIN) # CRASHES fromkindanddata(1, NULL, 1) # CRASHES fromkindanddata(4, b'\xff\xff\xff\xff') @@ -259,12 +280,14 @@ def test_substring(self): 'ab\xa1\xa2\u4f60\u597d\U0001f600\U0001f601' ] for s in strings: - for start in range(0, len(s) + 2): - for end in range(max(start-1, 0), len(s) + 2): + for start in [*range(0, len(s) + 2), PY_SSIZE_T_MAX]: + for end in [*range(max(start-1, 0), len(s) + 2), PY_SSIZE_T_MAX]: self.assertEqual(substring(s, start, end), s[start:end]) self.assertRaises(IndexError, substring, 'abc', -1, 0) + self.assertRaises(IndexError, substring, 'abc', PY_SSIZE_T_MIN, 0) self.assertRaises(IndexError, substring, 'abc', 0, -1) + self.assertRaises(IndexError, substring, 'abc', 0, PY_SSIZE_T_MIN) # CRASHES substring(b'abc', 0, 0) # CRASHES substring([], 0, 0) # CRASHES substring(NULL, 0, 0) @@ -294,7 +317,9 @@ def test_readchar(self): for i, c in enumerate(s): self.assertEqual(readchar(s, i), ord(c)) self.assertRaises(IndexError, readchar, s, len(s)) + self.assertRaises(IndexError, readchar, s, PY_SSIZE_T_MAX) self.assertRaises(IndexError, readchar, s, -1) + self.assertRaises(IndexError, readchar, s, PY_SSIZE_T_MIN) self.assertRaises(TypeError, readchar, b'abc', 0) self.assertRaises(TypeError, readchar, [], 0) @@ -729,10 +754,15 @@ def test_fromwidechar(self): if SIZEOF_WCHAR_T == 2: self.assertEqual(fromwidechar('a\U0001f600'.encode(encoding), 2), 'a\ud83d') + self.assertRaises(MemoryError, fromwidechar, b'', PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, -2) + self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, PY_SSIZE_T_MIN) self.assertEqual(fromwidechar(NULL, 0), '') self.assertRaises(SystemError, fromwidechar, NULL, 1) + self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromwidechar, NULL, -1) + self.assertRaises(SystemError, fromwidechar, NULL, -2) + self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MIN) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -967,6 +997,11 @@ def test_split(self): self.assertEqual(split('a|b|c|d', '|'), ['a', 'b', 'c', 'd']) self.assertEqual(split('a|b|c|d', '|', 2), ['a', 'b', 'c|d']) + self.assertEqual(split('a|b|c|d', '|', PY_SSIZE_T_MAX), + ['a', 'b', 'c', 'd']) + self.assertEqual(split('a|b|c|d', '|', -1), ['a', 'b', 'c', 'd']) + self.assertEqual(split('a|b|c|d', '|', PY_SSIZE_T_MIN), + ['a', 'b', 'c', 'd']) self.assertEqual(split('a|b|c|d', '\u20ac'), ['a|b|c|d']) self.assertEqual(split('a||b|c||d', '||'), ['a', 'b|c', 'd']) self.assertEqual(split('а|б|в|г', '|'), ['а', 'б', 'в', 'г']) @@ -990,6 +1025,11 @@ def test_rsplit(self): self.assertEqual(rsplit('a|b|c|d', '|'), ['a', 'b', 'c', 'd']) self.assertEqual(rsplit('a|b|c|d', '|', 2), ['a|b', 'c', 'd']) + self.assertEqual(rsplit('a|b|c|d', '|', PY_SSIZE_T_MAX), + ['a', 'b', 'c', 'd']) + self.assertEqual(rsplit('a|b|c|d', '|', -1), ['a', 'b', 'c', 'd']) + self.assertEqual(rsplit('a|b|c|d', '|', PY_SSIZE_T_MIN), + ['a', 'b', 'c', 'd']) self.assertEqual(rsplit('a|b|c|d', '\u20ac'), ['a|b|c|d']) self.assertEqual(rsplit('a||b|c||d', '||'), ['a', 'b|c', 'd']) self.assertEqual(rsplit('а|б|в|г', '|'), ['а', 'б', 'в', 'г']) @@ -1122,11 +1162,14 @@ def test_count(self): self.assertEqual(unicode_count(str, '', 0, len(str)), len(str)+1) # start < end self.assertEqual(unicode_count(str, '!', 1, len(str)+1), 1) + self.assertEqual(unicode_count(str, '!', 1, PY_SSIZE_T_MAX), 1) # start >= end self.assertEqual(unicode_count(str, '!', 0, 0), 0) self.assertEqual(unicode_count(str, '!', len(str), 0), 0) # negative self.assertEqual(unicode_count(str, '!', -len(str), -1), 1) + self.assertEqual(unicode_count(str, '!', -len(str)-1, -1), 1) + self.assertEqual(unicode_count(str, '!', PY_SSIZE_T_MIN, -1), 1) # bad arguments self.assertRaises(TypeError, unicode_count, str, b'!', 0, len(str)) self.assertRaises(TypeError, unicode_count, b"!>_= end self.assertEqual(find(str, '!', 0, 0, 1), -1) + self.assertEqual(find(str, '!', 0, 0, -1), -1) self.assertEqual(find(str, '!', len(str), 0, 1), -1) + self.assertEqual(find(str, '!', len(str), 0, -1), -1) # negative self.assertEqual(find(str, '!', -len(str), -1, 1), 0) self.assertEqual(find(str, '!', -len(str), -1, -1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, -1, 1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, -1, -1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, 1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1), 4) # bad arguments self.assertRaises(TypeError, find, str, b'!', 0, len(str), 1) self.assertRaises(TypeError, find, b"!>_= end self.assertEqual(unicode_findchar(str, ord('!'), 0, 0, 1), -1) + self.assertEqual(unicode_findchar(str, ord('!'), 0, 0, -1), -1) self.assertEqual(unicode_findchar(str, ord('!'), len(str), 0, 1), -1) + self.assertEqual(unicode_findchar(str, ord('!'), len(str), 0, -1), -1) # negative self.assertEqual(unicode_findchar(str, ord('!'), -len(str), -1, 1), 0) self.assertEqual(unicode_findchar(str, ord('!'), -len(str), -1, -1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, -1, 1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, -1, -1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, 1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1), 4) # bad arguments # CRASHES unicode_findchar(b"!>_ Date: Sat, 4 Nov 2023 20:55:55 +0100 Subject: [PATCH 1142/1206] [3.12] gh-111724: Fix doctest `ResourceWarning` in `howto/descriptor.rst` (GH-111725) (#111727) gh-111724: Fix doctest `ResourceWarning` in `howto/descriptor.rst` (GH-111725) Close database connection explicitly in test cleanup. (cherry picked from commit f48e669504ce53040a04e0181064c11741a87817) Co-authored-by: Nikita Sobolev --- Doc/howto/descriptor.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 1d9424cb735a46..0a7263614670a1 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -943,6 +943,10 @@ it can be updated: >>> Movie('Star Wars').director 'J.J. Abrams' +.. testcleanup:: + + conn.close() + Pure Python Equivalents ^^^^^^^^^^^^^^^^^^^^^^^ From 237b269298bbc2f604b86182597b832b219113d9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Nov 2023 05:28:58 +0100 Subject: [PATCH 1143/1206] [3.12] gh-111747: DOC: fix moved link to Documentation Translations (GH-111748) (#111749) Update old link in bugs.rst to the table of doc translators and translation repositories at Github. (cherry picked from commit 72e27a67b97993f277e69c9dafb063007ba79adf) Co-authored-by: partev --- Doc/bugs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/bugs.rst b/Doc/bugs.rst index d98192b369603e..908987cf41ff6e 100644 --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -38,7 +38,7 @@ though it may take a while to be processed. `Helping with Documentation `_ Comprehensive guide for individuals that are interested in contributing to Python documentation. - `Documentation Translations `_ + `Documentation Translations `_ A list of GitHub pages for documentation translation and their primary contacts. From fef32a1d08c52e4604a42857ab5dfe8e7b0a12ff Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Nov 2023 09:01:31 +0100 Subject: [PATCH 1144/1206] [3.12] gh-111495: Add tests for PyFloat C API (GH-111624) (GH-111752) (cherry picked from commit b452202a11c4cb60f69a098a0076a8a8aabade38) Co-authored-by: Sergey B Kirpichev --- Lib/test/test_capi/test_float.py | 117 +++++++++++++++++++++++++++++++ Modules/_testcapi/float.c | 74 +++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 Lib/test/test_capi/test_float.py diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py new file mode 100644 index 00000000000000..95635e822a1245 --- /dev/null +++ b/Lib/test/test_capi/test_float.py @@ -0,0 +1,117 @@ +import math +import sys +import unittest +import warnings + +from test.test_capi.test_getargs import (Float, FloatSubclass, FloatSubclass2, + BadIndex2, BadFloat2, Index, BadIndex, + BadFloat) +from test.support import import_helper + +_testcapi = import_helper.import_module('_testcapi') + +NULL = None + + +class CAPIFloatTest(unittest.TestCase): + def test_check(self): + # Test PyFloat_Check() + check = _testcapi.float_check + + self.assertTrue(check(4.25)) + self.assertTrue(check(FloatSubclass(4.25))) + self.assertFalse(check(Float())) + self.assertFalse(check(3)) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_checkexact(self): + # Test PyFloat_CheckExact() + checkexact = _testcapi.float_checkexact + + self.assertTrue(checkexact(4.25)) + self.assertFalse(checkexact(FloatSubclass(4.25))) + self.assertFalse(checkexact(Float())) + self.assertFalse(checkexact(3)) + self.assertFalse(checkexact(object())) + + # CRASHES checkexact(NULL) + + def test_fromstring(self): + # Test PyFloat_FromString() + fromstring = _testcapi.float_fromstring + + self.assertEqual(fromstring("4.25"), 4.25) + self.assertEqual(fromstring(b"4.25"), 4.25) + self.assertRaises(ValueError, fromstring, "4.25\0") + self.assertRaises(ValueError, fromstring, b"4.25\0") + + self.assertEqual(fromstring(bytearray(b"4.25")), 4.25) + + self.assertEqual(fromstring(memoryview(b"4.25")), 4.25) + self.assertEqual(fromstring(memoryview(b"4.255")[:-1]), 4.25) + self.assertRaises(TypeError, fromstring, memoryview(b"4.25")[::2]) + + self.assertRaises(TypeError, fromstring, 4.25) + + # CRASHES fromstring(NULL) + + def test_fromdouble(self): + # Test PyFloat_FromDouble() + fromdouble = _testcapi.float_fromdouble + + self.assertEqual(fromdouble(4.25), 4.25) + + def test_asdouble(self): + # Test PyFloat_AsDouble() + asdouble = _testcapi.float_asdouble + + class BadFloat3: + def __float__(self): + raise RuntimeError + + self.assertEqual(asdouble(4.25), 4.25) + self.assertEqual(asdouble(-1.0), -1.0) + self.assertEqual(asdouble(42), 42.0) + self.assertEqual(asdouble(-1), -1.0) + self.assertEqual(asdouble(2**1000), float(2**1000)) + + self.assertEqual(asdouble(FloatSubclass(4.25)), 4.25) + self.assertEqual(asdouble(FloatSubclass2(4.25)), 4.25) + self.assertEqual(asdouble(Index()), 99.) + + self.assertRaises(TypeError, asdouble, BadIndex()) + self.assertRaises(TypeError, asdouble, BadFloat()) + self.assertRaises(RuntimeError, asdouble, BadFloat3()) + with self.assertWarns(DeprecationWarning): + self.assertEqual(asdouble(BadIndex2()), 1.) + with self.assertWarns(DeprecationWarning): + self.assertEqual(asdouble(BadFloat2()), 4.25) + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.assertRaises(DeprecationWarning, asdouble, BadFloat2()) + self.assertRaises(TypeError, asdouble, object()) + self.assertRaises(TypeError, asdouble, NULL) + + def test_getinfo(self): + # Test PyFloat_GetInfo() + getinfo = _testcapi.float_getinfo + + self.assertEqual(getinfo(), sys.float_info) + + def test_getmax(self): + # Test PyFloat_GetMax() + getmax = _testcapi.float_getmax + + self.assertEqual(getmax(), sys.float_info.max) + + def test_getmin(self): + # Test PyFloat_GetMax() + getmin = _testcapi.float_getmin + + self.assertEqual(getmin(), sys.float_info.min) + + +if __name__ == "__main__": + unittest.main() diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c index 33cbda83a81af7..0c26eb9b058c5d 100644 --- a/Modules/_testcapi/float.c +++ b/Modules/_testcapi/float.c @@ -1,9 +1,75 @@ #define PY_SSIZE_T_CLEAN #include "parts.h" +#include "util.h" #include "clinic/float.c.h" +static PyObject * +float_check(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyFloat_Check(obj)); +} + +static PyObject * +float_checkexact(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyFloat_CheckExact(obj)); +} + +static PyObject * +float_fromstring(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyFloat_FromString(obj); +} + +static PyObject * +float_fromdouble(PyObject *Py_UNUSED(module), PyObject *obj) +{ + double d; + + if (!PyArg_Parse(obj, "d", &d)) { + return NULL; + } + + return PyFloat_FromDouble(d); +} + +static PyObject * +float_asdouble(PyObject *Py_UNUSED(module), PyObject *obj) +{ + double d; + + NULLABLE(obj); + d = PyFloat_AsDouble(obj); + if (d == -1. && PyErr_Occurred()) { + return NULL; + } + + return PyFloat_FromDouble(d); +} + +static PyObject * +float_getinfo(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg)) +{ + return PyFloat_GetInfo(); +} + +static PyObject * +float_getmax(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg)) +{ + return PyFloat_FromDouble(PyFloat_GetMax()); +} + +static PyObject * +float_getmin(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(arg)) +{ + return PyFloat_FromDouble(PyFloat_GetMin()); +} + /*[clinic input] module _testcapi [clinic start generated code]*/ @@ -98,6 +164,14 @@ _testcapi_float_unpack_impl(PyObject *module, const char *data, } static PyMethodDef test_methods[] = { + {"float_check", float_check, METH_O}, + {"float_checkexact", float_checkexact, METH_O}, + {"float_fromstring", float_fromstring, METH_O}, + {"float_fromdouble", float_fromdouble, METH_O}, + {"float_asdouble", float_asdouble, METH_O}, + {"float_getinfo", float_getinfo, METH_NOARGS}, + {"float_getmax", float_getmax, METH_NOARGS}, + {"float_getmin", float_getmin, METH_NOARGS}, _TESTCAPI_FLOAT_PACK_METHODDEF _TESTCAPI_FLOAT_UNPACK_METHODDEF {NULL}, From e0c2bf46729d763ea2354b7e4aaecbba581b0512 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 5 Nov 2023 09:12:57 +0100 Subject: [PATCH 1145/1206] [3.12] gh-111495: Add tests for PyComplex C API (GH-111591) (GH-111753) (cherry picked from commit 24b5cbd3dce3fe37cdc787ccedd1e73a4f8cfc3c) Co-authored-by: Sergey B Kirpichev --- Lib/test/test_capi/test_complex.py | 146 +++++++++++++++++++++++++++++ Modules/_testcapi/complex.c | 92 ++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 Lib/test/test_capi/test_complex.py diff --git a/Lib/test/test_capi/test_complex.py b/Lib/test/test_capi/test_complex.py new file mode 100644 index 00000000000000..9f51efb091dea5 --- /dev/null +++ b/Lib/test/test_capi/test_complex.py @@ -0,0 +1,146 @@ +import unittest +import warnings + +from test.test_capi.test_getargs import (BadComplex, BadComplex2, Complex, + FloatSubclass, Float, BadFloat, + BadFloat2, ComplexSubclass) +from test.support import import_helper + + +_testcapi = import_helper.import_module('_testcapi') + +NULL = None + +class BadComplex3: + def __complex__(self): + raise RuntimeError + + +class CAPIComplexTest(unittest.TestCase): + def test_check(self): + # Test PyComplex_Check() + check = _testcapi.complex_check + + self.assertTrue(check(1+2j)) + self.assertTrue(check(ComplexSubclass(1+2j))) + self.assertFalse(check(Complex())) + self.assertFalse(check(3)) + self.assertFalse(check(3.0)) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_checkexact(self): + # PyComplex_CheckExact() + checkexact = _testcapi.complex_checkexact + + self.assertTrue(checkexact(1+2j)) + self.assertFalse(checkexact(ComplexSubclass(1+2j))) + self.assertFalse(checkexact(Complex())) + self.assertFalse(checkexact(3)) + self.assertFalse(checkexact(3.0)) + self.assertFalse(checkexact(object())) + + # CRASHES checkexact(NULL) + + def test_fromccomplex(self): + # Test PyComplex_FromCComplex() + fromccomplex = _testcapi.complex_fromccomplex + + self.assertEqual(fromccomplex(1+2j), 1.0+2.0j) + + def test_fromdoubles(self): + # Test PyComplex_FromDoubles() + fromdoubles = _testcapi.complex_fromdoubles + + self.assertEqual(fromdoubles(1.0, 2.0), 1.0+2.0j) + + def test_realasdouble(self): + # Test PyComplex_RealAsDouble() + realasdouble = _testcapi.complex_realasdouble + + self.assertEqual(realasdouble(1+2j), 1.0) + self.assertEqual(realasdouble(-1+0j), -1.0) + self.assertEqual(realasdouble(4.25), 4.25) + self.assertEqual(realasdouble(-1.0), -1.0) + self.assertEqual(realasdouble(42), 42.) + self.assertEqual(realasdouble(-1), -1.0) + + # Test subclasses of complex/float + self.assertEqual(realasdouble(ComplexSubclass(1+2j)), 1.0) + self.assertEqual(realasdouble(FloatSubclass(4.25)), 4.25) + + # Test types with __complex__ dunder method + # Function doesn't support classes with __complex__ dunder, see #109598 + self.assertRaises(TypeError, realasdouble, Complex()) + + # Test types with __float__ dunder method + self.assertEqual(realasdouble(Float()), 4.25) + self.assertRaises(TypeError, realasdouble, BadFloat()) + with self.assertWarns(DeprecationWarning): + self.assertEqual(realasdouble(BadFloat2()), 4.25) + + self.assertRaises(TypeError, realasdouble, object()) + + # CRASHES realasdouble(NULL) + + def test_imagasdouble(self): + # Test PyComplex_ImagAsDouble() + imagasdouble = _testcapi.complex_imagasdouble + + self.assertEqual(imagasdouble(1+2j), 2.0) + self.assertEqual(imagasdouble(1-1j), -1.0) + self.assertEqual(imagasdouble(4.25), 0.0) + self.assertEqual(imagasdouble(42), 0.0) + + # Test subclasses of complex/float + self.assertEqual(imagasdouble(ComplexSubclass(1+2j)), 2.0) + self.assertEqual(imagasdouble(FloatSubclass(4.25)), 0.0) + + # Test types with __complex__ dunder method + # Function doesn't support classes with __complex__ dunder, see #109598 + self.assertEqual(imagasdouble(Complex()), 0.0) + + # Function returns 0.0 anyway, see #109598 + self.assertEqual(imagasdouble(object()), 0.0) + + # CRASHES imagasdouble(NULL) + + def test_asccomplex(self): + # Test PyComplex_AsCComplex() + asccomplex = _testcapi.complex_asccomplex + + self.assertEqual(asccomplex(1+2j), 1.0+2.0j) + self.assertEqual(asccomplex(-1+2j), -1.0+2.0j) + self.assertEqual(asccomplex(4.25), 4.25+0.0j) + self.assertEqual(asccomplex(-1.0), -1.0+0.0j) + self.assertEqual(asccomplex(42), 42+0j) + self.assertEqual(asccomplex(-1), -1.0+0.0j) + + # Test subclasses of complex/float + self.assertEqual(asccomplex(ComplexSubclass(1+2j)), 1.0+2.0j) + self.assertEqual(asccomplex(FloatSubclass(4.25)), 4.25+0.0j) + + # Test types with __complex__ dunder method + self.assertEqual(asccomplex(Complex()), 4.25+0.5j) + self.assertRaises(TypeError, asccomplex, BadComplex()) + with self.assertWarns(DeprecationWarning): + self.assertEqual(asccomplex(BadComplex2()), 4.25+0.5j) + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.assertRaises(DeprecationWarning, asccomplex, BadComplex2()) + self.assertRaises(RuntimeError, asccomplex, BadComplex3()) + + # Test types with __float__ dunder method + self.assertEqual(asccomplex(Float()), 4.25+0.0j) + self.assertRaises(TypeError, asccomplex, BadFloat()) + with self.assertWarns(DeprecationWarning): + self.assertEqual(asccomplex(BadFloat2()), 4.25+0.0j) + + self.assertRaises(TypeError, asccomplex, object()) + + # CRASHES asccomplex(NULL) + + +if __name__ == "__main__": + unittest.main() diff --git a/Modules/_testcapi/complex.c b/Modules/_testcapi/complex.c index 0402b8ecc9588f..400f4054c613ee 100644 --- a/Modules/_testcapi/complex.c +++ b/Modules/_testcapi/complex.c @@ -1,7 +1,99 @@ #include "parts.h" #include "util.h" + +static PyObject * +complex_check(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyComplex_Check(obj)); +} + +static PyObject * +complex_checkexact(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyComplex_CheckExact(obj)); +} + +static PyObject * +complex_fromccomplex(PyObject *Py_UNUSED(module), PyObject *obj) +{ + Py_complex complex; + + if (!PyArg_Parse(obj, "D", &complex)) { + return NULL; + } + + return PyComplex_FromCComplex(complex); +} + +static PyObject * +complex_fromdoubles(PyObject *Py_UNUSED(module), PyObject *args) +{ + double real, imag; + + if (!PyArg_ParseTuple(args, "dd", &real, &imag)) { + return NULL; + } + + return PyComplex_FromDoubles(real, imag); +} + +static PyObject * +complex_realasdouble(PyObject *Py_UNUSED(module), PyObject *obj) +{ + double real; + + NULLABLE(obj); + real = PyComplex_RealAsDouble(obj); + + if (real == -1. && PyErr_Occurred()) { + return NULL; + } + + return PyFloat_FromDouble(real); +} + +static PyObject * +complex_imagasdouble(PyObject *Py_UNUSED(module), PyObject *obj) +{ + double imag; + + NULLABLE(obj); + imag = PyComplex_ImagAsDouble(obj); + + if (imag == -1. && PyErr_Occurred()) { + return NULL; + } + + return PyFloat_FromDouble(imag); +} + +static PyObject * +complex_asccomplex(PyObject *Py_UNUSED(module), PyObject *obj) +{ + Py_complex complex; + + NULLABLE(obj); + complex = PyComplex_AsCComplex(obj); + + if (complex.real == -1. && PyErr_Occurred()) { + return NULL; + } + + return PyComplex_FromCComplex(complex); +} + + static PyMethodDef test_methods[] = { + {"complex_check", complex_check, METH_O}, + {"complex_checkexact", complex_checkexact, METH_O}, + {"complex_fromccomplex", complex_fromccomplex, METH_O}, + {"complex_fromdoubles", complex_fromdoubles, METH_VARARGS}, + {"complex_realasdouble", complex_realasdouble, METH_O}, + {"complex_imagasdouble", complex_imagasdouble, METH_O}, + {"complex_asccomplex", complex_asccomplex, METH_O}, {NULL}, }; From c4e524c3f25bb9b58427b0eb58d24989d81a2663 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:31:58 +0100 Subject: [PATCH 1146/1206] [3.12] gh-101180: Fix a bug where iso2022_jp_3 and iso2022_jp_2004 codecs read out of bounds (gh-111695) (gh-111769) gh-101180: Fix a bug where iso2022_jp_3 and iso2022_jp_2004 codecs read out of bounds (gh-111695) (cherry picked from commit c8faa3568afd255708096f6aa8df0afa80cf7697) Co-authored-by: Masayuki Moriyama --- Lib/test/test_codecencodings_iso2022.py | 46 +++++++++++++++++++ ...-10-27-19-38-33.gh-issue-102388.vd5YUZ.rst | 1 + Modules/cjkcodecs/_codecs_iso2022.c | 9 ++-- 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-27-19-38-33.gh-issue-102388.vd5YUZ.rst diff --git a/Lib/test/test_codecencodings_iso2022.py b/Lib/test/test_codecencodings_iso2022.py index 00ea1c39dd6fb6..027dbecc6134df 100644 --- a/Lib/test/test_codecencodings_iso2022.py +++ b/Lib/test/test_codecencodings_iso2022.py @@ -24,6 +24,52 @@ class Test_ISO2022_JP2(multibytecodec_support.TestBase, unittest.TestCase): (b'ab\x1BNdef', 'replace', 'abdef'), ) +class Test_ISO2022_JP3(multibytecodec_support.TestBase, unittest.TestCase): + encoding = 'iso2022_jp_3' + tstring = multibytecodec_support.load_teststring('iso2022_jp') + codectests = COMMON_CODEC_TESTS + ( + (b'ab\x1BNdef', 'replace', 'ab\x1BNdef'), + (b'\x1B$(O\x2E\x23\x1B(B', 'strict', '\u3402' ), + (b'\x1B$(O\x2E\x22\x1B(B', 'strict', '\U0002000B' ), + (b'\x1B$(O\x24\x77\x1B(B', 'strict', '\u304B\u309A'), + (b'\x1B$(P\x21\x22\x1B(B', 'strict', '\u4E02' ), + (b'\x1B$(P\x7E\x76\x1B(B', 'strict', '\U0002A6B2' ), + ('\u3402', 'strict', b'\x1B$(O\x2E\x23\x1B(B'), + ('\U0002000B', 'strict', b'\x1B$(O\x2E\x22\x1B(B'), + ('\u304B\u309A', 'strict', b'\x1B$(O\x24\x77\x1B(B'), + ('\u4E02', 'strict', b'\x1B$(P\x21\x22\x1B(B'), + ('\U0002A6B2', 'strict', b'\x1B$(P\x7E\x76\x1B(B'), + (b'ab\x1B$(O\x2E\x21\x1B(Bdef', 'replace', 'ab\uFFFDdef'), + ('ab\u4FF1def', 'replace', b'ab?def'), + ) + xmlcharnametest = ( + '\xAB\u211C\xBB = \u2329\u1234\u232A', + b'\x1B$(O\x29\x28\x1B(Bℜ\x1B$(O\x29\x32\x1B(B = ⟨ሴ⟩' + ) + +class Test_ISO2022_JP2004(multibytecodec_support.TestBase, unittest.TestCase): + encoding = 'iso2022_jp_2004' + tstring = multibytecodec_support.load_teststring('iso2022_jp') + codectests = COMMON_CODEC_TESTS + ( + (b'ab\x1BNdef', 'replace', 'ab\x1BNdef'), + (b'\x1B$(Q\x2E\x23\x1B(B', 'strict', '\u3402' ), + (b'\x1B$(Q\x2E\x22\x1B(B', 'strict', '\U0002000B' ), + (b'\x1B$(Q\x24\x77\x1B(B', 'strict', '\u304B\u309A'), + (b'\x1B$(P\x21\x22\x1B(B', 'strict', '\u4E02' ), + (b'\x1B$(P\x7E\x76\x1B(B', 'strict', '\U0002A6B2' ), + ('\u3402', 'strict', b'\x1B$(Q\x2E\x23\x1B(B'), + ('\U0002000B', 'strict', b'\x1B$(Q\x2E\x22\x1B(B'), + ('\u304B\u309A', 'strict', b'\x1B$(Q\x24\x77\x1B(B'), + ('\u4E02', 'strict', b'\x1B$(P\x21\x22\x1B(B'), + ('\U0002A6B2', 'strict', b'\x1B$(P\x7E\x76\x1B(B'), + (b'ab\x1B$(Q\x2E\x21\x1B(Bdef', 'replace', 'ab\u4FF1def'), + ('ab\u4FF1def', 'replace', b'ab\x1B$(Q\x2E\x21\x1B(Bdef'), + ) + xmlcharnametest = ( + '\xAB\u211C\xBB = \u2329\u1234\u232A', + b'\x1B$(Q\x29\x28\x1B(Bℜ\x1B$(Q\x29\x32\x1B(B = ⟨ሴ⟩' + ) + class Test_ISO2022_KR(multibytecodec_support.TestBase, unittest.TestCase): encoding = 'iso2022_kr' tstring = multibytecodec_support.load_teststring('iso2022_kr') diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-27-19-38-33.gh-issue-102388.vd5YUZ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-27-19-38-33.gh-issue-102388.vd5YUZ.rst new file mode 100644 index 00000000000000..268a3d310f2b49 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-27-19-38-33.gh-issue-102388.vd5YUZ.rst @@ -0,0 +1 @@ +Fix a bug where ``iso2022_jp_3`` and ``iso2022_jp_2004`` codecs read out of bounds diff --git a/Modules/cjkcodecs/_codecs_iso2022.c b/Modules/cjkcodecs/_codecs_iso2022.c index 86bb73b982a551..e8835ad0909633 100644 --- a/Modules/cjkcodecs/_codecs_iso2022.c +++ b/Modules/cjkcodecs/_codecs_iso2022.c @@ -207,8 +207,9 @@ ENCODER(iso2022) encoded = MAP_UNMAPPABLE; for (dsg = CONFIG_DESIGNATIONS; dsg->mark; dsg++) { + Py_UCS4 buf[2] = {c, 0}; Py_ssize_t length = 1; - encoded = dsg->encoder(codec, &c, &length); + encoded = dsg->encoder(codec, buf, &length); if (encoded == MAP_MULTIPLE_AVAIL) { /* this implementation won't work for pair * of non-bmp characters. */ @@ -217,9 +218,11 @@ ENCODER(iso2022) return MBERR_TOOFEW; length = -1; } - else + else { + buf[1] = INCHAR2; length = 2; - encoded = dsg->encoder(codec, &c, &length); + } + encoded = dsg->encoder(codec, buf, &length); if (encoded != MAP_UNMAPPABLE) { insize = length; break; From 35141842d350bfa2c8dc04e7cc886bdff03cf3b7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Nov 2023 02:00:16 +0100 Subject: [PATCH 1147/1206] [3.12] gh-111729: update generic syntax for `typing.Concatenate` sample code in `Doc/library/typing.rst` (GH-111734) (#111814) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit c3e19c3a62e82b9e77563e934059895b6230de6e) Co-authored-by: 方糖 --- Doc/library/typing.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 44665b63487b72..7cec24464a4cb9 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1135,16 +1135,13 @@ These can be used as types in annotations. They all support subscription using from collections.abc import Callable from threading import Lock - from typing import Concatenate, ParamSpec, TypeVar - - P = ParamSpec('P') - R = TypeVar('R') + from typing import Concatenate # Use this lock to ensure that only one thread is executing a function # at any time. my_lock = Lock() - def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]: + def with_lock[**P, R](f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]: '''A type-safe decorator which provides a lock.''' def inner(*args: P.args, **kwargs: P.kwargs) -> R: # Provide the lock as the first argument. From f70ae99cb47b9727d0d66fd636986cbfc0530b41 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Nov 2023 13:06:21 +0100 Subject: [PATCH 1148/1206] [3.12] gh-111765: Move old PyFloat_* tests to Lib/test/test_capi/test_float.py (GH-111766) (GH-111818) (cherry picked from commit a077b2fbb88f5192bb47e514334f760bf08d0295) Co-authored-by: Sergey B Kirpichev --- Lib/test/test_capi/test_float.py | 65 ++++++++++++++++++++++++++++++++ Lib/test/test_float.py | 65 -------------------------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py index 95635e822a1245..cb94d562645916 100644 --- a/Lib/test/test_capi/test_float.py +++ b/Lib/test/test_capi/test_float.py @@ -12,6 +12,19 @@ NULL = None +# For PyFloat_Pack/Unpack* +BIG_ENDIAN = 0 +LITTLE_ENDIAN = 1 +EPSILON = { + 2: 2.0 ** -11, # binary16 + 4: 2.0 ** -24, # binary32 + 8: 2.0 ** -53, # binary64 +} + +HAVE_IEEE_754 = float.__getformat__("double").startswith("IEEE") +INF = float("inf") +NAN = float("nan") + class CAPIFloatTest(unittest.TestCase): def test_check(self): @@ -112,6 +125,58 @@ def test_getmin(self): self.assertEqual(getmin(), sys.float_info.min) + def test_pack(self): + # Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8() + pack = _testcapi.float_pack + + self.assertEqual(pack(2, 1.5, BIG_ENDIAN), b'>\x00') + self.assertEqual(pack(4, 1.5, BIG_ENDIAN), b'?\xc0\x00\x00') + self.assertEqual(pack(8, 1.5, BIG_ENDIAN), + b'?\xf8\x00\x00\x00\x00\x00\x00') + self.assertEqual(pack(2, 1.5, LITTLE_ENDIAN), b'\x00>') + self.assertEqual(pack(4, 1.5, LITTLE_ENDIAN), b'\x00\x00\xc0?') + self.assertEqual(pack(8, 1.5, LITTLE_ENDIAN), + b'\x00\x00\x00\x00\x00\x00\xf8?') + + def test_unpack(self): + # Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8() + unpack = _testcapi.float_unpack + + self.assertEqual(unpack(b'>\x00', BIG_ENDIAN), 1.5) + self.assertEqual(unpack(b'?\xc0\x00\x00', BIG_ENDIAN), 1.5) + self.assertEqual(unpack(b'?\xf8\x00\x00\x00\x00\x00\x00', BIG_ENDIAN), + 1.5) + self.assertEqual(unpack(b'\x00>', LITTLE_ENDIAN), 1.5) + self.assertEqual(unpack(b'\x00\x00\xc0?', LITTLE_ENDIAN), 1.5) + self.assertEqual(unpack(b'\x00\x00\x00\x00\x00\x00\xf8?', LITTLE_ENDIAN), + 1.5) + + def test_pack_unpack_roundtrip(self): + pack = _testcapi.float_pack + unpack = _testcapi.float_unpack + + large = 2.0 ** 100 + values = [1.0, 1.5, large, 1.0/7, math.pi] + if HAVE_IEEE_754: + values.extend((INF, NAN)) + for value in values: + for size in (2, 4, 8,): + if size == 2 and value == large: + # too large for 16-bit float + continue + rel_tol = EPSILON[size] + for endian in (BIG_ENDIAN, LITTLE_ENDIAN): + with self.subTest(value=value, size=size, endian=endian): + data = pack(size, value, endian) + value2 = unpack(data, endian) + if math.isnan(value): + self.assertTrue(math.isnan(value2), (value, value2)) + elif size < 8: + self.assertTrue(math.isclose(value2, value, rel_tol=rel_tol), + (value, value2)) + else: + self.assertEqual(value2, value) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index 84270ce7dd4780..32aaf3a80ab64b 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -18,7 +18,6 @@ except ImportError: _testcapi = None -HAVE_IEEE_754 = float.__getformat__("double").startswith("IEEE") INF = float("inf") NAN = float("nan") @@ -1504,69 +1503,5 @@ def __init__(self, value): self.assertEqual(getattr(f, 'foo', 'none'), 'bar') -# Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8() -# Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8() -BIG_ENDIAN = 0 -LITTLE_ENDIAN = 1 -EPSILON = { - 2: 2.0 ** -11, # binary16 - 4: 2.0 ** -24, # binary32 - 8: 2.0 ** -53, # binary64 -} - -@unittest.skipIf(_testcapi is None, 'needs _testcapi') -class PackTests(unittest.TestCase): - def test_pack(self): - self.assertEqual(_testcapi.float_pack(2, 1.5, BIG_ENDIAN), - b'>\x00') - self.assertEqual(_testcapi.float_pack(4, 1.5, BIG_ENDIAN), - b'?\xc0\x00\x00') - self.assertEqual(_testcapi.float_pack(8, 1.5, BIG_ENDIAN), - b'?\xf8\x00\x00\x00\x00\x00\x00') - self.assertEqual(_testcapi.float_pack(2, 1.5, LITTLE_ENDIAN), - b'\x00>') - self.assertEqual(_testcapi.float_pack(4, 1.5, LITTLE_ENDIAN), - b'\x00\x00\xc0?') - self.assertEqual(_testcapi.float_pack(8, 1.5, LITTLE_ENDIAN), - b'\x00\x00\x00\x00\x00\x00\xf8?') - - def test_unpack(self): - self.assertEqual(_testcapi.float_unpack(b'>\x00', BIG_ENDIAN), - 1.5) - self.assertEqual(_testcapi.float_unpack(b'?\xc0\x00\x00', BIG_ENDIAN), - 1.5) - self.assertEqual(_testcapi.float_unpack(b'?\xf8\x00\x00\x00\x00\x00\x00', BIG_ENDIAN), - 1.5) - self.assertEqual(_testcapi.float_unpack(b'\x00>', LITTLE_ENDIAN), - 1.5) - self.assertEqual(_testcapi.float_unpack(b'\x00\x00\xc0?', LITTLE_ENDIAN), - 1.5) - self.assertEqual(_testcapi.float_unpack(b'\x00\x00\x00\x00\x00\x00\xf8?', LITTLE_ENDIAN), - 1.5) - - def test_roundtrip(self): - large = 2.0 ** 100 - values = [1.0, 1.5, large, 1.0/7, math.pi] - if HAVE_IEEE_754: - values.extend((INF, NAN)) - for value in values: - for size in (2, 4, 8,): - if size == 2 and value == large: - # too large for 16-bit float - continue - rel_tol = EPSILON[size] - for endian in (BIG_ENDIAN, LITTLE_ENDIAN): - with self.subTest(value=value, size=size, endian=endian): - data = _testcapi.float_pack(size, value, endian) - value2 = _testcapi.float_unpack(data, endian) - if isnan(value): - self.assertTrue(isnan(value2), (value, value2)) - elif size < 8: - self.assertTrue(math.isclose(value2, value, rel_tol=rel_tol), - (value, value2)) - else: - self.assertEqual(value2, value) - - if __name__ == '__main__': unittest.main() From d35c94566ad842d04a4cdeb2cf955f1c9874221e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 7 Nov 2023 23:04:29 +0100 Subject: [PATCH 1149/1206] [3.12] gh-111806: Fix `test_recursion` in `test_richcmp` on WASI builds (GH-111830) (GH-111831) gh-111806: Fix `test_recursion` in `test_richcmp` on WASI builds (GH-111830) (cherry picked from commit f115a55f0e455a4b43a1da9fd838a60a101f182a) Co-authored-by: Nikita Sobolev --- Lib/test/test_richcmp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py index 58729a9fea62fa..5f449cdc05c6ba 100644 --- a/Lib/test/test_richcmp.py +++ b/Lib/test/test_richcmp.py @@ -221,6 +221,7 @@ def do(bad): self.assertRaises(Exc, func, Bad()) @support.no_tracing + @support.infinite_recursion(25) def test_recursion(self): # Check that comparison for recursive objects fails gracefully from collections import UserList From 42699c82d7b274c73ab0f3970bf27e2228b813d1 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:45:17 +0100 Subject: [PATCH 1150/1206] [3.12] Glossary: Add "static type checker" (GH-111837) (#111854) Glossary: Add "static type checker" (GH-111837) (cherry picked from commit 8ab7ad63086b1793c24b1c5aaa19b60fc0e6540e) Co-authored-by: Jelle Zijlstra Co-authored-by: Alex Waygood --- Doc/glossary.rst | 9 +++++++-- Doc/howto/pyporting.rst | 5 +++-- Doc/library/datetime.rst | 3 ++- Doc/library/typing.rst | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index e43e755932b690..cd34d190c665d6 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1132,6 +1132,11 @@ Glossary an :term:`expression` or one of several constructs with a keyword, such as :keyword:`if`, :keyword:`while` or :keyword:`for`. + static type checker + An external tool that reads Python code and analyzes it, looking for + issues such as incorrect types. See also :term:`type hints ` + and the :mod:`typing` module. + strong reference In Python's C API, a strong reference is a reference to an object which is owned by the code holding the reference. The strong @@ -1208,8 +1213,8 @@ Glossary attribute, or a function parameter or return value. Type hints are optional and are not enforced by Python but - they are useful to static type analysis tools, and aid IDEs with code - completion and refactoring. + they are useful to :term:`static type checkers `. + They can also aid IDEs with code completion and refactoring. Type hints of global variables, class attributes, and functions, but not local variables, can be accessed using diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst index 6c30a0dd7d6bcc..501b16d82d4d6f 100644 --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -39,7 +39,8 @@ are: #. Once your dependencies are no longer blocking you, use continuous integration to make sure you stay compatible with Python 2 and 3 (tox_ can help test against multiple versions of Python; ``python -m pip install tox``) -#. Consider using optional static type checking to make sure your type usage +#. Consider using optional :term:`static type checking ` + to make sure your type usage works in both Python 2 and 3 (e.g. use mypy_ to check your typing under both Python 2 and Python 3; ``python -m pip install mypy``). @@ -395,7 +396,7 @@ comparisons occur, making the mistake much easier to track down. Consider using optional static type checking -------------------------------------------- -Another way to help port your code is to use a static type checker like +Another way to help port your code is to use a :term:`static type checker` like mypy_ or pytype_ on your code. These tools can be used to analyze your code as if it's being run under Python 2, then you can run the tool a second time as if your code is running under Python 3. By running a static type checker twice like diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 04cc75562937e0..649f1a3a5fc6d6 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -38,7 +38,8 @@ on efficient attribute extraction for output formatting and manipulation. Third-party library with expanded time zone and parsing support. Package `DateType `_ - Third-party library that introduces distinct static types to e.g. allow static type checkers + Third-party library that introduces distinct static types to e.g. allow + :term:`static type checkers ` to differentiate between naive and aware datetimes. .. _datetime-naive-aware: diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 7cec24464a4cb9..7b75094b9da0f6 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -18,8 +18,8 @@ .. note:: The Python runtime does not enforce function and variable type annotations. - They can be used by third party tools such as type checkers, IDEs, linters, - etc. + They can be used by third party tools such as :term:`type checkers `, + IDEs, linters, etc. -------------- From 992c3f6b51edd58ad6c751af9aa6a7819e2796c1 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 8 Nov 2023 19:56:24 +0300 Subject: [PATCH 1151/1206] [3.12] gh-108303: Move more typing related files to Lib/test/typinganndata (GH-111825) (#111859) [3.12] gh-108303: Move more typing related files to Lib/test/typinganndata(GH-111825) --- Lib/test/test_type_aliases.py | 2 +- Lib/test/test_typing.py | 3 +-- Lib/test/{ => typinganndata}/_typed_dict_helper.py | 0 Lib/test/{ => typinganndata}/mod_generics_cache.py | 0 4 files changed, 2 insertions(+), 3 deletions(-) rename Lib/test/{ => typinganndata}/_typed_dict_helper.py (100%) rename Lib/test/{ => typinganndata}/mod_generics_cache.py (100%) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index 8f0a998e1f3dc1..9c325bc595f585 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -2,7 +2,7 @@ import types import unittest from test.support import check_syntax_error, run_code -from test import mod_generics_cache +from test.typinganndata import mod_generics_cache from typing import Callable, TypeAliasType, TypeVar, get_args diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index dc5ab7d889e0f0..62fe00b0a02f28 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -46,8 +46,7 @@ import types from test.support import import_helper, captured_stderr, cpython_only -from test import mod_generics_cache -from test import _typed_dict_helper +from test.typinganndata import mod_generics_cache, _typed_dict_helper CANNOT_SUBCLASS_TYPE = 'Cannot subclass special typing classes' diff --git a/Lib/test/_typed_dict_helper.py b/Lib/test/typinganndata/_typed_dict_helper.py similarity index 100% rename from Lib/test/_typed_dict_helper.py rename to Lib/test/typinganndata/_typed_dict_helper.py diff --git a/Lib/test/mod_generics_cache.py b/Lib/test/typinganndata/mod_generics_cache.py similarity index 100% rename from Lib/test/mod_generics_cache.py rename to Lib/test/typinganndata/mod_generics_cache.py From 759168a2a9b6d56f3274ded92d376e472da3b99a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:10:13 +0100 Subject: [PATCH 1152/1206] [3.12] gh-111495: Add tests for PyList C API (GH-111562) (GH-111861) (cherry picked from commit a3903c8ec838f82338f7a7af68a6699118778e1d) Signed-off-by: kalyanr Co-authored-by: Kalyan Co-authored-by: Serhiy Storchaka Co-authored-by: Victor Stinner --- Lib/test/test_capi/test_list.py | 277 ++++++++++++++++++++++++++++++++ Modules/_testcapi/list.c | 180 ++++++++++++++++++++- 2 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_capi/test_list.py diff --git a/Lib/test/test_capi/test_list.py b/Lib/test/test_capi/test_list.py new file mode 100644 index 00000000000000..197da03e07fa27 --- /dev/null +++ b/Lib/test/test_capi/test_list.py @@ -0,0 +1,277 @@ +import unittest +import sys +from test.support import import_helper +from collections import UserList +_testcapi = import_helper.import_module('_testcapi') + +NULL = None +PY_SSIZE_T_MIN = _testcapi.PY_SSIZE_T_MIN +PY_SSIZE_T_MAX = _testcapi.PY_SSIZE_T_MAX + +class ListSubclass(list): + pass + + +class CAPITest(unittest.TestCase): + def test_check(self): + # Test PyList_Check() + check = _testcapi.list_check + self.assertTrue(check([1, 2])) + self.assertTrue(check([])) + self.assertTrue(check(ListSubclass([1, 2]))) + self.assertFalse(check({1: 2})) + self.assertFalse(check((1, 2))) + self.assertFalse(check(42)) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + + def test_list_check_exact(self): + # Test PyList_CheckExact() + check = _testcapi.list_check_exact + self.assertTrue(check([1])) + self.assertTrue(check([])) + self.assertFalse(check(ListSubclass([1]))) + self.assertFalse(check(UserList([1, 2]))) + self.assertFalse(check({1: 2})) + self.assertFalse(check(object())) + + # CRASHES check(NULL) + + def test_list_new(self): + # Test PyList_New() + list_new = _testcapi.list_new + lst = list_new(0) + self.assertEqual(lst, []) + self.assertIs(type(lst), list) + lst2 = list_new(0) + self.assertIsNot(lst2, lst) + self.assertRaises(SystemError, list_new, NULL) + self.assertRaises(SystemError, list_new, -1) + + def test_list_size(self): + # Test PyList_Size() + size = _testcapi.list_size + self.assertEqual(size([1, 2]), 2) + self.assertEqual(size(ListSubclass([1, 2])), 2) + self.assertRaises(SystemError, size, UserList()) + self.assertRaises(SystemError, size, {}) + self.assertRaises(SystemError, size, 23) + self.assertRaises(SystemError, size, object()) + # CRASHES size(NULL) + + def test_list_get_size(self): + # Test PyList_GET_SIZE() + size = _testcapi.list_get_size + self.assertEqual(size([1, 2]), 2) + self.assertEqual(size(ListSubclass([1, 2])), 2) + # CRASHES size(object()) + # CRASHES size(23) + # CRASHES size({}) + # CRASHES size(UserList()) + # CRASHES size(NULL) + + + def test_list_getitem(self): + # Test PyList_GetItem() + getitem = _testcapi.list_getitem + lst = [1, 2, 3] + self.assertEqual(getitem(lst, 0), 1) + self.assertEqual(getitem(lst, 2), 3) + self.assertRaises(IndexError, getitem, lst, 3) + self.assertRaises(IndexError, getitem, lst, -1) + self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN) + self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX) + self.assertRaises(SystemError, getitem, 42, 1) + self.assertRaises(SystemError, getitem, (1, 2, 3), 1) + self.assertRaises(SystemError, getitem, {1: 2}, 1) + + # CRASHES getitem(NULL, 1) + + def test_list_get_item(self): + # Test PyList_GET_ITEM() + get_item = _testcapi.list_get_item + lst = [1, 2, [1, 2, 3]] + self.assertEqual(get_item(lst, 0), 1) + self.assertEqual(get_item(lst, 2), [1, 2, 3]) + + # CRASHES for out of index: get_item(lst, 3) + # CRASHES for get_item(lst, PY_SSIZE_T_MIN) + # CRASHES for get_item(lst, PY_SSIZE_T_MAX) + # CRASHES get_item(21, 2) + # CRASHES get_item(NULL, 1) + + + def test_list_setitem(self): + # Test PyList_SetItem() + setitem = _testcapi.list_setitem + lst = [1, 2, 3] + setitem(lst, 0, 10) + self.assertEqual(lst, [10, 2, 3]) + setitem(lst, 2, 12) + self.assertEqual(lst, [10, 2, 12]) + self.assertRaises(IndexError, setitem, lst, 3 , 5) + self.assertRaises(IndexError, setitem, lst, -1, 5) + self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MIN, 5) + self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MAX, 5) + self.assertRaises(SystemError, setitem, (1, 2, 3), 1, 5) + self.assertRaises(SystemError, setitem, {1: 2}, 1, 5) + + # CRASHES setitem(NULL, 'a', 5) + + def test_list_set_item(self): + # Test PyList_SET_ITEM() + set_item = _testcapi.list_set_item + lst = [1, 2, 3] + set_item(lst, 1, 10) + set_item(lst, 2, [1, 2, 3]) + self.assertEqual(lst, [1, 10, [1, 2, 3]]) + + # CRASHES for set_item([1], -1, 5) + # CRASHES for set_item([1], PY_SSIZE_T_MIN, 5) + # CRASHES for set_item([1], PY_SSIZE_T_MAX, 5) + # CRASHES for set_item([], 0, 1) + # CRASHES for set_item(NULL, 0, 1) + + + def test_list_insert(self): + # Test PyList_Insert() + insert = _testcapi.list_insert + lst = [1, 2, 3] + insert(lst, 0, 23) + self.assertEqual(lst, [23, 1, 2, 3]) + insert(lst, -1, 22) + self.assertEqual(lst, [23, 1, 2, 22, 3]) + insert(lst, PY_SSIZE_T_MIN, 1) + self.assertEqual(lst[0], 1) + insert(lst, len(lst), 123) + self.assertEqual(lst[-1], 123) + insert(lst, len(lst)-1, 124) + self.assertEqual(lst[-2], 124) + insert(lst, PY_SSIZE_T_MAX, 223) + self.assertEqual(lst[-1], 223) + + self.assertRaises(SystemError, insert, (1, 2, 3), 1, 5) + self.assertRaises(SystemError, insert, {1: 2}, 1, 5) + + # CRASHES insert(NULL, 1, 5) + + def test_list_append(self): + # Test PyList_Append() + append = _testcapi.list_append + lst = [1, 2, 3] + append(lst, 10) + self.assertEqual(lst, [1, 2, 3, 10]) + append(lst, [4, 5]) + self.assertEqual(lst, [1, 2, 3, 10, [4, 5]]) + self.assertRaises(SystemError, append, lst, NULL) + self.assertRaises(SystemError, append, (), 0) + self.assertRaises(SystemError, append, 42, 0) + # CRASHES append(NULL, 0) + + def test_list_getslice(self): + # Test PyList_GetSlice() + getslice = _testcapi.list_getslice + lst = [1, 2, 3] + + # empty + self.assertEqual(getslice(lst, PY_SSIZE_T_MIN, 0), []) + self.assertEqual(getslice(lst, -1, 0), []) + self.assertEqual(getslice(lst, 3, PY_SSIZE_T_MAX), []) + + # slice + self.assertEqual(getslice(lst, 1, 3), [2, 3]) + + # whole + self.assertEqual(getslice(lst, 0, len(lst)), lst) + self.assertEqual(getslice(lst, 0, 100), lst) + self.assertEqual(getslice(lst, -100, 100), lst) + + self.assertRaises(SystemError, getslice, (1, 2, 3), 0, 0) + self.assertRaises(SystemError, getslice, 'abc', 0, 0) + self.assertRaises(SystemError, getslice, 42, 0, 0) + + # CRASHES getslice(NULL, 0, 0) + + def test_list_setslice(self): + # Test PyList_SetSlice() + setslice = _testcapi.list_setslice + def set_slice(lst, low, high, value): + lst = lst.copy() + self.assertEqual(setslice(lst, low, high, value), 0) + return lst + + # insert items + self.assertEqual(set_slice([], 0, 0, list("abc")), list("abc")) + self.assertEqual(set_slice([], PY_SSIZE_T_MIN, PY_SSIZE_T_MIN, list("abc")), list("abc")) + self.assertEqual(set_slice([], PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, list("abc")), list("abc")) + lst = list("abc") + self.assertEqual(set_slice(lst, 0, 0, ["X"]), list("Xabc")) + self.assertEqual(set_slice(lst, 1, 1, list("XY")), list("aXYbc")) + self.assertEqual(set_slice(lst, len(lst), len(lst), ["X"]), list("abcX")) + # self.assertEqual(set_slice(lst, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, ["X"]), list("abcX")) + + # replace items + lst = list("abc") + self.assertEqual(set_slice(lst, -100, 1, list("X")), list("Xbc")) + self.assertEqual(set_slice(lst, 1, 2, list("X")), list("aXc")) + self.assertEqual(set_slice(lst, 1, 3, list("XY")), list("aXY")) + self.assertEqual(set_slice(lst, 0, 3, list("XYZ")), list("XYZ")) + + # delete items + lst = list("abcdef") + self.assertEqual(set_slice(lst, 0, len(lst), []), []) + self.assertEqual(set_slice(lst, -100, 100, []), []) + self.assertEqual(set_slice(lst, 1, 5, []), list("af")) + self.assertEqual(set_slice(lst, 3, len(lst), []), list("abc")) + + # delete items with NULL + lst = list("abcdef") + self.assertEqual(set_slice(lst, 0, len(lst), NULL), []) + self.assertEqual(set_slice(lst, 3, len(lst), NULL), list("abc")) + + self.assertRaises(SystemError, setslice, (), 0, 0, []) + self.assertRaises(SystemError, setslice, 42, 0, 0, []) + + # CRASHES setslice(NULL, 0, 0, []) + + def test_list_sort(self): + # Test PyList_Sort() + sort = _testcapi.list_sort + lst = [4, 6, 7, 3, 1, 5, 9, 2, 0, 8] + sort(lst) + self.assertEqual(lst, list(range(10))) + + lst2 = ListSubclass([4, 6, 7, 3, 1, 5, 9, 2, 0, 8]) + sort(lst2) + self.assertEqual(lst2, list(range(10))) + + self.assertRaises(SystemError, sort, ()) + self.assertRaises(SystemError, sort, object()) + self.assertRaises(SystemError, sort, NULL) + + + def test_list_reverse(self): + # Test PyList_Reverse() + reverse = _testcapi.list_reverse + def list_reverse(lst): + self.assertEqual(reverse(lst), 0) + return lst + + self.assertEqual(list_reverse([]), []) + self.assertEqual(list_reverse([2, 5, 10]), [10, 5, 2]) + + self.assertRaises(SystemError, reverse, ()) + self.assertRaises(SystemError, reverse, object()) + self.assertRaises(SystemError, reverse, NULL) + + def test_list_astuple(self): + # Test PyList_AsTuple() + astuple = _testcapi.list_astuple + self.assertEqual(astuple([]), ()) + self.assertEqual(astuple([2, 5, 10]), (2, 5, 10)) + + self.assertRaises(SystemError, astuple, ()) + self.assertRaises(SystemError, astuple, object()) + self.assertRaises(SystemError, astuple, NULL) diff --git a/Modules/_testcapi/list.c b/Modules/_testcapi/list.c index 9329ddc3bddab4..6ba0e7ab27c5d7 100644 --- a/Modules/_testcapi/list.c +++ b/Modules/_testcapi/list.c @@ -1,15 +1,193 @@ #include "parts.h" #include "util.h" +static PyObject * +list_check(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyList_Check(obj)); +} + +static PyObject * +list_check_exact(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyLong_FromLong(PyList_CheckExact(obj)); +} + +static PyObject * +list_new(PyObject* Py_UNUSED(module), PyObject *obj) +{ + return PyList_New(PyLong_AsSsize_t(obj)); +} + +static PyObject * +list_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyList_Size(obj)); +} + +static PyObject * +list_get_size(PyObject *Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_SIZE(PyList_GET_SIZE(obj)); +} + +static PyObject * +list_getitem(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &obj, &i)) { + return NULL; + } + NULLABLE(obj); + return Py_XNewRef(PyList_GetItem(obj, i)); +} + +static PyObject * +list_get_item(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "On", &obj, &i)) { + return NULL; + } + NULLABLE(obj); + return Py_XNewRef(PyList_GET_ITEM(obj, i)); +} + +static PyObject * +list_setitem(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "OnO", &obj, &i, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyList_SetItem(obj, i, Py_XNewRef(value))); + +} + +static PyObject * +list_set_item(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t i; + if (!PyArg_ParseTuple(args, "OnO", &obj, &i, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + PyList_SET_ITEM(obj, i, Py_XNewRef(value)); + Py_RETURN_NONE; + +} + +static PyObject * +list_insert(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t where; + if (!PyArg_ParseTuple(args, "OnO", &obj, &where, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyList_Insert(obj, where, Py_XNewRef(value))); + +} + +static PyObject * +list_append(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + if (!PyArg_ParseTuple(args, "OO", &obj, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyList_Append(obj, value)); +} + +static PyObject * +list_getslice(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj; + Py_ssize_t ilow, ihigh; + if (!PyArg_ParseTuple(args, "Onn", &obj, &ilow, &ihigh)) { + return NULL; + } + NULLABLE(obj); + return PyList_GetSlice(obj, ilow, ihigh); + +} + +static PyObject * +list_setslice(PyObject *Py_UNUSED(module), PyObject *args) +{ + PyObject *obj, *value; + Py_ssize_t ilow, ihigh; + if (!PyArg_ParseTuple(args, "OnnO", &obj, &ilow, &ihigh, &value)) { + return NULL; + } + NULLABLE(obj); + NULLABLE(value); + RETURN_INT(PyList_SetSlice(obj, ilow, ihigh, value)); +} + +static PyObject * +list_sort(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyList_Sort(obj)); +} + +static PyObject * +list_reverse(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + RETURN_INT(PyList_Reverse(obj)); +} + +static PyObject * +list_astuple(PyObject* Py_UNUSED(module), PyObject *obj) +{ + NULLABLE(obj); + return PyList_AsTuple(obj); +} + + + static PyMethodDef test_methods[] = { + {"list_check", list_check, METH_O}, + {"list_check_exact", list_check_exact, METH_O}, + {"list_new", list_new, METH_O}, + {"list_size", list_size, METH_O}, + {"list_get_size", list_get_size, METH_O}, + {"list_getitem", list_getitem, METH_VARARGS}, + {"list_get_item", list_get_item, METH_VARARGS}, + {"list_setitem", list_setitem, METH_VARARGS}, + {"list_set_item", list_set_item, METH_VARARGS}, + {"list_insert", list_insert, METH_VARARGS}, + {"list_append", list_append, METH_VARARGS}, + {"list_getslice", list_getslice, METH_VARARGS}, + {"list_setslice", list_setslice, METH_VARARGS}, + {"list_sort", list_sort, METH_O}, + {"list_reverse", list_reverse, METH_O}, + {"list_astuple", list_astuple, METH_O}, {NULL}, }; int _PyTestCapi_Init_List(PyObject *m) { - if (PyModule_AddFunctions(m, test_methods) < 0){ + if (PyModule_AddFunctions(m, test_methods) < 0) { return -1; } From 4f976c3b9a6b3606c12924a1adadd12f9d5f0388 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 8 Nov 2023 21:48:18 +0100 Subject: [PATCH 1153/1206] [3.12] gh-110543: Fix CodeType.replace in presence of comprehensions (GH-110586) (#111866) gh-110543: Fix CodeType.replace in presence of comprehensions (GH-110586) (cherry picked from commit 0b718e6407da65b838576a2459d630824ca62155) Co-authored-by: Jelle Zijlstra --- Lib/test/test_listcomps.py | 45 ++++++++++++++++++- ...-10-09-19-54-33.gh-issue-110543.1wrxO8.rst | 3 ++ Objects/codeobject.c | 29 ++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-09-19-54-33.gh-issue-110543.1wrxO8.rst diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 12f7bbd123b30c..f95a78aff0c711 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -1,5 +1,6 @@ import doctest import textwrap +import types import unittest @@ -92,7 +93,8 @@ class ListComprehensionTest(unittest.TestCase): - def _check_in_scopes(self, code, outputs=None, ns=None, scopes=None, raises=()): + def _check_in_scopes(self, code, outputs=None, ns=None, scopes=None, raises=(), + exec_func=exec): code = textwrap.dedent(code) scopes = scopes or ["module", "class", "function"] for scope in scopes: @@ -119,7 +121,7 @@ def get_output(moddict, name): return moddict[name] newns = ns.copy() if ns else {} try: - exec(newcode, newns) + exec_func(newcode, newns) except raises as e: # We care about e.g. NameError vs UnboundLocalError self.assertIs(type(e), raises) @@ -613,6 +615,45 @@ def test_frame_locals(self): import sys self._check_in_scopes(code, {"val": 0}, ns={"sys": sys}) + def _recursive_replace(self, maybe_code): + if not isinstance(maybe_code, types.CodeType): + return maybe_code + return maybe_code.replace(co_consts=tuple( + self._recursive_replace(c) for c in maybe_code.co_consts + )) + + def _replacing_exec(self, code_string, ns): + co = compile(code_string, "", "exec") + co = self._recursive_replace(co) + exec(co, ns) + + def test_code_replace(self): + code = """ + x = 3 + [x for x in (1, 2)] + dir() + y = [x] + """ + self._check_in_scopes(code, {"y": [3], "x": 3}) + self._check_in_scopes(code, {"y": [3], "x": 3}, exec_func=self._replacing_exec) + + def test_code_replace_extended_arg(self): + num_names = 300 + assignments = "; ".join(f"x{i} = {i}" for i in range(num_names)) + name_list = ", ".join(f"x{i}" for i in range(num_names)) + expected = { + "y": list(range(num_names)), + **{f"x{i}": i for i in range(num_names)} + } + code = f""" + {assignments} + [({name_list}) for {name_list} in (range(300),)] + dir() + y = [{name_list}] + """ + self._check_in_scopes(code, expected) + self._check_in_scopes(code, expected, exec_func=self._replacing_exec) + __test__ = {'doctests' : doctests} diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-09-19-54-33.gh-issue-110543.1wrxO8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-09-19-54-33.gh-issue-110543.1wrxO8.rst new file mode 100644 index 00000000000000..5f9571566da18d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-09-19-54-33.gh-issue-110543.1wrxO8.rst @@ -0,0 +1,3 @@ +Fix regression in Python 3.12 where :meth:`types.CodeType.replace` would +produce a broken code object if called on a module or class code object that +contains a comprehension. Patch by Jelle Zijlstra. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index aee1213632e490..cda2d2f544ef60 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -665,6 +665,35 @@ PyUnstable_Code_NewWithPosOnlyArgs( _Py_set_localsplus_info(offset, name, CO_FAST_FREE, localsplusnames, localspluskinds); } + + // gh-110543: Make sure the CO_FAST_HIDDEN flag is set correctly. + if (!(flags & CO_OPTIMIZED)) { + Py_ssize_t code_len = PyBytes_GET_SIZE(code); + _Py_CODEUNIT *code_data = (_Py_CODEUNIT *)PyBytes_AS_STRING(code); + Py_ssize_t num_code_units = code_len / sizeof(_Py_CODEUNIT); + int extended_arg = 0; + for (int i = 0; i < num_code_units; i += 1 + _PyOpcode_Caches[code_data[i].op.code]) { + _Py_CODEUNIT *instr = &code_data[i]; + uint8_t opcode = instr->op.code; + if (opcode == EXTENDED_ARG) { + extended_arg = extended_arg << 8 | instr->op.arg; + continue; + } + if (opcode == LOAD_FAST_AND_CLEAR) { + int oparg = extended_arg << 8 | instr->op.arg; + if (oparg >= nlocalsplus) { + PyErr_Format(PyExc_ValueError, + "code: LOAD_FAST_AND_CLEAR oparg %d out of range", + oparg); + goto error; + } + _PyLocals_Kind kind = _PyLocals_GetKind(localspluskinds, oparg); + _PyLocals_SetKind(localspluskinds, oparg, kind | CO_FAST_HIDDEN); + } + extended_arg = 0; + } + } + // If any cells were args then nlocalsplus will have shrunk. if (nlocalsplus != PyTuple_GET_SIZE(localsplusnames)) { if (_PyTuple_Resize(&localsplusnames, nlocalsplus) < 0 From e11ea5a400ba1d52e948d50925f52ed664fd74b8 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:41:44 +0100 Subject: [PATCH 1154/1206] [3.12] gh-108303: Move config parser data to `Lib/test/configparserdata/` (gh-111879) (gh-111882) gh-108303: Move config parser data to `Lib/test/configparserdata/` (gh-111879) (cherry picked from commit cc18b886a51672c59622837a2b8e83bf6be28c58) Co-authored-by: Nikita Sobolev --- Lib/idlelib/idle_test/test_config.py | 8 ++++---- Lib/test/{ => configdata}/cfgparser.1 | 0 Lib/test/{ => configdata}/cfgparser.2 | 0 Lib/test/{ => configdata}/cfgparser.3 | 0 Lib/test/test_configparser.py | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) rename Lib/test/{ => configdata}/cfgparser.1 (100%) rename Lib/test/{ => configdata}/cfgparser.2 (100%) rename Lib/test/{ => configdata}/cfgparser.3 (100%) diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py index a746f1538a62b0..6d75cf7aa67dcc 100644 --- a/Lib/idlelib/idle_test/test_config.py +++ b/Lib/idlelib/idle_test/test_config.py @@ -85,8 +85,8 @@ def test_load_nothing(self): self.assertEqual(parser.sections(), []) def test_load_file(self): - # Borrow test/cfgparser.1 from test_configparser. - config_path = findfile('cfgparser.1') + # Borrow test/configdata/cfgparser.1 from test_configparser. + config_path = findfile('cfgparser.1', subdir='configdata') parser = config.IdleConfParser(config_path) parser.Load() @@ -294,8 +294,8 @@ def test_create_config_handlers(self): def test_load_cfg_files(self): conf = self.new_config(_utest=True) - # Borrow test/cfgparser.1 from test_configparser. - config_path = findfile('cfgparser.1') + # Borrow test/configdata/cfgparser.1 from test_configparser. + config_path = findfile('cfgparser.1', subdir='configdata') conf.defaultCfg['foo'] = config.IdleConfParser(config_path) conf.userCfg['foo'] = config.IdleUserConfParser(config_path) diff --git a/Lib/test/cfgparser.1 b/Lib/test/configdata/cfgparser.1 similarity index 100% rename from Lib/test/cfgparser.1 rename to Lib/test/configdata/cfgparser.1 diff --git a/Lib/test/cfgparser.2 b/Lib/test/configdata/cfgparser.2 similarity index 100% rename from Lib/test/cfgparser.2 rename to Lib/test/configdata/cfgparser.2 diff --git a/Lib/test/cfgparser.3 b/Lib/test/configdata/cfgparser.3 similarity index 100% rename from Lib/test/cfgparser.3 rename to Lib/test/configdata/cfgparser.3 diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index da17c00063c56d..14e4a2cf144409 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -544,7 +544,7 @@ def test_parse_errors(self): "[Foo]\n wrong-indent\n") self.assertEqual(e.args, ('',)) # read_file on a real file - tricky = support.findfile("cfgparser.3") + tricky = support.findfile("cfgparser.3", subdir="configdata") if self.delimiters[0] == '=': error = configparser.ParsingError expected = (tricky,) @@ -718,7 +718,7 @@ class mystr(str): def test_read_returns_file_list(self): if self.delimiters[0] != '=': self.skipTest('incompatible format') - file1 = support.findfile("cfgparser.1") + file1 = support.findfile("cfgparser.1", subdir="configdata") # check when we pass a mix of readable and non-readable files: cf = self.newconfig() parsed_files = cf.read([file1, "nonexistent-file"], encoding="utf-8") @@ -751,7 +751,7 @@ def test_read_returns_file_list(self): def test_read_returns_file_list_with_bytestring_path(self): if self.delimiters[0] != '=': self.skipTest('incompatible format') - file1_bytestring = support.findfile("cfgparser.1").encode() + file1_bytestring = support.findfile("cfgparser.1", subdir="configdata").encode() # check when passing an existing bytestring path cf = self.newconfig() parsed_files = cf.read(file1_bytestring, encoding="utf-8") @@ -1161,7 +1161,7 @@ class RawConfigParserTestSambaConf(CfgParserTestCaseClass, unittest.TestCase): empty_lines_in_values = False def test_reading(self): - smbconf = support.findfile("cfgparser.2") + smbconf = support.findfile("cfgparser.2", subdir="configdata") # check when we pass a mix of readable and non-readable files: cf = self.newconfig() parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8') @@ -1356,7 +1356,7 @@ class ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass, unittest.TestCase): allow_no_value = True def test_cfgparser_dot_3(self): - tricky = support.findfile("cfgparser.3") + tricky = support.findfile("cfgparser.3", subdir="configdata") cf = self.newconfig() self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1) self.assertEqual(cf.sections(), ['strange', @@ -1388,7 +1388,7 @@ def test_cfgparser_dot_3(self): self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping') def test_unicode_failure(self): - tricky = support.findfile("cfgparser.3") + tricky = support.findfile("cfgparser.3", subdir="configdata") cf = self.newconfig() with self.assertRaises(UnicodeDecodeError): cf.read(tricky, encoding='ascii') @@ -1489,7 +1489,7 @@ def fromstring(self, string, defaults=None): class FakeFile: def __init__(self): - file_path = support.findfile("cfgparser.1") + file_path = support.findfile("cfgparser.1", subdir="configdata") with open(file_path, encoding="utf-8") as f: self.lines = f.readlines() self.lines.reverse() @@ -1510,7 +1510,7 @@ def readline_generator(f): class ReadFileTestCase(unittest.TestCase): def test_file(self): - file_paths = [support.findfile("cfgparser.1")] + file_paths = [support.findfile("cfgparser.1", subdir="configdata")] try: file_paths.append(file_paths[0].encode('utf8')) except UnicodeEncodeError: From e0d827d479ae9970a3e80258d11667fe42f85039 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Nov 2023 16:21:24 +0100 Subject: [PATCH 1155/1206] [3.12] gh-108303: Move more files to `Lib/test/test_module` (GH-111880) (#111891) gh-108303: Move more files to `Lib/test/test_module` (GH-111880) (cherry picked from commit 0c42f7304a2757fe0f78bc6c6fbb33225cd9da15) Co-authored-by: Nikita Sobolev --- Lib/test/test_module/__init__.py | 2 +- Lib/test/{ => test_module}/final_a.py | 4 ++-- Lib/test/{ => test_module}/final_b.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename Lib/test/{ => test_module}/final_a.py (79%) rename Lib/test/{ => test_module}/final_b.py (79%) diff --git a/Lib/test/test_module/__init__.py b/Lib/test/test_module/__init__.py index 2524e6c87cb459..db2133a9e8d17b 100644 --- a/Lib/test/test_module/__init__.py +++ b/Lib/test/test_module/__init__.py @@ -266,7 +266,7 @@ def test_module_repr_source(self): def test_module_finalization_at_shutdown(self): # Module globals and builtins should still be available during shutdown - rc, out, err = assert_python_ok("-c", "from test import final_a") + rc, out, err = assert_python_ok("-c", "from test.test_module import final_a") self.assertFalse(err) lines = out.splitlines() self.assertEqual(set(lines), { diff --git a/Lib/test/final_a.py b/Lib/test/test_module/final_a.py similarity index 79% rename from Lib/test/final_a.py rename to Lib/test/test_module/final_a.py index 390ee8895a8a9e..a983f3111248e0 100644 --- a/Lib/test/final_a.py +++ b/Lib/test/test_module/final_a.py @@ -3,7 +3,7 @@ """ import shutil -import test.final_b +import test.test_module.final_b x = 'a' @@ -11,7 +11,7 @@ class C: def __del__(self): # Inspect module globals and builtins print("x =", x) - print("final_b.x =", test.final_b.x) + print("final_b.x =", test.test_module.final_b.x) print("shutil.rmtree =", getattr(shutil.rmtree, '__name__', None)) print("len =", getattr(len, '__name__', None)) diff --git a/Lib/test/final_b.py b/Lib/test/test_module/final_b.py similarity index 79% rename from Lib/test/final_b.py rename to Lib/test/test_module/final_b.py index 7228d82b880156..f3e8d5594904f2 100644 --- a/Lib/test/final_b.py +++ b/Lib/test/test_module/final_b.py @@ -3,7 +3,7 @@ """ import shutil -import test.final_a +import test.test_module.final_a x = 'b' @@ -11,7 +11,7 @@ class C: def __del__(self): # Inspect module globals and builtins print("x =", x) - print("final_a.x =", test.final_a.x) + print("final_a.x =", test.test_module.final_a.x) print("shutil.rmtree =", getattr(shutil.rmtree, '__name__', None)) print("len =", getattr(len, '__name__', None)) From e983ca859de279682631dbb13b959f14a7d89a7b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 9 Nov 2023 16:23:58 +0100 Subject: [PATCH 1156/1206] [3.12] gh-111881: Use lazy import in test.support (#111885) (#111890) gh-111881: Use lazy import in test.support (#111885) * Import lazily getpass in test.support * Only import ctypes on Windows in test.support.os_helper. (cherry picked from commit 0372e3b02a7e3dc1c564dba94dcd817c5472b04f) --- Lib/test/support/__init__.py | 2 +- Lib/test/support/os_helper.py | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 650d4aa7d4d84b..fd9265c93c35f3 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -6,7 +6,6 @@ import contextlib import dataclasses import functools -import getpass import opcode import os import re @@ -382,6 +381,7 @@ def wrapper(*args, **kw): def skip_if_buildbot(reason=None): """Decorator raising SkipTest if running on a buildbot.""" + import getpass if not reason: reason = 'not suitable for buildbots' try: diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py index 821a4b1ffd5077..46ae53aa11a91f 100644 --- a/Lib/test/support/os_helper.py +++ b/Lib/test/support/os_helper.py @@ -10,6 +10,8 @@ import unittest import warnings +from test import support + # Filename used for testing TESTFN_ASCII = '@test' @@ -720,13 +722,16 @@ def __exit__(self, *ignore_exc): try: - import ctypes - kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) - - ERROR_FILE_NOT_FOUND = 2 - DDD_REMOVE_DEFINITION = 2 - DDD_EXACT_MATCH_ON_REMOVE = 4 - DDD_NO_BROADCAST_SYSTEM = 8 + if support.MS_WINDOWS: + import ctypes + kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) + + ERROR_FILE_NOT_FOUND = 2 + DDD_REMOVE_DEFINITION = 2 + DDD_EXACT_MATCH_ON_REMOVE = 4 + DDD_NO_BROADCAST_SYSTEM = 8 + else: + raise AttributeError except (ImportError, AttributeError): def subst_drive(path): raise unittest.SkipTest('ctypes or kernel32 is not available') From 5089faf954d2c6c07e1acfd5d270c331f7c6acdc Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Nov 2023 16:40:10 +0100 Subject: [PATCH 1157/1206] [3.12] gh-111881: Import doctest lazily in libregrtest (GH-111884) (#111893) gh-111881: Import doctest lazily in libregrtest (GH-111884) In most cases, doctest is not needed. So don't always import it at startup. The change reduces the number of modules already imported when a test is run. (cherry picked from commit 6f09f69b7f85962f66d10637c3325bbb2b2d9853) Co-authored-by: Victor Stinner --- Lib/test/libregrtest/single.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py index ad75ef54a8c3f8..5c7bc7d40fb394 100644 --- a/Lib/test/libregrtest/single.py +++ b/Lib/test/libregrtest/single.py @@ -1,4 +1,3 @@ -import doctest import faulthandler import gc import importlib @@ -99,14 +98,18 @@ def regrtest_runner(result: TestResult, test_func, runtests: RunTests) -> None: stats = test_result case unittest.TestResult(): stats = TestStats.from_unittest(test_result) - case doctest.TestResults(): - stats = TestStats.from_doctest(test_result) case None: print_warning(f"{result.test_name} test runner returned None: {test_func}") stats = None case _: - print_warning(f"Unknown test result type: {type(test_result)}") - stats = None + # Don't import doctest at top level since only few tests return + # a doctest.TestResult instance. + import doctest + if isinstance(test_result, doctest.TestResults): + stats = TestStats.from_doctest(test_result) + else: + print_warning(f"Unknown test result type: {type(test_result)}") + stats = None result.stats = stats From fe7631e558b87761f3115302070fb9f440ace874 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Nov 2023 20:13:23 +0100 Subject: [PATCH 1158/1206] [3.12] gh-111895: Convert definition list to bullet list for readability on mobile (GH-111898) (#111908) gh-111895: Convert definition list to bullet list for readability on mobile (GH-111898) Convert definition list to bullet list for readability on mobile (cherry picked from commit 7d21e3d5ee9858aee570aa6c5b6a6e87d776f4b5) Co-authored-by: Hugo van Kemenade --- Doc/howto/enum.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 0830fb630d701b..a136c76303c8ef 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -607,9 +607,9 @@ The complete signature is:: start=1, ) -:value: What the new enum class will record as its name. +* *value*: What the new enum class will record as its name. -:names: The enum members. This can be a whitespace- or comma-separated string +* *names*: The enum members. This can be a whitespace- or comma-separated string (values will start at 1 unless otherwise specified):: 'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE' @@ -626,13 +626,13 @@ The complete signature is:: {'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42} -:module: name of module where new enum class can be found. +* *module*: name of module where new enum class can be found. -:qualname: where in module new enum class can be found. +* *qualname*: where in module new enum class can be found. -:type: type to mix in to new enum class. +* *type*: type to mix in to new enum class. -:start: number to start counting at if only names are passed in. +* *start*: number to start counting at if only names are passed in. .. versionchanged:: 3.5 The *start* parameter was added. From 09df271965b5af6beeaa6a2d17a2c5a145fc5201 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 9 Nov 2023 20:34:10 +0100 Subject: [PATCH 1159/1206] =?UTF-8?q?[3.12]=20gh-110875:=20Handle=20'.'=20?= =?UTF-8?q?properties=20in=20logging=20formatter=20configuration=20c?= =?UTF-8?q?=E2=80=A6=20(GH-110943)=20(GH-111911)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vinay Sajip --- Lib/logging/config.py | 8 ++++---- Lib/test/test_logging.py | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/Lib/logging/config.py b/Lib/logging/config.py index a68281d3e359fd..8eae263a500453 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -485,10 +485,10 @@ def configure_custom(self, config): c = config.pop('()') if not callable(c): c = self.resolve(c) - props = config.pop('.', None) # Check for valid identifiers - kwargs = {k: config[k] for k in config if valid_ident(k)} + kwargs = {k: config[k] for k in config if (k != '.' and valid_ident(k))} result = c(**kwargs) + props = config.pop('.', None) if props: for name, value in props.items(): setattr(result, name, value) @@ -841,8 +841,7 @@ def configure_handler(self, config): factory = functools.partial(self._configure_queue_handler, klass) else: factory = klass - props = config.pop('.', None) - kwargs = {k: config[k] for k in config if valid_ident(k)} + kwargs = {k: config[k] for k in config if (k != '.' and valid_ident(k))} try: result = factory(**kwargs) except TypeError as te: @@ -860,6 +859,7 @@ def configure_handler(self, config): result.setLevel(logging._checkLevel(level)) if filters: self.add_filters(result, filters) + props = config.pop('.', None) if props: for name, value in props.items(): setattr(result, name, value) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index a2300daff9c735..fdae35b5dff354 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3014,6 +3014,39 @@ class ConfigDictTest(BaseTest): }, } + class CustomFormatter(logging.Formatter): + custom_property = "." + + def format(self, record): + return super().format(record) + + config17 = { + 'version': 1, + 'formatters': { + "custom": { + "()": CustomFormatter, + "style": "{", + "datefmt": "%Y-%m-%d %H:%M:%S", + "format": "{message}", # <-- to force an exception when configuring + ".": { + "custom_property": "value" + } + } + }, + 'handlers' : { + 'hand1' : { + 'class' : 'logging.StreamHandler', + 'formatter' : 'custom', + 'level' : 'NOTSET', + 'stream' : 'ext://sys.stdout', + }, + }, + 'root' : { + 'level' : 'WARNING', + 'handlers' : ['hand1'], + }, + } + bad_format = { "version": 1, "formatters": { @@ -3495,7 +3528,10 @@ def test_config16_ok(self): {'msg': 'Hello'})) self.assertEqual(result, 'Hello ++ defaultvalue') - + def test_config17_ok(self): + self.apply_config(self.config17) + h = logging._handlers['hand1'] + self.assertEqual(h.formatter.custom_property, 'value') def setup_via_listener(self, text, verify=None): text = text.encode("utf-8") From 5a8e6f8bccd7048e592f6bd45af503ce3fac95dd Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Thu, 9 Nov 2023 15:35:51 -0800 Subject: [PATCH 1160/1206] [3.12] GH-111804: Drop posix.fallocate() under WASI (GH-111869) (GH-111919) GH-111804: Drop posix.fallocate() under WASI (GH-111869) Drop posix.fallocate() under WASI. The underlying POSIX function, posix_fallocate(), was found to vary too much between implementations to remain in WASI. As such, while it was available in WASI preview1, it's been dropped in preview2. --- .../Library/2023-11-08-15-58-57.gh-issue-111804.uAXTOL.rst | 2 ++ Modules/clinic/posixmodule.c.h | 6 +++--- Modules/posixmodule.c | 7 +++++-- 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-08-15-58-57.gh-issue-111804.uAXTOL.rst diff --git a/Misc/NEWS.d/next/Library/2023-11-08-15-58-57.gh-issue-111804.uAXTOL.rst b/Misc/NEWS.d/next/Library/2023-11-08-15-58-57.gh-issue-111804.uAXTOL.rst new file mode 100644 index 00000000000000..2696f2f492a8b0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-08-15-58-57.gh-issue-111804.uAXTOL.rst @@ -0,0 +1,2 @@ +Remove posix.fallocate() under WASI as the underlying posix_fallocate() is +not available in WASI preview2. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index fb01c8dbc8d81c..3e6d429eb9e06f 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -8159,7 +8159,7 @@ os_truncate(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject #endif /* (defined HAVE_TRUNCATE || defined MS_WINDOWS) */ -#if (defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG)) +#if (defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG) && !defined(__wasi__)) PyDoc_STRVAR(os_posix_fallocate__doc__, "posix_fallocate($module, fd, offset, length, /)\n" @@ -8204,7 +8204,7 @@ os_posix_fallocate(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } -#endif /* (defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG)) */ +#endif /* (defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG) && !defined(__wasi__)) */ #if (defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG)) @@ -11999,4 +11999,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=ce77253f8879f36e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fa29739d72cfc07e input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 265c817ca6e37d..a98841f375eb5e 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -11891,7 +11891,10 @@ os_truncate_impl(PyObject *module, path_t *path, Py_off_t length) #endif -#if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG) +/* GH-111804: Due to posix_fallocate() not having consistent semantics across + OSs, support was dropped in WASI preview2. */ +#if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG) && \ + !defined(__wasi__) /*[clinic input] os.posix_fallocate @@ -11929,7 +11932,7 @@ os_posix_fallocate_impl(PyObject *module, int fd, Py_off_t offset, errno = result; return posix_error(); } -#endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG */ +#endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG && !defined(__wasi__) */ #if defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG) From 4018209fff7ba1be3cc1f919f0bebc931febbf82 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 10 Nov 2023 09:17:02 +0200 Subject: [PATCH 1161/1206] [3.12] gh-109370: Fix unexpected traceback output in test_concurrent_futures (GH-109780) (GH-111934) Follow-up of gh-107219. * Only close the connection writer on Windows. * Also use existing constant _winapi.ERROR_OPERATION_ABORTED instead of WSA_OPERATION_ABORTED. (cherry picked from commit 0b4e090422db5f959184353d53552d1675f74212) --- Lib/concurrent/futures/process.py | 3 ++- Lib/multiprocessing/connection.py | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 8359a4fce6520d..33e62fe231e187 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -526,7 +526,8 @@ def _terminate_broken(self, cause): # gh-107219: Close the connection writer which can unblock # Queue._feed() if it was stuck in send_bytes(). - self.call_queue._writer.close() + if sys.platform == 'win32': + self.call_queue._writer.close() # clean up resources self._join_executor_internals(broken=True) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 7c425a2d8e7034..dbbf106f680964 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -42,7 +42,6 @@ BUFSIZE = 8192 # A very generous timeout when it comes to local connections... CONNECTION_TIMEOUT = 20. -WSA_OPERATION_ABORTED = 995 _mmap_counter = itertools.count() @@ -300,7 +299,7 @@ def _send_bytes(self, buf): finally: self._send_ov = None nwritten, err = ov.GetOverlappedResult(True) - if err == WSA_OPERATION_ABORTED: + if err == _winapi.ERROR_OPERATION_ABORTED: # close() was called by another thread while # WaitForMultipleObjects() was waiting for the overlapped # operation. From 95141aa7155afe3c98d6cbe0c8eb425a15d54b23 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:37:19 +0100 Subject: [PATCH 1162/1206] gh-111356: io: Add missing documented objects to io.__all__ (GH-111370) Add DEFAULT_BUFFER_SIZE, text_encoding, and IncrementalNewlineDecoder. (cherry picked from commit baeb7718f8981319c5cb1fbdd46d162ded7964ea) Co-authored-by: Nicolas Tessore --- Lib/io.py | 3 ++- Lib/test/test_io.py | 24 +++++++++++-------- ...-10-30-08-50-46.gh-issue-111356.Bc8LvA.rst | 1 + 3 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-30-08-50-46.gh-issue-111356.Bc8LvA.rst diff --git a/Lib/io.py b/Lib/io.py index 50ce97436ac1d1..f0e2fa15d5abcf 100644 --- a/Lib/io.py +++ b/Lib/io.py @@ -45,7 +45,8 @@ "FileIO", "BytesIO", "StringIO", "BufferedIOBase", "BufferedReader", "BufferedWriter", "BufferedRWPair", "BufferedRandom", "TextIOBase", "TextIOWrapper", - "UnsupportedOperation", "SEEK_SET", "SEEK_CUR", "SEEK_END"] + "UnsupportedOperation", "SEEK_SET", "SEEK_CUR", "SEEK_END", + "DEFAULT_BUFFER_SIZE", "text_encoding", "IncrementalNewlineDecoder"] import _io diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index e032325fbe2578..247ecebd1a909a 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4052,19 +4052,18 @@ class PyIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest): class MiscIOTest(unittest.TestCase): + # for test__all__, actual values are set in subclasses + name_of_module = None + extra_exported = () + not_exported = () + def tearDown(self): os_helper.unlink(os_helper.TESTFN) def test___all__(self): - for name in self.io.__all__: - obj = getattr(self.io, name, None) - self.assertIsNotNone(obj, name) - if name in ("open", "open_code"): - continue - elif "error" in name.lower() or name == "UnsupportedOperation": - self.assertTrue(issubclass(obj, Exception), name) - elif not name.startswith("SEEK_"): - self.assertTrue(issubclass(obj, self.IOBase)) + support.check__all__(self, self.io, self.name_of_module, + extra=self.extra_exported, + not_exported=self.not_exported) def test_attributes(self): f = self.open(os_helper.TESTFN, "wb", buffering=0) @@ -4426,6 +4425,8 @@ def test_text_encoding(self): class CMiscIOTest(MiscIOTest): io = io + name_of_module = "io", "_io" + extra_exported = "BlockingIOError", def test_readinto_buffer_overflow(self): # Issue #18025 @@ -4490,6 +4491,9 @@ def test_daemon_threads_shutdown_stderr_deadlock(self): class PyMiscIOTest(MiscIOTest): io = pyio + name_of_module = "_pyio", "io" + extra_exported = "BlockingIOError", "open_code", + not_exported = "valid_seek_flags", @unittest.skipIf(os.name == 'nt', 'POSIX signals required for this test.') @@ -4777,7 +4781,7 @@ def load_tests(loader, tests, pattern): mocks = (MockRawIO, MisbehavedRawIO, MockFileIO, CloseFailureIO, MockNonBlockWriterIO, MockUnseekableIO, MockRawIOWithoutRead, SlowFlushRawIO) - all_members = io.__all__ + ["IncrementalNewlineDecoder"] + all_members = io.__all__ c_io_ns = {name : getattr(io, name) for name in all_members} py_io_ns = {name : getattr(pyio, name) for name in all_members} globs = globals() diff --git a/Misc/NEWS.d/next/Library/2023-10-30-08-50-46.gh-issue-111356.Bc8LvA.rst b/Misc/NEWS.d/next/Library/2023-10-30-08-50-46.gh-issue-111356.Bc8LvA.rst new file mode 100644 index 00000000000000..a821b52b982175 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-30-08-50-46.gh-issue-111356.Bc8LvA.rst @@ -0,0 +1 @@ +Added :func:`io.text_encoding()`, :data:`io.DEFAULT_BUFFER_SIZE`, and :class:`io.IncrementalNewlineDecoder` to ``io.__all__``. From 5f42a2bc4017f2ed023f9cf19fdbffabd57527f5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 10 Nov 2023 10:32:06 +0100 Subject: [PATCH 1163/1206] gh-111929: Fix regrtest --pgo: test_str => test_unicode (#111938) test_unicode was renamed to test_str in Python 3.13, but Python 3.12 still uses test_unicode name. --- Lib/test/libregrtest/pgo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/libregrtest/pgo.py b/Lib/test/libregrtest/pgo.py index e3a6927be5db1d..cabbba73d5eff5 100644 --- a/Lib/test/libregrtest/pgo.py +++ b/Lib/test/libregrtest/pgo.py @@ -42,10 +42,10 @@ 'test_set', 'test_sqlite3', 'test_statistics', - 'test_str', 'test_struct', 'test_tabnanny', 'test_time', + 'test_unicode', 'test_xml_etree', 'test_xml_etree_c', ] From 881c9eb962608da8deb4d48fe1642f714ce00b91 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:32:21 +0100 Subject: [PATCH 1164/1206] [3.12] gh-108303: Install `Lib/test/configdata` (GH-111899) (#111946) gh-108303: Install `Lib/test/configdata` (GH-111899) (cherry picked from commit 65d6dc27156112ac6a9f722b7b62529c94e0344b) Co-authored-by: Nikita Sobolev --- Makefile.pre.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.pre.in b/Makefile.pre.in index 0cb9db744433a9..812bc93055e58e 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2121,6 +2121,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/certdata/capath \ test/cjkencodings \ test/crashers \ + test/configdata \ test/data \ test/decimaltestdata \ test/dtracedata \ From 4b0c875d91727440251a8427a80d8515e39d18cd Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 10 Nov 2023 14:07:45 +0100 Subject: [PATCH 1165/1206] [3.12] gh-109181: Fix refleak in tb_get_lineno() (#111948) PyFrame_GetCode() returns a strong reference. --- Python/traceback.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/traceback.c b/Python/traceback.c index b627b06df7e6a7..fdaf19d37074dd 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -111,7 +111,10 @@ static int tb_get_lineno(PyTracebackObject* tb) { PyFrameObject* frame = tb->tb_frame; assert(frame != NULL); - return PyCode_Addr2Line(PyFrame_GetCode(frame), tb->tb_lasti); + PyCodeObject *code = PyFrame_GetCode(frame); + int lineno = PyCode_Addr2Line(code, tb->tb_lasti); + Py_DECREF(code); + return lineno; } static PyObject * From 37804149ec432af9049d31a740f3422d0c29caa3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Nov 2023 15:00:48 +0100 Subject: [PATCH 1166/1206] [3.12] gh-103791: handle `BaseExceptionGroup` in `contextlib.suppress()` (GH-111910) (#111955) gh-103791: handle `BaseExceptionGroup` in `contextlib.suppress()` (GH-111910) (cherry picked from commit d61313bdb1eee3e4bb111e0b248ac2dbb48be917) Co-authored-by: Zac Hatfield-Dodds --- Doc/library/contextlib.rst | 6 +++--- Lib/contextlib.py | 2 +- Lib/test/test_contextlib.py | 18 ++++++++++++++++++ ...3-11-09-10-45-56.gh-issue-103791.sdfkja.rst | 3 +++ 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 66b9c137105223..f6ebbfacfba509 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -304,15 +304,15 @@ Functions and classes provided: This context manager is :ref:`reentrant `. - If the code within the :keyword:`!with` block raises an - :exc:`ExceptionGroup`, suppressed exceptions are removed from the + If the code within the :keyword:`!with` block raises a + :exc:`BaseExceptionGroup`, suppressed exceptions are removed from the group. If any exceptions in the group are not suppressed, a group containing them is re-raised. .. versionadded:: 3.4 .. versionchanged:: 3.12 ``suppress`` now supports suppressing exceptions raised as - part of an :exc:`ExceptionGroup`. + part of an :exc:`BaseExceptionGroup`. .. function:: redirect_stdout(new_target) diff --git a/Lib/contextlib.py b/Lib/contextlib.py index 2efed2d9ec4742..b831d8916ca6cf 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -457,7 +457,7 @@ def __exit__(self, exctype, excinst, exctb): return if issubclass(exctype, self._exceptions): return True - if issubclass(exctype, ExceptionGroup): + if issubclass(exctype, BaseExceptionGroup): match, rest = excinst.split(self._exceptions) if rest is None: return True diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index 3cc194417f257e..a50a4ed7ee4912 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -1287,6 +1287,24 @@ def test_exception_groups(self): [KeyError("ke1"), KeyError("ke2")], ), ) + # Check handling of BaseExceptionGroup, using GeneratorExit so that + # we don't accidentally discard a ctrl-c with KeyboardInterrupt. + with suppress(GeneratorExit): + raise BaseExceptionGroup("message", [GeneratorExit()]) + # If we raise a BaseException group, we can still suppress parts + with self.assertRaises(BaseExceptionGroup) as eg1: + with suppress(KeyError): + raise BaseExceptionGroup("message", [GeneratorExit("g"), KeyError("k")]) + self.assertExceptionIsLike( + eg1.exception, BaseExceptionGroup("message", [GeneratorExit("g")]), + ) + # If we suppress all the leaf BaseExceptions, we get a non-base ExceptionGroup + with self.assertRaises(ExceptionGroup) as eg1: + with suppress(GeneratorExit): + raise BaseExceptionGroup("message", [GeneratorExit("g"), KeyError("k")]) + self.assertExceptionIsLike( + eg1.exception, ExceptionGroup("message", [KeyError("k")]), + ) class TestChdir(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst b/Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst new file mode 100644 index 00000000000000..5bfdd75ccc93e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-09-10-45-56.gh-issue-103791.sdfkja.rst @@ -0,0 +1,3 @@ +:class:`contextlib.suppress` now supports suppressing exceptions raised as +part of a :exc:`BaseExceptionGroup`, in addition to the recent support for +:exc:`ExceptionGroup`. From 41b2d8c7fad084c7a279edfc26f8ceda41a62ca0 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Nov 2023 15:12:39 +0100 Subject: [PATCH 1167/1206] [3.12] gh-111912: Run test_posix on Windows (GH-111913) (GH-111953) (cherry picked from commit 64fea3211d08082236d05c38ee728f922eb7d8ed) Co-authored-by: Serhiy Storchaka --- Lib/test/test_posix.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 9d72dba159c6be..7440779d7200dd 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -6,9 +6,6 @@ from test.support import warnings_helper from test.support.script_helper import assert_python_ok -# Skip these tests if there is no posix module. -posix = import_helper.import_module('posix') - import errno import sys import signal @@ -22,6 +19,11 @@ import textwrap from contextlib import contextmanager +try: + import posix +except ImportError: + import nt as posix + try: import pwd except ImportError: @@ -1009,6 +1011,7 @@ def test_environ(self): self.assertEqual(type(k), item_type) self.assertEqual(type(v), item_type) + @unittest.skipUnless(os.name == 'posix', "see bug gh-111841") def test_putenv(self): with self.assertRaises(ValueError): os.putenv('FRUIT\0VEGETABLE', 'cabbage') @@ -1220,6 +1223,7 @@ def test_sched_setaffinity(self): self.assertRaises(OSError, posix.sched_setaffinity, -1, mask) @unittest.skipIf(support.is_wasi, "No dynamic linking on WASI") + @unittest.skipUnless(os.name == 'posix', "POSIX-only test") def test_rtld_constants(self): # check presence of major RTLD_* constants posix.RTLD_LAZY From 2c6000cba496ed572a682a41ba20a1b58534c45a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Nov 2023 15:58:00 +0100 Subject: [PATCH 1168/1206] [3.12] gh-111251: Fix error checking in _blake2 module init (GH-111252) (#111297) Co-authored-by: Nikita Sobolev --- ...-10-24-12-09-46.gh-issue-111251.urFYtn.rst | 1 + Modules/_blake2/blake2module.c | 25 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-24-12-09-46.gh-issue-111251.urFYtn.rst diff --git a/Misc/NEWS.d/next/Library/2023-10-24-12-09-46.gh-issue-111251.urFYtn.rst b/Misc/NEWS.d/next/Library/2023-10-24-12-09-46.gh-issue-111251.urFYtn.rst new file mode 100644 index 00000000000000..3a87cb25da5cb4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-24-12-09-46.gh-issue-111251.urFYtn.rst @@ -0,0 +1 @@ +Fix :mod:`_blake2` not checking for errors when initializing. diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c index 0d1d88c6603684..5df9fd3df493ee 100644 --- a/Modules/_blake2/blake2module.c +++ b/Modules/_blake2/blake2module.c @@ -74,6 +74,12 @@ _blake2_free(void *module) Py_DECREF(x); \ } while(0) +#define ADD_INT_CONST(NAME, VALUE) do { \ + if (PyModule_AddIntConstant(m, NAME, VALUE) < 0) { \ + return -1; \ + } \ +} while (0) + static int blake2_exec(PyObject *m) { @@ -95,10 +101,10 @@ blake2_exec(PyObject *m) ADD_INT(d, "MAX_KEY_SIZE", BLAKE2B_KEYBYTES); ADD_INT(d, "MAX_DIGEST_SIZE", BLAKE2B_OUTBYTES); - PyModule_AddIntConstant(m, "BLAKE2B_SALT_SIZE", BLAKE2B_SALTBYTES); - PyModule_AddIntConstant(m, "BLAKE2B_PERSON_SIZE", BLAKE2B_PERSONALBYTES); - PyModule_AddIntConstant(m, "BLAKE2B_MAX_KEY_SIZE", BLAKE2B_KEYBYTES); - PyModule_AddIntConstant(m, "BLAKE2B_MAX_DIGEST_SIZE", BLAKE2B_OUTBYTES); + ADD_INT_CONST("BLAKE2B_SALT_SIZE", BLAKE2B_SALTBYTES); + ADD_INT_CONST("BLAKE2B_PERSON_SIZE", BLAKE2B_PERSONALBYTES); + ADD_INT_CONST("BLAKE2B_MAX_KEY_SIZE", BLAKE2B_KEYBYTES); + ADD_INT_CONST("BLAKE2B_MAX_DIGEST_SIZE", BLAKE2B_OUTBYTES); /* BLAKE2s */ st->blake2s_type = (PyTypeObject *)PyType_FromModuleAndSpec( @@ -117,14 +123,17 @@ blake2_exec(PyObject *m) ADD_INT(d, "MAX_KEY_SIZE", BLAKE2S_KEYBYTES); ADD_INT(d, "MAX_DIGEST_SIZE", BLAKE2S_OUTBYTES); - PyModule_AddIntConstant(m, "BLAKE2S_SALT_SIZE", BLAKE2S_SALTBYTES); - PyModule_AddIntConstant(m, "BLAKE2S_PERSON_SIZE", BLAKE2S_PERSONALBYTES); - PyModule_AddIntConstant(m, "BLAKE2S_MAX_KEY_SIZE", BLAKE2S_KEYBYTES); - PyModule_AddIntConstant(m, "BLAKE2S_MAX_DIGEST_SIZE", BLAKE2S_OUTBYTES); + ADD_INT_CONST("BLAKE2S_SALT_SIZE", BLAKE2S_SALTBYTES); + ADD_INT_CONST("BLAKE2S_PERSON_SIZE", BLAKE2S_PERSONALBYTES); + ADD_INT_CONST("BLAKE2S_MAX_KEY_SIZE", BLAKE2S_KEYBYTES); + ADD_INT_CONST("BLAKE2S_MAX_DIGEST_SIZE", BLAKE2S_OUTBYTES); return 0; } +#undef ADD_INT +#undef ADD_INT_CONST + static PyModuleDef_Slot _blake2_slots[] = { {Py_mod_exec, blake2_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, From 3bd8b743305f0d788302df3ff08c2bb7eb0dd297 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 11 Nov 2023 09:02:08 +0100 Subject: [PATCH 1169/1206] [3.12] gh-111841: Fix os.putenv() and os.unsetenv() with embedded NUL on Windows (GH-111842) (GH-111966) (cherry picked from commit 0b06d2482d77e02c5d40e221f6046c9c355458b2) Co-authored-by: Serhiy Storchaka --- Lib/test/test_os.py | 5 ++++- Lib/test/test_posix.py | 14 +++++++------- .../2023-11-08-11-50-49.gh-issue-111841.iSqdQf.rst | 2 ++ Modules/posixmodule.c | 7 ++++++- 4 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-08-11-50-49.gh-issue-111841.iSqdQf.rst diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 38464c60a84315..1f0836b2476137 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1142,9 +1142,12 @@ def test_putenv_unsetenv(self): def test_putenv_unsetenv_error(self): # Empty variable name is invalid. # "=" and null character are not allowed in a variable name. - for name in ('', '=name', 'na=me', 'name=', 'name\0', 'na\0me'): + for name in ('', '=name', 'na=me', 'name='): self.assertRaises((OSError, ValueError), os.putenv, name, "value") self.assertRaises((OSError, ValueError), os.unsetenv, name) + for name in ('name\0', 'na\0me'): + self.assertRaises(ValueError, os.putenv, name, "value") + self.assertRaises(ValueError, os.unsetenv, name) if sys.platform == "win32": # On Windows, an environment variable string ("name=value" string) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 7440779d7200dd..1722c84727bbd8 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1011,20 +1011,20 @@ def test_environ(self): self.assertEqual(type(k), item_type) self.assertEqual(type(v), item_type) - @unittest.skipUnless(os.name == 'posix', "see bug gh-111841") def test_putenv(self): with self.assertRaises(ValueError): os.putenv('FRUIT\0VEGETABLE', 'cabbage') - with self.assertRaises(ValueError): - os.putenv(b'FRUIT\0VEGETABLE', b'cabbage') with self.assertRaises(ValueError): os.putenv('FRUIT', 'orange\0VEGETABLE=cabbage') - with self.assertRaises(ValueError): - os.putenv(b'FRUIT', b'orange\0VEGETABLE=cabbage') with self.assertRaises(ValueError): os.putenv('FRUIT=ORANGE', 'lemon') - with self.assertRaises(ValueError): - os.putenv(b'FRUIT=ORANGE', b'lemon') + if os.name == 'posix': + with self.assertRaises(ValueError): + os.putenv(b'FRUIT\0VEGETABLE', b'cabbage') + with self.assertRaises(ValueError): + os.putenv(b'FRUIT', b'orange\0VEGETABLE=cabbage') + with self.assertRaises(ValueError): + os.putenv(b'FRUIT=ORANGE', b'lemon') @unittest.skipUnless(hasattr(posix, 'getcwd'), 'test needs posix.getcwd()') def test_getcwd_long_pathnames(self): diff --git a/Misc/NEWS.d/next/Library/2023-11-08-11-50-49.gh-issue-111841.iSqdQf.rst b/Misc/NEWS.d/next/Library/2023-11-08-11-50-49.gh-issue-111841.iSqdQf.rst new file mode 100644 index 00000000000000..cd1780988aeac7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-08-11-50-49.gh-issue-111841.iSqdQf.rst @@ -0,0 +1,2 @@ +Fix truncating arguments on an embedded null character in :meth:`os.putenv` +and :meth:`os.unsetenv` on Windows. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a98841f375eb5e..0ac5a8d371419f 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -12006,7 +12006,6 @@ win32_putenv(PyObject *name, PyObject *value) } Py_ssize_t size; - /* PyUnicode_AsWideCharString() rejects embedded null characters */ wchar_t *env = PyUnicode_AsWideCharString(unicode, &size); Py_DECREF(unicode); @@ -12020,6 +12019,12 @@ win32_putenv(PyObject *name, PyObject *value) PyMem_Free(env); return NULL; } + if (wcslen(env) != (size_t)size) { + PyErr_SetString(PyExc_ValueError, + "embedded null character"); + PyMem_Free(env); + return NULL; + } /* _wputenv() and SetEnvironmentVariableW() update the environment in the Process Environment Block (PEB). _wputenv() also updates CRT 'environ' From 0f7671cc6963db087cb99354b03999bde5b1d2dd Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sat, 11 Nov 2023 09:21:52 -0800 Subject: [PATCH 1170/1206] [3.12] gh-110395: invalidate open kqueues after fork (GH-110517) (#111745) * [3.12] gh-110395: invalidate open kqueues after fork (GH-110517) Invalidate open select.kqueue instances after fork as the fd will be invalid in the child. (cherry picked from commit a6c1c04d4d2339f0094422974ae3f26f8c7c8565) Co-authored-by: Davide Rizzo * move assert to after the child dying this is in `main` via https://github.com/python/cpython/pull/111816/files --- Lib/test/test_kqueue.py | 18 +++ ...-10-08-14-17-06.gh-issue-110395._tdCsV.rst | 2 + Modules/selectmodule.c | 150 +++++++++++++++++- 3 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-08-14-17-06.gh-issue-110395._tdCsV.rst diff --git a/Lib/test/test_kqueue.py b/Lib/test/test_kqueue.py index 998fd9d46496bb..e94edcbc107ba9 100644 --- a/Lib/test/test_kqueue.py +++ b/Lib/test/test_kqueue.py @@ -5,6 +5,7 @@ import os import select import socket +from test import support import time import unittest @@ -256,6 +257,23 @@ def test_fd_non_inheritable(self): self.addCleanup(kqueue.close) self.assertEqual(os.get_inheritable(kqueue.fileno()), False) + @support.requires_fork() + def test_fork(self): + # gh-110395: kqueue objects must be closed after fork + kqueue = select.kqueue() + if (pid := os.fork()) == 0: + try: + self.assertTrue(kqueue.closed) + with self.assertRaisesRegex(ValueError, "closed kqueue"): + kqueue.fileno() + except: + os._exit(1) + finally: + os._exit(0) + else: + support.wait_process(pid, exitcode=0) + self.assertFalse(kqueue.closed) # child done, we're still open. + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-10-08-14-17-06.gh-issue-110395._tdCsV.rst b/Misc/NEWS.d/next/Library/2023-10-08-14-17-06.gh-issue-110395._tdCsV.rst new file mode 100644 index 00000000000000..eb9bcf1f337fb3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-08-14-17-06.gh-issue-110395._tdCsV.rst @@ -0,0 +1,2 @@ +Ensure that :func:`select.kqueue` objects correctly appear as closed in +forked children, to prevent operations on an invalid file descriptor. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index a88c3cb81520d2..b7c6b1b539904f 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -14,8 +14,16 @@ #include "Python.h" #include "pycore_fileutils.h" // _Py_set_inheritable() +#include "pycore_import.h" // _PyImport_GetModuleAttrString() +#include "pycore_time.h" // _PyTime_t #include "structmember.h" // PyMemberDef +#include +#include // offsetof() +#ifndef MS_WINDOWS +# include // close() +#endif + #ifdef HAVE_SYS_DEVPOLL_H #include #include @@ -70,13 +78,26 @@ extern void bzero(void *, int); # define POLLPRI 0 #endif +#ifdef HAVE_KQUEUE +// Linked list to track kqueue objects with an open fd, so +// that we can invalidate them at fork; +typedef struct _kqueue_list_item { + struct kqueue_queue_Object *obj; + struct _kqueue_list_item *next; +} _kqueue_list_item, *_kqueue_list; +#endif + typedef struct { PyObject *close; PyTypeObject *poll_Type; PyTypeObject *devpoll_Type; PyTypeObject *pyEpoll_Type; +#ifdef HAVE_KQUEUE PyTypeObject *kqueue_event_Type; PyTypeObject *kqueue_queue_Type; + _kqueue_list kqueue_open_list; + bool kqueue_tracking_initialized; +#endif } _selectstate; static struct PyModuleDef selectmodule; @@ -1749,7 +1770,7 @@ typedef struct { #define kqueue_event_Check(op, state) (PyObject_TypeCheck((op), state->kqueue_event_Type)) -typedef struct { +typedef struct kqueue_queue_Object { PyObject_HEAD SOCKET kqfd; /* kqueue control fd */ } kqueue_queue_Object; @@ -1935,6 +1956,107 @@ kqueue_queue_err_closed(void) return NULL; } +static PyObject* +kqueue_tracking_after_fork(PyObject *module) { + _selectstate *state = get_select_state(module); + _kqueue_list_item *item = state->kqueue_open_list; + state->kqueue_open_list = NULL; + while (item) { + // Safety: we hold the GIL, and references are removed from this list + // before the object is deallocated. + kqueue_queue_Object *obj = item->obj; + assert(obj->kqfd != -1); + obj->kqfd = -1; + _kqueue_list_item *next = item->next; + PyMem_Free(item); + item = next; + } + Py_RETURN_NONE; +} + +static PyMethodDef kqueue_tracking_after_fork_def = { + "kqueue_tracking_after_fork", (PyCFunction)kqueue_tracking_after_fork, + METH_NOARGS, "Invalidate open select.kqueue objects after fork." +}; + +static void +kqueue_tracking_init(PyObject *module) { + _selectstate *state = get_select_state(module); + assert(state->kqueue_open_list == NULL); + // Register a callback to invalidate kqueues with open fds after fork. + PyObject *register_at_fork = NULL, *cb = NULL, *args = NULL, + *kwargs = NULL, *result = NULL; + register_at_fork = _PyImport_GetModuleAttrString("posix", + "register_at_fork"); + if (register_at_fork == NULL) { + goto finally; + } + cb = PyCFunction_New(&kqueue_tracking_after_fork_def, module); + if (cb == NULL) { + goto finally; + } + args = PyTuple_New(0); + assert(args != NULL); + kwargs = Py_BuildValue("{sO}", "after_in_child", cb); + if (kwargs == NULL) { + goto finally; + } + result = PyObject_Call(register_at_fork, args, kwargs); + +finally: + if (PyErr_Occurred()) { + // There are a few reasons registration can fail, especially if someone + // touched posix.register_at_fork. But everything else still works so + // instead of raising we issue a warning and move along. + PyObject *exc = PyErr_GetRaisedException(); + PyObject *exctype = (PyObject*)Py_TYPE(exc); + PyErr_WarnFormat(PyExc_RuntimeWarning, 1, + "An exception of type %S was raised while registering an " + "after-fork handler for select.kqueue objects: %S", exctype, exc); + Py_DECREF(exc); + } + Py_XDECREF(register_at_fork); + Py_XDECREF(cb); + Py_XDECREF(args); + Py_XDECREF(kwargs); + Py_XDECREF(result); + state->kqueue_tracking_initialized = true; +} + +static int +kqueue_tracking_add(_selectstate *state, kqueue_queue_Object *self) { + if (!state->kqueue_tracking_initialized) { + kqueue_tracking_init(PyType_GetModule(Py_TYPE(self))); + } + assert(self->kqfd >= 0); + _kqueue_list_item *item = PyMem_New(_kqueue_list_item, 1); + if (item == NULL) { + PyErr_NoMemory(); + return -1; + } + item->obj = self; + item->next = state->kqueue_open_list; + state->kqueue_open_list = item; + return 0; +} + +static void +kqueue_tracking_remove(_selectstate *state, kqueue_queue_Object *self) { + _kqueue_list *listptr = &state->kqueue_open_list; + while (*listptr != NULL) { + _kqueue_list_item *item = *listptr; + if (item->obj == self) { + *listptr = item->next; + PyMem_Free(item); + return; + } + listptr = &item->next; + } + // The item should be in the list when we remove it, + // and it should only be removed once at close time. + assert(0); +} + static int kqueue_queue_internal_close(kqueue_queue_Object *self) { @@ -1942,6 +2064,8 @@ kqueue_queue_internal_close(kqueue_queue_Object *self) if (self->kqfd >= 0) { int kqfd = self->kqfd; self->kqfd = -1; + _selectstate *state = _selectstate_by_type(Py_TYPE(self)); + kqueue_tracking_remove(state, self); Py_BEGIN_ALLOW_THREADS if (close(kqfd) < 0) save_errno = errno; @@ -1982,6 +2106,13 @@ newKqueue_Object(PyTypeObject *type, SOCKET fd) return NULL; } } + + _selectstate *state = _selectstate_by_type(type); + if (kqueue_tracking_add(state, self) < 0) { + Py_DECREF(self); + return NULL; + } + return (PyObject *)self; } @@ -2012,13 +2143,11 @@ select_kqueue_impl(PyTypeObject *type) } static void -kqueue_queue_dealloc(kqueue_queue_Object *self) +kqueue_queue_finalize(kqueue_queue_Object *self) { - PyTypeObject* type = Py_TYPE(self); + PyObject* error = PyErr_GetRaisedException(); kqueue_queue_internal_close(self); - freefunc kqueue_free = PyType_GetSlot(type, Py_tp_free); - kqueue_free((PyObject *)self); - Py_DECREF((PyObject *)type); + PyErr_SetRaisedException(error); } /*[clinic input] @@ -2352,11 +2481,11 @@ static PyMethodDef kqueue_queue_methods[] = { }; static PyType_Slot kqueue_queue_Type_slots[] = { - {Py_tp_dealloc, kqueue_queue_dealloc}, {Py_tp_doc, (void*)select_kqueue__doc__}, {Py_tp_getset, kqueue_queue_getsetlist}, {Py_tp_methods, kqueue_queue_methods}, {Py_tp_new, select_kqueue}, + {Py_tp_finalize, kqueue_queue_finalize}, {0, 0}, }; @@ -2401,8 +2530,11 @@ _select_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->poll_Type); Py_VISIT(state->devpoll_Type); Py_VISIT(state->pyEpoll_Type); +#ifdef HAVE_KQUEUE Py_VISIT(state->kqueue_event_Type); Py_VISIT(state->kqueue_queue_Type); + // state->kqueue_open_list only holds borrowed refs +#endif return 0; } @@ -2415,8 +2547,10 @@ _select_clear(PyObject *module) Py_CLEAR(state->poll_Type); Py_CLEAR(state->devpoll_Type); Py_CLEAR(state->pyEpoll_Type); +#ifdef HAVE_KQUEUE Py_CLEAR(state->kqueue_event_Type); Py_CLEAR(state->kqueue_queue_Type); +#endif return 0; } @@ -2550,6 +2684,8 @@ _select_exec(PyObject *m) #endif /* HAVE_EPOLL */ #ifdef HAVE_KQUEUE + state->kqueue_open_list = NULL; + state->kqueue_event_Type = (PyTypeObject *)PyType_FromModuleAndSpec( m, &kqueue_event_Type_spec, NULL); if (state->kqueue_event_Type == NULL) { From 1afc4dc3e6b95d4a23cdcbe2ebebe1d0ba09f0f4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 12 Nov 2023 01:39:03 +0100 Subject: [PATCH 1171/1206] [3.12] Fix undefined behaviour in datetime.time.fromisoformat() (GH-111982) (#111992) Fix undefined behaviour in datetime.time.fromisoformat() (GH-111982) Fix undefined behaviour in datetime.time.fromisoformat() when parsing a string without a timezone. 'tzoffset' is not assigned to by parse_isoformat_time if it returns 0, but time_fromisoformat then passes tzoffset to another function, which is undefined behaviour (even if the function in question does not use the value). (cherry picked from commit 21615f77b5a580e83589abae618dbe7c298700e2) Co-authored-by: T. Wouters --- Modules/_datetimemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index d8183c63f44976..c8dbc750b0ef5b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4620,7 +4620,7 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { } int hour = 0, minute = 0, second = 0, microsecond = 0; - int tzoffset, tzimicrosecond = 0; + int tzoffset = 0, tzimicrosecond = 0; int rv = parse_isoformat_time(p, len, &hour, &minute, &second, µsecond, &tzoffset, &tzimicrosecond); From 13ca1f02a409a58ba86cd8247eb3e31dd21a81cf Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 12 Nov 2023 01:44:24 +0100 Subject: [PATCH 1172/1206] [3.12] gh-111777: Fix assertion errors on incorrectly still-tracked GC object destruction (GH-111778) (#111989) gh-111777: Fix assertion errors on incorrectly still-tracked GC object destruction (GH-111778) In PyObject_GC_Del, in Py_DEBUG mode, when warning about GC objects that were not properly untracked before starting destruction, take care to untrack the object _before_ warning, to avoid triggering a GC run and causing the problem the code tries to warn about. Also make sure to save and restore any pending exceptions, which the warning would otherwise clobber or trigger an assertion error on. (cherry picked from commit ce6a533c4bf1afa3775dfcaee5fc7d5c15a4af8c) Co-authored-by: T. Wouters --- Modules/gcmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 26ddcdd538a4d4..149a6a022d08ce 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2381,14 +2381,16 @@ PyObject_GC_Del(void *op) size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type); PyGC_Head *g = AS_GC(op); if (_PyObject_GC_IS_TRACKED(op)) { + gc_list_remove(g); #ifdef Py_DEBUG + PyObject *exc = PyErr_GetRaisedException(); if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, "gc", NULL, "Object of type %s is not untracked before destruction", ((PyObject*)op)->ob_type->tp_name)) { PyErr_WriteUnraisable(NULL); } + PyErr_SetRaisedException(exc); #endif - gc_list_remove(g); } GCState *gcstate = get_gc_state(); if (gcstate->generations[0].count > 0) { From 158a7e1acda71790f7c282949d1473d51e654d58 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 12 Nov 2023 02:22:44 +0100 Subject: [PATCH 1173/1206] [3.12] gh-111933: fix broken link to A.Neumaier article (gh-111937) (gh-111993) --- Python/bltinmodule.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 7f366b43599ae5..84fbc33a48ca61 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2605,7 +2605,10 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) } if (PyFloat_CheckExact(item)) { // Improved Kahan–BabuÅ¡ka algorithm by Arnold Neumaier - // https://www.mat.univie.ac.at/~neum/scan/01.pdf + // Neumaier, A. (1974), Rundungsfehleranalyse einiger Verfahren + // zur Summation endlicher Summen. Z. angew. Math. Mech., + // 54: 39-51. https://doi.org/10.1002/zamm.19740540106 + // https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements double x = PyFloat_AS_DOUBLE(item); double t = f_result + x; if (fabs(f_result) >= fabs(x)) { From 378a96e361bf8cd0614ef25368807fe02fffeab2 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 12 Nov 2023 14:20:36 +0100 Subject: [PATCH 1174/1206] [3.12] gh-112001: Fix test_builtins_have_signatures in test_inspect (GH-112002) (GH-112003) (cherry picked from commit 40752c1c1e8cec80e99a2c9796f4fde2f8b5d3e2) Co-authored-by: Serhiy Storchaka --- Lib/test/test_inspect/test_inspect.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 4a96502abffb66..63b15819584bbb 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -4516,19 +4516,14 @@ def test_builtins_have_signatures(self): # These have unrepresentable parameter default values of NULL needs_null = {"anext"} no_signature |= needs_null - # These need PEP 457 groups or a signature change to accept None - needs_semantic_update = {"round"} - no_signature |= needs_semantic_update # These need *args support in Argument Clinic - needs_varargs = {"breakpoint", "min", "max", "print", - "__build_class__"} + needs_varargs = {"breakpoint", "min", "max", "__build_class__"} no_signature |= needs_varargs - # These simply weren't covered in the initial AC conversion - # for builtin callables - not_converted_yet = {"open", "__import__"} - no_signature |= not_converted_yet # These builtin types are expected to provide introspection info - types_with_signatures = set() + types_with_signatures = { + 'complex', 'enumerate', 'float', 'list', 'memoryview', 'object', + 'property', 'reversed', 'tuple', + } # Check the signatures we expect to be there ns = vars(builtins) for name, obj in sorted(ns.items()): @@ -4547,9 +4542,9 @@ def test_builtins_have_signatures(self): # This ensures this test will start failing as more signatures are # added, so the affected items can be moved into the scope of the # regression test above - for name in no_signature: + for name in no_signature - needs_null - needs_groups: with self.subTest(builtin=name): - self.assertIsNone(obj.__text_signature__) + self.assertIsNone(ns[name].__text_signature__) def test_python_function_override_signature(self): def func(*args, **kwargs): From 3b7e308a24fdaf24e45ad3ce980e52a2778b548e Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Nov 2023 01:17:54 +0100 Subject: [PATCH 1175/1206] [3.12] gh-111944: Add assignment expression parentheses requirements (GH-111977) (#112010) Augment the list of places where parentheses are required around assignnment statements. In particular, 'a := 0' and 'a = b := 1' are syntax errors. (cherry picked from commit 9a2f25d374f027f6509484d66e1c7bba03977b99) Co-authored-by: Terry Jan Reedy --- Doc/reference/expressions.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index cac7ae7efa3d4d..e29d3a058c612d 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1774,10 +1774,11 @@ Or, when processing a file stream in chunks: while chunk := file.read(9000): process(chunk) -Assignment expressions must be surrounded by parentheses when used -as sub-expressions in slicing, conditional, lambda, -keyword-argument, and comprehension-if expressions -and in ``assert`` and ``with`` statements. +Assignment expressions must be surrounded by parentheses when +used as expression statements and when used as sub-expressions in +slicing, conditional, lambda, +keyword-argument, and comprehension-if expressions and +in ``assert``, ``with``, and ``assignment`` statements. In all other places where they can be used, parentheses are not required, including in ``if`` and ``while`` statements. From a1447af69c3063bb154d343628a19134901549ff Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Nov 2023 09:15:11 +0100 Subject: [PATCH 1176/1206] [3.12] Docs: Add `make htmllive` to rebuild and reload HTML files in your browser (GH-111900) (#112022) Co-authored-by: Hugo van Kemenade --- Doc/Makefile | 6 ++++++ Doc/requirements.txt | 1 + 2 files changed, 7 insertions(+) diff --git a/Doc/Makefile b/Doc/Makefile index 78ee4271e25f79..7af56e965e1be4 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -29,6 +29,7 @@ help: @echo " venv to create a venv with necessary tools" @echo " html to make standalone HTML files" @echo " htmlview to open the index page built by the html target in your browser" + @echo " htmllive to rebuild and reload HTML files in your browser" @echo " htmlhelp to make HTML files and a HTML help project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " text to make plain text files" @@ -139,6 +140,11 @@ pydoc-topics: build htmlview: html $(PYTHON) -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('build/html/index.html'))" +.PHONY: htmllive +htmllive: SPHINXBUILD = $(VENVDIR)/bin/sphinx-autobuild +htmllive: SPHINXOPTS = --re-ignore="/venv/" +htmllive: html + .PHONY: clean clean: clean-venv -rm -rf build/* diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 4741265a0347f2..07d20a63a6523a 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -10,6 +10,7 @@ sphinx==4.5.0 blurb +sphinx-autobuild sphinxext-opengraph==0.7.5 # The theme used by the documentation is stored separately, so we need From 7313bde84c82e37aa1110d44b796ec3025b0f611 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 13 Nov 2023 13:59:56 +0000 Subject: [PATCH 1177/1206] [3.12] Bump mypy to 1.7.0 (GH-111961) (#112033) --- .github/workflows/mypy.yml | 1 + Tools/requirements-dev.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 67a4af239e18fc..f6dc01986a13d6 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -8,6 +8,7 @@ on: pull_request: paths: - "Tools/clinic/**" + - "Tools/requirements-dev.txt" - ".github/workflows/mypy.yml" workflow_dispatch: diff --git a/Tools/requirements-dev.txt b/Tools/requirements-dev.txt index 79ef43a4024c98..b8ecea0e01e49b 100644 --- a/Tools/requirements-dev.txt +++ b/Tools/requirements-dev.txt @@ -1,2 +1,2 @@ # Requirements file for external linters and checks we run on Tools/clinic/ in CI -mypy==1.6.1 +mypy==1.7.0 From 9aa5ff82d43435293acf0337fd069dce783176fc Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 13 Nov 2023 14:08:57 +0000 Subject: [PATCH 1178/1206] [3.12] gh-111681: minor fixes to typing doctests; remove unused imports in `test_typing` (#111682) (#112035) Co-authored-by: Alex Waygood Co-authored-by: Nikita Sobolev --- Doc/library/typing.rst | 2 +- Lib/test/test_typing.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 7b75094b9da0f6..b00eb93f32ece4 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1941,7 +1941,7 @@ without the dedicated syntax, as documented below. .. doctest:: - >>> from typing import ParamSpec + >>> from typing import ParamSpec, get_origin >>> P = ParamSpec("P") >>> get_origin(P.args) is P True diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 62fe00b0a02f28..ca10a87b06130d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -10,7 +10,7 @@ import re import sys import warnings -from unittest import TestCase, main, skipUnless, skip +from unittest import TestCase, main, skip from unittest.mock import patch from copy import copy, deepcopy @@ -45,7 +45,7 @@ import weakref import types -from test.support import import_helper, captured_stderr, cpython_only +from test.support import captured_stderr, cpython_only from test.typinganndata import mod_generics_cache, _typed_dict_helper From c6aea46a71d158f993cc723c14b4bf7982b73a2a Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 13 Nov 2023 15:54:40 +0100 Subject: [PATCH 1179/1206] [3.12] gh-102837: more tests for the math module (GH-111930)(GH-102523) (GH-112030) * gh-102837: improve test coverage for math module (GH-102523) (Only the test changes from GH-102523 are cherry-picked) - input checks for math_1(L989), math_1a(L1023), math_2(L1064,L1071), hypot(L2682), log(L2307), ldexp(L2168), ceil(L1165), floor(L1236,L1239) and dist(L2587,L2588,L2628). - improve fsum coverage for exceptional cases (L1433,L1438,L1451,L1497), ditto fmod(L2378) (all line numbers are wrt the main branch at 5e6661bce9) * gh-102837: more tests for the math module (GH-111930) Add tests to improve coverage: * fsum: L1369, L1379, L1383, L1412 * trunc: L2081 * log: L2267 * dist: L2577, L2579 * hypot: L2632 * sumprod: L2744, L2754, L2774, L2778, L2781, L2785, L2831, L2835, L2838 * pow: L2982 * prod: L3294, L3308, L3318-3330 // line numbers wrt to 9dc4fb8204 (cherry picked from commit c61de456db0186b65d479d41e84127832205d30d) --------- Co-authored-by: Sergey B Kirpichev --- Lib/test/test_math.py | 96 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index faf067235c5dad..aeaa99cfb8b5fb 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -235,6 +235,10 @@ def __init__(self, value): def __index__(self): return self.value +class BadDescr: + def __get__(self, obj, objtype=None): + raise ValueError + class MathTests(unittest.TestCase): def ftest(self, name, got, expected, ulp_tol=5, abs_tol=0.0): @@ -324,6 +328,7 @@ def testAtan2(self): self.ftest('atan2(0, 1)', math.atan2(0, 1), 0) self.ftest('atan2(1, 1)', math.atan2(1, 1), math.pi/4) self.ftest('atan2(1, 0)', math.atan2(1, 0), math.pi/2) + self.ftest('atan2(1, -1)', math.atan2(1, -1), 3*math.pi/4) # math.atan2(0, x) self.ftest('atan2(0., -inf)', math.atan2(0., NINF), math.pi) @@ -417,16 +422,22 @@ def __ceil__(self): return 42 class TestNoCeil: pass + class TestBadCeil: + __ceil__ = BadDescr() self.assertEqual(math.ceil(TestCeil()), 42) self.assertEqual(math.ceil(FloatCeil()), 42) self.assertEqual(math.ceil(FloatLike(42.5)), 43) self.assertRaises(TypeError, math.ceil, TestNoCeil()) + self.assertRaises(ValueError, math.ceil, TestBadCeil()) t = TestNoCeil() t.__ceil__ = lambda *args: args self.assertRaises(TypeError, math.ceil, t) self.assertRaises(TypeError, math.ceil, t, 0) + self.assertEqual(math.ceil(FloatLike(+1.0)), +1.0) + self.assertEqual(math.ceil(FloatLike(-1.0)), -1.0) + @requires_IEEE_754 def testCopysign(self): self.assertEqual(math.copysign(1, 42), 1.0) @@ -567,16 +578,22 @@ def __floor__(self): return 42 class TestNoFloor: pass + class TestBadFloor: + __floor__ = BadDescr() self.assertEqual(math.floor(TestFloor()), 42) self.assertEqual(math.floor(FloatFloor()), 42) self.assertEqual(math.floor(FloatLike(41.9)), 41) self.assertRaises(TypeError, math.floor, TestNoFloor()) + self.assertRaises(ValueError, math.floor, TestBadFloor()) t = TestNoFloor() t.__floor__ = lambda *args: args self.assertRaises(TypeError, math.floor, t) self.assertRaises(TypeError, math.floor, t, 0) + self.assertEqual(math.floor(FloatLike(+1.0)), +1.0) + self.assertEqual(math.floor(FloatLike(-1.0)), -1.0) + def testFmod(self): self.assertRaises(TypeError, math.fmod) self.ftest('fmod(10, 1)', math.fmod(10, 1), 0.0) @@ -598,6 +615,7 @@ def testFmod(self): self.assertEqual(math.fmod(-3.0, NINF), -3.0) self.assertEqual(math.fmod(0.0, 3.0), 0.0) self.assertEqual(math.fmod(0.0, NINF), 0.0) + self.assertRaises(ValueError, math.fmod, INF, INF) def testFrexp(self): self.assertRaises(TypeError, math.frexp) @@ -667,6 +685,7 @@ def msum(iterable): ([], 0.0), ([0.0], 0.0), ([1e100, 1.0, -1e100, 1e-100, 1e50, -1.0, -1e50], 1e-100), + ([1e100, 1.0, -1e100, 1e-100, 1e50, -1, -1e50], 1e-100), ([2.0**53, -0.5, -2.0**-54], 2.0**53-1.0), ([2.0**53, 1.0, 2.0**-100], 2.0**53+2.0), ([2.0**53+10.0, 1.0, 2.0**-100], 2.0**53+12.0), @@ -714,6 +733,22 @@ def msum(iterable): s = msum(vals) self.assertEqual(msum(vals), math.fsum(vals)) + self.assertEqual(math.fsum([1.0, math.inf]), math.inf) + self.assertTrue(math.isnan(math.fsum([math.nan, 1.0]))) + self.assertEqual(math.fsum([1e100, FloatLike(1.0), -1e100, 1e-100, + 1e50, FloatLike(-1.0), -1e50]), 1e-100) + self.assertRaises(OverflowError, math.fsum, [1e+308, 1e+308]) + self.assertRaises(ValueError, math.fsum, [math.inf, -math.inf]) + self.assertRaises(TypeError, math.fsum, ['spam']) + self.assertRaises(TypeError, math.fsum, 1) + self.assertRaises(OverflowError, math.fsum, [10**1000]) + + def bad_iter(): + yield 1.0 + raise ZeroDivisionError + + self.assertRaises(ZeroDivisionError, math.fsum, bad_iter()) + def testGcd(self): gcd = math.gcd self.assertEqual(gcd(0, 0), 0) @@ -774,6 +809,8 @@ def testHypot(self): # Test allowable types (those with __float__) self.assertEqual(hypot(12.0, 5.0), 13.0) self.assertEqual(hypot(12, 5), 13) + self.assertEqual(hypot(1, -1), math.sqrt(2)) + self.assertEqual(hypot(1, FloatLike(-1.)), math.sqrt(2)) self.assertEqual(hypot(Decimal(12), Decimal(5)), 13) self.assertEqual(hypot(Fraction(12, 32), Fraction(5, 32)), Fraction(13, 32)) self.assertEqual(hypot(bool(1), bool(0), bool(1), bool(1)), math.sqrt(3)) @@ -831,6 +868,8 @@ def testHypot(self): scale = FLOAT_MIN / 2.0 ** exp self.assertEqual(math.hypot(4*scale, 3*scale), 5*scale) + self.assertRaises(TypeError, math.hypot, *([1.0]*18), 'spam') + @requires_IEEE_754 @unittest.skipIf(HAVE_DOUBLE_ROUNDING, "hypot() loses accuracy on machines with double rounding") @@ -923,6 +962,10 @@ def testDist(self): # Test allowable types (those with __float__) self.assertEqual(dist((14.0, 1.0), (2.0, -4.0)), 13.0) self.assertEqual(dist((14, 1), (2, -4)), 13) + self.assertEqual(dist((FloatLike(14.), 1), (2, -4)), 13) + self.assertEqual(dist((11, 1), (FloatLike(-1.), -4)), 13) + self.assertEqual(dist((14, FloatLike(-1.)), (2, -6)), 13) + self.assertEqual(dist((14, -1), (2, -6)), 13) self.assertEqual(dist((D(14), D(1)), (D(2), D(-4))), D(13)) self.assertEqual(dist((F(14, 32), F(1, 32)), (F(2, 32), F(-4, 32))), F(13, 32)) @@ -966,6 +1009,8 @@ class T(tuple): dist((1, 2, 3, 4), (5, 6, 7)) with self.assertRaises(ValueError): # Check dimension agree dist((1, 2, 3), (4, 5, 6, 7)) + with self.assertRaises(TypeError): + dist((1,)*17 + ("spam",), (1,)*18) with self.assertRaises(TypeError): # Rejects invalid types dist("abc", "xyz") int_too_big_for_float = 10 ** (sys.float_info.max_10_exp + 5) @@ -973,6 +1018,16 @@ class T(tuple): dist((1, int_too_big_for_float), (2, 3)) with self.assertRaises((ValueError, OverflowError)): dist((2, 3), (1, int_too_big_for_float)) + with self.assertRaises(TypeError): + dist((1,), 2) + with self.assertRaises(TypeError): + dist([1], 2) + + class BadFloat: + __float__ = BadDescr() + + with self.assertRaises(ValueError): + dist([1], [BadFloat()]) # Verify that the one dimensional case is equivalent to abs() for i in range(20): @@ -1111,6 +1166,7 @@ def test_lcm(self): def testLdexp(self): self.assertRaises(TypeError, math.ldexp) + self.assertRaises(TypeError, math.ldexp, 2.0, 1.1) self.ftest('ldexp(0,1)', math.ldexp(0,1), 0) self.ftest('ldexp(1,1)', math.ldexp(1,1), 2) self.ftest('ldexp(1,-1)', math.ldexp(1,-1), 0.5) @@ -1143,6 +1199,7 @@ def testLdexp(self): def testLog(self): self.assertRaises(TypeError, math.log) + self.assertRaises(TypeError, math.log, 1, 2, 3) self.ftest('log(1/e)', math.log(1/math.e), -1) self.ftest('log(1)', math.log(1), 0) self.ftest('log(e)', math.log(math.e), 1) @@ -1153,6 +1210,7 @@ def testLog(self): 2302.5850929940457) self.assertRaises(ValueError, math.log, -1.5) self.assertRaises(ValueError, math.log, -10**1000) + self.assertRaises(ValueError, math.log, 10, -10) self.assertRaises(ValueError, math.log, NINF) self.assertEqual(math.log(INF), INF) self.assertTrue(math.isnan(math.log(NAN))) @@ -1212,6 +1270,8 @@ def testSumProd(self): self.assertEqual(sumprod(iter([10, 20, 30]), (1, 2, 3)), 140) self.assertEqual(sumprod([1.5, 2.5], [3.5, 4.5]), 16.5) self.assertEqual(sumprod([], []), 0) + self.assertEqual(sumprod([-1], [1.]), -1) + self.assertEqual(sumprod([1.], [-1]), -1) # Type preservation and coercion for v in [ @@ -1237,11 +1297,20 @@ def testSumProd(self): self.assertRaises(TypeError, sumprod, [], [], []) # Three args self.assertRaises(TypeError, sumprod, None, [10]) # Non-iterable self.assertRaises(TypeError, sumprod, [10], None) # Non-iterable + self.assertRaises(TypeError, sumprod, ['x'], [1.0]) # Uneven lengths self.assertRaises(ValueError, sumprod, [10, 20], [30]) self.assertRaises(ValueError, sumprod, [10], [20, 30]) + # Overflows + self.assertEqual(sumprod([10**20], [1]), 10**20) + self.assertEqual(sumprod([1], [10**20]), 10**20) + self.assertEqual(sumprod([10**10], [10**10]), 10**20) + self.assertEqual(sumprod([10**7]*10**5, [10**7]*10**5), 10**19) + self.assertRaises(OverflowError, sumprod, [10**1000], [1.0]) + self.assertRaises(OverflowError, sumprod, [1.0], [10**1000]) + # Error in iterator def raise_after(n): for i in range(n): @@ -1252,6 +1321,11 @@ def raise_after(n): with self.assertRaises(RuntimeError): sumprod(raise_after(5), range(10)) + from test.test_iter import BasicIterClass + + self.assertEqual(sumprod(BasicIterClass(1), [1]), 0) + self.assertEqual(sumprod([1], BasicIterClass(1)), 0) + # Error in multiplication class BadMultiply: def __mul__(self, other): @@ -1491,6 +1565,7 @@ def testPow(self): self.assertTrue(math.isnan(math.pow(2, NAN))) self.assertTrue(math.isnan(math.pow(0, NAN))) self.assertEqual(math.pow(1, NAN), 1) + self.assertRaises(OverflowError, math.pow, 1e+100, 1e+100) # pow(0., x) self.assertEqual(math.pow(0., INF), 0.) @@ -1847,6 +1922,8 @@ def __trunc__(self): return 23 class TestNoTrunc: pass + class TestBadTrunc: + __trunc__ = BadDescr() self.assertEqual(math.trunc(TestTrunc()), 23) self.assertEqual(math.trunc(FloatTrunc()), 23) @@ -1855,6 +1932,7 @@ class TestNoTrunc: self.assertRaises(TypeError, math.trunc, 1, 2) self.assertRaises(TypeError, math.trunc, FloatLike(23.5)) self.assertRaises(TypeError, math.trunc, TestNoTrunc()) + self.assertRaises(ValueError, math.trunc, TestBadTrunc()) def testIsfinite(self): self.assertTrue(math.isfinite(0.0)) @@ -2055,6 +2133,8 @@ def test_mtestfile(self): '\n '.join(failures)) def test_prod(self): + from fractions import Fraction as F + prod = math.prod self.assertEqual(prod([]), 1) self.assertEqual(prod([], start=5), 5) @@ -2066,6 +2146,14 @@ def test_prod(self): self.assertEqual(prod([1.0, 2.0, 3.0, 4.0, 5.0]), 120.0) self.assertEqual(prod([1, 2, 3, 4.0, 5.0]), 120.0) self.assertEqual(prod([1.0, 2.0, 3.0, 4, 5]), 120.0) + self.assertEqual(prod([1., F(3, 2)]), 1.5) + + # Error in multiplication + class BadMultiply: + def __rmul__(self, other): + raise RuntimeError + with self.assertRaises(RuntimeError): + prod([10., BadMultiply()]) # Test overflow in fast-path for integers self.assertEqual(prod([1, 1, 2**32, 1, 1]), 2**32) @@ -2379,6 +2467,14 @@ def __float__(self): # argument to a float. self.assertFalse(getattr(y, "converted", False)) + def test_input_exceptions(self): + self.assertRaises(TypeError, math.exp, "spam") + self.assertRaises(TypeError, math.erf, "spam") + self.assertRaises(TypeError, math.atan2, "spam", 1.0) + self.assertRaises(TypeError, math.atan2, 1.0, "spam") + self.assertRaises(TypeError, math.atan2, 1.0) + self.assertRaises(TypeError, math.atan2, 1.0, 2.0, 3.0) + # Custom assertions. def assertIsNaN(self, value): From dfdbfc548f45dc254844b71f77f03136c413b76b Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:25:01 +0100 Subject: [PATCH 1180/1206] gh-111856: Fix os.fstat on windows with FAT32 and exFAT filesystem (GH-112038) (cherry picked from commit 29af7369dbbbba8cefafb196e977bce8189a527d) Co-authored-by: AN Long --- .../2023-11-13-22-35-27.gh-issue-111856.vEtA5z.rst | 2 ++ Python/fileutils.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-11-13-22-35-27.gh-issue-111856.vEtA5z.rst diff --git a/Misc/NEWS.d/next/Windows/2023-11-13-22-35-27.gh-issue-111856.vEtA5z.rst b/Misc/NEWS.d/next/Windows/2023-11-13-22-35-27.gh-issue-111856.vEtA5z.rst new file mode 100644 index 00000000000000..b1388df8e4c479 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-11-13-22-35-27.gh-issue-111856.vEtA5z.rst @@ -0,0 +1,2 @@ +Fixes :func:`~os.fstat` on file systems that do not support file ID +requests. This includes FAT32 and exFAT. diff --git a/Python/fileutils.c b/Python/fileutils.c index 610e729feb358e..c7521751cd26d1 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1236,6 +1236,7 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) BY_HANDLE_FILE_INFORMATION info; FILE_BASIC_INFO basicInfo; FILE_ID_INFO idInfo; + FILE_ID_INFO *pIdInfo = &idInfo; HANDLE h; int type; @@ -1268,15 +1269,19 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) } if (!GetFileInformationByHandle(h, &info) || - !GetFileInformationByHandleEx(h, FileBasicInfo, &basicInfo, sizeof(basicInfo)) || - !GetFileInformationByHandleEx(h, FileIdInfo, &idInfo, sizeof(idInfo))) { + !GetFileInformationByHandleEx(h, FileBasicInfo, &basicInfo, sizeof(basicInfo))) { /* The Win32 error is already set, but we also set errno for callers who expect it */ errno = winerror_to_errno(GetLastError()); return -1; } - _Py_attribute_data_to_stat(&info, 0, &basicInfo, &idInfo, status); + if (!GetFileInformationByHandleEx(h, FileIdInfo, &idInfo, sizeof(idInfo))) { + /* Failed to get FileIdInfo, so do not pass it along */ + pIdInfo = NULL; + } + + _Py_attribute_data_to_stat(&info, 0, &basicInfo, pIdInfo, status); return 0; #else return fstat(fd, status); From 02fdb420186295c6435b23f7e030ae989a0e42ac Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:55:33 +0100 Subject: [PATCH 1181/1206] [3.12] gh-112007: Re-organize help utility intro message (GH-112017) (#112047) gh-112007: Re-organize help utility intro message (GH-112017) Most important: move how-to-quit sentence to the end and mention 'q'. Re-group the other sentences and improve some wording. --------- (cherry picked from commit b28bb130bbc2ad956828819967d83e06d30a65c5) Co-authored-by: Terry Jan Reedy --- Lib/pydoc.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 185f09e603df2e..84bbf588dc9201 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2075,20 +2075,22 @@ def help(self, request, is_cli=False): self.output.write('\n') def intro(self): - self.output.write(''' -Welcome to Python {0}'s help utility! - -If this is your first time using Python, you should definitely check out -the tutorial on the internet at https://docs.python.org/{0}/tutorial/. + self.output.write('''\ +Welcome to Python {0}'s help utility! If this is your first time using +Python, you should definitely check out the tutorial at +https://docs.python.org/{0}/tutorial/. Enter the name of any module, keyword, or topic to get help on writing -Python programs and using Python modules. To quit this help utility and -return to the interpreter, just type "quit". +Python programs and using Python modules. To get a list of available +modules, keywords, symbols, or topics, enter "modules", "keywords", +"symbols", or "topics". + +Each module also comes with a one-line summary of what it does; to list +the modules whose name or summary contain a given string such as "spam", +enter "modules spam". -To get a list of available modules, keywords, symbols, or topics, type -"modules", "keywords", "symbols", or "topics". Each module also comes -with a one-line summary of what it does; to list the modules whose name -or summary contain a given string such as "spam", type "modules spam". +To quit this help utility and return to the interpreter, +enter "q" or "quit". '''.format('%d.%d' % sys.version_info[:2])) def list(self, items, columns=4, width=80): From d34650e7409b6a7cc64d7a118e4500c2f3cdbcf3 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Nov 2023 02:59:01 +0100 Subject: [PATCH 1182/1206] [3.12] gh-111460: Restore ncurses widechar support on macOS (GH-111878) (gh-112034) gh-111460: Restore ncurses widechar support on macOS (GH-111878) (cherry picked from commit d2f305dfd183025a95592319b280fcf4b20c8694) Co-authored-by: Davide Rizzo --- .../Library/2023-11-09-12-57-43.gh-issue-111460.TQaz9I.rst | 3 +++ configure | 2 +- configure.ac | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-09-12-57-43.gh-issue-111460.TQaz9I.rst diff --git a/Misc/NEWS.d/next/Library/2023-11-09-12-57-43.gh-issue-111460.TQaz9I.rst b/Misc/NEWS.d/next/Library/2023-11-09-12-57-43.gh-issue-111460.TQaz9I.rst new file mode 100644 index 00000000000000..956c536a291a9c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-09-12-57-43.gh-issue-111460.TQaz9I.rst @@ -0,0 +1,3 @@ +:mod:`curses`: restore wide character support (including +:func:`curses.unget_wch` and :meth:`~curses.window.get_wch`) on macOS, which +was unavailable due to a regression in Python 3.12. diff --git a/configure b/configure index 7c3250729c89d3..778eacf51c72f1 100755 --- a/configure +++ b/configure @@ -26079,7 +26079,7 @@ fi fi CURSES_CFLAGS=$(echo $CURSES_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') -if test "$have_curses" = no -a "$ac_sys_system" = "Darwin"; then +if test "$have_curses" != no -a "$ac_sys_system" = "Darwin"; then as_fn_append CURSES_CFLAGS " -D_XOPEN_SOURCE_EXTENDED=1" printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h diff --git a/configure.ac b/configure.ac index 3afa9aca8bbd43..ac8400183d8a7b 100644 --- a/configure.ac +++ b/configure.ac @@ -6439,9 +6439,11 @@ dnl remove _XOPEN_SOURCE macro from curses cflags. pyconfig.h sets dnl the macro to 700. CURSES_CFLAGS=$(echo $CURSES_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') -if test "$have_curses" = no -a "$ac_sys_system" = "Darwin"; then +if test "$have_curses" != no -a "$ac_sys_system" = "Darwin"; then dnl On macOS, there is no separate /usr/lib/libncursesw nor libpanelw. - dnl If we are here, we found a locally-supplied version of libncursesw. + dnl System-supplied ncurses combines libncurses/libpanel and supports wide + dnl characters, so we can use it like ncursesw. + dnl If a locally-supplied version of libncursesw is found, we will use that. dnl There should also be a libpanelw. dnl _XOPEN_SOURCE defines are usually excluded for macOS, but we need dnl _XOPEN_SOURCE_EXTENDED here for ncurses wide char support. From 18b88fecc9ddae7924a161c247c977412f177a51 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Nov 2023 10:38:19 +0100 Subject: [PATCH 1183/1206] [3.12] gh-111622: Fix doc for items views (GH-112051) (#112052) They are set-like even when some values are not hashable, but work even better when all are. (cherry picked from commit e31d65e0b7bb6d6fee4e8df54e10976b4cfab1de) Co-authored-by: Terry Jan Reedy --- Doc/library/stdtypes.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 4d44ca2766416d..a0db7ba22fbfc0 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4752,14 +4752,17 @@ support membership tests: .. versionadded:: 3.10 -Keys views are set-like since their entries are unique and :term:`hashable`. If all -values are hashable, so that ``(key, value)`` pairs are unique and hashable, -then the items view is also set-like. (Values views are not treated as set-like +Keys views are set-like since their entries are unique and :term:`hashable`. +Items views also have set-like operations since the (key, value) pairs +are unique and the keys are hashable. +If all values in an items view are hashable as well, +then the items view can interoperate with other sets. +(Values views are not treated as set-like since the entries are generally not unique.) For set-like views, all of the operations defined for the abstract base class :class:`collections.abc.Set` are available (for example, ``==``, ``<``, or ``^``). While using set operators, -set-like views accept any iterable as the other operand, unlike sets which only -accept sets as the input. +set-like views accept any iterable as the other operand, +unlike sets which only accept sets as the input. An example of dictionary view usage:: From c003de946793fe2f4e168ba231ea4ee9e88cc3fe Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:25:19 +0100 Subject: [PATCH 1184/1206] [3.12] gh-110944: Move pty helper to test.support and add basic pdb completion test (GH-111826) (GH-112024) gh-110944: Move pty helper to test.support and add basic pdb completion test (GH-111826) (cherry picked from commit 1c7ed7e9ebc53290c831d7b610219fa737153a1b) Co-authored-by: Tian Gao --- Lib/test/support/pty_helper.py | 60 ++++++++++++++++++++++++++++++++++ Lib/test/test_pdb.py | 30 +++++++++++++++++ Lib/test/test_readline.py | 55 +------------------------------ 3 files changed, 91 insertions(+), 54 deletions(-) create mode 100644 Lib/test/support/pty_helper.py diff --git a/Lib/test/support/pty_helper.py b/Lib/test/support/pty_helper.py new file mode 100644 index 00000000000000..11037d22516448 --- /dev/null +++ b/Lib/test/support/pty_helper.py @@ -0,0 +1,60 @@ +""" +Helper to run a script in a pseudo-terminal. +""" +import os +import selectors +import subprocess +import sys +from contextlib import ExitStack +from errno import EIO + +from test.support.import_helper import import_module + +def run_pty(script, input=b"dummy input\r", env=None): + pty = import_module('pty') + output = bytearray() + [master, slave] = pty.openpty() + args = (sys.executable, '-c', script) + proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave, env=env) + os.close(slave) + with ExitStack() as cleanup: + cleanup.enter_context(proc) + def terminate(proc): + try: + proc.terminate() + except ProcessLookupError: + # Workaround for Open/Net BSD bug (Issue 16762) + pass + cleanup.callback(terminate, proc) + cleanup.callback(os.close, master) + # Avoid using DefaultSelector and PollSelector. Kqueue() does not + # work with pseudo-terminals on OS X < 10.9 (Issue 20365) and Open + # BSD (Issue 20667). Poll() does not work with OS X 10.6 or 10.4 + # either (Issue 20472). Hopefully the file descriptor is low enough + # to use with select(). + sel = cleanup.enter_context(selectors.SelectSelector()) + sel.register(master, selectors.EVENT_READ | selectors.EVENT_WRITE) + os.set_blocking(master, False) + while True: + for [_, events] in sel.select(): + if events & selectors.EVENT_READ: + try: + chunk = os.read(master, 0x10000) + except OSError as err: + # Linux raises EIO when slave is closed (Issue 5380) + if err.errno != EIO: + raise + chunk = b"" + if not chunk: + return output + output.extend(chunk) + if events & selectors.EVENT_WRITE: + try: + input = input[os.write(master, input):] + except OSError as err: + # Apparently EIO means the slave was closed + if err.errno != EIO: + raise + input = b"" # Stop writing + if not input: + sel.modify(master, selectors.EVENT_READ) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 49a87b1bb47a7c..08b2867266e3c4 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -15,6 +15,8 @@ from io import StringIO from test import support from test.support import os_helper +from test.support.import_helper import import_module +from test.support.pty_helper import run_pty # This little helper class is essential for testing pdb under doctest. from test.test_doctest import _FakeInput from unittest.mock import patch @@ -2627,6 +2629,34 @@ def test_checkline_is_not_executable(self): self.assertFalse(db.checkline(os_helper.TESTFN, lineno)) +@support.requires_subprocess() +class PdbTestReadline(unittest.TestCase): + def setUpClass(): + # Ensure that the readline module is loaded + # If this fails, the test is skipped because SkipTest will be raised + readline = import_module('readline') + if readline.__doc__ and "libedit" in readline.__doc__: + raise unittest.SkipTest("libedit readline is not supported for pdb") + + def test_basic_completion(self): + script = textwrap.dedent(""" + import pdb; pdb.Pdb().set_trace() + # Concatenate strings so that the output doesn't appear in the source + print('hello' + '!') + """) + + # List everything starting with 'co', there should be multiple matches + # then add ntin and complete 'contin' to 'continue' + input = b"co\t\tntin\t\n" + + output = run_pty(script, input) + + self.assertIn(b'commands', output) + self.assertIn(b'condition', output) + self.assertIn(b'continue', output) + self.assertIn(b'hello!', output) + + def load_tests(loader, tests, pattern): from test import test_pdb tests.addTest(doctest.DocTestSuite(test_pdb)) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index 59dbef90380053..835280f2281cde 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -1,18 +1,15 @@ """ Very minimal unittests for parts of the readline module. """ -from contextlib import ExitStack -from errno import EIO import locale import os -import selectors -import subprocess import sys import tempfile import unittest from test.support import verbose from test.support.import_helper import import_module from test.support.os_helper import unlink, temp_dir, TESTFN +from test.support.pty_helper import run_pty from test.support.script_helper import assert_python_ok # Skip tests if there is no readline module @@ -304,55 +301,5 @@ def test_history_size(self): self.assertEqual(lines[-1].strip(), b"last input") -def run_pty(script, input=b"dummy input\r", env=None): - pty = import_module('pty') - output = bytearray() - [master, slave] = pty.openpty() - args = (sys.executable, '-c', script) - proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave, env=env) - os.close(slave) - with ExitStack() as cleanup: - cleanup.enter_context(proc) - def terminate(proc): - try: - proc.terminate() - except ProcessLookupError: - # Workaround for Open/Net BSD bug (Issue 16762) - pass - cleanup.callback(terminate, proc) - cleanup.callback(os.close, master) - # Avoid using DefaultSelector and PollSelector. Kqueue() does not - # work with pseudo-terminals on OS X < 10.9 (Issue 20365) and Open - # BSD (Issue 20667). Poll() does not work with OS X 10.6 or 10.4 - # either (Issue 20472). Hopefully the file descriptor is low enough - # to use with select(). - sel = cleanup.enter_context(selectors.SelectSelector()) - sel.register(master, selectors.EVENT_READ | selectors.EVENT_WRITE) - os.set_blocking(master, False) - while True: - for [_, events] in sel.select(): - if events & selectors.EVENT_READ: - try: - chunk = os.read(master, 0x10000) - except OSError as err: - # Linux raises EIO when slave is closed (Issue 5380) - if err.errno != EIO: - raise - chunk = b"" - if not chunk: - return output - output.extend(chunk) - if events & selectors.EVENT_WRITE: - try: - input = input[os.write(master, input):] - except OSError as err: - # Apparently EIO means the slave was closed - if err.errno != EIO: - raise - input = b"" # Stop writing - if not input: - sel.modify(master, selectors.EVENT_READ) - - if __name__ == "__main__": unittest.main() From 24216d0530fda84b482ab29490ddd0d496605e43 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Tue, 14 Nov 2023 17:15:10 +0100 Subject: [PATCH 1185/1206] [3.12] gh-111942: Fix crashes in TextIOWrapper.reconfigure() (GH-111976) (GH-112058) * Fix crash when encoding is not string or None. * Fix crash when both line_buffering and write_through raise exception when converted ti int. * Add a number of tests for constructor and reconfigure() method with invalid arguments. (cherry picked from commit ee06fffd38cb51ce1c045da9d8336d9ce13c318a) Co-authored-by: Serhiy Storchaka --- Lib/test/test_io.py | 86 ++++++++++++++++++- ...-11-10-22-08-28.gh-issue-111942.MDFm6v.rst | 2 + Modules/_io/textio.c | 39 ++++++++- 3 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-10-22-08-28.gh-issue-111942.MDFm6v.rst diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 247ecebd1a909a..0f4a56001c0f37 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -81,6 +81,10 @@ def _default_chunk_size(): ) +class BadIndex: + def __index__(self): + 1/0 + class MockRawIOWithoutRead: """A RawIO implementation without read(), so as to exercise the default RawIO.read() which calls readinto().""" @@ -2716,8 +2720,31 @@ def test_constructor(self): self.assertEqual(t.encoding, "utf-8") self.assertEqual(t.line_buffering, True) self.assertEqual("\xe9\n", t.readline()) - self.assertRaises(TypeError, t.__init__, b, encoding="utf-8", newline=42) - self.assertRaises(ValueError, t.__init__, b, encoding="utf-8", newline='xyzzy') + invalid_type = TypeError if self.is_C else ValueError + with self.assertRaises(invalid_type): + t.__init__(b, encoding=42) + with self.assertRaises(UnicodeEncodeError): + t.__init__(b, encoding='\udcfe') + with self.assertRaises(ValueError): + t.__init__(b, encoding='utf-8\0') + with self.assertRaises(invalid_type): + t.__init__(b, encoding="utf-8", errors=42) + if support.Py_DEBUG or sys.flags.dev_mode or self.is_C: + with self.assertRaises(UnicodeEncodeError): + t.__init__(b, encoding="utf-8", errors='\udcfe') + if support.Py_DEBUG or sys.flags.dev_mode: + # TODO: If encoded to UTF-8, should also be checked for + # embedded null characters. + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", errors='replace\0') + with self.assertRaises(TypeError): + t.__init__(b, encoding="utf-8", newline=42) + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", newline='\udcfe') + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", newline='\n\0') + with self.assertRaises(ValueError): + t.__init__(b, encoding="utf-8", newline='xyzzy') def test_uninitialized(self): t = self.TextIOWrapper.__new__(self.TextIOWrapper) @@ -3766,6 +3793,59 @@ def test_reconfigure_defaults(self): self.assertEqual(txt.detach().getvalue(), b'LF\nCRLF\r\n') + def test_reconfigure_errors(self): + txt = self.TextIOWrapper(self.BytesIO(), 'ascii', 'replace', '\r') + with self.assertRaises(TypeError): # there was a crash + txt.reconfigure(encoding=42) + if self.is_C: + with self.assertRaises(UnicodeEncodeError): + txt.reconfigure(encoding='\udcfe') + with self.assertRaises(LookupError): + txt.reconfigure(encoding='locale\0') + # TODO: txt.reconfigure(encoding='utf-8\0') + # TODO: txt.reconfigure(encoding='nonexisting') + with self.assertRaises(TypeError): + txt.reconfigure(errors=42) + if self.is_C: + with self.assertRaises(UnicodeEncodeError): + txt.reconfigure(errors='\udcfe') + # TODO: txt.reconfigure(errors='ignore\0') + # TODO: txt.reconfigure(errors='nonexisting') + with self.assertRaises(TypeError): + txt.reconfigure(newline=42) + with self.assertRaises(ValueError): + txt.reconfigure(newline='\udcfe') + with self.assertRaises(ValueError): + txt.reconfigure(newline='xyz') + if not self.is_C: + # TODO: Should fail in C too. + with self.assertRaises(ValueError): + txt.reconfigure(newline='\n\0') + if self.is_C: + # TODO: Use __bool__(), not __index__(). + with self.assertRaises(ZeroDivisionError): + txt.reconfigure(line_buffering=BadIndex()) + with self.assertRaises(OverflowError): + txt.reconfigure(line_buffering=2**1000) + with self.assertRaises(ZeroDivisionError): + txt.reconfigure(write_through=BadIndex()) + with self.assertRaises(OverflowError): + txt.reconfigure(write_through=2**1000) + with self.assertRaises(ZeroDivisionError): # there was a crash + txt.reconfigure(line_buffering=BadIndex(), + write_through=BadIndex()) + self.assertEqual(txt.encoding, 'ascii') + self.assertEqual(txt.errors, 'replace') + self.assertIs(txt.line_buffering, False) + self.assertIs(txt.write_through, False) + + txt.reconfigure(encoding='latin1', errors='ignore', newline='\r\n', + line_buffering=True, write_through=True) + self.assertEqual(txt.encoding, 'latin1') + self.assertEqual(txt.errors, 'ignore') + self.assertIs(txt.line_buffering, True) + self.assertIs(txt.write_through, True) + def test_reconfigure_newline(self): raw = self.BytesIO(b'CR\rEOF') txt = self.TextIOWrapper(raw, 'ascii', newline='\n') @@ -4791,9 +4871,11 @@ def load_tests(loader, tests, pattern): if test.__name__.startswith("C"): for name, obj in c_io_ns.items(): setattr(test, name, obj) + test.is_C = True elif test.__name__.startswith("Py"): for name, obj in py_io_ns.items(): setattr(test, name, obj) + test.is_C = False suite = loader.suiteClass() for test in tests: diff --git a/Misc/NEWS.d/next/Library/2023-11-10-22-08-28.gh-issue-111942.MDFm6v.rst b/Misc/NEWS.d/next/Library/2023-11-10-22-08-28.gh-issue-111942.MDFm6v.rst new file mode 100644 index 00000000000000..4fc505c8f257a6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-10-22-08-28.gh-issue-111942.MDFm6v.rst @@ -0,0 +1,2 @@ +Fix crashes in :meth:`io.TextIOWrapper.reconfigure` when pass invalid +arguments, e.g. non-string encoding. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index e8bf6bebad5509..d4797ca59ebea2 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1292,30 +1292,40 @@ textiowrapper_change_encoding(textio *self, PyObject *encoding, errors = &_Py_ID(strict); } } + Py_INCREF(errors); + const char *c_encoding = PyUnicode_AsUTF8(encoding); + if (c_encoding == NULL) { + Py_DECREF(encoding); + Py_DECREF(errors); + return -1; + } const char *c_errors = PyUnicode_AsUTF8(errors); if (c_errors == NULL) { Py_DECREF(encoding); + Py_DECREF(errors); return -1; } // Create new encoder & decoder PyObject *codec_info = _PyCodec_LookupTextEncoding( - PyUnicode_AsUTF8(encoding), "codecs.open()"); + c_encoding, "codecs.open()"); if (codec_info == NULL) { Py_DECREF(encoding); + Py_DECREF(errors); return -1; } if (_textiowrapper_set_decoder(self, codec_info, c_errors) != 0 || _textiowrapper_set_encoder(self, codec_info, c_errors) != 0) { Py_DECREF(codec_info); Py_DECREF(encoding); + Py_DECREF(errors); return -1; } Py_DECREF(codec_info); Py_SETREF(self->encoding, encoding); - Py_SETREF(self->errors, Py_NewRef(errors)); + Py_SETREF(self->errors, errors); return _textiowrapper_fix_encoder_state(self); } @@ -1346,6 +1356,26 @@ _io_TextIOWrapper_reconfigure_impl(textio *self, PyObject *encoding, int write_through; const char *newline = NULL; + if (encoding != Py_None && !PyUnicode_Check(encoding)) { + PyErr_Format(PyExc_TypeError, + "reconfigure() argument 'encoding' must be str or None, not %s", + Py_TYPE(encoding)->tp_name); + return NULL; + } + if (errors != Py_None && !PyUnicode_Check(errors)) { + PyErr_Format(PyExc_TypeError, + "reconfigure() argument 'errors' must be str or None, not %s", + Py_TYPE(errors)->tp_name); + return NULL; + } + if (newline_obj != NULL && newline_obj != Py_None && + !PyUnicode_Check(newline_obj)) + { + PyErr_Format(PyExc_TypeError, + "reconfigure() argument 'newline' must be str or None, not %s", + Py_TYPE(newline_obj)->tp_name); + return NULL; + } /* Check if something is in the read buffer */ if (self->decoded_chars != NULL) { if (encoding != Py_None || errors != Py_None || newline_obj != NULL) { @@ -1365,9 +1395,12 @@ _io_TextIOWrapper_reconfigure_impl(textio *self, PyObject *encoding, line_buffering = convert_optional_bool(line_buffering_obj, self->line_buffering); + if (line_buffering < 0) { + return NULL; + } write_through = convert_optional_bool(write_through_obj, self->write_through); - if (line_buffering < 0 || write_through < 0) { + if (write_through < 0) { return NULL; } From c1905527398da3c474ec783ad643330b405211fb Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Nov 2023 06:20:14 +0100 Subject: [PATCH 1186/1206] [3.12] Docs: Add the time to the HTML last updated format (GH-110091) (#112102) Docs: Add the time to the HTML last updated format (GH-110091) (cherry picked from commit 6c214dea7c503eb42bd130d43e8880f39bff0350) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/conf.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index 9f01bd89a35d3c..98b84db964bf5e 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -288,9 +288,8 @@ "pr_id": os.getenv("READTHEDOCS_VERSION") } -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%b %d, %Y' +# This 'Last updated on:' timestamp is inserted at the bottom of every page. +html_last_updated_fmt = time.strftime('%b %d, %Y (%H:%M UTC)', time.gmtime()) # Path to find HTML templates. templates_path = ['tools/templates'] From 91a33fde4826967aa929e53a234aff8a419c5166 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:08:05 +0100 Subject: [PATCH 1187/1206] [3.12] gh-108303: Delete `imp_dummy` test file (GH-112110) (#112114) gh-108303: Delete `imp_dummy` test file (GH-112110) (cherry picked from commit 422c0f030170490c001575303d9e628a0298d457) Co-authored-by: Nikita Sobolev --- Lib/test/imp_dummy.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 Lib/test/imp_dummy.py diff --git a/Lib/test/imp_dummy.py b/Lib/test/imp_dummy.py deleted file mode 100644 index 2a4deb49547cf4..00000000000000 --- a/Lib/test/imp_dummy.py +++ /dev/null @@ -1,3 +0,0 @@ -# Fodder for test of issue24748 in test_imp - -dummy_name = True From 1445d77282f9082f3fecde772ddf6bb2f5a383f1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 15 Nov 2023 14:55:46 +0100 Subject: [PATCH 1188/1206] [3.12] gh-111942: Fix SystemError in the TextIOWrapper constructor (GH-112061) (GH-112089) In non-debug more the check for the "errors" argument is skipped, and then PyUnicode_AsUTF8() can fail, but its result was not checked. Co-authored-by: Victor Stinner (cherry picked from commit 9302f05f9af07332c414b3c19003efd1b1763cf3) Co-authored-by: Serhiy Storchaka --- Lib/test/test_io.py | 4 +--- .../2023-11-14-18-43-55.gh-issue-111942.x1pnrj.rst | 2 ++ Modules/_io/textio.c | 13 +++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-14-18-43-55.gh-issue-111942.x1pnrj.rst diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 0f4a56001c0f37..196b7d2b1429ab 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2732,9 +2732,7 @@ def test_constructor(self): if support.Py_DEBUG or sys.flags.dev_mode or self.is_C: with self.assertRaises(UnicodeEncodeError): t.__init__(b, encoding="utf-8", errors='\udcfe') - if support.Py_DEBUG or sys.flags.dev_mode: - # TODO: If encoded to UTF-8, should also be checked for - # embedded null characters. + if support.Py_DEBUG or sys.flags.dev_mode or self.is_C: with self.assertRaises(ValueError): t.__init__(b, encoding="utf-8", errors='replace\0') with self.assertRaises(TypeError): diff --git a/Misc/NEWS.d/next/Library/2023-11-14-18-43-55.gh-issue-111942.x1pnrj.rst b/Misc/NEWS.d/next/Library/2023-11-14-18-43-55.gh-issue-111942.x1pnrj.rst new file mode 100644 index 00000000000000..ca58a6fa5d6ae1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-14-18-43-55.gh-issue-111942.x1pnrj.rst @@ -0,0 +1,2 @@ +Fix SystemError in the TextIOWrapper constructor with non-encodable "errors" +argument in non-debug mode. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index d4797ca59ebea2..efada7f0495357 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1119,6 +1119,15 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, else if (io_check_errors(errors)) { return -1; } + Py_ssize_t errors_len; + const char *errors_str = PyUnicode_AsUTF8AndSize(errors, &errors_len); + if (errors_str == NULL) { + return -1; + } + if (strlen(errors_str) != (size_t)errors_len) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + return -1; + } if (validate_newline(newline) < 0) { return -1; @@ -1191,11 +1200,11 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, /* Build the decoder object */ _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->state = state; - if (_textiowrapper_set_decoder(self, codec_info, PyUnicode_AsUTF8(errors)) != 0) + if (_textiowrapper_set_decoder(self, codec_info, errors_str) != 0) goto error; /* Build the encoder object */ - if (_textiowrapper_set_encoder(self, codec_info, PyUnicode_AsUTF8(errors)) != 0) + if (_textiowrapper_set_encoder(self, codec_info, errors_str) != 0) goto error; /* Finished sorting out the codec details */ From 77f59bf66448c0c0ea73066d4a220276a3fab99d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:48:04 +0100 Subject: [PATCH 1189/1206] [3.12] Fix typo in perf profiling docs (GH-112112) (#112117) Fix typo in perf profiling docs (GH-112112) (cherry picked from commit 0cfdd6e3d17fee8c1c1f4b42b2146abcb43aa34b) Co-authored-by: Ryuji Tsutsui --- Doc/howto/perf_profiling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst index af7b67d2042950..bb1c00e0aa51d5 100644 --- a/Doc/howto/perf_profiling.rst +++ b/Doc/howto/perf_profiling.rst @@ -97,7 +97,7 @@ Then we can use ``perf report`` to analyze the data: | | | | | |--2.97%--_PyObject_Malloc ... -As you can see, the Python functions are not shown in the output, only ``_Py_Eval_EvalFrameDefault`` +As you can see, the Python functions are not shown in the output, only ``_PyEval_EvalFrameDefault`` (the function that evaluates the Python bytecode) shows up. Unfortunately that's not very useful because all Python functions use the same C function to evaluate bytecode so we cannot know which Python function corresponds to which bytecode-evaluating function. From 427cf61b51e5fb95ebee6750ca530cc07e7a74e7 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 16 Nov 2023 02:44:39 +0200 Subject: [PATCH 1190/1206] [3.12] gh-111062: CI: Move OS test jobs to reusable workflows (gh-111568) CI: Move OS test jobs to reusable workflows Co-authored-by: Donghee Na --- .github/workflows/build.yml | 161 +++---------------------- .github/workflows/reusable-macos.yml | 46 +++++++ .github/workflows/reusable-ubuntu.yml | 71 +++++++++++ .github/workflows/reusable-windows.yml | 53 ++++++++ 4 files changed, 184 insertions(+), 147 deletions(-) create mode 100644 .github/workflows/reusable-macos.yml create mode 100644 .github/workflows/reusable-ubuntu.yml create mode 100644 .github/workflows/reusable-windows.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0bce1c57f17624..80a2126696a0cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -108,7 +108,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 - name: Install dependencies run: | @@ -208,159 +208,32 @@ jobs: if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME run: make check-c-globals - build_win32: - name: 'Windows (x86)' - runs-on: windows-latest - timeout-minutes: 60 + build_windows: + name: 'Windows' needs: check_source if: needs.check_source.outputs.run_tests == 'true' - env: - IncludeUwp: 'true' - steps: - - uses: actions/checkout@v4 - - name: Build CPython - run: .\PCbuild\build.bat -e -d -p Win32 - - name: Display build info - run: .\python.bat -m test.pythoninfo - - name: Tests - run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 - - build_win_amd64: - name: 'Windows (x64)' - runs-on: windows-latest - timeout-minutes: 60 - needs: check_source - if: needs.check_source.outputs.run_tests == 'true' - env: - IncludeUwp: 'true' - steps: - - uses: actions/checkout@v4 - - name: Register MSVC problem matcher - run: echo "::add-matcher::.github/problem-matchers/msvc.json" - - name: Build CPython - run: .\PCbuild\build.bat -e -d -p x64 - - name: Display build info - run: .\python.bat -m test.pythoninfo - - name: Tests - run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 - - build_win_arm64: - name: 'Windows (arm64)' - runs-on: windows-latest - timeout-minutes: 60 - needs: check_source - if: needs.check_source.outputs.run_tests == 'true' - env: - IncludeUwp: 'true' - steps: - - uses: actions/checkout@v4 - - name: Register MSVC problem matcher - run: echo "::add-matcher::.github/problem-matchers/msvc.json" - - name: Build CPython - run: .\PCbuild\build.bat -e -d -p arm64 + uses: ./.github/workflows/reusable-windows.yml build_macos: name: 'macOS' - runs-on: macos-latest - timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' - env: - HOMEBREW_NO_ANALYTICS: 1 - HOMEBREW_NO_AUTO_UPDATE: 1 - HOMEBREW_NO_INSTALL_CLEANUP: 1 - PYTHONSTRICTEXTENSIONBUILD: 1 - steps: - - uses: actions/checkout@v4 - - name: Restore config.cache - uses: actions/cache@v3 - with: - path: config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - - name: Install Homebrew dependencies - run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk - - name: Configure CPython - run: | - GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ - GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \ - ./configure \ - --config-cache \ - --with-pydebug \ - --prefix=/opt/python-dev \ - --with-openssl="$(brew --prefix openssl@3.0)" - - name: Build CPython - run: make -j4 - - name: Display build info - run: make pythoninfo - - name: Tests - run: make buildbottest TESTOPTS="-j4 -uall,-cpu" + uses: ./.github/workflows/reusable-macos.yml + with: + config_hash: ${{ needs.check_source.outputs.config_hash }} build_ubuntu: name: 'Ubuntu' - runs-on: ubuntu-20.04 - timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' - env: - OPENSSL_VER: 3.0.11 - PYTHONSTRICTEXTENSIONBUILD: 1 - steps: - - uses: actions/checkout@v4 - - name: Register gcc problem matcher - run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Install dependencies - run: sudo ./.github/workflows/posix-deps-apt.sh - - name: Configure OpenSSL env vars - run: | - echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV - echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV - - name: 'Restore OpenSSL build' - id: cache-openssl - uses: actions/cache@v3 - with: - path: ./multissl/openssl/${{ env.OPENSSL_VER }} - key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} - - name: Install OpenSSL - if: steps.cache-openssl.outputs.cache-hit != 'true' - run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux - - name: Add ccache to PATH - run: | - echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV - - name: Configure ccache action - uses: hendrikmuhs/ccache-action@v1.2 - - name: Setup directory envs for out-of-tree builds - run: | - echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV - echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV - - name: Create directories for read-only out-of-tree builds - run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR - - name: Bind mount sources read-only - run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR - - name: Restore config.cache - uses: actions/cache@v3 - with: - path: ${{ env.CPYTHON_BUILDDIR }}/config.cache - key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - - name: Configure CPython out-of-tree - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: | + uses: ./.github/workflows/reusable-ubuntu.yml + with: + config_hash: ${{ needs.check_source.outputs.config_hash }} + options: | ../cpython-ro-srcdir/configure \ --config-cache \ --with-pydebug \ --with-openssl=$OPENSSL_DIR - - name: Build CPython out-of-tree - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: make -j4 - - name: Display build info - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: make pythoninfo - - name: Remount sources writable for tests - # some tests write to srcdir, lack of pyc files slows down testing - run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw - - name: Tests - working-directory: ${{ env.CPYTHON_BUILDDIR }} - run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu" build_ubuntu_ssltests: name: 'Ubuntu SSL tests with OpenSSL' @@ -429,7 +302,7 @@ jobs: - uses: actions/checkout@v4 - name: Register gcc problem matcher run: echo "::add-matcher::.github/problem-matchers/gcc.json" - - name: Install Dependencies + - name: Install dependencies run: sudo ./.github/workflows/posix-deps-apt.sh - name: Configure OpenSSL env vars run: | @@ -586,12 +459,10 @@ jobs: - check_source # Transitive dependency, needed to access `run_tests` value - check-docs - check_generated_files - - build_win32 - - build_win_amd64 - - build_win_arm64 - build_macos - build_ubuntu - build_ubuntu_ssltests + - build_windows - test_hypothesis - build_asan @@ -604,8 +475,6 @@ jobs: allowed-failures: >- build_macos, build_ubuntu_ssltests, - build_win32, - build_win_arm64, test_hypothesis, allowed-skips: >- ${{ @@ -619,12 +488,10 @@ jobs: needs.check_source.outputs.run_tests != 'true' && ' check_generated_files, - build_win32, - build_win_amd64, - build_win_arm64, build_macos, build_ubuntu, build_ubuntu_ssltests, + build_windows, build_asan, ' || '' diff --git a/.github/workflows/reusable-macos.yml b/.github/workflows/reusable-macos.yml new file mode 100644 index 00000000000000..3ed8303ac16d97 --- /dev/null +++ b/.github/workflows/reusable-macos.yml @@ -0,0 +1,46 @@ +on: + workflow_call: + inputs: + config_hash: + required: true + type: string + free-threaded: + required: false + type: boolean + default: false + +jobs: + build_macos: + name: 'build and test' + runs-on: macos-latest + timeout-minutes: 60 + env: + HOMEBREW_NO_ANALYTICS: 1 + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + PYTHONSTRICTEXTENSIONBUILD: 1 + steps: + - uses: actions/checkout@v4 + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ inputs.config_hash }} + - name: Install Homebrew dependencies + run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk + - name: Configure CPython + run: | + GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ + GDBM_LIBS="-L$(brew --prefix gdbm)/lib -lgdbm" \ + ./configure \ + --config-cache \ + --with-pydebug \ + ${{ inputs.free-threaded && '--disable-gil' || '' }} \ + --prefix=/opt/python-dev \ + --with-openssl="$(brew --prefix openssl@3.0)" + - name: Build CPython + run: make -j4 + - name: Display build info + run: make pythoninfo + - name: Tests + run: make buildbottest TESTOPTS="-j4 -uall,-cpu" diff --git a/.github/workflows/reusable-ubuntu.yml b/.github/workflows/reusable-ubuntu.yml new file mode 100644 index 00000000000000..56268c8bfd3419 --- /dev/null +++ b/.github/workflows/reusable-ubuntu.yml @@ -0,0 +1,71 @@ +on: + workflow_call: + inputs: + config_hash: + required: true + type: string + options: + required: true + type: string + +jobs: + build_ubuntu_reusable: + name: 'build and test' + timeout-minutes: 60 + runs-on: ubuntu-20.04 + env: + OPENSSL_VER: 3.0.11 + PYTHONSTRICTEXTENSIONBUILD: 1 + steps: + - uses: actions/checkout@v4 + - name: Register gcc problem matcher + run: echo "::add-matcher::.github/problem-matchers/gcc.json" + - name: Install dependencies + run: sudo ./.github/workflows/posix-deps-apt.sh + - name: Configure OpenSSL env vars + run: | + echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV + echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV + - name: 'Restore OpenSSL build' + id: cache-openssl + uses: actions/cache@v3 + with: + path: ./multissl/openssl/${{ env.OPENSSL_VER }} + key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} + - name: Install OpenSSL + if: steps.cache-openssl.outputs.cache-hit != 'true' + run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux + - name: Add ccache to PATH + run: | + echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV + - name: Configure ccache action + uses: hendrikmuhs/ccache-action@v1.2 + - name: Setup directory envs for out-of-tree builds + run: | + echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV + echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV + - name: Create directories for read-only out-of-tree builds + run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR + - name: Bind mount sources read-only + run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR + - name: Restore config.cache + uses: actions/cache@v3 + with: + path: ${{ env.CPYTHON_BUILDDIR }}/config.cache + key: ${{ github.job }}-${{ runner.os }}-${{ inputs.config_hash }} + - name: Configure CPython out-of-tree + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: ${{ inputs.options }} + - name: Build CPython out-of-tree + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: make -j4 + - name: Display build info + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: make pythoninfo + - name: Remount sources writable for tests + # some tests write to srcdir, lack of pyc files slows down testing + run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw + - name: Tests + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu" diff --git a/.github/workflows/reusable-windows.yml b/.github/workflows/reusable-windows.yml new file mode 100644 index 00000000000000..98fb7cfa015587 --- /dev/null +++ b/.github/workflows/reusable-windows.yml @@ -0,0 +1,53 @@ +on: + workflow_call: + inputs: + free-threaded: + required: false + type: boolean + default: false + +jobs: + build_win32: + name: 'build and test (x86)' + runs-on: windows-latest + timeout-minutes: 60 + env: + IncludeUwp: 'true' + steps: + - uses: actions/checkout@v4 + - name: Build CPython + run: .\PCbuild\build.bat -e -d -p Win32 ${{ inputs.free-threaded && '--disable-gil' || '' }} + - name: Display build info + run: .\python.bat -m test.pythoninfo + - name: Tests + run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 + + build_win_amd64: + name: 'build and test (x64)' + runs-on: windows-latest + timeout-minutes: 60 + env: + IncludeUwp: 'true' + steps: + - uses: actions/checkout@v4 + - name: Register MSVC problem matcher + run: echo "::add-matcher::.github/problem-matchers/msvc.json" + - name: Build CPython + run: .\PCbuild\build.bat -e -d -p x64 ${{ inputs.free-threaded && '--disable-gil' || '' }} + - name: Display build info + run: .\python.bat -m test.pythoninfo + - name: Tests + run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 + + build_win_arm64: + name: 'build (arm64)' + runs-on: windows-latest + timeout-minutes: 60 + env: + IncludeUwp: 'true' + steps: + - uses: actions/checkout@v4 + - name: Register MSVC problem matcher + run: echo "::add-matcher::.github/problem-matchers/msvc.json" + - name: Build CPython + run: .\PCbuild\build.bat -e -d -p arm64 ${{ inputs.free-threaded && '--disable-gil' || '' }} From 2e17a81719921da8e75e7035ab057fb7bd408d96 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 16 Nov 2023 13:34:29 +0100 Subject: [PATCH 1191/1206] [3.12] gh-110812: Isolating Extension Modules HOWTO: List GC-related gotchas (GH-111504) (GH-112148) gh-110812: Isolating Extension Modules HOWTO: List GC-related gotchas (GH-111504) (cherry picked from commit 985679f05d1b72965bfbed99d1499c22815375e4) Co-authored-by: Petr Viktorin Co-authored-by: Hugo van Kemenade Co-authored-by: Eric Snow --- Doc/howto/isolating-extensions.rst | 103 +++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 6 deletions(-) diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 8f3787f2d2f145..835c0afad7c6c8 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -339,12 +339,44 @@ That is, heap types should: - Define a traverse function using ``Py_tp_traverse``, which visits the type (e.g. using :c:expr:`Py_VISIT(Py_TYPE(self))`). -Please refer to the :ref:`the documentation ` of +Please refer to the the documentation of :c:macro:`Py_TPFLAGS_HAVE_GC` and :c:member:`~PyTypeObject.tp_traverse` for additional considerations. -If your traverse function delegates to the ``tp_traverse`` of its base class -(or another type), ensure that ``Py_TYPE(self)`` is visited only once. +The API for defining heap types grew organically, leaving it +somewhat awkward to use in its current state. +The following sections will guide you through common issues. + + +``tp_traverse`` in Python 3.8 and lower +....................................... + +The requirement to visit the type from ``tp_traverse`` was added in Python 3.9. +If you support Python 3.8 and lower, the traverse function must *not* +visit the type, so it must be more complicated:: + + static int my_traverse(PyObject *self, visitproc visit, void *arg) + { + if (Py_Version >= 0x03090000) { + Py_VISIT(Py_TYPE(self)); + } + return 0; + } + +Unfortunately, :c:data:`Py_Version` was only added in Python 3.11. +As a replacement, use: + +* :c:macro:`PY_VERSION_HEX`, if not using the stable ABI, or +* :py:data:`sys.version_info` (via :c:func:`PySys_GetObject` and + :c:func:`PyArg_ParseTuple`). + + +Delegating ``tp_traverse`` +.......................... + +If your traverse function delegates to the :c:member:`~PyTypeObject.tp_traverse` +of its base class (or another type), ensure that ``Py_TYPE(self)`` is visited +only once. Note that only heap type are expected to visit the type in ``tp_traverse``. For example, if your traverse function includes:: @@ -356,11 +388,70 @@ For example, if your traverse function includes:: if (base->tp_flags & Py_TPFLAGS_HEAPTYPE) { // a heap type's tp_traverse already visited Py_TYPE(self) } else { - Py_VISIT(Py_TYPE(self)); + if (Py_Version >= 0x03090000) { + Py_VISIT(Py_TYPE(self)); + } } -It is not necessary to handle the type's reference count in ``tp_new`` -and ``tp_clear``. +It is not necessary to handle the type's reference count in +:c:member:`~PyTypeObject.tp_new` and :c:member:`~PyTypeObject.tp_clear`. + + +Defining ``tp_dealloc`` +....................... + +If your type has a custom :c:member:`~PyTypeObject.tp_dealloc` function, +it needs to: + +- call :c:func:`PyObject_GC_UnTrack` before any fields are invalidated, and +- decrement the reference count of the type. + +To keep the type valid while ``tp_free`` is called, the type's refcount needs +to be decremented *after* the instance is deallocated. For example:: + + static void my_dealloc(PyObject *self) + { + PyObject_GC_UnTrack(self); + ... + PyTypeObject *type = Py_TYPE(self); + type->tp_free(self); + Py_DECREF(type); + } + +The default ``tp_dealloc`` function does this, so +if your type does *not* override +``tp_dealloc`` you don't need to add it. + + +Not overriding ``tp_free`` +.......................... + +The :c:member:`~PyTypeObject.tp_free` slot of a heap type must be set to +:c:func:`PyObject_GC_Del`. +This is the default; do not override it. + + +Avoiding ``PyObject_New`` +......................... + +GC-tracked objects need to be allocated using GC-aware functions. + +If you use use :c:func:`PyObject_New` or :c:func:`PyObject_NewVar`: + +- Get and call type's :c:member:`~PyTypeObject.tp_alloc` slot, if possible. + That is, replace ``TYPE *o = PyObject_New(TYPE, typeobj)`` with:: + + TYPE *o = typeobj->tp_alloc(typeobj, 0); + + Replace ``o = PyObject_NewVar(TYPE, typeobj, size)`` with the same, + but use size instead of the 0. + +- If the above is not possible (e.g. inside a custom ``tp_alloc``), + call :c:func:`PyObject_GC_New` or :c:func:`PyObject_GC_NewVar`:: + + TYPE *o = PyObject_GC_New(TYPE, typeobj); + + TYPE *o = PyObject_GC_NewVar(TYPE, typeobj, size); Module State Access from Classes From a498433df2015143fe761dd1b839268fdba0e7d6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 16 Nov 2023 15:55:40 +0100 Subject: [PATCH 1192/1206] [3.12] gh-112088: Run autoreconf in GHA check_generated_files (GH-112090) (#112159) gh-112088: Run autoreconf in GHA check_generated_files (#112090) The "Check if generated files are up to date" job of GitHub Actions now runs the "autoreconf -ivf -Werror" command instead of the "make regen-configure" command to avoid depending on the external quay.io server. Add Tools/build/regen-configure.sh script to regenerate the configure with an Ubuntu container image. The "quay.io/tiran/cpython_autoconf:271" container image (https://github.com/tiran/cpython_autoconf) is no longer used. (cherry picked from commit d9fd33a869d2be769ff596530f63ee099465b037) --- .github/workflows/build.yml | 11 +- .github/workflows/posix-deps-apt.sh | 2 + Doc/using/configure.rst | 17 ++- Makefile.pre.in | 8 +- ...-11-15-13-40-29.gh-issue-112088.UJQxxh.rst | 5 + Tools/build/regen-configure.sh | 31 ++++ aclocal.m4 | 82 +---------- configure | 136 +++++++++--------- configure.ac | 15 +- 9 files changed, 139 insertions(+), 168 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-11-15-13-40-29.gh-issue-112088.UJQxxh.rst create mode 100755 Tools/build/regen-configure.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 80a2126696a0cc..545dd8c15dcf13 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -147,7 +147,9 @@ jobs: check_generated_files: name: 'Check if generated files are up to date' - runs-on: ubuntu-latest + # Don't use ubuntu-latest but a specific version to make the job + # reproducible: to get the same tools versions (autoconf, aclocal, ...) + runs-on: ubuntu-22.04 timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' @@ -170,15 +172,16 @@ jobs: - name: Check Autoconf and aclocal versions run: | grep "Generated by GNU Autoconf 2.71" configure - grep "aclocal 1.16.4" aclocal.m4 + grep "aclocal 1.16.5" aclocal.m4 grep -q "runstatedir" configure grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4 - name: Configure CPython run: | # Build Python with the libpython dynamic library ./configure --config-cache --with-pydebug --enable-shared - - name: Regenerate autoconf files with container image - run: make regen-configure + - name: Regenerate autoconf files + # Same command used by Tools/build/regen-configure.sh ($AUTORECONF) + run: autoreconf -ivf -Werror - name: Build CPython run: | # Deepfreeze will usually cause global objects to be added or removed, diff --git a/.github/workflows/posix-deps-apt.sh b/.github/workflows/posix-deps-apt.sh index a220896f2cd7be..bbae378f7b994e 100755 --- a/.github/workflows/posix-deps-apt.sh +++ b/.github/workflows/posix-deps-apt.sh @@ -1,9 +1,11 @@ #!/bin/sh apt-get update +# autoconf-archive is needed by autoreconf (check_generated_files job) apt-get -yq install \ build-essential \ pkg-config \ + autoconf-archive \ ccache \ gdb \ lcov \ diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 11b6b53f8bb269..7f250f1b2c2a51 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -57,14 +57,21 @@ files. Commands to regenerate all generated files:: The ``Makefile.pre.in`` file documents generated files, their inputs, and tools used to regenerate them. Search for ``regen-*`` make targets. -The ``make regen-configure`` command runs `tiran/cpython_autoconf -`_ container for reproducible build; -see container ``entry.sh`` script. The container is optional, the following -command can be run locally, the generated files depend on autoconf and aclocal -versions:: +configure script +---------------- + +The ``make regen-configure`` command regenerates the ``aclocal.m4`` file and +the ``configure`` script using the ``Tools/build/regen-configure.sh`` shell +script which uses an Ubuntu container to get the same tools versions and have a +reproducible output. + +The container is optional, the following command can be run locally:: autoreconf -ivf -Werror +The generated files can change depending on the exact ``autoconf-archive``, +``aclocal`` and ``pkg-config`` versions. + .. _configure-options: diff --git a/Makefile.pre.in b/Makefile.pre.in index 812bc93055e58e..37fe523625e02f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2594,15 +2594,9 @@ recheck: autoconf: (cd $(srcdir); autoreconf -ivf -Werror) -# See https://github.com/tiran/cpython_autoconf container .PHONY: regen-configure regen-configure: - @if command -v podman >/dev/null; then RUNTIME="podman"; else RUNTIME="docker"; fi; \ - if ! command -v $$RUNTIME; then echo "$@ needs either Podman or Docker container runtime." >&2; exit 1; fi; \ - if command -v selinuxenabled >/dev/null && selinuxenabled; then OPT=":Z"; fi; \ - CMD="$$RUNTIME run --rm --pull=always -v $(abs_srcdir):/src$$OPT quay.io/tiran/cpython_autoconf:271"; \ - echo $$CMD; \ - $$CMD || exit $? + $(srcdir)/Tools/build/regen-configure.sh # Create a tags file for vi tags:: diff --git a/Misc/NEWS.d/next/Build/2023-11-15-13-40-29.gh-issue-112088.UJQxxh.rst b/Misc/NEWS.d/next/Build/2023-11-15-13-40-29.gh-issue-112088.UJQxxh.rst new file mode 100644 index 00000000000000..b176d06ec8d749 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-11-15-13-40-29.gh-issue-112088.UJQxxh.rst @@ -0,0 +1,5 @@ +Add ``Tools/build/regen-configure.sh`` script to regenerate the ``configure`` +with an Ubuntu container image. The ``quay.io/tiran/cpython_autoconf:271`` +container image (`tiran/cpython_autoconf +`_) is no longer used. Patch by +Victor Stinner. diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh new file mode 100755 index 00000000000000..e34a36c1a573e5 --- /dev/null +++ b/Tools/build/regen-configure.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -e -x + +# The check_generated_files job of .github/workflows/build.yml must kept in +# sync with this script. Use the same container image than the job so the job +# doesn't need to run autoreconf in a container. +IMAGE="ubuntu:22.04" +DEPENDENCIES="autotools-dev autoconf autoconf-archive pkg-config" +AUTORECONF="autoreconf -ivf -Werror" + +WORK_DIR="/src" +SHELL_CMD="apt-get update && apt-get -yq install $DEPENDENCIES && cd $WORK_DIR && $AUTORECONF" + +abs_srcdir=$(cd $(dirname $0)/../..; pwd) + +if podman --version &>/dev/null; then + RUNTIME="podman" +elif docker --version &>/dev/null; then + RUNTIME="docker" +else + echo "$@ needs either Podman or Docker container runtime." >&2 + exit 1 +fi + +PATH_OPT="" +if command -v selinuxenabled >/dev/null && selinuxenabled; then + PATH_OPT=":Z" +fi + +"$RUNTIME" run --rm -v "$abs_srcdir:$WORK_DIR$PATH_OPT" "$IMAGE" /usr/bin/bash -c "$SHELL_CMD" diff --git a/aclocal.m4 b/aclocal.m4 index da8ee95b9c7f6b..09ae5d1aa8a608 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.16.4 -*- Autoconf -*- +# generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. @@ -276,7 +276,7 @@ AC_DEFUN([AX_CHECK_OPENSSL], [ ]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# serial 11 (pkg-config-0.29.1) +# serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson @@ -318,7 +318,7 @@ dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], -[m4_define([PKG_MACROS_VERSION], [0.29.1]) +[m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ @@ -419,7 +419,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no -AC_MSG_CHECKING([for $1]) +AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) @@ -429,11 +429,11 @@ and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else + else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs @@ -450,7 +450,7 @@ installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full @@ -551,74 +551,6 @@ AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR -dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, -dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], -dnl [DESCRIPTION], [DEFAULT]) -dnl ------------------------------------------ -dnl -dnl Prepare a "--with-" configure option using the lowercase -dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and -dnl PKG_CHECK_MODULES in a single macro. -AC_DEFUN([PKG_WITH_MODULES], -[ -m4_pushdef([with_arg], m4_tolower([$1])) - -m4_pushdef([description], - [m4_default([$5], [build with ]with_arg[ support])]) - -m4_pushdef([def_arg], [m4_default([$6], [auto])]) -m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) -m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) - -m4_case(def_arg, - [yes],[m4_pushdef([with_without], [--without-]with_arg)], - [m4_pushdef([with_without],[--with-]with_arg)]) - -AC_ARG_WITH(with_arg, - AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, - [AS_TR_SH([with_]with_arg)=def_arg]) - -AS_CASE([$AS_TR_SH([with_]with_arg)], - [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], - [auto],[PKG_CHECK_MODULES([$1],[$2], - [m4_n([def_action_if_found]) $3], - [m4_n([def_action_if_not_found]) $4])]) - -m4_popdef([with_arg]) -m4_popdef([description]) -m4_popdef([def_arg]) - -])dnl PKG_WITH_MODULES - -dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, -dnl [DESCRIPTION], [DEFAULT]) -dnl ----------------------------------------------- -dnl -dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES -dnl check._[VARIABLE-PREFIX] is exported as make variable. -AC_DEFUN([PKG_HAVE_WITH_MODULES], -[ -PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) - -AM_CONDITIONAL([HAVE_][$1], - [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) -])dnl PKG_HAVE_WITH_MODULES - -dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, -dnl [DESCRIPTION], [DEFAULT]) -dnl ------------------------------------------------------ -dnl -dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after -dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make -dnl and preprocessor variable. -AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], -[ -PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) - -AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], - [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) -])dnl PKG_HAVE_DEFINE_WITH_MODULES - # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2021 Free Software Foundation, Inc. diff --git a/configure b/configure index 778eacf51c72f1..99dd1fe595805e 100755 --- a/configure +++ b/configure @@ -13197,8 +13197,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBUUID" >&5 -printf %s "checking for LIBUUID... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uuid >= 2.20" >&5 +printf %s "checking for uuid >= 2.20... " >&6; } if test -n "$LIBUUID_CFLAGS"; then pkg_cv_LIBUUID_CFLAGS="$LIBUUID_CFLAGS" @@ -13238,7 +13238,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -13378,7 +13378,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -14086,8 +14086,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBFFI" >&5 -printf %s "checking for LIBFFI... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libffi" >&5 +printf %s "checking for libffi... " >&6; } if test -n "$LIBFFI_CFLAGS"; then pkg_cv_LIBFFI_CFLAGS="$LIBFFI_CFLAGS" @@ -14127,7 +14127,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -14214,7 +14214,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -14604,8 +14604,8 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBNSL" >&5 -printf %s "checking for LIBNSL... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libnsl" >&5 +printf %s "checking for libnsl... " >&6; } if test -n "$LIBNSL_CFLAGS"; then pkg_cv_LIBNSL_CFLAGS="$LIBNSL_CFLAGS" @@ -14645,7 +14645,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -14749,7 +14749,7 @@ esac LIBNSL_LIBS=${LIBNSL_LIBS-$libnsl} elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } LIBNSL_CFLAGS=${LIBNSL_CFLAGS-""} @@ -14897,8 +14897,8 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBSQLITE3" >&5 -printf %s "checking for LIBSQLITE3... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sqlite3 >= 3.7.15" >&5 +printf %s "checking for sqlite3 >= 3.7.15... " >&6; } if test -n "$LIBSQLITE3_CFLAGS"; then pkg_cv_LIBSQLITE3_CFLAGS="$LIBSQLITE3_CFLAGS" @@ -14938,7 +14938,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -14960,7 +14960,7 @@ fi elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } LIBSQLITE3_CFLAGS=${LIBSQLITE3_CFLAGS-""} @@ -15661,8 +15661,8 @@ for _QUERY in \ pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TCLTK" >&5 -printf %s "checking for TCLTK... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $_QUERY" >&5 +printf %s "checking for $_QUERY... " >&6; } if test -n "$TCLTK_CFLAGS"; then pkg_cv_TCLTK_CFLAGS="$TCLTK_CFLAGS" @@ -15702,7 +15702,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -15720,7 +15720,7 @@ fi found_tcltk=no elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_tcltk=no else @@ -15758,8 +15758,8 @@ case $ac_sys_system in #( pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for X11" >&5 -printf %s "checking for X11... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for x11" >&5 +printf %s "checking for x11... " >&6; } if test -n "$X11_CFLAGS"; then pkg_cv_X11_CFLAGS="$X11_CFLAGS" @@ -15799,7 +15799,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -15826,7 +15826,7 @@ Alternatively, you may set the environment variables X11_CFLAGS and X11_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} @@ -19713,8 +19713,8 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ZLIB" >&5 -printf %s "checking for ZLIB... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib >= 1.2.0" >&5 +printf %s "checking for zlib >= 1.2.0... " >&6; } if test -n "$ZLIB_CFLAGS"; then pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS" @@ -19754,7 +19754,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -19897,7 +19897,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -20061,8 +20061,8 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BZIP2" >&5 -printf %s "checking for BZIP2... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for bzip2" >&5 +printf %s "checking for bzip2... " >&6; } if test -n "$BZIP2_CFLAGS"; then pkg_cv_BZIP2_CFLAGS="$BZIP2_CFLAGS" @@ -20102,7 +20102,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -20198,7 +20198,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -20289,8 +20289,8 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBLZMA" >&5 -printf %s "checking for LIBLZMA... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for liblzma" >&5 +printf %s "checking for liblzma... " >&6; } if test -n "$LIBLZMA_CFLAGS"; then pkg_cv_LIBLZMA_CFLAGS="$LIBLZMA_CFLAGS" @@ -20330,7 +20330,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -20426,7 +20426,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -21757,8 +21757,8 @@ fi pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBCRYPT" >&5 -printf %s "checking for LIBCRYPT... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libxcrypt >= 3.1.1" >&5 +printf %s "checking for libxcrypt >= 3.1.1... " >&6; } if test -n "$LIBCRYPT_CFLAGS"; then pkg_cv_LIBCRYPT_CFLAGS="$LIBCRYPT_CFLAGS" @@ -21798,7 +21798,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -21898,7 +21898,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -24566,8 +24566,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBREADLINE" >&5 -printf %s "checking for LIBREADLINE... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for readline" >&5 +printf %s "checking for readline... " >&6; } if test -n "$LIBREADLINE_CFLAGS"; then pkg_cv_LIBREADLINE_CFLAGS="$LIBREADLINE_CFLAGS" @@ -24607,7 +24607,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -24700,7 +24700,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -24797,8 +24797,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBEDIT" >&5 -printf %s "checking for LIBEDIT... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libedit" >&5 +printf %s "checking for libedit... " >&6; } if test -n "$LIBEDIT_CFLAGS"; then pkg_cv_LIBEDIT_CFLAGS="$LIBEDIT_CFLAGS" @@ -24838,7 +24838,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -24933,7 +24933,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -25685,8 +25685,8 @@ then : if test "$ac_sys_system" != "Darwin"; then pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CURSES" >&5 -printf %s "checking for CURSES... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncursesw" >&5 +printf %s "checking for ncursesw... " >&6; } if test -n "$CURSES_CFLAGS"; then pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" @@ -25726,7 +25726,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -25804,7 +25804,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -25885,8 +25885,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CURSES" >&5 -printf %s "checking for CURSES... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncurses" >&5 +printf %s "checking for ncurses... " >&6; } if test -n "$CURSES_CFLAGS"; then pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" @@ -25926,7 +25926,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -26002,7 +26002,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -26120,8 +26120,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PANEL" >&5 -printf %s "checking for PANEL... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panelw" >&5 +printf %s "checking for panelw... " >&6; } if test -n "$PANEL_CFLAGS"; then pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" @@ -26161,7 +26161,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -26237,7 +26237,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -26316,8 +26316,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PANEL" >&5 -printf %s "checking for PANEL... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panel" >&5 +printf %s "checking for panel... " >&6; } if test -n "$PANEL_CFLAGS"; then pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" @@ -26357,7 +26357,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -26433,7 +26433,7 @@ LIBS=$save_LIBS elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } save_CFLAGS=$CFLAGS @@ -28423,8 +28423,8 @@ then : pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LIBB2" >&5 -printf %s "checking for LIBB2... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libb2" >&5 +printf %s "checking for libb2... " >&6; } if test -n "$LIBB2_CFLAGS"; then pkg_cv_LIBB2_CFLAGS="$LIBB2_CFLAGS" @@ -28464,7 +28464,7 @@ fi if test $pkg_failed = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -28482,7 +28482,7 @@ fi have_libb2=no elif test $pkg_failed = untried; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_libb2=no else diff --git a/configure.ac b/configure.ac index ac8400183d8a7b..bd2be94b47cb9c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,15 +1,12 @@ -dnl *************************************************** -dnl * Please run autoreconf -if to test your changes! * -dnl *************************************************** +dnl ************************************************************ +dnl * Please run autoreconf -ivf -Werror to test your changes! * +dnl ************************************************************ dnl dnl Python's configure script requires autoconf 2.71, autoconf-archive, -dnl pkgconf's m4 macros. +dnl aclocal 1.16, and pkg-config. dnl -dnl It is recommended to use a cpython_autoconf container to regenerate the -dnl configure script: -dnl -dnl podman run --rm --pull=always -v $(pwd):/src:Z quay.io/tiran/cpython_autoconf:271 -dnl docker run --rm --pull=always -v $(pwd):/src quay.io/tiran/cpython_autoconf:271 +dnl It is recommended to use the Tools/build/regen-configure.sh shell script +dnl to regenerate the configure script. dnl # Set VERSION so we only need to edit in one place (i.e., here) From 458a3c02e5734216af455172b35fa5ab96c9cfd4 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:32:47 +0100 Subject: [PATCH 1193/1206] [3.12] GH-112152: Fix typo in `typing.override` docstring (GH-112158) (#112162) GH-112152: Fix typo in `typing.override` docstring (GH-112158) (cherry picked from commit 12c7e9d573de57343cf018fb4e67521aba46c90f) Co-authored-by: Qua27 <92877777+Qua27@users.noreply.github.com> --- Lib/typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/typing.py b/Lib/typing.py index 9e2adbe2214a8a..9c8f48eef66b90 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -3364,7 +3364,7 @@ def override[F: _Func](method: F, /) -> F: Usage:: class Base: - def method(self) -> None: ... + def method(self) -> None: pass class Child(Base): From 3f2cdbe6668ae40e72a8a8f1530c860a776d0c62 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:11:33 +0100 Subject: [PATCH 1194/1206] [3.12] gh-111811: Fix test_recursive_repr for WASI (GH-112130) (#112131) gh-111811: Fix test_recursive_repr for WASI (GH-112130) (cherry picked from commit 7218bac8c84115a8e9a18a4a8f3146235068facb) Co-authored-by: Kushal Das --- Lib/test/test_xml_etree.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 3cde6ef5fa7c62..53a4e9f821d6dd 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2535,6 +2535,7 @@ def __eq__(self, o): e.extend([ET.Element('bar')]) self.assertRaises(ValueError, e.remove, X('baz')) + @support.infinite_recursion(25) def test_recursive_repr(self): # Issue #25455 e = ET.Element('foo') From 2ef3676a5bb8fba531fb8237ce50c27ebe37fb96 Mon Sep 17 00:00:00 2001 From: DPR Date: Fri, 17 Nov 2023 01:40:55 +0800 Subject: [PATCH 1195/1206] [3.12] gh-109538: Catch closed loop runtime error and issue warning (GH-111983) (#112142) * [3.12] gh-109538: Avoid RuntimeError when StreamWriter is deleted with closed loop (GH-111983) Issue a ResourceWarning instead. (cherry picked from commit e0f512797596282bff63260f8102592aad37cdf1) gh-109538: Avoid RuntimeError when StreamWriter is deleted with closed loop (#111983) Issue a ResourceWarning instead. Co-authored-by: Hugo van Kemenade (cherry picked from commit e0f512797596282bff63260f8102592aad37cdf1) * Fix missing warnings import --- Lib/asyncio/streams.py | 8 ++- Lib/test/test_asyncio/test_streams.py | 59 +++++++++++++++++++ ...-11-11-16-42-48.gh-issue-109538.cMG5ux.rst | 1 + 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-11-16-42-48.gh-issue-109538.cMG5ux.rst diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index f63eeca2a7719a..f5695266e1a8c6 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -5,6 +5,7 @@ import collections import socket import sys +import warnings import weakref if hasattr(socket, 'AF_UNIX'): @@ -405,8 +406,11 @@ async def start_tls(self, sslcontext, *, def __del__(self): if not self._transport.is_closing(): - self.close() - + if self._loop.is_closed(): + warnings.warn("loop is closed", ResourceWarning) + else: + self.close() + warnings.warn(f"unclosed {self!r}", ResourceWarning) class StreamReader: diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 5a22232c00a36a..ccb7dbf667c320 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -1073,6 +1073,65 @@ def test_eof_feed_when_closing_writer(self): self.assertEqual(messages, []) + def test_unclosed_resource_warnings(self): + async def inner(httpd): + rd, wr = await asyncio.open_connection(*httpd.address) + + wr.write(b'GET / HTTP/1.0\r\n\r\n') + data = await rd.readline() + self.assertEqual(data, b'HTTP/1.0 200 OK\r\n') + data = await rd.read() + self.assertTrue(data.endswith(b'\r\n\r\nTest message')) + with self.assertWarns(ResourceWarning) as cm: + del wr + gc.collect() + self.assertEqual(len(cm.warnings), 1) + self.assertTrue(str(cm.warnings[0].message).startswith("unclosed None: port = socket_helper.find_unused_port() diff --git a/Misc/NEWS.d/next/Library/2023-11-11-16-42-48.gh-issue-109538.cMG5ux.rst b/Misc/NEWS.d/next/Library/2023-11-11-16-42-48.gh-issue-109538.cMG5ux.rst new file mode 100644 index 00000000000000..d1ee4c054a3f19 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-11-16-42-48.gh-issue-109538.cMG5ux.rst @@ -0,0 +1 @@ +Issue warning message instead of having :class:`RuntimeError` be displayed when event loop has already been closed at :meth:`StreamWriter.__del__`. From 8e37445044ffcbeedabe495bbc413b2f50b5b713 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Thu, 16 Nov 2023 22:09:34 +0100 Subject: [PATCH 1196/1206] [3.12] Remove `imp_dummy_def` from `Tools/c-analyzer/cpython/ignored.tsv` (gh-112122) (gh-112177) It was removed in 3.12, no need to keep the ignore. (cherry picked from commit 762eb58220992d1ab809b9a281d47c0cd48a5aec) Co-authored-by: Nikita Sobolev --- Tools/c-analyzer/cpython/ignored.tsv | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 629a9a10ae59bb..9f36c47ca7ea03 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -550,7 +550,6 @@ Modules/_testmultiphase.c - def_nonascii_latin - Modules/_testmultiphase.c - def_nonmodule - Modules/_testmultiphase.c - def_nonmodule_with_exec_slots - Modules/_testmultiphase.c - def_nonmodule_with_methods - -Modules/_testmultiphase.c - imp_dummy_def - Modules/_testmultiphase.c - main_def - Modules/_testmultiphase.c - main_slots - Modules/_testmultiphase.c - meth_state_access_slots - From 94bac1c407dc1ab8fe0d59a8faf180538e513de7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 17 Nov 2023 02:11:46 +0100 Subject: [PATCH 1197/1206] [3.12] gh-112165: Fix typo in `__main__.py` (GH-112183) (#112184) gh-112165: Fix typo in `__main__.py` (GH-112183) Change '[2]' to '[1]' to get second argument. (cherry picked from commit 8cd70eefc7f3363cfa0d43f34522c3072fa9e160) Co-authored-by: Terry Jan Reedy --- Doc/library/__main__.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index 24a32b30bba673..c999253f781b10 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -227,7 +227,7 @@ students:: import sys from .student import search_students - student_name = sys.argv[2] if len(sys.argv) >= 2 else '' + student_name = sys.argv[1] if len(sys.argv) >= 2 else '' print(f'Found student: {search_students(student_name)}') Note that ``from .student import search_students`` is an example of a relative From 976488ebf654c837e63aa7d3077878c2c50c0c44 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:37:12 +0100 Subject: [PATCH 1198/1206] [3.12] gh-94309: "What's new in Python 3.12": improve deprecation notice for typing.Hashable and typing.Sized (GH-112196) (#112200) gh-94309: "What's new in Python 3.12": improve deprecation notice for typing.Hashable and typing.Sized (GH-112196) (cherry picked from commit fb4cddb0cc6c9b94929f846da8e95aeec3849212) Co-authored-by: Ori Avtalion --- Doc/whatsnew/3.12.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index feed5238bfab26..a046a8d95564b2 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1289,8 +1289,9 @@ Deprecated * :mod:`typing`: - * :class:`typing.Hashable` and :class:`typing.Sized` aliases for :class:`collections.abc.Hashable` - and :class:`collections.abc.Sized`. (:gh:`94309`.) + * :class:`typing.Hashable` and :class:`typing.Sized`, aliases for + :class:`collections.abc.Hashable` and :class:`collections.abc.Sized` respectively, are + deprecated. (:gh:`94309`.) * :class:`typing.ByteString`, deprecated since Python 3.9, now causes a :exc:`DeprecationWarning` to be emitted when it is used. From 0ea645445d749635cc6d369e9c42d6e176fc21dd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:28:35 +0100 Subject: [PATCH 1199/1206] [3.12] gh-112194: Convert more examples to doctests in `typing.py` (GH-112195) (#112208) gh-112194: Convert more examples to doctests in `typing.py` (GH-112195) (cherry picked from commit 949b2cc6eae6ef4f3312dfd4e2650a138446fe77) Co-authored-by: Nikita Sobolev Co-authored-by: Alex Waygood --- Lib/typing.py | 74 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index 9c8f48eef66b90..16243002640624 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -218,8 +218,12 @@ def _should_unflatten_callable_args(typ, args): For example:: - assert collections.abc.Callable[[int, int], str].__args__ == (int, int, str) - assert collections.abc.Callable[ParamSpec, str].__args__ == (ParamSpec, str) + >>> import collections.abc + >>> P = ParamSpec('P') + >>> collections.abc.Callable[[int, int], str].__args__ == (int, int, str) + True + >>> collections.abc.Callable[P, str].__args__ == (P, str) + True As a result, if we need to reconstruct the Callable from its __args__, we need to unflatten it. @@ -261,7 +265,10 @@ def _collect_parameters(args): For example:: - assert _collect_parameters((T, Callable[P, T])) == (T, P) + >>> P = ParamSpec('P') + >>> T = TypeVar('T') + >>> _collect_parameters((T, Callable[P, T])) + (~T, ~P) """ parameters = [] for t in args: @@ -2268,14 +2275,15 @@ def get_origin(tp): Examples:: - assert get_origin(Literal[42]) is Literal - assert get_origin(int) is None - assert get_origin(ClassVar[int]) is ClassVar - assert get_origin(Generic) is Generic - assert get_origin(Generic[T]) is Generic - assert get_origin(Union[T, int]) is Union - assert get_origin(List[Tuple[T, T]][int]) is list - assert get_origin(P.args) is P + >>> P = ParamSpec('P') + >>> assert get_origin(Literal[42]) is Literal + >>> assert get_origin(int) is None + >>> assert get_origin(ClassVar[int]) is ClassVar + >>> assert get_origin(Generic) is Generic + >>> assert get_origin(Generic[T]) is Generic + >>> assert get_origin(Union[T, int]) is Union + >>> assert get_origin(List[Tuple[T, T]][int]) is list + >>> assert get_origin(P.args) is P """ if isinstance(tp, _AnnotatedAlias): return Annotated @@ -2296,11 +2304,12 @@ def get_args(tp): Examples:: - assert get_args(Dict[str, int]) == (str, int) - assert get_args(int) == () - assert get_args(Union[int, Union[T, int], str][int]) == (int, str) - assert get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) - assert get_args(Callable[[], T][int]) == ([], int) + >>> T = TypeVar('T') + >>> assert get_args(Dict[str, int]) == (str, int) + >>> assert get_args(int) == () + >>> assert get_args(Union[int, Union[T, int], str][int]) == (int, str) + >>> assert get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + >>> assert get_args(Callable[[], T][int]) == ([], int) """ if isinstance(tp, _AnnotatedAlias): return (tp.__origin__,) + tp.__metadata__ @@ -2319,12 +2328,15 @@ def is_typeddict(tp): For example:: - class Film(TypedDict): - title: str - year: int - - is_typeddict(Film) # => True - is_typeddict(Union[list, str]) # => False + >>> from typing import TypedDict + >>> class Film(TypedDict): + ... title: str + ... year: int + ... + >>> is_typeddict(Film) + True + >>> is_typeddict(dict) + False """ return isinstance(tp, _TypedDictMeta) @@ -2881,15 +2893,15 @@ def TypedDict(typename, fields=None, /, *, total=True, **kwargs): Usage:: - class Point2D(TypedDict): - x: int - y: int - label: str - - a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK - b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check - - assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + >>> class Point2D(TypedDict): + ... x: int + ... y: int + ... label: str + ... + >>> a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + >>> b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + >>> Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + True The type info can be accessed via the Point2D.__annotations__ dict, and the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. From 919be35eae2413dfb59b9517879f69fedec68b7e Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sat, 18 Nov 2023 14:13:37 +0300 Subject: [PATCH 1200/1206] [3.12] gh-112155: Run `typing.py` doctests during tests (GH-112156) (#112230) --- Lib/test/test_typing.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ca10a87b06130d..a26e80995fef3f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -9282,5 +9282,11 @@ def test_is_not_instance_of_iterable(self): self.assertNotIsInstance(type_to_test, collections.abc.Iterable) +def load_tests(loader, tests, pattern): + import doctest + tests.addTests(doctest.DocTestSuite(typing)) + return tests + + if __name__ == '__main__': main() From a62dcacc6e7fabc82c50dd942a838cd69d2846bd Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Nov 2023 05:35:59 +0100 Subject: [PATCH 1201/1206] [3.12] gh-79871: IDLE - Fix and test debugger module (GH-11451) (#112256) gh-79871: IDLE - Fix and test debugger module (GH-11451) Add docstrings to the debugger module. Fix two bugs: initialize Idb.botframe (should be in Bdb); In Idb.in_rpc_code, check whether prev_frame is None before trying to use it. Make other code changes. Expand test_debugger coverage from 19% to 66%. --------- (cherry picked from commit adedcfa06b553242d8033f6d9bebbcb3bc0dbb4d) Co-authored-by: Anthony Shaw Co-authored-by: Terry Jan Reedy --- Lib/idlelib/debugger.py | 179 ++++++++---- Lib/idlelib/idle_test/test_debugger.py | 276 +++++++++++++++++- Lib/idlelib/pyshell.py | 16 +- Lib/idlelib/stackviewer.py | 2 + .../2019-01-07-06-18-25.bpo-35668.JimxP5.rst | 4 + 5 files changed, 400 insertions(+), 77 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2019-01-07-06-18-25.bpo-35668.JimxP5.rst diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index a92bb98d908d46..f487b4c4b16a60 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -1,3 +1,20 @@ +"""Debug user code with a GUI interface to a subclass of bdb.Bdb. + +The Idb idb and Debugger gui instances each need a reference to each +other or to an rpc proxy for each other. + +If IDLE is started with '-n', so that user code and idb both run in the +IDLE process, Debugger is called without an idb. Debugger.__init__ +calls Idb with its incomplete self. Idb.__init__ stores gui and gui +then stores idb. + +If IDLE is started normally, so that user code executes in a separate +process, debugger_r.start_remote_debugger is called, executing in the +IDLE process. It calls 'start the debugger' in the remote process, +which calls Idb with a gui proxy. Then Debugger is called in the IDLE +for more. +""" + import bdb import os @@ -10,66 +27,95 @@ class Idb(bdb.Bdb): + "Supply user_line and user_exception functions for Bdb." def __init__(self, gui): - self.gui = gui # An instance of Debugger or proxy of remote. - bdb.Bdb.__init__(self) + self.gui = gui # An instance of Debugger or proxy thereof. + super().__init__() def user_line(self, frame): - if self.in_rpc_code(frame): + """Handle a user stopping or breaking at a line. + + Convert frame to a string and send it to gui. + """ + if _in_rpc_code(frame): self.set_step() return - message = self.__frame2message(frame) + message = _frame2message(frame) try: self.gui.interaction(message, frame) except TclError: # When closing debugger window with [x] in 3.x pass - def user_exception(self, frame, info): - if self.in_rpc_code(frame): + def user_exception(self, frame, exc_info): + """Handle an the occurrence of an exception.""" + if _in_rpc_code(frame): self.set_step() return - message = self.__frame2message(frame) - self.gui.interaction(message, frame, info) - - def in_rpc_code(self, frame): - if frame.f_code.co_filename.count('rpc.py'): - return True - else: - prev_frame = frame.f_back - prev_name = prev_frame.f_code.co_filename - if 'idlelib' in prev_name and 'debugger' in prev_name: - # catch both idlelib/debugger.py and idlelib/debugger_r.py - # on both Posix and Windows - return False - return self.in_rpc_code(prev_frame) - - def __frame2message(self, frame): - code = frame.f_code - filename = code.co_filename - lineno = frame.f_lineno - basename = os.path.basename(filename) - message = f"{basename}:{lineno}" - if code.co_name != "?": - message = f"{message}: {code.co_name}()" - return message + message = _frame2message(frame) + self.gui.interaction(message, frame, exc_info) + +def _in_rpc_code(frame): + "Determine if debugger is within RPC code." + if frame.f_code.co_filename.count('rpc.py'): + return True # Skip this frame. + else: + prev_frame = frame.f_back + if prev_frame is None: + return False + prev_name = prev_frame.f_code.co_filename + if 'idlelib' in prev_name and 'debugger' in prev_name: + # catch both idlelib/debugger.py and idlelib/debugger_r.py + # on both Posix and Windows + return False + return _in_rpc_code(prev_frame) + +def _frame2message(frame): + """Return a message string for frame.""" + code = frame.f_code + filename = code.co_filename + lineno = frame.f_lineno + basename = os.path.basename(filename) + message = f"{basename}:{lineno}" + if code.co_name != "?": + message = f"{message}: {code.co_name}()" + return message class Debugger: - - vstack = vsource = vlocals = vglobals = None + """The debugger interface. + + This class handles the drawing of the debugger window and + the interactions with the underlying debugger session. + """ + vstack = None + vsource = None + vlocals = None + vglobals = None + stackviewer = None + localsviewer = None + globalsviewer = None def __init__(self, pyshell, idb=None): + """Instantiate and draw a debugger window. + + :param pyshell: An instance of the PyShell Window + :type pyshell: :class:`idlelib.pyshell.PyShell` + + :param idb: An instance of the IDLE debugger (optional) + :type idb: :class:`idlelib.debugger.Idb` + """ if idb is None: idb = Idb(self) self.pyshell = pyshell self.idb = idb # If passed, a proxy of remote instance. self.frame = None self.make_gui() - self.interacting = 0 + self.interacting = False self.nesting_level = 0 def run(self, *args): + """Run the debugger.""" # Deal with the scenario where we've already got a program running # in the debugger and we want to start another. If that is the case, # our second 'run' was invoked from an event dispatched not from @@ -104,12 +150,13 @@ def run(self, *args): self.root.after(100, lambda: self.run(*args)) return try: - self.interacting = 1 + self.interacting = True return self.idb.run(*args) finally: - self.interacting = 0 + self.interacting = False def close(self, event=None): + """Close the debugger and window.""" try: self.quit() except Exception: @@ -127,6 +174,7 @@ def close(self, event=None): self.top.destroy() def make_gui(self): + """Draw the debugger gui on the screen.""" pyshell = self.pyshell self.flist = pyshell.flist self.root = root = pyshell.root @@ -135,11 +183,11 @@ def make_gui(self): self.top.wm_iconname("Debug") top.wm_protocol("WM_DELETE_WINDOW", self.close) self.top.bind("", self.close) - # + self.bframe = bframe = Frame(top) self.bframe.pack(anchor="w") self.buttons = bl = [] - # + self.bcont = b = Button(bframe, text="Go", command=self.cont) bl.append(b) self.bstep = b = Button(bframe, text="Step", command=self.step) @@ -150,14 +198,14 @@ def make_gui(self): bl.append(b) self.bret = b = Button(bframe, text="Quit", command=self.quit) bl.append(b) - # + for b in bl: b.configure(state="disabled") b.pack(side="left") - # + self.cframe = cframe = Frame(bframe) self.cframe.pack(side="left") - # + if not self.vstack: self.__class__.vstack = BooleanVar(top) self.vstack.set(1) @@ -180,20 +228,20 @@ def make_gui(self): self.bglobals = Checkbutton(cframe, text="Globals", command=self.show_globals, variable=self.vglobals) self.bglobals.grid(row=1, column=1) - # + self.status = Label(top, anchor="w") self.status.pack(anchor="w") self.error = Label(top, anchor="w") self.error.pack(anchor="w", fill="x") self.errorbg = self.error.cget("background") - # + self.fstack = Frame(top, height=1) self.fstack.pack(expand=1, fill="both") self.flocals = Frame(top) self.flocals.pack(expand=1, fill="both") self.fglobals = Frame(top, height=1) self.fglobals.pack(expand=1, fill="both") - # + if self.vstack.get(): self.show_stack() if self.vlocals.get(): @@ -204,7 +252,7 @@ def make_gui(self): def interaction(self, message, frame, info=None): self.frame = frame self.status.configure(text=message) - # + if info: type, value, tb = info try: @@ -223,28 +271,28 @@ def interaction(self, message, frame, info=None): tb = None bg = self.errorbg self.error.configure(text=m1, background=bg) - # + sv = self.stackviewer if sv: stack, i = self.idb.get_stack(self.frame, tb) sv.load_stack(stack, i) - # + self.show_variables(1) - # + if self.vsource.get(): self.sync_source_line() - # + for b in self.buttons: b.configure(state="normal") - # + self.top.wakeup() # Nested main loop: Tkinter's main loop is not reentrant, so use # Tcl's vwait facility, which reenters the event loop until an - # event handler sets the variable we're waiting on + # event handler sets the variable we're waiting on. self.nesting_level += 1 self.root.tk.call('vwait', '::idledebugwait') self.nesting_level -= 1 - # + for b in self.buttons: b.configure(state="disabled") self.status.configure(text="") @@ -288,8 +336,6 @@ def quit(self): def abort_loop(self): self.root.tk.call('set', '::idledebugwait', '1') - stackviewer = None - def show_stack(self): if not self.stackviewer and self.vstack.get(): self.stackviewer = sv = StackViewer(self.fstack, self.flist, self) @@ -311,9 +357,6 @@ def show_frame(self, stackitem): self.frame = stackitem[0] # lineno is stackitem[1] self.show_variables() - localsviewer = None - globalsviewer = None - def show_locals(self): lv = self.localsviewer if self.vlocals.get(): @@ -354,26 +397,32 @@ def show_variables(self, force=0): if gv: gv.load_dict(gdict, force, self.pyshell.interp.rpcclt) - def set_breakpoint_here(self, filename, lineno): + def set_breakpoint(self, filename, lineno): + """Set a filename-lineno breakpoint in the debugger. + + Called from self.load_breakpoints and EW.setbreakpoint + """ self.idb.set_break(filename, lineno) - def clear_breakpoint_here(self, filename, lineno): + def clear_breakpoint(self, filename, lineno): self.idb.clear_break(filename, lineno) def clear_file_breaks(self, filename): self.idb.clear_all_file_breaks(filename) def load_breakpoints(self): - "Load PyShellEditorWindow breakpoints into subprocess debugger" + """Load PyShellEditorWindow breakpoints into subprocess debugger.""" for editwin in self.pyshell.flist.inversedict: filename = editwin.io.filename try: for lineno in editwin.breakpoints: - self.set_breakpoint_here(filename, lineno) + self.set_breakpoint(filename, lineno) except AttributeError: continue + class StackViewer(ScrolledList): + "Code stack viewer for debugger GUI." def __init__(self, master, flist, gui): if macosx.isAquaTk(): @@ -414,12 +463,12 @@ def load_stack(self, stack, index=None): self.select(index) def popup_event(self, event): - "override base method" + "Override base method." if self.stack: return ScrolledList.popup_event(self, event) def fill_menu(self): - "override base method" + "Override base method." menu = self.menu menu.add_command(label="Go to source line", command=self.goto_source_line) @@ -427,12 +476,12 @@ def fill_menu(self): command=self.show_stack_frame) def on_select(self, index): - "override base method" + "Override base method." if 0 <= index < len(self.stack): self.gui.show_frame(self.stack[index]) def on_double(self, index): - "override base method" + "Override base method." self.show_source(index) def goto_source_line(self): @@ -457,6 +506,7 @@ def show_source(self, index): class NamespaceViewer: + "Global/local namespace viewer for debugger GUI." def __init__(self, master, title, dict=None): width = 0 @@ -544,6 +594,7 @@ def load_dict(self, dict, force=0, rpc_client=None): def close(self): self.frame.destroy() + if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_debugger', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_debugger.py b/Lib/idlelib/idle_test/test_debugger.py index 35efb3411c73b5..db01a893cb1980 100644 --- a/Lib/idlelib/idle_test/test_debugger.py +++ b/Lib/idlelib/idle_test/test_debugger.py @@ -1,11 +1,279 @@ "Test debugger, coverage 19%" from idlelib import debugger -import unittest -from test.support import requires -requires('gui') +from collections import namedtuple +from textwrap import dedent from tkinter import Tk +from test.support import requires +import unittest +from unittest import mock +from unittest.mock import Mock, patch + +"""A test python script for the debug tests.""" +TEST_CODE = dedent(""" + i = 1 + i += 2 + if i == 3: + print(i) + """) + + +class MockFrame: + "Minimal mock frame." + + def __init__(self, code, lineno): + self.f_code = code + self.f_lineno = lineno + + +class IdbTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.gui = Mock() + cls.idb = debugger.Idb(cls.gui) + + # Create test and code objects to simulate a debug session. + code_obj = compile(TEST_CODE, 'idlelib/file.py', mode='exec') + frame1 = MockFrame(code_obj, 1) + frame1.f_back = None + frame2 = MockFrame(code_obj, 2) + frame2.f_back = frame1 + cls.frame = frame2 + cls.msg = 'file.py:2: ()' + + def test_init(self): + # Test that Idb.__init_ calls Bdb.__init__. + idb = debugger.Idb(None) + self.assertIsNone(idb.gui) + self.assertTrue(hasattr(idb, 'breaks')) + + def test_user_line(self): + # Test that .user_line() creates a string message for a frame. + self.gui.interaction = Mock() + self.idb.user_line(self.frame) + self.gui.interaction.assert_called_once_with(self.msg, self.frame) + + def test_user_exception(self): + # Test that .user_exception() creates a string message for a frame. + exc_info = (type(ValueError), ValueError(), None) + self.gui.interaction = Mock() + self.idb.user_exception(self.frame, exc_info) + self.gui.interaction.assert_called_once_with( + self.msg, self.frame, exc_info) + + +class FunctionTest(unittest.TestCase): + # Test module functions together. + + def test_functions(self): + rpc_obj = compile(TEST_CODE,'rpc.py', mode='exec') + rpc_frame = MockFrame(rpc_obj, 2) + rpc_frame.f_back = rpc_frame + self.assertTrue(debugger._in_rpc_code(rpc_frame)) + self.assertEqual(debugger._frame2message(rpc_frame), + 'rpc.py:2: ()') + + code_obj = compile(TEST_CODE, 'idlelib/debugger.py', mode='exec') + code_frame = MockFrame(code_obj, 1) + code_frame.f_back = None + self.assertFalse(debugger._in_rpc_code(code_frame)) + self.assertEqual(debugger._frame2message(code_frame), + 'debugger.py:1: ()') + + code_frame.f_back = code_frame + self.assertFalse(debugger._in_rpc_code(code_frame)) + code_frame.f_back = rpc_frame + self.assertTrue(debugger._in_rpc_code(code_frame)) + + +class DebuggerTest(unittest.TestCase): + "Tests for Debugger that do not need a real root." + + @classmethod + def setUpClass(cls): + cls.pyshell = Mock() + cls.pyshell.root = Mock() + cls.idb = Mock() + with patch.object(debugger.Debugger, 'make_gui'): + cls.debugger = debugger.Debugger(cls.pyshell, cls.idb) + cls.debugger.root = Mock() + + def test_cont(self): + self.debugger.cont() + self.idb.set_continue.assert_called_once() + + def test_step(self): + self.debugger.step() + self.idb.set_step.assert_called_once() + + def test_quit(self): + self.debugger.quit() + self.idb.set_quit.assert_called_once() + + def test_next(self): + with patch.object(self.debugger, 'frame') as frame: + self.debugger.next() + self.idb.set_next.assert_called_once_with(frame) + + def test_ret(self): + with patch.object(self.debugger, 'frame') as frame: + self.debugger.ret() + self.idb.set_return.assert_called_once_with(frame) + + def test_clear_breakpoint(self): + self.debugger.clear_breakpoint('test.py', 4) + self.idb.clear_break.assert_called_once_with('test.py', 4) + + def test_clear_file_breaks(self): + self.debugger.clear_file_breaks('test.py') + self.idb.clear_all_file_breaks.assert_called_once_with('test.py') + + def test_set_load_breakpoints(self): + # Test the .load_breakpoints() method calls idb. + FileIO = namedtuple('FileIO', 'filename') + + class MockEditWindow(object): + def __init__(self, fn, breakpoints): + self.io = FileIO(fn) + self.breakpoints = breakpoints + + self.pyshell.flist = Mock() + self.pyshell.flist.inversedict = ( + MockEditWindow('test1.py', [4, 4]), + MockEditWindow('test2.py', [13, 44, 45]), + ) + self.debugger.set_breakpoint('test0.py', 1) + self.idb.set_break.assert_called_once_with('test0.py', 1) + self.debugger.load_breakpoints() # Call set_breakpoint 5 times. + self.idb.set_break.assert_has_calls( + [mock.call('test0.py', 1), + mock.call('test1.py', 4), + mock.call('test1.py', 4), + mock.call('test2.py', 13), + mock.call('test2.py', 44), + mock.call('test2.py', 45)]) + + def test_sync_source_line(self): + # Test that .sync_source_line() will set the flist.gotofileline with fixed frame. + test_code = compile(TEST_CODE, 'test_sync.py', 'exec') + test_frame = MockFrame(test_code, 1) + self.debugger.frame = test_frame + + self.debugger.flist = Mock() + with patch('idlelib.debugger.os.path.exists', return_value=True): + self.debugger.sync_source_line() + self.debugger.flist.gotofileline.assert_called_once_with('test_sync.py', 1) + + +class DebuggerGuiTest(unittest.TestCase): + """Tests for debugger.Debugger that need tk root. + + close needs debugger.top set in make_gui. + """ + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = root = Tk() + root.withdraw() + cls.pyshell = Mock() + cls.pyshell.root = root + cls.idb = Mock() +# stack tests fail with debugger here. +## cls.debugger = debugger.Debugger(cls.pyshell, cls.idb) +## cls.debugger.root = root +## # real root needed for real make_gui +## # run, interacting, abort_loop + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + del cls.root + + def setUp(self): + self.debugger = debugger.Debugger(self.pyshell, self.idb) + self.debugger.root = self.root + # real root needed for real make_gui + # run, interacting, abort_loop + + def test_run_debugger(self): + self.debugger.run(1, 'two') + self.idb.run.assert_called_once_with(1, 'two') + self.assertEqual(self.debugger.interacting, 0) + + def test_close(self): + # Test closing the window in an idle state. + self.debugger.close() + self.pyshell.close_debugger.assert_called_once() + + def test_show_stack(self): + self.debugger.show_stack() + self.assertEqual(self.debugger.stackviewer.gui, self.debugger) + + def test_show_stack_with_frame(self): + test_frame = MockFrame(None, None) + self.debugger.frame = test_frame + + # Reset the stackviewer to force it to be recreated. + self.debugger.stackviewer = None + self.idb.get_stack.return_value = ([], 0) + self.debugger.show_stack() + + # Check that the newly created stackviewer has the test gui as a field. + self.assertEqual(self.debugger.stackviewer.gui, self.debugger) + self.idb.get_stack.assert_called_once_with(test_frame, None) + + +class StackViewerTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = Tk() + cls.root.withdraw() + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + del cls.root + + def setUp(self): + self.code = compile(TEST_CODE, 'test_stackviewer.py', 'exec') + self.stack = [ + (MockFrame(self.code, 1), 1), + (MockFrame(self.code, 2), 2) + ] + # Create a stackviewer and load the test stack. + self.sv = debugger.StackViewer(self.root, None, None) + self.sv.load_stack(self.stack) + + def test_init(self): + # Test creation of StackViewer. + gui = None + flist = None + master_window = self.root + sv = debugger.StackViewer(master_window, flist, gui) + self.assertTrue(hasattr(sv, 'stack')) + + def test_load_stack(self): + # Test the .load_stack() method against a fixed test stack. + # Check the test stack is assigned and the list contains the repr of them. + self.assertEqual(self.sv.stack, self.stack) + self.assertTrue('?.(), line 1:' in self.sv.get(0)) + self.assertEqual(self.sv.get(1), '?.(), line 2: ') + + def test_show_source(self): + # Test the .show_source() method against a fixed test stack. + # Patch out the file list to monitor it + self.sv.flist = Mock() + # Patch out isfile to pretend file exists. + with patch('idlelib.debugger.os.path.isfile', return_value=True) as isfile: + self.sv.show_source(1) + isfile.assert_called_once_with('test_stackviewer.py') + self.sv.flist.open.assert_called_once_with('test_stackviewer.py') + class NameSpaceTest(unittest.TestCase): @@ -23,7 +291,5 @@ def test_init(self): debugger.NamespaceViewer(self.root, 'Test') -# Other classes are Idb, Debugger, and StackViewer. - if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 7a2707935b60c9..00b3732a7bc4eb 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -133,8 +133,8 @@ class PyShellEditorWindow(EditorWindow): def __init__(self, *args): self.breakpoints = [] EditorWindow.__init__(self, *args) - self.text.bind("<>", self.set_breakpoint_here) - self.text.bind("<>", self.clear_breakpoint_here) + self.text.bind("<>", self.set_breakpoint_event) + self.text.bind("<>", self.clear_breakpoint_event) self.text.bind("<>", self.flist.open_shell) #TODO: don't read/write this from/to .idlerc when testing @@ -155,8 +155,8 @@ def filename_changed_hook(old_hook=self.io.filename_change_hook, ("Copy", "<>", "rmenu_check_copy"), ("Paste", "<>", "rmenu_check_paste"), (None, None, None), - ("Set Breakpoint", "<>", None), - ("Clear Breakpoint", "<>", None) + ("Set Breakpoint", "<>", None), + ("Clear Breakpoint", "<>", None) ] def color_breakpoint_text(self, color=True): @@ -181,11 +181,11 @@ def set_breakpoint(self, lineno): self.breakpoints.append(lineno) try: # update the subprocess debugger debug = self.flist.pyshell.interp.debugger - debug.set_breakpoint_here(filename, lineno) + debug.set_breakpoint(filename, lineno) except: # but debugger may not be active right now.... pass - def set_breakpoint_here(self, event=None): + def set_breakpoint_event(self, event=None): text = self.text filename = self.io.filename if not filename: @@ -194,7 +194,7 @@ def set_breakpoint_here(self, event=None): lineno = int(float(text.index("insert"))) self.set_breakpoint(lineno) - def clear_breakpoint_here(self, event=None): + def clear_breakpoint_event(self, event=None): text = self.text filename = self.io.filename if not filename: @@ -209,7 +209,7 @@ def clear_breakpoint_here(self, event=None): "insert lineend +1char") try: debug = self.flist.pyshell.interp.debugger - debug.clear_breakpoint_here(filename, lineno) + debug.clear_breakpoint(filename, lineno) except: pass diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 4858cc682a4f45..f8e60fd9b6d818 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -1,3 +1,5 @@ +# Rename to stackbrowser or possibly consolidate with browser. + import linecache import os diff --git a/Misc/NEWS.d/next/IDLE/2019-01-07-06-18-25.bpo-35668.JimxP5.rst b/Misc/NEWS.d/next/IDLE/2019-01-07-06-18-25.bpo-35668.JimxP5.rst new file mode 100644 index 00000000000000..8bb5420517d55f --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2019-01-07-06-18-25.bpo-35668.JimxP5.rst @@ -0,0 +1,4 @@ +Add docstrings to the IDLE debugger module. Fix two bugs: +initialize Idb.botframe (should be in Bdb); in Idb.in_rpc_code, +check whether prev_frame is None before trying to use it. +Greatly expand test_debugger. From 89c51808398c2f4e199c7c61404ea2113f6890e9 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Nov 2023 07:53:37 +0100 Subject: [PATCH 1202/1206] [3.12] IDLE: Fix test_debugger bug and buildbot failures (GH-112258) (#112259) IDLE: Fix test_debugger bug and buildbot failures (GH-112258) Missing "requires('gui')" causes Tk() to fail when no gui. This caused CI Hypothesis test to fail, but I did not understand the its error message. Then buildbots failed. IdbTest failed on draft Bdb replacement because so different. Simplified version works on old and new. (cherry picked from commit 14fd86a59d0d91fe72641efeb14a59d99127dec3) Co-authored-by: Terry Jan Reedy --- Lib/idlelib/idle_test/test_debugger.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/idle_test/test_debugger.py b/Lib/idlelib/idle_test/test_debugger.py index db01a893cb1980..d1c9638dd5d711 100644 --- a/Lib/idlelib/idle_test/test_debugger.py +++ b/Lib/idlelib/idle_test/test_debugger.py @@ -1,4 +1,7 @@ -"Test debugger, coverage 19%" +"""Test debugger, coverage 66% + +Try to make tests pass with draft bdbx, which may replace bdb in 3.13+. +""" from idlelib import debugger from collections import namedtuple @@ -44,10 +47,8 @@ def setUpClass(cls): cls.msg = 'file.py:2: ()' def test_init(self): - # Test that Idb.__init_ calls Bdb.__init__. - idb = debugger.Idb(None) - self.assertIsNone(idb.gui) - self.assertTrue(hasattr(idb, 'breaks')) + self.assertIs(self.idb.gui, self.gui) + # Won't test super call since two Bdbs are very different. def test_user_line(self): # Test that .user_line() creates a string message for a frame. @@ -279,6 +280,7 @@ class NameSpaceTest(unittest.TestCase): @classmethod def setUpClass(cls): + requires('gui') cls.root = Tk() cls.root.withdraw() From 5134f668b4054f99f317c1300a3c09c6a0e93ca7 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Nov 2023 11:03:07 +0100 Subject: [PATCH 1203/1206] [3.12] gh-110383: Fix documentation profile cumtime fix (GH-112221) (#112262) Co-authored-by: Alex Ptakhin Co-authored-by: Hugo van Kemenade --- Doc/library/profile.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index 4c60a1e0d781b0..cc059b66fcb84b 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -82,8 +82,8 @@ the following:: The first line indicates that 214 calls were monitored. Of those calls, 207 were :dfn:`primitive`, meaning that the call was not induced via recursion. The -next line: ``Ordered by: cumulative time``, indicates that the text string in the -far right column was used to sort the output. The column headings include: +next line: ``Ordered by: cumulative time`` indicates the output is sorted +by the ``cumtime`` values. The column headings include: ncalls for the number of calls. From dedbd266d3dbbf460651d132a5f1d61643d9e20d Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:29:24 +0100 Subject: [PATCH 1204/1206] [3.12] gh-110383: Explained which error message is generated when there is an unhandled exception (GH-111574) (#112264) Co-authored-by: Unique-Usman <86585626+Unique-Usman@users.noreply.github.com> Co-authored-by: Hugo van Kemenade --- Doc/tutorial/errors.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index 1ec59767e9ce12..4058ebe8efdb42 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -108,8 +108,7 @@ The :keyword:`try` statement works as follows. * If an exception occurs which does not match the exception named in the *except clause*, it is passed on to outer :keyword:`try` statements; if no handler is - found, it is an *unhandled exception* and execution stops with a message as - shown above. + found, it is an *unhandled exception* and execution stops with an error message. A :keyword:`try` statement may have more than one *except clause*, to specify handlers for different exceptions. At most one handler will be executed. From f521321ddf055636eb33c5b65456404762f5be62 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Nov 2023 16:19:12 +0100 Subject: [PATCH 1205/1206] [3.12] gh-112186: Improve test case `test_loop_is_closed_resource_warnings` (GH-112187) (#112255) (cherry picked from commit 18c692946953e586db432fd06c856531a2b05127) Co-authored-by: DPR --- Lib/test/test_asyncio/test_streams.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index ccb7dbf667c320..b408cd1f7da205 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -1122,13 +1122,10 @@ async def inner(httpd): self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) with test_utils.run_test_server() as httpd: - try: + with self.assertRaises(RuntimeError): + # This exception is caused by `self.loop.stop()` as expected. self.loop.run_until_complete(inner(httpd)) - # This exception is caused by `self.loop.stop()` as expected. - except RuntimeError: - pass - finally: - gc.collect() + gc.collect() self.assertEqual(messages, []) From cf8c8307554939fd299cebfa00ccd49bc758f7ad Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Nov 2023 19:59:50 +0100 Subject: [PATCH 1206/1206] [3.12] gh-112266: Remove `(if defined)` part from `__dict__` and `__weakref__` docstrings (GH-112268) (#112270) gh-112266: Remove `(if defined)` part from `__dict__` and `__weakref__` docstrings (GH-112268) (cherry picked from commit f8129146ef9e1b71609ef4becc5d508061970733) Co-authored-by: Nikita Sobolev --- Lib/test/test_pydoc.py | 28 +++++++++---------- ...-11-19-15-57-23.gh-issue-112266.BSJMbR.rst | 2 ++ Objects/typeobject.c | 8 +++--- 3 files changed, 20 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-11-19-15-57-23.gh-issue-112266.BSJMbR.rst diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index ddb5187f90da9b..e70a80f13e8736 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -40,8 +40,8 @@ class nonascii: if test.support.HAVE_DOCSTRINGS: expected_data_docstrings = ( - 'dictionary for instance variables (if defined)', - 'list of weak references to the object (if defined)', + 'dictionary for instance variables', + 'list of weak references to the object', ) * 2 else: expected_data_docstrings = ('', '', '', '') @@ -105,10 +105,10 @@ class C(builtins.object) | Data descriptors defined here: | | __dict__ - | dictionary for instance variables (if defined) + | dictionary for instance variables | | __weakref__ - | list of weak references to the object (if defined) + | list of weak references to the object FUNCTIONS doc_func() @@ -166,16 +166,16 @@ class A(builtins.object) Data descriptors defined here: __dict__ - dictionary for instance variables (if defined) + dictionary for instance variables __weakref__ - list of weak references to the object (if defined) + list of weak references to the object class B(builtins.object) Data descriptors defined here: __dict__ - dictionary for instance variables (if defined) + dictionary for instance variables __weakref__ - list of weak references to the object (if defined) + list of weak references to the object Data and other attributes defined here: NO_MEANING = 'eggs' __annotations__ = {'NO_MEANING': } @@ -192,9 +192,9 @@ class C(builtins.object) __class_getitem__(item) from builtins.type Data descriptors defined here: __dict__ - dictionary for instance variables (if defined) + dictionary for instance variables __weakref__ - list of weak references to the object (if defined) + list of weak references to the object Functions doc_func() @@ -826,10 +826,10 @@ class B(A) | Data descriptors inherited from A: | | __dict__ - | dictionary for instance variables (if defined) + | dictionary for instance variables | | __weakref__ - | list of weak references to the object (if defined) + | list of weak references to the object ''' % __name__) doc = pydoc.render_doc(B, renderer=pydoc.HTMLDoc()) @@ -858,9 +858,9 @@ class B(A) Data descriptors inherited from A: __dict__ - dictionary for instance variables (if defined) + dictionary for instance variables __weakref__ - list of weak references to the object (if defined) + list of weak references to the object """ as_text = html2text(doc) expected_lines = [line.strip() for line in expected_text.split("\n") if line] diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-11-19-15-57-23.gh-issue-112266.BSJMbR.rst b/Misc/NEWS.d/next/Core and Builtins/2023-11-19-15-57-23.gh-issue-112266.BSJMbR.rst new file mode 100644 index 00000000000000..18433db9bb976e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-11-19-15-57-23.gh-issue-112266.BSJMbR.rst @@ -0,0 +1,2 @@ +Change docstrings of :attr:`~object.__dict__` and +:attr:`~object.__weakref__`. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5c71c28f751504..d0c7c5f9439ccc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2974,21 +2974,21 @@ subtype_getweakref(PyObject *obj, void *context) static PyGetSetDef subtype_getsets_full[] = { {"__dict__", subtype_dict, subtype_setdict, - PyDoc_STR("dictionary for instance variables (if defined)")}, + PyDoc_STR("dictionary for instance variables")}, {"__weakref__", subtype_getweakref, NULL, - PyDoc_STR("list of weak references to the object (if defined)")}, + PyDoc_STR("list of weak references to the object")}, {0} }; static PyGetSetDef subtype_getsets_dict_only[] = { {"__dict__", subtype_dict, subtype_setdict, - PyDoc_STR("dictionary for instance variables (if defined)")}, + PyDoc_STR("dictionary for instance variables")}, {0} }; static PyGetSetDef subtype_getsets_weakref_only[] = { {"__weakref__", subtype_getweakref, NULL, - PyDoc_STR("list of weak references to the object (if defined)")}, + PyDoc_STR("list of weak references to the object")}, {0} };

Unix users should download the .tar.bz2 archives; these are bzipped tar archives and can be handled in the usual way using tar and the bzip2 -program. The InfoZIP unzip program can be +program. The Info-ZIP unzip program can be used to handle the ZIP archives if desired. The .tar.bz2 archives provide the best compression and fastest download times.